viduq2视频模型兼容不同生成方式的适配 - #2216
Conversation
… improve error reporting
…eletion and improve user feedback
…for improved customization
fix: improve text visibility in warning box for dark mode in SettingsLog
Implement comprehensive topup billing system with user history viewing and admin management capabilities.
## Features Added
### Frontend
- Add topup history modal with paginated billing records
- Display order details: trade number, payment method, amount, money, status, create time
- Implement empty state with proper illustrations
- Add payment method column with localized display (Stripe, Alipay, WeChat)
- Add admin manual completion feature for pending orders
- Add Coins icon for recharge amount display
- Integrate "Bills" button in RechargeCard header
- Optimize code quality by using shared utility functions (isAdmin)
- Extract constants for status and payment method mappings
- Use React.useMemo for performance optimization
### Backend
- Create GET `/api/user/topup/self` endpoint for user topup history with pagination
- Create POST `/api/user/topup/complete` endpoint for admin manual order completion
- Add `payment_method` field to TopUp model for tracking payment types
- Implement `GetUserTopUps` method with proper pagination and ordering
- Implement `ManualCompleteTopUp` with transaction safety and row-level locking
- Add application-level mutex locks to prevent concurrent order processing
- Record payment method in Epay and Stripe payment flows
- Ensure idempotency and data consistency with proper error handling
### Internationalization
- Add i18n keys for Chinese (zh), English (en), and French (fr)
- Support for billing-related UI text and status messages
## Technical Improvements
- Use database transactions with FOR UPDATE row-level locking
- Implement sync.Map-based mutex for order-level concurrency control
- Proper error handling and user-friendly toast notifications
- Follow existing codebase patterns for empty states and modals
- Maintain code quality with extracted render functions and constants
## Files Changed
- Backend: controller/topup.go, controller/topup_stripe.go, model/topup.go, router/api-router.go
- Frontend: web/src/components/topup/modals/TopupHistoryModal.jsx (new), web/src/components/topup/RechargeCard.jsx, web/src/components/topup/index.jsx
- i18n: web/src/i18n/locales/{zh,en,fr}.json
Allow administrators to view all platform topup orders and streamline admin-only routes. Frontend - TopupHistoryModal: dynamically switch endpoint by role - Admin → GET /api/user/topup (all orders) - Non-admin → GET /api/user/topup/self (own orders) - Use shared utils `isAdmin()`; keep logic centralized and DRY - Minor UI: set admin action button theme to outline for clarity Backend - model/topup.go: add GetAllTopUps(pageInfo) with pagination (ordered by id desc) - controller/topup.go: add GetAllTopUps handler returning PageInfo response - router/api-router.go: - Add admin route GET /api/user/topup (AdminAuth) - Move POST /api/user/topup/complete to adminRoute (keeps path stable, consolidates admin endpoints) Security/Behavior - Admin-only endpoints now reside under the admin route group with AdminAuth - No behavior change for regular users; no schema changes Affected files - model/topup.go - controller/topup.go - router/api-router.go - web/src/components/topup/modals/TopupHistoryModal.jsx
… user)
Enable searching topup records by trade_no across both admin-wide and user-only views.
Frontend
- TopupHistoryModal.jsx:
- Add search input with prefix icon (IconSearch) to filter by order number
- Send `keyword` query param to backend; works with both endpoints:
- Admin: GET /api/user/topup?p=1&page_size=10&keyword=...
- User: GET /api/user/topup/self?p=1&page_size=10&keyword=...
- Keep endpoint auto-switching based on role (isAdmin)
- Minor UI polish: outlined admin action button; keep Coins icon for amount
Backend
- model/topup.go:
- Add SearchUserTopUps(userId, keyword, pageInfo)
- Add SearchAllTopUps(keyword, pageInfo)
- Both support pagination and `trade_no LIKE %keyword%` filtering (ordered by id desc)
- controller/topup.go:
- GetUserTopUps / GetAllTopUps accept optional `keyword` and route to search functions when present
Routes
- No new endpoints; search is enabled via `keyword` on existing:
- GET /api/user/topup
- GET /api/user/topup/self
Affected files
- model/topup.go
- controller/topup.go
- web/src/components/topup/modals/TopupHistoryModal.jsx
✨ feat: Add topup billing history with admin manual completion
Add early return when Epay client is missing in controller/topup.go to avoid panic Introduce handleKeywordChange in TopupHistoryModal.jsx to reset page to 1 when keyword updates Wire input onChange to new handler; minor UX improvement to avoid empty results on pagination mismatch
❤ fix(topup): prevent nil-pointer in Epay callback; reset page on search
Extracted the User Agreement and Privacy Policy presentation into a reusable DocumentRenderer component (web/src/components/common/DocumentRenderer). Unified rendering logic and i18n source for these documents, removed the legacy contentDetector utility, and updated the related pages to use the new component. Adjusted controller/backend (controller/misc.go) and locale files to support the new rendering approach. This improves reuse, maintainability, and future extensibility.
zhipu_v4 usage
… to support Anthropic channel type
feat: gemini imagen quality value
…dels feat: add GetClaudeAuthHeader function and update FetchUpstreamModels to support Anthropic channel type
fix(openai): account cached tokens for zhipu_v4 usage
Bumps [electron](https://github.com/electron/electron) from 28.3.3 to 35.7.5. - [Release notes](https://github.com/electron/electron/releases) - [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md) - [Commits](electron/electron@v28.3.3...v35.7.5) --- updated-dependencies: - dependency-name: electron dependency-version: 35.7.5 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com>
…nd_yarn/electron/electron-35.7.5 chore(deps-dev): bump electron from 28.3.3 to 35.7.5 in /electron
feat: EditTokenModal 中针对用户创建的 token 默认无限额度
feat: add environment variable switch for critical rate limit
…80p-image fix: trim suffix p for jimeng image model
…space fix: tag splitting by whitespace
…odisable fix(channel): 当没有可用密钥时返回错误而不是第一个密钥
… new sections for partners, acknowledgments, and deployment instructions
- 更新中文README.md中的语言链接 - 完全重写英文README.en.md,包含所有详细功能说明 - 完全重写法文README.fr.md,确保内容一致性 - 完全重写日文README.ja.md,提供完整的项目说明 所有语言版本现在具有: - 相同的结构和格式 - 一致的语言导航 - 完整的功能特性和部署指南 - 统一的环境变量配置说明
…ence 修复viduq2不支持参考生视频的问题
…annel feat: replicate channel flux model
fix GetChannelKey AdminAuth -> RootAuth
fix GetChannelKey AdminAuth -> RootAuth
…future adjustments
WalkthroughThe changes extend model selection logic in the Vidu adaptor's BuildRequestBody function to handle multiple action types. ReferenceGenerate and TextGenerate now force "viduq2" variants, while Generate and FirstTailGenerate upgrade "viduq2" to "viduq2-turbo". Import reordering is also applied. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
relay/channel/task/vidu/adaptor.go(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-26T09:59:00.337Z
Learnt from: Sh1n3zZ
Repo: QuantumNous/new-api PR: 1659
File: relay/relay_task.go:285-305
Timestamp: 2025-08-26T09:59:00.337Z
Learning: In controller/task_video.go, the redactVideoResponseBody function sanitizes video task responses by removing bytesBase64Encoded fields and truncating base64 strings to 256 characters to prevent large binary data from being stored in task.Data.
Applied to files:
relay/channel/task/vidu/adaptor.go
🧬 Code graph analysis (1)
relay/channel/task/vidu/adaptor.go (1)
constant/task.go (4)
TaskActionReferenceGenerate(17-17)TaskActionTextGenerate(15-15)TaskActionGenerate(14-14)TaskActionFirstTailGenerate(16-16)
| switch info.Action { | ||
| case constant.TaskActionReferenceGenerate, constant.TaskActionTextGenerate: | ||
| // 参考图生视频和文生视频只能用 viduq2 模型, 不能带有pro或turbo后缀 https://platform.vidu.cn/docs/reference-to-video | ||
| if strings.Contains(body.Model, "viduq2") { | ||
| // 参考图生视频只能用 viduq2 模型, 不能带有pro或turbo后缀 https://platform.vidu.cn/docs/reference-to-video | ||
| body.Model = "viduq2" | ||
| } | ||
| case constant.TaskActionGenerate, constant.TaskActionFirstTailGenerate: | ||
| // 图生视频和首尾帧生视频只能用 viduq2-turbo 或 viduq2-pro | ||
| if body.Model == "viduq2" { | ||
| body.Model = "viduq2-turbo" | ||
| } | ||
| } |
There was a problem hiding this comment.
Add validation to reject invalid models for each action type.
The current logic partially adjusts models but doesn't validate that only permitted models are used for each action. According to the Vidu API requirements:
-
ReferenceGenerate & TextGenerate: Must use
viduq2only (no pro/turbo suffix)- Current: Forces viduq2 variants to
viduq2, but allows invalid models likeviduq1to pass through
- Current: Forces viduq2 variants to
-
Generate & FirstTailGenerate: Must use
viduq2-turboorviduq2-proonly- Current: Upgrades bare
viduq2toviduq2-turbo, but allows invalid models to pass through
- Current: Upgrades bare
If a user submits an incompatible model (e.g., viduq1 for Generate action), the request will fail at Vidu's API rather than being caught early with a clear error.
Consider this validation approach:
switch info.Action {
case constant.TaskActionReferenceGenerate, constant.TaskActionTextGenerate:
// 参考图生视频和文生视频只能用 viduq2 模型, 不能带有pro或turbo后缀 https://platform.vidu.cn/docs/reference-to-video
if strings.Contains(body.Model, "viduq2") {
body.Model = "viduq2"
+ } else {
+ return nil, fmt.Errorf("model %s is not supported for action %s, only viduq2 is allowed", body.Model, info.Action)
}
case constant.TaskActionGenerate, constant.TaskActionFirstTailGenerate:
// 图生视频和首尾帧生视频只能用 viduq2-turbo 或 viduq2-pro
if body.Model == "viduq2" {
body.Model = "viduq2-turbo"
+ } else if body.Model != "viduq2-turbo" && body.Model != "viduq2-pro" {
+ return nil, fmt.Errorf("model %s is not supported for action %s, only viduq2-turbo or viduq2-pro are allowed", body.Model, info.Action)
}
}📝 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.
| switch info.Action { | |
| case constant.TaskActionReferenceGenerate, constant.TaskActionTextGenerate: | |
| // 参考图生视频和文生视频只能用 viduq2 模型, 不能带有pro或turbo后缀 https://platform.vidu.cn/docs/reference-to-video | |
| if strings.Contains(body.Model, "viduq2") { | |
| // 参考图生视频只能用 viduq2 模型, 不能带有pro或turbo后缀 https://platform.vidu.cn/docs/reference-to-video | |
| body.Model = "viduq2" | |
| } | |
| case constant.TaskActionGenerate, constant.TaskActionFirstTailGenerate: | |
| // 图生视频和首尾帧生视频只能用 viduq2-turbo 或 viduq2-pro | |
| if body.Model == "viduq2" { | |
| body.Model = "viduq2-turbo" | |
| } | |
| } | |
| switch info.Action { | |
| case constant.TaskActionReferenceGenerate, constant.TaskActionTextGenerate: | |
| // 参考图生视频和文生视频只能用 viduq2 模型, 不能带有pro或turbo后缀 https://platform.vidu.cn/docs/reference-to-video | |
| if strings.Contains(body.Model, "viduq2") { | |
| body.Model = "viduq2" | |
| } else { | |
| return nil, fmt.Errorf("model %s is not supported for action %s, only viduq2 is allowed", body.Model, info.Action) | |
| } | |
| case constant.TaskActionGenerate, constant.TaskActionFirstTailGenerate: | |
| // 图生视频和首尾帧生视频只能用 viduq2-turbo 或 viduq2-pro | |
| if body.Model == "viduq2" { | |
| body.Model = "viduq2-turbo" | |
| } else if body.Model != "viduq2-turbo" && body.Model != "viduq2-pro" { | |
| return nil, fmt.Errorf("model %s is not supported for action %s, only viduq2-turbo or viduq2-pro are allowed", body.Model, info.Action) | |
| } | |
| } |
🤖 Prompt for AI Agents
In relay/channel/task/vidu/adaptor.go around lines 122 to 133, the code only
coerces some model values but does not validate allowed models per action; add
explicit validation so invalid models are rejected early: for
TaskActionReferenceGenerate and TaskActionTextGenerate accept only "viduq2"
(reject anything else with a descriptive error), and for TaskActionGenerate and
TaskActionFirstTailGenerate accept only "viduq2-turbo" or "viduq2-pro" (if
incoming is exactly "viduq2" you may coerce to "viduq2-turbo" but otherwise
reject unknown values); return a clear validation error before calling the Vidu
API when the model is not one of the permitted values.
图生视频和首尾帧生视频只能用 viduq2-turbo 或 viduq2-pro
参考图生视频和文生视频只能用 viduq2 , 不能带有pro或turbo后缀
https://platform.vidu.cn/docs/reference-to-video
Summary by CodeRabbit