feat: 重构为 Go Web 脚手架——在线图片识别 Web 服务 + vision-cli 独立工具
- Gin + config.yaml + SQLite 后端骨架,JWT 登录 + 管理员初始化
- web/ 原生单页:拖拽多图上传 → Agnes 免费识别 → 结果复制
- HTTP API:/api/v1/vision/analyze 免鉴权 + 令牌桶限流,支持程序直调
- cmd/vision-cli 独立 CLI 工具(复用 service 层,不依赖 Web 服务)
- build.bat / build.sh 构建脚本,移除 mcp-server
- 统一响应格式 {code, message, data},CORS/JWT/限流中间件
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
91
internal/config/config.go
Normal file
91
internal/config/config.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Config 是应用统一配置,对应 config.yaml。
|
||||
type Config struct {
|
||||
Server ServerConfig `yaml:"server"`
|
||||
Database DatabaseConfig `yaml:"database"`
|
||||
JWT JWTConfig `yaml:"jwt"`
|
||||
Upload UploadConfig `yaml:"upload"`
|
||||
AI AIConfig `yaml:"ai"`
|
||||
Env EnvConfig `yaml:"env"`
|
||||
}
|
||||
|
||||
type ServerConfig struct {
|
||||
Port int `yaml:"port"`
|
||||
}
|
||||
|
||||
type DatabaseConfig struct {
|
||||
Driver string `yaml:"driver"`
|
||||
Path string `yaml:"path"`
|
||||
AutoMigrate bool `yaml:"auto_migrate"`
|
||||
}
|
||||
|
||||
type JWTConfig struct {
|
||||
Secret string `yaml:"secret"`
|
||||
ExpireHours int `yaml:"expire_hours"`
|
||||
}
|
||||
|
||||
type UploadConfig struct {
|
||||
Path string `yaml:"path"`
|
||||
MaxSize int64 `yaml:"max_size"`
|
||||
}
|
||||
|
||||
type AIConfig struct {
|
||||
APIKey string `yaml:"api_key"`
|
||||
BaseURL string `yaml:"base_url"`
|
||||
Model string `yaml:"model"`
|
||||
}
|
||||
|
||||
type EnvConfig struct {
|
||||
Name string `yaml:"name"`
|
||||
}
|
||||
|
||||
// hardcodedAPIKey 内置默认免费 Key(与 config.yaml 一致),
|
||||
// 保证 CLI 工具在无配置文件时也能开箱即用。
|
||||
const hardcodedAPIKey = "sk-68FL9xXRrJhxcY5TCGxoaFlQ94oCBioIJhyGfeDMCkCvA0SV"
|
||||
|
||||
// DefaultConfig 返回开箱即用的默认配置。
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Server: ServerConfig{Port: 8080},
|
||||
Database: DatabaseConfig{Driver: "sqlite", Path: "./data/app.db", AutoMigrate: true},
|
||||
JWT: JWTConfig{Secret: "change-me-in-production", ExpireHours: 720},
|
||||
Upload: UploadConfig{Path: "uploads", MaxSize: 10 * 1024 * 1024},
|
||||
AI: AIConfig{
|
||||
APIKey: hardcodedAPIKey,
|
||||
Model: "agnes-2.0-flash",
|
||||
BaseURL: "https://apihub.agnes-ai.com/v1/chat/completions",
|
||||
},
|
||||
Env: EnvConfig{Name: "dev"},
|
||||
}
|
||||
}
|
||||
|
||||
// Load 从 yaml 文件加载配置;文件不存在时使用默认值(便于快速上手)。
|
||||
// 环境变量覆盖:AGNES_API_KEY → ai.api_key。
|
||||
func Load(path string) (*Config, error) {
|
||||
cfg := DefaultConfig()
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return cfg, nil
|
||||
}
|
||||
return nil, fmt.Errorf("读取 %s: %w", path, err)
|
||||
}
|
||||
if err := yaml.Unmarshal(data, cfg); err != nil {
|
||||
return nil, fmt.Errorf("解析 %s: %w", path, err)
|
||||
}
|
||||
|
||||
// 环境变量覆盖
|
||||
if key := os.Getenv("AGNES_API_KEY"); key != "" {
|
||||
cfg.AI.APIKey = key
|
||||
}
|
||||
return cfg, nil
|
||||
}
|
||||
Reference in New Issue
Block a user