From 360b2a4f503143e54c8247af37e0df6396eb6689 Mon Sep 17 00:00:00 2001 From: hhs <386998068@qq.com> Date: Sat, 13 Jun 2026 13:31:48 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E8=A7=84=E8=8C=83=EF=BC=88Viper=20+=20?= =?UTF-8?q?=E7=8E=AF=E5=A2=83=E5=8F=98=E9=87=8F=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 03-接口文档: 新增第六章配置管理(Go 配置结构体、YAML 配置示例、环境变量覆盖规则、Viper 加载代码、启动命令示例) - 03-接口文档: 原七~九章重新编号为八~十章 - 02-系统架构: 配置管理行补充交叉引用 - README.md: 索引补充配置管理关键词 --- docs/02-系统架构.md | 2 +- docs/03-接口文档.md | 237 +++++++++++++++++++++++++++++++++++++++++++- docs/README.md | 2 +- 3 files changed, 235 insertions(+), 6 deletions(-) diff --git a/docs/02-系统架构.md b/docs/02-系统架构.md index cbc1506..9dd6a5f 100644 --- a/docs/02-系统架构.md +++ b/docs/02-系统架构.md @@ -35,7 +35,7 @@ | WebSocket | gorilla/websocket | Go 生态最成熟的 WebSocket 库 | | 会话存储 | Redis | 高速 KV 存储,适合会话状态和上下文缓存 | | 持久化存储 | PostgreSQL | 对话历史、用量统计、用户偏好(MVP 阶段可选) | -| 配置管理 | Viper | 支持多格式配置,环境变量覆盖 | +| 配置管理 | Viper | 支持 YAML + 环境变量覆盖,详见 `03-接口文档.md` 第六章 | | 日志 | Zap | 高性能结构化日志 | ### AI 服务 diff --git a/docs/03-接口文档.md b/docs/03-接口文档.md index e8e5380..32b6974 100644 --- a/docs/03-接口文档.md +++ b/docs/03-接口文档.md @@ -673,7 +673,236 @@ if cfg.Redis.Addr != "" { --- -## 六、数据模型 +## 六、配置管理 + +使用 Viper 加载配置,支持 YAML 文件 + 环境变量覆盖。**环境变量优先级高于配置文件**。 + +### 配置文件位置 + +``` +backend/config.yaml # 默认加载 +backend/config.dev.yaml # 开发环境(go run 时使用) +backend/config.prod.yaml # 生产环境 +``` + +Viper 加载顺序:先读 `config.yaml`,再根据 `APP_ENV` 环境变量尝试读 `config.{env}.yaml` 覆盖,最后所有环境变量自动覆盖对应字段。 + +### Go 配置结构体 + +```go +// Config 应用配置。 +type Config struct { + App AppConfig `mapstructure:"app"` + Server ServerConfig `mapstructure:"server"` + Redis RedisConfig `mapstructure:"redis"` + AI AIConfig `mapstructure:"ai"` + Storage StorageConfig `mapstructure:"storage"` + Log LogConfig `mapstructure:"log"` +} + +type AppConfig struct { + Env string `mapstructure:"env"` // "dev" | "prod",默认 "dev" + Version string `mapstructure:"version"` // 由编译时注入 +} + +type ServerConfig struct { + Host string `mapstructure:"host"` // 默认 "0.0.0.0" + Port int `mapstructure:"port"` // 默认 8080 + ReadTimeout int `mapstructure:"read_timeout"` // 秒,默认 30 + WriteTimeout int `mapstructure:"write_timeout"` // 秒,默认 30 +} + +type RedisConfig struct { + Addr string `mapstructure:"addr"` // "localhost:6379" + Password string `mapstructure:"password"` // 无密码留空 + DB int `mapstructure:"db"` // 默认 0 +} + +type AIConfig struct { + STT STTConfig `mapstructure:"stt"` + LLM LLMConfig `mapstructure:"llm"` + TTS TTSConfig `mapstructure:"tts"` +} + +type STTConfig struct { + Provider string `mapstructure:"provider"` // "deepgram" + APIKey string `mapstructure:"api_key"` + Endpoint string `mapstructure:"endpoint"` // 默认 "wss://api.deepgram.com/v1/listen" +} + +type LLMConfig struct { + Provider string `mapstructure:"provider"` // "openai" + APIKey string `mapstructure:"api_key"` + Model string `mapstructure:"model"` // 默认 "gpt-4o" + Endpoint string `mapstructure:"endpoint"` // 默认 "https://api.openai.com/v1" + Timeout int `mapstructure:"timeout"` // 秒,默认 10 +} + +type TTSConfig struct { + Provider string `mapstructure:"provider"` // "openai" + APIKey string `mapstructure:"api_key"` + Voice string `mapstructure:"voice"` // 默认 "alloy" + Speed float64 `mapstructure:"speed"` // 默认 1.0 + Endpoint string `mapstructure:"endpoint"` // 默认 "https://api.openai.com/v1" + Timeout int `mapstructure:"timeout"` // 秒,默认 5 +} + +type StorageConfig struct { + Driver string `mapstructure:"driver"` // "memory" | "postgres" + DSN string `mapstructure:"dsn"` // PostgreSQL 连接串,driver=postgres 时必填 +} + +type LogConfig struct { + Level string `mapstructure:"level"` // "debug" | "info" | "warn" | "error",默认 "info" + Format string `mapstructure:"format"` // "json" | "console",生产用 json +} +``` + +### 配置文件示例 + +```yaml +# config.yaml — 所有环境共享的默认值 +app: + env: dev + +server: + host: "0.0.0.0" + port: 8080 + read_timeout: 30 + write_timeout: 30 + +redis: + addr: "localhost:6379" + password: "" + db: 0 + +ai: + stt: + provider: deepgram + endpoint: "wss://api.deepgram.com/v1/listen" + llm: + provider: openai + model: gpt-4o + endpoint: "https://api.openai.com/v1" + timeout: 10 + tts: + provider: openai + voice: alloy + speed: 1.0 + endpoint: "https://api.openai.com/v1" + timeout: 5 + +storage: + driver: memory + +log: + level: info + format: console +``` + +### 环境变量覆盖规则 + +Viper 自动将配置项映射为环境变量,规则:**前缀 `CAMTALK_` + 路径大写用 `_` 连接**。 + +| 配置项 | 环境变量 | 示例 | +|--------|---------|------| +| `server.port` | `CAMTALK_SERVER_PORT` | `8080` | +| `redis.addr` | `CAMTALK_REDIS_ADDR` | `redis:6379` | +| `redis.password` | `CAMTALK_REDIS_PASSWORD` | — | +| `ai.stt.api_key` | `CAMTALK_AI_STT_API_KEY` | — | +| `ai.llm.api_key` | `CAMTALK_AI_LLM_API_KEY` | — | +| `ai.tts.api_key` | `CAMTALK_AI_TTS_API_KEY` | — | +| `ai.llm.model` | `CAMTALK_AI_LLM_MODEL` | `gpt-4o` | +| `storage.driver` | `CAMTALK_STORAGE_DRIVER` | `postgres` | +| `storage.dsn` | `CAMTALK_STORAGE_DSN` | — | +| `app.env` | `CAMTALK_APP_ENV` | `prod` | +| `log.level` | `CAMTALK_LOG_LEVEL` | `warn` | +| `log.format` | `CAMTALK_LOG_FORMAT` | `json` | + +> API Key 和密码**只通过环境变量注入**,不写入配置文件,避免泄露到版本控制。 + +### 配置加载代码 + +```go +// internal/config/config.go + +func Load() (*Config, error) { + v := viper.New() + + // 1. 读默认配置文件 + v.SetConfigName("config") + v.SetConfigType("yaml") + v.AddConfigPath("./config") // go run 时 + v.AddConfigPath(".") // 二进制运行时 + if err := v.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); !ok { + return nil, fmt.Errorf("read config: %w", err) + } + } + + // 2. 按环境覆盖 + env := os.Getenv("CAMTALK_APP_ENV") + if env == "" { + env = "dev" + } + v.SetConfigName("config." + env) + v.MergeInConfig() // 忽略文件不存在 + + // 3. 环境变量覆盖 + v.SetEnvPrefix("CAMTALK") + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + v.AutomaticEnv() + + // 4. 解析 + var cfg Config + if err := v.Unmarshal(&cfg); err != nil { + return nil, fmt.Errorf("unmarshal config: %w", err) + } + return &cfg, nil +} +``` + +### main.go 集成 + +```go +func main() { + cfg, err := config.Load() + if err != nil { + log.Fatalf("load config: %v", err) + } + + r := gin.Default() + // 使用 cfg.Server.Port 替代硬编码 :8080 + addr := fmt.Sprintf("%s:%d", cfg.Server.Host, cfg.Server.Port) + log.Printf("CamTalk gateway starting on %s (env=%s)", addr, cfg.App.Env) + r.Run(addr) +} +``` + +### 启动方式 + +```bash +# 开发环境(默认 config.yaml,API Key 通过环境变量注入) +CAMTALK_AI_LLM_API_KEY=sk-xxx \ +CAMTALK_AI_STT_API_KEY=xxx \ +go run ./cmd/server + +# 生产环境 +CAMTALK_APP_ENV=prod \ +CAMTALK_REDIS_ADDR=redis:6379 \ +CAMTALK_AI_LLM_API_KEY=sk-xxx \ +CAMTALK_AI_STT_API_KEY=xxx \ +CAMTALK_AI_TTS_API_KEY=xxx \ +CAMTALK_STORAGE_DRIVER=postgres \ +CAMTALK_STORAGE_DSN="postgres://user:pass@db:5432/camtalk?sslmode=disable" \ +CAMTALK_LOG_LEVEL=warn \ +CAMTALK_LOG_FORMAT=json \ +./bin/camtalk +``` + +--- + +## 七、数据模型 > 注:Go 和 TypeScript 的数据模型定义见下方。AI 服务层的 Go 模型见上方"AI 服务层接口"章节。 @@ -751,7 +980,7 @@ type ClientMessage = --- -## 七、扩展接口设计 +## 八、扩展接口设计 通过 Repository 接口隔离存储层,MVP 用内存实现,后续替换为数据库——业务逻辑零改动。 @@ -827,7 +1056,7 @@ func NewApp(cfg *Config) *App { --- -## 八、错误码 +## 九、错误码 | 错误码 | 含义 | 客户端处理建议 | |--------|------|--------------| @@ -842,7 +1071,7 @@ func NewApp(cfg *Config) *App { | `TTS_ERROR` | 语音合成失败 | 静默回退到纯文本回复 | | `INTERNAL_ERROR` | 服务端内部错误 | 提示用户重试 | -## 九、连接管理 +## 十、连接管理 **心跳机制**:客户端每 30 秒发送 `ping`,服务端回复 `pong`。超过 60 秒无 `ping`,服务端判定连接断开并清理会话资源。 diff --git a/docs/README.md b/docs/README.md index 99153d2..790d21d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,7 +8,7 @@ CamTalk 是一款多模态实时 AI 视觉对话助手。用户通过摄像头 |------|------| | [01-项目概述](01-项目概述.md) | 项目目标、核心挑战、交付物 | | [02-系统架构](02-系统架构.md) | 三层架构、技术栈、核心交互流程、前后端模块、存储策略、部署架构 | -| [03-接口文档](03-接口文档.md) | WebSocket 协议、REST API、**AI 服务层接口**、**编排器设计**、**Session Manager(Redis)**、数据模型、错误码、连接管理(**实现时首先阅读**) | +| [03-接口文档](03-接口文档.md) | WebSocket 协议、REST API、**AI 服务层接口**、**编排器设计**、**Session Manager**、**配置管理(Viper)**、数据模型、错误码、连接管理(**实现时首先阅读**) | | [04-技术选型](04-技术选型.md) | 持久化层(PostgreSQL)和前端边缘处理层的选型对比与决策理由 | | [05-用户故事](05-用户故事.md) | P0/P1/P2 用户故事、验收标准、优先级决策依据 | | [06-语音交互](06-语音交互.md) | VAD → STT → LLM → TTS 全链路、延迟优化 |