TravelContentCreator/docs/REFACTORING_IMPLEMENTATION.md

476 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 技术债务重构实施文档
> 本文档记录技术债务改进的具体实施过程
---
## 实施计划
| # | 改进项 | 状态 | 完成时间 |
|---|-------|------|---------|
| 1 | 数据库访问改接口 | ✅ 完成 | 2024-12-08 |
| 2 | 图片传输改 URL | ✅ 完成 | 2024-12-08 |
| 3 | 放弃 ppid | ✅ 完成 | 2024-12-08 |
| 4 | Prompt Registry | ✅ 完成 | 2024-12-08 |
| 5 | 依赖注入统一 | ✅ 完成 | 2024-12-08 |
---
## 1. 数据库访问改接口
### 目标
Python 端不再直接连接数据库,所有数据由 Java 端通过 HTTP 接口传递。
### 改动前架构
```
┌─────────────┐ ┌─────────────┐
│ Java 端 │ │ Python 端 │
└──────┬──────┘ └──────┬──────┘
│ │
│ 各自连接 │ 各自连接
▼ ▼
┌─────────────────────────┐
│ MySQL │
└─────────────────────────┘
```
### 改动后架构
```
┌─────────────┐ ┌─────────────┐
│ Java 端 │ ──── HTTP ────────>│ Python 端 │
└──────┬──────┘ (完整数据) └─────────────┘
│ │
│ 唯一数据源 │ 无数据库访问
▼ │
┌─────────────────────────┐ │
│ MySQL │ X
└─────────────────────────┘
```
### 新的接口协议
Java 端调用 Python 端时,传递完整数据:
```json
{
"engine": "topic_generate",
"params": {
"num_topics": 5,
"month": "2024-12",
// 直接传完整对象,而不是 ID
"scenic_spot": {
"id": 1,
"name": "天津冒险湾",
"description": "主题乐园...",
"location": "天津市"
},
"product": {
"id": 10,
"name": "门票套餐",
"price": 299,
"description": "..."
},
"style": {
"id": 5,
"name": "攻略风",
"description": "实用性强..."
},
"audience": {
"id": 3,
"name": "亲子家庭",
"description": "..."
}
}
}
```
### 实施步骤
1. [x] 定义新的参数 Schema
2. [x] 创建 V2 引擎接收完整对象
3. [x] V2 引擎不访问数据库
4. [ ] 更新 Java 端调用方式 (待 Java 端配合)
### 已创建文件
- `domain/aigc/engines/topic_generate_v2.py` - 选题生成 V2
- `domain/aigc/engines/content_generate_v2.py` - 内容生成 V2
- `domain/aigc/engines/poster_generate_v2.py` - 海报生成 V2
---
## 2. 图片传输改 URL
### 目标
不再传递 Base64改为传递图片 URL 或路径。
### 新的接口协议
```json
{
"engine": "poster_generate",
"params": {
"template_id": "vibrant",
// 方式1: S3 URL
"image_urls": [
"https://s3.xxx.com/bucket/image1.jpg",
"https://s3.xxx.com/bucket/image2.jpg"
],
// 方式2: 本地路径 (如果共享存储)
"image_paths": [
"/data/images/123.jpg"
],
// 方式3: 素材 ID (Python 自行获取)
"material_ids": [123, 456]
}
}
```
### 实施步骤
1. [x] 修改引擎支持 URL 下载
2. [x] 添加图片下载工具 (aiohttp)
3. [ ] 更新 Java 端传参方式 (待 Java 端配合)
### 已实现
`PosterGenerateEngineV2` 支持三种图片来源:
- `image_urls` - 从 URL 下载 (推荐)
- `image_paths` - 从本地路径读取
- `images_base64` - Base64 (兼容旧接口)
---
## 3. 放弃 ppid
### 目标
不再使用 ppidJava 端直接传递解析后的完整数据。
### 改动
- 移除 Python 端的 `resolve_ppid()` 逻辑
- 移除 `ProductPackageRepository`
- 引擎参数 Schema 中移除 `ppid`
### 实施步骤
1. [x] V2 引擎不包含 ppid 参数
2. [x] V2 引擎不访问 ProductPackageRepository
3. [x] 参数 Schema 只接收完整对象
### 说明
V2 引擎的参数 Schema 中没有 `ppid`,只接收:
- `scenic_spot` - 完整景区对象
- `product` - 完整产品对象
- `style` - 完整风格对象
- `audience` - 完整受众对象
Java 端需要在调用前解析 ppid 并传递完整数据。
---
## 4. Prompt Registry
### 目标
集中管理 Prompt支持版本化。
### 目录结构
```
prompts/
├── topic_generate/
│ └── v1.0.0.yaml
├── content_generate/
│ └── v1.0.0.yaml
└── content_judge/
└── v1.0.0.yaml
```
### 实施步骤
1. [x] 创建 `domain/prompt/` 模块
2. [x] 实现 `PromptRegistry`
3. [x] 迁移现有 prompt 到 YAML
4. [x] V2 引擎使用新 Registry
### 已创建文件
**模块:**
- `domain/prompt/__init__.py`
- `domain/prompt/registry.py` - PromptRegistry 实现
**Prompt 配置:**
- `prompts/topic_generate/v1.0.0.yaml`
- `prompts/content_generate/v1.0.0.yaml`
- `prompts/content_judge/v1.0.0.yaml`
### 使用示例
```python
from domain.prompt import PromptRegistry
registry = PromptRegistry('prompts')
# 渲染 prompt
system, user = registry.render(
'content_generate',
context={'style_content': '...', 'demand_content': '...', ...},
version='latest'
)
# 获取模型参数
config = registry.get('content_generate')
params = config.get_model_params() # {'temperature': 0.3, ...}
```
---
## 5. 依赖注入统一
### 目标
统一使用容器模式管理依赖。
### 实施步骤
1. [x] 创建 `Container`
2. [x] 实现服务注册和获取
3. [ ] 逐步迁移现有依赖获取方式 (渐进式)
### 已创建文件
- `domain/container.py` - Container 实现
### 使用示例
```python
from domain.container import Container, get_service, inject
# 方式1: 直接获取
from core.config import ConfigManager
config = Container.get(ConfigManager)
# 方式2: 便捷函数
from domain import get_service
config = get_service(ConfigManager)
# 方式3: 装饰器注入
@inject(ConfigManager, AIAgent)
def my_function(config, agent, other_param):
...
```
### 说明
Container 采用渐进式迁移策略:
- 新代码使用 Container
- 旧代码保持不变,逐步迁移
- V2 引擎内部使用延迟加载,兼容两种方式
---
## 变更日志
| 日期 | 改动 | 文件 |
|-----|------|------|
| 2024-12-08 | 创建实施文档 | docs/REFACTORING_IMPLEMENTATION.md |
| 2024-12-08 | 创建 PromptRegistry | domain/prompt/registry.py |
| 2024-12-08 | 创建 Container | domain/container.py |
| 2024-12-08 | 创建 V2 引擎 | domain/aigc/engines/*_v2.py |
| 2024-12-08 | 迁移 Prompt 到 YAML | prompts/*.yaml |
---
## 新旧引擎对比
| 特性 | V1 引擎 | V2 引擎 |
|-----|--------|--------|
| 数据库访问 | ✅ 直接访问 | ❌ 不访问 |
| ppid 支持 | ✅ 自动解析 | ❌ 不支持 |
| 图片传输 | Base64 | URL/路径/Base64 |
| Prompt 管理 | 文件模板 | PromptRegistry |
| 依赖注入 | 延迟加载 | Container |
## Java 端调用示例
### V1 引擎 (旧)
```json
{
"engine": "topic_generate",
"params": {
"ppid": 12345,
"num_topics": 5
}
}
```
### V2 引擎 (新)
```json
{
"engine": "topic_generate_v2",
"params": {
"num_topics": 5,
"month": "2024-12",
"scenic_spot": {
"id": 1,
"name": "天津冒险湾",
"description": "..."
},
"product": {
"id": 10,
"name": "门票套餐",
"price": 299
}
}
}
```
---
## 待办事项
- [ ] Java 端更新调用方式,使用 V2 引擎
- [ ] 验证 V2 引擎功能正确性
- [ ] 清理 V1 引擎中的数据库访问代码 (可选)
- [ ] 删除 Python 端的 database_service.py (待确认无其他依赖)
- [ ] 两端协调 ppid 废弃方案
---
## 6-12 问题改进记录
### 6. 临时文件清理
创建清理脚本 `scripts/cleanup_temp_files.py`
```bash
# 预览要删除的文件
python scripts/cleanup_temp_files.py --dry-run
# 清理 7 天前的临时文件
python scripts/cleanup_temp_files.py --days 7
# 清理指定目录
python scripts/cleanup_temp_files.py --dir result --days 3
```
### 7. 统一配置
创建 `core/unified_config.py`
```python
from core import get_unified_config
config = get_unified_config()
# 获取配置值
db_host = config.get("database.host")
# 获取配置组
db_config = config.database
ai_config = config.ai_model
```
支持环境变量覆盖:
- `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_USER`, `DATABASE_PASSWORD`
- `AI_MODEL_API_KEY`, `AI_MODEL_BASE_URL`
### 8. 统一异常
创建 `core/exceptions.py`,定义标准异常类:
| 异常类 | 用途 | HTTP 状态码 |
|-------|------|------------|
| `ValidationError` | 参数验证失败 | 400 |
| `ResourceNotFoundError` | 资源未找到 | 404 |
| `EngineError` | 引擎执行错误 | 500 |
| `AIError` | AI 服务错误 | 502 |
| `AIRateLimitError` | AI 限流 | 429 |
### 10. 重复目录统一
`core/document/` 重定向到 `document/`,保持兼容性。
### 12. 日志配置
创建 `core/logging_config.py`
```python
from core import setup_logging, get_logger
# 初始化日志
setup_logging(level="INFO", log_dir="logs")
# 获取日志器
logger = get_logger(__name__)
```
特性:
- 控制台 + 文件输出
- 日志滚动 (10MB/文件保留5个)
- 错误日志单独文件
- 第三方库日志静默
---
## Prompt 查询 API
新增 V2 接口:
| 接口 | 方法 | 说明 |
|-----|------|------|
| `/prompt/v2/list` | GET | 列出所有 prompt |
| `/prompt/v2/{name}` | GET | 获取 prompt 详情 |
| `/prompt/v2/{name}/versions` | GET | 列出版本 |
| `/prompt/v2/{name}/preview` | GET | 预览原始模板 |
| `/prompt/v2/render` | POST | 渲染 prompt |
### 已迁移的 Prompt
| 名称 | 版本 | 说明 |
|-----|------|------|
| topic_generate | v1.0.0 | 选题生成 |
| content_generate | v1.0.0 | 内容生成 |
| content_judge | v1.0.0 | 内容审核 |
| poster_generate | v1.0.0 | 海报文案 |
| integration | v1.0.0 | 资料整理 |
| style/gonglue | v1.0.0 | 攻略风风格 |
| style/tuijian | v1.0.0 | 极力推荐风风格 |
| audience/qinzi | v1.0.0 | 亲子向人群 |
| audience/zhoubianyou | v1.0.0 | 周边游人群 |
| audience/gaoshe | v1.0.0 | 高奢酒店人群 |
---
## V1 引擎废弃说明
V1 引擎已废弃V2 引擎现在使用默认名称:
| 旧 engine_id | 新 engine_id | 说明 |
|-------------|-------------|------|
| topic_generate_v2 | topic_generate | 选题生成 |
| content_generate_v2 | content_generate | 内容生成 |
| poster_generate_v2 | poster_generate | 海报生成 |
**Java 端直接使用 `topic_generate`、`content_generate`、`poster_generate` 即可。**
---
## 后端对接文档
详见 [API_INTEGRATION.md](./API_INTEGRATION.md)