Skip to content

Commit

Permalink
#42 init router config (#48)
Browse files Browse the repository at this point in the history
- Cleaned up and restructured provider/openai codebase. Separated unified schemas to the api package.
- Added and exposed the language chat API with the unified request/response schemas. Updated the bruno collection with this request
- Added an example of client tests
- Connected Glide API with the underlying model provider (OpenAI client is hardcoded for now)
- Implemented default value setting for nested nillable config items
- Implemented provider setting validation on the model item level
  • Loading branch information
roma-glushko authored Jan 1, 2024
1 parent c62579d commit ae3cf1b
Show file tree
Hide file tree
Showing 29 changed files with 693 additions and 312 deletions.
21 changes: 21 additions & 0 deletions docs/api/[Lang] Chat.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
meta {
name: [Lang] Chat
type: http
seq: 2
}

post {
url: {{base_url}}/v1/language/myrouter/chat/
body: json
auth: none
}

body:json {
{
"message": {
"role": "user",
"content": "How are you doing?"
},
"messageHistory": []
}
}
2 changes: 1 addition & 1 deletion docs/api/environments/Development.bru
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
vars {
base_url: http://localhost:9099
base_url: http://127.0.0.1:9099
}
9 changes: 9 additions & 0 deletions pkg/api/http/schemas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package http

type ErrorSchema struct {
Message string `json:"message"`
}

type HealthSchema struct {
Healthy bool `json:"healthy"`
}
59 changes: 48 additions & 11 deletions pkg/api/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,74 @@ package http

import (
"context"
"errors"
"fmt"
"time"

"glide/pkg/pools"
"glide/pkg/api/schemas"

"glide/pkg/routers"

"glide/pkg/telemetry"

"github.com/cloudwego/hertz/pkg/app"
"github.com/cloudwego/hertz/pkg/app/server"
"github.com/cloudwego/hertz/pkg/common/utils"
"github.com/cloudwego/hertz/pkg/protocol/consts"
)

type Server struct {
telemetry *telemetry.Telemetry
router *pools.Router
server *server.Hertz
telemetry *telemetry.Telemetry
routerManager *routers.RouterManager
server *server.Hertz
}

func NewServer(config *ServerConfig, tel *telemetry.Telemetry, router *pools.Router) (*Server, error) {
func NewServer(config *ServerConfig, tel *telemetry.Telemetry, routerManager *routers.RouterManager) (*Server, error) {
srv := config.ToServer()

return &Server{
telemetry: tel,
router: router,
server: srv,
telemetry: tel,
routerManager: routerManager,
server: srv,
}, nil
}

func (srv *Server) Run() error {
srv.server.GET("/health", func(ctx context.Context, c *app.RequestContext) {
c.JSON(consts.StatusOK, utils.H{"healthy": true})
srv.server.POST("/v1/language/:router/chat/", func(ctx context.Context, c *app.RequestContext) {
var req *schemas.UnifiedChatRequest

err := c.BindJSON(&req)
if err != nil {
c.JSON(consts.StatusBadRequest, ErrorSchema{
Message: err.Error(),
})

return
}

routerID := c.Param("router")
router, err := srv.routerManager.GetLangRouter(routerID)

if errors.Is(err, routers.ErrRouterNotFound) {
c.JSON(consts.StatusNotFound, ErrorSchema{
Message: err.Error(),
})
return
}

resp, err := router.Chat(ctx, req)
if err != nil {
// TODO: do a better handling, not everything is going to be an internal error
c.JSON(consts.StatusInternalServerError, ErrorSchema{
Message: err.Error(),
})
return
}

c.JSON(consts.StatusOK, resp)
})

srv.server.GET("/v1/health/", func(ctx context.Context, c *app.RequestContext) {
c.JSON(consts.StatusOK, HealthSchema{Healthy: true})
})

return srv.server.Run()
Expand Down
41 changes: 41 additions & 0 deletions pkg/api/schemas/language.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package schemas

// UnifiedChatRequest defines Glide's Chat Request Schema unified across all language models
type UnifiedChatRequest struct {
Message ChatMessage `json:"message"`
MessageHistory []ChatMessage `json:"messageHistory"`
}

// UnifiedChatResponse defines Glide's Chat Response Schema unified across all language models
type UnifiedChatResponse struct {
ID string `json:"id,omitempty"`
Created float64 `json:"created,omitempty"`
Choices []*ChatChoice `json:"choices,omitempty"`
Model string `json:"model,omitempty"`
Object string `json:"object,omitempty"` // TODO: what does this mean "Object"?
Usage Usage `json:"usage,omitempty"`
}

// ChatMessage is a message in a chat request.
type ChatMessage struct {
// The role of the author of this message. One of system, user, or assistant.
Role string `json:"role"`
// The content of the message.
Content string `json:"content"`
// The name of the author of this message. May contain a-z, A-Z, 0-9, and underscores,
// with a maximum length of 64 characters.
Name string `json:"name,omitempty"`
}

// ChatChoice is a choice in a chat response.
type ChatChoice struct {
Index int `json:"index"`
Message ChatMessage `json:"message"`
FinishReason string `json:"finish_reason"`
}

type Usage struct {
CompletionTokens float64 `json:"completion_tokens,omitempty"`
PromptTokens float64 `json:"prompt_tokens,omitempty"`
TotalTokens float64 `json:"total_tokens,omitempty"`
}
5 changes: 3 additions & 2 deletions pkg/api/servers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import (
"context"
"sync"

"glide/pkg/pools"
"glide/pkg/routers"

"glide/pkg/telemetry"

"glide/pkg/api/http"
Expand All @@ -15,7 +16,7 @@ type ServerManager struct {
shutdownWG *sync.WaitGroup
}

func NewServerManager(httpConfig *http.ServerConfig, tel *telemetry.Telemetry, router *pools.Router) (*ServerManager, error) {
func NewServerManager(httpConfig *http.ServerConfig, tel *telemetry.Telemetry, router *routers.RouterManager) (*ServerManager, error) {
httpServer, err := http.NewServer(httpConfig, tel, router)
if err != nil {
return nil, err
Expand Down
3 changes: 3 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ package config

import (
"glide/pkg/api"
"glide/pkg/routers"
"glide/pkg/telemetry"
)

// Config is a general top-level Glide configuration
type Config struct {
Telemetry *telemetry.Config `yaml:"telemetry"`
API *api.Config `yaml:"api"`
Routers routers.Config `yaml:"routers"`
}

func DefaultConfig() *Config {
return &Config{
Telemetry: telemetry.DefaultConfig(),
API: api.DefaultConfig(),
// Routers should be defined by users
}
}
2 changes: 1 addition & 1 deletion pkg/config/secret.go → pkg/config/fields/secret.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package config
package fields

import "encoding"

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package config
package fields

import (
"testing"
Expand Down
24 changes: 24 additions & 0 deletions pkg/config/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,27 @@ func TestConfigProvider_NonYAMLConfigFile(t *testing.T) {
require.Error(t, err)
require.ErrorContains(t, err, "unable to parse config file")
}

func TestConfigProvider_ValidConfigLoaded(t *testing.T) {
configProvider := NewProvider()
configProvider, err := configProvider.Load("./testdata/provider.fullconfig.yaml")
require.NoError(t, err)

cfg := configProvider.Get()

langRouters := cfg.Routers.LanguageRouters

require.Len(t, langRouters, 1)
require.True(t, langRouters[0].Enabled)

models := langRouters[0].Models
require.Len(t, models, 1)
}

func TestConfigProvider_NoProvider(t *testing.T) {
configProvider := NewProvider()
_, err := configProvider.Load("./testdata/provider.nomodelprovider.yaml")

require.Error(t, err)
require.ErrorContains(t, err, "none is configured")
}
17 changes: 17 additions & 0 deletions pkg/config/testdata/provider.fullconfig.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
telemetry:
logging:
level: INFO # DEBUG, INFO, WARNING, ERROR, FATAL
encoding: json # console, json

routers:
language:
- id: simplerouter
strategy: priority
models:
- id: openai-boring
openai:
model: gpt-3.5-turbo
api_key: "ABSC@124"
default_params:
temperature: 0

12 changes: 12 additions & 0 deletions pkg/config/testdata/provider.nomodelprovider.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
telemetry:
logging:
level: INFO # DEBUG, INFO, WARNING, ERROR, FATAL
encoding: json # console, json

routers:
language:
- id: simplerouter
strategy: priority
models:
- id: openaimodel

8 changes: 4 additions & 4 deletions pkg/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import (
"os/signal"
"syscall"

"glide/pkg/config"
"glide/pkg/routers"

"glide/pkg/pools"
"glide/pkg/config"

"glide/pkg/telemetry"
"go.uber.org/zap"
Expand Down Expand Up @@ -43,12 +43,12 @@ func NewGateway(configProvider *config.Provider) (*Gateway, error) {
return nil, err
}

router, err := pools.NewRouter(tel)
routerManager, err := routers.NewManager(&cfg.Routers, tel)
if err != nil {
return nil, err
}

serverManager, err := api.NewServerManager(&http.ServerConfig{}, tel, router)
serverManager, err := api.NewServerManager(&http.ServerConfig{}, tel, routerManager)
if err != nil {
return nil, err
}
Expand Down
13 changes: 0 additions & 13 deletions pkg/pools/router.go

This file was deleted.

12 changes: 12 additions & 0 deletions pkg/providers/language.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package providers

import (
"context"

"glide/pkg/api/schemas"
)

// ChatModel defines the interface a provider should fulfill to be able to serve language chat requests
type ChatModel interface {
Chat(ctx *context.Context, request *schemas.UnifiedChatRequest) (*schemas.UnifiedChatResponse, error)
}
Loading

0 comments on commit ae3cf1b

Please sign in to comment.