Skip to content

Dev open video - #4382

Closed
0xheliuni wants to merge 15 commits into
QuantumNous:mainfrom
0xheliuni:dev-open-video
Closed

Dev open video#4382
0xheliuni wants to merge 15 commits into
QuantumNous:mainfrom
0xheliuni:dev-open-video

Conversation

@0xheliuni

@0xheliuni 0xheliuni commented Apr 22, 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 AIGC video generation support with multiple model options (Vidu, Kling, Hunyuan, and others).
    • Introduced video API endpoints for task creation and progress querying.
  • Documentation

    • Added local development setup guide for Windows environments.
    • Added OpenAPI specifications for video generation APIs.
  • Chores

    • Consolidated CI/CD workflows; updated production and test build pipelines.
    • Removed legacy build workflows and external sync processes.

自动同步上游
chore: 初始化 CI/CD 流水线与自动同步配置
- 新增 constant.ChannelTypeAIGCVideo 类型及其基础配置
- 在 endpoint_defaults.go 添加 OpenAIVideo 接口路径
- 更新 endpoint_type.go 支持 AIGCVideo 渠道类型映射
- 实现 relay/channel/task/aigc 下全新任务适配器及常量定义
- 在 relay_adaptor.go 添加 AIGCVideo 渠道任务适配器实例
- 增加 controller/channel-test.go 中 AIGCVideo 渠道的测试函数及流程
- 在 middleware/distributor.go 设置 AIGCVideo 特殊上下文参数 region
- 在 model_ratio.go 新增 AIGC Video 系列模型的价格配置
- 在前端常量及编辑模态框中添加 AIGC Video 渠道选项及认证说明
- 更新前端渠道模型列表支持 AIGC Video 系列模型
- 新增 LOCAL_DEV_GUIDE.md,补充 Windows 本地开发环境启动指南文档
- 兼顾安全性采用 HMAC-SHA256 签名认证方式完成请求鉴权
- 实现任务查询接口,可获取视频生成任务的状态及结果URL
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR refactors CI/CD workflows (removes deprecated alpha, arm64, electron, and gitee-sync workflows; adds new prod-cd and test-ci pipelines), introduces comprehensive AIGC video channel support with task adaptor implementation, adds video model pricing entries, updates frontend channel configuration, and provides Windows local development documentation.

Changes

Cohort / File(s) Summary
GitHub Actions Workflow Restructuring
.github/workflows/prod-cd.yml, .github/workflows/test-ci.yml, .github/workflows/docker-image-alpha.yml, .github/workflows/docker-image-arm64.yml, .github/workflows/electron-build.yml, .github/workflows/sync-to-gitee.yml
Removed four legacy workflows (alpha/arm64 multi-arch builds with manifest creation, Electron Windows build and release automation, Gitee release sync). Added prod-cd.yml for production Docker image builds on version tags (v\*) and test-ci.yml for test image builds on prod branch pushes, both using docker/metadata-action for semver tagging and multi-arch Buildx support.
AIGC Video Channel Type Definition
constant/channel.go
Added new channel type constant ChannelTypeAIGCVideo = 58 with corresponding base URL and name mappings.
AIGC Video Endpoint & Relay Support
common/endpoint_defaults.go, common/endpoint_type.go, relay/relay_adaptor.go
Extended endpoint type handling for OpenAI video (/v1/videos POST), updated channel-to-endpoint type resolution to recognize ChannelTypeAIGCVideo, and registered new task adaptor in relay dispatcher.
AIGC Video Task Adaptor Implementation
relay/channel/task/aigc/adaptor.go, relay/channel/task/aigc/constants.go
Implemented comprehensive task adaptor (337 lines) supporting video generation API integration: request validation and action determination, HMAC-SHA256 signature generation with SubAppId/SecretId/SecretKey credentials, request body reconstruction with model remapping, streaming response parsing, task polling via FetchTask, task status mapping, and OpenAI video format conversion.
Controller & Middleware Integration
controller/channel-test.go, middleware/distributor.go
Added channel test dispatch for ChannelTypeAIGCVideo with dedicated testAIGCVideoChannel function (103 lines) validating credentials, signing requests, and handling error responses; extended distributor to extract region from channel metadata.
Video Model Pricing
setting/ratio_setting/model_ratio.go
Added default pricing entries for 26+ video model variants across Vidu, Kling, Hunyuan, Mingmou, OS, GV, Hailuo, SV, and JV model families.
Frontend Channel Configuration
web/src/constants/channel.constants.js, web/src/components/table/channels/modals/EditChannelModal.jsx
Added AIGC Video (type 58, violet color) to channel options and extended EditChannelModal with model list initialization and credential format guidance (SubAppId|SecretId|SecretKey\[|Region\]).
Documentation
LOCAL_DEV_GUIDE.md
Added comprehensive Windows local development guide covering environment setup, project structure, .env configuration, frontend and backend runtime modes, troubleshooting, and recommended dual-terminal workflow.
AIGC Video API Specifications
国产视频模型文档-AIGC/...
Added three OpenAPI 3.0.1 documentation files (国产视频模型全系列文档.txt, 视频接口.txt, 任务查询.txt) defining video generation and task query endpoints, request/response schemas, parameter mappings, authentication, model pricing table, and usage examples.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • seefs001
  • creamlike1024
  • xyfacai

Poem

🐰 A video channel hops to life,
With signatures signed and models thriving—
CI flows sleeker, docs now bright,
Windows devs no longer striving!
From AIGC dreams, productivity springs,
And workflows soar on Buildx wings! 🎬✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Dev open video' is vague and generic; it does not clearly convey the specific change (adding AIGC Video channel support). Revise the title to be more descriptive, such as 'Add AIGC Video channel integration with task generation and polling' or 'Support new AIGC Video channel type with video generation endpoints'.
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
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.
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.

Actionable comments posted: 12

🧹 Nitpick comments (3)
LOCAL_DEV_GUIDE.md (2)

224-230: Add language identifier to fenced code block.

The code block showing the recommended development workflow should specify a language identifier (e.g., text or bash) for consistent rendering.

📝 Suggested fix
-```
+```text
 终端 1(后端):  go run main.go
 终端 2(前端):  cd web && bun run dev
 浏览器:         http://localhost:5173
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@LOCAL_DEV_GUIDE.md` around lines 224 - 230, The fenced code block showing the
dev workflow lacks a language identifier; update the triple-backtick fence that
wraps the three-line snippet (the block containing "终端 1(后端):  go run main.go",
"终端 2(前端):  cd web && bun run dev", and "浏览器:         http://localhost:5173") to
include a language tag such as text or bash (e.g., change ``` to ```text) so the
block renders consistently.

33-41: Add language identifier to fenced code block.

The code block showing the project structure should specify a language identifier (e.g., text or plaintext) for better rendering and accessibility.

📝 Suggested fix
-```
+```text
 new-api/
 ├── main.go              # 后端入口
 ├── web/                 # React 前端(Vite + Semi Design)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@LOCAL_DEV_GUIDE.md` around lines 33 - 41, The fenced code block containing
the project tree (starting with "new-api/" and the lines with "main.go", "web/",
".env.example", "go.mod", "web/package.json") is missing a language identifier;
update the opening fence from ``` to include a plain-text identifier such as
```text or ```plaintext so the block renders/accessibility metadata correctly
(e.g., change the opening fence immediately before "new-api/" to ```text).
web/src/components/table/channels/modals/EditChannelModal.jsx (1)

653-662: Avoid maintaining another hard-coded AIGC model list.

This list duplicates the backend AIGC ModelList and pricing/docs model lists, so future additions can become selectable-but-unpriced or priced-but-unselectable. Prefer centralizing type 58 defaults in getChannelModels(58) or returning them from the backend.

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

In `@web/src/components/table/channels/modals/EditChannelModal.jsx` around lines
653 - 662, The hard-coded AIGC Video model array in EditChannelModal.jsx
duplicates backend model lists; replace the literal list in the case 58 branch
with a call to the centralized source (e.g., use getChannelModels(58) or the
backend-provided model list) so the UI consumes the single canonical model list;
update imports/params to access getChannelModels (or call the existing API
helper used elsewhere), set localModels = getChannelModels(58) (or assign the
fetched backend result) and remove the inline array to avoid desynchronization
with backend ModelList/pricing lists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/prod-cd.yml:
- Around line 1-47: The workflow defined as "Build and Release Production"
contains a misplaced file that will not be executed; delete the redundant
inactive workflow file and merge its important build steps into the existing
prod-cd workflow: copy the build-job "build-prod-image" additions
(docker/setup-buildx-action@v3 step, the docker/build-push-action@v5 fields
platforms: linux/amd64,linux/arm64 and cache-from/cache-to settings, and any
meta step tags/labels usage) into the active prod-cd workflow so the multi-arch
build and GHA cache configuration are preserved, then remove the inactive file
to avoid duplication.

In @.github/test-ci.yml:
- Around line 1-37: The file containing the workflow named "Build for Test
Environment" with job "build-test-image" is a duplicate and inert (GitHub only
runs workflows placed in the workflows directory); delete this duplicate
workflow file (the one defining the "Build for Test Environment" workflow and
"build-test-image" job) from the repo so maintainers won't edit a non-running
copy, and verify the functional workflow remains in the active workflows
location.

In @.github/workflows/prod-cd.yml:
- Around line 1-47: There are two copies of the production CD workflow; keep the
one that actually runs (the workflow with name "Build Production Release" and
job "build-and-push-prod") and delete the duplicate file that lives outside the
workflows folder; before deleting, merge the missing multi-arch/buildx/cache
steps into this active workflow by adding the buildx setup and cache actions
into the "Build and push Production Docker image" stage (refer to step names
like "Log in to the Container registry", "Extract metadata for Docker", and the
build-push action) so the consolidated workflow includes multi-arch builds,
buildx setup, and caching, then remove the orphaned copy to leave a single
source of truth.
- Around line 4-7: The push tag trigger currently uses a loose glob 'v*' which
will match non-release tags; update the GitHub Actions trigger in the workflow
(the on: push: tags: entry) to use a SemVer-restricted pattern (e.g., 'v*.*.*'
or a full semver regex) to match only release tags and align with the sibling
workflow; modify the tags value in the .github/workflows/prod-cd.yml workflow's
on.push.tags from 'v*' to the tighter SemVer pattern so both workflows are
consistent.
- Around line 41-47: The workflow currently uses docker/build-push-action@v5 but
dropped multi-arch and build cache settings; add a prior step that runs
docker/setup-buildx-action@v3 to enable buildx, then update the
docker/build-push-action@v5 step (the step that uses tags: ${{
steps.meta.outputs.tags }} and labels: ${{ steps.meta.outputs.labels }}) to
include platforms: linux/amd64,linux/arm64 and cache settings (cache-from:
type=gha and cache-to: type=gha,mode=max) so builds are multi-arch and use
GitHub Actions cache; ensure the buildx setup step id is referenced if needed by
the build step.

In @.github/workflows/test-ci.yml:
- Around line 1-40: Remove the duplicate workflow file `.github/test-ci.yml` and
keep this workflow under `.github/workflows/`; delete the extraneous copy to
avoid confusion and stale drift. In the "Build and push Test Docker image" step
(docker/build-push-action@v5) update the tags configuration so you continue to
push the mutable :test tag but also push an immutable tag using the commit SHA
(e.g. add a second tag using ${{ github.sha }}), ensuring you reference the
existing "tags" key in that step rather than replacing it.

In `@controller/channel-test.go`:
- Around line 514-609: The testAIGCVideoChannel function returns testResult
values that set newAPIError but leave the result.context nil; update all returns
that include newAPIError (e.g., the "bad response status code" and "response
missing task id" return branches) to also set context: channel.Context (or the
channel's existing context field) so testAllChannels can safely read
result.context when handling enable/disable logic. Ensure any other branches
that construct newAPIError in testAIGCVideoChannel also populate the context
field with the channel's context.

In `@relay/channel/task/aigc/adaptor.go`:
- Around line 142-153: The billing size is currently read from req.Size (size :=
req.Size) but AIGC requests put resolution in metadata.output_config.resolution;
update the logic to prefer req.Metadata.OutputConfig.Resolution (or
Metadata.OutputConfig.Resolution) if present and non-empty, falling back to
req.Size, then compute ratios as before (use seconds variable and the ratios
map) and ensure the special-case checks for "1792x1024", "1024x1792", and
"1080P" also consider the metadata-based resolution value so 1080P submitted via
metadata is charged correctly.
- Around line 254-274: The request signing block in adaptor.go must fail fast
when the parsed `key` doesn't contain at least three pipe-delimited parts: in
the function that builds/signs the polling request (e.g., FetchTask), validate
the credential string before making the HTTP request and return an error if
`strings.Split(key, "|")` yields fewer than 3 parts; do not send an unsigned
request. Also prefer per-task credentials by using `task.PrivateData.Key` (when
present and non-empty) over `channel.Key` for async video follow-up polling and
ensure the caller supplies that per-task key into the signing logic so the
X-SubAppId/X-SecretId/X-Timestamp/X-Signature headers are only set when a valid
key is provided.

In `@国产视频模型文档-AIGC/任务查询.txt`:
- Around line 26-32: The OpenAPI snippet only documents Authorization but the
implementation uses HMAC headers; update the spec to add header parameters for
X-SubAppId, X-SecretId, X-Timestamp, X-Signature (required string headers) and
X-Region (optional string) alongside or instead of the bearer Authorization
entry so consumers can reproduce the auth flow; for each header (X-SubAppId,
X-SecretId, X-Timestamp, X-Signature, X-Region) add description, in: header,
type: string, and example values and mark X-Region optional while the others are
required.

In `@国产视频模型文档-AIGC/视频接口.txt`:
- Around line 47-65: The example payload is missing the required aspect_ratio
under metadata.output_config; update the example so metadata.output_config
includes both required fields resolution and aspect_ratio (and any other
required nested fields), and verify the top-level required keys model, prompt,
and metadata are present; ensure the example mirrors the schema structure
exactly (e.g., metadata.output_config.resolution and
metadata.output_config.aspect_ratio) so generated clients and contract tests
accept it—apply the same fix to the other example instances referenced around
the same block.
- Around line 20-26: The spec currently documents only an Authorization header
(the "Authorization" header block) but the implementation uses HMAC-style
headers; update the OpenAPI header definitions to replace or supplement the
Authorization bearer example with explicit headers: X-SubAppId, X-SecretId,
X-Timestamp, X-Signature, and optional X-Region (each as required/optional with
type: string and an example value), and similarly update the other duplicated
header blocks referenced (around the section noted 128-139) so consumers can
construct the HMAC signing headers correctly when testing the channel.

---

Nitpick comments:
In `@LOCAL_DEV_GUIDE.md`:
- Around line 224-230: The fenced code block showing the dev workflow lacks a
language identifier; update the triple-backtick fence that wraps the three-line
snippet (the block containing "终端 1(后端):  go run main.go", "终端 2(前端):  cd web &&
bun run dev", and "浏览器:         http://localhost:5173") to include a language
tag such as text or bash (e.g., change ``` to ```text) so the block renders
consistently.
- Around line 33-41: The fenced code block containing the project tree (starting
with "new-api/" and the lines with "main.go", "web/", ".env.example", "go.mod",
"web/package.json") is missing a language identifier; update the opening fence
from ``` to include a plain-text identifier such as ```text or ```plaintext so
the block renders/accessibility metadata correctly (e.g., change the opening
fence immediately before "new-api/" to ```text).

In `@web/src/components/table/channels/modals/EditChannelModal.jsx`:
- Around line 653-662: The hard-coded AIGC Video model array in
EditChannelModal.jsx duplicates backend model lists; replace the literal list in
the case 58 branch with a call to the centralized source (e.g., use
getChannelModels(58) or the backend-provided model list) so the UI consumes the
single canonical model list; update imports/params to access getChannelModels
(or call the existing API helper used elsewhere), set localModels =
getChannelModels(58) (or assign the fetched backend result) and remove the
inline array to avoid desynchronization with backend ModelList/pricing lists.
🪄 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: 82479e7f-8b05-455b-a53a-a24218176ab3

📥 Commits

Reviewing files that changed from the base of the PR and between f995a86 and f11cedb.

⛔ Files ignored due to path filters (1)
  • web/bun.lock is excluded by !**/*.lock
📒 Files selected for processing (24)
  • .github/prod-cd.yml
  • .github/test-ci.yml
  • .github/workflows/docker-image-alpha.yml
  • .github/workflows/docker-image-arm64.yml
  • .github/workflows/electron-build.yml
  • .github/workflows/prod-cd.yml
  • .github/workflows/sync-to-gitee.yml
  • .github/workflows/test-ci.yml
  • LOCAL_DEV_GUIDE.md
  • common/endpoint_defaults.go
  • common/endpoint_type.go
  • constant/channel.go
  • controller/channel-test.go
  • middleware/distributor.go
  • relay/channel/task/aigc/adaptor.go
  • relay/channel/task/aigc/constants.go
  • relay/relay_adaptor.go
  • review_diff.txt
  • setting/ratio_setting/model_ratio.go
  • web/src/components/table/channels/modals/EditChannelModal.jsx
  • web/src/constants/channel.constants.js
  • 国产视频模型文档-AIGC/任务查询.txt
  • 国产视频模型文档-AIGC/国产视频模型全系列文档.txt
  • 国产视频模型文档-AIGC/视频接口.txt
💤 Files with no reviewable changes (4)
  • .github/workflows/electron-build.yml
  • .github/workflows/sync-to-gitee.yml
  • .github/workflows/docker-image-arm64.yml
  • .github/workflows/docker-image-alpha.yml

Comment thread .github/prod-cd.yml
Comment on lines +1 to +47
name: Build and Release Production

on:
push:
tags:
- 'v*.*.*'

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-prod-image:
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v4

- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=semver,pattern={{version}}
type=raw,value=latest

- uses: docker/setup-buildx-action@v3

- uses: docker/build-push-action@v5
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

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 | 🔴 Critical

This file is in the wrong location and will never run.

GitHub Actions only discovers workflows under .github/workflows/. A file at .github/prod-cd.yml is inert — it will not trigger on tag pushes despite the on: push: tags block. Given .github/workflows/prod-cd.yml already exists in this PR, please delete this file and instead merge its extra steps (buildx setup, platforms: linux/amd64,linux/arm64, gha cache) into .github/workflows/prod-cd.yml, otherwise the multi-arch and caching configuration that appears to be the whole point of this file is silently lost.

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

In @.github/prod-cd.yml around lines 1 - 47, The workflow defined as "Build and
Release Production" contains a misplaced file that will not be executed; delete
the redundant inactive workflow file and merge its important build steps into
the existing prod-cd workflow: copy the build-job "build-prod-image" additions
(docker/setup-buildx-action@v3 step, the docker/build-push-action@v5 fields
platforms: linux/amd64,linux/arm64 and cache-from/cache-to settings, and any
meta step tags/labels usage) into the active prod-cd workflow so the multi-arch
build and GHA cache configuration are preserved, then remove the inactive file
to avoid duplication.

Comment thread .github/test-ci.yml
Comment on lines +1 to +37
# .github/workflows/test-ci.yml
name: Build for Test Environment

on:
push:
branches:
- prod # 只监听 prod 分支的变更

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-test-image:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push Test Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
# 固定打上 test 标签,供测试服务器拉取
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:test

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

This file is in the wrong location and will never run.

Same issue as .github/prod-cd.yml: GitHub Actions only picks up workflow YAML under .github/workflows/. This file at .github/test-ci.yml is a no-op. The functionally identical .github/workflows/test-ci.yml already covers this trigger, so please delete this duplicate to prevent future maintainers from editing the inert copy.

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

In @.github/test-ci.yml around lines 1 - 37, The file containing the workflow
named "Build for Test Environment" with job "build-test-image" is a duplicate
and inert (GitHub only runs workflows placed in the workflows directory); delete
this duplicate workflow file (the one defining the "Build for Test Environment"
workflow and "build-test-image" job) from the repo so maintainers won't edit a
non-running copy, and verify the functional workflow remains in the active
workflows location.

Comment on lines +1 to +47
name: Build Production Release

# 触发条件:当推送以 'v' 开头的 tag 时触发
on:
push:
tags:
- 'v*'

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build-and-push-prod:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Log in to the Container registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# 自动提取你打的 Tag 版本号,并附加一个 latest 标签
tags: |
type=semver,pattern={{version}}
type=raw,value=latest

- name: Build and push Production Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

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.

🛠️ Refactor suggestion | 🟠 Major

Duplicate of .github/prod-cd.yml — consolidate into this single file.

.github/prod-cd.yml sits outside .github/workflows/ so GitHub Actions will not run it; this copy is the one that actually executes. Please delete .github/prod-cd.yml after folding the missing multi-arch/buildx/cache steps (see the other comment) into this file, so there is one source of truth.

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

In @.github/workflows/prod-cd.yml around lines 1 - 47, There are two copies of
the production CD workflow; keep the one that actually runs (the workflow with
name "Build Production Release" and job "build-and-push-prod") and delete the
duplicate file that lives outside the workflows folder; before deleting, merge
the missing multi-arch/buildx/cache steps into this active workflow by adding
the buildx setup and cache actions into the "Build and push Production Docker
image" stage (refer to step names like "Log in to the Container registry",
"Extract metadata for Docker", and the build-push action) so the consolidated
workflow includes multi-arch builds, buildx setup, and caching, then remove the
orphaned copy to leave a single source of truth.

Comment on lines +4 to +7
on:
push:
tags:
- 'v*'

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 | 🟡 Minor

Tag filter inconsistency with the sibling file.

This workflow triggers on v* while .github/prod-cd.yml (the duplicate) triggers on v*.*.*. v* will also match non-release tags such as v1-rc, vtest, etc., which can accidentally cut a production release and publish :latest. Tighten to SemVer to match intent:

     tags:
-      - 'v*'
+      - 'v*.*.*'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
on:
push:
tags:
- 'v*'
on:
push:
tags:
- 'v*.*.*'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/prod-cd.yml around lines 4 - 7, The push tag trigger
currently uses a loose glob 'v*' which will match non-release tags; update the
GitHub Actions trigger in the workflow (the on: push: tags: entry) to use a
SemVer-restricted pattern (e.g., 'v*.*.*' or a full semver regex) to match only
release tags and align with the sibling workflow; modify the tags value in the
.github/workflows/prod-cd.yml workflow's on.push.tags from 'v*' to the tighter
SemVer pattern so both workflows are consistent.

Comment on lines +41 to +47
- name: Build and push Production Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

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

Regression: multi-arch (arm64) builds and build cache were dropped.

Comparing with the near-duplicate .github/prod-cd.yml and the removed docker-image-arm64.yml workflow mentioned in the PR summary, this workflow is missing:

  • docker/setup-buildx-action@v3 (required for multi-platform builds)
  • platforms: linux/amd64,linux/arm64
  • cache-from: type=gha / cache-to: type=gha,mode=max

As written, production releases will publish amd64 only, silently breaking arm64 consumers that the previous workflows supported. Please restore these:

🔧 Proposed fix
+      - name: Set up Docker Buildx
+        uses: docker/setup-buildx-action@v3
+
       - name: Build and push Production Docker image
         uses: docker/build-push-action@v5
         with:
           context: .
           push: true
+          platforms: linux/amd64,linux/arm64
           tags: ${{ steps.meta.outputs.tags }}
           labels: ${{ steps.meta.outputs.labels }}
+          cache-from: type=gha
+          cache-to: type=gha,mode=max
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Build and push Production Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Production Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/prod-cd.yml around lines 41 - 47, The workflow currently
uses docker/build-push-action@v5 but dropped multi-arch and build cache
settings; add a prior step that runs docker/setup-buildx-action@v3 to enable
buildx, then update the docker/build-push-action@v5 step (the step that uses
tags: ${{ steps.meta.outputs.tags }} and labels: ${{ steps.meta.outputs.labels
}}) to include platforms: linux/amd64,linux/arm64 and cache settings
(cache-from: type=gha and cache-to: type=gha,mode=max) so builds are multi-arch
and use GitHub Actions cache; ensure the buildx setup step id is referenced if
needed by the build step.

Comment on lines +142 to +153
size := req.Size
if size == "" {
size = "720x1280"
}

ratios := map[string]float64{
"seconds": float64(seconds),
"size": 1,
}
if size == "1792x1024" || size == "1024x1792" || size == "1080P" {
ratios["size"] = 1.666667
}

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

Use metadata.output_config.resolution for billing size.

AIGC requests document and send resolution under metadata.output_config.resolution, but billing only checks top-level size; 1080P requests submitted through the documented shape will be charged with size = 1.

💰 Suggested billing fix
 	size := req.Size
+	if size == "" && req.Metadata != nil {
+		if outputConfig, ok := req.Metadata["output_config"].(map[string]interface{}); ok {
+			if resolution, ok := outputConfig["resolution"].(string); ok {
+				size = strings.TrimSpace(resolution)
+			}
+		}
+	}
 	if size == "" {
 		size = "720x1280"
 	}
@@
-	if size == "1792x1024" || size == "1024x1792" || size == "1080P" {
+	normalizedSize := strings.ToUpper(size)
+	if normalizedSize == "1792X1024" || normalizedSize == "1024X1792" || normalizedSize == "1080P" {
 		ratios["size"] = 1.666667
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
size := req.Size
if size == "" {
size = "720x1280"
}
ratios := map[string]float64{
"seconds": float64(seconds),
"size": 1,
}
if size == "1792x1024" || size == "1024x1792" || size == "1080P" {
ratios["size"] = 1.666667
}
size := req.Size
if size == "" && req.Metadata != nil {
if outputConfig, ok := req.Metadata["output_config"].(map[string]interface{}); ok {
if resolution, ok := outputConfig["resolution"].(string); ok {
size = strings.TrimSpace(resolution)
}
}
}
if size == "" {
size = "720x1280"
}
ratios := map[string]float64{
"seconds": float64(seconds),
"size": 1,
}
normalizedSize := strings.ToUpper(size)
if normalizedSize == "1792X1024" || normalizedSize == "1024X1792" || normalizedSize == "1080P" {
ratios["size"] = 1.666667
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/channel/task/aigc/adaptor.go` around lines 142 - 153, The billing size
is currently read from req.Size (size := req.Size) but AIGC requests put
resolution in metadata.output_config.resolution; update the logic to prefer
req.Metadata.OutputConfig.Resolution (or Metadata.OutputConfig.Resolution) if
present and non-empty, falling back to req.Size, then compute ratios as before
(use seconds variable and the ratios map) and ensure the special-case checks for
"1792x1024", "1024x1792", and "1080P" also consider the metadata-based
resolution value so 1080P submitted via metadata is charged correctly.

Comment on lines +254 to +274
// Parse pipe-separated key and set auth headers
parts := strings.Split(key, "|")
if len(parts) >= 3 {
subAppId := parts[0]
secretId := parts[1]
secretKey := parts[2]

timestamp := strconv.FormatInt(time.Now().Unix(), 10)
signStr := fmt.Sprintf("%s\n%s\n%s", secretId, timestamp, secretKey)
h := hmac.New(sha256.New, []byte(secretKey))
h.Write([]byte(signStr))
signature := hex.EncodeToString(h.Sum(nil))

req.Header.Set("X-SubAppId", subAppId)
req.Header.Set("X-SecretId", secretId)
req.Header.Set("X-Timestamp", timestamp)
req.Header.Set("X-Signature", signature)
if len(parts) >= 4 && parts[3] != "" {
req.Header.Set("X-Region", parts[3])
}
}

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

Fail fast when polling credentials are malformed.

If key has fewer than three pipe-delimited parts, FetchTask still sends an unsigned request and turns a local configuration/auth-context problem into an upstream polling failure. Return an error before issuing the request, and make sure the caller passes the captured per-task key when available. Based on learnings, task.PrivateData.Key may hold a per-task key that should be preferred over channel.Key for async video follow-up requests.

🔐 Suggested validation
 	// Parse pipe-separated key and set auth headers
 	parts := strings.Split(key, "|")
-	if len(parts) >= 3 {
-		subAppId := parts[0]
-		secretId := parts[1]
-		secretKey := parts[2]
+	if len(parts) < 3 || strings.TrimSpace(parts[0]) == "" || strings.TrimSpace(parts[1]) == "" || strings.TrimSpace(parts[2]) == "" {
+		return nil, fmt.Errorf("invalid AIGC key format, expected SubAppId|SecretId|SecretKey[|Region]")
+	}
+	subAppId := parts[0]
+	secretId := parts[1]
+	secretKey := parts[2]
 
-		timestamp := strconv.FormatInt(time.Now().Unix(), 10)
-		signStr := fmt.Sprintf("%s\n%s\n%s", secretId, timestamp, secretKey)
-		h := hmac.New(sha256.New, []byte(secretKey))
-		h.Write([]byte(signStr))
-		signature := hex.EncodeToString(h.Sum(nil))
+	timestamp := strconv.FormatInt(time.Now().Unix(), 10)
+	signStr := fmt.Sprintf("%s\n%s\n%s", secretId, timestamp, secretKey)
+	h := hmac.New(sha256.New, []byte(secretKey))
+	h.Write([]byte(signStr))
+	signature := hex.EncodeToString(h.Sum(nil))
 
-		req.Header.Set("X-SubAppId", subAppId)
-		req.Header.Set("X-SecretId", secretId)
-		req.Header.Set("X-Timestamp", timestamp)
-		req.Header.Set("X-Signature", signature)
-		if len(parts) >= 4 && parts[3] != "" {
-			req.Header.Set("X-Region", parts[3])
-		}
+	req.Header.Set("X-SubAppId", subAppId)
+	req.Header.Set("X-SecretId", secretId)
+	req.Header.Set("X-Timestamp", timestamp)
+	req.Header.Set("X-Signature", signature)
+	if len(parts) >= 4 && parts[3] != "" {
+		req.Header.Set("X-Region", parts[3])
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Parse pipe-separated key and set auth headers
parts := strings.Split(key, "|")
if len(parts) >= 3 {
subAppId := parts[0]
secretId := parts[1]
secretKey := parts[2]
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
signStr := fmt.Sprintf("%s\n%s\n%s", secretId, timestamp, secretKey)
h := hmac.New(sha256.New, []byte(secretKey))
h.Write([]byte(signStr))
signature := hex.EncodeToString(h.Sum(nil))
req.Header.Set("X-SubAppId", subAppId)
req.Header.Set("X-SecretId", secretId)
req.Header.Set("X-Timestamp", timestamp)
req.Header.Set("X-Signature", signature)
if len(parts) >= 4 && parts[3] != "" {
req.Header.Set("X-Region", parts[3])
}
}
// Parse pipe-separated key and set auth headers
parts := strings.Split(key, "|")
if len(parts) < 3 || strings.TrimSpace(parts[0]) == "" || strings.TrimSpace(parts[1]) == "" || strings.TrimSpace(parts[2]) == "" {
return nil, fmt.Errorf("invalid AIGC key format, expected SubAppId|SecretId|SecretKey[|Region]")
}
subAppId := parts[0]
secretId := parts[1]
secretKey := parts[2]
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
signStr := fmt.Sprintf("%s\n%s\n%s", secretId, timestamp, secretKey)
h := hmac.New(sha256.New, []byte(secretKey))
h.Write([]byte(signStr))
signature := hex.EncodeToString(h.Sum(nil))
req.Header.Set("X-SubAppId", subAppId)
req.Header.Set("X-SecretId", secretId)
req.Header.Set("X-Timestamp", timestamp)
req.Header.Set("X-Signature", signature)
if len(parts) >= 4 && parts[3] != "" {
req.Header.Set("X-Region", parts[3])
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@relay/channel/task/aigc/adaptor.go` around lines 254 - 274, The request
signing block in adaptor.go must fail fast when the parsed `key` doesn't contain
at least three pipe-delimited parts: in the function that builds/signs the
polling request (e.g., FetchTask), validate the credential string before making
the HTTP request and return an error if `strings.Split(key, "|")` yields fewer
than 3 parts; do not send an unsigned request. Also prefer per-task credentials
by using `task.PrivateData.Key` (when present and non-empty) over `channel.Key`
for async video follow-up polling and ensure the caller supplies that per-task
key into the signing logic so the X-SubAppId/X-SecretId/X-Timestamp/X-Signature
headers are only set when a valid key is provided.

Comment on lines +26 to +32
- name: Authorization
in: header
description: ''
example: '{{Authorization}}'
schema:
type: string
default: '{{Authorization}}'

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 | 🟡 Minor

Document the HMAC headers used by the implementation.

The AIGC adaptor signs task-query requests with X-SubAppId, X-SecretId, X-Timestamp, X-Signature, and optional X-Region, but this spec only documents a bearer Authorization header. Consumers following this doc will not be able to reproduce the implemented auth flow.

📝 Suggested doc adjustment
-        - name: Authorization
+        - name: X-SubAppId
           in: header
-          description: ''
-          example: '{{Authorization}}'
+          description: AIGC sub application id
           schema:
             type: string
-            default: '{{Authorization}}'
+        - name: X-SecretId
+          in: header
+          description: AIGC secret id
+          schema:
+            type: string
+        - name: X-Timestamp
+          in: header
+          description: Unix timestamp used in the signature string
+          schema:
+            type: string
+        - name: X-Signature
+          in: header
+          description: HMAC-SHA256 signature
+          schema:
+            type: string
+        - name: X-Region
+          in: header
+          required: false
+          description: Optional AIGC region
+          schema:
+            type: string

Also applies to: 117-128

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

In `@国产视频模型文档-AIGC/任务查询.txt` around lines 26 - 32, The OpenAPI snippet only
documents Authorization but the implementation uses HMAC headers; update the
spec to add header parameters for X-SubAppId, X-SecretId, X-Timestamp,
X-Signature (required string headers) and X-Region (optional string) alongside
or instead of the bearer Authorization entry so consumers can reproduce the auth
flow; for each header (X-SubAppId, X-SecretId, X-Timestamp, X-Signature,
X-Region) add description, in: header, type: string, and example values and mark
X-Region optional while the others are required.

Comment on lines +20 to +26
- name: Authorization
in: header
description: ''
required: false
example: Bearer {{key}}
schema:
type: string

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 | 🟡 Minor

Document the actual AIGC signing headers instead of bearer auth only.

The implementation sends HMAC authentication headers, not just Authorization: Bearer .... This spec should list X-SubAppId, X-SecretId, X-Timestamp, X-Signature, and optional X-Region so operators can configure and test the channel correctly.

Also applies to: 128-139

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

In `@国产视频模型文档-AIGC/视频接口.txt` around lines 20 - 26, The spec currently documents
only an Authorization header (the "Authorization" header block) but the
implementation uses HMAC-style headers; update the OpenAPI header definitions to
replace or supplement the Authorization bearer example with explicit headers:
X-SubAppId, X-SecretId, X-Timestamp, X-Signature, and optional X-Region (each as
required/optional with type: string and an example value), and similarly update
the other duplicated header blocks referenced (around the section noted 128-139)
so consumers can construct the HMAC signing headers correctly when testing the
channel.

Comment on lines +47 to +65
required:
- resolution
- aspect_ratio
x-apifox-orders:
- resolution
- aspect_ratio
required:
- output_config
x-apifox-orders:
- output_config
required:
- model
- prompt
- metadata
x-apifox-orders:
- model
- prompt
- metadata
example:

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 | 🟡 Minor

Make the example satisfy the declared required schema.

aspect_ratio is required by the schema, but the example omits it under metadata.output_config, so generated clients or contract tests will reject the sample payload.

📝 Suggested example fix
                 output_config:
                   resolution: 1080P
+                  aspect_ratio: '16:9'
                   audio_generation: Enabled

Also applies to: 75-78

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

In `@国产视频模型文档-AIGC/视频接口.txt` around lines 47 - 65, The example payload is missing
the required aspect_ratio under metadata.output_config; update the example so
metadata.output_config includes both required fields resolution and aspect_ratio
(and any other required nested fields), and verify the top-level required keys
model, prompt, and metadata are present; ensure the example mirrors the schema
structure exactly (e.g., metadata.output_config.resolution and
metadata.output_config.aspect_ratio) so generated clients and contract tests
accept it—apply the same fix to the other example instances referenced around
the same block.

@0xheliuni 0xheliuni closed this Apr 22, 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