diff --git a/backend/internal/protocol/autodl_plugin_artifact_test.go b/backend/internal/protocol/autodl_plugin_artifact_test.go index 12c057991..ecff94c6e 100644 --- a/backend/internal/protocol/autodl_plugin_artifact_test.go +++ b/backend/internal/protocol/autodl_plugin_artifact_test.go @@ -25,7 +25,7 @@ func TestAutoDLPluginArtifact(t *testing.T) { t.Fatalf("loaded adapters = %d", len(adapters)) } adapter := adapters[0] - if adapter.Metadata().ID != "autodl-comfyui" || adapter.Metadata().Execution != "declarative" { + if adapter.Metadata().ID != "autodl-comfyui" || adapter.Metadata().Version != "1.0.1" || adapter.Metadata().Execution != "declarative" { t.Fatalf("metadata = %#v", adapter.Metadata()) } if !adapter.Metadata().RequiresPublicMediaURLs { @@ -33,7 +33,7 @@ func TestAutoDLPluginArtifact(t *testing.T) { } create, err := adapter.BuildCreate(context.Background(), RequestContext{BaseURL: "https://autodl.art", Request: GenerationRequest{ - Model: "minimax_h3_lightx2v_no_pic", Prompt: "a cinematic test", Duration: 3, Resolution: "768P", Images: []MediaReference{{URL: "https://cdn.example/reference.png"}}, + Model: "minimax_h3_lightx2v_no_pic", Prompt: "a cinematic test", Duration: 3, Resolution: "768", Images: []MediaReference{{URL: "https://cdn.example/reference.png"}}, }}) if err != nil { t.Fatal(err) diff --git a/backend/internal/protocol/builtin_test.go b/backend/internal/protocol/builtin_test.go index 8056838d7..10426f1da 100644 --- a/backend/internal/protocol/builtin_test.go +++ b/backend/internal/protocol/builtin_test.go @@ -365,6 +365,23 @@ func TestDeclarativeManifestSupportsMediaPathsTransformsAndErrors(t *testing.T) } } +func TestDeclarativeManifestNormalizesVideoResolutionWithoutBreakingWorkflowValues(t *testing.T) { + tests := map[string]string{ + "768": "768p", + "768p": "768p", + "768P": "768p", + " 768P ": "768p", + "768p竖": "768p竖", + "768P横": "768p横", + "2K": "2k", + } + for input, expected := range tests { + if actual := applyManifestTransform(input, "video-resolution"); actual != expected { + t.Errorf("video resolution transform %q = %#v, want %q", input, actual, expected) + } + } +} + func TestDeclarativeManifestRequiresDocumentation(t *testing.T) { manifest := Manifest{ APIVersion: "v1", diff --git a/backend/internal/protocol/docs/autodl-comfyui.md b/backend/internal/protocol/docs/autodl-comfyui.md index d401d709e..275293e9e 100644 --- a/backend/internal/protocol/docs/autodl-comfyui.md +++ b/backend/internal/protocol/docs/autodl-comfyui.md @@ -10,7 +10,7 @@ AutoDL 的模型选择对应 ComfyUI 工作流 ID。不同工作流可以声明 ## 参数 -请求体为 JSON。常用字段包括 `prompt`、`duration` 和 `resolution`;实际工作流可以扩展自己的参数 schema。状态返回值位于 `data.status`,任务 ID 位于 `data.task_id`,成功结果位于 `data.results`。结果数组中的地址是短期 URL,成功后必须立即由宿主下载到影策资源存储,不能把临时地址直接写入画布长期数据。 +请求体为 JSON。常用字段包括 `prompt`、`duration` 和 `resolution`;实际工作流可以扩展自己的参数 schema。插件使用 `video-resolution` 字段变换:历史状态中的纯数字 `768` 会发送为 `768p`,已经带后缀的 `768p` 以及工作流值 `768p竖`、`768p横` 保持其语义。状态返回值位于 `data.status`,任务 ID 位于 `data.task_id`,成功结果位于 `data.results`。结果数组中的地址是短期 URL,成功后必须立即由宿主下载到影策资源存储,不能把临时地址直接写入画布长期数据。 ## 鉴权 diff --git a/backend/internal/protocol/manifest.go b/backend/internal/protocol/manifest.go index f5403eb09..e20def879 100644 --- a/backend/internal/protocol/manifest.go +++ b/backend/internal/protocol/manifest.go @@ -554,11 +554,26 @@ func applyManifestTransform(value any, transform string) any { return strings.ToLower(text) case "upper", "uppercase": return strings.ToUpper(text) + case "video-resolution", "video_resolution", "videoresolution": + return normalizeManifestVideoResolution(text) default: return value } } +func normalizeManifestVideoResolution(value string) string { + normalized := strings.ToLower(strings.TrimSpace(value)) + if normalized == "" { + return "" + } + for _, char := range normalized { + if char < '0' || char > '9' { + return normalized + } + } + return normalized + "p" +} + func pathValue(payload map[string]any, path string) any { var value any = payload for _, part := range strings.Split(strings.Trim(path, "."), ".") { diff --git a/plugin-packages/autodl-comfyui.yingce-plugin b/plugin-packages/autodl-comfyui.yingce-plugin index bbcf657bc..87d348c87 100644 Binary files a/plugin-packages/autodl-comfyui.yingce-plugin and b/plugin-packages/autodl-comfyui.yingce-plugin differ diff --git a/plugin-packages/autodl-comfyui/manifest.json b/plugin-packages/autodl-comfyui/manifest.json index b3a7dc36a..89ec4c079 100644 --- a/plugin-packages/autodl-comfyui/manifest.json +++ b/plugin-packages/autodl-comfyui/manifest.json @@ -2,10 +2,10 @@ "apiVersion": "yingce.plugin/v1", "id": "autodl-comfyui", "name": "AutoDL ComfyUI 视频", - "version": "1.0.0", + "version": "1.0.1", "author": "影策社区", "description": "通过 AutoDL.Art ComfyUI 工作流 API 接入异步视频生成。", - "documentation": "# AutoDL ComfyUI 视频\n\n## 接口\n\n创建任务:`POST /api/v1/comfyui/comfyui_workflow/{workflow_id}`。清单把渠道中的模型字段作为 `workflow_id`,因此每个 ComfyUI 工作流都可以通过工作流贡献加入,不需要修改宿主代码。\n\n查询任务:`GET /api/v1/comfyui/comfyui_workflow/result/{task_id}`。\n\n## 工作流\n\n示例 `minimax_h3_lightx2v_no_pic` 作为 MiniMax H3 文生视频入口,默认时长为 5 秒、分辨率为 `768p竖`。支持 `480p竖`、`768p竖`、`480p横`、`768p横`。上传后可以在渠道中直接选择该工作流;新增工作流只需扩展本清单。\n\n## 请求与鉴权\n\n创建请求为 JSON,发送 `prompt`、`duration`、`resolution`,并按存在的参考图片发送 `ref_image_0` 至 `ref_image_8`。分辨率字段由插件在发送前统一转换为小写。参考图片由宿主转换为短期签名公网 URL。AutoDL Token 在渠道密钥字段中配置,宿主以后端出站请求发送 `Authorization: Bearer `;清单不包含密钥。\n\n## 状态与结果\n\n`QUEUED` 和 `RUNNING` 映射为统一任务的排队与处理中,`SUCCESS` 和 `completed` 映射为成功,`FAILED` 映射为失败。错误响应的 `code` 和 `msg` 会保留为任务错误。成功结果从 `data.results[].url` 读取为视频地址。AutoDL 地址是短期地址,清单标记为临时结果,宿主会在完成时下载并保存到影策资源存储。\n\n官方文档:[AutoDL ComfyUI API](https://autodl.art/docs/comfyui_api/)。", + "documentation": "# AutoDL ComfyUI 视频\n\n## 接口\n\n创建任务:`POST /api/v1/comfyui/comfyui_workflow/{workflow_id}`。清单把渠道中的模型字段作为 `workflow_id`,因此每个 ComfyUI 工作流都可以通过工作流贡献加入,不需要修改宿主代码。\n\n查询任务:`GET /api/v1/comfyui/comfyui_workflow/result/{task_id}`。\n\n## 工作流\n\n示例 `minimax_h3_lightx2v_no_pic` 作为 MiniMax H3 文生视频入口,默认时长为 5 秒、分辨率为 `768p竖`。支持 `480p竖`、`768p竖`、`480p横`、`768p横`。上传后可以在渠道中直接选择该工作流;新增工作流只需扩展本清单。\n\n## 请求与鉴权\n\n创建请求为 JSON,发送 `prompt`、`duration`、`resolution`,并按存在的参考图片发送 `ref_image_0` 至 `ref_image_8`。分辨率字段由插件在发送前统一 trim 并转换为小写;纯数字值会自动补上 `p`,因此 `768` 与 `768p` 都会发送为 `768p`,`768p竖`、`768p横` 等工作流值保持不变。参考图片由宿主转换为短期签名公网 URL。AutoDL Token 在渠道密钥字段中配置,宿主以后端出站请求发送 `Authorization: Bearer `;清单不包含密钥。\n\n## 状态与结果\n\n`QUEUED` 和 `RUNNING` 映射为统一任务的排队与处理中,`SUCCESS` 和 `completed` 映射为成功,`FAILED` 映射为失败。错误响应的 `code` 和 `msg` 会保留为任务错误。成功结果从 `data.results[].url` 读取为视频地址。AutoDL 地址是短期地址,清单标记为临时结果,宿主会在完成时下载并保存到影策资源存储。\n\n官方文档:[AutoDL ComfyUI API](https://autodl.art/docs/comfyui_api/)。", "permissions": [ "generation.run", "media.read" @@ -70,7 +70,7 @@ "fields": { "prompt": "request.prompt", "duration": "request.duration", - "resolution": "request.resolution|lower", + "resolution": "request.resolution|video-resolution", "ref_image_0": "request.images.0.url", "ref_image_1": "request.images.1.url", "ref_image_2": "request.images.2.url", diff --git a/web/src/pages/plugins/plugin-development-guide.md b/web/src/pages/plugins/plugin-development-guide.md index dd68745f1..699d9c290 100644 --- a/web/src/pages/plugins/plugin-development-guide.md +++ b/web/src/pages/plugins/plugin-development-guide.md @@ -65,7 +65,7 @@ my-plugin.yingce-plugin ## 4. Provider 与工作流 -请求字段右侧只能引用影策统一请求,例如 `request.prompt`、`request.model`、`request.duration`、`request.extra`。声明式字段也支持安全的对象/数组路径(例如 `request.images.0.url`)和字符串变换(`|trim`、`|lower`、`|upper`),不执行插件代码。字段解析为空时会省略该字段,适合映射可选参考素材。Provider 如果把 `requiresPublicMediaUrls` 设为 `true`,宿主会在请求前把用户资源转换为短期签名公网 URL。响应映射支持对象路径和数组下标,并可用 `errorPaths` 声明上游错误码路径。同步 provider 只需要 `create` 和 `response`;异步 provider 再声明 `poll`。 +请求字段右侧只能引用影策统一请求,例如 `request.prompt`、`request.model`、`request.duration`、`request.extra`。声明式字段也支持安全的对象/数组路径(例如 `request.images.0.url`)和字符串变换(`|trim`、`|lower`、`|upper`、`|video-resolution`),不执行插件代码。`video-resolution` 会 trim 并转为小写,仅在输入是纯数字时补上 `p`,因此同时兼容历史状态中的 `768`、标准值 `768p` 和工作流值 `768p竖`。字段解析为空时会省略该字段,适合映射可选参考素材。Provider 如果把 `requiresPublicMediaUrls` 设为 `true`,宿主会在请求前把用户资源转换为短期签名公网 URL。响应映射支持对象路径和数组下标,并可用 `errorPaths` 声明上游错误码路径。同步 provider 只需要 `create` 和 `response`;异步 provider 再声明 `poll`。 结果 URL 如果是短期地址,必须设置 `resultEphemeral: true`。宿主会在任务完成后立即下载并保存资源,画布和任务记录只保存影策资源引用。