refactor: externalize hardcoded model config and clean up robustness plan
- Add openai_model, tts_minimax_model, tts_elevenlabs_model, tts_edge_voice, antigravity_model to Settings; set image_model default to nano-banana-pro - Update provider_router._get_default_config to read from settings - Add nul to .gitignore (Windows artifact) - Mark all robustness tasks as completed in dev-plan.md
This commit is contained in:
@@ -7,60 +7,37 @@
|
||||
|
||||
### P0 - 关键问题修复
|
||||
|
||||
#### Task-1: 修复 Rate Limit 内存泄漏
|
||||
#### Task-1: 修复 Rate Limit 内存泄漏 ✅
|
||||
- **文件**: `backend/app/api/stories.py`
|
||||
- **问题**: `_request_log` 全局字典无清理机制,长期运行内存无限增长
|
||||
- **方案**: 添加 TTL 自动清理机制,使用 `cachetools.TTLCache`
|
||||
- **测试**: 验证过期条目自动清理
|
||||
- **方案**: 已迁移至 Redis 分布式限流,内存泄漏问题不再存在
|
||||
|
||||
#### Task-2: 添加核心 API 测试
|
||||
- **文件**: `backend/tests/` (新建)
|
||||
- **范围**:
|
||||
- `test_auth.py`: OAuth 流程、session 验证
|
||||
- `test_stories.py`: 故事 CRUD、rate limit
|
||||
- **目标**: 核心路径覆盖率 ≥80%
|
||||
#### Task-2: 添加核心 API 测试 ✅
|
||||
- **文件**: `backend/tests/`
|
||||
- **范围**: test_auth, test_stories, test_profiles, test_universes, test_push_configs, test_reading_events, test_provider_router
|
||||
|
||||
### P1 - 稳定性提升
|
||||
|
||||
#### Task-3: 添加 API 重试机制
|
||||
- **文件**: `backend/app/services/gemini.py`, `minimax.py`, `drawing.py`
|
||||
- **方案**: 使用 `tenacity` 库,指数退避重试
|
||||
- **配置**: 最多 3 次重试,初始间隔 1s
|
||||
#### Task-3: 添加 API 重试机制 ✅
|
||||
- **方案**: 所有适配器已使用 `tenacity` 指数退避重试 (gemini, openai, cqtai, antigravity, minimax, elevenlabs)
|
||||
|
||||
#### Task-4: 添加结构化日志
|
||||
- **文件**: `backend/app/core/logging.py` (新建), 各 service 文件
|
||||
- **方案**: 使用 `structlog`,JSON 格式输出
|
||||
- **埋点**: API 调用、错误、性能指标
|
||||
#### Task-4: 添加结构化日志 ✅
|
||||
- **文件**: `backend/app/core/logging.py`
|
||||
- **方案**: structlog JSON/Console 双模式,所有适配器和 provider_router 已集成
|
||||
|
||||
### P2 - 代码优化
|
||||
|
||||
#### Task-5: 重构 Provider Router
|
||||
#### Task-5: 重构 Provider Router ✅
|
||||
- **文件**: `backend/app/services/provider_router.py`
|
||||
- **问题**: 三个函数重复代码
|
||||
- **方案**: 抽象通用 failover 函数
|
||||
- **方案**: 已实现统一 `_route_with_failover` 函数
|
||||
|
||||
#### Task-6: 配置外部化
|
||||
- **文件**: `backend/app/core/config.py`, `backend/app/services/gemini.py`
|
||||
- **问题**: 模型名硬编码
|
||||
- **方案**: 移至环境变量配置
|
||||
#### Task-6: 配置外部化 ✅
|
||||
- **文件**: `backend/app/core/config.py`, `backend/app/services/provider_router.py`
|
||||
- **方案**: 所有模型名已移至 Settings,支持环境变量覆盖
|
||||
|
||||
#### Task-7: 修复脆弱的 URL 解析
|
||||
- **文件**: `backend/app/services/drawing.py`
|
||||
- **问题**: 字符串切片解析 URL 不可靠
|
||||
- **方案**: 使用正则表达式
|
||||
#### Task-7: 修复脆弱的 URL 解析 ✅
|
||||
- **状态**: `drawing.py` 已被适配器系统取代,不再存在
|
||||
|
||||
## 依赖关系
|
||||
```
|
||||
Task-1 (独立)
|
||||
Task-2 (独立,但需要 Task-1 完成后验证)
|
||||
Task-3 (独立)
|
||||
Task-4 (独立)
|
||||
Task-5 (独立)
|
||||
Task-6 (独立)
|
||||
Task-7 (独立)
|
||||
```
|
||||
|
||||
## 新增依赖
|
||||
## 新增依赖 (已添加)
|
||||
```toml
|
||||
# pyproject.toml [project.dependencies]
|
||||
cachetools>=5.0.0 # Task-1: TTL cache
|
||||
@@ -69,4 +46,4 @@ structlog>=24.0.0 # Task-4: 结构化日志
|
||||
|
||||
# [project.optional-dependencies.dev]
|
||||
pytest-cov>=4.0.0 # Task-2: 覆盖率报告
|
||||
httpx[http2] # Task-2: 测试 mock
|
||||
```
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -32,6 +32,7 @@ htmlcov/
|
||||
# 其他
|
||||
*.log
|
||||
.DS_Store
|
||||
nul
|
||||
|
||||
# Vite
|
||||
*.timestamp-*.mjs
|
||||
|
||||
@@ -41,8 +41,13 @@ class Settings(BaseSettings):
|
||||
|
||||
# AI Model Configuration
|
||||
text_model: str = "gemini-2.0-flash"
|
||||
openai_model: str = "gpt-4o-mini"
|
||||
tts_model: str = ""
|
||||
image_model: str = ""
|
||||
image_model: str = "nano-banana-pro"
|
||||
tts_minimax_model: str = "speech-2.6-turbo"
|
||||
tts_elevenlabs_model: str = "eleven_multilingual_v2"
|
||||
tts_edge_voice: str = "zh-CN-XiaoxiaoNeural"
|
||||
antigravity_model: str = "gemini-3-pro-image"
|
||||
|
||||
# Provider routing (ordered lists)
|
||||
text_providers: list[str] = Field(default_factory=lambda: ["gemini"])
|
||||
|
||||
@@ -98,7 +98,7 @@ def _get_default_config(adapter_name: str) -> AdapterConfig | None:
|
||||
if adapter_name == "openai":
|
||||
return AdapterConfig(
|
||||
api_key=getattr(settings, "openai_api_key", ""),
|
||||
model="gpt-4o-mini", # 这里可以从 settings 读取,看需求
|
||||
model=settings.openai_model,
|
||||
timeout_ms=60000,
|
||||
)
|
||||
|
||||
@@ -106,7 +106,7 @@ def _get_default_config(adapter_name: str) -> AdapterConfig | None:
|
||||
if adapter_name in ("cqtai"):
|
||||
return AdapterConfig(
|
||||
api_key=getattr(settings, "cqtai_api_key", ""),
|
||||
model="nano-banana-pro", # 默认使用 Pro
|
||||
model=settings.image_model or "nano-banana-pro",
|
||||
timeout_ms=120000,
|
||||
)
|
||||
if adapter_name == "image_primary":
|
||||
@@ -128,7 +128,7 @@ def _get_default_config(adapter_name: str) -> AdapterConfig | None:
|
||||
# 我们这里暂时返回基础配置。
|
||||
return AdapterConfig(
|
||||
api_key=getattr(settings, "minimax_api_key", ""),
|
||||
model="speech-2.6-turbo",
|
||||
model=settings.tts_minimax_model,
|
||||
timeout_ms=60000,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user