feat: 分组特殊倍率 - #1207
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis update introduces a new "user group ratio" mechanism, allowing pricing and quota calculations to use a more granular, user-group-specific ratio when available. The change propagates this ratio through backend structs, APIs, logging, and frontend rendering, and adds corresponding configuration and UI elements for managing the new ratio settings. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend
participant Backend
participant SettingStore
User->>Frontend: Set GroupGroupRatio in settings UI
Frontend->>Backend: Submit updated GroupGroupRatio JSON
Backend->>SettingStore: UpdateGroupGroupRatioByJSONString()
SettingStore-->>Backend: Update in-memory map
User->>Frontend: Triggers operation (e.g., model request)
Frontend->>Backend: API request (with user context)
Backend->>SettingStore: GetGroupGroupRatio(userGroup, group)
SettingStore-->>Backend: Return user-group-specific ratio or fallback
Backend->>Backend: Calculate price/quota using ratio
Backend->>Frontend: Respond with log info including user_group_ratio
Frontend->>Frontend: Render log/price using user_group_ratio if present
Poem
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 4
🔭 Outside diff range comments (3)
relay/relay-text.go (1)
366-383: 💡 Verification agent🧩 Analysis chain
userGroupRatiois ignored in quota calculation – risk of inconsistent billing
userGroupRatiois read frompriceData(l 366) but never folded into theratiomultiplier (l 382-383).
IfUserGroupRatiois intended to override or complementGroupRatio, the current logic silently drops it, so the consumed-quota math and the value sent toGenerateTextOtherInfomay diverge.- ratio := dModelRatio.Mul(dGroupRatio) + dUserGroupRatio := decimal.NewFromFloat(userGroupRatio) + if dUserGroupRatio.IsZero() { // default to 1 when not set + dUserGroupRatio = decimal.NewFromInt(1) + } + ratio := dModelRatio.Mul(dGroupRatio).Mul(dUserGroupRatio)Please also update
logContent(l 474-479) and any downstream quota accounting to reflect the extra factor.
Otherwise, end-users in different user-groups will see the correct ratio in logs but be charged the wrong quota.
🏁 Script executed:
#!/bin/bash set -e echo "=== Occurrences of UserGroupRatio ===" grep -R "UserGroupRatio" -n relay/relay-text.go || true echo "" echo "=== Lines 350–500 in relay/relay-text.go ===" sed -n '350,500p' relay/relay-text.go echo "" echo "=== Lines 470–490 (logContent) in relay/relay-text.go ===" sed -n '470,490p' relay/relay-text.go echo "" echo "=== Occurrences of GenerateTextOtherInfo ===" grep -R "GenerateTextOtherInfo" -n relay/relay-text.go || trueLength of output: 8193
Include userGroupRatio in quota calculation
The current code reads
userGroupRatio(l. 366) but never applies it when computingratioor in theUsePricebranch—so billing ignores the per‐user‐group adjustment even though it’s shown in logs and passed toGenerateTextOtherInfo.Please update:
• relay/relay-text.go, around line 382 (ratio calc):
- ratio := dModelRatio.Mul(dGroupRatio) + dUserGroupRatio := decimal.NewFromFloat(userGroupRatio) + if dUserGroupRatio.IsZero() { + dUserGroupRatio = decimal.NewFromInt(1) + } + ratio := dModelRatio.Mul(dGroupRatio).Mul(dUserGroupRatio)• relay/relay-text.go, in the
UsePricebranch (around line 440):- quotaCalculateDecimal = dModelPrice.Mul(dQuotaPerUnit).Mul(dGroupRatio) + quotaCalculateDecimal = dModelPrice. + Mul(dQuotaPerUnit). + Mul(dGroupRatio). + Mul(dUserGroupRatio)• relay/relay-text.go, log formatting (lines 472–479):
- logContent = fmt.Sprintf("模型倍率 %.2f,补全倍率 %.2f,分组倍率 %.2f", modelRatio, completionRatio, groupRatio) + logContent = fmt.Sprintf( + "模型倍率 %.2f,补全倍率 %.2f,分组倍率 %.2f,用户分组倍率 %.2f", + modelRatio, completionRatio, groupRatio, userGroupRatio, + ) … - logContent = fmt.Sprintf("模型价格 %.2f,分组倍率 %.2f", modelPrice, groupRatio) + logContent = fmt.Sprintf( + "模型价格 %.2f,分组倍率 %.2f,用户分组倍率 %.2f", + modelPrice, groupRatio, userGroupRatio, + )This ensures
userGroupRatiois consistently applied to quota calculations, logging, and downstream info.controller/channel-test.go (1)
155-170: 💡 Verification agent🧩 Analysis chain
Quota estimate omits
GroupRatioandUserGroupRatioWhen
priceData.UsePrice == false, the local quota estimate only usesModelRatio(l 158-159) but not the newly introducedGroupRatioorUserGroupRatio.
This makes the “channel test” endpoint under-estimate cost compared to production flow (relay/relay-text.go) and can mislead operators.- quota = int(math.Round(float64(quota) * priceData.ModelRatio)) + quota = int(math.Round(float64(quota) * + priceData.ModelRatio * + priceData.GroupRatio * + priceData.UserGroupRatio))Apply the same default-to-1 safeguard as in the main flow.
🏁 Script executed:
#!/bin/bash set -e echo "=== Searching for GroupRatio occurrences across the repo ===" rg -n "GroupRatio" echo -e "\n=== Searching for UserGroupRatio occurrences across the repo ===" rg -n "UserGroupRatio" echo -e "\n=== Searching for priceData.UsePrice occurrences across the repo ===" rg -n "priceData.UsePrice"Length of output: 16295
🏁 Script executed:
#!/bin/bash set -e echo "=== Extracting production quota calculation in relay-text.go (lines 350-430) ===" sed -n '350,430p' relay/relay-text.goLength of output: 3920
🏁 Script executed:
#!/bin/bash set -e echo "=== Extracting service/quota.go around priceData.UsePrice branch (lines 200-260) ===" sed -n '200,260p' service/quota.goLength of output: 2800
🏁 Script executed:
#!/bin/bash set -e echo "=== Extracting PriceData struct definition and builder in relay/helper/price.go ===" sed -n '1,200p' relay/helper/price.goLength of output: 3619
Include GroupRatio and UserGroupRatio in channel-test quota calculation
When
priceData.UsePrice == false, we only multiply byModelRatio, so tests under-estimate actual cost compared to production (relay/relay-text.go). We need to mirror the relay flow by also applyingGroupRatioandUserGroupRatio, and then re-apply the existing “min 1” safeguard.• File: controller/channel-test.go
• Lines: 157–161Suggested change:
- quota = int(math.Round(float64(quota) * priceData.ModelRatio)) + // apply model, group and user-group multipliers + quota = int(math.Round( + float64(quota) * + priceData.ModelRatio * + priceData.GroupRatio * + priceData.UserGroupRatio, + )) + // same minimum-1 fallback as in production + if priceData.ModelRatio != 0 && quota <= 0 { + quota = 1 + }service/quota.go (1)
152-170:⚠️ Potential issueLog message shows base
groupRatio, not the effective ratio
actualGroupRatiooverridesgroupRatiofor quota calculation, yet the log andGenerateWssOtherInfostill receive the un-overriddengroupRatio.
This will confuse operators when the user-specific multiplier differs.Either update
groupRatioafter override or passactualGroupRatioto downstream calls and log:- logContent = fmt.Sprintf("模型倍率 %.2f,补全倍率 %.2f,音频倍率 %.2f,音频补全倍率 %.2f,分组倍率 %.2f", - modelRatio, completionRatio.InexactFloat64(), audioRatio.InexactFloat64(), audioCompletionRatio.InexactFloat64(), groupRatio) + effective := actualGroupRatio + logContent = fmt.Sprintf("模型倍率 %.2f,补全倍率 %.2f,音频倍率 %.2f,音频补全倍率 %.2f,分组倍率 %.2f", + modelRatio, completionRatio.InexactFloat64(), audioRatio.InexactFloat64(), audioCompletionRatio.InexactFloat64(), effective)…and likewise pass
effectivetoGenerateWssOtherInfo/GenerateAudioOtherInfo.
🧹 Nitpick comments (13)
relay/relay-text.go (1)
514-518: Pass-through is correct, but consider logging the effective ratio
GenerateTextOtherInfonow receivesuserGroupRatio; good.
Once the previous comment is addressed, consider adding the effective multiplier (model*group*userGroup) to theothermap, so UI/analytics don’t have to reconstruct it client-side.relay/common/relay_info.go (1)
64-65: Document & validate the newUserGroupfield
UserGroupis a first-class attribute now. Add a short comment to the struct explaining its semantics (e.g. “sub-group inside Group used for tiered ratios”).
Also, if the context key is absent the value will be""; consider normalising to the top-levelGroupor logging a warning so pricing helpers don’t mis-interpret an empty string as a real group id.Also applies to: 208-209
controller/pricing.go (1)
24-29: Safe map mutation during iterationUpdating map entries while ranging over the same map is allowed in Go, but if future code adds deletions this block will break.
Consider copying keys first:for name := range groupRatio { if ratio, ok := setting.GetGroupGroupRatio(group, name); ok { groupRatio[name] = ratio } }No functional change required, just a defensive rewrite.
setting/group_ratio.go (1)
17-22: Remove hard-coded placeholderThe initial value
"edit_this": 0.9looks like a stub and will leak to production defaults.
Prefer an empty map or meaningful example in documentation / migration script instead of code.relay/helper/price.go (1)
27-29:ToSettingomits the newUserGroupRatiofieldDebug prints will silently miss the most important value you’ve just added.
-return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, ShouldPreConsumedQuota: %d, ImageRatio: %f", - p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatio, p.UsePrice, p.CacheCreationRatio, p.ShouldPreConsumedQuota, p.ImageRatio) +return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UserGroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, ShouldPreConsumedQuota: %d, ImageRatio: %f", + p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatio, p.UserGroupRatio, p.UsePrice, p.CacheCreationRatio, p.ShouldPreConsumedQuota, p.ImageRatio)web/src/pages/Setting/Operation/GroupRatioSettings.js (1)
140-160: Consider consistent JSON validation semantics
verifyJSON('')returnsfalse, so an empty textarea cannot be saved – unlike most other optional numeric / string fields in the form.
If administrators should be able to clear this config, allow empty input or add explicit guidance.web/src/components/table/LogsTable.js (5)
768-772: Defensive check can still throw
formValues.dateRange.length === 2does not guarantee that both
elements are non-empty strings.
Consider guarding against empty / null members to avoidDate.parse('')
returningNaNfurther down the pipeline.- if (formValues.dateRange && Array.isArray(formValues.dateRange) && formValues.dateRange.length === 2) { + if ( + Array.isArray(formValues.dateRange) && + formValues.dateRange[0] && + formValues.dateRange[1] + ) {
1078-1085: Ternary chain hurts readabilityThe nested ternary used to resolve
currentLogTypeis hard to read and
easy to extend incorrectly.-const currentLogType = - customLogType !== null - ? customLogType - : formLogType !== undefined - ? formLogType - : logType; +const currentLogType = + customLogType ?? (formLogType ?? logType);Using the nullish-coalescing operator clarifies intent and removes one
level of nesting.
1312-1330: Hard-coded options → risk of drift
<Form.Select>literals duplicate log-type constants already used in
the backend (enum 0-5). Consider mapping over a single source of
truth (array / object) so a future change in the enum cannot silently
break the UI.
1381-1399:rowExpandablerecalculated every renderThe arrow function captures
expandDatafrom closure each render.
Because its reference identity changes,Tablemay re-build internal
handlers unnecessarily.
Define it withuseCallbackor move it outside the component if
possible to avoid needless re-renders on large datasets.
1392-1398: Missing accessibility fall-backWhen
IllustrationNoResultDarkis supplied asdarkModeImage, make sure
users withprefers-color-schemeunsupported browsers still see a
placeholder. Semi UI handles this, but adding analttext is cheap:<IllustrationNoResultDark style={{ width: 150, height: 150 }} aria-label={t('搜索无结果')} />web/src/helpers/render.js (1)
895-905: Mutation of parameters – create a new variable insteadEach pricing function re-assigns
groupRatio:groupRatio = useUserGroupRatio ? user_group_ratio : groupRatio;Mutating parameters can be confusing and prevents the original value
from being inspected later in the function. Use an explicit
effectiveGroupRatioinstead.- groupRatio = useUserGroupRatio ? user_group_ratio : groupRatio; + const effectiveGroupRatio = useUserGroupRatio ? user_group_ratio : groupRatio;Update subsequent references accordingly.
model/option.go (1)
100-103: Addition looks correct – remember to keep key names DRYThe new entry
GroupGroupRatiois wired exactly the same way as the other JSON-backed ratio options, so it will be visible from the very first boot and later overridden by DB values – good.For long-term maintainability, consider extracting all option-key literals (now well over 120) into typed
constdefinitions or an enum-like map. This avoids typos acrossInitOptionMap, the giantswitch, and any future callers.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
controller/channel-test.go(1 hunks)controller/pricing.go(2 hunks)model/option.go(2 hunks)relay/common/relay_info.go(2 hunks)relay/helper/price.go(4 hunks)relay/relay-text.go(2 hunks)service/log_info_generate.go(4 hunks)service/quota.go(9 hunks)setting/group_ratio.go(4 hunks)web/src/components/settings/OperationSetting.js(2 hunks)web/src/components/table/LogsTable.js(19 hunks)web/src/helpers/render.js(15 hunks)web/src/pages/Setting/Operation/GroupRatioSettings.js(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
relay/relay-text.go (1)
service/log_info_generate.go (1)
GenerateTextOtherInfo(10-32)
relay/common/relay_info.go (1)
constant/context_key.go (1)
ContextKeyUserGroup(9-9)
controller/pricing.go (1)
setting/group_ratio.go (1)
GetGroupGroupRatio(73-83)
model/option.go (1)
setting/group_ratio.go (2)
GroupGroupRatio2JSONString(85-91)UpdateGroupGroupRatioByJSONString(93-96)
web/src/pages/Setting/Operation/GroupRatioSettings.js (2)
web/src/helpers/utils.js (2)
verifyJSON(236-243)verifyJSON(236-243)web/src/components/settings/OperationSetting.js (1)
inputs(21-65)
service/quota.go (1)
setting/group_ratio.go (1)
GetGroupGroupRatio(73-83)
relay/helper/price.go (1)
setting/group_ratio.go (1)
GetGroupGroupRatio(73-83)
setting/group_ratio.go (1)
common/logger.go (1)
SysError(55-58)
service/log_info_generate.go (3)
relay/common/relay_info.go (1)
RelayInfo(57-107)dto/realtime.go (1)
RealtimeUsage(38-44)dto/openai_response.go (1)
Usage(170-181)
web/src/helpers/render.js (1)
web/src/components/table/ModelPricing.js (1)
groupRatio(261-261)
🔇 Additional comments (4)
web/src/components/settings/OperationSetting.js (1)
21-35: UI wiring looks correct
GroupGroupRatiois added to state and pretty-printed on fetch – implementation is consistent with other JSON options.Also applies to: 75-83
web/src/components/table/LogsTable.js (1)
746-749: Potential timestamp mis-calculation
now.getTime()returns a value in milliseconds.
By dividing first (/ 1000) and then adding3600you end up with “current seconds + 3600”, i.e. one hour in the future.
If the intent was “current time plus one hour”, the arithmetic is correct.
If the intent was “the end of today”, you probably want something likegetTodayStartTimestamp() + 24 * 3600.
Please double-check the requirement.service/log_info_generate.go (1)
34-38:Details
✅ Verification successful
Signature change – ensure all call-sites updated
The helper now expects
userGroupRatio. Any forgotten callers will not
compile. A quick scan can catch stragglers.
🏁 Script executed:
#!/bin/bash # List GenerateTextOtherInfo calls with argument count != 8 rg --line-number 'GenerateTextOtherInfo\(' | awk -F':' '{print $1":"$2}' | while read loc; do file=${loc%:*}; line=${loc#*:} args=$(sed -n "${line}p" "$file" | grep -o ',' | wc -l) if [ "$args" -ne 7 ]; then # 7 commas = 8 args echo "✅ ok $loc" else echo "❌ check $loc" fi doneLength of output: 1451
🏁 Script executed:
#!/bin/bash # Verify GenerateTextOtherInfo calls have the updated 9-argument signature rg -n 'GenerateTextOtherInfo\(' | awk -F: '{print $1 ":" $2}' | while read loc; do file=${loc%:*} line=${loc#*:} code=$(sed -n "${line}p" "$file") comma_count=$(grep -o "," <<< "$code" | wc -l) expected=8 # 8 commas = 9 arguments if [ "$comma_count" -ne "$expected" ]; then echo "❌ $file:$line — found $comma_count commas (expected $expected)" else echo "✅ $file:$line — correct argument count" fi doneLength of output: 2675
🏁 Script executed:
#!/bin/bash # Inspect the multi-line declaration of GenerateTextOtherInfo rg -n -A2 'func GenerateTextOtherInfo' service/log_info_generate.go echo # Show the full invocation in controller/channel-test.go to verify argument count rg -n -A5 'GenerateTextOtherInfo' controller/channel-test.goLength of output: 979
Signature change verified – all call-sites updated
A full inspection confirms that
GenerateTextOtherInfo’s newuserGroupRatioparameter is included in every invocation. No forgotten callers remain.model/option.go (1)
359-361: Update path completes the feature – mirrors existing patternThe switch-case now delegates
GroupGroupRatioupdates tosetting.UpdateGroupGroupRatioByJSONString, matching the pattern used for the other ratio maps. Error propagation is preserved via the sharederrvariable – looks good.No functional issues spotted.
…ed clarity and consistency in function signatures
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Style