From 0a06783f44176ae3eb687f755526500c0f74b8e3 Mon Sep 17 00:00:00 2001 From: ddCat <2695092045@qq.com> Date: Sat, 19 Sep 2026 07:48:08 +0800 Subject: [PATCH] =?UTF-8?q?fix(*):=20=E8=A7=86=E9=A2=91=E8=AE=A1=E8=B4=B9?= =?UTF-8?q?=E4=B8=8E=E7=BB=93=E6=9E=9C=E8=A7=A3=E6=9E=90=20-=20=E6=8C=89?= =?UTF-8?q?=20Token=20=E9=A2=84=E4=BC=B0=E5=B1=95=E7=A4=BA=E5=B9=B6?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=95=B0=E7=BB=84=E5=AA=92=E4=BD=93=E7=BB=93?= =?UTF-8?q?=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../protocol/official_catalog_test.go | 10 +++--- .../newapi-video-generations-v1.yingce-plugin | Bin 8129 -> 8410 bytes .../docs/interface.md | 29 ++++++++++++++++- .../newapi-video-generations-v1/manifest.json | 29 ++++++++++++++++- .../canvas/canvas-node-prompt-panel.tsx | 4 +-- web/src/components/model-picker.tsx | 2 +- web/src/pages/create/creation-workspace.tsx | 30 +++++++++++++++--- .../detail/workflow-production-workbench.tsx | 2 +- 8 files changed, 92 insertions(+), 14 deletions(-) diff --git a/backend/internal/protocol/official_catalog_test.go b/backend/internal/protocol/official_catalog_test.go index a7839099c..c949d10a8 100644 --- a/backend/internal/protocol/official_catalog_test.go +++ b/backend/internal/protocol/official_catalog_test.go @@ -441,9 +441,11 @@ func TestNewAPIVideoGenerationsParsesNestedVideoResults(t *testing.T) { tests := []struct { name string payload string + wantURL string }{ - {name: "channel result URL", payload: `{"code":"success","data":{"task_id":"task-upstream","status":"SUCCESS","result_url":"https://cdn.example/channel-result.mp4"}}`}, - {name: "provider nested video URL", payload: `{"code":"success","data":{"task_id":"task-upstream","status":"SUCCESS","data":{"status":"completed","video_url":"https://cdn.example/provider-result.mp4"}}}`}, + {name: "channel result URL", payload: `{"code":"success","data":{"task_id":"task-upstream","status":"SUCCESS","result_url":"https://cdn.example/channel-result.mp4"}}`, wantURL: "https://cdn.example/channel-result.mp4"}, + {name: "provider nested video URL", payload: `{"code":"success","data":{"task_id":"task-upstream","status":"SUCCESS","data":{"status":"completed","video_url":"https://cdn.example/provider-result.mp4"}}}`, wantURL: "https://cdn.example/provider-result.mp4"}, + {name: "provider data array URL", payload: `{"created":1789773326,"data":[{"url":"https://cdn.example/seedance-result.mp4?preview=1"}],"id":"task-upstream","object":"video.generation","status":"completed","usage":{"completion_tokens":108872,"total_tokens":108872}}`, wantURL: "https://cdn.example/seedance-result.mp4?preview=1"}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -454,8 +456,8 @@ func TestNewAPIVideoGenerationsParsesNestedVideoResults(t *testing.T) { if state.Status != StatusSucceeded || state.Result == nil || len(state.Result.Videos) != 1 { t.Fatalf("state = %#v, want one completed video", state) } - if state.Result.Videos[0].URL == "" { - t.Fatalf("video = %#v, want a result URL", state.Result.Videos[0]) + if state.Result.Videos[0].URL != test.wantURL { + t.Fatalf("video = %#v, want URL %q", state.Result.Videos[0], test.wantURL) } }) } diff --git a/plugin-packages/newapi-video-generations-v1.yingce-plugin b/plugin-packages/newapi-video-generations-v1.yingce-plugin index a66e26a907c84cdd3d75e8db61e8341fe3cc81a7..ca2eace898d788052c113111a342b7a61800227f 100644 GIT binary patch delta 8083 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 delta 7800 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\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"newapi-video-generations-v1\",\n \"name\": \"NewAPI Video Generations Channel 2\",\n \"version\": \"2.0.0\",\n \"author\": \"NewAPI / 影策\",\n \"description\": \"NewAPI Video Generations Channel 2 独立请求协议插件。\",\n \"documentation\": \"<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>\",\n \"permissions\": [\n \"generation.run\",\n \"media.read\"\n ],\n \"configuration\": {\n \"fields\": [\n {\n \"name\": \"apiKey\",\n \"type\": \"secret\",\n \"label\": \"API Key\",\n \"required\": true\n }\n ]\n },\n \"contributes\": {\n \"providers\": [\n {\n \"id\": \"newapi-channel-2\",\n \"label\": \"NewAPI Video Generations Channel 2\",\n \"capabilities\": [\n \"video\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"http://127.0.0.1:3000\",\n \"requiresPublicMediaUrls\": true,\n \"auth\": {\n \"type\": \"bearer\",\n \"field\": \"apiKey\"\n },\n \"parameters\": [\n {\n \"name\": \"model\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"model\",\n \"description\": \"视频模型 ID。\"\n },\n {\n \"name\": \"prompt\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"prompt/content/input\",\n \"description\": \"视频提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"first/last/reference image\",\n \"description\": \"显式 role 图片输入。\"\n },\n {\n \"name\": \"videos\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"reference video\",\n \"description\": \"参考视频。\"\n },\n {\n \"name\": \"audios\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"reference audio/voice\",\n \"description\": \"参考音频或音色。\"\n },\n {\n \"name\": \"duration\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"duration/seconds\",\n \"description\": \"时长秒数。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"ratio/aspect_ratio/size\",\n \"description\": \"画幅比例或尺寸。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution\",\n \"description\": \"分辨率档位。\"\n },\n {\n \"name\": \"generateAudio\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"generate_audio\",\n \"description\": \"是否生成音频。\"\n },\n {\n \"name\": \"watermark\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"watermark\",\n \"description\": \"水印开关。\"\n },\n {\n \"name\": \"providerOptions\",\n \"type\": \"object\",\n \"required\": false,\n \"mapping\": \"provider-specific fields\",\n \"description\": \"插件命名空间内的厂商扩展字段。\"\n }\n ],\n \"create\": {\n \"method\": \"POST\",\n \"path\": \"/v1/video/generations\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"prompt\": {\n \"$ref\": \"request.prompt\"\n },\n \"seconds\": {\n \"$toString\": {\n \"$ref\": \"request.duration\"\n }\n },\n \"aspect_ratio\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"16:9\"\n ]\n },\n \"resolution\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.resolution\"\n }\n },\n \"generate_audio\": {\n \"$ref\": \"request.generateAudio\"\n },\n \"image_urls\": {\n \"$omitEmpty\": {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.images\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n },\n \"video_urls\": {\n \"$omitEmpty\": {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.videos\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n },\n \"audio_urls\": {\n \"$omitEmpty\": {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.audios\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n }\n }\n },\n \"poll\": {\n \"method\": \"GET\",\n \"path\": \"/v1/video/generations/{{taskId}}\"\n },\n \"response\": {\n \"taskId\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.data.task_id\"\n },\n {\n \"$ref\": \"response.data.taskId\"\n },\n {\n \"$ref\": \"response.task_id\"\n },\n {\n \"$ref\": \"response.taskId\"\n },\n {\n \"$ref\": \"response.data.id\"\n },\n {\n \"$ref\": \"response.id\"\n },\n {\n \"$ref\": \"taskId\"\n }\n ]\n },\n \"status\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.status\"\n },\n {\n \"$ref\": \"response.state\"\n },\n {\n \"$ref\": \"response.data.status\"\n },\n \"pending\"\n ]\n },\n \"message\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.error.message\"\n },\n {\n \"$ref\": \"response.message\"\n },\n {\n \"$ref\": \"response.fail_reason\"\n }\n ]\n },\n \"videos\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.data.result_url\"\n },\n {\n \"$ref\": \"response.data.video_url\"\n },\n {\n \"$ref\": \"response.data.output_url\"\n },\n {\n \"$ref\": \"response.data.url\"\n },\n {\n \"$ref\": \"response.data.metadata.url\"\n },\n {\n \"$ref\": \"response.data.data.video_url\"\n },\n {\n \"$ref\": \"response.data.data.output_url\"\n },\n {\n \"$ref\": \"response.data.data.result_url\"\n },\n {\n \"$ref\": \"response.data.data.url\"\n },\n {\n \"$ref\": \"response.data.data.metadata.url\"\n },\n {\n \"$ref\": \"response.video_url\"\n },\n {\n \"$ref\": \"response.videoUrl\"\n },\n {\n \"$ref\": \"response.result_url\"\n },\n {\n \"$ref\": \"response.output_url\"\n },\n {\n \"$ref\": \"response.url\"\n },\n {\n \"$ref\": \"response.metadata.url\"\n },\n {\n \"$ref\": \"response.output.url\"\n }\n ]\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"resultEphemeral\": true\n }\n }\n ]\n }\n}\n```\n\n", + "documentation": "# NewAPI Video Generations Channel 2\n\n该目录是独立官方协议插件源码。后端从生成的 `newapi-video-generations-v1.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# NewAPI Video Generations Channel 2 接口字段\n\n## 协议身份\n\n- 插件 ID:`newapi-video-generations-v1`。\n- Provider ID:`newapi-channel-2`。\n- 能力:`video`。\n- 默认 Base URL:`http://127.0.0.1:3000`。\n- 鉴权驱动:`bearer`。\n- 创建:`POST /v1/video/generations`。\n- 查询:`GET /v1/video/generations/{{taskId}}`。\n\n## 配置字段\n\n| 字段 | 类型 | 必填 | 含义 |\n| --- | --- | --- | --- |\n| `apiKey` | secret | 是 | API Key |\n\n## 统一字段映射\n\n| 统一字段 | 类型 | 必填 | 上游映射 | 说明 |\n| --- | --- | --- | --- | --- |\n| `model` | string | 是 | `model` | 视频模型 ID。 |\n| `prompt` | string | 是 | `prompt/content/input` | 视频提示词。 |\n| `images` | media[] | 否 | `first/last/reference image` | 显式 role 图片输入。 |\n| `videos` | media[] | 否 | `reference video` | 参考视频。 |\n| `audios` | media[] | 否 | `reference audio/voice` | 参考音频或音色。 |\n| `duration` | integer | 否 | `duration/seconds` | 时长秒数。 |\n| `aspectRatio` | string | 否 | `ratio/aspect_ratio/size` | 画幅比例或尺寸。 |\n| `resolution` | string | 否 | `resolution` | 分辨率档位。 |\n| `generateAudio` | boolean | 否 | `generate_audio` | 是否生成音频。 |\n| `watermark` | boolean | 否 | `watermark` | 水印开关。 |\n| `providerOptions` | object | 否 | `provider-specific fields` | 插件命名空间内的厂商扩展字段。 |\n\n## 上游请求模板逐字段清单\n\n下表由插件请求模板生成,覆盖 body、query、headers 和 multipart 文件声明中的每个字段。\n\n| 上游位置 | 值或转换表达式 |\n| --- | --- |\n| `create.method` | `\"POST\"` |\n| `create.path` | `\"/v1/video/generations\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.prompt` | `{\"$ref\":\"request.prompt\"}` |\n| `create.body.seconds` | `{\"$toString\":{\"$ref\":\"request.duration\"}}` |\n| `create.body.aspect_ratio` | `{\"$coalesce\":[{\"$ref\":\"request.aspectRatio\"},\"16:9\"]}` |\n| `create.body.resolution` | `{\"$omitEmpty\":{\"$ref\":\"request.resolution\"}}` |\n| `create.body.generate_audio` | `{\"$ref\":\"request.generateAudio\"}` |\n| `create.body.image_urls` | `{\"$omitEmpty\":{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.images\"}},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}}}` |\n| `create.body.video_urls` | `{\"$omitEmpty\":{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.videos\"}},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}}}` |\n| `create.body.audio_urls` | `{\"$omitEmpty\":{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.audios\"}},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}}}` |\n| `poll.method` | `\"GET\"` |\n| `poll.path` | `\"/v1/video/generations/{{taskId}}\"` |\n| `poll.contentType` | `\"application/json\"` |\n\n## Provider 扩展键\n\n- 无额外扩展键。\n\n动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。\n\n## 响应映射逐字段清单\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.taskId` | `{\"$coalesce\":[{\"$ref\":\"response.data.task_id\"},{\"$ref\":\"response.data.taskId\"},{\"$ref\":\"response.task_id\"},{\"$ref\":\"response.taskId\"},{\"$ref\":\"response.data.id\"},{\"$ref\":\"response.id\"},{\"$ref\":\"taskId\"}]}` |\n| `response.status` | `{\"$coalesce\":[{\"$ref\":\"response.status\"},{\"$ref\":\"response.state\"},{\"$ref\":\"response.data.status\"},\"pending\"]}` |\n| `response.message` | `{\"$coalesce\":[{\"$ref\":\"response.error.message\"},{\"$ref\":\"response.message\"},{\"$ref\":\"response.fail_reason\"}]}` |\n| `response.videos` | `{\"$coalesce\":[{\"$map\":{\"from\":{\"$ref\":\"response.data\"},\"as\":\"item\",\"in\":{\"$coalesce\":[{\"$ref\":\"item.url\"},{\"$ref\":\"item.video_url\"},{\"$ref\":\"item.videoUrl\"},{\"$ref\":\"item.output_url\"},{\"$ref\":\"item.outputUrl\"}]}}},{\"$ref\":\"response.data.result_url\"},{\"$ref\":\"response.data.video_url\"},{\"$ref\":\"response.data.output_url\"},{\"$ref\":\"response.data.url\"},{\"$ref\":\"response.data.metadata.url\"},{\"$ref\":\"response.data.data.video_url\"},{\"$ref\":\"response.data.data.output_url\"},{\"$ref\":\"response.data.data.result_url\"},{\"$ref\":\"response.data.data.url\"},{\"$ref\":\"response.data.data.metadata.url\"},{\"$ref\":\"response.video_url\"},{\"$ref\":\"response.videoUrl\"},{\"$ref\":\"response.result_url\"},{\"$ref\":\"response.output_url\"},{\"$ref\":\"response.url\"},{\"$ref\":\"response.metadata.url\"},{\"$ref\":\"response.output.url\"}]}` |\n| `response.errorPaths[0]` | `\"error.code\"` |\n| `response.resultEphemeral` | `true` |\n\n## 响应与错误\n\n插件把上游 task/status/text/media/usage 映射为统一结果。临时媒体 URL 标记为 ephemeral,由宿主立即下载持久化。HTTP 错误、业务 code 和 error object 保持失败语义,不包装成成功。\n\n## 兼容边界\n\n该包只代表上述线协议 profile;同一品牌的其他 endpoint、云区域或网关包装必须使用独立插件,不能根据模型名猜测。\n\n\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"newapi-video-generations-v1\",\n \"name\": \"NewAPI Video Generations Channel 2\",\n \"version\": \"2.0.0\",\n \"author\": \"NewAPI / 影策\",\n \"description\": \"NewAPI Video Generations Channel 2 独立请求协议插件。\",\n \"documentation\": \"<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>\",\n \"permissions\": [\n \"generation.run\",\n \"media.read\"\n ],\n \"configuration\": {\n \"fields\": [\n {\n \"name\": \"apiKey\",\n \"type\": \"secret\",\n \"label\": \"API Key\",\n \"required\": true\n }\n ]\n },\n \"contributes\": {\n \"providers\": [\n {\n \"id\": \"newapi-channel-2\",\n \"label\": \"NewAPI Video Generations Channel 2\",\n \"capabilities\": [\n \"video\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"http://127.0.0.1:3000\",\n \"requiresPublicMediaUrls\": true,\n \"auth\": {\n \"type\": \"bearer\",\n \"field\": \"apiKey\"\n },\n \"parameters\": [\n {\n \"name\": \"model\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"model\",\n \"description\": \"视频模型 ID。\"\n },\n {\n \"name\": \"prompt\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"prompt/content/input\",\n \"description\": \"视频提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"first/last/reference image\",\n \"description\": \"显式 role 图片输入。\"\n },\n {\n \"name\": \"videos\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"reference video\",\n \"description\": \"参考视频。\"\n },\n {\n \"name\": \"audios\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"reference audio/voice\",\n \"description\": \"参考音频或音色。\"\n },\n {\n \"name\": \"duration\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"duration/seconds\",\n \"description\": \"时长秒数。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"ratio/aspect_ratio/size\",\n \"description\": \"画幅比例或尺寸。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution\",\n \"description\": \"分辨率档位。\"\n },\n {\n \"name\": \"generateAudio\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"generate_audio\",\n \"description\": \"是否生成音频。\"\n },\n {\n \"name\": \"watermark\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"watermark\",\n \"description\": \"水印开关。\"\n },\n {\n \"name\": \"providerOptions\",\n \"type\": \"object\",\n \"required\": false,\n \"mapping\": \"provider-specific fields\",\n \"description\": \"插件命名空间内的厂商扩展字段。\"\n }\n ],\n \"create\": {\n \"method\": \"POST\",\n \"path\": \"/v1/video/generations\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"prompt\": {\n \"$ref\": \"request.prompt\"\n },\n \"seconds\": {\n \"$toString\": {\n \"$ref\": \"request.duration\"\n }\n },\n \"aspect_ratio\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"16:9\"\n ]\n },\n \"resolution\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.resolution\"\n }\n },\n \"generate_audio\": {\n \"$ref\": \"request.generateAudio\"\n },\n \"image_urls\": {\n \"$omitEmpty\": {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.images\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n },\n \"video_urls\": {\n \"$omitEmpty\": {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.videos\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n },\n \"audio_urls\": {\n \"$omitEmpty\": {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.audios\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n }\n }\n },\n \"poll\": {\n \"method\": \"GET\",\n \"path\": \"/v1/video/generations/{{taskId}}\"\n },\n \"response\": {\n \"taskId\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.data.task_id\"\n },\n {\n \"$ref\": \"response.data.taskId\"\n },\n {\n \"$ref\": \"response.task_id\"\n },\n {\n \"$ref\": \"response.taskId\"\n },\n {\n \"$ref\": \"response.data.id\"\n },\n {\n \"$ref\": \"response.id\"\n },\n {\n \"$ref\": \"taskId\"\n }\n ]\n },\n \"status\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.status\"\n },\n {\n \"$ref\": \"response.state\"\n },\n {\n \"$ref\": \"response.data.status\"\n },\n \"pending\"\n ]\n },\n \"message\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.error.message\"\n },\n {\n \"$ref\": \"response.message\"\n },\n {\n \"$ref\": \"response.fail_reason\"\n }\n ]\n },\n \"videos\": {\n \"$coalesce\": [\n {\n \"$map\": {\n \"from\": {\n \"$ref\": \"response.data\"\n },\n \"as\": \"item\",\n \"in\": {\n \"$coalesce\": [\n {\n \"$ref\": \"item.url\"\n },\n {\n \"$ref\": \"item.video_url\"\n },\n {\n \"$ref\": \"item.videoUrl\"\n },\n {\n \"$ref\": \"item.output_url\"\n },\n {\n \"$ref\": \"item.outputUrl\"\n }\n ]\n }\n }\n },\n {\n \"$ref\": \"response.data.result_url\"\n },\n {\n \"$ref\": \"response.data.video_url\"\n },\n {\n \"$ref\": \"response.data.output_url\"\n },\n {\n \"$ref\": \"response.data.url\"\n },\n {\n \"$ref\": \"response.data.metadata.url\"\n },\n {\n \"$ref\": \"response.data.data.video_url\"\n },\n {\n \"$ref\": \"response.data.data.output_url\"\n },\n {\n \"$ref\": \"response.data.data.result_url\"\n },\n {\n \"$ref\": \"response.data.data.url\"\n },\n {\n \"$ref\": \"response.data.data.metadata.url\"\n },\n {\n \"$ref\": \"response.video_url\"\n },\n {\n \"$ref\": \"response.videoUrl\"\n },\n {\n \"$ref\": \"response.result_url\"\n },\n {\n \"$ref\": \"response.output_url\"\n },\n {\n \"$ref\": \"response.url\"\n },\n {\n \"$ref\": \"response.metadata.url\"\n },\n {\n \"$ref\": \"response.output.url\"\n }\n ]\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"resultEphemeral\": true\n }\n }\n ]\n }\n}\n```\n\n", "permissions": [ "generation.run", "media.read" @@ -258,6 +258,33 @@ }, "videos": { "$coalesce": [ + { + "$map": { + "from": { + "$ref": "response.data" + }, + "as": "item", + "in": { + "$coalesce": [ + { + "$ref": "item.url" + }, + { + "$ref": "item.video_url" + }, + { + "$ref": "item.videoUrl" + }, + { + "$ref": "item.output_url" + }, + { + "$ref": "item.outputUrl" + } + ] + } + } + }, { "$ref": "response.data.result_url" }, diff --git a/web/src/components/canvas/canvas-node-prompt-panel.tsx b/web/src/components/canvas/canvas-node-prompt-panel.tsx index 228786735..60ac2acee 100644 --- a/web/src/components/canvas/canvas-node-prompt-panel.tsx +++ b/web/src/components/canvas/canvas-node-prompt-panel.tsx @@ -337,7 +337,7 @@ export function CanvasNodePromptPanel({ projectId, node, isRunning, onPromptChan const renderSubmitButton = (expanded: boolean) => { const showCost = creditsEnabled && credits !== null; const formattedCredits = credits?.toLocaleString("zh-CN", { maximumFractionDigits: 6 }); - const actionLabel = isRunning ? "生成中" : showCost ? `预计消耗 ${formattedCredits} 积分,生成` : "生成"; + const actionLabel = isRunning ? "生成中" : showCost ? `${routeQuote?.estimated ? "预估" : "消耗"} ${formattedCredits} 积分,生成` : "生成"; return ( diff --git a/web/src/pages/projects/detail/workflow-production-workbench.tsx b/web/src/pages/projects/detail/workflow-production-workbench.tsx index 8501983ce..1d00163c8 100644 --- a/web/src/pages/projects/detail/workflow-production-workbench.tsx +++ b/web/src/pages/projects/detail/workflow-production-workbench.tsx @@ -545,7 +545,7 @@ export default function WorkflowProductionWorkbench(props: Props) {