# AI 对话生成业务流程总览 **更新日期**: 2026-02-13 **版本**: v2.0 (补齐业务表写入环节) --- ## 🎯 业务场景映射 ### 目标类型(target_type)与存储关系 | target_type | 前端传值 | 业务场景 | 存储目标表 | 必传关联 ID | 资源类型 (type) | |------------|---------|----------|-----------|------------|----------------| | 1 | storyboard | 分镜生图 | `storyboard_images` | `storyboard_id` | - | | 1 | storyboard | 分镜生视频 | `storyboard_videos` | `storyboard_id` | - | | 2 | character | 角色生图 | `project_resources` | `project_id` + `element_tag_id` | 1 (角色) | | 3 | scene | 场景生图 | `project_resources` | `project_id` + `element_tag_id` | 2 (场景) | | 4 | prop | 道具生图 | `project_resources` | `project_id` + `element_tag_id` | 3 (道具) | **注意**: 音效和配音不通过对话生成,使用其他 API 接口处理。 --- ## 🔄 完整业务流程 ### 步骤 1: 创建对话会话 **API**: `POST /api/v1/ai/conversations` **请求示例** (角色生图): ```json { "projectId": "019d1234-5678-7abc-def0-123456789abc", "targetType": 2, "targetId": "019d1234-5678-7abc-def0-character001", "tagId": "019d1234-5678-7abc-def0-tag-young", "mediaType": 1, "title": "张三-少年版 - 图片生成" } ``` **数据库记录**: ```sql INSERT INTO ai_conversations ( conversation_id, user_id, project_id, target_type, target_id, tag_id, media_type, title, status ) VALUES ( '019d1234-...', '019d1234-...', '019d1234-...', 2, '019d1234-...', '019d1234-...', 1, '张三-少年版 - 图片生成', 1 ); ``` --- ### 步骤 2: 发送消息 + 触发生成 **API**: `POST /api/v1/ai/conversations/{conversation_id}/messages` **请求示例 A** (仅发送消息): ```json { "content": "帮我生成一个日落场景" } ``` **请求示例 B** (发送消息 + 自动触发生成): ```json { "content": "生成一个日落场景,色调偏暖", "generate": { "generationType": "image", "modelId": "dall-e-3", "aiParams": { "resolution": "1024", "aspectRatio": "1:1" } } } ``` **内部流程**: 1. 创建用户消息 (`role=USER`) 2. 保存到 `ai_conversation_messages` 表 3. 如果提供 `generate` 对象 → 调用 `trigger_ai_generation()` 4. 创建 AI 任务 → `ai_jobs` 表 (status=PENDING) 5. 投递 Celery 任务到队列 **数据库记录**: ```sql -- 用户消息 INSERT INTO ai_conversation_messages ( message_id, conversation_id, user_id, role, content, meta_data, order_index, ai_job_id ) VALUES ( '019d1234-...', '019d1234-...', '019d1234-...', 1, '生成一个日落场景', '{"generate": {...}}', 0, '019d1234-job-001' ); -- AI 任务 INSERT INTO ai_jobs ( ai_job_id, user_id, project_id, job_type, status, input_data, model_name ) VALUES ( '019d1234-job-001', '019d1234-...', '019d1234-...', 1, 1, '{"prompt": "生成一个日落场景", ...}', 'dall-e-3' ); ``` --- ### 步骤 3: Celery 异步任务执行 **任务**: `generate_image_task` / `generate_video_task` **执行流程**: 1. 更新任务状态 → `PROCESSING` 2. 调用 AI Provider (OpenAI, FLUX, Doubao, etc.) 3. 下载生成的文件 4. 上传到自有 OSS (MinIO) 5. 更新任务状态 → `COMPLETED` **数据库更新**: ```sql UPDATE ai_jobs SET status = 3, -- COMPLETED progress = 100, output_data = '{ "file_url": "https://minio.example.com/ai-generated/images/019d1234.png", "file_size": 2048576, "width": 1024, "height": 1024, "checksum": "abc123...", "storage_provider": "minio", "storage_path": "/ai-generated/images/019d1234.png" }', completed_at = now() WHERE ai_job_id = '019d1234-job-001'; ``` --- ### 步骤 4: 🆕 自动写入业务表 **服务**: `AIGenerationResultService.save_generation_result()` **执行逻辑**: 1. 通过 `ai_job_id` 查询关联的消息 (`ai_conversation_messages`) 2. 获取对话上下文 (`ai_conversations`) 3. 根据 `target_type` + `media_type` 路由到对应的保存方法 #### 场景 A: 分镜图片 (target_type=1, media_type=1) ```sql INSERT INTO storyboard_images ( image_id, storyboard_id, name, url, status, is_active, version, width, height, file_size, format, checksum, storage_provider, storage_path, ai_model, ai_prompt, ai_params, created_at, completed_at ) VALUES ( '019d1234-img-001', '019d1234-storyboard-001', 'AI生成图片 - 20260213_143022', 'https://minio.../019d1234.png', 2, true, 1, 1024, 1024, 2048576, 'png', 'abc123...', 'minio', '/ai-generated/images/019d1234.png', 'dall-e-3', '生成一个日落场景', '{"resolution": "1024", ...}', now(), now() ); ``` #### 场景 B: 角色/场景/道具 (target_type=2/3/4, media_type=1) ```sql INSERT INTO project_resources ( project_resource_id, project_id, name, type, file_url, file_size, mime_type, width, height, checksum, element_tag_id, ai_job_id, meta_data, created_by, created_at, updated_at ) VALUES ( '019d1234-res-001', '019d1234-proj-001', 'AI生成角色 - 20260213', 1, -- ResourceType.CHARACTER 'https://minio.../019d1234.png', 2048576, 'image/png', 1024, 1024, 'abc123...', '019d1234-tag-young', '019d1234-job-001', '{"conversation_id": "...", "prompt": "...", "ai_params": {...}}', '019d1234-user-001', now(), now() ); ``` --- ## 📊 数据流示意图 ``` ┌─────────────────┐ │ 前端创建会话 │ │ POST /conversations └────────┬────────┘ ↓ ┌─────────────────┐ │ ai_conversations│ (记录 target_type, target_id, tag_id) └────────┬────────┘ ↓ ┌─────────────────┐ │ 前端发送消息 │ │ POST /messages │ │ (附带 generate) │ └────────┬────────┘ ↓ ┌───────────────────────┐ │ ai_conversation_messages│ (记录 content, ai_job_id) └────────┬──────────────┘ ↓ ┌─────────────────┐ │ 创建 AI 任务 │ └────────┬────────┘ ↓ ┌─────────────────┐ │ ai_jobs │ (status=PENDING) └────────┬────────┘ ↓ ┌─────────────────┐ │ Celery Worker │ │ 调用 AI Provider│ │ 下载文件 │ │ 上传到 OSS │ └────────┬────────┘ ↓ ┌─────────────────┐ │ ai_jobs │ (status=COMPLETED, output_data) └────────┬────────┘ ↓ ┌─────────────────────────┐ │ 🆕 自动写入业务表 │ │ AIGenerationResultService│ └────────┬────────────────┘ ↓ ┌──────┴──────┐ │ │ ↓ ↓ ┌─────────────┐ ┌─────────────┐ │storyboard_ │ │project_ │ │images/videos│ │resources │ └─────────────┘ └─────────────┘ ``` --- ## 🔑 关键字段说明 ### ai_conversations 表 - `target_type`: 目标类型(1=分镜 2=角色 3=场景 4=道具 5=资源) - `target_id`: 目标对象 ID(storyboard_id / character_id / scene_id / prop_id) - `tag_id`: 标签 ID(用于区分变体,如"少年版"、"中年版") - `media_type`: 媒体类型(1=图片 2=视频) ### ai_conversation_messages 表 - `role`: 消息角色(1=USER 用户消息, 2=ASSISTANT AI回复) - `content`: 消息内容(用户提示词或 AI 回复) - `ai_job_id`: 关联的 AI 任务 ID(如果触发了生成) - `meta_data`: 扩展数据(包含 generate 配置、mentions、reference_images) ### ai_jobs 表 - `job_type`: 任务类型(1=图片 2=视频 3=音效 4=配音) - `status`: 任务状态(1=等待 2=处理中 3=已完成 4=失败) - `output_data`: 输出结果(file_url, file_size, width, height, checksum 等) --- ## ✅ 前端查询指南 ### 查询角色生成的所有图片 ```sql SELECT * FROM project_resources WHERE project_id = '019d1234-proj-001' AND type = 1 -- CHARACTER AND element_tag_id = '019d1234-tag-young' AND deleted_at IS NULL ORDER BY created_at DESC; ``` ### 查询分镜的所有图片 ```sql SELECT * FROM storyboard_images WHERE storyboard_id = '019d1234-storyboard-001' AND is_active = true ORDER BY version DESC, created_at DESC; ``` ### 查询某个对话生成的资源 ```sql -- 1. 通过 conversation_id 查询所有消息 SELECT * FROM ai_conversation_messages WHERE conversation_id = '019d1234-conv-001'; -- 2. 通过 ai_job_id 查询任务结果 SELECT * FROM ai_jobs WHERE ai_job_id IN ( SELECT ai_job_id FROM ai_conversation_messages WHERE conversation_id = '019d1234-conv-001' ); -- 3. 通过 meta_data 查询资源(如果需要) SELECT * FROM project_resources WHERE meta_data->>'conversation_id' = '019d1234-conv-001'; ``` --- ## 🎉 完成标志 ✅ **现在前端可以直接从业务表查询生成的资源,无需解析 `ai_jobs.output_data`!** **优势**: 1. 统一数据结构:所有资源都在业务表中 2. 支持版本管理:通过 `version` 字段管理多版本 3. 支持标签筛选:通过 `element_tag_id` 精准查询 4. 支持状态管理:通过 `is_active` 控制激活状态 --- ## 📝 相关文档 - [完整实现文档](./2026-02-13-ai-generation-result-auto-save.md) - [API 文档](../../guides/ai-conversation-message-api.md) - [数据库设计](../../database-schema/ai-conversations.md)