Skip to content

新增支持 Sora-2-Pro 1080P,支持 豆包Seedance 2.0 视频 官方原生路由 - #4180

Merged
Calcium-Ion merged 0 commit into
QuantumNous:mainfrom
aabao325:main
Apr 12, 2026
Merged

新增支持 Sora-2-Pro 1080P,支持 豆包Seedance 2.0 视频 官方原生路由#4180
Calcium-Ion merged 0 commit into
QuantumNous:mainfrom
aabao325:main

Conversation

@aabao325

@aabao325 aabao325 commented Apr 10, 2026

Copy link
Copy Markdown

⚠️ 提交说明 / PR Notice

Important

  • 请提供人工撰写的简洁摘要,避免直接粘贴未经整理的 AI 输出。

📝 变更描述 / Description

(简述:做了什么?为什么这样改能生效?请基于你对代码逻辑的理解来写,避免粘贴未经整理的内容)

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix) - 请关联对应 Issue,避免将设计取舍、理解偏差或预期不一致直接归类为 bug
  • ✨ 新功能 (New feature) - 重大特性建议先通过 Issue 沟通
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 IssuesPRs,确认不是重复提交。
  • Bug fix 说明: 若此 PR 标记为 Bug fix,我已提交或关联对应 Issue,且不会将设计取舍、预期不一致或理解偏差直接归类为 bug。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行并通过测试或手动验证,维护者可以据此复核结果。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

(请在此粘贴截图、关键日志或测试报告,以证明变更生效)

Summary by CodeRabbit

  • New Features

    • Added native Doubao video generation API support with automatic request and response conversion.
  • Improvements

    • Enhanced Sora model size validation with clearer error messages specifying supported resolutions.
    • Refined Sora billing calculations to accurately reflect resolution-based pricing.

@coderabbitai

coderabbitai Bot commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR adds support for Doubao's native video generation API integration. It introduces request middleware to translate native API calls into the internal relay format, a response converter interface to map internal task records back to native format, new route handlers for Doubao endpoints, and updates Sora billing/validation logic.

Changes

Cohort / File(s) Summary
Doubao Request Conversion
middleware/doubao_adapter.go
New middleware that converts Doubao native video generation API requests (both GET task status and POST task creation) into internal relay pipeline format, handling request body unmarshaling, unified payload construction, and path rewriting.
Doubao Response Conversion
relay/channel/adapter.go, relay/channel/task/doubao/adaptor.go
Introduces DoubaoNativeResponseConverter interface and implements ConvertToDoubaoNativeResponse method to convert internal task records back to Doubao-native response format with status mapping and optional fields (video URL, errors, usage, timestamps).
Doubao Route Handlers
router/video-router.go
Adds new Doubao native API route group at /api/v3/contents/generations with POST/GET endpoints, middleware chain, and wiring to existing relay task controllers.
Relay Task Response Handling
relay/relay_task.go
Extends videoFetchByIDRespBodyBuilder to detect Doubao native requests via context flag and apply Doubao-native response conversion before falling back to OpenAI format or generic marshaling.
Sora Billing & Validation Updates
relay/channel/task/sora/adaptor.go, relay/common/relay_utils.go
Updates Sora EstimateBilling to compute size ratios dynamically based on model variant and resolution; refines ValidateMultipartDirect error messages for sora-2 and sora-2-pro with supported resolution groups.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant DoubaoMiddleware as DoubaoRequestConvert<br/>Middleware
    participant RelayTask as Relay Task<br/>Pipeline
    participant TaskAdaptor as Doubao Task<br/>Adaptor
    participant ResponseConverter as Response<br/>Converter
    
    rect rgba(100, 150, 200, 0.5)
    Note over Client,ResponseConverter: Doubao Native Request Flow
    Client->>DoubaoMiddleware: POST /api/v3/contents/generations/tasks<br/>(native request body)
    DoubaoMiddleware->>DoubaoMiddleware: Parse native request<br/>Extract model, prompts, images
    DoubaoMiddleware->>DoubaoMiddleware: Build unified internal payload<br/>with metadata normalization
    DoubaoMiddleware->>RelayTask: Forward to /v1/video/generations<br/>(internal format body)
    RelayTask->>RelayTask: Process relay task<br/>(platform routing, execution)
    RelayTask->>TaskAdaptor: Create/track task
    end
    
    rect rgba(150, 100, 200, 0.5)
    Note over Client,ResponseConverter: Doubao Native Response Flow
    Client->>RelayTask: GET /api/v3/contents/generations/tasks/:task_id
    RelayTask->>RelayTask: Detect doubao_native_route flag
    RelayTask->>TaskAdaptor: Retrieve internal task record
    RelayTask->>ResponseConverter: ConvertToDoubaoNativeResponse(task)
    ResponseConverter->>ResponseConverter: Map internal status<br/>to Doubao format
    ResponseConverter->>ResponseConverter: Build response with<br/>video_url/error/usage
    ResponseConverter-->>RelayTask: Doubao native JSON
    RelayTask-->>Client: Doubao native response
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • PR #1951: Main PR's Doubao request/response conversion logic and new DoubaoNativeResponseConverter directly extend the doubao channel adaptor introduced in that PR.
  • PR #1659: Both PRs modify relay/relay_task.go's videoFetchByIDRespBodyBuilder to add platform-specific response handling branches.
  • PR #2632: Both PRs modify the Doubao task adaptor to add conversion logic for native/OpenAI-style task payloads.

Suggested reviewers

  • creamlike1024
  • Calcium-Ion

Poem

🐰 A Doubao request hops through middleware gates,
Transforming native calls to our relay's fates,
Tasks convert to Doubao's native tongue,
Video routes now elegantly strung! 📹✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly addresses the main changes: adding Sora-2-Pro 1080P support and implementing Doubao native API routing.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (5)
middleware/doubao_adapter.go (2)

209-212: Missing doubao_native_route flag for POST requests.

The GET handler sets c.Set("doubao_native_route", true) (Line 73), but the POST handler does not. While the submit response is handled differently (via DoResponse in the adaptor), setting this flag consistently could be useful for future logging, metrics, or response customization.

♻️ Optional: Set doubao_native_route for POST consistency
 		// Redirect to the internal video generation endpoint
 		c.Request.URL.Path = "/v1/video/generations"
+		c.Set("doubao_native_route", true)
 
 		c.Next()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@middleware/doubao_adapter.go` around lines 209 - 212, The POST branch that
rewrites requests to c.Request.URL.Path = "/v1/video/generations" is missing the
same c.Set("doubao_native_route", true) that the GET handler sets; add
c.Set("doubao_native_route", true) in the POST handler (before calling c.Next()
/ before the path rewrite or immediately after) so the POST path follows the
same flag convention used by the GET route and downstream logic like DoResponse
in the adaptor can rely on it for logging/metrics/customization.

85-101: Empty prompt validation missing.

If the native request contains no "text" type content items, prompt will be an empty string. The downstream ValidateBasicTaskRequest (via validatePrompt) will catch this, but returning an error earlier with a Doubao-specific message would provide better UX.

♻️ Optional: Add early prompt validation
 		prompt := strings.Join(promptParts, "\n")
+
+		if strings.TrimSpace(prompt) == "" {
+			abortWithOpenAiMessage(c, http.StatusBadRequest, "content must include at least one text item with non-empty text")
+			return
+		}
 
 		// Build metadata — carry all non-standard fields so the doubao adaptor
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@middleware/doubao_adapter.go` around lines 85 - 101, The code builds prompt
from nativeReq.Content into promptParts/images but does not validate an empty
prompt early; after the existing loop that constructs prompt (using promptParts,
images and prompt) add an early check if prompt == "" and return a
Doubao-specific error response (instead of deferring to
ValidateBasicTaskRequest/validatePrompt) so callers get immediate, user-friendly
feedback; locate the validation right after prompt := strings.Join(promptParts,
"\n") in middleware/doubao_adapter.go and return the appropriate error payload
expected by the surrounding handler.
relay/relay_task.go (2)

402-411: Fallback path silently swallows conversion errors.

When DoubaoNativeResponseConverter is not implemented and the OpenAIVideoConverter fallback fails, the error is silently discarded (Line 406 only returns on convertErr == nil). This allows execution to continue to the generic TaskDto path, which may not be the intended behavior for Doubao native routes.

Consider either logging the error or returning it explicitly to avoid masking conversion failures.

♻️ Suggested fix to handle fallback error
 			// Fallback: if the platform doesn't implement DoubaoNativeResponseConverter,
 			// return OpenAI Video API format as the next best option.
 			if converter, ok := adaptor.(channel.OpenAIVideoConverter); ok {
 				openAIVideoData, convertErr := converter.ConvertToOpenAIVideo(originTask)
-				if convertErr == nil {
-					respBody = openAIVideoData
-					return
+				if convertErr != nil {
+					common.SysError("doubao_native_route fallback to OpenAI format failed: " + convertErr.Error())
 				}
+				respBody = openAIVideoData
+				return
 			}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/relay_task.go` around lines 402 - 411, The fallback branch that
attempts to use channel.OpenAIVideoConverter currently swallows conversion
errors (ConvertToOpenAIVideo on originTask) and only proceeds on success; update
that branch in relay_task.go so conversion failures are surfaced instead of
ignored: capture convertErr and either log it with the component logger
(including converter type and originTask ID/context) or return it up the call
chain (so respBody is not silently replaced by the generic TaskDto path); modify
the code around the adaptor.(channel.OpenAIVideoConverter) check and the
handling of respBody/return to propagate the conversion error for Doubao native
routes.

390-412: Consider handling nil adaptor explicitly for doubao_native_route.

If GetTaskAdaptor(originTask.Platform) returns nil (Line 391), the code falls through to the isOpenAIVideoAPI branch or generic TaskDto path. For doubao_native_route, this could return an unexpected response format to the downstream client expecting Doubao-native JSON.

♻️ Optional: Return explicit error for unsupported platform
 	if c.GetBool("doubao_native_route") {
 		adaptor := GetTaskAdaptor(originTask.Platform)
-		if adaptor != nil {
+		if adaptor == nil {
+			taskResp = service.TaskErrorWrapperLocal(
+				fmt.Errorf("unsupported platform for doubao native route: %s", originTask.Platform),
+				"unsupported_platform", http.StatusNotImplemented)
+			return
+		}
+		{
 			if converter, ok := adaptor.(channel.DoubaoNativeResponseConverter); ok {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/relay_task.go` around lines 390 - 412, When doubao_native_route is
enabled and GetTaskAdaptor(originTask.Platform) returns nil, explicitly return a
clear error instead of falling through; in the doubao_native_route branch
(around GetTaskAdaptor and the checks for channel.DoubaoNativeResponseConverter
and channel.OpenAIVideoConverter) detect adaptor == nil and call
service.TaskErrorWrapper with an appropriate error message and code (e.g.,
"unsupported_platform_for_doubao_native" and http.StatusBadRequest or
http.StatusInternalServerError) so the caller receives an explicit Doubao-native
format error rather than an unexpected OpenAI/generic TaskDto response.
relay/channel/task/doubao/adaptor.go (1)

408-413: Error details may be empty when task data is unavailable.

When doubaoStatus == "failed" but originTask.Data is empty or fails to unmarshal (Line 379 silently ignores errors), dResp.Error.Code and dResp.Error.Message will be empty strings. Consider falling back to originTask.FailReason for the message:

♻️ Suggested fix to use FailReason as fallback
 	if doubaoStatus == "failed" {
+		errMsg := dResp.Error.Message
+		if errMsg == "" {
+			errMsg = originTask.FailReason
+		}
 		native["error"] = map[string]interface{}{
 			"code":    dResp.Error.Code,
-			"message": dResp.Error.Message,
+			"message": errMsg,
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/channel/task/doubao/adaptor.go` around lines 408 - 413, When
doubaoStatus == "failed" the code currently uses dResp.Error.Code and
dResp.Error.Message which can be empty if originTask.Data was missing or
unmarshal silently failed; update the failure branch that builds native["error"]
to use a fallback: set the "message" to dResp.Error.Message if non-empty,
otherwise use originTask.FailReason (and similarly fall back for "code" if
appropriate), ensuring you check originTask.FailReason for emptiness before
assigning; modify the error-building logic in the same function where
doubaoStatus, dResp, originTask, and native are referenced so the
native["error"] always contains a meaningful message when available.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@middleware/doubao_adapter.go`:
- Around line 209-212: The POST branch that rewrites requests to
c.Request.URL.Path = "/v1/video/generations" is missing the same
c.Set("doubao_native_route", true) that the GET handler sets; add
c.Set("doubao_native_route", true) in the POST handler (before calling c.Next()
/ before the path rewrite or immediately after) so the POST path follows the
same flag convention used by the GET route and downstream logic like DoResponse
in the adaptor can rely on it for logging/metrics/customization.
- Around line 85-101: The code builds prompt from nativeReq.Content into
promptParts/images but does not validate an empty prompt early; after the
existing loop that constructs prompt (using promptParts, images and prompt) add
an early check if prompt == "" and return a Doubao-specific error response
(instead of deferring to ValidateBasicTaskRequest/validatePrompt) so callers get
immediate, user-friendly feedback; locate the validation right after prompt :=
strings.Join(promptParts, "\n") in middleware/doubao_adapter.go and return the
appropriate error payload expected by the surrounding handler.

In `@relay/channel/task/doubao/adaptor.go`:
- Around line 408-413: When doubaoStatus == "failed" the code currently uses
dResp.Error.Code and dResp.Error.Message which can be empty if originTask.Data
was missing or unmarshal silently failed; update the failure branch that builds
native["error"] to use a fallback: set the "message" to dResp.Error.Message if
non-empty, otherwise use originTask.FailReason (and similarly fall back for
"code" if appropriate), ensuring you check originTask.FailReason for emptiness
before assigning; modify the error-building logic in the same function where
doubaoStatus, dResp, originTask, and native are referenced so the
native["error"] always contains a meaningful message when available.

In `@relay/relay_task.go`:
- Around line 402-411: The fallback branch that attempts to use
channel.OpenAIVideoConverter currently swallows conversion errors
(ConvertToOpenAIVideo on originTask) and only proceeds on success; update that
branch in relay_task.go so conversion failures are surfaced instead of ignored:
capture convertErr and either log it with the component logger (including
converter type and originTask ID/context) or return it up the call chain (so
respBody is not silently replaced by the generic TaskDto path); modify the code
around the adaptor.(channel.OpenAIVideoConverter) check and the handling of
respBody/return to propagate the conversion error for Doubao native routes.
- Around line 390-412: When doubao_native_route is enabled and
GetTaskAdaptor(originTask.Platform) returns nil, explicitly return a clear error
instead of falling through; in the doubao_native_route branch (around
GetTaskAdaptor and the checks for channel.DoubaoNativeResponseConverter and
channel.OpenAIVideoConverter) detect adaptor == nil and call
service.TaskErrorWrapper with an appropriate error message and code (e.g.,
"unsupported_platform_for_doubao_native" and http.StatusBadRequest or
http.StatusInternalServerError) so the caller receives an explicit Doubao-native
format error rather than an unexpected OpenAI/generic TaskDto response.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 756296b9-49e8-45a8-bb82-2fa2aa978b23

📥 Commits

Reviewing files that changed from the base of the PR and between 0664bb3 and fa42bcc.

📒 Files selected for processing (7)
  • middleware/doubao_adapter.go
  • relay/channel/adapter.go
  • relay/channel/task/doubao/adaptor.go
  • relay/channel/task/sora/adaptor.go
  • relay/common/relay_utils.go
  • relay/relay_task.go
  • router/video-router.go

@Calcium-Ion
Calcium-Ion merged commit ed7f839 into QuantumNous:main Apr 12, 2026
1 check passed
@coderabbitai coderabbitai Bot mentioned this pull request Apr 20, 2026
11 tasks
@coderabbitai coderabbitai Bot mentioned this pull request Apr 30, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants