-
-
Notifications
You must be signed in to change notification settings - Fork 2k
feat: 图像倍率,音频倍率和音频补全倍率配置 #1698
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: alpha
Are you sure you want to change the base?
feat: 图像倍率,音频倍率和音频补全倍率配置 #1698
Conversation
WalkthroughAdds ImageRatio, AudioRatio, and AudioCompletionRatio options end‑to‑end: controller handlers, model option initialization, runtime ratio storage and JSON management, propagation into pricing/PriceData, and frontend UI/i18n for editing these ratios. No public API signatures changed. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Admin as Admin (Web UI)
participant UI as Settings UI
participant API as Controller (UpdateOption)
participant Ratio as ratio_setting
participant Pricing as ModelPriceHelper
participant Client as Requester
rect rgb(240,248,255)
Admin->>UI: Edit Image/Audio ratio JSON
UI->>API: POST UpdateOption(key, value)
API->>Ratio: UpdateXRatioByJSONString(value)
Ratio-->>API: success / error
API-->>UI: {"success": true/false}
end
rect rgb(245,255,245)
Client->>Pricing: Request model price
alt usePrice disabled
Pricing->>Ratio: GetAudioRatio/GetAudioCompletionRatio
Ratio-->>Pricing: ratios
end
Pricing-->>Client: PriceData{..., AudioRatio, AudioCompletionRatio}
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
web/src/i18n/locales/en.json (1)
1298-1299
: Duplicate i18n key will shadow earlier entryKey "模型补全倍率(仅对自定义模型有效)" exists twice (Lines 1298 and 2021). Many JSON loaders keep only the last occurrence; some tooling flags this as invalid JSON. Remove the duplicate.
Apply one of the following diffs (prefer removing the later duplicate):
- "模型补全倍率(仅对自定义模型有效)": "Model completion ratio (only effective for custom models)",
Also applies to: 2021-2021
setting/ratio_setting/model_ratio.go (1)
673-678
: Image ratio updates don’t invalidate exposed cache and can lose state on parse error
- No InvalidateExposedDataCache() call (audio/model/comp do it), causing stale exposed data.
- Map is cleared before unmarshal; on error the in-memory map stays empty.
func UpdateImageRatioByJSONString(jsonStr string) error { - imageRatioMapMutex.Lock() - defer imageRatioMapMutex.Unlock() - imageRatioMap = make(map[string]float64) - return common.Unmarshal([]byte(jsonStr), &imageRatioMap) + var tmp = make(map[string]float64) + if err := common.Unmarshal([]byte(jsonStr), &tmp); err != nil { + return err + } + imageRatioMapMutex.Lock() + imageRatioMap = tmp + imageRatioMapMutex.Unlock() + InvalidateExposedDataCache() + return nil }
🧹 Nitpick comments (5)
web/src/i18n/locales/en.json (1)
2020-2020
: Minor copy: prefer 'Key retrieved successfully'"Key acquisition successful" is understandable but non-idiomatic. Suggest: "Key retrieved successfully".
- "密钥获取成功": "Key acquisition successful", + "密钥获取成功": "Key retrieved successfully",setting/ratio_setting/model_ratio.go (2)
666-669
: Incorrect log label ('cache ratio')This is ImageRatio2JSONString; message should say "image ratio" for diagnostics clarity.
- common.SysError("error marshalling cache ratio: " + err.Error()) + common.SysError("error marshalling image ratio: " + err.Error())
619-626
: Optional: consider model-name normalization for image ratios tooIf future image models adopt date-suffixed versions (e.g., gpt-image-1-YYYY-MM-DD), consider using FormatMatchingModelName in GetImageRatio as a preventive measure.
func GetImageRatio(name string) (float64, bool) { - imageRatioMapMutex.RLock() + name = FormatMatchingModelName(name) + imageRatioMapMutex.RLock() defer imageRatioMapMutex.RUnlock() ratio, ok := imageRatioMap[name] if !ok { return 1, false } return ratio, true }Also applies to: 628-636
web/src/components/settings/RatioSetting.jsx (1)
42-44
: State extended with Image/Audio ratios — OK; avoid key driftConsider centralizing the JSON-config keys in a single constant shared across components to prevent future omissions.
web/src/pages/Setting/Ratio/ModelRatioSettings.jsx (1)
225-246
: ImageRatio textarea is consistent; minor UX nitsConsider using a monospace font and optional JSON linting hint to ease editing large JSON.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (8)
controller/option.go
(1 hunks)model/option.go
(2 hunks)relay/helper/price.go
(3 hunks)setting/ratio_setting/model_ratio.go
(6 hunks)types/price_data.go
(2 hunks)web/src/components/settings/RatioSetting.jsx
(2 hunks)web/src/i18n/locales/en.json
(1 hunks)web/src/pages/Setting/Ratio/ModelRatioSettings.jsx
(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
web/src/pages/Setting/Ratio/ModelRatioSettings.jsx (1)
web/src/components/settings/RatioSetting.jsx (1)
inputs
(35-49)
model/option.go (2)
common/constants.go (1)
OptionMap
(36-36)setting/ratio_setting/model_ratio.go (6)
ImageRatio2JSONString
(663-671)AudioRatio2JSONString
(690-698)AudioCompletionRatio2JSONString
(721-729)UpdateImageRatioByJSONString
(673-678)UpdateAudioRatioByJSONString
(700-709)UpdateAudioCompletionRatioByJSONString
(731-740)
controller/option.go (1)
setting/ratio_setting/model_ratio.go (3)
UpdateImageRatioByJSONString
(673-678)UpdateAudioRatioByJSONString
(700-709)UpdateAudioCompletionRatioByJSONString
(731-740)
relay/helper/price.go (1)
setting/ratio_setting/model_ratio.go (2)
GetAudioRatio
(619-626)GetAudioCompletionRatio
(628-636)
setting/ratio_setting/model_ratio.go (3)
common/json.go (2)
Marshal
(20-22)Unmarshal
(8-10)common/sys_log.go (1)
SysError
(15-18)setting/ratio_setting/exposed_cache.go (1)
InvalidateExposedDataCache
(23-25)
🔇 Additional comments (8)
types/price_data.go (1)
18-19
: Audio fields added and surfaced in ToSetting look goodStruct extension and ToSetting formatting are consistent with existing fields. No functional concerns.
Also applies to: 31-33
setting/ratio_setting/model_ratio.go (1)
341-350
: New ratio maps, JSON helpers, and getters are consistentInitialization, JSON (de)serialization, and copy getters follow existing patterns. After applying the safe-swap/invalidation fixes above, this section is solid.
Also applies to: 690-699, 711-720, 721-730, 742-751, 441-452, 655-661
relay/helper/price.go (1)
55-57
: Audio ratios are correctly plumbed into PriceData when using ratiosLooks good. Note: when UsePrice is true, audio fields remain zero in PriceData (debug output will show 0). That’s acceptable if downstream ignores them in price mode.
Do you expect pre-consumed quota to account for audio ratios as well for audio-heavy requests? If yes, we should multiply into the ratio used at Line 81 for such models.
Also applies to: 78-80, 97-99
model/option.go (1)
114-116
: Init default ratios in OptionMap — LGTMKeys and sources align with existing pattern; safe to expose via GET /api/option.
web/src/components/settings/RatioSetting.jsx (1)
67-71
: Prettify JSON for new keys — OKHandling matches existing keys and try/catch protects non-JSON values.
web/src/pages/Setting/Ratio/ModelRatioSettings.jsx (3)
47-50
: Local state extended — LGTMKeys mirror the backend options and parent props; ready for compareObjects diffing.
247-268
: AudioRatio textarea — LGTMValidation and autosize are consistent with other fields.
269-290
: AudioCompletionRatio textarea — LGTMConsistent rules and wiring; works with existing submit flow.
case "ImageRatio": | ||
err = ratio_setting.UpdateImageRatioByJSONString(option.Value) | ||
if err != nil { | ||
c.JSON(http.StatusOK, gin.H{ | ||
"success": false, | ||
"message": "图片倍率设置失败: " + err.Error(), | ||
}) | ||
return | ||
} | ||
case "AudioRatio": | ||
err = ratio_setting.UpdateAudioRatioByJSONString(option.Value) | ||
if err != nil { | ||
c.JSON(http.StatusOK, gin.H{ | ||
"success": false, | ||
"message": "音频倍率设置失败: " + err.Error(), | ||
}) | ||
return | ||
} | ||
case "AudioCompletionRatio": | ||
err = ratio_setting.UpdateAudioCompletionRatioByJSONString(option.Value) | ||
if err != nil { | ||
c.JSON(http.StatusOK, gin.H{ | ||
"success": false, | ||
"message": "音频补全倍率设置失败: " + err.Error(), | ||
}) | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
New options handled; align image-ratio cache invalidation with audio/model
Controller wiring is fine. Ensure UpdateImageRatioByJSONString also invalidates exposed cache (audio functions already do). See suggested fix in ratio_setting/model_ratio.go.
After applying the InvalidateExposedDataCache() fix, please verify the exposed ratios API reflects changes immediately after updating ImageRatio via this endpoint.
🏁 Script executed:
#!/usr/bin/env bash
# Locate model_ratio.go
file=$(fd model_ratio.go)
echo "Found file: $file"
# Inspect UpdateImageRatioByJSONString
echo "=== UpdateImageRatioByJSONString ==="
rg -nP 'func UpdateImageRatioByJSONString' -C15 "$file" || true
# Inspect UpdateAudioRatioByJSONString
echo "=== UpdateAudioRatioByJSONString ==="
rg -nP 'func UpdateAudioRatioByJSONString' -C15 "$file" || true
# Inspect UpdateAudioCompletionRatioByJSONString
echo "=== UpdateAudioCompletionRatioByJSONString ==="
rg -nP 'func UpdateAudioCompletionRatioByJSONString' -C15 "$file" || true
Length of output: 3706
Add cache invalidation to UpdateImageRatioByJSONString
UpdateImageRatioByJSONString in setting/ratio_setting/model_ratio.go (around line 673) currently unmarshals into imageRatioMap without calling InvalidateExposedDataCache(). Mirror the audio handlers by invoking InvalidateExposedDataCache() on successful unmarshal. After making this change, verify that the exposed ratios API reflects image-ratio updates immediately.
🤖 Prompt for AI Agents
In controller/option.go around lines 115-141, the ImageRatio branch updates via
ratio_setting.UpdateImageRatioByJSONString(option.Value) but the underlying
UpdateImageRatioByJSONString (setting/ratio_setting/model_ratio.go around line
673) does not call InvalidateExposedDataCache() after a successful unmarshal;
modify UpdateImageRatioByJSONString to mirror the audio handlers by invoking
InvalidateExposedDataCache() immediately after the unmarshalling/update succeeds
so the exposed ratios API reflects changes immediately, then run a quick test to
confirm the exposed ratios endpoint shows the updated image ratios.
case "ImageRatio": | ||
err = ratio_setting.UpdateImageRatioByJSONString(value) | ||
case "AudioRatio": | ||
err = ratio_setting.UpdateAudioRatioByJSONString(value) | ||
case "AudioCompletionRatio": | ||
err = ratio_setting.UpdateAudioCompletionRatioByJSONString(value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Stale cache risk: ImageRatio update lacks exposed-data invalidation
AudioRatio/AudioCompletionRatio updaters call InvalidateExposedDataCache() on success (see setting/ratio_setting/model_ratio.go), but UpdateImageRatioByJSONString does not. Exposed ratio endpoints/UI may serve stale ImageRatio after updates.
Proposed fix (in setting/ratio_setting/model_ratio.go):
func UpdateImageRatioByJSONString(jsonStr string) error {
imageRatioMapMutex.Lock()
defer imageRatioMapMutex.Unlock()
imageRatioMap = make(map[string]float64)
err := common.Unmarshal([]byte(jsonStr), &imageRatioMap)
if err == nil {
InvalidateExposedDataCache()
}
return err
}
Verify current behavior:
🏁 Script executed:
#!/bin/bash
# Show the ImageRatio updater and check for cache invalidation usage
rg -nP -C3 'func\s+UpdateImageRatioByJSONString\(' --type=go
rg -n 'InvalidateExposedDataCache\(' setting/ratio_setting --type=go
Length of output: 1121
Add cache invalidation to UpdateImageRatioByJSONString
UpdateImageRatioByJSONString (setting/ratio_setting/model_ratio.go) never calls InvalidateExposedDataCache() after unmarshalling, so the exposed ImageRatio remains stale. Add an InvalidateExposedDataCache()
call inside the if err == nil
block, matching the pattern used by AudioRatio and AudioCompletionRatio updaters.
🤖 Prompt for AI Agents
In model/option.go around lines 402 to 407, the ImageRatio updater does not
invalidate the exposed data cache after a successful JSON update; modify the
UpdateImageRatioByJSONString call path (in setting/ratio_setting/model_ratio.go)
to invoke InvalidateExposedDataCache() inside the `if err == nil` block
immediately after successful unmarshalling/update, following the same pattern
used by AudioRatio and AudioCompletionRatio updaters so the exposed ImageRatio
is refreshed.
var defaultAudioRatio = map[string]float64{ | ||
"gpt-4o-audio-preview": 16, | ||
"gpt-4o-mini-audio-preview": 66.67, | ||
"gpt-4o-realtime-preview": 8, | ||
"gpt-4o-mini-realtime-preview": 16.67, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mismatched model IDs between audio ratio and audio completion ratio
defaultAudioRatio uses "-realtime-preview" keys; defaultAudioCompletionRatio uses "-realtime" keys. Given incoming names are often "-realtime-preview[-DATE]", completion lookups will miss and fall back to 2. Align keys.
var defaultAudioCompletionRatio = map[string]float64{
- "gpt-4o-realtime": 2,
- "gpt-4o-mini-realtime": 2,
+ "gpt-4o-realtime-preview": 2,
+ "gpt-4o-mini-realtime-preview": 2,
}
Also applies to: 288-291
🤖 Prompt for AI Agents
In setting/ratio_setting/model_ratio.go around lines 281-286 (and similarly
lines 288-291), the map keys use "-realtime-preview" while the audio completion
ratio map uses "-realtime", causing lookups to miss when incoming model names
are "-realtime-preview[-DATE]"; update the keys so both maps use the same
canonical form (prefer matching incoming names, e.g., use "-realtime-preview" in
both maps) or normalize incoming model IDs before lookup (strip or map
"-realtime-preview" ↔ "-realtime") so lookups succeed and do not fall back to
the default 2.
✅ Addressed in commit d15718a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (3)
setting/ratio_setting/model_ratio.go (3)
692-713
: Safe-swap with cache invalidation after unlock. LGTM; fixes prior data-loss risk.Also applies to: 735-745
281-286
: Fix mismatched realtime model IDs (preview vs non-preview) to avoid lookup misses.defaultAudioRatio uses "-realtime-preview" while defaultAudioCompletionRatio uses "-realtime". Align to the preview form to match incoming IDs and your normalization path.
var defaultAudioCompletionRatio = map[string]float64{ - "gpt-4o-realtime": 2, - "gpt-4o-mini-realtime": 2, + "gpt-4o-realtime-preview": 2, + "gpt-4o-mini-realtime-preview": 2, }Also applies to: 288-291
619-627
: Normalize audio variants and date-suffixed IDs; also normalize before locking.
- Move FormatMatchingModelName call before acquiring the RLock. Minor contention win.
- Extend FormatMatchingModelName to collapse audio/realtime preview variants (and map non-preview -> preview) so lookups don’t fall back.
Apply this small locking nit:
func GetAudioRatio(name string) float64 { - audioRatioMapMutex.RLock() - defer audioRatioMapMutex.RUnlock() - name = FormatMatchingModelName(name) + name = FormatMatchingModelName(name) + audioRatioMapMutex.RLock() + defer audioRatioMapMutex.RUnlock() if ratio, ok := audioRatioMap[name]; ok { return ratio } return 20 } func GetAudioCompletionRatio(name string) float64 { - audioCompletionRatioMapMutex.RLock() - defer audioCompletionRatioMapMutex.RUnlock() - name = FormatMatchingModelName(name) + name = FormatMatchingModelName(name) + audioCompletionRatioMapMutex.RLock() + defer audioCompletionRatioMapMutex.RUnlock() if ratio, ok := audioCompletionRatioMap[name]; ok { return ratio } return 2 }Then, add these normalizations near the end of FormatMatchingModelName (just before
return name
):// Normalize audio/realtime preview variants and versioned IDs if strings.HasPrefix(name, "gpt-4o-audio-preview") { name = "gpt-4o-audio-preview" } if strings.HasPrefix(name, "gpt-4o-mini-audio-preview") { name = "gpt-4o-mini-audio-preview" } if strings.HasPrefix(name, "gpt-4o-realtime-preview") { name = "gpt-4o-realtime-preview" } if strings.HasPrefix(name, "gpt-4o-mini-realtime-preview") { name = "gpt-4o-mini-realtime-preview" } // Map non-preview aliases to preview keys to match ratio maps if strings.HasPrefix(name, "gpt-4o-realtime") && !strings.HasPrefix(name, "gpt-4o-realtime-preview") { name = "gpt-4o-realtime-preview" } if strings.HasPrefix(name, "gpt-4o-mini-realtime") && !strings.HasPrefix(name, "gpt-4o-mini-realtime-preview") { name = "gpt-4o-mini-realtime-preview" }Also applies to: 629-638
🧹 Nitpick comments (1)
setting/ratio_setting/model_ratio.go (1)
441-452
: Return copies of default maps to prevent accidental mutation.Optional hardening so callers can’t mutate defaults.
func GetDefaultImageRatioMap() map[string]float64 { - return defaultImageRatio + out := make(map[string]float64, len(defaultImageRatio)) + for k, v := range defaultImageRatio { + out[k] = v + } + return out } func GetDefaultAudioRatioMap() map[string]float64 { - return defaultAudioRatio + out := make(map[string]float64, len(defaultAudioRatio)) + for k, v := range defaultAudioRatio { + out[k] = v + } + return out } func GetDefaultAudioCompletionRatioMap() map[string]float64 { - return defaultAudioCompletionRatio + out := make(map[string]float64, len(defaultAudioCompletionRatio)) + for k, v := range defaultAudioCompletionRatio { + out[k] = v + } + return out }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
setting/ratio_setting/model_ratio.go
(6 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-08-05T17:14:17.246Z
Learnt from: neotf
PR: QuantumNous/new-api#1511
File: setting/ratio_setting/model_ratio.go:118-123
Timestamp: 2025-08-05T17:14:17.246Z
Learning: Claude models handle "-thinking" variants differently from Gemini models. For Claude models, only the base model (without "-thinking") gets an entry in defaultModelRatio map. The "-thinking" variants rely on the Claude relay handler stripping the suffix using strings.TrimSuffix(textRequest.Model, "-thinking") before looking up the ratio, so they automatically use the base model's ratio.
Applied to files:
setting/ratio_setting/model_ratio.go
🧬 Code graph analysis (1)
setting/ratio_setting/model_ratio.go (3)
common/json.go (2)
Marshal
(20-22)Unmarshal
(8-10)common/sys_log.go (1)
SysError
(15-18)setting/ratio_setting/exposed_cache.go (1)
InvalidateExposedDataCache
(23-25)
🔇 Additional comments (3)
setting/ratio_setting/model_ratio.go (3)
341-350
: Audio maps initialization mirrors existing patterns. LGTM.
715-723
: Return-by-copy under read lock. LGTM.Also applies to: 747-755
656-663
: Separate maps and mutexes for audio ratios. LGTM.
Summary by CodeRabbit
New Features
Pricing
UI
Internationalization