Skip to content

feat(ali): 适配阿里万相 wan2.7 并修复密钥聚合模式下异步任务轮询失败问题 - #4272

Closed
wans10 wants to merge 10 commits into
QuantumNous:mainfrom
wans10:main
Closed

feat(ali): 适配阿里万相 wan2.7 并修复密钥聚合模式下异步任务轮询失败问题#4272
wans10 wants to merge 10 commits into
QuantumNous:mainfrom
wans10:main

Conversation

@wans10

@wans10 wans10 commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

⚠️ 提交说明 / PR Notice

Important

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

📝 变更描述 / Description

本次变更主要实现了对阿里万相 wan2.7 系列模型的支持,并适配了其最新的媒体输入协议,同时修复了密钥聚合模式下异步视频任务无法推进的问题。

  1. 协议适配: wan2.7 及以上模型弃用了传统的 img_url 字符串字段,转而采用 media 数组协议([{"type": "image", "url": "..."}])。代码中新增了 AliMediaItem 结构,并根据模型前缀自动切换协议,确保了与旧版模型(wan2.6 及以下)的向下兼容。
  2. 模型扩展: 在 ModelList 中正式加入 wan2.7-i2v 模型。
  3. 参数处理: 针对 wan2.7 模型的特性,在未指定分辨率时默认映射为 1080P
  4. 统计完善: 扩展了 AliUsage 结构,新增了输入和输出视频时长的统计字段,为后续更精细的业务审计和计费提供了数据支持。
  5. Bug 修复: 修复了"字节火山方舟/豆包通用"等渠道在密钥聚合模式下,异步视频生成任务状态始终停留在"未启动"的问题。根因在于:任务提交时系统从多个密钥中随机选取一个发送上游,但未将该密钥持久化到任务记录,导致后台轮询时因使用错误的凭据查询上游而静默失败。修复方案:在 InitTask 中,当渠道启用密钥聚合模式(ChannelIsMultiKey)时,将请求实际使用的密钥存储至 task.PrivateData.Key,轮询时优先使用该值。此修复同样适用于其他类型的异步任务渠道(如 Kling、Ali 等)。

🚀 变更类型 / Type of change

  • 🐛 Bug 修复 (Bug fix)
  • ✨ 新功能 (New feature)
  • ⚡ 性能优化 / 重构 (Refactor)
  • 📝 文档更新 (Documentation)

🔗 关联任务 / Related Issue

  • Closes # (如适用)

✅ 提交前检查项 / Checklist

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

📸 运行证明 / Proof of Work

wan2.7 协议适配:
修复了调用 wan2.7-i2v 时报 Field required: input.media 的协议兼容性问题。
经测试,发送包含 input_reference 的请求时,系统能正确根据模型版本:

  • 对于 wan2.7:将其包装为 media 数组发送至上游。
  • 对于 wan2.6 及以下:继续使用 img_url 字段发送。
    生成的视频任务已能成功在阿里后台创建并正常处理。

密钥聚合模式 Bug 修复:
修复了字节火山方舟/豆包通用渠道在密钥聚合模式下,视频任务提交成功但任务日志中任务状态始终显示"未启动"的问题。
经测试,启用密钥聚合(随机/轮询)的渠道下,视频生成任务现可正常推进并最终完成。

Summary by CodeRabbit

  • New Features

    • Added support for Alibaba wan2.7-i2v video model.
    • Accepts multiple media items and prefers frame-based media for wan2.7+ input references.
    • Default outputs for wan2.7+ models now favor higher resolution (1080P).
    • Usage reporting now includes input and output video durations.
    • Safer base64 decoding and normalized tier-label matching across UI helpers and billing/usage displays.
  • Bug Fixes

    • Improved task key assignment for additional channel configurations.

wans10 and others added 3 commits April 14, 2026 14:48
- Added `wan2.7-i2v` to the model list
- Implemented `AliMediaItem` and updated `AliVideoInput` to support the new media array protocol
- Updated request conversion logic to handle model-specific input parameters and resolutions
- Expanded `AliUsage` to include input and output video duration statistics
@coderabbitai

coderabbitai Bot commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Add wan2.7+ model handling to the Alibaba adaptor (media-array video input, model-detection helper, resolution change), extend usage metrics, add "wan2.7-i2v" model, adjust Task init API-key sourcing, and introduce shared base64/tier-label normalization helpers in web UI decoding logic.

Changes

Cohort / File(s) Summary
Ali adaptor core
relay/channel/task/ali/adaptor.go
Added AliMediaItem and Media []AliMediaItem; convertToAliRequest now prefers Input.Media with type:"first_frame" for wan2.7+ models and falls back to legacy ImgURL for others; introduced isWan27Model(model string); switched some checks to use upstreamModel; default resolution for wan2.7+ set to 1080P; AliUsage extended with input_video_duration and output_video_duration.
Ali constants
relay/channel/task/ali/constants.go
Appended new model identifier "wan2.7-i2v" to ModelList.
Task init key sourcing
model/task.go
InitTask now sets TaskPrivateData.Key from relayInfo.ApiKey and populates it when relayInfo.ChannelIsMultiKey is true (in addition to existing Gemini/VertexAi cases).
Web UI decoding & tier helpers
web/classic/src/helpers/render.jsx, web/default/src/features/usage-logs/lib/format.ts
Added environment-aware base64 decoding (decodeFromBase64/decodeBillingExprB64) using TextDecoder fallback and Buffer decoding for non-browser runtimes; added/used normalizeLabel/normalizeTierLabel to canonicalize tier expressions (normalize operators, whitespace, case) when matching tiers; applied to tiered price/usage rendering.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • creamlike1024
  • seefs001

Poem

🐇 I hopped through code with whiskers bright,
First_frame now leads where lone URLs once might,
Wan2.7 hums in crisp 1080 light,
Media arrays nest videos just right,
A little rabbit cheers this tidy flight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title focuses on two main aspects: wan2.7 model support and fixing async task polling issues in multi-key mode. Both are well-represented in the changeset across Ali adaptor, constants, task initialization, and web components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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
Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
relay/channel/task/ali/adaptor.go (1)

191-194: Align helper naming/comment with actual predicate scope.

Line 191 says “wan2.7+”, but Line 193 only matches wan2.7*. Consider either broadening logic or renaming/commenting it as “wan2.7-series” to avoid future misrouting assumptions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/channel/task/ali/adaptor.go` around lines 191 - 194, The comment claims
“wan2.7+” but the predicate isWan27Model only checks strings.HasPrefix(model,
"wan2.7"), so update the naming/comment to reflect the actual scope: rename
isWan27Model to isWan27SeriesModel and change the comment to indicate "wan2.7
系列模型(使用新版 media 数组协议)", or alternatively broaden the predicate if you truly mean
"2.7 and newer"; locate the function isWan27Model and the
strings.HasPrefix(model, "wan2.7") usage and make the corresponding rename and
comment change (plus update all call sites) so the code and documentation match.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@relay/channel/task/ali/adaptor.go`:
- Around line 323-325: The branching that sets aliReq.Parameters.Resolution to
"1080P" currently checks req.Model but the function already computes a mapped
model in upstreamModel (see lines where upstreamModel is derived); update the
condition to use upstreamModel (or call isWan27Model(upstreamModel)) instead of
req.Model so mapped wan2.7 models correctly get the 1080P default; ensure all
subsequent model-prefix checks (e.g., strings.HasPrefix) also use upstreamModel
for consistency.

---

Nitpick comments:
In `@relay/channel/task/ali/adaptor.go`:
- Around line 191-194: The comment claims “wan2.7+” but the predicate
isWan27Model only checks strings.HasPrefix(model, "wan2.7"), so update the
naming/comment to reflect the actual scope: rename isWan27Model to
isWan27SeriesModel and change the comment to indicate "wan2.7 系列模型(使用新版 media
数组协议)", or alternatively broaden the predicate if you truly mean "2.7 and
newer"; locate the function isWan27Model and the strings.HasPrefix(model,
"wan2.7") usage and make the corresponding rename and comment change (plus
update all call sites) so the code and documentation match.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b6943406-4abf-4317-a4a1-134f224f46cf

📥 Commits

Reviewing files that changed from the base of the PR and between 8aaec8b and 1510cf0.

📒 Files selected for processing (2)
  • relay/channel/task/ali/adaptor.go
  • relay/channel/task/ali/constants.go

Comment thread relay/channel/task/ali/adaptor.go Outdated
@wans10 wans10 changed the title feat(ali): 适配阿里万相 wan2.7 媒体数组协议并新增模型支持 feat(ali): 适配阿里万相 wan2.7 并修复密钥聚合模式下异步任务轮询失败问题 Apr 22, 2026
wans10 and others added 2 commits April 29, 2026 13:13
- 优化 Base64 解码逻辑:引入 UTF-8 感知的解码方法(使用 TextDecoder/Uint8Array),替换原有的简单 `atob`,修复包含非拉丁字符时解码失败的问题。
- 增强阶梯标签匹配机制:新增标签规范化处理(移除空格、统一大小写、转换 `<`/`≤`/`<=` 等符号),确保日志记录中的标签能够与配置中的标签准确匹配。
- 将上述修复同步应用于 default 和 classic 两套前端主题。

@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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
web/default/src/features/usage-logs/lib/format.ts (1)

160-178: Cross-environment base64 decoding is well-handled, but any type usage should be avoided.

The decoding logic correctly handles browser vs Node environments. However, line 176 uses any type which violates the coding guideline.

♻️ Proposed fix: use explicit type annotation
     return decodeURIComponent(
       Array.prototype.map
-        .call(bytes, (byte: any) => '%' + byte.toString(16).padStart(2, '0'))
+        .call(bytes, (byte: number) => '%' + byte.toString(16).padStart(2, '0'))
         .join('')
     )

As per coding guidelines: "Avoid any type in TypeScript; prefer specific types or unknown"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/default/src/features/usage-logs/lib/format.ts` around lines 160 - 178,
Replace the use of the any type in the Array.prototype.map callback by typing
the mapped parameter as a number (e.g., change the callback signature from
(byte: any) => ... to (byte: number) => ...), since the source Uint8Array
(bytes) yields numbers; update the map callback reference accordingly so
TypeScript recognizes the parameter type and remove the any usage in that
mapping expression that builds the percent-encoded string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/classic/src/helpers/render.jsx`:
- Around line 2295-2302: normalizeLabel incorrectly normalizes "<=" and ">="
because the regex alternatives match the single-char "<" or ">" first; update
the two replace regexes in normalizeLabel to match the longer sequences first
(e.g., use alternatives that list "<=" before "<" and ">=" before ">") so "<="
and ">=" are replaced to "<" and ">" correctly, keeping the existing
replacements for the unicode characters (≤, ≥), the whitespace removal, and
toLowerCase behavior.

In `@web/default/src/features/usage-logs/lib/format.ts`:
- Around line 184-191: In normalizeTierLabel, the regex alternation orders
shorter tokens before longer ones so "<" matches before "<=" and prevents
normalizing "<=" to "<"; update the patterns used in normalizeTierLabel (the two
.replace calls that target <=/≤/< and >=/≥/> ) to list longer sequences first
(e.g., match "<=" before "<" and ">=" before ">") so the multi-character
operators normalize correctly while keeping the subsequent .replace(/\s/g, '')
and .toLowerCase() calls intact.

---

Nitpick comments:
In `@web/default/src/features/usage-logs/lib/format.ts`:
- Around line 160-178: Replace the use of the any type in the
Array.prototype.map callback by typing the mapped parameter as a number (e.g.,
change the callback signature from (byte: any) => ... to (byte: number) => ...),
since the source Uint8Array (bytes) yields numbers; update the map callback
reference accordingly so TypeScript recognizes the parameter type and remove the
any usage in that mapping expression that builds the percent-encoded string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a63ff397-0091-4b24-bd9e-6acd6c05cf4f

📥 Commits

Reviewing files that changed from the base of the PR and between d64680d and f6c74f8.

📒 Files selected for processing (2)
  • web/classic/src/helpers/render.jsx
  • web/default/src/features/usage-logs/lib/format.ts

Comment on lines +2295 to +2302
export const normalizeLabel = (label) => {
if (!label) return '';
return label
.replace(/<|≤|<=/g, '<')
.replace(/>|≥|>=/g, '>')
.replace(/\s/g, '')
.toLowerCase();
};

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.

⚠️ Potential issue | 🟠 Major

Regex alternation order prevents proper normalization of <= and >=.

The regex /<|≤|<=/g tries alternatives left-to-right at each position. When encountering <=, the engine matches < first (at position 0) and moves on, leaving = unprocessed. This means:

  • <
  • <=<= (unchanged) ✗

Similarly for />|≥|>=/g. If a tier label uses <= and matched_tier uses (or vice versa), they won't match after normalization.

🐛 Proposed fix: reorder alternatives to match longer sequences first
 export const normalizeLabel = (label) => {
   if (!label) return '';
   return label
-    .replace(/<|≤|<=/g, '<')
-    .replace(/>|≥|>=/g, '>')
+    .replace(/<=|≤|</g, '<')
+    .replace(/>=|≥|>/g, '>')
     .replace(/\s/g, '')
     .toLowerCase();
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/classic/src/helpers/render.jsx` around lines 2295 - 2302, normalizeLabel
incorrectly normalizes "<=" and ">=" because the regex alternatives match the
single-char "<" or ">" first; update the two replace regexes in normalizeLabel
to match the longer sequences first (e.g., use alternatives that list "<="
before "<" and ">=" before ">") so "<=" and ">=" are replaced to "<" and ">"
correctly, keeping the existing replacements for the unicode characters (≤, ≥),
the whitespace removal, and toLowerCase behavior.

Comment on lines +184 to +191
export function normalizeTierLabel(label: string | undefined): string {
if (!label) return ''
return label
.replace(/<|≤|<=/g, '<')
.replace(/>|≥|>=/g, '>')
.replace(/\s/g, '')
.toLowerCase()
}

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.

⚠️ Potential issue | 🟠 Major

Same regex alternation ordering issue as in render.jsx.

The regex /<|≤|<=/g will not properly normalize <= to < because < matches first. This causes tier matching failures when one side uses <= and the other uses .

🐛 Proposed fix: reorder alternatives to match longer sequences first
 export function normalizeTierLabel(label: string | undefined): string {
   if (!label) return ''
   return label
-    .replace(/<|≤|<=/g, '<')
-    .replace(/>|≥|>=/g, '>')
+    .replace(/<=|≤|</g, '<')
+    .replace(/>=|≥|>/g, '>')
     .replace(/\s/g, '')
     .toLowerCase()
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/default/src/features/usage-logs/lib/format.ts` around lines 184 - 191, In
normalizeTierLabel, the regex alternation orders shorter tokens before longer
ones so "<" matches before "<=" and prevents normalizing "<=" to "<"; update the
patterns used in normalizeTierLabel (the two .replace calls that target <=/≤/<
and >=/≥/> ) to list longer sequences first (e.g., match "<=" before "<" and
">=" before ">") so the multi-character operators normalize correctly while
keeping the subsequent .replace(/\s/g, '') and .toLowerCase() calls intact.

@wans10 wans10 closed this by deleting the head repository Apr 29, 2026
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.

1 participant