You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
11 KiB
11 KiB
AI 对话生成任务创建修复
日期: 2026-02-12
类型: Bug 修复
模块: AI 对话 (ai_conversations)
影响范围: 后端 API
优先级: 🔴 高
📋 问题描述
现象 1:任务创建后 404 错误
用户在对话中触发 AI 生成后,前端轮询任务状态时返回 404 错误:
POST /api/v1/ai/conversations/{id}/generate
# 返回 jobId: 019c4fb4-06b6-75f1-97a1-f4346172b0a1
GET /api/v1/ai/jobs/019c4fb4-06b6-75f1-97a1-f4346172b0a1
# 返回 404 Not Found
现象 2:Gemini API 参数错误
任务创建成功,但执行时报错:
Error code: 400 - {
'error': {
'message': 'Invalid JSON payload received. Unknown name "prompt": Cannot find field.
Invalid JSON payload received. Unknown name "quality": Cannot find field.
Invalid JSON payload received. Unknown name "style": Cannot find field.
...'
}
}
根本原因
原因 1:任务记录未创建
AIConversationService.trigger_ai_generation() 方法中:
# ❌ 旧代码:仅生成 UUID,未创建数据库记录
# TODO: 调用 AI Service 创建任务
# 当前返回模拟数据
job_id = str(generate_uuid())
task_id = f"task-{job_id[:8]}"
原因 2:参数未过滤
# ❌ 旧代码:将所有前端参数传给 AI Service
result = await ai_service.generate_image(
...,
**params # 包含 modelId, aspectRatio, cameraSettings, mode 等
)
问题:
modelId,aspectRatio等前端参数被直接传给 Provider- Gemini API 不支持 OpenAI 风格的参数(
prompt,n,quality,size,style) - 导致 API 返回 400 错误
✅ 解决方案
修复内容
修复 1:创建真实任务记录
将模拟实现替换为真实的 AI Service 调用:
# ✅ 新代码:调用 AIService 创建真实任务
from app.services.ai_service import AIService
ai_service = AIService(self.db)
if generation_type == 'image':
# 解析参数
model_id = params.get('modelId', 'gemini-2.5-flash-image')
aspect_ratio = params.get('aspectRatio', '16:9')
# 解析宽高
if aspect_ratio == '16:9':
width, height = 1024, 576
elif aspect_ratio == '1:1':
width, height = 1024, 1024
elif aspect_ratio == '9:16':
width, height = 576, 1024
else:
width, height = 1024, 1024
# 调用生成图片方法(会创建数据库记录 + Celery 任务)
result = await ai_service.generate_image(
user_id=str(user_id),
prompt=message.content,
model=model_id,
width=width,
height=height,
project_id=str(conversation.project_id) if conversation.project_id else None,
reference_images=reference_images, # 传递 @ 提及的参考图
**extra_kwargs # 仅传递有效参数
)
修复 2:过滤前端参数
# ✅ 新代码:仅传递 AI Service 支持的参数
extra_kwargs = {}
if 'cameraSettings' in params:
extra_kwargs['cameraSettings'] = params['cameraSettings']
if 'mode' in params:
extra_kwargs['mode'] = params['mode']
# 排除不支持的参数:
# - modelId (已单独处理)
# - aspectRatio (已单独处理)
# - generationType (已单独处理)
# 避免传递给 Provider 导致 API 错误
修复后的完整流程
1. 用户触发 AI 生成
POST /ai/conversations/.../generate
↓
2. trigger_ai_generation()
├─ 验证对话会话
├─ 验证权限
├─ 获取消息
├─ 提取参考图(从 @ 提及)
├─ ✅ 调用 ai_service.generate_image()
│ ├─ 验证用户积分
│ ├─ 预扣积分
│ ├─ 创建 ai_jobs 记录 ← 修复关键!
│ ├─ 提交 Celery 任务
│ └─ 返回 job_id + task_id
├─ 更新消息的 ai_job_id
├─ 创建系统消息
└─ 更新对话统计信息
↓
3. 返回响应给前端
↓
4. 前端轮询任务状态
GET /api/v1/ai/jobs/{job_id}
↓
5. ✅ 成功查询到任务记录
🔧 修改的文件
1. server/app/services/ai_conversation_service.py
修改方法: trigger_ai_generation()
主要变更:
- ✅ 移除模拟 UUID 生成逻辑
- ✅ 添加
AIService调用(创建真实任务记录) - ✅ 实现图片生成任务创建
- ✅ 实现视频生成任务创建
- ✅ 支持
aspectRatio参数解析(图片) - ✅ 支持
videoType参数解析(视频:text2video / img2video) - ✅ 参数过滤:仅传递 AI Service 支持的参数(修复 Gemini API 400 错误)
- ✅ 传递
reference_images参考图 - ✅ 更新对话统计信息(
message_count,last_message_at) - ✅ 返回
estimatedCredits字段 - ✅ 优化导入结构(移到文件顶部)
新增功能:
- 支持图片生成:16:9、1:1、9:16 等宽高比
- 支持视频生成:text2video(文本转视频)、img2video(图片转视频)
- 支持将消息内容作为 prompt
- 支持从 @ 提及中提取参考图
- img2video 自动使用第一张参考图作为输入
- 参数白名单过滤:避免传递不支持的参数给 AI Provider
🧪 测试验证
测试步骤
-
创建对话并发送消息
POST /api/v1/ai/conversations POST /api/v1/ai/conversations/{id}/messages -
触发 AI 生成(图片)
POST /api/v1/ai/conversations/{id}/generate { "messageId": "019c...", "generationType": "image", "params": { "modelId": "gemini-2.5-flash-image", "aspectRatio": "16:9", "mode": "storyboard-image" } }
2.1 触发 AI 生成(视频 - 文本转视频)
POST /api/v1/ai/conversations/{id}/generate
{
"messageId": "019c...",
"generationType": "video",
"params": {
"modelId": "runway-gen3-turbo",
"videoType": "text2video",
"duration": 5,
"fps": 30
}
}
2.2 触发 AI 生成(视频 - 图片转视频)
POST /api/v1/ai/conversations/{id}/generate
{
"messageId": "019c...", # 消息中必须包含 @ 提及的图片
"generationType": "video",
"params": {
"modelId": "runway-gen3-turbo",
"videoType": "img2video",
"duration": 5,
"fps": 30
}
}
-
验证响应
{ "code": 0, "data": { "jobId": "019c4fb4-06b6-75f1-97a1-f4346172b0a1", "taskId": "celery-task-id", "status": "pending", "estimatedCredits": 10, "referenceImagesCount": 2 } } -
查询任务状态
GET /api/v1/ai/jobs/019c4fb4-06b6-75f1-97a1-f4346172b0a1 # ✅ 应返回 200,包含任务详情 -
验证数据库
SELECT * FROM ai_jobs WHERE ai_job_id = '019c4fb4-06b6-75f1-97a1-f4346172b0a1'; -- ✅ 应该存在该记录
预期结果
- ✅ 任务创建成功
- ✅ 数据库中存在
ai_jobs记录 - ✅ 前端可以正常轮询任务状态
- ✅ Celery 任务已提交
- ✅ 积分已预扣
📊 影响范围
受影响的功能
| 功能 | 影响 | 状态 |
|---|---|---|
| 对话触发图片生成 | ✅ 修复 | 已完成 |
| 对话触发视频生成 | ✅ 修复 | 已完成 |
| 任务状态查询 | ✅ 修复 | 已完成 |
| @ 提及参考图 | ✅ 增强 | 已支持 |
| 积分预扣 | ✅ 修复 | 已完成 |
| Celery 任务提交 | ✅ 修复 | 已完成 |
不受影响的功能
- ❌ 直接调用
/api/v1/ai/generate接口(独立接口,未修改) - ❌ 其他 AI 功能(音频、配音等)
⚠️ 注意事项
1. 图片转视频需要参考图
if video_type == 'img2video':
if reference_images:
image_url = reference_images[0] # 使用第一张参考图
else:
raise ValidationError("图片转视频需要提供参考图,请在消息中 @ 提及图片资源")
要求: 使用 img2video 时,必须在消息中 @ 提及至少一张图片资源
2. 参数过滤机制
问题: 前端传来的参数可能包含 AI Provider 不支持的字段(如 modelId, aspectRatio, mode)
解决: 使用白名单过滤
# 图片生成:仅传递 cameraSettings 和 mode
extra_kwargs = {}
if 'cameraSettings' in params:
extra_kwargs['cameraSettings'] = params['cameraSettings']
if 'mode' in params:
extra_kwargs['mode'] = params['mode']
# 视频生成:仅传递 quality 和 style
extra_kwargs = {}
if 'quality' in params:
extra_kwargs['quality'] = params['quality']
if 'style' in params:
extra_kwargs['style'] = params['style']
避免的错误:
- ❌
modelId→ 前端参数,不应传给 Provider - ❌
aspectRatio→ 前端参数,已转换为 width/height - ❌
generationType→ 前端参数,不应传给 Provider
3. 视频生成参数
支持的参数:
videoType:text2video或img2videoduration: 视频时长(秒),默认 5fps: 帧率,默认 30modelId: 模型 ID,默认runway-gen3-turbo
4. 宽高比映射(图片生成)
当前硬编码了几种常见比例:
if aspect_ratio == '16:9':
width, height = 1024, 576
elif aspect_ratio == '1:1':
width, height = 1024, 1024
elif aspect_ratio == '9:16':
width, height = 576, 1024
else:
width, height = 1024, 1024 # 默认 1:1
建议: 可以考虑将映射关系提取为配置文件
5. 对话统计信息更新
修复中添加了对话统计信息更新:
conversation.message_count += 1
conversation.last_message_at = datetime.now(timezone.utc)
原因: 创建系统消息时需要同步更新计数器
🔄 后续优化建议
1. 支持更多生成类型
- 实现视频生成 (
generate_video) - 已完成 - 实现音频生成 (
generate_sound) - 实现配音生成 (
generate_voice)
1. 增强参数验证
- 验证
aspectRatio合法性(添加支持更多比例) - 验证
modelId是否存在 - 验证
cameraSettings参数范围 - 验证
videoType合法性
2. 优化参数过滤
当前使用硬编码白名单:
extra_kwargs = {}
if 'cameraSettings' in params:
extra_kwargs['cameraSettings'] = params['cameraSettings']
if 'mode' in params:
extra_kwargs['mode'] = params['mode']
建议: 为每个模型配置支持的参数列表
# 配置文件
MODEL_PARAMS_WHITELIST = {
'gemini-2.5-flash-image': ['cameraSettings', 'mode'],
'runway-gen3-turbo': ['quality', 'style', 'motion_level']
}
# 动态过滤
allowed_params = MODEL_PARAMS_WHITELIST.get(model_id, [])
extra_kwargs = {k: v for k, v in params.items() if k in allowed_params}
3. 优化错误处理
- 区分积分不足、模型不存在等错误类型
- 返回更友好的错误提示
- 记录详细的错误日志
4. 性能优化
- 缓存模型配置
- 批量查询资源信息
- 异步处理参考图上传
📝 相关文档
✅ 审核清单
- 代码已修改
- 语法检查通过
- 功能逻辑正确
- 错误处理完善
- 日志记录清晰
- 文档已更新
- 单元测试通过(待编写)
- 集成测试通过(待验证)
修复者: Claude (AI Assistant)
审核者: 待审核
版本: v1.2.0 (修复 Gemini API 参数错误)