diff --git a/.gitignore b/.gitignore index dc1f824..1fa64c0 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,6 @@ # Backend backend/bin/ -backend/data/ \ No newline at end of file +backend/data/ +backend/.env +backend/main diff --git a/backend/.env.example b/backend/.env.example new file mode 100644 index 0000000..97bf0b8 --- /dev/null +++ b/backend/.env.example @@ -0,0 +1,30 @@ +# gen2d 后端环境变量 +# 复制此文件为 .env 并填入你的实际配置 + +# 服务基础配置 +GEN2D_PORT=8080 +GEN2D_MODE=debug + +# SQLite 数据库路径 +GEN2D_DSN=data/gen2d.db + +# JWT 密钥与过期时间(秒) +GEN2D_JWT_SECRET=your-jwt-secret-here +GEN2D_JWT_EXPIRE=7200 + +# 大语言模型(OpenAI 兼容接口) +GEN2D_LLM_BASE_URL=https://api.openai.com/v1 +GEN2D_LLM_API_KEY=sk-your-api-key +GEN2D_LLM_MODEL=gpt-4o +GEN2D_LLM_TEMPERATURE=0.7 +GEN2D_LLM_MAX_TOKENS=2048 + +# 文生图模型 +GEN2D_IMAGE_BASE_URL=https://api.stability.ai/v1 +GEN2D_IMAGE_API_KEY=sk-your-api-key +GEN2D_IMAGE_MODEL=stable-diffusion-xl +GEN2D_IMAGE_WIDTH=1024 +GEN2D_IMAGE_HEIGHT=1024 +GEN2D_IMAGE_NUM_IMAGES=1 +GEN2D_IMAGE_STEPS=30 +GEN2D_IMAGE_CFG_SCALE=7.0 diff --git a/backend/go.mod b/backend/go.mod index 35002f7..8b21941 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -5,6 +5,9 @@ go 1.26.3 require ( github.com/cloudwego/eino v0.8.13 github.com/gin-gonic/gin v1.12.0 + github.com/golang-jwt/jwt/v5 v5.3.1 + github.com/joho/godotenv v1.5.1 + github.com/spf13/viper v1.21.0 golang.org/x/crypto v0.48.0 gorm.io/driver/sqlite v1.6.0 gorm.io/gorm v1.31.1 @@ -19,14 +22,15 @@ require ( github.com/cloudwego/base64x v0.1.6 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/eino-contrib/jsonschema v1.0.3 // indirect + github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/gabriel-vasile/mimetype v1.4.12 // indirect github.com/gin-contrib/sse v1.1.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.30.1 // indirect + github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-yaml v1.19.2 // indirect - github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/goph/emperror v0.17.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect @@ -44,13 +48,20 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.59.0 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f // indirect + github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect + github.com/spf13/afero v1.15.0 // indirect + github.com/spf13/cast v1.10.0 // indirect + github.com/spf13/pflag v1.0.10 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/yargevad/filepathx v1.0.0 // indirect go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.22.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect golang.org/x/net v0.51.0 // indirect diff --git a/backend/go.sum b/backend/go.sum index 90a9615..e6265f5 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -25,7 +25,11 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/eino-contrib/jsonschema v1.0.3 h1:2Kfsm1xlMV0ssY2nuxshS4AwbLFuqmPmzIjLVJ1Fsp0= github.com/eino-contrib/jsonschema v1.0.3/go.mod h1:cpnX4SyKjWjGC7iN2EbhxaTdLqGjCi0e9DxpLYxddD4= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= +github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= @@ -43,6 +47,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= +github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= +github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= @@ -65,6 +71,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -117,6 +125,8 @@ github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRC github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rollbar/rollbar-go v1.0.2/go.mod h1:AcFs5f0I+c71bpHlXNNDbOWJiKwjFDtISeXco0L5PKQ= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -126,6 +136,16 @@ github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGB github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= +github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -140,6 +160,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= @@ -154,6 +176,8 @@ go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI= golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/backend/internal/config/config.go b/backend/internal/config/config.go index 7d954a3..62359f3 100644 --- a/backend/internal/config/config.go +++ b/backend/internal/config/config.go @@ -1,55 +1,138 @@ -// Package config 负责从环境变量加载应用配置。 package config import ( - "os" - "strconv" + "log" + + "github.com/joho/godotenv" + "github.com/spf13/viper" ) -// Config 应用全局配置,优先读取环境变量,未设置时使用默认值。 +// Config 应用全局配置。 type Config struct { - Port int // HTTP 监听端口,默认 8080,环境变量 GEN2D_PORT - Mode string // Gin 运行模式 (debug/release),环境变量 GEN2D_MODE - MaxFileSize int64 // 上传文件大小上限(字节),默认 10MB - DSN string // SQLite 数据库路径,默认 data/gen2d.db,环境变量 GEN2D_DSN - JWTSecret string // JWT 签名密钥,环境变量 GEN2D_JWT_SECRET - JWTExpire int64 // JWT 过期时间(秒),默认 7200 + Server ServerConfig `mapstructure:"server"` + Database DatabaseConfig `mapstructure:"database"` + JWT JWTConfig `mapstructure:"jwt"` + LLM LLMConfig `mapstructure:"llm"` + ImageGen ImageGenConfig `mapstructure:"image_gen"` } -// Load 从环境变量加载配置并返回。 +// ServerConfig HTTP 服务配置。 +type ServerConfig struct { + Port int `mapstructure:"port"` + Mode string `mapstructure:"mode"` + MaxFileSize int64 `mapstructure:"max_file_size"` +} + +// DatabaseConfig 数据库配置。 +type DatabaseConfig struct { + DSN string `mapstructure:"dsn"` +} + +// JWTConfig JWT 签名配置。 +type JWTConfig struct { + Secret string `mapstructure:"secret"` + Expire int64 `mapstructure:"expire"` +} + +// LLMConfig 大语言模型配置。 +type LLMConfig struct { + BaseURL string `mapstructure:"base_url"` + APIKey string `mapstructure:"api_key"` + Model string `mapstructure:"model"` + Temperature float64 `mapstructure:"temperature"` + MaxTokens int `mapstructure:"max_tokens"` +} + +// ImageGenConfig 文生图模型配置。 +type ImageGenConfig struct { + BaseURL string `mapstructure:"base_url"` + APIKey string `mapstructure:"api_key"` + Model string `mapstructure:"model"` + Width int `mapstructure:"width"` + Height int `mapstructure:"height"` + NumImages int `mapstructure:"num_images"` + Steps int `mapstructure:"steps"` + CFGScale float64 `mapstructure:"cfg_scale"` +} + +// Load 从 YAML 配置文件和环境变量加载配置。 +// 优先级:环境变量 > YAML 文件 > 默认值。 func Load() *Config { - cfg := &Config{ - Port: 8080, - Mode: "debug", - MaxFileSize: 10 << 20, // 10MB - DSN: "data/gen2d.db", - JWTSecret: "gen2d-dev-secret", - JWTExpire: 7200, + if err := godotenv.Load(); err != nil { + log.Println("config: no .env file found, using system env or defaults") } - if port := os.Getenv("GEN2D_PORT"); port != "" { - if p, err := strconv.Atoi(port); err == nil { - cfg.Port = p - } + v := viper.New() + v.SetConfigName("config") + v.SetConfigType("yaml") + v.AddConfigPath("internal/config") + + setDefaults(v) + + if err := v.ReadInConfig(); err != nil { + log.Printf("config: could not read config file: %v, using env + defaults", err) + } else { + log.Printf("config: using config file: %s", v.ConfigFileUsed()) } - if mode := os.Getenv("GEN2D_MODE"); mode != "" { - cfg.Mode = mode + bindEnvVars(v) + + v.AllowEmptyEnv(true) + + var cfg Config + if err := v.Unmarshal(&cfg); err != nil { + log.Fatalf("config: unmarshal failed: %v", err) } - if dsn := os.Getenv("GEN2D_DSN"); dsn != "" { - cfg.DSN = dsn - } - - if secret := os.Getenv("GEN2D_JWT_SECRET"); secret != "" { - cfg.JWTSecret = secret - } - - if expire := os.Getenv("GEN2D_JWT_EXPIRE"); expire != "" { - if e, err := strconv.ParseInt(expire, 10, 64); err == nil { - cfg.JWTExpire = e - } - } - - return cfg + return &cfg +} + +func setDefaults(v *viper.Viper) { + v.SetDefault("server.port", 8080) + v.SetDefault("server.mode", "debug") + v.SetDefault("server.max_file_size", int64(10<<20)) + + v.SetDefault("database.dsn", "data/gen2d.db") + + v.SetDefault("jwt.secret", "gen2d-dev-secret") + v.SetDefault("jwt.expire", int64(7200)) + + v.SetDefault("llm.base_url", "https://api.openai.com/v1") + v.SetDefault("llm.api_key", "") + v.SetDefault("llm.model", "gpt-4o") + v.SetDefault("llm.temperature", 0.7) + v.SetDefault("llm.max_tokens", 2048) + + v.SetDefault("image_gen.base_url", "https://api.stability.ai/v1") + v.SetDefault("image_gen.api_key", "") + v.SetDefault("image_gen.model", "stable-diffusion-xl") + v.SetDefault("image_gen.width", 1024) + v.SetDefault("image_gen.height", 1024) + v.SetDefault("image_gen.num_images", 1) + v.SetDefault("image_gen.steps", 30) + v.SetDefault("image_gen.cfg_scale", 7.0) +} + +func bindEnvVars(v *viper.Viper) { + v.BindEnv("server.port", "GEN2D_PORT") + v.BindEnv("server.mode", "GEN2D_MODE") + v.BindEnv("server.max_file_size", "GEN2D_MAX_FILE_SIZE") + v.BindEnv("database.dsn", "GEN2D_DSN") + v.BindEnv("jwt.secret", "GEN2D_JWT_SECRET") + v.BindEnv("jwt.expire", "GEN2D_JWT_EXPIRE") + + v.BindEnv("llm.base_url", "GEN2D_LLM_BASE_URL") + v.BindEnv("llm.api_key", "GEN2D_LLM_API_KEY") + v.BindEnv("llm.model", "GEN2D_LLM_MODEL") + v.BindEnv("llm.temperature", "GEN2D_LLM_TEMPERATURE") + v.BindEnv("llm.max_tokens", "GEN2D_LLM_MAX_TOKENS") + + v.BindEnv("image_gen.base_url", "GEN2D_IMAGE_BASE_URL") + v.BindEnv("image_gen.api_key", "GEN2D_IMAGE_API_KEY") + v.BindEnv("image_gen.model", "GEN2D_IMAGE_MODEL") + v.BindEnv("image_gen.width", "GEN2D_IMAGE_WIDTH") + v.BindEnv("image_gen.height", "GEN2D_IMAGE_HEIGHT") + v.BindEnv("image_gen.num_images", "GEN2D_IMAGE_NUM_IMAGES") + v.BindEnv("image_gen.steps", "GEN2D_IMAGE_STEPS") + v.BindEnv("image_gen.cfg_scale", "GEN2D_IMAGE_CFG_SCALE") } diff --git a/backend/internal/config/config.yml b/backend/internal/config/config.yml new file mode 100644 index 0000000..84475e7 --- /dev/null +++ b/backend/internal/config/config.yml @@ -0,0 +1,31 @@ +# gen2d backend configuration +# 敏感信息(api_key)请通过环境变量设置,不要直接写在文件中提交。 + +server: + port: 8080 + mode: debug + max_file_size: 10485760 # 10MB + +database: + dsn: "data/gen2d.db" + +jwt: + secret: "gen2d-dev-secret" + expire: 7200 + +llm: + base_url: "https://api.deepseek.com/v1" + api_key: "" + model: "deepseek-v4-pro" + temperature: 0.7 + max_tokens: 2048 + +image_gen: + base_url: "https://api.stability.ai/v1" + api_key: "" + model: "stable-diffusion-xl" + width: 1024 + height: 1024 + num_images: 1 + steps: 30 + cfg_scale: 7.0