feat: task reconsume log add taskId and ratio - #2633
Conversation
fix: volcengine && baidu claude adapter
fix: volcengine claude DoResponse
fix: volcengine claude DoResponse
…pro-image-preview-oai OAI生图接口支持gemini 3 pro image preview
…ageConfig fix: gemini image correct generationConfig
…ith i18n - Add SSEViewer component for interactive SSE message inspection * Display SSE data stream with collapsible panels * Show parsed JSON with syntax highlighting * Display key information badges (content, tokens, finish reason) * Support copy individual or all SSE messages * Show error messages with detailed information - Support Ctrl+V to paste images in chat input * Enable image paste in CustomInputRender component * Auto-detect and add pasted images to image list * Show toast notifications for paste results - Add complete i18n support for 6 languages * Chinese (zh): Complete translations * English (en): Complete translations * Japanese (ja): Add 28 new translations * French (fr): Add 28 new translations * Russian (ru): Add 28 new translations * Vietnamese (vi): Add 32 new translations - Update .gitignore to exclude data directory
…-i2v Gemini Veo3.1[AI Studio]增加图生视频支持
Ensure image file is closed using defer after opening.
…edit Gemini Image系列支持图像编辑
…d-oai feat: 视频下载和界面预览统一使用OAI标准接口
…-err-code fix(aws): extract HTTP status code from AWS SDK errors
…na-err fix: nano-banana not compatible imageSize
…nce-playground-debugging feat(playground): enhance SSE debugging and add image paste support with i18n
fix: nano banana pro 4k(StreamScannerMaxBufferMB env)
…QuantumNous#2556) * fix: fix model deployment style issues, lint problems, and i18n gaps. * fix: adjust the key not to be displayed on the frontend, tested via the backend. * fix: adjust the sidebar configuration logic to use the default configuration items if they are not defined.
…rride_trim_prefix
fix: 修复 gemini 文件类型不支持 image/jpg
…figuration && the AWS calling side did not apply the relay timeout.
fix: fix the proxyURL is empty, not using the default HTTP client configuration && the AWS calling side did not apply the relay timeout.
fix: add tips for model management and channel testing
问题描述: - 使用 auto 分组的令牌调用 /v1/videos 等 Task 接口时,虽然任务能成功创建, 但使用日志不显示记录,且不会扣费 根本原因: - Distribute 中间件在选择渠道后,会将实际选中的分组存储在 ContextKeyAutoGroup 中 - 但 RelayTaskSubmit 函数没有从 context 中读取这个值来更新 info.UsingGroup - 导致 info.UsingGroup 始终是 "auto" 而不是实际选中的分组(如 "sora2逆") - 当 auto 分组的倍率配置为 0 时,quota 计算结果为 0 - 日志记录条件 "if quota != 0" 不满足,导致日志不记录、不扣费 修复方案: - 在 RelayTaskSubmit 函数中计算分组倍率之前,添加从 ContextKeyAutoGroup 获取实际分组的逻辑 - 使用安全的类型断言,避免潜在的 panic 风险 影响范围: - 仅影响 Task Relay 流程(/v1/videos, /suno, /kling 等接口) - 不影响使用具体分组令牌的调用 - 不影响其他 Relay 类型(chat/completions 等已有类似处理逻辑)
…task-logging fix(task): 修复使用 auto 分组时 Task Relay 不记录日志和不扣费的问题
fix: 设置默认max req body 为128MB
Use the native Gemini Models API (/v1beta/models) instead of the OpenAI-compatible path when listing models for Gemini channels, improving compatibility with third-party Gemini-format providers that don't implement OpenAI routes. - Add paginated model listing with timeout and optional proxy support - Select an enabled key for multi-key Gemini channels
…etchModels fix: remove Minimax from FETCHABLE channels
…tchModels fix(gemini): fetch model list via native v1beta/models endpoint
WalkthroughEnhanced logging for video task quota reconciliation: two log calls in Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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 |
left a comment
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
controller/task_video.go (1)
181-233: Critical: quota adjustment can be applied twice iftask.Update()fails after charging/refunding.You adjust user quota (and channel usage) and only later persist the new
task.Quotaviatask.Update()(Line 197-203 vs Line 266). Iftask.Update()fails, the next polling run can recompute the samequotaDeltafrom the old persistedtask.Quotaand apply it again.Suggested direction (pick one):
- Persist the task’s
Quota/status change atomically with the quota adjustment (single DB transaction if feasible), or- Add a reconciliation marker (e.g., “reconciled_at” / “reconciled_tokens”) and guard the adjustment on it, or
- On
task.Update()failure, immediately attempt to rollback the quota adjustment (best-effort) and log loudly.
🧹 Nitpick comments (1)
controller/task_video.go (1)
205-210: De-duplicate the reconsume/refund log formatting + pass/record the actualmodelName.Both branches build near-identical
logContentand callRecordReConsumeLog. Consider extracting a small helper to avoid drift. Also, you computemodelRatiofrommodelNameparsed fromtask.Data, butRecordReConsumeLogcurrently persistsLog.ModelNamefromtask.Properties.UpstreamModelName—these may not match, so either passmodelNameinto the log call or store it inOther.Also applies to: 227-232
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
controller/task_video.gomodel/log.go
🧰 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:
controller/task_video.go
🧬 Code graph analysis (2)
model/log.go (4)
model/user.go (1)
GetUsernameById(883-908)common/utils.go (1)
GetTimestamp(261-263)common/str.go (1)
MapToJsonStr(37-43)model/main.go (1)
LOG_DB(66-66)
controller/task_video.go (2)
logger/logger.go (1)
LogQuota(99-124)model/log.go (1)
RecordReConsumeLog(413-438)
|
|
||
| func RecordReConsumeLog(task *Task, modelRatio float64, groupRatio float64, totalTokens int, preConsumedQuota int, actualQuota int, content string) { | ||
| username, _ := GetUsernameById(task.UserId, false) | ||
| quotaDelta := actualQuota - preConsumedQuota | ||
| other := map[string]interface{}{ | ||
| "task_id": task.TaskID, | ||
| "model_ratio": modelRatio, | ||
| "group_ratio": groupRatio, | ||
| "total_tokens": totalTokens, | ||
| "pre_consumed": preConsumedQuota, | ||
| "actual_quota": actualQuota, | ||
| "quota_delta": quotaDelta, | ||
| } | ||
| log := &Log{ | ||
| UserId: task.UserId, | ||
| Username: username, | ||
| CreatedAt: common.GetTimestamp(), | ||
| Type: LogTypeConsume, | ||
| Content: content, | ||
| ModelName: task.Properties.UpstreamModelName, | ||
| Quota: quotaDelta, | ||
| ChannelId: task.ChannelId, | ||
| Group: task.Group, | ||
| Other: common.MapToJsonStr(other), | ||
| } | ||
| LOG_DB.Create(log) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -type f -name "*.go" | grep -E "(model|log)" | head -20Repository: QuantumNous/new-api
Length of output: 511
🏁 Script executed:
cd model && ls -laRepository: QuantumNous/new-api
Length of output: 1950
🏁 Script executed:
cat -n log.go | sed -n '410,445p'Repository: QuantumNous/new-api
Length of output: 101
🏁 Script executed:
# Search for RecordConsumeLog to compare implementation
rg "func RecordConsumeLog" -A 30 -B 2Repository: QuantumNous/new-api
Length of output: 1578
🏁 Script executed:
# Check the Log struct definition
rg "type Log struct" -A 30Repository: QuantumNous/new-api
Length of output: 1967
🏁 Script executed:
cat -n model/log.go | sed -n '405,445p'Repository: QuantumNous/new-api
Length of output: 1228
🏁 Script executed:
# Check if LogTypeRefund is used in the codebase
rg "LogTypeRefund" -B 5 -A 5Repository: QuantumNous/new-api
Length of output: 413
🏁 Script executed:
# Search for RecordReConsumeLog usage to understand call sites
rg "RecordReConsumeLog" -B 3 -A 3Repository: QuantumNous/new-api
Length of output: 1593
🏁 Script executed:
# Check controller/task_video.go for model ratio context
fd task_video.go --exec cat {}Repository: QuantumNous/new-api
Length of output: 10722
🏁 Script executed:
# Check how RecordConsumeLog uses the guard and error handling
cat -n model/log.go | sed -n '262,310p'Repository: QuantumNous/new-api
Length of output: 1768
🏁 Script executed:
# Verify GetUsernameById behavior with nil task
rg "func GetUsernameById" -A 15Repository: QuantumNous/new-api
Length of output: 773
🏁 Script executed:
# Check if LOG_DB.Create() result is ever used elsewhere
rg "LOG_DB\.Create\(" -B 2 -A 3 | head -40Repository: QuantumNous/new-api
Length of output: 825
🏁 Script executed:
# Verify if quotaDelta being negative with LogTypeConsume is intentional
# Check if there are queries that sum Quota by LogTypeConsume
rg "SumUsedQuota\|Quota.*LogTypeConsume" -B 3 -A 3Repository: QuantumNous/new-api
Length of output: 45
🏁 Script executed:
# Check if there's any documentation or comments about LogTypeConsume semantics
rg "LogTypeConsume" -B 2 -A 2 | head -50Repository: QuantumNous/new-api
Length of output: 1301
🏁 Script executed:
# Check if there are any other consume log functions to see established patterns
rg "RecordLog\|RecordConsumeLog" -B 1 | grep "^model/log.go:func" | head -20Repository: QuantumNous/new-api
Length of output: 45
Fix RecordReConsumeLog: add missing consume-log guard, nil-safety checks, DB error handling, and complete token logging.
Currently, this function lacks three defenses present in other log functions:
- No
common.LogConsumeEnabledguard (unlikeRecordConsumeLog), so it logs even when logging is disabled - No nil checks before accessing
taskortask.Properties, risking panic - No error handling on
LOG_DB.Create(log)(other log functions check and report errors) CompletionTokensfield is left at zero despite being available fromtotalTokensparameter
Additionally, the ModelName is sourced from task.Properties.UpstreamModelName, while modelRatio is computed from a different field (model in task.Data). When these diverge, the log becomes misleading.
Recommended fix
func RecordReConsumeLog(task *Task, modelRatio float64, groupRatio float64, totalTokens int, preConsumedQuota int, actualQuota int, content string) {
+ if !common.LogConsumeEnabled {
+ return
+ }
+ if task == nil {
+ common.SysLog("RecordReConsumeLog: task is nil")
+ return
+ }
username, _ := GetUsernameById(task.UserId, false)
quotaDelta := actualQuota - preConsumedQuota
other := map[string]interface{}{
"task_id": task.TaskID,
"model_ratio": modelRatio,
"group_ratio": groupRatio,
"total_tokens": totalTokens,
"pre_consumed": preConsumedQuota,
"actual_quota": actualQuota,
"quota_delta": quotaDelta,
}
+
+ modelName := ""
+ if task.Properties != nil {
+ modelName = task.Properties.UpstreamModelName
+ }
log := &Log{
UserId: task.UserId,
Username: username,
CreatedAt: common.GetTimestamp(),
Type: LogTypeConsume,
Content: content,
- ModelName: task.Properties.UpstreamModelName,
+ ModelName: modelName,
Quota: quotaDelta,
ChannelId: task.ChannelId,
Group: task.Group,
+ CompletionTokens: totalTokens,
Other: common.MapToJsonStr(other),
}
- LOG_DB.Create(log)
+ if err := LOG_DB.Create(log).Error; err != nil {
+ common.SysLog("failed to record reconsume log: " + err.Error())
+ }
}
优化视频补扣费和退款日志, 增加taskId和倍率等信息
Summary by CodeRabbit
Bug Fixes
New Features
✏️ Tip: You can customize this high-level summary in your review settings.