# 修复 AI 任务 output_data 存储 Base64 数据问题 **日期**: 2026-02-14 **类型**: Bug Fix **影响范围**: AI 图片生成任务 **严重程度**: Medium (数据库膨胀、查询性能) ## 问题描述 ### 背景 在图片生成任务 (`generate_image_task`) 中,当 AI Provider 返回 Base64 格式的图片数据时,系统会: 1. 解码 Base64 数据为二进制 2. 上传到 MinIO 获取永久 URL 3. 更新任务的 `output_data` 字段 ### 问题 **在第 3 步时,原始的 `b64_json` 字段没有被移除**,导致: - 1024x1024 PNG 图片的 Base64 约 **1-2 MB** - 频繁生成图片会导致数据库快速膨胀 - 查询 `ai_jobs` 表时加载大量无用数据 - 影响 API 响应性能 ### 受影响的 Provider - OpenAI (DALL-E): 默认返回 Base64 - Gemini (Imagen): 返回 Base64 - 其他使用 Base64 响应格式的 Provider ### 对比 视频/音频生成任务已正确处理此问题: ```python result.pop('audio_data', None) # ✅ 显式移除二进制数据 result.update(file_metadata) ``` ## 修复方案 ### 代码变更 **文件**: `server/app/tasks/ai_tasks.py` **修改前** (第 471-494 行): ```python if result.get('b64_json'): file_data = base64.b64decode(result['b64_json']) file_metadata = await _upload_file_from_bytes(...) # ❌ 仅更新 result,未移除 b64_json result.update(file_metadata) elif result.get('url'): file_metadata = await _download_and_upload_file(...) # ❌ 仅更新 result,未移除 url result.update(file_metadata) ``` **修改后**: ```python if result.get('b64_json'): file_data = base64.b64decode(result['b64_json']) file_metadata = await _upload_file_from_bytes(...) # ✅ 移除 Base64 数据(避免存入数据库) result.pop('b64_json', None) result.pop('url', None) result.update(file_metadata) elif result.get('url'): file_metadata = await _download_and_upload_file(...) # ✅ 移除临时 URL(避免存入数据库) result.pop('url', None) result.pop('b64_json', None) result.update(file_metadata) ``` ### 修复后的 output_data 结构 ```json { "file_url": "http://minio:9000/jointo/ai-generated/images/...", "file_size": 245678, "checksum": "sha256:abc123...", "mime_type": "image/png", "storage_provider": "minio", "storage_path": "ai-generated/images/image_xxx.png", "metadata": { "model": "dall-e-3", "size": "1024x1024", "quality": "standard", "style": "vivid", "revised_prompt": "..." } } ``` **移除的字段**: - ❌ `b64_json`: Base64 编码的图片数据 (1-2 MB) - ❌ `url`: AI Provider 的临时 URL (已过期) **保留的字段**: - ✅ `file_url`: MinIO 永久 URL - ✅ `metadata`: 模型元数据 (< 1 KB) ## 影响评估 ### 数据库影响 **修复前**: - 单个图片任务 `output_data`: **1-2 MB** - 100 个图片任务: **100-200 MB** **修复后**: - 单个图片任务 `output_data`: **< 10 KB** - 100 个图片任务: **< 1 MB** **节省空间**: **约 99% (200MB → 1MB)** ### API 性能影响 - 查询 `ai_jobs` 表时数据传输量减少 99% - 前端轮询任务状态的响应速度提升 - 数据库 JSONB 索引效率提升 ### 历史数据 - 已存储的历史任务**不受影响** - 可选:运行清理脚本移除历史数据中的 Base64 字段 ## 验证方法 ### 1. 测试图片生成 ```bash # 生成测试图片 curl -X POST http://localhost:8000/api/v1/ai/jobs/generate-image \ -H "Authorization: Bearer $TOKEN" \ -d '{ "prompt": "A beautiful sunset", "model": "dall-e-3", "width": 1024, "height": 1024 }' # 查询任务结果 curl http://localhost:8000/api/v1/ai/jobs/{job_id} ``` ### 2. 验证 output_data 大小 ```sql -- 查询最新图片任务的 output_data 大小 SELECT ai_job_id, created_at, pg_column_size(output_data) as size_bytes, pg_column_size(output_data) / 1024 as size_kb, jsonb_object_keys(output_data) as keys FROM ai_jobs WHERE job_type = 1 -- IMAGE AND status = 3 -- COMPLETED ORDER BY created_at DESC LIMIT 5; ``` **预期结果**: `size_kb` 应 **< 10 KB** ### 3. 验证字段不存在 ```sql -- 确认 output_data 中不包含 b64_json 或临时 url SELECT ai_job_id, output_data ? 'b64_json' as has_base64, output_data ? 'file_url' as has_file_url, output_data->'metadata'->>'model' as model FROM ai_jobs WHERE job_type = 1 AND status = 3 ORDER BY created_at DESC LIMIT 5; ``` **预期结果**: `has_base64` 应为 `false` ## 清理历史数据(可选) 如需清理历史数据中的 Base64 字段: ```sql -- 1. 查看需要清理的任务数量 SELECT COUNT(*) as count, SUM(pg_column_size(output_data)) / 1024 / 1024 as total_mb FROM ai_jobs WHERE job_type = 1 AND output_data ? 'b64_json'; -- 2. 清理 Base64 字段(谨慎操作,建议先备份) UPDATE ai_jobs SET output_data = output_data - 'b64_json' - 'url' WHERE job_type = 1 AND output_data ? 'b64_json'; -- 3. 验证清理结果 SELECT COUNT(*) as remaining_count FROM ai_jobs WHERE job_type = 1 AND output_data ? 'b64_json'; -- 应返回 0 ``` ## 回滚方案 如需回滚此修复: ```bash cd server git revert ``` **注意**: 回滚后新生成的图片任务会再次存储 Base64 数据。 ## 相关问题 ### 其他任务类型状态 - ✅ **视频生成**: 已正确移除 `video_data` - ✅ **音频生成**: 已正确移除 `audio_data` - ✅ **配音生成**: 已正确移除 `audio_data` - ✅ **批量对话配音**: 无大字段问题 - ⚠️ **剧本解析**: `parsed_data` 可能包含大量文本 (待优化) ### 剧本解析优化建议 剧本解析任务的 `output_data.parsed_data` 可能包含: - 完整剧本内容 - 角色/场景/道具描述 - 分镜详情和对白 **建议**: 1. 仅保存摘要统计(角色数、场景数、分镜数) 2. 详细数据已存入业务表,无需重复存储 3. 或标记为大字段,允许 API 选择性加载 ## 测试清单 - [x] 修复代码并通过 Linter 检查 - [ ] 测试 OpenAI DALL-E 图片生成 - [ ] 测试 Gemini Imagen 图片生成 - [ ] 验证 output_data 大小 < 10 KB - [ ] 验证不包含 b64_json 字段 - [ ] 查询历史数据统计 - [ ] (可选) 执行历史数据清理 ## 参考文档 - **AI 任务模型**: `server/app/models/ai_job.py` - **AI 任务处理**: `server/app/tasks/ai_tasks.py` - **OpenAI Adapter**: `server/app/services/ai_providers/sdk_adapters/openai_sdk_adapter.py` - **Gemini Adapter**: `server/app/services/ai_providers/sdk_adapters/gemini_sdk_adapter.py` ## 总结 此修复解决了图片生成任务中 Base64 数据存入数据库的问题,预期可: - **节省数据库空间 99%** - **提升查询性能** - **优化 API 响应速度** - **与视频/音频任务保持一致的处理逻辑** 修复已生效,新生成的图片任务将不再存储 Base64 数据。