AI_Painting_V2.0/docs/模型参数后端化方案.md
WangLeo ac7a592618 docs: 补充 dimension.separator 字段说明
JSON 无法携带 JS 函数,dimension 类型需通过 separator 字段
让前端在运行时生成等价的 parse/format 逻辑。
2026-06-09 14:39:54 +08:00

283 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 模型参数后端化方案
## 一、当前架构(平台重构后)
平台重构已采用 **Platform Descriptor 模式**Painting 和 Video 统一走扁平 `modelParams`
```
src/platforms/
├── registry.js # 注册表registerPlatform() + createPlatform()
├── painting/
│ ├── index.js # Painting descriptorcontrols, state, loadConfig 等)
│ ├── modelSelector.vue
│ ├── imageUploader.vue
│ ├── models/ # 模型参数 schema本地 JS 文件,待后端化)
│ │ ├── index.js # getModelConfig(modelName) → 查找本地 config
│ │ └── flux-2.js # 单个模型的 params 定义
│ └── controls/
│ ├── proportion.vue
│ ├── dimension.vue
│ ├── quality.vue
│ └── quantity.vue
└── video/
├── index.js # Video descriptor仍用 fetchModelConfig 拉远程 JSON
├── modelSelector.vue
├── imageUploader.vue
└── controls/
├── pattern.vue
├── proportion.vue
└── time.vue
```
**核心数据流(两个平台统一):**
1. 用户选择模型 → `dialogBox` 调用 `platform.loadConfig(modelName, modelType)`
2. `loadConfig` 获取参数 schema → 驱动 `controls` 数组渲染对应 UI 控件
3. 用户点击发送 → `platform.buildTaskBody({ prompt, referenceImages })` 返回扁平 `modelParams`
4. `createTask.js` 透传 `data.body`(不再做任何转换)
5. POST `/suanli/v1/tasks`,携带 `X-Session-Id` header
**当前参数配置来源(待统一):**
| 平台 | 参数配置来源 | 位置 |
|------|-------------|------|
| Painting | 本地 JS 文件(硬编码) | `src/platforms/painting/models/*.js` |
| Video | 远程静态 JSON每日 localStorage 缓存) | `fetchModelConfig()``resources.xueai.art/AIGC/static/public/Platform/Video/workflows/...` |
两个平台的 `buildTaskBody()` 均已返回扁平 `modelParams`,不再构造 `{ workflowId, nodeInfoList }` 格式。
---
## 二、目标架构
将模型参数配置从**前端代码**迁移到**后端 API**,实现:
- 新增模型/修改参数无需前端发版
- Painting 和 Video 使用统一的 API 获取配置
- 前端只保留 UI 控件库,参数 schema 完全由后端驱动
```
后端 API
├── GET /api/v1/platforms/:code/models # 模型列表(已有)
│ └── 响应: [{ id, display_name, tags, config? }]
├── GET /api/v1/models/:id/config # 模型参数配置(新增)
│ └── 响应: { params: [...], inputType, maxImages, ... }
└── POST /api/v1/tasks # 创建任务(已有)
└── 请求体: 扁平 modelParams与 RunningHub API 格式对齐)
```
**改造后的数据流:**
```
用户选择模型
→ platform.loadConfig(modelName)
→ GET /api/v1/models/:id/config
→ 返回 { params: [{ name, ui, default, options, ... }] }
→ 前端根据 ui 字段渲染对应控件
→ 用户填写参数
→ buildTaskBody() 返回扁平 { aspectRatio, resolution, ... }
→ POST /api/v1/tasks
```
---
## 三、模型配置 API 格式
### 3.1 请求
```
GET /api/v1/models/:modelId/config
```
`modelId` 来自模型列表接口返回的 `id` 字段UUID
### 3.2 响应格式
```json
{
"code": 0,
"data": {
"inputType": "text",
"maxImages": 4,
"promptPlaceholder": "描述你想生成的画面和动作。",
"params": [
{
"name": "prompt",
"ui": "textarea",
"label": "提示词",
"required": true,
"default": ""
},
{
"name": "aspectRatio",
"ui": "proportion",
"label": "比例",
"default": "1:1",
"options": ["1:1", "3:4", "4:3", "9:16", "16:9", "custom"]
},
{
"name": "resolution",
"ui": "resolution",
"label": "分辨率",
"default": "2k",
"options": ["1k", "2k", "4k"]
},
{
"name": "size",
"ui": "dimension",
"label": "尺寸",
"default": "1024*1024",
"dimension": {
"separator": "*",
"width": { "min": 256, "max": 6197 },
"height": { "min": 256, "max": 4096 }
}
},
{
"name": "quality",
"ui": "select",
"label": "画质",
"default": "medium",
"options": ["low", "medium", "high"]
},
{
"name": "quantity",
"ui": "quantity",
"label": "生成数量",
"default": 1,
"options": [1, 2, 3, 4]
},
{
"name": "imageUrl",
"ui": "imageUpload",
"label": "参考图",
"maxCount": 4
}
]
}
}
```
### 3.3 `ui` 字段与前端控件映射
| `ui` 值 | 前端控件 | 说明 |
|---------|---------|------|
| `textarea` | Sender 内置 textarea | 提示词输入框,不需要额外渲染控件 |
| `proportion` | `PaintingProportion` / `VideoProportion` | 比例选择 Popover`options` 含 `custom` 时允许自定义宽高 |
| `resolution` | `proportion` 控件内部 | 分辨率子选项,与 proportion 共用 Popover |
| `dimension` | `DimensionInput` | **组合模式**:单字段 `"W*H"` 格式,通过 `dimension.parse/format` 序列化 |
| `dimensionWidth` + `dimensionHeight` | `DimensionInput` | **拆分模式**:两个独立字段,共享同一个 Popover 和比例锁 |
| `select` | `Select` | 通用下拉选择(如 quality |
| `quantity` | `Quantity` | 生成数量,上限由 `options` 最大值派生 |
| `imageUpload` | `ImageUploader` | 参考图上传,`maxCount` 控制数量上限 |
| `hidden` | 无 | 静默写入默认值,不渲染控件 |
> **关于 `dimension.separator`** 当前前端 Painting 配置中 `parse/format` 为 JS 函数(`s.split('*')` / `` `${w}*${h}` ``),后端返回 JSON 无法携带函数。因此 `dimension` 类型的配置需包含 `separator` 字段,前端据此在运行时生成等价的 parse/format 逻辑,无需硬编码分隔符。拆分模式(`dimensionWidth` + `dimensionHeight`)无此字段。
### 3.4 条件显示
```json
{
"name": "customWidth",
"ui": "dimensionWidth",
"showWhen": { "aspectRatio": "custom" }
}
```
`showWhen` 字段使参数仅在指定条件满足时显示。当前支持的条件:`aspectRatio` 值为 `custom`
---
## 四、迁移步骤
### 阶段一:后端实现模型配置 API
- [ ] 设计并实现 `GET /api/v1/models/:id/config` 接口
- [ ] 将 Painting 的 9 个模型配置(`src/platforms/painting/models/*.js`)迁移到数据库/配置文件
- [ ] 将 Video 的 workflow 配置(`resources.xueai.art/AIGC/static/public/Platform/Video/workflows/...`)迁移到同一接口
- [ ] 响应格式对齐 3.2 节的 schema
### 阶段二:前端适配
- [ ] `src/platforms/painting/models/` 目录删除,`getModelConfig()` 改为调用 API
- [ ] `src/utils/modelConfig.js`Video 旧架构遗留删除Video descriptor 改为调用同一 API
- [ ] `src/utils/createTask.js`(当前仅透传)删除,`dialogBox` 直接使用 `buildTaskBody()` 返回值
- [ ] Painting descriptor 的 `loadConfig()` 改为 `fetch` API + 本地缓存30s TTL与模型列表一致
### 阶段三:清理
- [ ] 删除 `src/utils/modelConfig.js`
- [ ] 删除 `src/utils/createTask.js`
- [ ] 确认前端不再包含任何硬编码的模型参数
---
## 五、与 RunningHub API 的关系
后端创建任务的请求体格式应**直接对齐 RunningHub 标准模型 API**,前端 `buildTaskBody()` 返回的扁平 `modelParams` 即是 API body
```json
{
"prompt": "...",
"resolution": "720p",
"aspectRatio": "16:9",
"duration": 5
}
```
不再需要中间层转换(旧架构的 `src/config/runninghub/` 已删除)。
---
## 附录RunningHub API 参考
以下为 RunningHub 标准模型 API 的原始文档,作为后端任务创建接口的设计参考。
### A.1 提交任务
```curl
curl --location --request POST 'https://www.runninghub.cn/openapi/v2/rhart-video/ltx-2.3/text-to-video' \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${RUNNINGHUB_API_KEY}" \
--data-raw '{
"prompt": "...",
"resolution": "720p",
"aspectRatio": "16:9",
"duration": 5
}'
```
| 参数 | 类型 | 必填/可选 | 说明 |
| --- | --- | --- | --- |
| `prompt` | String | 必填 | 提示词 |
| `resolution` | String | 必填 | 枚举值: [1080p, 720p, 480p] |
| `aspectRatio` | String | 必填 | 枚举值: [16:9, 9:16] |
| `duration` | Int | 必填 | 输入范围值: 5 - 15 |
### A.2 查询结果
```curl
curl --location --request POST 'https://www.runninghub.cn/openapi/v2/query' \
--header "Content-Type: application/json" \
--header "Authorization: Bearer ${RUNNINGHUB_API_KEY}" \
--data-raw '{"taskId": "${RUNNINGHUB_TASKID}"}'
```
响应字段:
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `taskId` | String | 任务 ID |
| `status` | String | QUEUED / RUNNING / SUCCESS / FAILED |
| `results` | List | 生成结果列表 |
| `results[].url` | String | 结果 URL24 小时有效) |
| `results[].nodeId` | String | 工作流节点 ID |
| `results[].outputType` | String | 文件扩展名 (png, mp4, txt) |
| `results[].text` | String | 纯文本输出内容 |
### A.3 文件上传
**上传接口:** `POST https://www.runninghub.cn/openapi/v2/media/upload/binary`
支持 `imageUrls`(公共 URL、Base64 Data URI、RH 上传接口三种方式传入图片。