Merge pull request #87 from svc-design/codex/update-config-code-for-new-format
refactor: update server config structure
This commit is contained in:
commit
f46c58efd6
@ -22,7 +22,7 @@ func main() {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
slog.Warn("load config", "err", err)
|
||||
cfg = &config.Server{}
|
||||
cfg = &config.Config{}
|
||||
}
|
||||
|
||||
level := slog.LevelInfo
|
||||
@ -38,7 +38,7 @@ func main() {
|
||||
slog.SetDefault(logger)
|
||||
|
||||
var conn *pgx.Conn
|
||||
if dsn := cfg.Postgres.DSN; dsn != "" {
|
||||
if dsn := cfg.Global.VectorDB.DSN(); dsn != "" {
|
||||
logger.Debug("connecting to postgres", "dsn", dsn)
|
||||
conn, err = pgx.Connect(context.Background(), dsn)
|
||||
if err != nil {
|
||||
@ -50,11 +50,11 @@ func main() {
|
||||
logger.Warn("postgres dsn not provided")
|
||||
}
|
||||
|
||||
if addr := cfg.Redis.Addr; addr != "" {
|
||||
if addr := cfg.Global.Redis.Addr; addr != "" {
|
||||
logger.Debug("connecting to redis", "addr", addr)
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: addr,
|
||||
Password: cfg.Redis.Password,
|
||||
Password: cfg.Global.Redis.Password,
|
||||
})
|
||||
if err := rdb.Ping(context.Background()).Err(); err != nil {
|
||||
logger.Error("redis connect error", "err", err)
|
||||
|
||||
@ -45,19 +45,25 @@ func registerAskAIRoutes(r *gin.RouterGroup) {
|
||||
const chutesURL = "https://llm.chutes.ai/v1/chat/completions"
|
||||
|
||||
type serverConfig struct {
|
||||
Env map[string]string `yaml:"env"`
|
||||
Model []string `yaml:"model"`
|
||||
AskAI struct {
|
||||
Timeout int `yaml:"timeout"` // seconds
|
||||
Retries int `yaml:"retries"`
|
||||
} `yaml:"askai"`
|
||||
LLM struct {
|
||||
URL string `yaml:"url"`
|
||||
Token string `yaml:"token"`
|
||||
Models []string `yaml:"models"`
|
||||
} `yaml:"llm"`
|
||||
API struct {
|
||||
AskAI struct {
|
||||
Timeout int `yaml:"timeout"` // seconds
|
||||
Retries int `yaml:"retries"`
|
||||
} `yaml:"askai"`
|
||||
} `yaml:"api"`
|
||||
}
|
||||
|
||||
// loadConfig attempts to read CHUTES_API_TOKEN, model, timeout and retries from
|
||||
// loadConfig attempts to read CHUTES_API_TOKEN, model, URL, timeout and retries from
|
||||
// environment variables, falling back to config/server.yaml.
|
||||
func loadConfig() (string, string, time.Duration, int) {
|
||||
func loadConfig() (string, string, string, time.Duration, int) {
|
||||
token := os.Getenv("CHUTES_API_TOKEN")
|
||||
model := os.Getenv("CHUTES_API_MODEL")
|
||||
url := os.Getenv("CHUTES_API_URL")
|
||||
timeout := 30 * time.Second
|
||||
retries := 3
|
||||
path := filepath.Join("server", "config", "server.yaml")
|
||||
@ -66,16 +72,19 @@ func loadConfig() (string, string, time.Duration, int) {
|
||||
var cfg serverConfig
|
||||
if err := yaml.Unmarshal(data, &cfg); err == nil {
|
||||
if token == "" {
|
||||
token = cfg.Env["CHUTES_API_TOKEN"]
|
||||
token = cfg.LLM.Token
|
||||
}
|
||||
if model == "" && len(cfg.Model) > 0 {
|
||||
model = cfg.Model[0]
|
||||
if model == "" && len(cfg.LLM.Models) > 0 {
|
||||
model = cfg.LLM.Models[0]
|
||||
}
|
||||
if cfg.AskAI.Timeout > 0 {
|
||||
timeout = time.Duration(cfg.AskAI.Timeout) * time.Second
|
||||
if url == "" {
|
||||
url = cfg.LLM.URL
|
||||
}
|
||||
if cfg.AskAI.Retries > 0 {
|
||||
retries = cfg.AskAI.Retries
|
||||
if cfg.API.AskAI.Timeout > 0 {
|
||||
timeout = time.Duration(cfg.API.AskAI.Timeout) * time.Second
|
||||
}
|
||||
if cfg.API.AskAI.Retries > 0 {
|
||||
retries = cfg.API.AskAI.Retries
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,19 +97,18 @@ func loadConfig() (string, string, time.Duration, int) {
|
||||
if model == "" {
|
||||
model = "deepseek-ai/DeepSeek-R1"
|
||||
}
|
||||
return token, model, timeout, retries
|
||||
if url == "" {
|
||||
url = chutesURL
|
||||
}
|
||||
return token, model, url, timeout, retries
|
||||
}
|
||||
|
||||
// callChutes sends the question to the hosted LLM service and returns the reply.
|
||||
func callChutes(question string) (string, error) {
|
||||
token, model, timeout, retries := loadConfig()
|
||||
token, model, url, timeout, retries := loadConfig()
|
||||
if token == "" {
|
||||
return "", errors.New("CHUTES_API_TOKEN not set")
|
||||
}
|
||||
url := os.Getenv("CHUTES_API_URL")
|
||||
if url == "" {
|
||||
url = chutesURL
|
||||
}
|
||||
|
||||
reqBody := map[string]interface{}{
|
||||
"model": model,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@ -16,24 +17,74 @@ type Redis struct {
|
||||
Password string `yaml:"password"`
|
||||
}
|
||||
|
||||
type Postgres struct {
|
||||
DSN string `yaml:"dsn"`
|
||||
type VectorDB struct {
|
||||
PGURL string `yaml:"pgurl"`
|
||||
PGHost string `yaml:"pg_host"`
|
||||
PGPort int `yaml:"pg_port"`
|
||||
PGUser string `yaml:"pg_user"`
|
||||
PGPassword string `yaml:"pg_password"`
|
||||
PGDBName string `yaml:"pg_db_name"`
|
||||
PGSSLMode string `yaml:"pg_sslmode"`
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
Log Log `yaml:"log"`
|
||||
Redis Redis `yaml:"redis"`
|
||||
Postgres Postgres `yaml:"postgres"`
|
||||
func (v VectorDB) DSN() string {
|
||||
if v.PGURL != "" {
|
||||
return v.PGURL
|
||||
}
|
||||
if v.PGHost == "" || v.PGUser == "" || v.PGDBName == "" {
|
||||
return ""
|
||||
}
|
||||
port := v.PGPort
|
||||
if port == 0 {
|
||||
port = 5432
|
||||
}
|
||||
ssl := v.PGSSLMode
|
||||
if ssl == "" {
|
||||
ssl = "require"
|
||||
}
|
||||
return fmt.Sprintf("postgres://%s:%s@%s:%d/%s?sslmode=%s", v.PGUser, v.PGPassword, v.PGHost, port, v.PGDBName, ssl)
|
||||
}
|
||||
|
||||
// Load reads server/config/server.yaml and unmarshals into Server struct.
|
||||
func Load() (*Server, error) {
|
||||
type Datasource struct {
|
||||
Name string `yaml:"name"`
|
||||
Repo string `yaml:"repo"`
|
||||
Path string `yaml:"path"`
|
||||
}
|
||||
|
||||
type Global struct {
|
||||
Redis Redis `yaml:"redis"`
|
||||
VectorDB VectorDB `yaml:"vectordb"`
|
||||
Datasources []Datasource `yaml:"datasources"`
|
||||
}
|
||||
|
||||
type LLM struct {
|
||||
URL string `yaml:"url"`
|
||||
Token string `yaml:"token"`
|
||||
Models []string `yaml:"models"`
|
||||
}
|
||||
|
||||
type API struct {
|
||||
AskAI struct {
|
||||
Timeout int `yaml:"timeout"`
|
||||
Retries int `yaml:"retries"`
|
||||
} `yaml:"askai"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Log Log `yaml:"log"`
|
||||
Global Global `yaml:"global"`
|
||||
LLM LLM `yaml:"llm"`
|
||||
API API `yaml:"api"`
|
||||
}
|
||||
|
||||
// Load reads server/config/server.yaml and unmarshals into Config struct.
|
||||
func Load() (*Config, error) {
|
||||
path := filepath.Join("server", "config", "server.yaml")
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var cfg Server
|
||||
var cfg Config
|
||||
if err := yaml.Unmarshal(b, &cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -21,7 +21,10 @@ func TestLoad(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Load returned error: %v", err)
|
||||
}
|
||||
if cfg.Log.Level != "info" {
|
||||
t.Fatalf("unexpected log level %q", cfg.Log.Level)
|
||||
if cfg.Global.Redis.Addr != "127.0.0.1:6479" {
|
||||
t.Fatalf("unexpected redis addr %q", cfg.Global.Redis.Addr)
|
||||
}
|
||||
if cfg.API.AskAI.Timeout != 100 {
|
||||
t.Fatalf("unexpected askai timeout %d", cfg.API.AskAI.Timeout)
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,17 +50,26 @@ func (c *Config) ResolveEmbedding() RuntimeEmbedding {
|
||||
return rt
|
||||
}
|
||||
|
||||
// ResolveChunking returns chunking configuration with defaults applied.
|
||||
func (c *Config) ResolveChunking() ChunkingCfg {
|
||||
ch := c.Chunking
|
||||
if ch.MaxTokens == 0 {
|
||||
ch.MaxTokens = 800
|
||||
// LoadServer loads global configuration from server/config/server.yaml.
|
||||
func LoadServer() (*Runtime, error) {
|
||||
path := filepath.Join("server", "config", "server.yaml")
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var cfg struct {
|
||||
Global Runtime `yaml:"global"`
|
||||
}
|
||||
if ch.OverlapTokens == 0 {
|
||||
ch.OverlapTokens = 80
|
||||
}
|
||||
if len(ch.IncludeExts) == 0 {
|
||||
ch.IncludeExts = []string{".md", ".mdx"}
|
||||
return &cfg.Global, nil
|
||||
}
|
||||
|
||||
// ToConfig converts runtime configuration into service configuration.
|
||||
func (rt *Runtime) ToConfig() *Config {
|
||||
if rt == nil {
|
||||
return nil
|
||||
}
|
||||
if len(ch.IgnoreDirs) == 0 {
|
||||
ch.IgnoreDirs = []string{".git", "node_modules", "dist", "build"}
|
||||
|
||||
@ -12,8 +12,11 @@ import (
|
||||
|
||||
// Config represents server configuration loaded from YAML.
|
||||
type Config struct {
|
||||
Env map[string]string `yaml:"env"`
|
||||
Model []string `yaml:"model"`
|
||||
LLM struct {
|
||||
URL string `yaml:"url"`
|
||||
Token string `yaml:"token"`
|
||||
Models []string `yaml:"models"`
|
||||
} `yaml:"llm"`
|
||||
}
|
||||
|
||||
// cfg holds the loaded configuration.
|
||||
@ -31,8 +34,14 @@ func loadConfig() {
|
||||
log.Printf("server config parse: %v", err)
|
||||
return
|
||||
}
|
||||
for k, v := range cfg.Env {
|
||||
os.Setenv(k, v)
|
||||
if cfg.LLM.Token != "" {
|
||||
os.Setenv("CHUTES_API_TOKEN", cfg.LLM.Token)
|
||||
}
|
||||
if cfg.LLM.URL != "" {
|
||||
os.Setenv("CHUTES_API_URL", cfg.LLM.URL)
|
||||
}
|
||||
if len(cfg.LLM.Models) > 0 {
|
||||
os.Setenv("CHUTES_API_MODEL", cfg.LLM.Models[0])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user