From 1e228a04dc0c17859ab10e1882c702643af76455 Mon Sep 17 00:00:00 2001 From: VicoHu Date: Thu, 17 Sep 2026 17:52:52 +0800 Subject: [PATCH] =?UTF-8?q?feat(plugins):=20=E6=96=B9=E8=88=9F=20Agent=20P?= =?UTF-8?q?lan=20-=20=E6=96=B0=E5=A2=9E=E5=9B=BE=E7=89=87=E4=B8=8E?= =?UTF-8?q?=E8=A7=86=E9=A2=91=E5=8D=8F=E8=AE=AE=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 独立 /api/plan/v3 Seedream、Seedance 插件,并同步宿主能力默认值与渠道识别,避免与官方 /api/v3 凭证混用。 Co-authored-by: Cursor --- backend/internal/app/channel_models.go | 2 +- backend/internal/app/model_capability.go | 6 +- backend/internal/app/price_validation.go | 2 +- backend/internal/app/provider.go | 6 +- backend/internal/app/provider_image.go | 2 +- .../app/provider_task_cancellation.go | 14 +- backend/internal/app/provider_video.go | 4 +- backend/internal/generation/registry.go | 4 +- backend/internal/handler/security.go | 4 +- backend/internal/model/models.go | 22 +- backend/internal/model/volcengine_ark.go | 11 + backend/internal/model/volcengine_ark_test.go | 24 + .../docs/volcengine-ark-agent-plan-image.md | 37 ++ .../docs/volcengine-ark-agent-plan-video.md | 43 ++ .../protocol/official_catalog_test.go | 30 + docs/content/docs/progress/pending-test.mdx | 7 + .../model-request-protocol-landscape.md | 2 + plugin-packages/generate-catalog.mjs | 126 ++++- ...gine-ark-agent-plan-seedance.yingce-plugin | Bin 0 -> 9515 bytes .../README.md | 5 + .../docs/interface.md | 527 ++++++++++++++++++ .../manifest.json | 431 ++++++++++++++ ...gine-ark-agent-plan-seedream.yingce-plugin | Bin 0 -> 8614 bytes .../README.md | 5 + .../docs/interface.md | 418 ++++++++++++++ .../manifest.json | 332 +++++++++++ .../volcengine-ark-seedance.yingce-plugin | Bin 8546 -> 9473 bytes .../volcengine-ark-seedance/README.md | 5 + .../volcengine-ark-seedance/docs/interface.md | 527 ++++++++++++++++++ .../volcengine-ark-seedance/manifest.json | 431 ++++++++++++++ .../volcengine-ark-seedream.yingce-plugin | Bin 8513 -> 8457 bytes .../volcengine-ark-seedream/docs/interface.md | 2 +- .../volcengine-ark-seedream/manifest.json | 2 +- web/src/components/video-settings-panel.tsx | 3 +- web/src/lib/model-capabilities.ts | 8 +- web/src/lib/model-protocols.ts | 10 +- .../lib/plugins/builtin/prompt-optimizer.ts | 4 +- web/src/services/api/image.ts | 5 +- .../services/api/video-provider-seedance.ts | 11 +- web/src/stores/use-config-store.ts | 1 + web/test/model-protocols.test.ts | 2 + 41 files changed, 3012 insertions(+), 63 deletions(-) create mode 100644 backend/internal/model/volcengine_ark.go create mode 100644 backend/internal/model/volcengine_ark_test.go create mode 100644 backend/internal/protocol/docs/volcengine-ark-agent-plan-image.md create mode 100644 backend/internal/protocol/docs/volcengine-ark-agent-plan-video.md create mode 100644 plugin-packages/volcengine-ark-agent-plan-seedance.yingce-plugin create mode 100644 plugin-packages/volcengine-ark-agent-plan-seedance/README.md create mode 100644 plugin-packages/volcengine-ark-agent-plan-seedance/docs/interface.md create mode 100644 plugin-packages/volcengine-ark-agent-plan-seedance/manifest.json create mode 100644 plugin-packages/volcengine-ark-agent-plan-seedream.yingce-plugin create mode 100644 plugin-packages/volcengine-ark-agent-plan-seedream/README.md create mode 100644 plugin-packages/volcengine-ark-agent-plan-seedream/docs/interface.md create mode 100644 plugin-packages/volcengine-ark-agent-plan-seedream/manifest.json create mode 100644 plugin-packages/volcengine-ark-seedance/README.md create mode 100644 plugin-packages/volcengine-ark-seedance/docs/interface.md create mode 100644 plugin-packages/volcengine-ark-seedance/manifest.json diff --git a/backend/internal/app/channel_models.go b/backend/internal/app/channel_models.go index fcefe4fff..d105dade0 100644 --- a/backend/internal/app/channel_models.go +++ b/backend/internal/app/channel_models.go @@ -438,7 +438,7 @@ func (s *Service) syncLogicalModelsFromChannelModel(actor *model.User, channelMo } func supportsTokenBilling(capability string, protocol model.ChannelInterfaceType) bool { - return capability == "text" || (capability == "video" && protocol == model.ChannelInterfaceVolcengineArkVideo) + return capability == "text" || (capability == "video" && model.IsVolcengineArkVideoProtocol(protocol)) } func (s *Service) normalizeChannelModelPriceTiers(req ChannelModelRequest, capability string, protocol model.ChannelInterfaceType, fallbackProviderModelKey string) ([]model.ChannelModelPriceTier, error) { diff --git a/backend/internal/app/model_capability.go b/backend/internal/app/model_capability.go index a9b0612ab..240ab5699 100644 --- a/backend/internal/app/model_capability.go +++ b/backend/internal/app/model_capability.go @@ -153,7 +153,7 @@ func DefaultImageCapabilityConfig(protocol string, modelName string) *ImageCapab image.ResponseFormat = ParameterSupport{Supported: true} image.OutputFormat = ParameterSupport{Supported: false} image.MaxOutputs = 1 - case model.ChannelInterfaceVolcengineArkImage: + case model.ChannelInterfaceVolcengineArkImage, model.ChannelInterfaceVolcengineArkAgentPlanImage: image.References.MaskSupported = false image.Quality.Supported = false image.TransparentBackground.Supported = false @@ -229,7 +229,7 @@ func DefaultModelCapabilityConfigForModel(protocol string, modelName string) *Mo case model.ChannelInterfaceGeminiVeo: video.Duration = VideoDurationConfig{Selection: "enum", Values: []int{4, 6, 8}, Default: 6} video.Resolutions = []string{"720p", "1080p"} - case model.ChannelInterfaceVolcengineArkVideo: + case model.ChannelInterfaceVolcengineArkVideo, model.ChannelInterfaceVolcengineArkAgentPlanVideo: video.Operations = append(video.Operations, "reference_to_video", "audio_to_video") video.References.MaxVideos, video.References.MaxAudios = 3, 3 video.References.MaxVideoBytes, video.References.MaxAudioBytes = 200*1024*1024, 15*1024*1024 @@ -798,7 +798,7 @@ func validateVideoTask(profile *VideoCapabilityConfig, input canvasGenerationInp if len(input.ReferenceImages) > profile.References.MaxImages || len(input.ReferenceVideos) > profile.References.MaxVideos || len(input.ReferenceAudios) > profile.References.MaxAudios { return BadAuthRequest("参考素材数量超过当前模型限制") } - if input.Config.InterfaceType == string(model.ChannelInterfaceVolcengineArkVideo) && len(input.ReferenceAudios) > 0 && len(input.ReferenceImages) == 0 && len(input.ReferenceVideos) == 0 { + if model.IsVolcengineArkVideoProtocol(model.ChannelInterfaceType(input.Config.InterfaceType)) && len(input.ReferenceAudios) > 0 && len(input.ReferenceImages) == 0 && len(input.ReferenceVideos) == 0 { return BadAuthRequest("火山方舟全模态参考不支持纯音频或文本+音频,请同时添加参考图片或参考视频") } if len(input.ReferenceImages) < profile.References.MinImages { diff --git a/backend/internal/app/price_validation.go b/backend/internal/app/price_validation.go index 76e60d890..060311779 100644 --- a/backend/internal/app/price_validation.go +++ b/backend/internal/app/price_validation.go @@ -14,7 +14,7 @@ func ValidateChannelModelPrice(billingMode string, capability string, protocol m return unitPrice >= 0 case "token": if capability == "video" { - return protocol == model.ChannelInterfaceVolcengineArkVideo && inputPrice >= 0 && outputPrice >= 0 && cachedPrice >= 0 + return model.IsVolcengineArkVideoProtocol(protocol) && inputPrice >= 0 && outputPrice >= 0 && cachedPrice >= 0 } if capability != "" && capability != "text" { return false diff --git a/backend/internal/app/provider.go b/backend/internal/app/provider.go index 6b7b1ff94..3030ef1bf 100644 --- a/backend/internal/app/provider.go +++ b/backend/internal/app/provider.go @@ -464,7 +464,7 @@ type providerMediaHydrationPolicy struct { func providerMediaHydrationPolicyFor(ctx context.Context, input canvasGenerationInput) providerMediaHydrationPolicy { policy := providerMediaHydrationPolicy{preferURL: providerPrefersMediaURLs(input.Config.InterfaceType, input)} switch strings.TrimSpace(input.Config.InterfaceType) { - case string(model.ChannelInterfaceNewAPIVideo), string(model.ChannelInterfaceNewAPIChannel1), string(model.ChannelInterfaceNewAPIChannel2), string(model.ChannelInterfaceVolcengineArkVideo), string(model.ChannelInterfaceMiniMaxVideo): + case string(model.ChannelInterfaceNewAPIVideo), string(model.ChannelInterfaceNewAPIChannel1), string(model.ChannelInterfaceNewAPIChannel2), string(model.ChannelInterfaceVolcengineArkVideo), string(model.ChannelInterfaceVolcengineArkAgentPlanVideo), string(model.ChannelInterfaceMiniMaxVideo): policy.requireURL = true policy.preferURL = true } @@ -488,11 +488,11 @@ func providerPrefersMediaURLs(interfaceType string, input canvasGenerationInput) } switch strings.TrimSpace(interfaceType) { case string(model.ChannelInterfaceChatCompletion), string(model.ChannelInterfaceOpenAIResponse), string(model.ChannelInterfaceClaudeAPI), - string(model.ChannelInterfaceGrokImage), string(model.ChannelInterfaceVolcengineArkImage), + string(model.ChannelInterfaceGrokImage), string(model.ChannelInterfaceVolcengineArkImage), string(model.ChannelInterfaceVolcengineArkAgentPlanImage), string(model.ChannelInterfaceXAIVideo), string(model.ChannelInterfaceNovitaVideo), string(model.ChannelInterfaceMiniMaxVideo), string(model.ChannelInterfaceNewAPIVideo), string(model.ChannelInterfaceNewAPIChannel1), string(model.ChannelInterfaceNewAPIChannel2), - string(model.ChannelInterfaceVolcengineArkVideo): + string(model.ChannelInterfaceVolcengineArkVideo), string(model.ChannelInterfaceVolcengineArkAgentPlanVideo): return true } if isGrokVideoConfig(input.Config) || isSeedanceVideoConfig(input.Config) || isArkPlanVideoConfig(input.Config) { diff --git a/backend/internal/app/provider_image.go b/backend/internal/app/provider_image.go index e1b3886af..38d1b27d1 100644 --- a/backend/internal/app/provider_image.go +++ b/backend/internal/app/provider_image.go @@ -28,7 +28,7 @@ func runImageTask(ctx context.Context, input canvasGenerationInput) (map[string] if input.Config.InterfaceType == string(model.ChannelInterfaceVolcengineJiMengImage) { return runVolcengineJiMengImageTask(ctx, input) } - if input.Config.InterfaceType == string(model.ChannelInterfaceVolcengineArkImage) { + if model.IsVolcengineArkImageProtocol(model.ChannelInterfaceType(input.Config.InterfaceType)) { return runVolcengineArkImageTask(ctx, input) } if input.Config.InterfaceType == string(model.ChannelInterfaceGeminiImage) { diff --git a/backend/internal/app/provider_task_cancellation.go b/backend/internal/app/provider_task_cancellation.go index 59b357aa4..1e9ac04d2 100644 --- a/backend/internal/app/provider_task_cancellation.go +++ b/backend/internal/app/provider_task_cancellation.go @@ -194,15 +194,15 @@ func (s *Service) providerCancellationInput(task *model.Task) (canvasGenerationI } func supportsProviderCancellation(interfaceType string) bool { - return interfaceType == string(model.ChannelInterfaceGeminiVeo) || interfaceType == string(model.ChannelInterfaceVolcengineArkVideo) + return interfaceType == string(model.ChannelInterfaceGeminiVeo) || model.IsVolcengineArkVideoProtocol(model.ChannelInterfaceType(interfaceType)) } func cancelProviderTask(ctx context.Context, config providerConfig, providerRequestID string) error { - switch config.InterfaceType { - case string(model.ChannelInterfaceGeminiVeo): + switch { + case config.InterfaceType == string(model.ChannelInterfaceGeminiVeo): path := "/" + strings.TrimLeft(providerRequestID, "/") + ":cancel" return postGeminiJSON(ctx, config, path, map[string]any{}, &map[string]any{}) - case string(model.ChannelInterfaceVolcengineArkVideo): + case model.IsVolcengineArkVideoProtocol(model.ChannelInterfaceType(config.InterfaceType)): path := "/contents/generations/tasks/" + url.PathEscape(providerRequestID) return deleteProviderTask(ctx, config, path) default: @@ -228,8 +228,8 @@ func deleteProviderTask(ctx context.Context, config providerConfig, path string) } func queryProviderCancellation(ctx context.Context, config providerConfig, providerRequestID string) (providerCancellationOutcome, string, error) { - switch config.InterfaceType { - case string(model.ChannelInterfaceGeminiVeo): + switch { + case config.InterfaceType == string(model.ChannelInterfaceGeminiVeo): // Gemini 用 operation.error 表示取消终态,此处必须保留该字段再判断, // 不能让通用 JSON 解包提前把它转换成请求失败。 var operation geminiOperation @@ -248,7 +248,7 @@ func queryProviderCancellation(ctx context.Context, config providerConfig, provi return providerCancellationFailed, firstNonEmpty(message, "failed"), nil } return providerCancellationSucceeded, "succeeded", nil - case string(model.ChannelInterfaceVolcengineArkVideo): + case model.IsVolcengineArkVideoProtocol(model.ChannelInterfaceType(config.InterfaceType)): var state map[string]any if err := getJSON(ctx, config, "/contents/generations/tasks/"+url.PathEscape(providerRequestID), &state); err != nil { return "", "", err diff --git a/backend/internal/app/provider_video.go b/backend/internal/app/provider_video.go index 51884a221..f09410cad 100644 --- a/backend/internal/app/provider_video.go +++ b/backend/internal/app/provider_video.go @@ -287,7 +287,7 @@ func runSeedanceVideosTask(ctx context.Context, input canvasGenerationInput, pol func runSeedanceAgentPlanVideoTask(ctx context.Context, input canvasGenerationInput, pollPolicy videoPollPolicy) (map[string]interface{}, error) { providerName := "Seedance" - if input.Config.InterfaceType == string(model.ChannelInterfaceVolcengineArkVideo) { + if model.IsVolcengineArkVideoProtocol(model.ChannelInterfaceType(input.Config.InterfaceType)) { providerName = "火山方舟" } // Agent Plan 与 Videos API 使用相同的恢复合同:已有任务只查询,不重复创建。 @@ -299,7 +299,7 @@ func runSeedanceAgentPlanVideoTask(ctx context.Context, input canvasGenerationIn if err != nil { return nil, err } - if input.Config.InterfaceType == string(model.ChannelInterfaceVolcengineArkVideo) { + if model.IsVolcengineArkVideoProtocol(model.ChannelInterfaceType(input.Config.InterfaceType)) { for _, item := range content { if item["type"] == "image_url" { item["role"] = "reference_image" diff --git a/backend/internal/generation/registry.go b/backend/internal/generation/registry.go index 4d4673640..451639aef 100644 --- a/backend/internal/generation/registry.go +++ b/backend/internal/generation/registry.go @@ -70,7 +70,7 @@ func OfficialDeclarativeVideoInterface(interfaceType string) (string, bool) { return "NewAPI 媒体任务", true case string(model.ChannelInterfaceXAIVideo): return "xAI", true - case string(model.ChannelInterfaceVolcengineArkVideo): + case string(model.ChannelInterfaceVolcengineArkVideo), string(model.ChannelInterfaceVolcengineArkAgentPlanVideo): return "火山方舟", true case string(model.ChannelInterfaceVolcengineJiMengVideo): return "即梦", true @@ -91,6 +91,8 @@ func OfficialDeclarativeImageInterface(interfaceType string) (string, bool) { return "Grok Images", true case string(model.ChannelInterfaceVolcengineArkImage): return "火山方舟图片", true + case string(model.ChannelInterfaceVolcengineArkAgentPlanImage): + return "火山方舟 Agent Plan 图片", true case string(model.ChannelInterfaceVolcengineJiMengImage): return "即梦图片", true default: diff --git a/backend/internal/handler/security.go b/backend/internal/handler/security.go index 487c305e9..b1417f77e 100644 --- a/backend/internal/handler/security.go +++ b/backend/internal/handler/security.go @@ -244,11 +244,11 @@ func interfaceAllowsProxyPath(interfaceType model.ChannelInterfaceType, requestP return requestPath == "/messages" case model.ChannelInterfaceOpenAIImage, model.ChannelInterfaceGrokImage: return requestPath == "/images/generations" || requestPath == "/images/edits" - case model.ChannelInterfaceVolcengineArkImage: + case model.ChannelInterfaceVolcengineArkImage, model.ChannelInterfaceVolcengineArkAgentPlanImage: return requestPath == "/images/generations" case model.ChannelInterfaceOpenAIAudio: return requestPath == "/audio/speech" - case model.ChannelInterfaceAsyncAudio, model.ChannelInterfaceNewAPIVideo, model.ChannelInterfaceNewAPIChannel1, model.ChannelInterfaceNewAPIChannel2, model.ChannelInterfaceXAIVideo, model.ChannelInterfaceVolcengineArkVideo, model.ChannelInterfaceVolcengineJiMengImage, model.ChannelInterfaceVolcengineJiMengVideo, model.ChannelInterfaceGeminiVeo, model.ChannelInterfaceGeminiImage, model.ChannelInterfaceNovitaVideo, model.ChannelInterfaceMiniMaxVideo: + case model.ChannelInterfaceAsyncAudio, model.ChannelInterfaceNewAPIVideo, model.ChannelInterfaceNewAPIChannel1, model.ChannelInterfaceNewAPIChannel2, model.ChannelInterfaceXAIVideo, model.ChannelInterfaceVolcengineArkVideo, model.ChannelInterfaceVolcengineArkAgentPlanVideo, model.ChannelInterfaceVolcengineJiMengImage, model.ChannelInterfaceVolcengineJiMengVideo, model.ChannelInterfaceGeminiVeo, model.ChannelInterfaceGeminiImage, model.ChannelInterfaceNovitaVideo, model.ChannelInterfaceMiniMaxVideo: return false default: return true diff --git a/backend/internal/model/models.go b/backend/internal/model/models.go index d9e8d36d3..f9bb461bc 100644 --- a/backend/internal/model/models.go +++ b/backend/internal/model/models.go @@ -63,16 +63,18 @@ const ( ChannelInterfaceClaudeAPI ChannelInterfaceType = "claude-api" ChannelInterfaceOpenAIImage ChannelInterfaceType = "openai-image" ChannelInterfaceGrokImage ChannelInterfaceType = "grok-image" - ChannelInterfaceVolcengineArkImage ChannelInterfaceType = "volcengine-ark-image" - ChannelInterfaceVolcengineJiMengImage ChannelInterfaceType = "volcengine-jimeng-image" - ChannelInterfaceGeminiImage ChannelInterfaceType = "gemini-image" - ChannelInterfaceOpenAIAudio ChannelInterfaceType = "openai-audio" - ChannelInterfaceAsyncAudio ChannelInterfaceType = "async-audio" - ChannelInterfaceNewAPIVideo ChannelInterfaceType = "newapi" - ChannelInterfaceNewAPIChannel1 ChannelInterfaceType = "newapi-channel-1" - ChannelInterfaceNewAPIChannel2 ChannelInterfaceType = "newapi-channel-2" - ChannelInterfaceXAIVideo ChannelInterfaceType = "xai-video" - ChannelInterfaceVolcengineArkVideo ChannelInterfaceType = "volcengine-ark-video" + ChannelInterfaceVolcengineArkImage ChannelInterfaceType = "volcengine-ark-image" + ChannelInterfaceVolcengineArkAgentPlanImage ChannelInterfaceType = "volcengine-ark-agent-plan-image" + ChannelInterfaceVolcengineJiMengImage ChannelInterfaceType = "volcengine-jimeng-image" + ChannelInterfaceGeminiImage ChannelInterfaceType = "gemini-image" + ChannelInterfaceOpenAIAudio ChannelInterfaceType = "openai-audio" + ChannelInterfaceAsyncAudio ChannelInterfaceType = "async-audio" + ChannelInterfaceNewAPIVideo ChannelInterfaceType = "newapi" + ChannelInterfaceNewAPIChannel1 ChannelInterfaceType = "newapi-channel-1" + ChannelInterfaceNewAPIChannel2 ChannelInterfaceType = "newapi-channel-2" + ChannelInterfaceXAIVideo ChannelInterfaceType = "xai-video" + ChannelInterfaceVolcengineArkVideo ChannelInterfaceType = "volcengine-ark-video" + ChannelInterfaceVolcengineArkAgentPlanVideo ChannelInterfaceType = "volcengine-ark-agent-plan-video" ChannelInterfaceVolcengineJiMengVideo ChannelInterfaceType = "volcengine-jimeng-video" ChannelInterfaceGeminiVeo ChannelInterfaceType = "gemini-veo" ChannelInterfaceNovitaVideo ChannelInterfaceType = "novita-video" diff --git a/backend/internal/model/volcengine_ark.go b/backend/internal/model/volcengine_ark.go new file mode 100644 index 000000000..c333e38c0 --- /dev/null +++ b/backend/internal/model/volcengine_ark.go @@ -0,0 +1,11 @@ +package model + +// IsVolcengineArkImageProtocol 识别官方 Ark 图片与 Agent Plan 图片协议。 +func IsVolcengineArkImageProtocol(protocol ChannelInterfaceType) bool { + return protocol == ChannelInterfaceVolcengineArkImage || protocol == ChannelInterfaceVolcengineArkAgentPlanImage +} + +// IsVolcengineArkVideoProtocol 识别官方 Ark 视频与 Agent Plan 视频协议。 +func IsVolcengineArkVideoProtocol(protocol ChannelInterfaceType) bool { + return protocol == ChannelInterfaceVolcengineArkVideo || protocol == ChannelInterfaceVolcengineArkAgentPlanVideo +} diff --git a/backend/internal/model/volcengine_ark_test.go b/backend/internal/model/volcengine_ark_test.go new file mode 100644 index 000000000..2ee5254f9 --- /dev/null +++ b/backend/internal/model/volcengine_ark_test.go @@ -0,0 +1,24 @@ +package model + +import "testing" + +func TestIsVolcengineArkProtocols(t *testing.T) { + if !IsVolcengineArkImageProtocol(ChannelInterfaceVolcengineArkImage) { + t.Fatal("official ark image should match") + } + if !IsVolcengineArkImageProtocol(ChannelInterfaceVolcengineArkAgentPlanImage) { + t.Fatal("agent plan image should match") + } + if IsVolcengineArkImageProtocol(ChannelInterfaceOpenAIImage) { + t.Fatal("openai image should not match ark image") + } + if !IsVolcengineArkVideoProtocol(ChannelInterfaceVolcengineArkVideo) { + t.Fatal("official ark video should match") + } + if !IsVolcengineArkVideoProtocol(ChannelInterfaceVolcengineArkAgentPlanVideo) { + t.Fatal("agent plan video should match") + } + if IsVolcengineArkVideoProtocol(ChannelInterfaceNewAPIVideo) { + t.Fatal("newapi video should not match ark video") + } +} diff --git a/backend/internal/protocol/docs/volcengine-ark-agent-plan-image.md b/backend/internal/protocol/docs/volcengine-ark-agent-plan-image.md new file mode 100644 index 000000000..c2350a80d --- /dev/null +++ b/backend/internal/protocol/docs/volcengine-ark-agent-plan-image.md @@ -0,0 +1,37 @@ +# 火山方舟 Agent Plan 图片生成 + +本插件面向火山方舟 Agent Plan 专属图片入口。请求体与官方 Ark Seedream 协议一致,但 Base URL 与 API Key 必须来自 Agent Plan 控制台。 + +## 接口、鉴权与区域 + +{{OPERATIONS}} + +```http +POST {channel_base_url}/api/plan/v3/images/generations +Authorization: Bearer +Content-Type: application/json +``` + +与官方 `/api/v3` 的差异: + +| 项 | 官方 Ark | Agent Plan | +| --- | --- | --- | +| Base URL | `https://ark.cn-beijing.volces.com/api/v3` | `https://ark.cn-beijing.volces.com/api/plan/v3` | +| API Key | 推理接入控制台 Key | Agent Plan 专属 Key | +| 计费 | 推理后付费/项目额度 | AFP 套餐抵扣 | +| 请求体 | Seedream images/generations | 同左 | + +不要把官方 Key 打到 `/api/plan/v3`,也不要把 Agent Plan Key 打到 `/api/v3`。 + +## 参数与字段映射 + +{{PARAMETERS}} + +当前实现:`aspectRatio -> size`,所有 `images -> image[]`;`extra` 可透传 `size`、`sequential_image_generation`、`sequential_image_generation_options`、`watermark`。 + +## 官方资料 + +- [火山方舟 Agent Plan 文档](https://www.volcengine.com/docs/82379/2375486) +- [火山方舟视觉模型 API 文档](https://www.volcengine.com/docs/82379) + +{{CONTRACT}} diff --git a/backend/internal/protocol/docs/volcengine-ark-agent-plan-video.md b/backend/internal/protocol/docs/volcengine-ark-agent-plan-video.md new file mode 100644 index 000000000..b3a7d361a --- /dev/null +++ b/backend/internal/protocol/docs/volcengine-ark-agent-plan-video.md @@ -0,0 +1,43 @@ +# 火山方舟 Agent Plan 视频任务 + +本插件使用 Agent Plan 专属 Contents Generations Tasks 异步接口。提示词、参考图、参考视频和参考音频组成 `content[]`;比例、分辨率、时长、生成音频和水印位于顶层任务参数。请求体与官方 Ark Seedance 一致,入口改为 `/api/plan/v3`。 + +## 接口与鉴权 + +{{OPERATIONS}} + +```http +POST {channel_base_url}/api/plan/v3/contents/generations/tasks +GET {channel_base_url}/api/plan/v3/contents/generations/tasks/{task_id} +DELETE {channel_base_url}/api/plan/v3/contents/generations/tasks/{task_id} +Authorization: Bearer +Content-Type: application/json +``` + +与官方 `/api/v3` 的差异: + +| 项 | 官方 Ark | Agent Plan | +| --- | --- | --- | +| Base URL | `https://ark.cn-beijing.volces.com/api/v3` | `https://ark.cn-beijing.volces.com/api/plan/v3` | +| API Key | 推理接入控制台 Key | Agent Plan 专属 Key | +| 计费 | 推理后付费/项目额度 | AFP 套餐抵扣 | +| 请求体 | contents/generations/tasks | 同左 | + +## 参数与字段映射 + +{{PARAMETERS}} + +全模态参考的素材映射如下: + +- 图片:`{"type":"image_url","image_url":{"url":"..."},"role":"reference_image"}` +- 视频:`{"type":"video_url","video_url":{"url":"..."},"role":"reference_video"}` +- 音频:`{"type":"audio_url","audio_url":{"url":"..."},"role":"reference_audio"}` + +单次最多发送 9 张图片、3 个视频和 3 个音频。参考素材可以组合使用,但上游不支持纯音频或“文本 + 音频”。 + +## 官方资料 + +- [火山方舟 Agent Plan 文档](https://www.volcengine.com/docs/82379/2375486) +- [火山方舟内容生成任务文档](https://www.volcengine.com/docs/82379/1520757) + +{{CONTRACT}} diff --git a/backend/internal/protocol/official_catalog_test.go b/backend/internal/protocol/official_catalog_test.go index 3cb15ca9e..db64ef790 100644 --- a/backend/internal/protocol/official_catalog_test.go +++ b/backend/internal/protocol/official_catalog_test.go @@ -599,6 +599,36 @@ func TestOfficialArkSeedreamMapsAspectRatioToPixelSize(t *testing.T) { } } +func TestOfficialArkAgentPlanPluginsUsePlanPaths(t *testing.T) { + image := officialPackageAdapter(t, "volcengine-ark-agent-plan-seedream.yingce-plugin", "volcengine-ark-agent-plan-image") + imageCreate, err := image.BuildCreate(context.Background(), RequestContext{Request: GenerationRequest{Model: "doubao-seedream-5-0-260128", Prompt: "circle", AspectRatio: "1:1"}}) + if err != nil { + t.Fatal(err) + } + if imageCreate.Path != "/api/plan/v3/images/generations" { + t.Fatalf("agent plan image create = %#v", imageCreate) + } + if body := manifestTestBody(t, imageCreate); body["size"] != "2048x2048" { + t.Fatalf("agent plan image size = %#v", body["size"]) + } + + video := officialPackageAdapter(t, "volcengine-ark-agent-plan-seedance.yingce-plugin", "volcengine-ark-agent-plan-video") + videoCreate, err := video.BuildCreate(context.Background(), RequestContext{Request: GenerationRequest{Model: "doubao-seedance-2-0-260128", Prompt: "walk", AspectRatio: "16:9", Resolution: "720p", Duration: 5}}) + if err != nil { + t.Fatal(err) + } + if videoCreate.Path != "/api/plan/v3/contents/generations/tasks" { + t.Fatalf("agent plan video create = %#v", videoCreate) + } + poll, err := video.BuildPoll(context.Background(), PollContext{TaskID: "task-1", Model: "doubao-seedance-2-0-260128"}) + if err != nil { + t.Fatal(err) + } + if poll.Path != "/api/plan/v3/contents/generations/tasks/task-1" { + t.Fatalf("agent plan video poll = %#v", poll) + } +} + func TestOfficialGeminiImageMapsQualityToImageSize(t *testing.T) { adapter := officialPackageAdapter(t, "google-gemini-image.yingce-plugin", "gemini-image") tests := []struct { diff --git a/docs/content/docs/progress/pending-test.mdx b/docs/content/docs/progress/pending-test.mdx index 11f78111b..f2a2e2347 100644 --- a/docs/content/docs/progress/pending-test.mdx +++ b/docs/content/docs/progress/pending-test.mdx @@ -5,6 +5,13 @@ description: 当前项目已实现功能的手工验证清单与未确认边界 # 待测试 +## 火山方舟 Agent Plan 图片 / 视频插件 + +- 新增官方协议插件:`volcengine-ark-agent-plan-seedream`(provider `volcengine-ark-agent-plan-image`)与 `volcengine-ark-agent-plan-seedance`(provider `volcengine-ark-agent-plan-video`)。 +- 与官方 Ark 插件的差异只在接入面:默认 Base URL 为 `https://ark.cn-beijing.volces.com/api/plan/v3`,创建路径分别为 `/api/plan/v3/images/generations` 与 `/api/plan/v3/contents/generations/tasks`;请求体、参考素材 role、能力档位与官方 Seedream/Seedance 对齐。必须使用 Agent Plan 专属 API Key,不可与 `/api/v3` 官方 Key 混用。 +- 宿主已把 Agent Plan 协议纳入与官方 Ark 相同的能力默认值、Token 计费校验、方舟素材引用、取消任务与前端 payload 分支。 +- 待管理端安装这两个 `.yingce-plugin` 后:分别创建图片/视频渠道,确认默认 Base URL 为 `/api/plan/v3`;用 Agent Plan Key 文生图、参考图生图、Seedance 文生视频与全模态参考成功;故意混用官方 Key 应失败;官方 `volcengine-ark-*` 渠道行为不受影响。 + ## Agent Plan Seedream 误走可信素材(2026-09-17) 根因:`isArkPlanVideoConfig` / 前端 `usesArkVideoAssetReference` 仅按 Base URL 含 `/api/plan/v3` 判断,Agent Plan Seedream 与 Seedance 共用该路径,图片生成被误判为视频可信素材路径,自动 CreateAsset 并把参考图改成 `asset://`,上游图片接口拒绝。修复:后端仅 `mode=video` 且非图片协议时同步可信素材;前端仅视频 mode + 视频协议(或非图片协议的 Plan BaseURL)才提交 `asset://`。后端单测已覆盖。需浏览器验收: diff --git a/docs/design/model-request-protocol-landscape.md b/docs/design/model-request-protocol-landscape.md index 4f4f5a3c3..f1f830b3e 100644 --- a/docs/design/model-request-protocol-landscape.md +++ b/docs/design/model-request-protocol-landscape.md @@ -435,6 +435,8 @@ if model name contains minimax/h3 | `openai-videos` | multipart create/task/content/cancel | | `xai-video` | xAI JSON video + reference_images | | `volcengine-ark-seedance` | Ark contents task + multimodal roles | +| `volcengine-ark-agent-plan-seedream` | Agent Plan `/api/plan/v3/images/generations` | +| `volcengine-ark-agent-plan-seedance` | Agent Plan `/api/plan/v3/contents/generations/tasks` | | `minimax-hailuo-video-v2` | MiniMax `/v2/video_generation` | | `dashscope-wan-video` | DashScope async Wan task | | `newapi-media-task-v1` | NewAPI Channel 1 包装 | diff --git a/plugin-packages/generate-catalog.mjs b/plugin-packages/generate-catalog.mjs index 3c02b3c4d..8d7838f3c 100644 --- a/plugin-packages/generate-catalog.mjs +++ b/plugin-packages/generate-catalog.mjs @@ -374,27 +374,123 @@ const arkSeedreamRatioSizes = [ ["3:2", "2496x1664"], ["2:3", "1664x2496"], ["21:9", "3024x1296"] ]; +const arkSeedreamImageBody = (optionNamespace) => ({ + model: ref("request.model"), prompt: ref("request.prompt"), + // Ark 的 size 只接受 WIDTHxHEIGHT 或 2k/3k/4k;统一层的比例值在这里换算成 2K 档像素尺寸,像素或档位值原样透传。 + size: omit({ $switch: { cases: arkSeedreamRatioSizes.map(([ratio, size]) => ({ when: eq(ref("request.aspectRatio"), ratio), then: size })), default: ref("request.aspectRatio") } }), + image: omit(conditional( + eq(len(ref("request.images")), 1), + first(map(ref("request.images"), "media", ref("media.value"))), + conditional(gt(len(ref("request.images")), 1), map(ref("request.images"), "media", ref("media.value")), null) + )), + sequential_image_generation: omit(ref(`request.providerOptions.${optionNamespace}.sequential_image_generation`)), + sequential_image_generation_options: omit(ref(`request.providerOptions.${optionNamespace}.sequential_image_generation_options`)), + watermark: coalesce(ref(`request.providerOptions.${optionNamespace}.watermark`), ref("request.watermark"), false), + seed: omit(ref(`request.providerOptions.${optionNamespace}.seed`)), + response_format: coalesce(ref(`request.providerOptions.${optionNamespace}.response_format`), "b64_json") +}); + add({ id: "volcengine-ark-seedream", providerId: "volcengine-ark-image", name: "Volcengine Ark Seedream Images", vendor: "Volcengine", capability: "image", baseUrl: "https://ark.cn-beijing.volces.com", auth: bearer, params: imageParams, - create: jsonCreate("/api/v3/images/generations", { - model: ref("request.model"), prompt: ref("request.prompt"), - // Ark 的 size 只接受 WIDTHxHEIGHT 或 2k/3k/4k;统一层的比例值在这里换算成 2K 档像素尺寸,像素或档位值原样透传。 - size: omit({ $switch: { cases: arkSeedreamRatioSizes.map(([ratio, size]) => ({ when: eq(ref("request.aspectRatio"), ratio), then: size })), default: ref("request.aspectRatio") } }), - image: omit(conditional( - eq(len(ref("request.images")), 1), - first(map(ref("request.images"), "media", ref("media.value"))), - conditional(gt(len(ref("request.images")), 1), map(ref("request.images"), "media", ref("media.value")), null) - )), - sequential_image_generation: omit(ref("request.providerOptions.volcengine-ark-image.sequential_image_generation")), - sequential_image_generation_options: omit(ref("request.providerOptions.volcengine-ark-image.sequential_image_generation_options")), - watermark: coalesce(ref("request.providerOptions.volcengine-ark-image.watermark"), ref("request.watermark"), false), - seed: omit(ref("request.providerOptions.volcengine-ark-image.seed")), - response_format: coalesce(ref("request.providerOptions.volcengine-ark-image.response_format"), "b64_json") - }), + notes: "官方 Ark 推理接入:Base URL 使用 /api/v3,API Key 来自方舟推理接入控制台,不可与 Agent Plan 专属 Key 混用。", + create: jsonCreate("/api/v3/images/generations", arkSeedreamImageBody("volcengine-ark-image")), response: { status: "succeeded", images: ref("response.data"), usage: ref("response.usage"), errorPaths: ["error.code"], messagePaths: ["error.message"] } }); +add({ + id: "volcengine-ark-agent-plan-seedream", providerId: "volcengine-ark-agent-plan-image", name: "Volcengine Ark Agent Plan Seedream Images", vendor: "Volcengine", capability: "image", + baseUrl: "https://ark.cn-beijing.volces.com", auth: bearer, params: imageParams, + notes: "Agent Plan 专属接入:请求路径为 /api/plan/v3/images/generations,必须使用 Agent Plan 控制台专属 API Key;请求体与官方 Seedream 协议一致,但凭证与额度按 AFP 套餐结算,不能与 /api/v3 官方 Key 混用。", + create: jsonCreate("/api/plan/v3/images/generations", arkSeedreamImageBody("volcengine-ark-agent-plan-image")), + response: { status: "succeeded", images: ref("response.data"), usage: ref("response.usage"), errorPaths: ["error.code"], messagePaths: ["error.message"] } +}); + +const arkSeedanceValidations = [ + { assert: { $lte: [len(ref("request.images")), 9] }, message: "Seedance 最多支持 9 张参考图片" }, + { assert: { $lte: [len(ref("request.videos")), 3] }, message: "Seedance 最多支持 3 个参考视频" }, + { assert: { $lte: [len(ref("request.audios")), 3] }, message: "Seedance 最多支持 3 个参考音频" }, + { assert: { $or: [eq(len(ref("request.audios")), 0), gt({ $add: [len(ref("request.images")), len(ref("request.videos"))] }, 0)] }, message: "Seedance 不支持纯音频或文本+音频,请同时添加参考图片或参考视频" } +]; + +const arkSeedanceParams = [ + ["model", "string", true, "model", "Ark endpoint/model ID。"], + ["prompt", "string", true, "content[type=text].text", "视频提示词。"], + ["images", "media[]", false, "content[type=image_url]", "first_frame、last_frame、reference_image 等 role 原样映射。"], + ["videos", "media[]", false, "content[type=video_url]", "reference_video。"], + ["audios", "media[]", false, "content[type=audio_url]", "reference_audio/reference_voice。"], + ["aspectRatio", "string", false, "ratio", "输出画幅。"], + ["resolution", "string", false, "resolution", "输出分辨率档位。"], + ["duration", "integer", false, "duration", "输出时长秒数。"], + ["generateAudio", "boolean", false, "generate_audio", "是否生成音频。"], + ["watermark", "boolean", false, "watermark", "是否带水印。"], + ["seed", "integer", false, "seed", "providerOptions seed。"], + ["camera_fixed", "boolean", false, "camera_fixed", "providerOptions camera_fixed。"] +]; + +const arkSeedanceBody = (optionNamespace) => ({ + model: ref("request.model"), + content: { + $concatArrays: [ + [{ type: "text", text: ref("request.prompt") }], + map(sorted(ref("request.images")), "media", { + type: "image_url", + image_url: { url: ref("media.value") }, + role: coalesce(ref("media.role"), "reference_image") + }), + map(sorted(ref("request.videos")), "media", { + type: "video_url", + video_url: { url: ref("media.value") }, + role: coalesce(ref("media.role"), "reference_video") + }), + map(sorted(ref("request.audios")), "media", { + type: "audio_url", + audio_url: { url: ref("media.value") }, + role: coalesce(ref("media.role"), "reference_audio") + }) + ] + }, + ratio: coalesce(ref("request.aspectRatio"), "16:9"), + resolution: coalesce(ref("request.resolution"), "720p"), + duration: conditional(gt(ref("request.duration"), 0), ref("request.duration"), 5), + generate_audio: ref("request.generateAudio"), + watermark: ref("request.watermark"), + seed: omit(ref(`request.providerOptions.${optionNamespace}.seed`)), + camera_fixed: omit(ref(`request.providerOptions.${optionNamespace}.camera_fixed`)) +}); + +const arkSeedanceResponse = { + taskId: coalesce(ref("response.id"), ref("response.task_id"), ref("response.data.id"), ref("taskId")), + status: coalesce(ref("response.status"), ref("response.data.status"), "pending"), + message: coalesce(ref("response.error.message"), ref("response.message"), ref("response.fail_reason")), + videos: coalesce(ref("response.content.video_url"), ref("response.video_url"), ref("response.output.video_url"), ref("response.data.video_url")), + usage: ref("response.usage"), + errorPaths: ["error.code"], + resultEphemeral: true +}; + +add({ + id: "volcengine-ark-seedance", providerId: "volcengine-ark-video", name: "Volcengine Ark Seedance", vendor: "Volcengine", capability: "video", + baseUrl: "https://ark.cn-beijing.volces.com", auth: bearer, params: arkSeedanceParams, requiresPublicMediaUrls: true, + validations: arkSeedanceValidations, + notes: "官方 Ark 推理接入:创建/查询/取消走 /api/v3/contents/generations/tasks;插件不根据图片下标推断首尾帧,role 由业务层确定。API Key 来自方舟推理接入控制台。", + create: jsonCreate("/api/v3/contents/generations/tasks", arkSeedanceBody("volcengine-ark-video")), + poll: { method: "GET", path: "/api/v3/contents/generations/tasks/{{taskId}}" }, + cancel: { method: "DELETE", path: "/api/v3/contents/generations/tasks/{{taskId}}" }, + response: arkSeedanceResponse +}); + +add({ + id: "volcengine-ark-agent-plan-seedance", providerId: "volcengine-ark-agent-plan-video", name: "Volcengine Ark Agent Plan Seedance", vendor: "Volcengine", capability: "video", + baseUrl: "https://ark.cn-beijing.volces.com", auth: bearer, params: arkSeedanceParams, requiresPublicMediaUrls: true, + validations: arkSeedanceValidations, + notes: "Agent Plan 专属接入:创建/查询/取消走 /api/plan/v3/contents/generations/tasks;请求体与官方 Seedance 协议一致,但必须使用 Agent Plan 专属 API Key 与 AFP 额度,不能与 /api/v3 官方 Key 混用。", + create: jsonCreate("/api/plan/v3/contents/generations/tasks", arkSeedanceBody("volcengine-ark-agent-plan-video")), + poll: { method: "GET", path: "/api/plan/v3/contents/generations/tasks/{{taskId}}" }, + cancel: { method: "DELETE", path: "/api/plan/v3/contents/generations/tasks/{{taskId}}" }, + response: arkSeedanceResponse +}); + // Gemini imageConfig.imageSize 只接受 1K/2K/4K;画布统一层用 1k/2k/4k 或 low/medium/high。 const geminiImageSize = omit({ $coalesce: [ diff --git a/plugin-packages/volcengine-ark-agent-plan-seedance.yingce-plugin b/plugin-packages/volcengine-ark-agent-plan-seedance.yingce-plugin new file mode 100644 index 0000000000000000000000000000000000000000..f234239ea02724528a74a197f921228430faadd2 GIT binary patch literal 9515 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 QY(xL6hJW3R>Oa%}0=aD%Q~&?~ literal 0 HcmV?d00001 diff --git a/plugin-packages/volcengine-ark-agent-plan-seedance/README.md b/plugin-packages/volcengine-ark-agent-plan-seedance/README.md new file mode 100644 index 000000000..5c0da702e --- /dev/null +++ b/plugin-packages/volcengine-ark-agent-plan-seedance/README.md @@ -0,0 +1,5 @@ +# Volcengine Ark Agent Plan Seedance + +该目录是独立官方协议插件源码。后端从生成的 `volcengine-ark-agent-plan-seedance.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。 + +完整接口见 [docs/interface.md](docs/interface.md)。 diff --git a/plugin-packages/volcengine-ark-agent-plan-seedance/docs/interface.md b/plugin-packages/volcengine-ark-agent-plan-seedance/docs/interface.md new file mode 100644 index 000000000..8e4f49c6c --- /dev/null +++ b/plugin-packages/volcengine-ark-agent-plan-seedance/docs/interface.md @@ -0,0 +1,527 @@ +# Volcengine Ark Agent Plan Seedance 接口字段 + +## 协议身份 + +- 插件 ID:`volcengine-ark-agent-plan-seedance`。 +- Provider ID:`volcengine-ark-agent-plan-video`。 +- 能力:`video`。 +- 默认 Base URL:`https://ark.cn-beijing.volces.com`。 +- 鉴权驱动:`bearer`。 +- 创建:`POST /api/plan/v3/contents/generations/tasks`。 +- 查询:`GET /api/plan/v3/contents/generations/tasks/{{taskId}}`。 +- 取消:`DELETE /api/plan/v3/contents/generations/tasks/{{taskId}}`。 + +## 配置字段 + +| 字段 | 类型 | 必填 | 含义 | +| --- | --- | --- | --- | +| `apiKey` | secret | 是 | API Key | + +## 统一字段映射 + +| 统一字段 | 类型 | 必填 | 上游映射 | 说明 | +| --- | --- | --- | --- | --- | +| `model` | string | 是 | `model` | Ark endpoint/model ID。 | +| `prompt` | string | 是 | `content[type=text].text` | 视频提示词。 | +| `images` | media[] | 否 | `content[type=image_url]` | first_frame、last_frame、reference_image 等 role 原样映射。 | +| `videos` | media[] | 否 | `content[type=video_url]` | reference_video。 | +| `audios` | media[] | 否 | `content[type=audio_url]` | reference_audio/reference_voice。 | +| `aspectRatio` | string | 否 | `ratio` | 输出画幅。 | +| `resolution` | string | 否 | `resolution` | 输出分辨率档位。 | +| `duration` | integer | 否 | `duration` | 输出时长秒数。 | +| `generateAudio` | boolean | 否 | `generate_audio` | 是否生成音频。 | +| `watermark` | boolean | 否 | `watermark` | 是否带水印。 | +| `seed` | integer | 否 | `seed` | providerOptions seed。 | +| `camera_fixed` | boolean | 否 | `camera_fixed` | providerOptions camera_fixed。 | + +## 上游请求模板逐字段清单 + +下表由插件请求模板生成,覆盖 body、query、headers 和 multipart 文件声明中的每个字段。 + +| 上游位置 | 值或转换表达式 | +| --- | --- | +| `create.method` | `"POST"` | +| `create.path` | `"/api/plan/v3/contents/generations/tasks"` | +| `create.contentType` | `"application/json"` | +| `create.body.model` | `{"$ref":"request.model"}` | +| `create.body.content` | `{"$concatArrays":[[{"type":"text","text":{"$ref":"request.prompt"}}],{"$map":{"from":{"$sortByOrder":{"$ref":"request.images"}},"as":"media","in":{"type":"image_url","image_url":{"url":{"$ref":"media.value"}},"role":{"$coalesce":[{"$ref":"media.role"},"reference_image"]}}}},{"$map":{"from":{"$sortByOrder":{"$ref":"request.videos"}},"as":"media","in":{"type":"video_url","video_url":{"url":{"$ref":"media.value"}},"role":{"$coalesce":[{"$ref":"media.role"},"reference_video"]}}}},{"$map":{"from":{"$sortByOrder":{"$ref":"request.audios"}},"as":"media","in":{"type":"audio_url","audio_url":{"url":{"$ref":"media.value"}},"role":{"$coalesce":[{"$ref":"media.role"},"reference_audio"]}}}}]}` | +| `create.body.ratio` | `{"$coalesce":[{"$ref":"request.aspectRatio"},"16:9"]}` | +| `create.body.resolution` | `{"$coalesce":[{"$ref":"request.resolution"},"720p"]}` | +| `create.body.duration` | `{"$if":{"condition":{"$gt":[{"$ref":"request.duration"},0]},"then":{"$ref":"request.duration"},"else":5}}` | +| `create.body.generate_audio` | `{"$ref":"request.generateAudio"}` | +| `create.body.watermark` | `{"$ref":"request.watermark"}` | +| `create.body.seed` | `{"$omitEmpty":{"$ref":"request.providerOptions.volcengine-ark-agent-plan-video.seed"}}` | +| `create.body.camera_fixed` | `{"$omitEmpty":{"$ref":"request.providerOptions.volcengine-ark-agent-plan-video.camera_fixed"}}` | +| `poll.method` | `"GET"` | +| `poll.path` | `"/api/plan/v3/contents/generations/tasks/{{taskId}}"` | +| `poll.contentType` | `"application/json"` | +| `cancel.method` | `"DELETE"` | +| `cancel.path` | `"/api/plan/v3/contents/generations/tasks/{{taskId}}"` | +| `cancel.contentType` | `"application/json"` | + +## Provider 扩展键 + +- `providerOptions.volcengine-ark-agent-plan-video.camera_fixed` +- `providerOptions.volcengine-ark-agent-plan-video.seed` + +动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。 + +## 响应映射逐字段清单 + +| 映射位置 | 上游路径或转换表达式 | +| --- | --- | +| `response.taskId` | `{"$coalesce":[{"$ref":"response.id"},{"$ref":"response.task_id"},{"$ref":"response.data.id"},{"$ref":"taskId"}]}` | +| `response.status` | `{"$coalesce":[{"$ref":"response.status"},{"$ref":"response.data.status"},"pending"]}` | +| `response.message` | `{"$coalesce":[{"$ref":"response.error.message"},{"$ref":"response.message"},{"$ref":"response.fail_reason"}]}` | +| `response.videos` | `{"$coalesce":[{"$ref":"response.content.video_url"},{"$ref":"response.video_url"},{"$ref":"response.output.video_url"},{"$ref":"response.data.video_url"}]}` | +| `response.usage` | `{"$ref":"response.usage"}` | +| `response.errorPaths[0]` | `"error.code"` | +| `response.resultEphemeral` | `true` | + +## 响应与错误 + +插件把上游 task/status/text/media/usage 映射为统一结果。临时媒体 URL 标记为 ephemeral,由宿主立即下载持久化。HTTP 错误、业务 code 和 error object 保持失败语义,不包装成成功。 + +## 兼容边界 + +Agent Plan 专属接入:创建/查询/取消走 /api/plan/v3/contents/generations/tasks;请求体与官方 Seedance 协议一致,但必须使用 Agent Plan 专属 API Key 与 AFP 额度,不能与 /api/v3 官方 Key 混用。 + + +## Manifest 完整接口定义 + +以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。 + +```json +{ + "apiVersion": "yingce.plugin/v2", + "id": "volcengine-ark-agent-plan-seedance", + "name": "Volcengine Ark Agent Plan Seedance", + "version": "2.0.0", + "author": "Volcengine / 影策", + "description": "Volcengine Ark Agent Plan Seedance 独立请求协议插件。", + "documentation": "<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "volcengine-ark-agent-plan-video", + "label": "Volcengine Ark Agent Plan Seedance", + "capabilities": [ + "video" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://ark.cn-beijing.volces.com", + "requiresPublicMediaUrls": true, + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "Ark endpoint/model ID。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "content[type=text].text", + "description": "视频提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "content[type=image_url]", + "description": "first_frame、last_frame、reference_image 等 role 原样映射。" + }, + { + "name": "videos", + "type": "media[]", + "required": false, + "mapping": "content[type=video_url]", + "description": "reference_video。" + }, + { + "name": "audios", + "type": "media[]", + "required": false, + "mapping": "content[type=audio_url]", + "description": "reference_audio/reference_voice。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "ratio", + "description": "输出画幅。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution", + "description": "输出分辨率档位。" + }, + { + "name": "duration", + "type": "integer", + "required": false, + "mapping": "duration", + "description": "输出时长秒数。" + }, + { + "name": "generateAudio", + "type": "boolean", + "required": false, + "mapping": "generate_audio", + "description": "是否生成音频。" + }, + { + "name": "watermark", + "type": "boolean", + "required": false, + "mapping": "watermark", + "description": "是否带水印。" + }, + { + "name": "seed", + "type": "integer", + "required": false, + "mapping": "seed", + "description": "providerOptions seed。" + }, + { + "name": "camera_fixed", + "type": "boolean", + "required": false, + "mapping": "camera_fixed", + "description": "providerOptions camera_fixed。" + } + ], + "validations": [ + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.images" + } + }, + 9 + ] + }, + "message": "Seedance 最多支持 9 张参考图片" + }, + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.videos" + } + }, + 3 + ] + }, + "message": "Seedance 最多支持 3 个参考视频" + }, + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.audios" + } + }, + 3 + ] + }, + "message": "Seedance 最多支持 3 个参考音频" + }, + { + "assert": { + "$or": [ + { + "$eq": [ + { + "$len": { + "$ref": "request.audios" + } + }, + 0 + ] + }, + { + "$gt": [ + { + "$add": [ + { + "$len": { + "$ref": "request.images" + } + }, + { + "$len": { + "$ref": "request.videos" + } + } + ] + }, + 0 + ] + } + ] + }, + "message": "Seedance 不支持纯音频或文本+音频,请同时添加参考图片或参考视频" + } + ], + "create": { + "method": "POST", + "path": "/api/plan/v3/contents/generations/tasks", + "contentType": "application/json", + "body": { + "model": { + "$ref": "request.model" + }, + "content": { + "$concatArrays": [ + [ + { + "type": "text", + "text": { + "$ref": "request.prompt" + } + } + ], + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.images" + } + }, + "as": "media", + "in": { + "type": "image_url", + "image_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_image" + ] + } + } + } + }, + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.videos" + } + }, + "as": "media", + "in": { + "type": "video_url", + "video_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_video" + ] + } + } + } + }, + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.audios" + } + }, + "as": "media", + "in": { + "type": "audio_url", + "audio_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_audio" + ] + } + } + } + } + ] + }, + "ratio": { + "$coalesce": [ + { + "$ref": "request.aspectRatio" + }, + "16:9" + ] + }, + "resolution": { + "$coalesce": [ + { + "$ref": "request.resolution" + }, + "720p" + ] + }, + "duration": { + "$if": { + "condition": { + "$gt": [ + { + "$ref": "request.duration" + }, + 0 + ] + }, + "then": { + "$ref": "request.duration" + }, + "else": 5 + } + }, + "generate_audio": { + "$ref": "request.generateAudio" + }, + "watermark": { + "$ref": "request.watermark" + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-video.seed" + } + }, + "camera_fixed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-video.camera_fixed" + } + } + } + }, + "poll": { + "method": "GET", + "path": "/api/plan/v3/contents/generations/tasks/{{taskId}}" + }, + "cancel": { + "method": "DELETE", + "path": "/api/plan/v3/contents/generations/tasks/{{taskId}}" + }, + "response": { + "taskId": { + "$coalesce": [ + { + "$ref": "response.id" + }, + { + "$ref": "response.task_id" + }, + { + "$ref": "response.data.id" + }, + { + "$ref": "taskId" + } + ] + }, + "status": { + "$coalesce": [ + { + "$ref": "response.status" + }, + { + "$ref": "response.data.status" + }, + "pending" + ] + }, + "message": { + "$coalesce": [ + { + "$ref": "response.error.message" + }, + { + "$ref": "response.message" + }, + { + "$ref": "response.fail_reason" + } + ] + }, + "videos": { + "$coalesce": [ + { + "$ref": "response.content.video_url" + }, + { + "$ref": "response.video_url" + }, + { + "$ref": "response.output.video_url" + }, + { + "$ref": "response.data.video_url" + } + ] + }, + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "resultEphemeral": true + } + } + ] + } +} +``` + diff --git a/plugin-packages/volcengine-ark-agent-plan-seedance/manifest.json b/plugin-packages/volcengine-ark-agent-plan-seedance/manifest.json new file mode 100644 index 000000000..90c6d4348 --- /dev/null +++ b/plugin-packages/volcengine-ark-agent-plan-seedance/manifest.json @@ -0,0 +1,431 @@ +{ + "apiVersion": "yingce.plugin/v2", + "id": "volcengine-ark-agent-plan-seedance", + "name": "Volcengine Ark Agent Plan Seedance", + "version": "2.0.0", + "author": "Volcengine / 影策", + "description": "Volcengine Ark Agent Plan Seedance 独立请求协议插件。", + "documentation": "# Volcengine Ark Agent Plan Seedance\n\n该目录是独立官方协议插件源码。后端从生成的 `volcengine-ark-agent-plan-seedance.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# Volcengine Ark Agent Plan Seedance 接口字段\n\n## 协议身份\n\n- 插件 ID:`volcengine-ark-agent-plan-seedance`。\n- Provider ID:`volcengine-ark-agent-plan-video`。\n- 能力:`video`。\n- 默认 Base URL:`https://ark.cn-beijing.volces.com`。\n- 鉴权驱动:`bearer`。\n- 创建:`POST /api/plan/v3/contents/generations/tasks`。\n- 查询:`GET /api/plan/v3/contents/generations/tasks/{{taskId}}`。\n- 取消:`DELETE /api/plan/v3/contents/generations/tasks/{{taskId}}`。\n\n## 配置字段\n\n| 字段 | 类型 | 必填 | 含义 |\n| --- | --- | --- | --- |\n| `apiKey` | secret | 是 | API Key |\n\n## 统一字段映射\n\n| 统一字段 | 类型 | 必填 | 上游映射 | 说明 |\n| --- | --- | --- | --- | --- |\n| `model` | string | 是 | `model` | Ark endpoint/model ID。 |\n| `prompt` | string | 是 | `content[type=text].text` | 视频提示词。 |\n| `images` | media[] | 否 | `content[type=image_url]` | first_frame、last_frame、reference_image 等 role 原样映射。 |\n| `videos` | media[] | 否 | `content[type=video_url]` | reference_video。 |\n| `audios` | media[] | 否 | `content[type=audio_url]` | reference_audio/reference_voice。 |\n| `aspectRatio` | string | 否 | `ratio` | 输出画幅。 |\n| `resolution` | string | 否 | `resolution` | 输出分辨率档位。 |\n| `duration` | integer | 否 | `duration` | 输出时长秒数。 |\n| `generateAudio` | boolean | 否 | `generate_audio` | 是否生成音频。 |\n| `watermark` | boolean | 否 | `watermark` | 是否带水印。 |\n| `seed` | integer | 否 | `seed` | providerOptions seed。 |\n| `camera_fixed` | boolean | 否 | `camera_fixed` | providerOptions camera_fixed。 |\n\n## 上游请求模板逐字段清单\n\n下表由插件请求模板生成,覆盖 body、query、headers 和 multipart 文件声明中的每个字段。\n\n| 上游位置 | 值或转换表达式 |\n| --- | --- |\n| `create.method` | `\"POST\"` |\n| `create.path` | `\"/api/plan/v3/contents/generations/tasks\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.content` | `{\"$concatArrays\":[[{\"type\":\"text\",\"text\":{\"$ref\":\"request.prompt\"}}],{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.images\"}},\"as\":\"media\",\"in\":{\"type\":\"image_url\",\"image_url\":{\"url\":{\"$ref\":\"media.value\"}},\"role\":{\"$coalesce\":[{\"$ref\":\"media.role\"},\"reference_image\"]}}}},{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.videos\"}},\"as\":\"media\",\"in\":{\"type\":\"video_url\",\"video_url\":{\"url\":{\"$ref\":\"media.value\"}},\"role\":{\"$coalesce\":[{\"$ref\":\"media.role\"},\"reference_video\"]}}}},{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.audios\"}},\"as\":\"media\",\"in\":{\"type\":\"audio_url\",\"audio_url\":{\"url\":{\"$ref\":\"media.value\"}},\"role\":{\"$coalesce\":[{\"$ref\":\"media.role\"},\"reference_audio\"]}}}}]}` |\n| `create.body.ratio` | `{\"$coalesce\":[{\"$ref\":\"request.aspectRatio\"},\"16:9\"]}` |\n| `create.body.resolution` | `{\"$coalesce\":[{\"$ref\":\"request.resolution\"},\"720p\"]}` |\n| `create.body.duration` | `{\"$if\":{\"condition\":{\"$gt\":[{\"$ref\":\"request.duration\"},0]},\"then\":{\"$ref\":\"request.duration\"},\"else\":5}}` |\n| `create.body.generate_audio` | `{\"$ref\":\"request.generateAudio\"}` |\n| `create.body.watermark` | `{\"$ref\":\"request.watermark\"}` |\n| `create.body.seed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-agent-plan-video.seed\"}}` |\n| `create.body.camera_fixed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-agent-plan-video.camera_fixed\"}}` |\n| `poll.method` | `\"GET\"` |\n| `poll.path` | `\"/api/plan/v3/contents/generations/tasks/{{taskId}}\"` |\n| `poll.contentType` | `\"application/json\"` |\n| `cancel.method` | `\"DELETE\"` |\n| `cancel.path` | `\"/api/plan/v3/contents/generations/tasks/{{taskId}}\"` |\n| `cancel.contentType` | `\"application/json\"` |\n\n## Provider 扩展键\n\n- `providerOptions.volcengine-ark-agent-plan-video.camera_fixed`\n- `providerOptions.volcengine-ark-agent-plan-video.seed`\n\n动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。\n\n## 响应映射逐字段清单\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.taskId` | `{\"$coalesce\":[{\"$ref\":\"response.id\"},{\"$ref\":\"response.task_id\"},{\"$ref\":\"response.data.id\"},{\"$ref\":\"taskId\"}]}` |\n| `response.status` | `{\"$coalesce\":[{\"$ref\":\"response.status\"},{\"$ref\":\"response.data.status\"},\"pending\"]}` |\n| `response.message` | `{\"$coalesce\":[{\"$ref\":\"response.error.message\"},{\"$ref\":\"response.message\"},{\"$ref\":\"response.fail_reason\"}]}` |\n| `response.videos` | `{\"$coalesce\":[{\"$ref\":\"response.content.video_url\"},{\"$ref\":\"response.video_url\"},{\"$ref\":\"response.output.video_url\"},{\"$ref\":\"response.data.video_url\"}]}` |\n| `response.usage` | `{\"$ref\":\"response.usage\"}` |\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\nAgent Plan 专属接入:创建/查询/取消走 /api/plan/v3/contents/generations/tasks;请求体与官方 Seedance 协议一致,但必须使用 Agent Plan 专属 API Key 与 AFP 额度,不能与 /api/v3 官方 Key 混用。\n\n\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"volcengine-ark-agent-plan-seedance\",\n \"name\": \"Volcengine Ark Agent Plan Seedance\",\n \"version\": \"2.0.0\",\n \"author\": \"Volcengine / 影策\",\n \"description\": \"Volcengine Ark Agent Plan Seedance 独立请求协议插件。\",\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\": \"volcengine-ark-agent-plan-video\",\n \"label\": \"Volcengine Ark Agent Plan Seedance\",\n \"capabilities\": [\n \"video\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"https://ark.cn-beijing.volces.com\",\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\": \"Ark endpoint/model ID。\"\n },\n {\n \"name\": \"prompt\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"content[type=text].text\",\n \"description\": \"视频提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"content[type=image_url]\",\n \"description\": \"first_frame、last_frame、reference_image 等 role 原样映射。\"\n },\n {\n \"name\": \"videos\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"content[type=video_url]\",\n \"description\": \"reference_video。\"\n },\n {\n \"name\": \"audios\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"content[type=audio_url]\",\n \"description\": \"reference_audio/reference_voice。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"ratio\",\n \"description\": \"输出画幅。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution\",\n \"description\": \"输出分辨率档位。\"\n },\n {\n \"name\": \"duration\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"duration\",\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\": \"seed\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"seed\",\n \"description\": \"providerOptions seed。\"\n },\n {\n \"name\": \"camera_fixed\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"camera_fixed\",\n \"description\": \"providerOptions camera_fixed。\"\n }\n ],\n \"validations\": [\n {\n \"assert\": {\n \"$lte\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 9\n ]\n },\n \"message\": \"Seedance 最多支持 9 张参考图片\"\n },\n {\n \"assert\": {\n \"$lte\": [\n {\n \"$len\": {\n \"$ref\": \"request.videos\"\n }\n },\n 3\n ]\n },\n \"message\": \"Seedance 最多支持 3 个参考视频\"\n },\n {\n \"assert\": {\n \"$lte\": [\n {\n \"$len\": {\n \"$ref\": \"request.audios\"\n }\n },\n 3\n ]\n },\n \"message\": \"Seedance 最多支持 3 个参考音频\"\n },\n {\n \"assert\": {\n \"$or\": [\n {\n \"$eq\": [\n {\n \"$len\": {\n \"$ref\": \"request.audios\"\n }\n },\n 0\n ]\n },\n {\n \"$gt\": [\n {\n \"$add\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n {\n \"$len\": {\n \"$ref\": \"request.videos\"\n }\n }\n ]\n },\n 0\n ]\n }\n ]\n },\n \"message\": \"Seedance 不支持纯音频或文本+音频,请同时添加参考图片或参考视频\"\n }\n ],\n \"create\": {\n \"method\": \"POST\",\n \"path\": \"/api/plan/v3/contents/generations/tasks\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"content\": {\n \"$concatArrays\": [\n [\n {\n \"type\": \"text\",\n \"text\": {\n \"$ref\": \"request.prompt\"\n }\n }\n ],\n {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.images\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"image_url\",\n \"image_url\": {\n \"url\": {\n \"$ref\": \"media.value\"\n }\n },\n \"role\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.role\"\n },\n \"reference_image\"\n ]\n }\n }\n }\n },\n {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.videos\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"video_url\",\n \"video_url\": {\n \"url\": {\n \"$ref\": \"media.value\"\n }\n },\n \"role\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.role\"\n },\n \"reference_video\"\n ]\n }\n }\n }\n },\n {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.audios\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"audio_url\",\n \"audio_url\": {\n \"url\": {\n \"$ref\": \"media.value\"\n }\n },\n \"role\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.role\"\n },\n \"reference_audio\"\n ]\n }\n }\n }\n }\n ]\n },\n \"ratio\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"16:9\"\n ]\n },\n \"resolution\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.resolution\"\n },\n \"720p\"\n ]\n },\n \"duration\": {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$ref\": \"request.duration\"\n },\n 0\n ]\n },\n \"then\": {\n \"$ref\": \"request.duration\"\n },\n \"else\": 5\n }\n },\n \"generate_audio\": {\n \"$ref\": \"request.generateAudio\"\n },\n \"watermark\": {\n \"$ref\": \"request.watermark\"\n },\n \"seed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-agent-plan-video.seed\"\n }\n },\n \"camera_fixed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-agent-plan-video.camera_fixed\"\n }\n }\n }\n },\n \"poll\": {\n \"method\": \"GET\",\n \"path\": \"/api/plan/v3/contents/generations/tasks/{{taskId}}\"\n },\n \"cancel\": {\n \"method\": \"DELETE\",\n \"path\": \"/api/plan/v3/contents/generations/tasks/{{taskId}}\"\n },\n \"response\": {\n \"taskId\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.id\"\n },\n {\n \"$ref\": \"response.task_id\"\n },\n {\n \"$ref\": \"response.data.id\"\n },\n {\n \"$ref\": \"taskId\"\n }\n ]\n },\n \"status\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.status\"\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.content.video_url\"\n },\n {\n \"$ref\": \"response.video_url\"\n },\n {\n \"$ref\": \"response.output.video_url\"\n },\n {\n \"$ref\": \"response.data.video_url\"\n }\n ]\n },\n \"usage\": {\n \"$ref\": \"response.usage\"\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"resultEphemeral\": true\n }\n }\n ]\n }\n}\n```\n\n", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "volcengine-ark-agent-plan-video", + "label": "Volcengine Ark Agent Plan Seedance", + "capabilities": [ + "video" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://ark.cn-beijing.volces.com", + "requiresPublicMediaUrls": true, + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "Ark endpoint/model ID。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "content[type=text].text", + "description": "视频提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "content[type=image_url]", + "description": "first_frame、last_frame、reference_image 等 role 原样映射。" + }, + { + "name": "videos", + "type": "media[]", + "required": false, + "mapping": "content[type=video_url]", + "description": "reference_video。" + }, + { + "name": "audios", + "type": "media[]", + "required": false, + "mapping": "content[type=audio_url]", + "description": "reference_audio/reference_voice。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "ratio", + "description": "输出画幅。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution", + "description": "输出分辨率档位。" + }, + { + "name": "duration", + "type": "integer", + "required": false, + "mapping": "duration", + "description": "输出时长秒数。" + }, + { + "name": "generateAudio", + "type": "boolean", + "required": false, + "mapping": "generate_audio", + "description": "是否生成音频。" + }, + { + "name": "watermark", + "type": "boolean", + "required": false, + "mapping": "watermark", + "description": "是否带水印。" + }, + { + "name": "seed", + "type": "integer", + "required": false, + "mapping": "seed", + "description": "providerOptions seed。" + }, + { + "name": "camera_fixed", + "type": "boolean", + "required": false, + "mapping": "camera_fixed", + "description": "providerOptions camera_fixed。" + } + ], + "validations": [ + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.images" + } + }, + 9 + ] + }, + "message": "Seedance 最多支持 9 张参考图片" + }, + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.videos" + } + }, + 3 + ] + }, + "message": "Seedance 最多支持 3 个参考视频" + }, + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.audios" + } + }, + 3 + ] + }, + "message": "Seedance 最多支持 3 个参考音频" + }, + { + "assert": { + "$or": [ + { + "$eq": [ + { + "$len": { + "$ref": "request.audios" + } + }, + 0 + ] + }, + { + "$gt": [ + { + "$add": [ + { + "$len": { + "$ref": "request.images" + } + }, + { + "$len": { + "$ref": "request.videos" + } + } + ] + }, + 0 + ] + } + ] + }, + "message": "Seedance 不支持纯音频或文本+音频,请同时添加参考图片或参考视频" + } + ], + "create": { + "method": "POST", + "path": "/api/plan/v3/contents/generations/tasks", + "contentType": "application/json", + "body": { + "model": { + "$ref": "request.model" + }, + "content": { + "$concatArrays": [ + [ + { + "type": "text", + "text": { + "$ref": "request.prompt" + } + } + ], + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.images" + } + }, + "as": "media", + "in": { + "type": "image_url", + "image_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_image" + ] + } + } + } + }, + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.videos" + } + }, + "as": "media", + "in": { + "type": "video_url", + "video_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_video" + ] + } + } + } + }, + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.audios" + } + }, + "as": "media", + "in": { + "type": "audio_url", + "audio_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_audio" + ] + } + } + } + } + ] + }, + "ratio": { + "$coalesce": [ + { + "$ref": "request.aspectRatio" + }, + "16:9" + ] + }, + "resolution": { + "$coalesce": [ + { + "$ref": "request.resolution" + }, + "720p" + ] + }, + "duration": { + "$if": { + "condition": { + "$gt": [ + { + "$ref": "request.duration" + }, + 0 + ] + }, + "then": { + "$ref": "request.duration" + }, + "else": 5 + } + }, + "generate_audio": { + "$ref": "request.generateAudio" + }, + "watermark": { + "$ref": "request.watermark" + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-video.seed" + } + }, + "camera_fixed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-video.camera_fixed" + } + } + } + }, + "poll": { + "method": "GET", + "path": "/api/plan/v3/contents/generations/tasks/{{taskId}}" + }, + "cancel": { + "method": "DELETE", + "path": "/api/plan/v3/contents/generations/tasks/{{taskId}}" + }, + "response": { + "taskId": { + "$coalesce": [ + { + "$ref": "response.id" + }, + { + "$ref": "response.task_id" + }, + { + "$ref": "response.data.id" + }, + { + "$ref": "taskId" + } + ] + }, + "status": { + "$coalesce": [ + { + "$ref": "response.status" + }, + { + "$ref": "response.data.status" + }, + "pending" + ] + }, + "message": { + "$coalesce": [ + { + "$ref": "response.error.message" + }, + { + "$ref": "response.message" + }, + { + "$ref": "response.fail_reason" + } + ] + }, + "videos": { + "$coalesce": [ + { + "$ref": "response.content.video_url" + }, + { + "$ref": "response.video_url" + }, + { + "$ref": "response.output.video_url" + }, + { + "$ref": "response.data.video_url" + } + ] + }, + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "resultEphemeral": true + } + } + ] + } +} diff --git a/plugin-packages/volcengine-ark-agent-plan-seedream.yingce-plugin b/plugin-packages/volcengine-ark-agent-plan-seedream.yingce-plugin new file mode 100644 index 0000000000000000000000000000000000000000..9c6c95b3614a2e1f2d0821e01676b391aeba3b93 GIT binary patch literal 8614 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 literal 0 HcmV?d00001 diff --git a/plugin-packages/volcengine-ark-agent-plan-seedream/README.md b/plugin-packages/volcengine-ark-agent-plan-seedream/README.md new file mode 100644 index 000000000..8d6f789c6 --- /dev/null +++ b/plugin-packages/volcengine-ark-agent-plan-seedream/README.md @@ -0,0 +1,5 @@ +# Volcengine Ark Agent Plan Seedream Images + +该目录是独立官方协议插件源码。后端从生成的 `volcengine-ark-agent-plan-seedream.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。 + +完整接口见 [docs/interface.md](docs/interface.md)。 diff --git a/plugin-packages/volcengine-ark-agent-plan-seedream/docs/interface.md b/plugin-packages/volcengine-ark-agent-plan-seedream/docs/interface.md new file mode 100644 index 000000000..c207d9653 --- /dev/null +++ b/plugin-packages/volcengine-ark-agent-plan-seedream/docs/interface.md @@ -0,0 +1,418 @@ +# Volcengine Ark Agent Plan Seedream Images 接口字段 + +## 协议身份 + +- 插件 ID:`volcengine-ark-agent-plan-seedream`。 +- Provider ID:`volcengine-ark-agent-plan-image`。 +- 能力:`image`。 +- 默认 Base URL:`https://ark.cn-beijing.volces.com`。 +- 鉴权驱动:`bearer`。 +- 创建:`POST /api/plan/v3/images/generations`。 +- 生命周期:同步响应。 + +## 配置字段 + +| 字段 | 类型 | 必填 | 含义 | +| --- | --- | --- | --- | +| `apiKey` | secret | 是 | API Key | + +## 统一字段映射 + +| 统一字段 | 类型 | 必填 | 上游映射 | 说明 | +| --- | --- | --- | --- | --- | +| `model` | string | 是 | `model` | 图片模型 ID。 | +| `prompt` | string | 是 | `prompt` | 图片提示词。 | +| `images` | media[] | 否 | `provider image/reference fields` | 参考图或编辑源图,role 由业务层确定。 | +| `imageCount` | integer | 否 | `n/sample_count` | 输出数量。 | +| `aspectRatio` | string | 否 | `size/aspect_ratio` | 比例或尺寸,语义按协议说明。 | +| `resolution` | string | 否 | `resolution/imageSize` | 分辨率档位。 | +| `quality` | string | 否 | `quality` | 质量档位。 | +| `providerOptions` | object | 否 | `provider-specific fields` | 插件命名空间内的厂商扩展字段。 | + +## 上游请求模板逐字段清单 + +下表由插件请求模板生成,覆盖 body、query、headers 和 multipart 文件声明中的每个字段。 + +| 上游位置 | 值或转换表达式 | +| --- | --- | +| `create.method` | `"POST"` | +| `create.path` | `"/api/plan/v3/images/generations"` | +| `create.contentType` | `"application/json"` | +| `create.body.model` | `{"$ref":"request.model"}` | +| `create.body.prompt` | `{"$ref":"request.prompt"}` | +| `create.body.size` | `{"$omitEmpty":{"$switch":{"cases":[{"when":{"$eq":[{"$ref":"request.aspectRatio"},"auto"]},"then":"2k"},{"when":{"$eq":[{"$ref":"request.aspectRatio"},"1:1"]},"then":"2048x2048"},{"when":{"$eq":[{"$ref":"request.aspectRatio"},"4:3"]},"then":"2304x1728"},{"when":{"$eq":[{"$ref":"request.aspectRatio"},"3:4"]},"then":"1728x2304"},{"when":{"$eq":[{"$ref":"request.aspectRatio"},"16:9"]},"then":"2560x1440"},{"when":{"$eq":[{"$ref":"request.aspectRatio"},"9:16"]},"then":"1440x2560"},{"when":{"$eq":[{"$ref":"request.aspectRatio"},"3:2"]},"then":"2496x1664"},{"when":{"$eq":[{"$ref":"request.aspectRatio"},"2:3"]},"then":"1664x2496"},{"when":{"$eq":[{"$ref":"request.aspectRatio"},"21:9"]},"then":"3024x1296"}],"default":{"$ref":"request.aspectRatio"}}}}` | +| `create.body.image` | `{"$omitEmpty":{"$if":{"condition":{"$eq":[{"$len":{"$ref":"request.images"}},1]},"then":{"$first":{"$map":{"from":{"$ref":"request.images"},"as":"media","in":{"$ref":"media.value"}}}},"else":{"$if":{"condition":{"$gt":[{"$len":{"$ref":"request.images"}},1]},"then":{"$map":{"from":{"$ref":"request.images"},"as":"media","in":{"$ref":"media.value"}}},"else":null}}}}}` | +| `create.body.sequential_image_generation` | `{"$omitEmpty":{"$ref":"request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation"}}` | +| `create.body.sequential_image_generation_options` | `{"$omitEmpty":{"$ref":"request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation_options"}}` | +| `create.body.watermark` | `{"$coalesce":[{"$ref":"request.providerOptions.volcengine-ark-agent-plan-image.watermark"},{"$ref":"request.watermark"},false]}` | +| `create.body.seed` | `{"$omitEmpty":{"$ref":"request.providerOptions.volcengine-ark-agent-plan-image.seed"}}` | +| `create.body.response_format` | `{"$coalesce":[{"$ref":"request.providerOptions.volcengine-ark-agent-plan-image.response_format"},"b64_json"]}` | + +## Provider 扩展键 + +- `providerOptions.volcengine-ark-agent-plan-image.response_format` +- `providerOptions.volcengine-ark-agent-plan-image.seed` +- `providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation` +- `providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation_options` +- `providerOptions.volcengine-ark-agent-plan-image.watermark` + +动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。 + +## 响应映射逐字段清单 + +| 映射位置 | 上游路径或转换表达式 | +| --- | --- | +| `response.status` | `"succeeded"` | +| `response.images` | `{"$ref":"response.data"}` | +| `response.usage` | `{"$ref":"response.usage"}` | +| `response.errorPaths[0]` | `"error.code"` | +| `response.messagePaths[0]` | `"error.message"` | + +## 响应与错误 + +插件把上游 task/status/text/media/usage 映射为统一结果。临时媒体 URL 标记为 ephemeral,由宿主立即下载持久化。HTTP 错误、业务 code 和 error object 保持失败语义,不包装成成功。 + +## 兼容边界 + +Agent Plan 专属接入:请求路径为 /api/plan/v3/images/generations,必须使用 Agent Plan 控制台专属 API Key;请求体与官方 Seedream 协议一致,但凭证与额度按 AFP 套餐结算,不能与 /api/v3 官方 Key 混用。 + + +## Manifest 完整接口定义 + +以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。 + +```json +{ + "apiVersion": "yingce.plugin/v2", + "id": "volcengine-ark-agent-plan-seedream", + "name": "Volcengine Ark Agent Plan Seedream Images", + "version": "2.0.0", + "author": "Volcengine / 影策", + "description": "Volcengine Ark Agent Plan Seedream Images 独立请求协议插件。", + "documentation": "<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "volcengine-ark-agent-plan-image", + "label": "Volcengine Ark Agent Plan Seedream Images", + "capabilities": [ + "image" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://ark.cn-beijing.volces.com", + "requiresPublicMediaUrls": false, + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "图片模型 ID。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "prompt", + "description": "图片提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "provider image/reference fields", + "description": "参考图或编辑源图,role 由业务层确定。" + }, + { + "name": "imageCount", + "type": "integer", + "required": false, + "mapping": "n/sample_count", + "description": "输出数量。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "size/aspect_ratio", + "description": "比例或尺寸,语义按协议说明。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution/imageSize", + "description": "分辨率档位。" + }, + { + "name": "quality", + "type": "string", + "required": false, + "mapping": "quality", + "description": "质量档位。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } + ], + "create": { + "method": "POST", + "path": "/api/plan/v3/images/generations", + "contentType": "application/json", + "body": { + "model": { + "$ref": "request.model" + }, + "prompt": { + "$ref": "request.prompt" + }, + "size": { + "$omitEmpty": { + "$switch": { + "cases": [ + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "auto" + ] + }, + "then": "2k" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "1:1" + ] + }, + "then": "2048x2048" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "4:3" + ] + }, + "then": "2304x1728" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "3:4" + ] + }, + "then": "1728x2304" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "16:9" + ] + }, + "then": "2560x1440" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "9:16" + ] + }, + "then": "1440x2560" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "3:2" + ] + }, + "then": "2496x1664" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "2:3" + ] + }, + "then": "1664x2496" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "21:9" + ] + }, + "then": "3024x1296" + } + ], + "default": { + "$ref": "request.aspectRatio" + } + } + } + }, + "image": { + "$omitEmpty": { + "$if": { + "condition": { + "$eq": [ + { + "$len": { + "$ref": "request.images" + } + }, + 1 + ] + }, + "then": { + "$first": { + "$map": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "in": { + "$ref": "media.value" + } + } + } + }, + "else": { + "$if": { + "condition": { + "$gt": [ + { + "$len": { + "$ref": "request.images" + } + }, + 1 + ] + }, + "then": { + "$map": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "in": { + "$ref": "media.value" + } + } + }, + "else": null + } + } + } + } + }, + "sequential_image_generation": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation" + } + }, + "sequential_image_generation_options": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation_options" + } + }, + "watermark": { + "$coalesce": [ + { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.watermark" + }, + { + "$ref": "request.watermark" + }, + false + ] + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.seed" + } + }, + "response_format": { + "$coalesce": [ + { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.response_format" + }, + "b64_json" + ] + } + } + }, + "response": { + "status": "succeeded", + "images": { + "$ref": "response.data" + }, + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "messagePaths": [ + "error.message" + ] + } + } + ] + } +} +``` + diff --git a/plugin-packages/volcengine-ark-agent-plan-seedream/manifest.json b/plugin-packages/volcengine-ark-agent-plan-seedream/manifest.json new file mode 100644 index 000000000..3626d36a0 --- /dev/null +++ b/plugin-packages/volcengine-ark-agent-plan-seedream/manifest.json @@ -0,0 +1,332 @@ +{ + "apiVersion": "yingce.plugin/v2", + "id": "volcengine-ark-agent-plan-seedream", + "name": "Volcengine Ark Agent Plan Seedream Images", + "version": "2.0.0", + "author": "Volcengine / 影策", + "description": "Volcengine Ark Agent Plan Seedream Images 独立请求协议插件。", + "documentation": "# Volcengine Ark Agent Plan Seedream Images\n\n该目录是独立官方协议插件源码。后端从生成的 `volcengine-ark-agent-plan-seedream.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# Volcengine Ark Agent Plan Seedream Images 接口字段\n\n## 协议身份\n\n- 插件 ID:`volcengine-ark-agent-plan-seedream`。\n- Provider ID:`volcengine-ark-agent-plan-image`。\n- 能力:`image`。\n- 默认 Base URL:`https://ark.cn-beijing.volces.com`。\n- 鉴权驱动:`bearer`。\n- 创建:`POST /api/plan/v3/images/generations`。\n- 生命周期:同步响应。\n\n## 配置字段\n\n| 字段 | 类型 | 必填 | 含义 |\n| --- | --- | --- | --- |\n| `apiKey` | secret | 是 | API Key |\n\n## 统一字段映射\n\n| 统一字段 | 类型 | 必填 | 上游映射 | 说明 |\n| --- | --- | --- | --- | --- |\n| `model` | string | 是 | `model` | 图片模型 ID。 |\n| `prompt` | string | 是 | `prompt` | 图片提示词。 |\n| `images` | media[] | 否 | `provider image/reference fields` | 参考图或编辑源图,role 由业务层确定。 |\n| `imageCount` | integer | 否 | `n/sample_count` | 输出数量。 |\n| `aspectRatio` | string | 否 | `size/aspect_ratio` | 比例或尺寸,语义按协议说明。 |\n| `resolution` | string | 否 | `resolution/imageSize` | 分辨率档位。 |\n| `quality` | string | 否 | `quality` | 质量档位。 |\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/plan/v3/images/generations\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.prompt` | `{\"$ref\":\"request.prompt\"}` |\n| `create.body.size` | `{\"$omitEmpty\":{\"$switch\":{\"cases\":[{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"auto\"]},\"then\":\"2k\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"1:1\"]},\"then\":\"2048x2048\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"4:3\"]},\"then\":\"2304x1728\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"3:4\"]},\"then\":\"1728x2304\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"16:9\"]},\"then\":\"2560x1440\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"9:16\"]},\"then\":\"1440x2560\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"3:2\"]},\"then\":\"2496x1664\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"2:3\"]},\"then\":\"1664x2496\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"21:9\"]},\"then\":\"3024x1296\"}],\"default\":{\"$ref\":\"request.aspectRatio\"}}}}` |\n| `create.body.image` | `{\"$omitEmpty\":{\"$if\":{\"condition\":{\"$eq\":[{\"$len\":{\"$ref\":\"request.images\"}},1]},\"then\":{\"$first\":{\"$map\":{\"from\":{\"$ref\":\"request.images\"},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}}},\"else\":{\"$if\":{\"condition\":{\"$gt\":[{\"$len\":{\"$ref\":\"request.images\"}},1]},\"then\":{\"$map\":{\"from\":{\"$ref\":\"request.images\"},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}},\"else\":null}}}}}` |\n| `create.body.sequential_image_generation` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation\"}}` |\n| `create.body.sequential_image_generation_options` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation_options\"}}` |\n| `create.body.watermark` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.volcengine-ark-agent-plan-image.watermark\"},{\"$ref\":\"request.watermark\"},false]}` |\n| `create.body.seed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-agent-plan-image.seed\"}}` |\n| `create.body.response_format` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.volcengine-ark-agent-plan-image.response_format\"},\"b64_json\"]}` |\n\n## Provider 扩展键\n\n- `providerOptions.volcengine-ark-agent-plan-image.response_format`\n- `providerOptions.volcengine-ark-agent-plan-image.seed`\n- `providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation`\n- `providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation_options`\n- `providerOptions.volcengine-ark-agent-plan-image.watermark`\n\n动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。\n\n## 响应映射逐字段清单\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.status` | `\"succeeded\"` |\n| `response.images` | `{\"$ref\":\"response.data\"}` |\n| `response.usage` | `{\"$ref\":\"response.usage\"}` |\n| `response.errorPaths[0]` | `\"error.code\"` |\n| `response.messagePaths[0]` | `\"error.message\"` |\n\n## 响应与错误\n\n插件把上游 task/status/text/media/usage 映射为统一结果。临时媒体 URL 标记为 ephemeral,由宿主立即下载持久化。HTTP 错误、业务 code 和 error object 保持失败语义,不包装成成功。\n\n## 兼容边界\n\nAgent Plan 专属接入:请求路径为 /api/plan/v3/images/generations,必须使用 Agent Plan 控制台专属 API Key;请求体与官方 Seedream 协议一致,但凭证与额度按 AFP 套餐结算,不能与 /api/v3 官方 Key 混用。\n\n\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"volcengine-ark-agent-plan-seedream\",\n \"name\": \"Volcengine Ark Agent Plan Seedream Images\",\n \"version\": \"2.0.0\",\n \"author\": \"Volcengine / 影策\",\n \"description\": \"Volcengine Ark Agent Plan Seedream Images 独立请求协议插件。\",\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\": \"volcengine-ark-agent-plan-image\",\n \"label\": \"Volcengine Ark Agent Plan Seedream Images\",\n \"capabilities\": [\n \"image\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"https://ark.cn-beijing.volces.com\",\n \"requiresPublicMediaUrls\": false,\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\",\n \"description\": \"图片提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"provider image/reference fields\",\n \"description\": \"参考图或编辑源图,role 由业务层确定。\"\n },\n {\n \"name\": \"imageCount\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"n/sample_count\",\n \"description\": \"输出数量。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"size/aspect_ratio\",\n \"description\": \"比例或尺寸,语义按协议说明。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution/imageSize\",\n \"description\": \"分辨率档位。\"\n },\n {\n \"name\": \"quality\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"quality\",\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\": \"/api/plan/v3/images/generations\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"prompt\": {\n \"$ref\": \"request.prompt\"\n },\n \"size\": {\n \"$omitEmpty\": {\n \"$switch\": {\n \"cases\": [\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"auto\"\n ]\n },\n \"then\": \"2k\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"1:1\"\n ]\n },\n \"then\": \"2048x2048\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"4:3\"\n ]\n },\n \"then\": \"2304x1728\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"3:4\"\n ]\n },\n \"then\": \"1728x2304\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"16:9\"\n ]\n },\n \"then\": \"2560x1440\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"9:16\"\n ]\n },\n \"then\": \"1440x2560\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"3:2\"\n ]\n },\n \"then\": \"2496x1664\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"2:3\"\n ]\n },\n \"then\": \"1664x2496\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"21:9\"\n ]\n },\n \"then\": \"3024x1296\"\n }\n ],\n \"default\": {\n \"$ref\": \"request.aspectRatio\"\n }\n }\n }\n },\n \"image\": {\n \"$omitEmpty\": {\n \"$if\": {\n \"condition\": {\n \"$eq\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 1\n ]\n },\n \"then\": {\n \"$first\": {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n },\n \"else\": {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 1\n ]\n },\n \"then\": {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n },\n \"else\": null\n }\n }\n }\n }\n },\n \"sequential_image_generation\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation\"\n }\n },\n \"sequential_image_generation_options\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation_options\"\n }\n },\n \"watermark\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.providerOptions.volcengine-ark-agent-plan-image.watermark\"\n },\n {\n \"$ref\": \"request.watermark\"\n },\n false\n ]\n },\n \"seed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-agent-plan-image.seed\"\n }\n },\n \"response_format\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.providerOptions.volcengine-ark-agent-plan-image.response_format\"\n },\n \"b64_json\"\n ]\n }\n }\n },\n \"response\": {\n \"status\": \"succeeded\",\n \"images\": {\n \"$ref\": \"response.data\"\n },\n \"usage\": {\n \"$ref\": \"response.usage\"\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"messagePaths\": [\n \"error.message\"\n ]\n }\n }\n ]\n }\n}\n```\n\n", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "volcengine-ark-agent-plan-image", + "label": "Volcengine Ark Agent Plan Seedream Images", + "capabilities": [ + "image" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://ark.cn-beijing.volces.com", + "requiresPublicMediaUrls": false, + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "图片模型 ID。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "prompt", + "description": "图片提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "provider image/reference fields", + "description": "参考图或编辑源图,role 由业务层确定。" + }, + { + "name": "imageCount", + "type": "integer", + "required": false, + "mapping": "n/sample_count", + "description": "输出数量。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "size/aspect_ratio", + "description": "比例或尺寸,语义按协议说明。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution/imageSize", + "description": "分辨率档位。" + }, + { + "name": "quality", + "type": "string", + "required": false, + "mapping": "quality", + "description": "质量档位。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } + ], + "create": { + "method": "POST", + "path": "/api/plan/v3/images/generations", + "contentType": "application/json", + "body": { + "model": { + "$ref": "request.model" + }, + "prompt": { + "$ref": "request.prompt" + }, + "size": { + "$omitEmpty": { + "$switch": { + "cases": [ + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "auto" + ] + }, + "then": "2k" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "1:1" + ] + }, + "then": "2048x2048" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "4:3" + ] + }, + "then": "2304x1728" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "3:4" + ] + }, + "then": "1728x2304" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "16:9" + ] + }, + "then": "2560x1440" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "9:16" + ] + }, + "then": "1440x2560" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "3:2" + ] + }, + "then": "2496x1664" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "2:3" + ] + }, + "then": "1664x2496" + }, + { + "when": { + "$eq": [ + { + "$ref": "request.aspectRatio" + }, + "21:9" + ] + }, + "then": "3024x1296" + } + ], + "default": { + "$ref": "request.aspectRatio" + } + } + } + }, + "image": { + "$omitEmpty": { + "$if": { + "condition": { + "$eq": [ + { + "$len": { + "$ref": "request.images" + } + }, + 1 + ] + }, + "then": { + "$first": { + "$map": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "in": { + "$ref": "media.value" + } + } + } + }, + "else": { + "$if": { + "condition": { + "$gt": [ + { + "$len": { + "$ref": "request.images" + } + }, + 1 + ] + }, + "then": { + "$map": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "in": { + "$ref": "media.value" + } + } + }, + "else": null + } + } + } + } + }, + "sequential_image_generation": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation" + } + }, + "sequential_image_generation_options": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.sequential_image_generation_options" + } + }, + "watermark": { + "$coalesce": [ + { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.watermark" + }, + { + "$ref": "request.watermark" + }, + false + ] + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.seed" + } + }, + "response_format": { + "$coalesce": [ + { + "$ref": "request.providerOptions.volcengine-ark-agent-plan-image.response_format" + }, + "b64_json" + ] + } + } + }, + "response": { + "status": "succeeded", + "images": { + "$ref": "response.data" + }, + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "messagePaths": [ + "error.message" + ] + } + } + ] + } +} diff --git a/plugin-packages/volcengine-ark-seedance.yingce-plugin b/plugin-packages/volcengine-ark-seedance.yingce-plugin index 9d0700c14b1c179c7a9bab28c2f3b5c7baacffb5..f95dc8a1dc30b5e999f62ce8559b0f427420e9c0 100644 GIT binary patch literal 9473 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 O?7vgzT!Om=XK)Md?k=0Jw(9Nf+ugd= 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 diff --git a/plugin-packages/volcengine-ark-seedance/README.md b/plugin-packages/volcengine-ark-seedance/README.md new file mode 100644 index 000000000..859054a7d --- /dev/null +++ b/plugin-packages/volcengine-ark-seedance/README.md @@ -0,0 +1,5 @@ +# Volcengine Ark Seedance + +该目录是独立官方协议插件源码。后端从生成的 `volcengine-ark-seedance.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。 + +完整接口见 [docs/interface.md](docs/interface.md)。 diff --git a/plugin-packages/volcengine-ark-seedance/docs/interface.md b/plugin-packages/volcengine-ark-seedance/docs/interface.md new file mode 100644 index 000000000..c71a76aba --- /dev/null +++ b/plugin-packages/volcengine-ark-seedance/docs/interface.md @@ -0,0 +1,527 @@ +# Volcengine Ark Seedance 接口字段 + +## 协议身份 + +- 插件 ID:`volcengine-ark-seedance`。 +- Provider ID:`volcengine-ark-video`。 +- 能力:`video`。 +- 默认 Base URL:`https://ark.cn-beijing.volces.com`。 +- 鉴权驱动:`bearer`。 +- 创建:`POST /api/v3/contents/generations/tasks`。 +- 查询:`GET /api/v3/contents/generations/tasks/{{taskId}}`。 +- 取消:`DELETE /api/v3/contents/generations/tasks/{{taskId}}`。 + +## 配置字段 + +| 字段 | 类型 | 必填 | 含义 | +| --- | --- | --- | --- | +| `apiKey` | secret | 是 | API Key | + +## 统一字段映射 + +| 统一字段 | 类型 | 必填 | 上游映射 | 说明 | +| --- | --- | --- | --- | --- | +| `model` | string | 是 | `model` | Ark endpoint/model ID。 | +| `prompt` | string | 是 | `content[type=text].text` | 视频提示词。 | +| `images` | media[] | 否 | `content[type=image_url]` | first_frame、last_frame、reference_image 等 role 原样映射。 | +| `videos` | media[] | 否 | `content[type=video_url]` | reference_video。 | +| `audios` | media[] | 否 | `content[type=audio_url]` | reference_audio/reference_voice。 | +| `aspectRatio` | string | 否 | `ratio` | 输出画幅。 | +| `resolution` | string | 否 | `resolution` | 输出分辨率档位。 | +| `duration` | integer | 否 | `duration` | 输出时长秒数。 | +| `generateAudio` | boolean | 否 | `generate_audio` | 是否生成音频。 | +| `watermark` | boolean | 否 | `watermark` | 是否带水印。 | +| `seed` | integer | 否 | `seed` | providerOptions seed。 | +| `camera_fixed` | boolean | 否 | `camera_fixed` | providerOptions camera_fixed。 | + +## 上游请求模板逐字段清单 + +下表由插件请求模板生成,覆盖 body、query、headers 和 multipart 文件声明中的每个字段。 + +| 上游位置 | 值或转换表达式 | +| --- | --- | +| `create.method` | `"POST"` | +| `create.path` | `"/api/v3/contents/generations/tasks"` | +| `create.contentType` | `"application/json"` | +| `create.body.model` | `{"$ref":"request.model"}` | +| `create.body.content` | `{"$concatArrays":[[{"type":"text","text":{"$ref":"request.prompt"}}],{"$map":{"from":{"$sortByOrder":{"$ref":"request.images"}},"as":"media","in":{"type":"image_url","image_url":{"url":{"$ref":"media.value"}},"role":{"$coalesce":[{"$ref":"media.role"},"reference_image"]}}}},{"$map":{"from":{"$sortByOrder":{"$ref":"request.videos"}},"as":"media","in":{"type":"video_url","video_url":{"url":{"$ref":"media.value"}},"role":{"$coalesce":[{"$ref":"media.role"},"reference_video"]}}}},{"$map":{"from":{"$sortByOrder":{"$ref":"request.audios"}},"as":"media","in":{"type":"audio_url","audio_url":{"url":{"$ref":"media.value"}},"role":{"$coalesce":[{"$ref":"media.role"},"reference_audio"]}}}}]}` | +| `create.body.ratio` | `{"$coalesce":[{"$ref":"request.aspectRatio"},"16:9"]}` | +| `create.body.resolution` | `{"$coalesce":[{"$ref":"request.resolution"},"720p"]}` | +| `create.body.duration` | `{"$if":{"condition":{"$gt":[{"$ref":"request.duration"},0]},"then":{"$ref":"request.duration"},"else":5}}` | +| `create.body.generate_audio` | `{"$ref":"request.generateAudio"}` | +| `create.body.watermark` | `{"$ref":"request.watermark"}` | +| `create.body.seed` | `{"$omitEmpty":{"$ref":"request.providerOptions.volcengine-ark-video.seed"}}` | +| `create.body.camera_fixed` | `{"$omitEmpty":{"$ref":"request.providerOptions.volcengine-ark-video.camera_fixed"}}` | +| `poll.method` | `"GET"` | +| `poll.path` | `"/api/v3/contents/generations/tasks/{{taskId}}"` | +| `poll.contentType` | `"application/json"` | +| `cancel.method` | `"DELETE"` | +| `cancel.path` | `"/api/v3/contents/generations/tasks/{{taskId}}"` | +| `cancel.contentType` | `"application/json"` | + +## Provider 扩展键 + +- `providerOptions.volcengine-ark-video.camera_fixed` +- `providerOptions.volcengine-ark-video.seed` + +动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。 + +## 响应映射逐字段清单 + +| 映射位置 | 上游路径或转换表达式 | +| --- | --- | +| `response.taskId` | `{"$coalesce":[{"$ref":"response.id"},{"$ref":"response.task_id"},{"$ref":"response.data.id"},{"$ref":"taskId"}]}` | +| `response.status` | `{"$coalesce":[{"$ref":"response.status"},{"$ref":"response.data.status"},"pending"]}` | +| `response.message` | `{"$coalesce":[{"$ref":"response.error.message"},{"$ref":"response.message"},{"$ref":"response.fail_reason"}]}` | +| `response.videos` | `{"$coalesce":[{"$ref":"response.content.video_url"},{"$ref":"response.video_url"},{"$ref":"response.output.video_url"},{"$ref":"response.data.video_url"}]}` | +| `response.usage` | `{"$ref":"response.usage"}` | +| `response.errorPaths[0]` | `"error.code"` | +| `response.resultEphemeral` | `true` | + +## 响应与错误 + +插件把上游 task/status/text/media/usage 映射为统一结果。临时媒体 URL 标记为 ephemeral,由宿主立即下载持久化。HTTP 错误、业务 code 和 error object 保持失败语义,不包装成成功。 + +## 兼容边界 + +官方 Ark 推理接入:创建/查询/取消走 /api/v3/contents/generations/tasks;插件不根据图片下标推断首尾帧,role 由业务层确定。API Key 来自方舟推理接入控制台。 + + +## Manifest 完整接口定义 + +以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。 + +```json +{ + "apiVersion": "yingce.plugin/v2", + "id": "volcengine-ark-seedance", + "name": "Volcengine Ark Seedance", + "version": "2.0.0", + "author": "Volcengine / 影策", + "description": "Volcengine Ark Seedance 独立请求协议插件。", + "documentation": "<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "volcengine-ark-video", + "label": "Volcengine Ark Seedance", + "capabilities": [ + "video" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://ark.cn-beijing.volces.com", + "requiresPublicMediaUrls": true, + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "Ark endpoint/model ID。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "content[type=text].text", + "description": "视频提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "content[type=image_url]", + "description": "first_frame、last_frame、reference_image 等 role 原样映射。" + }, + { + "name": "videos", + "type": "media[]", + "required": false, + "mapping": "content[type=video_url]", + "description": "reference_video。" + }, + { + "name": "audios", + "type": "media[]", + "required": false, + "mapping": "content[type=audio_url]", + "description": "reference_audio/reference_voice。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "ratio", + "description": "输出画幅。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution", + "description": "输出分辨率档位。" + }, + { + "name": "duration", + "type": "integer", + "required": false, + "mapping": "duration", + "description": "输出时长秒数。" + }, + { + "name": "generateAudio", + "type": "boolean", + "required": false, + "mapping": "generate_audio", + "description": "是否生成音频。" + }, + { + "name": "watermark", + "type": "boolean", + "required": false, + "mapping": "watermark", + "description": "是否带水印。" + }, + { + "name": "seed", + "type": "integer", + "required": false, + "mapping": "seed", + "description": "providerOptions seed。" + }, + { + "name": "camera_fixed", + "type": "boolean", + "required": false, + "mapping": "camera_fixed", + "description": "providerOptions camera_fixed。" + } + ], + "validations": [ + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.images" + } + }, + 9 + ] + }, + "message": "Seedance 最多支持 9 张参考图片" + }, + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.videos" + } + }, + 3 + ] + }, + "message": "Seedance 最多支持 3 个参考视频" + }, + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.audios" + } + }, + 3 + ] + }, + "message": "Seedance 最多支持 3 个参考音频" + }, + { + "assert": { + "$or": [ + { + "$eq": [ + { + "$len": { + "$ref": "request.audios" + } + }, + 0 + ] + }, + { + "$gt": [ + { + "$add": [ + { + "$len": { + "$ref": "request.images" + } + }, + { + "$len": { + "$ref": "request.videos" + } + } + ] + }, + 0 + ] + } + ] + }, + "message": "Seedance 不支持纯音频或文本+音频,请同时添加参考图片或参考视频" + } + ], + "create": { + "method": "POST", + "path": "/api/v3/contents/generations/tasks", + "contentType": "application/json", + "body": { + "model": { + "$ref": "request.model" + }, + "content": { + "$concatArrays": [ + [ + { + "type": "text", + "text": { + "$ref": "request.prompt" + } + } + ], + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.images" + } + }, + "as": "media", + "in": { + "type": "image_url", + "image_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_image" + ] + } + } + } + }, + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.videos" + } + }, + "as": "media", + "in": { + "type": "video_url", + "video_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_video" + ] + } + } + } + }, + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.audios" + } + }, + "as": "media", + "in": { + "type": "audio_url", + "audio_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_audio" + ] + } + } + } + } + ] + }, + "ratio": { + "$coalesce": [ + { + "$ref": "request.aspectRatio" + }, + "16:9" + ] + }, + "resolution": { + "$coalesce": [ + { + "$ref": "request.resolution" + }, + "720p" + ] + }, + "duration": { + "$if": { + "condition": { + "$gt": [ + { + "$ref": "request.duration" + }, + 0 + ] + }, + "then": { + "$ref": "request.duration" + }, + "else": 5 + } + }, + "generate_audio": { + "$ref": "request.generateAudio" + }, + "watermark": { + "$ref": "request.watermark" + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-video.seed" + } + }, + "camera_fixed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-video.camera_fixed" + } + } + } + }, + "poll": { + "method": "GET", + "path": "/api/v3/contents/generations/tasks/{{taskId}}" + }, + "cancel": { + "method": "DELETE", + "path": "/api/v3/contents/generations/tasks/{{taskId}}" + }, + "response": { + "taskId": { + "$coalesce": [ + { + "$ref": "response.id" + }, + { + "$ref": "response.task_id" + }, + { + "$ref": "response.data.id" + }, + { + "$ref": "taskId" + } + ] + }, + "status": { + "$coalesce": [ + { + "$ref": "response.status" + }, + { + "$ref": "response.data.status" + }, + "pending" + ] + }, + "message": { + "$coalesce": [ + { + "$ref": "response.error.message" + }, + { + "$ref": "response.message" + }, + { + "$ref": "response.fail_reason" + } + ] + }, + "videos": { + "$coalesce": [ + { + "$ref": "response.content.video_url" + }, + { + "$ref": "response.video_url" + }, + { + "$ref": "response.output.video_url" + }, + { + "$ref": "response.data.video_url" + } + ] + }, + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "resultEphemeral": true + } + } + ] + } +} +``` + diff --git a/plugin-packages/volcengine-ark-seedance/manifest.json b/plugin-packages/volcengine-ark-seedance/manifest.json new file mode 100644 index 000000000..facb8c063 --- /dev/null +++ b/plugin-packages/volcengine-ark-seedance/manifest.json @@ -0,0 +1,431 @@ +{ + "apiVersion": "yingce.plugin/v2", + "id": "volcengine-ark-seedance", + "name": "Volcengine Ark Seedance", + "version": "2.0.0", + "author": "Volcengine / 影策", + "description": "Volcengine Ark Seedance 独立请求协议插件。", + "documentation": "# Volcengine Ark Seedance\n\n该目录是独立官方协议插件源码。后端从生成的 `volcengine-ark-seedance.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# Volcengine Ark Seedance 接口字段\n\n## 协议身份\n\n- 插件 ID:`volcengine-ark-seedance`。\n- Provider ID:`volcengine-ark-video`。\n- 能力:`video`。\n- 默认 Base URL:`https://ark.cn-beijing.volces.com`。\n- 鉴权驱动:`bearer`。\n- 创建:`POST /api/v3/contents/generations/tasks`。\n- 查询:`GET /api/v3/contents/generations/tasks/{{taskId}}`。\n- 取消:`DELETE /api/v3/contents/generations/tasks/{{taskId}}`。\n\n## 配置字段\n\n| 字段 | 类型 | 必填 | 含义 |\n| --- | --- | --- | --- |\n| `apiKey` | secret | 是 | API Key |\n\n## 统一字段映射\n\n| 统一字段 | 类型 | 必填 | 上游映射 | 说明 |\n| --- | --- | --- | --- | --- |\n| `model` | string | 是 | `model` | Ark endpoint/model ID。 |\n| `prompt` | string | 是 | `content[type=text].text` | 视频提示词。 |\n| `images` | media[] | 否 | `content[type=image_url]` | first_frame、last_frame、reference_image 等 role 原样映射。 |\n| `videos` | media[] | 否 | `content[type=video_url]` | reference_video。 |\n| `audios` | media[] | 否 | `content[type=audio_url]` | reference_audio/reference_voice。 |\n| `aspectRatio` | string | 否 | `ratio` | 输出画幅。 |\n| `resolution` | string | 否 | `resolution` | 输出分辨率档位。 |\n| `duration` | integer | 否 | `duration` | 输出时长秒数。 |\n| `generateAudio` | boolean | 否 | `generate_audio` | 是否生成音频。 |\n| `watermark` | boolean | 否 | `watermark` | 是否带水印。 |\n| `seed` | integer | 否 | `seed` | providerOptions seed。 |\n| `camera_fixed` | boolean | 否 | `camera_fixed` | providerOptions camera_fixed。 |\n\n## 上游请求模板逐字段清单\n\n下表由插件请求模板生成,覆盖 body、query、headers 和 multipart 文件声明中的每个字段。\n\n| 上游位置 | 值或转换表达式 |\n| --- | --- |\n| `create.method` | `\"POST\"` |\n| `create.path` | `\"/api/v3/contents/generations/tasks\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.content` | `{\"$concatArrays\":[[{\"type\":\"text\",\"text\":{\"$ref\":\"request.prompt\"}}],{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.images\"}},\"as\":\"media\",\"in\":{\"type\":\"image_url\",\"image_url\":{\"url\":{\"$ref\":\"media.value\"}},\"role\":{\"$coalesce\":[{\"$ref\":\"media.role\"},\"reference_image\"]}}}},{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.videos\"}},\"as\":\"media\",\"in\":{\"type\":\"video_url\",\"video_url\":{\"url\":{\"$ref\":\"media.value\"}},\"role\":{\"$coalesce\":[{\"$ref\":\"media.role\"},\"reference_video\"]}}}},{\"$map\":{\"from\":{\"$sortByOrder\":{\"$ref\":\"request.audios\"}},\"as\":\"media\",\"in\":{\"type\":\"audio_url\",\"audio_url\":{\"url\":{\"$ref\":\"media.value\"}},\"role\":{\"$coalesce\":[{\"$ref\":\"media.role\"},\"reference_audio\"]}}}}]}` |\n| `create.body.ratio` | `{\"$coalesce\":[{\"$ref\":\"request.aspectRatio\"},\"16:9\"]}` |\n| `create.body.resolution` | `{\"$coalesce\":[{\"$ref\":\"request.resolution\"},\"720p\"]}` |\n| `create.body.duration` | `{\"$if\":{\"condition\":{\"$gt\":[{\"$ref\":\"request.duration\"},0]},\"then\":{\"$ref\":\"request.duration\"},\"else\":5}}` |\n| `create.body.generate_audio` | `{\"$ref\":\"request.generateAudio\"}` |\n| `create.body.watermark` | `{\"$ref\":\"request.watermark\"}` |\n| `create.body.seed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-video.seed\"}}` |\n| `create.body.camera_fixed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-video.camera_fixed\"}}` |\n| `poll.method` | `\"GET\"` |\n| `poll.path` | `\"/api/v3/contents/generations/tasks/{{taskId}}\"` |\n| `poll.contentType` | `\"application/json\"` |\n| `cancel.method` | `\"DELETE\"` |\n| `cancel.path` | `\"/api/v3/contents/generations/tasks/{{taskId}}\"` |\n| `cancel.contentType` | `\"application/json\"` |\n\n## Provider 扩展键\n\n- `providerOptions.volcengine-ark-video.camera_fixed`\n- `providerOptions.volcengine-ark-video.seed`\n\n动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。\n\n## 响应映射逐字段清单\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.taskId` | `{\"$coalesce\":[{\"$ref\":\"response.id\"},{\"$ref\":\"response.task_id\"},{\"$ref\":\"response.data.id\"},{\"$ref\":\"taskId\"}]}` |\n| `response.status` | `{\"$coalesce\":[{\"$ref\":\"response.status\"},{\"$ref\":\"response.data.status\"},\"pending\"]}` |\n| `response.message` | `{\"$coalesce\":[{\"$ref\":\"response.error.message\"},{\"$ref\":\"response.message\"},{\"$ref\":\"response.fail_reason\"}]}` |\n| `response.videos` | `{\"$coalesce\":[{\"$ref\":\"response.content.video_url\"},{\"$ref\":\"response.video_url\"},{\"$ref\":\"response.output.video_url\"},{\"$ref\":\"response.data.video_url\"}]}` |\n| `response.usage` | `{\"$ref\":\"response.usage\"}` |\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官方 Ark 推理接入:创建/查询/取消走 /api/v3/contents/generations/tasks;插件不根据图片下标推断首尾帧,role 由业务层确定。API Key 来自方舟推理接入控制台。\n\n\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"volcengine-ark-seedance\",\n \"name\": \"Volcengine Ark Seedance\",\n \"version\": \"2.0.0\",\n \"author\": \"Volcengine / 影策\",\n \"description\": \"Volcengine Ark Seedance 独立请求协议插件。\",\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\": \"volcengine-ark-video\",\n \"label\": \"Volcengine Ark Seedance\",\n \"capabilities\": [\n \"video\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"https://ark.cn-beijing.volces.com\",\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\": \"Ark endpoint/model ID。\"\n },\n {\n \"name\": \"prompt\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"content[type=text].text\",\n \"description\": \"视频提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"content[type=image_url]\",\n \"description\": \"first_frame、last_frame、reference_image 等 role 原样映射。\"\n },\n {\n \"name\": \"videos\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"content[type=video_url]\",\n \"description\": \"reference_video。\"\n },\n {\n \"name\": \"audios\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"content[type=audio_url]\",\n \"description\": \"reference_audio/reference_voice。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"ratio\",\n \"description\": \"输出画幅。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution\",\n \"description\": \"输出分辨率档位。\"\n },\n {\n \"name\": \"duration\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"duration\",\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\": \"seed\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"seed\",\n \"description\": \"providerOptions seed。\"\n },\n {\n \"name\": \"camera_fixed\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"camera_fixed\",\n \"description\": \"providerOptions camera_fixed。\"\n }\n ],\n \"validations\": [\n {\n \"assert\": {\n \"$lte\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 9\n ]\n },\n \"message\": \"Seedance 最多支持 9 张参考图片\"\n },\n {\n \"assert\": {\n \"$lte\": [\n {\n \"$len\": {\n \"$ref\": \"request.videos\"\n }\n },\n 3\n ]\n },\n \"message\": \"Seedance 最多支持 3 个参考视频\"\n },\n {\n \"assert\": {\n \"$lte\": [\n {\n \"$len\": {\n \"$ref\": \"request.audios\"\n }\n },\n 3\n ]\n },\n \"message\": \"Seedance 最多支持 3 个参考音频\"\n },\n {\n \"assert\": {\n \"$or\": [\n {\n \"$eq\": [\n {\n \"$len\": {\n \"$ref\": \"request.audios\"\n }\n },\n 0\n ]\n },\n {\n \"$gt\": [\n {\n \"$add\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n {\n \"$len\": {\n \"$ref\": \"request.videos\"\n }\n }\n ]\n },\n 0\n ]\n }\n ]\n },\n \"message\": \"Seedance 不支持纯音频或文本+音频,请同时添加参考图片或参考视频\"\n }\n ],\n \"create\": {\n \"method\": \"POST\",\n \"path\": \"/api/v3/contents/generations/tasks\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"content\": {\n \"$concatArrays\": [\n [\n {\n \"type\": \"text\",\n \"text\": {\n \"$ref\": \"request.prompt\"\n }\n }\n ],\n {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.images\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"image_url\",\n \"image_url\": {\n \"url\": {\n \"$ref\": \"media.value\"\n }\n },\n \"role\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.role\"\n },\n \"reference_image\"\n ]\n }\n }\n }\n },\n {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.videos\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"video_url\",\n \"video_url\": {\n \"url\": {\n \"$ref\": \"media.value\"\n }\n },\n \"role\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.role\"\n },\n \"reference_video\"\n ]\n }\n }\n }\n },\n {\n \"$map\": {\n \"from\": {\n \"$sortByOrder\": {\n \"$ref\": \"request.audios\"\n }\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"audio_url\",\n \"audio_url\": {\n \"url\": {\n \"$ref\": \"media.value\"\n }\n },\n \"role\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.role\"\n },\n \"reference_audio\"\n ]\n }\n }\n }\n }\n ]\n },\n \"ratio\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"16:9\"\n ]\n },\n \"resolution\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.resolution\"\n },\n \"720p\"\n ]\n },\n \"duration\": {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$ref\": \"request.duration\"\n },\n 0\n ]\n },\n \"then\": {\n \"$ref\": \"request.duration\"\n },\n \"else\": 5\n }\n },\n \"generate_audio\": {\n \"$ref\": \"request.generateAudio\"\n },\n \"watermark\": {\n \"$ref\": \"request.watermark\"\n },\n \"seed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-video.seed\"\n }\n },\n \"camera_fixed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-video.camera_fixed\"\n }\n }\n }\n },\n \"poll\": {\n \"method\": \"GET\",\n \"path\": \"/api/v3/contents/generations/tasks/{{taskId}}\"\n },\n \"cancel\": {\n \"method\": \"DELETE\",\n \"path\": \"/api/v3/contents/generations/tasks/{{taskId}}\"\n },\n \"response\": {\n \"taskId\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.id\"\n },\n {\n \"$ref\": \"response.task_id\"\n },\n {\n \"$ref\": \"response.data.id\"\n },\n {\n \"$ref\": \"taskId\"\n }\n ]\n },\n \"status\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.status\"\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.content.video_url\"\n },\n {\n \"$ref\": \"response.video_url\"\n },\n {\n \"$ref\": \"response.output.video_url\"\n },\n {\n \"$ref\": \"response.data.video_url\"\n }\n ]\n },\n \"usage\": {\n \"$ref\": \"response.usage\"\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"resultEphemeral\": true\n }\n }\n ]\n }\n}\n```\n\n", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "volcengine-ark-video", + "label": "Volcengine Ark Seedance", + "capabilities": [ + "video" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://ark.cn-beijing.volces.com", + "requiresPublicMediaUrls": true, + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "Ark endpoint/model ID。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "content[type=text].text", + "description": "视频提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "content[type=image_url]", + "description": "first_frame、last_frame、reference_image 等 role 原样映射。" + }, + { + "name": "videos", + "type": "media[]", + "required": false, + "mapping": "content[type=video_url]", + "description": "reference_video。" + }, + { + "name": "audios", + "type": "media[]", + "required": false, + "mapping": "content[type=audio_url]", + "description": "reference_audio/reference_voice。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "ratio", + "description": "输出画幅。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution", + "description": "输出分辨率档位。" + }, + { + "name": "duration", + "type": "integer", + "required": false, + "mapping": "duration", + "description": "输出时长秒数。" + }, + { + "name": "generateAudio", + "type": "boolean", + "required": false, + "mapping": "generate_audio", + "description": "是否生成音频。" + }, + { + "name": "watermark", + "type": "boolean", + "required": false, + "mapping": "watermark", + "description": "是否带水印。" + }, + { + "name": "seed", + "type": "integer", + "required": false, + "mapping": "seed", + "description": "providerOptions seed。" + }, + { + "name": "camera_fixed", + "type": "boolean", + "required": false, + "mapping": "camera_fixed", + "description": "providerOptions camera_fixed。" + } + ], + "validations": [ + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.images" + } + }, + 9 + ] + }, + "message": "Seedance 最多支持 9 张参考图片" + }, + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.videos" + } + }, + 3 + ] + }, + "message": "Seedance 最多支持 3 个参考视频" + }, + { + "assert": { + "$lte": [ + { + "$len": { + "$ref": "request.audios" + } + }, + 3 + ] + }, + "message": "Seedance 最多支持 3 个参考音频" + }, + { + "assert": { + "$or": [ + { + "$eq": [ + { + "$len": { + "$ref": "request.audios" + } + }, + 0 + ] + }, + { + "$gt": [ + { + "$add": [ + { + "$len": { + "$ref": "request.images" + } + }, + { + "$len": { + "$ref": "request.videos" + } + } + ] + }, + 0 + ] + } + ] + }, + "message": "Seedance 不支持纯音频或文本+音频,请同时添加参考图片或参考视频" + } + ], + "create": { + "method": "POST", + "path": "/api/v3/contents/generations/tasks", + "contentType": "application/json", + "body": { + "model": { + "$ref": "request.model" + }, + "content": { + "$concatArrays": [ + [ + { + "type": "text", + "text": { + "$ref": "request.prompt" + } + } + ], + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.images" + } + }, + "as": "media", + "in": { + "type": "image_url", + "image_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_image" + ] + } + } + } + }, + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.videos" + } + }, + "as": "media", + "in": { + "type": "video_url", + "video_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_video" + ] + } + } + } + }, + { + "$map": { + "from": { + "$sortByOrder": { + "$ref": "request.audios" + } + }, + "as": "media", + "in": { + "type": "audio_url", + "audio_url": { + "url": { + "$ref": "media.value" + } + }, + "role": { + "$coalesce": [ + { + "$ref": "media.role" + }, + "reference_audio" + ] + } + } + } + } + ] + }, + "ratio": { + "$coalesce": [ + { + "$ref": "request.aspectRatio" + }, + "16:9" + ] + }, + "resolution": { + "$coalesce": [ + { + "$ref": "request.resolution" + }, + "720p" + ] + }, + "duration": { + "$if": { + "condition": { + "$gt": [ + { + "$ref": "request.duration" + }, + 0 + ] + }, + "then": { + "$ref": "request.duration" + }, + "else": 5 + } + }, + "generate_audio": { + "$ref": "request.generateAudio" + }, + "watermark": { + "$ref": "request.watermark" + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-video.seed" + } + }, + "camera_fixed": { + "$omitEmpty": { + "$ref": "request.providerOptions.volcengine-ark-video.camera_fixed" + } + } + } + }, + "poll": { + "method": "GET", + "path": "/api/v3/contents/generations/tasks/{{taskId}}" + }, + "cancel": { + "method": "DELETE", + "path": "/api/v3/contents/generations/tasks/{{taskId}}" + }, + "response": { + "taskId": { + "$coalesce": [ + { + "$ref": "response.id" + }, + { + "$ref": "response.task_id" + }, + { + "$ref": "response.data.id" + }, + { + "$ref": "taskId" + } + ] + }, + "status": { + "$coalesce": [ + { + "$ref": "response.status" + }, + { + "$ref": "response.data.status" + }, + "pending" + ] + }, + "message": { + "$coalesce": [ + { + "$ref": "response.error.message" + }, + { + "$ref": "response.message" + }, + { + "$ref": "response.fail_reason" + } + ] + }, + "videos": { + "$coalesce": [ + { + "$ref": "response.content.video_url" + }, + { + "$ref": "response.video_url" + }, + { + "$ref": "response.output.video_url" + }, + { + "$ref": "response.data.video_url" + } + ] + }, + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "resultEphemeral": true + } + } + ] + } +} diff --git a/plugin-packages/volcengine-ark-seedream.yingce-plugin b/plugin-packages/volcengine-ark-seedream.yingce-plugin index eb223b15926ad974254005719b9430c588479bbb..0eeb378b6162aa3e77eb38b9966ed4d2d97ee951 100644 GIT binary patch delta 8116 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 diff --git a/plugin-packages/volcengine-ark-seedream/docs/interface.md b/plugin-packages/volcengine-ark-seedream/docs/interface.md index 8e6883d5b..c3bb2a96b 100644 --- a/plugin-packages/volcengine-ark-seedream/docs/interface.md +++ b/plugin-packages/volcengine-ark-seedream/docs/interface.md @@ -74,7 +74,7 @@ ## 兼容边界 -该包只代表上述线协议 profile;同一品牌的其他 endpoint、云区域或网关包装必须使用独立插件,不能根据模型名猜测。 +官方 Ark 推理接入:Base URL 使用 /api/v3,API Key 来自方舟推理接入控制台,不可与 Agent Plan 专属 Key 混用。 ## Manifest 完整接口定义 diff --git a/plugin-packages/volcengine-ark-seedream/manifest.json b/plugin-packages/volcengine-ark-seedream/manifest.json index 7932f5b1b..3a4951286 100644 --- a/plugin-packages/volcengine-ark-seedream/manifest.json +++ b/plugin-packages/volcengine-ark-seedream/manifest.json @@ -5,7 +5,7 @@ "version": "2.0.0", "author": "Volcengine / 影策", "description": "Volcengine Ark Seedream Images 独立请求协议插件。", - "documentation": "# Volcengine Ark Seedream Images\n\n该目录是独立官方协议插件源码。后端从生成的 `volcengine-ark-seedream.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# Volcengine Ark Seedream Images 接口字段\n\n## 协议身份\n\n- 插件 ID:`volcengine-ark-seedream`。\n- Provider ID:`volcengine-ark-image`。\n- 能力:`image`。\n- 默认 Base URL:`https://ark.cn-beijing.volces.com`。\n- 鉴权驱动:`bearer`。\n- 创建:`POST /api/v3/images/generations`。\n- 生命周期:同步响应。\n\n## 配置字段\n\n| 字段 | 类型 | 必填 | 含义 |\n| --- | --- | --- | --- |\n| `apiKey` | secret | 是 | API Key |\n\n## 统一字段映射\n\n| 统一字段 | 类型 | 必填 | 上游映射 | 说明 |\n| --- | --- | --- | --- | --- |\n| `model` | string | 是 | `model` | 图片模型 ID。 |\n| `prompt` | string | 是 | `prompt` | 图片提示词。 |\n| `images` | media[] | 否 | `provider image/reference fields` | 参考图或编辑源图,role 由业务层确定。 |\n| `imageCount` | integer | 否 | `n/sample_count` | 输出数量。 |\n| `aspectRatio` | string | 否 | `size/aspect_ratio` | 比例或尺寸,语义按协议说明。 |\n| `resolution` | string | 否 | `resolution/imageSize` | 分辨率档位。 |\n| `quality` | string | 否 | `quality` | 质量档位。 |\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/v3/images/generations\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.prompt` | `{\"$ref\":\"request.prompt\"}` |\n| `create.body.size` | `{\"$omitEmpty\":{\"$switch\":{\"cases\":[{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"auto\"]},\"then\":\"2k\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"1:1\"]},\"then\":\"2048x2048\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"4:3\"]},\"then\":\"2304x1728\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"3:4\"]},\"then\":\"1728x2304\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"16:9\"]},\"then\":\"2560x1440\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"9:16\"]},\"then\":\"1440x2560\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"3:2\"]},\"then\":\"2496x1664\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"2:3\"]},\"then\":\"1664x2496\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"21:9\"]},\"then\":\"3024x1296\"}],\"default\":{\"$ref\":\"request.aspectRatio\"}}}}` |\n| `create.body.image` | `{\"$omitEmpty\":{\"$if\":{\"condition\":{\"$eq\":[{\"$len\":{\"$ref\":\"request.images\"}},1]},\"then\":{\"$first\":{\"$map\":{\"from\":{\"$ref\":\"request.images\"},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}}},\"else\":{\"$if\":{\"condition\":{\"$gt\":[{\"$len\":{\"$ref\":\"request.images\"}},1]},\"then\":{\"$map\":{\"from\":{\"$ref\":\"request.images\"},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}},\"else\":null}}}}}` |\n| `create.body.sequential_image_generation` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-image.sequential_image_generation\"}}` |\n| `create.body.sequential_image_generation_options` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-image.sequential_image_generation_options\"}}` |\n| `create.body.watermark` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.volcengine-ark-image.watermark\"},{\"$ref\":\"request.watermark\"},false]}` |\n| `create.body.seed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-image.seed\"}}` |\n| `create.body.response_format` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.volcengine-ark-image.response_format\"},\"b64_json\"]}` |\n\n## Provider 扩展键\n\n- `providerOptions.volcengine-ark-image.response_format`\n- `providerOptions.volcengine-ark-image.seed`\n- `providerOptions.volcengine-ark-image.sequential_image_generation`\n- `providerOptions.volcengine-ark-image.sequential_image_generation_options`\n- `providerOptions.volcengine-ark-image.watermark`\n\n动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。\n\n## 响应映射逐字段清单\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.status` | `\"succeeded\"` |\n| `response.images` | `{\"$ref\":\"response.data\"}` |\n| `response.usage` | `{\"$ref\":\"response.usage\"}` |\n| `response.errorPaths[0]` | `\"error.code\"` |\n| `response.messagePaths[0]` | `\"error.message\"` |\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\": \"volcengine-ark-seedream\",\n \"name\": \"Volcengine Ark Seedream Images\",\n \"version\": \"2.0.0\",\n \"author\": \"Volcengine / 影策\",\n \"description\": \"Volcengine Ark Seedream Images 独立请求协议插件。\",\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\": \"volcengine-ark-image\",\n \"label\": \"Volcengine Ark Seedream Images\",\n \"capabilities\": [\n \"image\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"https://ark.cn-beijing.volces.com\",\n \"requiresPublicMediaUrls\": false,\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\",\n \"description\": \"图片提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"provider image/reference fields\",\n \"description\": \"参考图或编辑源图,role 由业务层确定。\"\n },\n {\n \"name\": \"imageCount\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"n/sample_count\",\n \"description\": \"输出数量。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"size/aspect_ratio\",\n \"description\": \"比例或尺寸,语义按协议说明。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution/imageSize\",\n \"description\": \"分辨率档位。\"\n },\n {\n \"name\": \"quality\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"quality\",\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\": \"/api/v3/images/generations\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"prompt\": {\n \"$ref\": \"request.prompt\"\n },\n \"size\": {\n \"$omitEmpty\": {\n \"$switch\": {\n \"cases\": [\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"auto\"\n ]\n },\n \"then\": \"2k\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"1:1\"\n ]\n },\n \"then\": \"2048x2048\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"4:3\"\n ]\n },\n \"then\": \"2304x1728\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"3:4\"\n ]\n },\n \"then\": \"1728x2304\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"16:9\"\n ]\n },\n \"then\": \"2560x1440\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"9:16\"\n ]\n },\n \"then\": \"1440x2560\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"3:2\"\n ]\n },\n \"then\": \"2496x1664\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"2:3\"\n ]\n },\n \"then\": \"1664x2496\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"21:9\"\n ]\n },\n \"then\": \"3024x1296\"\n }\n ],\n \"default\": {\n \"$ref\": \"request.aspectRatio\"\n }\n }\n }\n },\n \"image\": {\n \"$omitEmpty\": {\n \"$if\": {\n \"condition\": {\n \"$eq\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 1\n ]\n },\n \"then\": {\n \"$first\": {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n },\n \"else\": {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 1\n ]\n },\n \"then\": {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n },\n \"else\": null\n }\n }\n }\n }\n },\n \"sequential_image_generation\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.sequential_image_generation\"\n }\n },\n \"sequential_image_generation_options\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.sequential_image_generation_options\"\n }\n },\n \"watermark\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.watermark\"\n },\n {\n \"$ref\": \"request.watermark\"\n },\n false\n ]\n },\n \"seed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.seed\"\n }\n },\n \"response_format\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.response_format\"\n },\n \"b64_json\"\n ]\n }\n }\n },\n \"response\": {\n \"status\": \"succeeded\",\n \"images\": {\n \"$ref\": \"response.data\"\n },\n \"usage\": {\n \"$ref\": \"response.usage\"\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"messagePaths\": [\n \"error.message\"\n ]\n }\n }\n ]\n }\n}\n```\n\n", + "documentation": "# Volcengine Ark Seedream Images\n\n该目录是独立官方协议插件源码。后端从生成的 `volcengine-ark-seedream.yingce-plugin` 包加载,不依赖系统内置 `host:` 适配器。\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# Volcengine Ark Seedream Images 接口字段\n\n## 协议身份\n\n- 插件 ID:`volcengine-ark-seedream`。\n- Provider ID:`volcengine-ark-image`。\n- 能力:`image`。\n- 默认 Base URL:`https://ark.cn-beijing.volces.com`。\n- 鉴权驱动:`bearer`。\n- 创建:`POST /api/v3/images/generations`。\n- 生命周期:同步响应。\n\n## 配置字段\n\n| 字段 | 类型 | 必填 | 含义 |\n| --- | --- | --- | --- |\n| `apiKey` | secret | 是 | API Key |\n\n## 统一字段映射\n\n| 统一字段 | 类型 | 必填 | 上游映射 | 说明 |\n| --- | --- | --- | --- | --- |\n| `model` | string | 是 | `model` | 图片模型 ID。 |\n| `prompt` | string | 是 | `prompt` | 图片提示词。 |\n| `images` | media[] | 否 | `provider image/reference fields` | 参考图或编辑源图,role 由业务层确定。 |\n| `imageCount` | integer | 否 | `n/sample_count` | 输出数量。 |\n| `aspectRatio` | string | 否 | `size/aspect_ratio` | 比例或尺寸,语义按协议说明。 |\n| `resolution` | string | 否 | `resolution/imageSize` | 分辨率档位。 |\n| `quality` | string | 否 | `quality` | 质量档位。 |\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/v3/images/generations\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.prompt` | `{\"$ref\":\"request.prompt\"}` |\n| `create.body.size` | `{\"$omitEmpty\":{\"$switch\":{\"cases\":[{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"auto\"]},\"then\":\"2k\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"1:1\"]},\"then\":\"2048x2048\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"4:3\"]},\"then\":\"2304x1728\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"3:4\"]},\"then\":\"1728x2304\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"16:9\"]},\"then\":\"2560x1440\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"9:16\"]},\"then\":\"1440x2560\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"3:2\"]},\"then\":\"2496x1664\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"2:3\"]},\"then\":\"1664x2496\"},{\"when\":{\"$eq\":[{\"$ref\":\"request.aspectRatio\"},\"21:9\"]},\"then\":\"3024x1296\"}],\"default\":{\"$ref\":\"request.aspectRatio\"}}}}` |\n| `create.body.image` | `{\"$omitEmpty\":{\"$if\":{\"condition\":{\"$eq\":[{\"$len\":{\"$ref\":\"request.images\"}},1]},\"then\":{\"$first\":{\"$map\":{\"from\":{\"$ref\":\"request.images\"},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}}},\"else\":{\"$if\":{\"condition\":{\"$gt\":[{\"$len\":{\"$ref\":\"request.images\"}},1]},\"then\":{\"$map\":{\"from\":{\"$ref\":\"request.images\"},\"as\":\"media\",\"in\":{\"$ref\":\"media.value\"}}},\"else\":null}}}}}` |\n| `create.body.sequential_image_generation` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-image.sequential_image_generation\"}}` |\n| `create.body.sequential_image_generation_options` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-image.sequential_image_generation_options\"}}` |\n| `create.body.watermark` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.volcengine-ark-image.watermark\"},{\"$ref\":\"request.watermark\"},false]}` |\n| `create.body.seed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.volcengine-ark-image.seed\"}}` |\n| `create.body.response_format` | `{\"$coalesce\":[{\"$ref\":\"request.providerOptions.volcengine-ark-image.response_format\"},\"b64_json\"]}` |\n\n## Provider 扩展键\n\n- `providerOptions.volcengine-ark-image.response_format`\n- `providerOptions.volcengine-ark-image.seed`\n- `providerOptions.volcengine-ark-image.sequential_image_generation`\n- `providerOptions.volcengine-ark-image.sequential_image_generation_options`\n- `providerOptions.volcengine-ark-image.watermark`\n\n动态模型或工作流允许使用文档声明的完整 `parameters/input/extra_body` 对象;该对象是协议本身的开放 schema,不会被宿主裁剪。\n\n## 响应映射逐字段清单\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.status` | `\"succeeded\"` |\n| `response.images` | `{\"$ref\":\"response.data\"}` |\n| `response.usage` | `{\"$ref\":\"response.usage\"}` |\n| `response.errorPaths[0]` | `\"error.code\"` |\n| `response.messagePaths[0]` | `\"error.message\"` |\n\n## 响应与错误\n\n插件把上游 task/status/text/media/usage 映射为统一结果。临时媒体 URL 标记为 ephemeral,由宿主立即下载持久化。HTTP 错误、业务 code 和 error object 保持失败语义,不包装成成功。\n\n## 兼容边界\n\n官方 Ark 推理接入:Base URL 使用 /api/v3,API Key 来自方舟推理接入控制台,不可与 Agent Plan 专属 Key 混用。\n\n\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"volcengine-ark-seedream\",\n \"name\": \"Volcengine Ark Seedream Images\",\n \"version\": \"2.0.0\",\n \"author\": \"Volcengine / 影策\",\n \"description\": \"Volcengine Ark Seedream Images 独立请求协议插件。\",\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\": \"volcengine-ark-image\",\n \"label\": \"Volcengine Ark Seedream Images\",\n \"capabilities\": [\n \"image\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"https://ark.cn-beijing.volces.com\",\n \"requiresPublicMediaUrls\": false,\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\",\n \"description\": \"图片提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"provider image/reference fields\",\n \"description\": \"参考图或编辑源图,role 由业务层确定。\"\n },\n {\n \"name\": \"imageCount\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"n/sample_count\",\n \"description\": \"输出数量。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"size/aspect_ratio\",\n \"description\": \"比例或尺寸,语义按协议说明。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution/imageSize\",\n \"description\": \"分辨率档位。\"\n },\n {\n \"name\": \"quality\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"quality\",\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\": \"/api/v3/images/generations\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"prompt\": {\n \"$ref\": \"request.prompt\"\n },\n \"size\": {\n \"$omitEmpty\": {\n \"$switch\": {\n \"cases\": [\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"auto\"\n ]\n },\n \"then\": \"2k\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"1:1\"\n ]\n },\n \"then\": \"2048x2048\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"4:3\"\n ]\n },\n \"then\": \"2304x1728\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"3:4\"\n ]\n },\n \"then\": \"1728x2304\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"16:9\"\n ]\n },\n \"then\": \"2560x1440\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"9:16\"\n ]\n },\n \"then\": \"1440x2560\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"3:2\"\n ]\n },\n \"then\": \"2496x1664\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"2:3\"\n ]\n },\n \"then\": \"1664x2496\"\n },\n {\n \"when\": {\n \"$eq\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n \"21:9\"\n ]\n },\n \"then\": \"3024x1296\"\n }\n ],\n \"default\": {\n \"$ref\": \"request.aspectRatio\"\n }\n }\n }\n },\n \"image\": {\n \"$omitEmpty\": {\n \"$if\": {\n \"condition\": {\n \"$eq\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 1\n ]\n },\n \"then\": {\n \"$first\": {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n }\n },\n \"else\": {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 1\n ]\n },\n \"then\": {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"in\": {\n \"$ref\": \"media.value\"\n }\n }\n },\n \"else\": null\n }\n }\n }\n }\n },\n \"sequential_image_generation\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.sequential_image_generation\"\n }\n },\n \"sequential_image_generation_options\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.sequential_image_generation_options\"\n }\n },\n \"watermark\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.watermark\"\n },\n {\n \"$ref\": \"request.watermark\"\n },\n false\n ]\n },\n \"seed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.seed\"\n }\n },\n \"response_format\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.providerOptions.volcengine-ark-image.response_format\"\n },\n \"b64_json\"\n ]\n }\n }\n },\n \"response\": {\n \"status\": \"succeeded\",\n \"images\": {\n \"$ref\": \"response.data\"\n },\n \"usage\": {\n \"$ref\": \"response.usage\"\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"messagePaths\": [\n \"error.message\"\n ]\n }\n }\n ]\n }\n}\n```\n\n", "permissions": [ "generation.run", "media.read" diff --git a/web/src/components/video-settings-panel.tsx b/web/src/components/video-settings-panel.tsx index b6b055d42..249c77dfb 100644 --- a/web/src/components/video-settings-panel.tsx +++ b/web/src/components/video-settings-panel.tsx @@ -3,6 +3,7 @@ import { Switch } from "@/components/ui/base/switch"; import { ImageSettingsTheme } from "@/components/image-settings-panel"; import { boolConfig, isSeedanceFastModel, isSeedanceVideoConfig, normalizeSeedanceDuration, normalizeSeedanceRatio, normalizeSeedanceResolution, seedanceRatioOptions } from "@/lib/seedance-video"; +import { isVolcengineArkVideoProtocol } from "@/lib/model-protocols"; import { type CanvasTheme } from "@/lib/canvas-theme"; import { formatVideoResolutionLabel, isVideoResolutionMatch, normalizeVideoDuration, videoDimensionsForRatioAndResolution, videoResolutionComparisonKey, VIDEO_DURATION_MIN } from "@/lib/video-generation-options"; import { modelCapabilityConfigFor, resolveVideoRatioValue, resolveVideoResolutionValue, videoDurationOptions, type VideoCapabilityConfig } from "@/lib/model-capabilities"; @@ -115,7 +116,7 @@ function SeedanceVideoSettingsPanel({ config, profile, priceTiers, onConfigChang const generateAudio = boolConfig(config.videoGenerateAudio, profile.generateAudio.default); const watermark = boolConfig(config.videoWatermark, profile.watermark.default); const useArkPrivateAssets = boolConfig(config.videoArkPrivateAssetUpload, true); - const isArkSeedance = resolveModelRequestConfig(config, config.model).interfaceType === "volcengine-ark-video"; + const isArkSeedance = isVolcengineArkVideoProtocol(resolveModelRequestConfig(config, config.model).interfaceType); return ( diff --git a/web/src/lib/model-capabilities.ts b/web/src/lib/model-capabilities.ts index 5cf64edef..3f2e93493 100644 --- a/web/src/lib/model-capabilities.ts +++ b/web/src/lib/model-capabilities.ts @@ -216,7 +216,7 @@ export function defaultImageCapabilityConfig(protocol?: ModelProtocol, model = " image.responseFormat = { supported: true }; image.outputFormat = { supported: false }; image.maxOutputs = 1; - } else if (protocol === "volcengine-ark-image") { + } else if (protocol === "volcengine-ark-image" || protocol === "volcengine-ark-agent-plan-image") { image.references.maskSupported = false; image.quality.supported = false; image.transparentBackground.supported = false; @@ -320,7 +320,7 @@ export function defaultModelCapabilityConfig(protocol?: ModelProtocol, model = " video.duration = { selection: "enum", values: [4, 6, 8], default: 6 }; video.resolutions = ["720p", "1080p"]; } - if (protocol === "volcengine-ark-video" || protocol === "newapi-channel-1" || protocol === "newapi-channel-2") { + if (protocol === "volcengine-ark-video" || protocol === "volcengine-ark-agent-plan-video" || protocol === "newapi-channel-1" || protocol === "newapi-channel-2") { video.references.maxVideos = 3; video.references.maxAudios = 3; video.references.maxVideoBytes = 200 * 1024 * 1024; @@ -329,8 +329,8 @@ export function defaultModelCapabilityConfig(protocol?: ModelProtocol, model = " video.references.maxAudioDurationSeconds = 15; video.generateAudio = { supported: true, default: true }; } - if (protocol === "volcengine-ark-video" || protocol === "newapi-channel-1") video.resolutions = ["480p", "720p", "1080p"]; - if (protocol === "volcengine-ark-video") { + if (protocol === "volcengine-ark-video" || protocol === "volcengine-ark-agent-plan-video" || protocol === "newapi-channel-1") video.resolutions = ["480p", "720p", "1080p"]; + if (protocol === "volcengine-ark-video" || protocol === "volcengine-ark-agent-plan-video") { video.watermark = { supported: true, default: false }; video.operations.push("reference_to_video", "audio_to_video"); } diff --git a/web/src/lib/model-protocols.ts b/web/src/lib/model-protocols.ts index c1ac8e28c..729bd8b8b 100644 --- a/web/src/lib/model-protocols.ts +++ b/web/src/lib/model-protocols.ts @@ -9,8 +9,16 @@ export function protocolGroups(protocols: ModelProtocolDefinition[]) { export function modelProtocolDefinition(value: string | undefined, definitions: ModelProtocolDefinition[] = []) { return definitions.find((item) => item.value === value); } export function modelProtocolLabel(value: string | undefined, definitions: ModelProtocolDefinition[] = []) { return modelProtocolDefinition(value, definitions)?.label || (value ? value : "未安装协议"); } export function modelProtocolCapability(value: string | undefined, definitions: ModelProtocolDefinition[] = []) { return modelProtocolDefinition(value, definitions)?.capability; } +export function isVolcengineArkImageProtocol(protocol?: string) { + return protocol === "volcengine-ark-image" || protocol === "volcengine-ark-agent-plan-image"; +} + +export function isVolcengineArkVideoProtocol(protocol?: string) { + return protocol === "volcengine-ark-video" || protocol === "volcengine-ark-agent-plan-video"; +} + export function modelProtocolSupportsTokenBilling(capability?: string, protocol?: string) { - return capability === "text" || (capability === "video" && protocol === "volcengine-ark-video"); + return capability === "text" || (capability === "video" && isVolcengineArkVideoProtocol(protocol)); } export function protocolForModelCatalog(_endpointTypes: string[] = []): ModelProtocol | undefined { diff --git a/web/src/lib/plugins/builtin/prompt-optimizer.ts b/web/src/lib/plugins/builtin/prompt-optimizer.ts index 1073869c0..39b089524 100644 --- a/web/src/lib/plugins/builtin/prompt-optimizer.ts +++ b/web/src/lib/plugins/builtin/prompt-optimizer.ts @@ -136,7 +136,7 @@ function resolveModelAdaptationProfile(input: PromptOptimizationInput): ModelAda avoid: ["不要添加 SD 权重、Midjourney 参数或模型未确认支持的控制语法。"], }; } - if (containsAny(model, ["seedream", "jimeng", "doubao", "volcengine-ark-image", "volcengine-jimeng-image"])) { + if (containsAny(model, ["seedream", "jimeng", "doubao", "volcengine-ark-image", "volcengine-ark-agent-plan-image", "volcengine-jimeng-image"])) { return { id: "seedream-image", label: "Seedream / 即梦 / 火山图片模型", @@ -184,7 +184,7 @@ function resolveModelAdaptationProfile(input: PromptOptimizationInput): ModelAda return genericImageProfile; } - if (containsAny(model, ["seedance", "doubao-seedance", "volcengine-ark-video", "volcengine-jimeng-video", "jimeng-video"])) { + if (containsAny(model, ["seedance", "doubao-seedance", "volcengine-ark-video", "volcengine-ark-agent-plan-video", "volcengine-jimeng-video", "jimeng-video"])) { return { id: "seedance-video", label: "Seedance / 即梦视频模型", diff --git a/web/src/services/api/image.ts b/web/src/services/api/image.ts index 769fb82f1..7ab3978ea 100644 --- a/web/src/services/api/image.ts +++ b/web/src/services/api/image.ts @@ -6,6 +6,7 @@ import type { ReferenceImage } from "@/types/image"; import { withOpenAIPromptCacheKey } from "@/lib/openai-prompt-cache"; import { modelCapabilityConfigFor, normalizeImageValue } from "@/lib/model-capabilities"; import { buildGeminiImageGenerationConfig, parseGeminiImageDataUrl, type GeminiImageGenerationConfig } from "@/lib/gemini-image"; +import { isVolcengineArkImageProtocol } from "@/lib/model-protocols"; import { aiApiUrl, aiHeaders, imageChannelTransport, postChannelJSON, postGeminiJSON, postVolcengineArkImage } from "@/services/api/image-transport"; const IMAGE_OUTPUT_FORMAT = "png"; @@ -94,7 +95,7 @@ export async function requestGeneration(config: AiConfig, prompt: string, option } const quality = imageProfile.quality.supported && normalizedImage.quality !== "auto" ? normalizeQuality(normalizedImage.quality) || normalizedImage.quality : undefined; const requestSize = resolveImageRequestSize(imageProfile, quality, normalizedImage.size); - const isVolcengineArk = requestConfig.interfaceType === "volcengine-ark-image"; + const isVolcengineArk = isVolcengineArkImageProtocol(requestConfig.interfaceType); const normalizedRequestSize = requestSize?.parameter === "size" && isVolcengineArk ? { ...requestSize, value: normalizeVolcengineArkImageSize(requestSize.value)! } : requestSize; try { const payload = isVolcengineArk @@ -174,7 +175,7 @@ export async function requestEdit(config: AiConfig, prompt: string, references: throw new Error(readAxiosError(error, "Grok 图片编辑失败")); } } - if (requestConfig.interfaceType === "volcengine-ark-image") { + if (isVolcengineArkImageProtocol(requestConfig.interfaceType)) { if (mask) throw new Error("火山方舟图片协议不支持蒙版编辑,请移除蒙版后重试"); const quality = imageProfile.quality.supported && normalizedImage.quality !== "auto" ? normalizeQuality(normalizedImage.quality) || normalizedImage.quality : undefined; const sizeRequest = resolveImageRequestSize(imageProfile, quality, normalizedImage.size); diff --git a/web/src/services/api/video-provider-seedance.ts b/web/src/services/api/video-provider-seedance.ts index abf255c62..757b35702 100644 --- a/web/src/services/api/video-provider-seedance.ts +++ b/web/src/services/api/video-provider-seedance.ts @@ -1,4 +1,5 @@ import { modelCapabilityConfigFor } from "@/lib/model-capabilities"; +import { isVolcengineArkVideoProtocol } from "@/lib/model-protocols"; import { boolConfig, buildSeedancePromptText, isArkPlanBaseUrl, isSeedanceVideoConfig, normalizeSeedanceDuration, normalizeSeedanceRatio, normalizeSeedanceResolution, seedanceVideoReferenceError, SEEDANCE_REFERENCE_LIMITS } from "@/lib/seedance-video"; import { getResourceOSSUrl } from "@/services/api/resources"; import { getMediaBlob } from "@/services/file-storage"; @@ -13,13 +14,13 @@ import type { VideoProviderDeps } from "./video-provider-deps"; import { hasExplicitVideoFrames, resolveVideoImageReferences } from "./video-reference-roles"; export function isSeedanceConfig(config: ResolvedAiConfig) { - return config.interfaceType === "volcengine-ark-video" || isSeedanceVideoConfig(config); + return isVolcengineArkVideoProtocol(config.interfaceType) || isSeedanceVideoConfig(config); } export async function createSeedanceTask(deps: VideoProviderDeps, config: ResolvedAiConfig, model: string, prompt: string, references: ReferenceImage[], videoReferences: ReferenceVideo[], audioReferences: ReferenceAudio[], options?: RequestOptions): Promise { assertSeedanceVideoReferences(videoReferences); assertSeedanceAudioReferences(audioReferences); - const isVolcengineArk = config.interfaceType === "volcengine-ark-video"; + const isVolcengineArk = isVolcengineArkVideoProtocol(config.interfaceType); const payload = isVolcengineArk || isArkPlanBaseUrl(config.baseUrl) ? await buildSeedanceAgentPlanPayload(config, model, prompt, references, videoReferences, audioReferences, deps, options) : await buildSeedanceVideosPayload(config, model, prompt, references, videoReferences, audioReferences, deps, options); @@ -77,15 +78,15 @@ function assertSeedanceAudioReferences(audioReferences: ReferenceAudio[]) { } function seedanceApiUrl(config: ResolvedAiConfig, taskId?: string) { - if (config.interfaceType === "volcengine-ark-video" || isArkPlanBaseUrl(config.baseUrl)) return buildApiUrl(config.baseUrl, `/contents/generations/tasks${taskId ? `/${encodeURIComponent(taskId)}` : ""}`); + if (isVolcengineArkVideoProtocol(config.interfaceType) || isArkPlanBaseUrl(config.baseUrl)) return buildApiUrl(config.baseUrl, `/contents/generations/tasks${taskId ? `/${encodeURIComponent(taskId)}` : ""}`); return buildApiUrl(config.baseUrl, `/videos${taskId ? `/${encodeURIComponent(taskId)}` : ""}`); } async function buildSeedanceAgentPlanPayload(config: ResolvedAiConfig, model: string, prompt: string, references: ReferenceImage[], videoReferences: ReferenceVideo[], audioReferences: ReferenceAudio[], deps: VideoProviderDeps, options?: RequestOptions) { if (audioReferences.length && !references.length && !videoReferences.length) { - throw new Error(config.interfaceType === "volcengine-ark-video" ? "火山方舟全模态参考不支持纯音频或文本+音频,请同时添加参考图片或参考视频" : "Seedance 参考音频不能单独使用,请同时添加参考图或参考视频"); + throw new Error(isVolcengineArkVideoProtocol(config.interfaceType) ? "火山方舟全模态参考不支持纯音频或文本+音频,请同时添加参考图片或参考视频" : "Seedance 参考音频不能单独使用,请同时添加参考图或参考视频"); } - const content = config.interfaceType === "volcengine-ark-video" + const content = isVolcengineArkVideoProtocol(config.interfaceType) ? await buildVolcengineArkContent(prompt, references, videoReferences, audioReferences, options) : await buildSeedanceContent(config, prompt, references, videoReferences, audioReferences, deps, options); if (!content.length) throw new Error("请输入视频提示词,或连接参考图片/视频/音频"); diff --git a/web/src/stores/use-config-store.ts b/web/src/stores/use-config-store.ts index 8e71ad05c..626ef91a4 100644 --- a/web/src/stores/use-config-store.ts +++ b/web/src/stores/use-config-store.ts @@ -912,6 +912,7 @@ export function defaultBaseUrlForApiFormat(apiFormat: ApiCallFormat) { export function defaultBaseUrlForChannelInterface(interfaceType?: ChannelInterfaceType) { if (interfaceType === "gemini-veo" || interfaceType === "gemini-image") return GEMINI_BASE_URL; if (interfaceType === "novita-video") return "https://api.novita.ai/v3"; + if (interfaceType === "volcengine-ark-agent-plan-image" || interfaceType === "volcengine-ark-agent-plan-video") return "https://ark.cn-beijing.volces.com/api/plan/v3"; if (interfaceType === "volcengine-ark-image" || interfaceType === "volcengine-ark-video") return "https://ark.cn-beijing.volces.com/api/v3"; if (interfaceType === "volcengine-jimeng-image" || interfaceType === "volcengine-jimeng-video") return "https://visual.volcengineapi.com"; if (interfaceType === "minimax-video") return "https://api.minimaxi.com"; diff --git a/web/test/model-protocols.test.ts b/web/test/model-protocols.test.ts index 6cccde9f7..24a2ddad2 100644 --- a/web/test/model-protocols.test.ts +++ b/web/test/model-protocols.test.ts @@ -6,8 +6,10 @@ describe("model protocol Token billing", () => { test("supports text models and Volcengine Ark video only", () => { expect(modelProtocolSupportsTokenBilling("text", "chat-completion")).toBe(true); expect(modelProtocolSupportsTokenBilling("video", "volcengine-ark-video")).toBe(true); + expect(modelProtocolSupportsTokenBilling("video", "volcengine-ark-agent-plan-video")).toBe(true); expect(modelProtocolSupportsTokenBilling("video", "volcengine-jimeng-video")).toBe(false); expect(modelProtocolSupportsTokenBilling("video", "newapi")).toBe(false); expect(modelProtocolSupportsTokenBilling("image", "volcengine-ark-image")).toBe(false); + expect(modelProtocolSupportsTokenBilling("image", "volcengine-ark-agent-plan-image")).toBe(false); }); });