Skip to content

任务多图支持设计

状态:暂不实现 - 复杂度较高,收益有限,详见文末"复杂度评估"章节

概述

支持单个绘图任务生成多张图片。用户对生成结果不满意时,可点击"重新生成"按钮追加新图片,同时保留历史图片供切换查看。

使用场景

  1. 嵌入式绘图组件:AI 生成的插图不满意,点击重新生成
  2. 绘图工作台:对任务结果不满意,追加生成新图片
  3. 图片浏览:在多张图片间切换,选择最满意的一张

数据模型变更

方案:新增 task_images 表

sql
CREATE TABLE task_images (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  task_id INTEGER NOT NULL REFERENCES tasks(id),
  image_url TEXT NOT NULL,           -- 图片 URL
  created_at TEXT NOT NULL,          -- 生成时间
  status TEXT NOT NULL DEFAULT 'pending',  -- pending/processing/success/failed
  error TEXT,                        -- 失败原因
  progress TEXT                      -- 生成进度
);

CREATE INDEX task_images_task_id ON task_images(task_id);

tasks 表变更

sql
ALTER TABLE tasks ADD COLUMN selected_image_id INTEGER REFERENCES task_images(id);
字段说明
selected_image_id当前选中的图片 ID,用于记录用户偏好

字段迁移

现有 tasks 表的图片相关字段保持不变(兼容性),新生成的图片写入 task_images 表:

原字段处理方式
imageUrl保留,作为第一张图片的冗余存储
progress保留,表示当前正在生成的图片进度
error保留,表示当前生成的错误

任务状态设计

任务级状态 (tasks.status)

状态含义
pending任务创建,等待提交
submitting正在提交到上游
processing有图片正在生成中
success至少有一张图片生成成功,且当前无进行中的生成
failed最近一次生成失败,且当前无进行中的生成

图片级状态 (task_images.status)

状态含义
pending等待生成
processing生成中
success生成成功
failed生成失败

状态流转

任务创建 → pending

首次提交 → submitting → processing → success/failed

                              点击重新生成 → processing → success/failed

                                                 再次重新生成 → ...

API 设计

POST /api/tasks/:id/regenerate

触发重新生成(追加新图片)

请求:无需 body

响应

json
{
  "taskId": 123,
  "imageId": 456,
  "status": "processing"
}

逻辑

  1. 检查任务是否存在且属于当前用户
  2. 创建新的 task_images 记录(状态为 pending
  3. 更新 tasks.statusprocessing
  4. 提交生成任务

并发生成:允许同时生成多张图片,用户可连续点击多次

PUT /api/tasks/:id/select-image

切换选中的图片

请求

json
{
  "imageId": 456
}

响应

json
{
  "success": true
}

GET /api/tasks/:id(现有接口扩展)

响应新增字段

json
{
  "id": 123,
  "status": "success",
  "images": [
    {
      "id": 1,
      "imageUrl": "/api/images/xxx.jpg",
      "status": "success",
      "createdAt": "2025-12-24T10:00:00Z"
    },
    {
      "id": 2,
      "imageUrl": "/api/images/yyy.jpg",
      "status": "success",
      "createdAt": "2025-12-24T10:05:00Z"
    }
  ],
  "selectedImageId": 2,
  "currentImageUrl": "/api/images/yyy.jpg"
}

POST /api/illustrations(现有接口扩展)

响应新增字段

json
{
  "taskId": 123,
  "status": "success",
  "images": [...],
  "selectedImageId": 2,
  "currentImageUrl": "/api/images/yyy.jpg"
}

前端组件设计

MjDrawingBlock.vue 变更

┌─────────────────────────────────────┐
│  [图片区域]                          │
│  ┌─────────────────────────────┐   │
│  │                             │   │
│  │         [当前图片]           │   │
│  │                             │   │
│  │  [◀]                  [▶]  │   │ ← 多图时显示切换按钮
│  └─────────────────────────────┘   │
│                                     │
│  [下载] [放大]          [重新生成]  │ ← 成功时显示重新生成按钮
│  [模型标签]    [2/3]    [信息按钮]  │ ← 显示当前图片索引
│  ════════════════════════════════  │
└─────────────────────────────────────┘

新增功能

  • 左右切换按钮(多图时显示)
  • 图片索引指示器(如 2/3)
  • 重新生成按钮(成功状态时显示)

TaskCard.vue 变更(绘图工作台)

与 MjDrawingBlock 类似:

  • 添加图片切换功能
  • 添加重新生成按钮
  • 显示图片数量指示器

实现文件清单

数据库

  • server/database/schema.ts - 添加 taskImages 表,tasks 添加 selectedImageId
  • server/database/migrations/ - 生成迁移文件

后端

  • server/services/task.ts - 添加 regenerate()selectImage() 方法
  • server/api/tasks/[id]/regenerate.post.ts - 重新生成接口
  • server/api/tasks/[id]/select-image.put.ts - 切换图片接口
  • server/api/tasks/[id].get.ts - 扩展返回 images 数组

前端

  • app/components/chat/MjDrawingBlock.vue - 添加多图切换和重新生成
  • app/components/drawing/TaskCard.vue - 添加多图切换和重新生成
  • app/composables/useTasks.ts - 添加 regenerate()selectImage() 方法

兼容性考虑

  1. 现有任务:通过迁移脚本将 tasks.imageUrl 导入 task_images
  2. API 响应:统一从 task_images 表读取,保持接口一致性
  3. tasks.imageUrl 字段:保留但不再写入,仅用于迁移过渡期的兼容

数据迁移脚本

迁移时执行:

sql
-- 将现有成功任务的图片导入 task_images
INSERT INTO task_images (task_id, image_url, status, created_at)
SELECT id, image_url, 'success', created_at
FROM tasks
WHERE image_url IS NOT NULL AND status = 'success';

-- 更新 selected_image_id 指向迁移的图片
UPDATE tasks
SET selected_image_id = (
  SELECT id FROM task_images WHERE task_images.task_id = tasks.id LIMIT 1
)
WHERE image_url IS NOT NULL AND status = 'success';

边界情况

  1. 并发重新生成:允许同时生成多张,前端显示多个进度条或合并显示
  2. 生成中切换图片:允许,不影响正在进行的生成
  3. 删除任务:级联删除所有 task_images 记录

复杂度评估

新增复杂度

方面变更复杂度增量
数据库新增 task_images 表 + 迁移脚本
后端服务TaskService 需管理两张表的状态同步
并发控制多个图片同时生成,状态聚合逻辑复杂
轮询逻辑需轮询多个图片状态,判断整体完成
前端组件图片切换、多进度显示、索引同步
API3 个新接口 + 现有接口扩展

风险点

  1. 状态同步tasks.status 需根据所有 task_images 状态聚合计算

    • 任一图片 processing → 任务 processing
    • 全部完成且至少一张成功 → 任务 success
    • 全部完成且全部失败 → 任务 failed
  2. 并发生成的 UI 表达:多张图片同时生成时如何展示?

    • 方案 A:显示多个进度条(复杂)
    • 方案 B:只显示"N 张生成中"文字(简单)
  3. 轮询效率:每次轮询需查询 task_images 表,数据量大时可能有性能问题

建议

不建议现阶段实现此功能,理由:

  1. 投入产出比低:当前单图模式已能满足基本需求,重新生成可通过"删除 + 新建"实现
  2. 复杂度显著增加:状态管理从单一变为聚合,容易出 bug
  3. 并发生成场景少:用户通常看到结果后才决定是否重新生成,很少连续点击

如果确实需要,建议简化方案:

  1. 禁止并发生成:同一任务同时只能有一个生成进行中,降低状态管理复杂度
  2. 延迟实现切换记忆selectedImageId 可以先不做服务端持久化,仅前端记忆
  3. 分阶段交付
    • 第一阶段:仅支持重新生成 + 图片切换(无并发、无持久化选择)
    • 第二阶段:按需添加并发和持久化

MJ-Studio - 多模型 AI 工作台