feat: WebSearch tri-state, account stats pricing fix, quota cache fix, usage tooltip

WebSearch tri-state switch:
- Account-level web_search_emulation changed from bool to tri-state
  string: "default" (follow channel) / "enabled" / "disabled"
- shouldEmulateWebSearch checks channel config when account is "default"
- SQL migration converts old bool values
- Frontend select replaces toggle in Edit/CreateAccountModal

Account stats pricing:
- resolveAccountStatsCost uses upstream model (post-mapping) for matching
- Priority: custom rules → model pricing file (when toggle on) → default
- Custom rules always configurable, independent of toggle
- Account ID field changed to searchable selector filtered by platform
- Description updated to reflect new behavior

Quota notification cache fix:
- CheckAccountQuotaAfterIncrement fetches real-time account from DB
- Reconstructs pre-increment usage for accurate threshold crossing detection
- New AccountQuotaReader interface (minimal: GetByID only)

Usage tooltip:
- Per-request/image billing shows per-request price instead of $0 token price
- Token billing continues to show input/output price per million tokens
This commit is contained in:
erio
2026-04-13 11:37:08 +08:00
parent 11c4606874
commit 1262654d97
18 changed files with 346 additions and 79 deletions

View File

@@ -774,6 +774,8 @@ export default {
inputTokenPrice: 'Input price',
outputTokenPrice: 'Output price',
perMillionTokens: '/ 1M tokens',
unitPrice: 'Per-request price',
imageUnitPrice: 'Per-image price',
cacheRead: 'Read',
cacheWrite: 'Write',
serviceTier: 'Service tier',
@@ -1877,14 +1879,15 @@ export default {
pricingEntry: 'Pricing Entry',
noModels: 'No models added',
applyPricingToAccountStats: 'Apply Pricing to Account Stats',
applyPricingToAccountStatsDesc: 'When enabled, custom account stats model pricing rules will be applied.',
applyPricingToAccountStatsDesc: 'When enabled, requests not matched by custom rules will use standard model pricing for account stats calculation',
accountStatsPricingRules: 'Custom Account Stats Pricing Rules',
addRule: 'Add Rule',
noRulesConfigured: 'No custom rules configured. Channel model pricing above will be used.',
ruleName: 'Rule name (optional)',
ruleGroups: 'Groups',
ruleAccounts: 'Account IDs',
ruleAccountsPlaceholder: 'Enter account IDs, comma-separated',
ruleAccounts: 'Accounts',
searchAccountPlaceholder: 'Search accounts...',
ruleAccountsHint: 'Leave empty to match all accounts',
ruleModelPricing: 'Model Pricing',
noGroupsInChannel: 'No groups selected in platform tabs above'
}
@@ -2380,6 +2383,9 @@ export default {
webSearchEmulation: 'Web Search Emulation',
webSearchEmulationDesc:
'Enable web search emulation for this API Key account. When a pure web_search request is detected, the gateway calls a third-party search API and constructs the response locally.',
webSearchDefault: 'Default (follow channel)',
webSearchEnabled: 'Enabled',
webSearchDisabled: 'Disabled',
},
modelRestriction: 'Model Restriction (Optional)',
modelWhitelist: 'Model Whitelist',

View File

@@ -778,6 +778,8 @@ export default {
inputTokenPrice: '输入单价',
outputTokenPrice: '输出单价',
perMillionTokens: '/ 1M Token',
unitPrice: '单次价格',
imageUnitPrice: '单张价格',
cacheRead: '读取',
cacheWrite: '写入',
serviceTier: '服务档位',
@@ -1956,14 +1958,15 @@ export default {
pricingEntry: '定价配置',
noModels: '未添加模型',
applyPricingToAccountStats: '应用模型定价到账号统计',
applyPricingToAccountStatsDesc: '启用后将支持自定义账号统计的模型价格',
applyPricingToAccountStatsDesc: '启用后,未被自定义规则匹配的请求将使用模型定价文件中的标准价格计算账号统计费用',
accountStatsPricingRules: '自定义账号统计定价规则',
addRule: '添加规则',
noRulesConfigured: '未配置自定义规则,将使用上方的模型定价。',
ruleName: '规则名称(可选)',
ruleGroups: '分组',
ruleAccounts: '账号 ID',
ruleAccountsPlaceholder: '输入账号 ID逗号分隔',
ruleAccounts: '账号',
searchAccountPlaceholder: '搜索账号...',
ruleAccountsHint: '留空表示匹配所有账号',
ruleModelPricing: '模型定价',
noGroupsInChannel: '上方平台标签页中未选择分组'
}
@@ -2527,6 +2530,9 @@ export default {
webSearchEmulation: 'Web Search 模拟',
webSearchEmulationDesc:
'为该 API Key 账号启用 web search 模拟。客户端发送纯 web_search 请求时,由网关调用第三方搜索 API 并构造响应返回。',
webSearchDefault: '默认(跟随渠道)',
webSearchEnabled: '开启',
webSearchDisabled: '关闭',
},
modelRestriction: '模型限制(可选)',
modelWhitelist: '模型白名单',