fix(plugin): 万相3.0视频 - 分辨率大写与上游错误解析(#614)
fix(plugin): 万相3.0视频 - 分辨率大写与上游错误解析
This commit is contained in:
commit
5bbd208bef
6 files changed
+71
-21
No files matched your search
@@ -48,27 +48,43 @@ func providerResponseBusinessFailure(responseBody []byte) (string, string, bool)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func providerPayloadBusinessFailure(payload map[string]any) (string, string, bool) {
|
func providerPayloadBusinessFailure(payload map[string]any) (string, string, bool) {
|
||||||
|
if code, message, failed := providerBusinessFailure(payload); failed {
|
||||||
|
return code, message, true
|
||||||
|
}
|
||||||
|
// DashScope 业务失败在 output 内
|
||||||
|
if output, ok := payload["output"].(map[string]any); ok {
|
||||||
|
return providerBusinessFailure(output)
|
||||||
|
}
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func providerBusinessFailure(payload map[string]any) (string, string, bool) {
|
||||||
if errorValue, ok := payload["error"].(map[string]any); ok {
|
if errorValue, ok := payload["error"].(map[string]any); ok {
|
||||||
code, message := providerFailureDetails(map[string]any{"error": errorValue})
|
code, message := providerFailureDetails(map[string]any{"error": errorValue})
|
||||||
if code != "" || message != "" {
|
if code != "" || message != "" {
|
||||||
return code, message, true
|
return code, message, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !providerBusinessCodeFailed(payload["code"]) {
|
|
||||||
return "", "", false
|
|
||||||
}
|
|
||||||
code, message := providerFailureDetails(payload)
|
|
||||||
return code, message, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func providerBusinessCodeFailed(value any) bool {
|
code := strings.ToLower(strings.TrimSpace(fmt.Sprint(payload["code"])))
|
||||||
code := strings.ToLower(strings.TrimSpace(fmt.Sprint(value)))
|
if code != "" && code != "0" &&
|
||||||
switch code {
|
code != "success" && code != "succeeded" &&
|
||||||
case "", "0", "success", "succeeded", "ok", "<nil>":
|
code != "ok" && code != "<nil>" {
|
||||||
return false
|
code, message := providerFailureDetails(payload)
|
||||||
default:
|
return code, message, true
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status := strings.ToLower(strings.TrimSpace(fmt.Sprint(payload["task_status"])))
|
||||||
|
switch status {
|
||||||
|
case "failed", "failure", "error", "expired":
|
||||||
|
code, message := providerFailureDetails(payload)
|
||||||
|
if code == "" {
|
||||||
|
code = "task_failed"
|
||||||
|
}
|
||||||
|
return code, message, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func normalizedProviderErrorCode(value any) string {
|
func normalizedProviderErrorCode(value any) string {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
func TestProviderFailureDetailsReadsTopLevelModerationError(t *testing.T) {
|
func TestProviderFailureDetailsReadsTopLevelModerationError(t *testing.T) {
|
||||||
code, message := providerFailureDetails(map[string]any{
|
code, message := providerFailureDetails(map[string]any{
|
||||||
@@ -59,3 +62,30 @@ func TestProviderPayloadBusinessFailureAcceptsStringSuccessCode(t *testing.T) {
|
|||||||
t.Fatalf("success payload was marked failed: (%q, %q)", code, message)
|
t.Fatalf("success payload was marked failed: (%q, %q)", code, message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProviderPayloadBusinessFailureReadsNestedOutputFailure(t *testing.T) {
|
||||||
|
code, message, failed := providerPayloadBusinessFailure(map[string]any{
|
||||||
|
"output": map[string]any{
|
||||||
|
"code": "InvalidParameter",
|
||||||
|
"message": "Input should be '1080P', '720P' or '480P': parameters.resolution",
|
||||||
|
"task_id": "e0d8c86d-4939-4f2e-93f7-e2cd10a07d58",
|
||||||
|
"task_status": "FAILED",
|
||||||
|
},
|
||||||
|
"request_id": "c3c98e67-830d-9f1d-8a62-fff019ffa522",
|
||||||
|
})
|
||||||
|
if !failed || code != "InvalidParameter" {
|
||||||
|
t.Fatalf("nested output failure = (%q, %q, %v)", code, message, failed)
|
||||||
|
}
|
||||||
|
if !strings.Contains(message, "parameters.resolution") {
|
||||||
|
t.Fatalf("unexpected message: %q", message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProviderPayloadBusinessFailureIgnoresPendingOutput(t *testing.T) {
|
||||||
|
if code, message, failed := providerPayloadBusinessFailure(map[string]any{
|
||||||
|
"output": map[string]any{"task_id": "task-1", "task_status": "PENDING"},
|
||||||
|
"request_id": "req-1",
|
||||||
|
}); failed {
|
||||||
|
t.Fatalf("pending output marked failed: (%q, %q)", code, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
func TestDashscopeWan3VideoCreateAndLifecycle(t *testing.T) {
|
func TestDashscopeWan3VideoCreateAndLifecycle(t *testing.T) {
|
||||||
adapter := officialPackageAdapter(t, "dashscope-wan3-video.yingce-plugin", "dashscope-wan3-video")
|
adapter := officialPackageAdapter(t, "dashscope-wan3-video.yingce-plugin", "dashscope-wan3-video")
|
||||||
create, err := adapter.BuildCreate(context.Background(), RequestContext{Request: GenerationRequest{
|
create, err := adapter.BuildCreate(context.Background(), RequestContext{Request: GenerationRequest{
|
||||||
Model: "wan3.0-video-prime", Prompt: "一只猫在海边奔跑", Duration: 6, AspectRatio: "16:9", Resolution: "1080P",
|
Model: "wan3.0-video-prime", Prompt: "一只猫在海边奔跑", Duration: 6, AspectRatio: "16:9", Resolution: "1080p",
|
||||||
GenerateAudio: true, Watermark: true,
|
GenerateAudio: true, Watermark: true,
|
||||||
Inputs: []MediaReference{
|
Inputs: []MediaReference{
|
||||||
{URL: "https://cdn.example/audio.mp3", Kind: "audio", Role: "reference_audio", Order: 3},
|
{URL: "https://cdn.example/audio.mp3", Kind: "audio", Role: "reference_audio", Order: 3},
|
||||||
|
|||||||
Binary file not shown.
@@ -44,7 +44,7 @@
|
|||||||
| `create.body.model` | `{"$ref":"request.model"}` |
|
| `create.body.model` | `{"$ref":"request.model"}` |
|
||||||
| `create.body.input.prompt` | `{"$omitEmpty":{"$ref":"request.prompt"}}` |
|
| `create.body.input.prompt` | `{"$omitEmpty":{"$ref":"request.prompt"}}` |
|
||||||
| `create.body.input.media` | `{"$omitEmpty":{"$coalesce":[{"$ref":"request.providerOptions.dashscope-wan3-video.media"},{"$map":{"from":{"$sortByOrder":{"$ref":"request.inputs"}},"as":"media","in":{"type":{"$coalesce":[{"$ref":"media.role"},{"$if":{"condition":{"$eq":[{"$ref":"media.kind"},"image"]},"then":"reference_image","else":{"$if":{"condition":{"$eq":[{"$ref":"media.kind"},"video"]},"then":"reference_video","else":{"$if":{"condition":{"$eq":[{"$ref":"media.kind"},"audio"]},"then":"reference_audio","else":{"$ref":"media.kind"}}}}}}}]},"url":{"$ref":"media.value"}}}}]}}` |
|
| `create.body.input.media` | `{"$omitEmpty":{"$coalesce":[{"$ref":"request.providerOptions.dashscope-wan3-video.media"},{"$map":{"from":{"$sortByOrder":{"$ref":"request.inputs"}},"as":"media","in":{"type":{"$coalesce":[{"$ref":"media.role"},{"$if":{"condition":{"$eq":[{"$ref":"media.kind"},"image"]},"then":"reference_image","else":{"$if":{"condition":{"$eq":[{"$ref":"media.kind"},"video"]},"then":"reference_video","else":{"$if":{"condition":{"$eq":[{"$ref":"media.kind"},"audio"]},"then":"reference_audio","else":{"$ref":"media.kind"}}}}}}}]},"url":{"$ref":"media.value"}}}}]}}` |
|
||||||
| `create.body.parameters.resolution` | `{"$omitEmpty":{"$ref":"request.resolution"}}` |
|
| `create.body.parameters.resolution` | `{"$omitEmpty":{"$upper":{"$ref":"request.resolution"}}}` |
|
||||||
| `create.body.parameters.ratio` | `{"$omitEmpty":{"$ref":"request.aspectRatio"}}` |
|
| `create.body.parameters.ratio` | `{"$omitEmpty":{"$ref":"request.aspectRatio"}}` |
|
||||||
| `create.body.parameters.duration` | `{"$omitEmpty":{"$ref":"request.duration"}}` |
|
| `create.body.parameters.duration` | `{"$omitEmpty":{"$ref":"request.duration"}}` |
|
||||||
| `create.body.parameters.audio` | `{"$coalesce":[{"$ref":"request.providerOptions.dashscope-wan3-video.audio"},{"$ref":"request.generateAudio"}]}` |
|
| `create.body.parameters.audio` | `{"$coalesce":[{"$ref":"request.providerOptions.dashscope-wan3-video.audio"},{"$ref":"request.generateAudio"}]}` |
|
||||||
@@ -98,7 +98,7 @@
|
|||||||
"apiVersion": "yingce.plugin/v2",
|
"apiVersion": "yingce.plugin/v2",
|
||||||
"id": "dashscope-wan3-video",
|
"id": "dashscope-wan3-video",
|
||||||
"name": "DashScope Wan 3.0 Video",
|
"name": "DashScope Wan 3.0 Video",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"author": "Alibaba Cloud / 影策",
|
"author": "Alibaba Cloud / 影策",
|
||||||
"description": "DashScope Wan 3.0 Video 独立请求协议插件。",
|
"description": "DashScope Wan 3.0 Video 独立请求协议插件。",
|
||||||
"documentation": "<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>",
|
"documentation": "<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>",
|
||||||
@@ -385,7 +385,9 @@
|
|||||||
"parameters": {
|
"parameters": {
|
||||||
"resolution": {
|
"resolution": {
|
||||||
"$omitEmpty": {
|
"$omitEmpty": {
|
||||||
"$ref": "request.resolution"
|
"$upper": {
|
||||||
|
"$ref": "request.resolution"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ratio": {
|
"ratio": {
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
"apiVersion": "yingce.plugin/v2",
|
"apiVersion": "yingce.plugin/v2",
|
||||||
"id": "dashscope-wan3-video",
|
"id": "dashscope-wan3-video",
|
||||||
"name": "DashScope Wan 3.0 Video",
|
"name": "DashScope Wan 3.0 Video",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"author": "Alibaba Cloud / 影策",
|
"author": "Alibaba Cloud / 影策",
|
||||||
"description": "DashScope Wan 3.0 Video 独立请求协议插件。",
|
"description": "DashScope Wan 3.0 Video 独立请求协议插件。",
|
||||||
"documentation": "# DashScope Wan 3.0 Video\n\n该目录是独立官方协议插件源码。后端从生成的 `dashscope-wan3-video.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# DashScope Wan 3.0 Video 接口字段\n\n## 协议身份\n\n- 插件 ID:`dashscope-wan3-video`。\n- Provider ID:`dashscope-wan3-video`。\n- 能力:`video`。\n- 默认 Base URL:`https://dashscope.aliyuncs.com`。\n- 鉴权驱动:`bearer`。\n- 创建:`POST /api/v1/services/aigc/video-generation/video-synthesis`。\n- 查询:`GET /api/v1/tasks/{{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` | `\"/api/v1/services/aigc/video-generation/video-synthesis\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.input.prompt` | `{\"$omitEmpty\":{\"$ref\":\"request.prompt\"}}` |\n| `create.body.input.media` | `{\"$omitEmpty\":{\"$coalesce\":[{\"$ref\":\"request.providerOptions.dashscope-wan3-video.media\"},{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.inputs\"}},\"as\":\"media\",\"in\":{\"type\":{\"$coalesce\":[{\"$ref\":\"media.role\"},{\"$if\":{\"condition\":{\"$eq\":[{\"$ref\":\"media.kind\"},\"image\"]},\"then\":\"reference_image\",\"else\":{\"$if\":{\"condition\":{\"$eq\":[{\"$ref\":\"media.kind\"},\"video\"]},\"then\":\"reference_video\",\"else\":{\"$if\":{\"condition\":{\"$eq\":[{\"$ref\":\"media.kind\"},\"audio\"]},\"then\":\"reference_audio\",\"else\":{\"$ref\":\"media.kind\"}}}}}}}]},\"url\":{\"$ref\":\"media.value\"}}}}]}}` |\n| `create.body.parameters.resolution` | `{\"$omitEmpty\":{\"$ref\":\"request.resolution\"}}` |\n| `create.body.parameters.ratio` | `{\"$omitEmpty\":{\"$ref\":\"request.aspectRatio\"}}` |\n| `create.body.parameters.duration` | `{\"$omitEmpty\":{\"$ref\":\"request.duration\"}}` |\n| `create.body.parameters.audio` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.dashscope-wan3-video.audio\"},{\"$ref\":\"request.generateAudio\"}]}` |\n| `create.body.parameters.seed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.dashscope-wan3-video.seed\"}}` |\n| `create.body.parameters.prompt_extend` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.dashscope-wan3-video.prompt_extend\"},true]}` |\n| `create.body.parameters.watermark` | `{\"$ref\":\"request.watermark\"}` |\n| `create.headers.X-DashScope-Async` | `\"enable\"` |\n| `poll.method` | `\"GET\"` |\n| `poll.path` | `\"/api/v1/tasks/{{taskId}}\"` |\n| `poll.contentType` | `\"application/json\"` |\n\n## Provider 扩展键\n\n- `providerOptions.dashscope-wan3-video.audio`\n- `providerOptions.dashscope-wan3-video.media`\n- `providerOptions.dashscope-wan3-video.prompt_extend`\n- `providerOptions.dashscope-wan3-video.seed`\n\n动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。\n\n## 响应映射逐字段清单\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.taskId` | `{\"$coalesce\":[{\"$ref\":\"response.output.task_id\"},{\"$ref\":\"response.task_id\"},{\"$ref\":\"taskId\"}]}` |\n| `response.status` | `{\"$if\":{\"condition\":{\"$eq\":[{\"$lower\":{\"$ref\":\"response.output.task_status\"}},\"unknown\"]},\"then\":\"failed\",\"else\":{\"$coalesce\":[{\"$ref\":\"response.output.task_status\"},{\"$ref\":\"response.status\"},\"pending\"]}}}` |\n| `response.message` | `{\"$coalesce\":[{\"$ref\":\"response.error.message\"},{\"$ref\":\"response.message\"},{\"$ref\":\"response.fail_reason\"}]}` |\n| `resLine truncated
|
"documentation": "# DashScope Wan 3.0 Video\n\n该目录是独立官方协议插件源码。后端从生成的 `dashscope-wan3-video.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# DashScope Wan 3.0 Video 接口字段\n\n## 协议身份\n\n- 插件 ID:`dashscope-wan3-video`。\n- Provider ID:`dashscope-wan3-video`。\n- 能力:`video`。\n- 默认 Base URL:`https://dashscope.aliyuncs.com`。\n- 鉴权驱动:`bearer`。\n- 创建:`POST /api/v1/services/aigc/video-generation/video-synthesis`。\n- 查询:`GET /api/v1/tasks/{{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` | `\"/api/v1/services/aigc/video-generation/video-synthesis\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.input.prompt` | `{\"$omitEmpty\":{\"$ref\":\"request.prompt\"}}` |\n| `create.body.input.media` | `{\"$omitEmpty\":{\"$coalesce\":[{\"$ref\":\"request.providerOptions.dashscope-wan3-video.media\"},{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.inputs\"}},\"as\":\"media\",\"in\":{\"type\":{\"$coalesce\":[{\"$ref\":\"media.role\"},{\"$if\":{\"condition\":{\"$eq\":[{\"$ref\":\"media.kind\"},\"image\"]},\"then\":\"reference_image\",\"else\":{\"$if\":{\"condition\":{\"$eq\":[{\"$ref\":\"media.kind\"},\"video\"]},\"then\":\"reference_video\",\"else\":{\"$if\":{\"condition\":{\"$eq\":[{\"$ref\":\"media.kind\"},\"audio\"]},\"then\":\"reference_audio\",\"else\":{\"$ref\":\"media.kind\"}}}}}}}]},\"url\":{\"$ref\":\"media.value\"}}}}]}}` |\n| `create.body.parameters.resolution` | `{\"$omitEmpty\":{\"$upper\":{\"$ref\":\"request.resolution\"}}}` |\n| `create.body.parameters.ratio` | `{\"$omitEmpty\":{\"$ref\":\"request.aspectRatio\"}}` |\n| `create.body.parameters.duration` | `{\"$omitEmpty\":{\"$ref\":\"request.duration\"}}` |\n| `create.body.parameters.audio` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.dashscope-wan3-video.audio\"},{\"$ref\":\"request.generateAudio\"}]}` |\n| `create.body.parameters.seed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.dashscope-wan3-video.seed\"}}` |\n| `create.body.parameters.prompt_extend` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.dashscope-wan3-video.prompt_extend\"},true]}` |\n| `create.body.parameters.watermark` | `{\"$ref\":\"request.watermark\"}` |\n| `create.headers.X-DashScope-Async` | `\"enable\"` |\n| `poll.method` | `\"GET\"` |\n| `poll.path` | `\"/api/v1/tasks/{{taskId}}\"` |\n| `poll.contentType` | `\"application/json\"` |\n\n## Provider 扩展键\n\n- `providerOptions.dashscope-wan3-video.audio`\n- `providerOptions.dashscope-wan3-video.media`\n- `providerOptions.dashscope-wan3-video.prompt_extend`\n- `providerOptions.dashscope-wan3-video.seed`\n\n动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。\n\n## 响应映射逐字段清单\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.taskId` | `{\"$coalesce\":[{\"$ref\":\"response.output.task_id\"},{\"$ref\":\"response.task_id\"},{\"$ref\":\"taskId\"}]}` |\n| `response.status` | `{\"$if\":{\"condition\":{\"$eq\":[{\"$lower\":{\"$ref\":\"response.output.task_status\"}},\"unknown\"]},\"then\":\"failed\",\"else\":{\"$coalesce\":[{\"$ref\":\"response.output.task_status\"},{\"$ref\":\"response.status\"},\"pending\"]}}}` |\n| `response.message` | `{\"$coalesce\":[{\"$ref\":\"response.error.message\"},{\"$ref\":\"response.message\"},{\"$ref\":\"response.fail_reason\"}Line truncated
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"generation.run",
|
"generation.run",
|
||||||
"media.read"
|
"media.read"
|
||||||
@@ -289,7 +289,9 @@
|
|||||||
"parameters": {
|
"parameters": {
|
||||||
"resolution": {
|
"resolution": {
|
||||||
"$omitEmpty": {
|
"$omitEmpty": {
|
||||||
"$ref": "request.resolution"
|
"$upper": {
|
||||||
|
"$ref": "request.resolution"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ratio": {
|
"ratio": {
|
||||||
|
|||||||
Reference in new issue
Block a user