# 模型参数后端化方案 ## 一、当前架构(平台重构后) 平台重构已采用 **Platform Descriptor 模式**,Painting 和 Video 统一走扁平 `modelParams`: ``` src/platforms/ ├── registry.js # 注册表:registerPlatform() + createPlatform() ├── painting/ │ ├── index.js # Painting descriptor(controls, 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 | 结果 URL(24 小时有效) | | `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 上传接口三种方式传入图片。