Skip to content

嵌入式绘图组件介绍

在 MJ-Studio 的对话功能中,AI 可以通过 Markdown 代码块直接生成插图,让文字内容与视觉效果无缝结合。这个功能特别适合生成小说配图、教程插图、场景可视化等场景。

功能概述

  • 对话中生图: AI 在回复中插入特殊格式的代码块,自动触发图片生成
  • 幂等设计: 相同的唯一标识不会重复生成,刷新页面保持状态
  • 状态同步: 基于全局事件系统,图片生成进度实时更新
  • 任务复用: 与绘图工作台共享任务系统,统一管理
  • 模糊控制: 遵循全局模糊设置,保护隐私内容

使用方式

AI 输出格式

AI 在回复中使用 mj-drawing 代码块定义绘图参数:

markdown
```mj-drawing
uniqueId: 第一章-主角初遇场景
prompt: A young swordsman drawing his sword under moonlight, silver blade reflecting the moon
model: flux-schnell
negative: blurry, low quality
autostart: false
```

参数说明

参数必需默认值说明
uniqueId-全局唯一标识,用于缓存和去重
prompt-绘图提示词
model默认配置模型名称,匹配用户启用的模型配置
negative-负面提示词
autostartfalse是否自动开始生成

uniqueId 设计

  • 用途: 防止相同场景重复生图,支持刷新页面后状态恢复
  • 格式建议: 章节-场景-序号,如 第一章-林雨拔剑-001
  • 全局唯一: 同一用户下,相同 uniqueId 只会生成一次任务

autostart 参数

  • false (默认): 显示"生成插图"按钮,用户点击后才开始生成
  • true: 组件挂载后自动开始生成任务

典型场景

场景 1: 小说配图

AI 在生成小说内容时,在关键场景自动插入绘图组件:

markdown
林雨缓缓拔出长剑,月光在剑身上流转,映照出他坚毅的面容。

```mj-drawing
uniqueId: 第一章-林雨拔剑-001
prompt: A young swordsman drawing his sword under moonlight, silver blade reflecting the moon, determined expression, ancient Chinese martial arts style, dramatic lighting, cinematic composition
model: flux-schnell
negative: blurry, low quality, modern clothing
```

对面的蒙面杀手也不甘示弱,黑色斗篷在夜风中猎猎作响。

场景 2: 教程插图

技术教程中插入架构图或流程图:

markdown
用户登录流程如下:

```mj-drawing
uniqueId: 用户登录流程图
prompt: Clean flowchart diagram showing user login process, boxes and arrows, professional style, white background
model: dalle-3
negative: messy, cluttered
```

首先验证用户名和密码...

场景 3: 场景可视化

游戏设计文档中可视化场景:

markdown
这个关卡的地图布局如下:

```mj-drawing
uniqueId: 第三关-地图布局
prompt: Top-down view of a dungeon level, stone corridors, treasure chests, monster spawn points, grid-based layout, pixel art style
model: midjourney-v6
```

玩家从左上角入口进入...

组件界面

状态显示

嵌入式绘图组件会根据任务状态显示不同的界面:

idle 状态 (等待生成):

┌─────────────────────────────────────┐
│  ┌─────────────────────────────┐   │
│  │         ✨ 图标              │   │
│  │      等待提交                │   │
│  │   [生成插图] 按钮            │   │
│  │                             │   │
│  │  ─────────────────────      │   │
│  │  uniqueId: xxx              │   │
│  │  prompt: xxx                │   │
│  └─────────────────────────────┘   │
│  [模型标签]                         │
└─────────────────────────────────────┘

processing 状态 (生成中):

┌─────────────────────────────────────┐
│  ┌─────────────────────────────┐   │
│  │      [竖线加载动画]          │   │
│  │     正在创作中...            │   │
│  │                             │   │
│  │  ─────────────────────      │   │
│  │  uniqueId: xxx              │   │
│  │  prompt: xxx                │   │
│  └─────────────────────────────┘   │
│  [模型标签]                         │
│  ════════════════════════════════  │ ← 彩色进度条
└─────────────────────────────────────┘

success 状态 (已完成):

┌─────────────────────────────────────┐
│  [生成的图片]                       │
│  (点击切换模糊/清晰)                │
│                                     │
│  [操作按钮组] ← 默认隐藏            │
│  [模型标签]                         │
└─────────────────────────────────────┘

failed 状态 (失败):

┌─────────────────────────────────────┐
│  ┌─────────────────────────────┐   │
│  │         ⚠️ 图标              │   │
│  │       生成失败               │   │
│  │    错误信息: xxx             │   │
│  │     [重试] 按钮              │   │
│  │  ─────────────────────      │   │
│  │  uniqueId: xxx              │   │
│  │  prompt: xxx                │   │
│  └─────────────────────────────┘   │
│  [模型标签]                         │
└─────────────────────────────────────┘

操作按钮

按钮显示规则 (仅成功状态):

  • 默认隐藏: 所有按钮默认不显示
  • PC 端: 鼠标悬浮图片时显示按钮
  • 移动端: 点击图片切换按钮显示/隐藏

按钮布局 (左上角半透明按钮组):

┌─────────────────────────────────────┐
│  [⬇][🔍][🔄][ℹ️]  ← 半透明圆形按钮  │
│                                     │
│         [生成的图片]                │
│                                     │
│  [模型标签]                         │
└─────────────────────────────────────┘

按钮功能:

  1. 下载按钮 (⬇): 下载图片到本地
  2. 放大查看 (🔍): 在模态框中查看大图
  3. 重新生成 (🔄): 删除旧任务重新生成
  4. 查看详情 (ℹ️): 显示 uniqueId、提示词、模型等信息

详情弹窗

点击信息按钮显示绘图参数:

┌─────────────────────────────────┐
│  绘图详情                  [×]  │
├─────────────────────────────────┤
│                                 │
│  标识 (uniqueId)                │
│  第一章-林雨拔剑-001             │
│                                 │
│  提示词 (prompt)                │
│  A young swordsman drawing...   │
│                                 │
│  模型 (model)                   │
│  flux-schnell                   │
│                                 │
│  负面提示词 (negative)          │
│  blurry, low quality           │
│                                 │
│           [关闭]                │
└─────────────────────────────────┘

技术实现

前端流程

1. AI 输出 mj-drawing 代码块

2. useMarkdown 识别并解析参数

3. MarkdownContent 渲染 MjDrawingBlock 组件

4. 组件挂载时调用 POST /api/illustrations
   - 已存在任务 → 显示当前状态
   - 不存在 + autostart=false → 显示"生成"按钮
   - 不存在 + autostart=true → 创建并开始任务

5. 订阅全局事件,实时更新任务状态

6. 任务完成后显示图片

流式输出处理

AI 流式输出时,代码块可能未闭合:

AI 正在输出 →  ```mj-drawing
               uniqueId: xxx
               prompt: A young... (未闭合)

解决方案:

  • 检测未闭合的代码块,显示占位符 "正在生成插图参数..."
  • 等待代码块闭合后再解析参数
  • 清理 AI 输出中的零宽字符,避免解析错误

数据库设计

复用 tasks 表,新增两个字段:

字段类型说明
uniqueIdTEXT全局唯一标识 (唯一索引)
sourceTypeTEXT来源类型 (workbench / chat)

来源标记:

  • workbench: 绘图工作台创建
  • chat: 对话中的嵌入式绘图组件创建

筛选分离:

  • 绘图工作台默认只显示 sourceType = workbench 的任务
  • 需要筛选才会显示 sourceType = chat 的任务

API 接口

POST /api/illustrations

查询或创建插图任务 (幂等接口)

请求体:

json
{
  "uniqueId": "第一章-林雨拔剑-001",
  "prompt": "A young swordsman...",
  "model": "flux-schnell",
  "negative": "blurry, low quality",
  "autostart": false
}

响应:

json
{
  "taskId": 123,
  "status": "success",
  "progress": null,
  "resourceUrl": "/api/images/xxx.jpg",
  "error": null,
  "isBlurred": true
}

逻辑:

  1. 根据 uniqueId 查询任务
  2. 已存在 → 返回当前状态
  3. 不存在 + autostart=false → 返回 { status: 'idle', taskId: null }
  4. 不存在 + autostart=true → 创建任务并提交,返回 pending 状态

核心组件

组件文件路径功能
useMarkdownapp/composables/useMarkdown.ts识别 mj-drawing 代码块,生成占位符 HTML
MarkdownContentapp/components/chat/MarkdownContent.vue解析占位符,渲染 MjDrawingBlock 组件
MjDrawingBlockapp/components/chat/MjDrawingBlock.vue嵌入式绘图组件,管理任务状态和 UI

与绘图工作台的关系

共享部分

  • 任务系统: 共享 tasks 表和任务服务
  • 模型配置: 使用相同的上游和模型配置
  • 全局事件: 共享任务状态更新事件
  • 模糊控制: 遵循全局模糊设置

独立部分

  • 来源标记: sourceType = chat,与工作台任务分开筛选
  • 唯一标识: uniqueId 字段,工作台任务为 null
  • 参数来源: 通过代码块定义,而非表单输入
  • 自动触发: 支持 autostart 自动生成

配置 AI 助手

要让 AI 在对话中使用嵌入式绘图功能,可以在助手的 System Prompt 中添加指引:

## 插图功能

在输出小说内容时,请在以下场景插入绘图组件生成插图:
- 重要场景切换
- 关键人物登场
- 高潮情节
- 环境氛围描写

### 插图组件格式

​```mj-drawing
uniqueId: 唯一标识 (描述性名称,如"第一章-主角初遇场景")
prompt: 详细的画面描述 (英文效果更佳)
model: flux-schnell
negative: blurry, low quality, distorted
​```

### 插图要求

1. uniqueId 必须全局唯一,建议格式: 章节-场景-序号
2. prompt 要详细描述:
   - 人物外貌、服装、动作
   - 场景环境、光线、氛围
   - 画面构图、视角
   - 艺术风格 (如: digital art, anime style, realistic)
3. 每个章节建议 2-4 张插图
4. 插图位置应在相关描写段落之后

### 插图示例

林雨缓缓拔出长剑,月光在剑身上流转,映照出他坚毅的面容。

​```mj-drawing
uniqueId: 第一章-林雨拔剑-001
prompt: A young swordsman drawing his sword under moonlight, silver blade reflecting the moon, determined expression, ancient Chinese martial arts style, dramatic lighting, cinematic composition
model: flux-schnell
negative: blurry, low quality, modern clothing
​```

对面的蒙面杀手也不甘示弱,黑色斗篷在夜风中猎猎作响。

使用技巧

优化提示词

  • 详细描述: 包含人物、场景、光线、氛围、风格等要素
  • 英文优先: 大部分模型对英文提示词效果更好
  • 指定风格: 添加 digital artanime stylerealistic 等风格关键词
  • 负面提示词: 使用 blurrylow qualitydistorted 等避免常见问题

uniqueId 命名规范

  • 描述性: 清晰描述场景,如 第一章-林雨拔剑-001
  • 层级结构: 章节-场景-序号
  • 唯一性: 确保全局唯一,避免重复生成

模型选择

  • 快速生成: flux-schnell (速度快,效果好)
  • 高质量: midjourney-v6dalle-3 (质量高,速度慢)
  • 中文提示词: z-image-turbo (支持中文提示词)

注意事项

限制和约束

  • uniqueId 唯一性: 相同 uniqueId 只会生成一次,修改参数不会重新生成
  • 模型可用性: 指定的 model 必须在用户的上游配置中存在
  • 流式输出: 代码块未闭合时不会触发生成,等待完整输出
  • 事件订阅: 需要用户登录并建立全局 SSE 连接

性能优化

  • 懒加载: 组件挂载时才查询任务状态
  • 事件驱动: 状态更新通过全局事件推送,不轮询
  • 模糊加载: 图片默认模糊,点击后加载原图
  • 缓存复用: 相同 uniqueId 复用已有任务

下一步计划

短期增强

  • 批量操作: 支持一键重新生成所有失败的插图
  • 参数编辑: 允许用户修改 uniqueId 后的绘图参数
  • 预览优化: 支持图片放大查看、全屏模式

中期扩展

  • 视频支持: 支持 mj-video 代码块生成视频
  • 音频支持: 支持 mj-audio 代码块生成配乐
  • 图库导入: 支持从图库选择已有图片作为插图

长期规划

  • 智能插图: AI 自动判断何时需要插图,自动生成
  • 风格一致性: 同一对话中的插图保持风格一致
  • 角色记忆: 记住角色外貌,保持插图中的角色一致性

MJ-Studio - 多模型 AI 工作台