feat: add cost-safe AI growth configuration
This commit is contained in:
@@ -8,21 +8,32 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
HTTPAddr string
|
||||
DatabaseURL string
|
||||
RedisAddr string
|
||||
RedisPassword string
|
||||
ImportPath string
|
||||
DemoUsername string
|
||||
DemoPassword string
|
||||
SessionSecret string
|
||||
CursorSecret string
|
||||
FrontendOrigin string
|
||||
CookieSecure bool
|
||||
AppEnv string
|
||||
HTTPAddr string
|
||||
DatabaseURL string
|
||||
RedisAddr string
|
||||
RedisPassword string
|
||||
ImportPath string
|
||||
DemoUsername string
|
||||
DemoPassword string
|
||||
SessionSecret string
|
||||
CursorSecret string
|
||||
FrontendOrigin string
|
||||
CookieSecure bool
|
||||
AIGrowthEnabled bool
|
||||
AvalAIAPIKey string
|
||||
AvalAIBaseURL string
|
||||
AvalAIModel string
|
||||
AIDailyRequestBudget int64
|
||||
AIDailyTokenBudget int64
|
||||
AIMaxConcurrent int
|
||||
AICreatePerMinute int64
|
||||
AIUncachedScopesPerDay int64
|
||||
}
|
||||
|
||||
func Load() (Config, error) {
|
||||
cfg := Config{
|
||||
AppEnv: value("APP_ENV", "development"),
|
||||
HTTPAddr: value("HTTP_ADDR", "127.0.0.1:8080"),
|
||||
DatabaseURL: os.Getenv("DATABASE_URL"),
|
||||
RedisAddr: value("REDIS_ADDR", "localhost:6379"),
|
||||
@@ -33,6 +44,9 @@ func Load() (Config, error) {
|
||||
SessionSecret: os.Getenv("SESSION_SECRET"),
|
||||
CursorSecret: os.Getenv("CURSOR_SECRET"),
|
||||
FrontendOrigin: value("FRONTEND_ORIGIN", "http://localhost:5173"),
|
||||
AvalAIAPIKey: os.Getenv("AVALAI_API_KEY"),
|
||||
AvalAIBaseURL: value("AVALAI_BASE_URL", "https://api.avalai.ir"),
|
||||
AvalAIModel: value("AVALAI_MODEL", "gpt-5-mini-2025-08-07"),
|
||||
}
|
||||
|
||||
var err error
|
||||
@@ -40,6 +54,31 @@ func Load() (Config, error) {
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("parsing cookie secure: %w", err)
|
||||
}
|
||||
cfg.AIGrowthEnabled, err = strconv.ParseBool(value("AI_GROWTH_ENABLED", "false"))
|
||||
if err != nil {
|
||||
return Config{}, fmt.Errorf("parsing AI growth enabled: %w", err)
|
||||
}
|
||||
cfg.AIDailyRequestBudget, err = parseInt64("AI_DAILY_REQUEST_BUDGET", 0)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.AIDailyTokenBudget, err = parseInt64("AI_DAILY_TOKEN_BUDGET", 0)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
maxConcurrent, err := parseInt64("AI_MAX_CONCURRENT", 4)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.AIMaxConcurrent = int(maxConcurrent)
|
||||
cfg.AICreatePerMinute, err = parseInt64("AI_CREATE_PER_MINUTE", 10)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
cfg.AIUncachedScopesPerDay, err = parseInt64("AI_UNCACHED_SCOPES_PER_DAY", 5)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
if cfg.DatabaseURL == "" {
|
||||
return Config{}, errors.New("config: DATABASE_URL is required")
|
||||
}
|
||||
@@ -56,6 +95,17 @@ func (c Config) ValidateAPI() error {
|
||||
if c.CursorSecret == c.SessionSecret {
|
||||
return errors.New("config: CURSOR_SECRET must differ from SESSION_SECRET")
|
||||
}
|
||||
if c.AIMaxConcurrent < 1 || c.AICreatePerMinute < 1 || c.AIUncachedScopesPerDay < 1 {
|
||||
return errors.New("config: AI limits must be positive")
|
||||
}
|
||||
if c.AppEnv == "production" && c.AIGrowthEnabled {
|
||||
if c.AvalAIAPIKey == "" || c.AvalAIModel == "" {
|
||||
return errors.New("config: enabled production AI requires AVALAI_API_KEY and AVALAI_MODEL")
|
||||
}
|
||||
if c.AIDailyRequestBudget < 1 || c.AIDailyTokenBudget < 1 {
|
||||
return errors.New("config: enabled production AI requires positive daily budgets")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -72,3 +122,12 @@ func value(name, fallback string) string {
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func parseInt64(name string, fallback int64) (int64, error) {
|
||||
raw := value(name, strconv.FormatInt(fallback, 10))
|
||||
parsed, err := strconv.ParseInt(raw, 10, 64)
|
||||
if err != nil || parsed < 0 {
|
||||
return 0, fmt.Errorf("config: %s must be a non-negative integer", name)
|
||||
}
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user