Skip to content

feat(channel): add per-channel billing ratio (渠道倍率) - #5470

Closed
monlor wants to merge 1 commit into
QuantumNous:mainfrom
monlor:feat/channel-ratio
Closed

feat(channel): add per-channel billing ratio (渠道倍率)#5470
monlor wants to merge 1 commit into
QuantumNous:mainfrom
monlor:feat/channel-ratio

Conversation

@monlor

@monlor monlor commented Jun 13, 2026

Copy link
Copy Markdown

Note

This code was generated and implemented with AI assistance (Claude Sonnet 4.6). The description below has been reviewed and written by the submitter.

📝 变更描述 / Description

新增渠道倍率(Channel Ratio)功能,允许在渠道级别配置独立的计费乘数。

当多个渠道服务同一模型时(如 OpenAI 直连 vs Azure),可以为不同渠道设置不同倍率,以反映实际成本差异,而不必为每个渠道单独分组。

新计费公式:

实际消耗配额 = Token数 × 模型倍率 × 分组倍率 × 渠道倍率

后端改动:

  • model/channel.go: 添加 Ratio *float64 字段(GORM 自动迁移,默认 1.0,nil/0 视为 1.0)
  • 通过 gin.Context → ChannelMeta 传播渠道倍率到三条计费路径(按量、按次、分层表达式)
  • BillingSnapshot 增加 ChannelRatio 字段,保证分层表达式计费在结算时使用正确倍率
  • 音频、WebSocket、Task 等计费路径同步更新
  • log_info_generate.go:当 channelRatio != 1.0 时写入日志 other 字段

Pricing API 改动:

  • model/ability.goAbilityWithChannel 扩展 ChannelRatioChannelWeight
  • model/pricing.goupdatePricing 按权重(channel.weight)加权平均计算每个 (model, group) 的有效渠道倍率,通过 group_channel_ratios 字段暴露于 /api/pricing 响应

前端改动:

  • 渠道编辑表单新增 Ratio 输入框(位于 Weight 字段之后)
  • 模型广场价格计算引入 group_channel_ratios,正确反映渠道倍率
  • 使用日志详情对话框在 channel_ratio != 1 时展示渠道倍率
  • zh.json 添加"渠道倍率"中文翻译

向后兼容: 未设置 ratio 的渠道等同于 ratio=1.0,行为与旧版本完全一致。

🚀 变更类型 / Type of change

  • ✨ 新功能 (New feature)

🔗 关联任务 / Related Issue

  • Closes # (如有)

✅ 提交前检查项 / Checklist

  • 人工确认: 我已亲自整理并撰写此描述,没有直接粘贴未经处理的 AI 输出。
  • 非重复提交: 我已搜索现有的 Issues 与 PRs,确认不是重复提交。
  • 变更理解: 我已理解这些更改的工作原理及可能影响。
  • 范围聚焦: 本 PR 未包含任何与当前任务无关的代码改动。
  • 本地验证: 已在本地运行 go buildbun run build 验证编译通过。
  • 安全合规: 代码中无敏感凭据,且符合项目代码规范。

📸 运行证明 / Proof of Work

后端编译:

go build ./model/... ./relay/... ./service/... ./middleware/... ./constant/... ./types/... ./pkg/billingexpr/... ./controller/...
# 无错误输出

前端编译:

bun run build
# Total: 18844.2 kB  4417.8 kB  (成功)

Summary by CodeRabbit

  • New Features
    • Channel Ratio billing multiplier added and configurable in channel settings (numeric, default 1).
    • Channel Ratio applied across pricing, tiered quota calculations, quota consumption, and rebilling flows.
    • Pricing responses can include per-group channel ratio min/max to show price ranges.
    • Channel Ratio surfaced in logs, billing breakdowns, quota summaries, and “Upstream Cost” when non-default.
    • UI i18n added for “Channel Ratio” and “Upstream Cost”.

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 088658e8-2e1b-4c66-adfd-56511942f37a

📥 Commits

Reviewing files that changed from the base of the PR and between a189cde and 58dc2e4.

📒 Files selected for processing (23)
  • constant/context_key.go
  • controller/relay.go
  • middleware/distributor.go
  • model/ability.go
  • model/channel.go
  • model/pricing.go
  • model/task.go
  • pkg/billingexpr/settle.go
  • pkg/billingexpr/types.go
  • relay/common/relay_info.go
  • relay/helper/price.go
  • service/log_info_generate.go
  • service/quota.go
  • service/task_billing.go
  • service/text_quota.go
  • types/price_data.go
  • web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/features/pricing/lib/price.ts
  • web/default/src/features/pricing/types.ts
  • web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
  • web/default/src/features/usage-logs/types.ts
  • web/default/src/i18n/locales/zh.json
✅ Files skipped from review due to trivial changes (3)
  • middleware/distributor.go
  • web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/default/src/i18n/locales/zh.json
🚧 Files skipped from review as they are similar to previous changes (19)
  • pkg/billingexpr/types.go
  • web/default/src/features/pricing/types.ts
  • constant/context_key.go
  • pkg/billingexpr/settle.go
  • controller/relay.go
  • web/default/src/features/usage-logs/types.ts
  • model/task.go
  • model/channel.go
  • types/price_data.go
  • service/log_info_generate.go
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
  • model/ability.go
  • service/task_billing.go
  • relay/common/relay_info.go
  • service/quota.go
  • model/pricing.go
  • relay/helper/price.go
  • service/text_quota.go

Walkthrough

Adds a per-channel billing ratio multiplier: stored on Channel, set in middleware context, propagated into RelayInfo/PriceData/TaskBillingContext/BillingSnapshot, applied across price/quota/settlement calculations, and surfaced in frontend channel settings, pricing displays, and usage logs.

Changes

Channel Ratio Feature

Layer / File(s) Summary
Type definitions and context infra
constant/context_key.go, model/channel.go, model/task.go, relay/common/relay_info.go, pkg/billingexpr/types.go, types/price_data.go
Context key and Channel.Ratio/GetRatio added; TaskBillingContext, ChannelMeta, BillingSnapshot, and PriceData gain ChannelRatio fields.
Request context propagation and relay info
middleware/distributor.go, relay/common/relay_info.go
Middleware stores channel ratio into Gin context from channel.GetRatio(); InitChannelMeta reads and normalizes it to 1.0 default.
Ability and Pricing aggregation
model/ability.go, model/pricing.go
AbilityWithChannel includes channel metadata; updatePricing accumulates per-(model,group) min/max channel ratios and populates Pricing.group_channel_ratio_min/max.
Relay price helpers
relay/helper/price.go
Helpers read channelRatio from context, apply it to both usePrice and non-usePrice quota paths (including tiered billing), and write ChannelRatio into BillingSnapshot and PriceData.
Quota service
service/quota.go
QuotaInfo adds ChannelRatio; calculateAudioQuota clamps and applies channel ratio in priced and non-priced branches; pre/post consume flows set ChannelRatio from ChannelMeta or PriceData.
Settlement and task billing
pkg/billingexpr/settle.go, controller/relay.go, service/task_billing.go, service/log_info_generate.go, service/text_quota.go
Settlement multiplies after-group quota by clamped ChannelRatio; controller persists ChannelRatio into TaskBillingContext; task re-billing uses channelRatio; logs conditionally include channel_ratio and upstream_quota.
Frontend: Channel form and drawer
web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx, web/default/src/features/channels/lib/channel-form.ts
Form schema adds ratio (min 0.01, default 1); drawer renders numeric input; transforms include ratio in create/update payloads.
Frontend: Pricing display
web/default/src/features/pricing/lib/price.ts, web/default/src/features/pricing/types.ts
PricingModel adds per-group min/max channel ratios; price formatters compute effective min/max (group_ratio × group_channel_ratio) and render single values or lo ~ hi ranges.
Frontend: Usage logs and i18n
web/default/src/features/usage-logs/types.ts, web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx, web/default/src/i18n/locales/zh.json
LogOtherData adds channel_ratio and upstream_quota; BillingBreakdown conditionally shows Channel Ratio and Upstream Cost rows; Chinese translations added.

Sequence Diagram(s)

sequenceDiagram
  participant Client as API Client
  participant Middleware as Middleware:SetupContextForSelectedChannel
  participant Init as Relay:InitChannelMeta
  participant Helper as Relay:ModelPriceHelper
  participant QuotaSvc as Quota Service:calculateAudioQuota
  participant Settle as Settlement:ComputeTieredQuotaWithRequest
  participant Task as Task Billing:RecalculateTaskQuotaByTokens/LogTaskConsumption

  Client->>Middleware: request with selected channel
  Middleware->>Middleware: call channel.GetRatio()
  Middleware->>Init: set ContextKeyChannelRatio
  Init->>Helper: provide ChannelMeta.ChannelRatio
  Helper->>QuotaSvc: compute pre-consumed quota using groupRatio × channelRatio
  QuotaSvc->>Settle: settle tiered quota using ChannelRatio in BillingSnapshot
  Settle->>Task: settled quota used in task billing/recalculation
  Task->>Task: log other.{channel_ratio, upstream_quota} when ratio ≠ 1
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • Calcium-Ion
  • creamlike1024

Poem

🐰 I clipped a number, small and spry,

From channel to quota it hops by,
Multiplied in price and logged with cheer,
A tiny ratio makes billing clear,
Hop, hop — the rabbit tuned the sky.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding a per-channel billing ratio feature. It is concise, specific, and directly reflects the primary objective of the entire changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
web/default/src/features/pricing/lib/price.ts (1)

83-99: 💤 Low value

Remove unused function getMinGroupRatio.

This function is no longer called after being replaced by getMinEffectiveRatio at lines 204–208 and 310–314. Removing dead code improves maintainability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/features/pricing/lib/price.ts` around lines 83 - 99, The
function getMinGroupRatio is dead code and should be removed: delete the entire
getMinGroupRatio function definition and any tests/usages if found, since
getMinEffectiveRatio now replaces it (verify there are no remaining references
to getMinGroupRatio before committing). Ensure no other code relies on
getMinGroupRatio and run tests to confirm removal is safe.
types/price_data.go (1)

41-43: 💤 Low value

ToSetting() omits the new ChannelRatio field.

The debug output string includes most pricing fields but not ChannelRatio. This could make troubleshooting channel-ratio billing issues harder since the debug log at relay/helper/price.go:166 uses this method.

🔧 Suggested fix
 func (p *PriceData) ToSetting() string {
-	return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, UsePrice: %t, CacheCreationRatio: %f, CacheCreation5mRatio: %f, CacheCreation1hRatio: %f, QuotaToPreConsume: %d, ImageRatio: %f, AudioRatio: %f, AudioCompletionRatio: %f", p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatioInfo.GroupRatio, p.UsePrice, p.CacheCreationRatio, p.CacheCreation5mRatio, p.CacheCreation1hRatio, p.QuotaToPreConsume, p.ImageRatio, p.AudioRatio, p.AudioCompletionRatio)
+	return fmt.Sprintf("ModelPrice: %f, ModelRatio: %f, CompletionRatio: %f, CacheRatio: %f, GroupRatio: %f, ChannelRatio: %f, UsePrice: %t, CacheCreationRatio: %f, CacheCreation5mRatio: %f, CacheCreation1hRatio: %f, QuotaToPreConsume: %d, ImageRatio: %f, AudioRatio: %f, AudioCompletionRatio: %f", p.ModelPrice, p.ModelRatio, p.CompletionRatio, p.CacheRatio, p.GroupRatioInfo.GroupRatio, p.ChannelRatio, p.UsePrice, p.CacheCreationRatio, p.CacheCreation5mRatio, p.CacheCreation1hRatio, p.QuotaToPreConsume, p.ImageRatio, p.AudioRatio, p.AudioCompletionRatio)
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@types/price_data.go` around lines 41 - 43, The PriceData.ToSetting method is
missing the new ChannelRatio field in its debug string; update the fmt.Sprintf
format string in ToSetting and its argument list to include ChannelRatio (e.g.,
add "ChannelRatio: %f" in the format and pass p.ChannelRatio in the
corresponding position) so the returned string contains the channel ratio for
debugging/troubleshooting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@web/default/src/features/channels/lib/channel-form.ts`:
- Line 141: Update the channel form schema's field named "ratio" (currently
declared as ratio: z.number().min(0).optional()) so users cannot submit
zero—change the validator to .min(0.01) (e.g., ratio:
z.number().min(0.01).optional()); alternatively, if you prefer to preserve zeros
from the UI, add a .transform on that schema to map 0 -> 1 (or null) before
validation and ensure the UI shows the effective minimum in help text.

In `@web/default/src/features/pricing/lib/price.ts`:
- Line 70: The code currently treats an explicit channel ratio of 0 as valid by
using the nullish coalescing operator, but backend semantics require nil/0 to be
treated as 1.0; update the three places in
web/default/src/features/pricing/lib/price.ts so they coerce falsy 0 to 1: in
getMinEffectiveRatio (line 70) replace the expression using
groupChannelRatios?.[group] ?? 1 with one that treats 0 as 1 (use || 1), and
likewise in formatGroupPrice (line 243) and formatFixedPrice (line 276) replace
(model.group_channel_ratios?.[group] ?? 1) with
(model.group_channel_ratios?.[group] || 1); these changes ensure
getMinEffectiveRatio, formatGroupPrice, and formatFixedPrice all treat nil or 0
as 1.0.
- Around line 55-78: getMinEffectiveRatio currently uses
groupChannelRatios?.[group] ?? 1 which preserves an explicit 0; change the
calculation of cr inside getMinEffectiveRatio so that 0, null, and undefined are
treated as 1.0 (e.g., read the value from groupChannelRatios for the group, and
if the value is null/undefined or === 0, set cr = 1; otherwise use the provided
value) to mirror backend behavior.

In `@web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx`:
- Around line 220-229: The UI uses t('Channel Ratio') in the DetailsDialog rows
push (the block that sets label: t('Channel Ratio')), but that i18n key is
missing in most locale files; add the "Channel Ratio" key with appropriate
translations to all supported locale JSONs (en, fr, ru, ja, vi — matching the
existing keys structure) or run the project's i18n sync command to propagate the
key (e.g., run the i18n:sync script so all locales include the new key), then
verify the DetailsDialog renders the localized label.

---

Nitpick comments:
In `@types/price_data.go`:
- Around line 41-43: The PriceData.ToSetting method is missing the new
ChannelRatio field in its debug string; update the fmt.Sprintf format string in
ToSetting and its argument list to include ChannelRatio (e.g., add
"ChannelRatio: %f" in the format and pass p.ChannelRatio in the corresponding
position) so the returned string contains the channel ratio for
debugging/troubleshooting.

In `@web/default/src/features/pricing/lib/price.ts`:
- Around line 83-99: The function getMinGroupRatio is dead code and should be
removed: delete the entire getMinGroupRatio function definition and any
tests/usages if found, since getMinEffectiveRatio now replaces it (verify there
are no remaining references to getMinGroupRatio before committing). Ensure no
other code relies on getMinGroupRatio and run tests to confirm removal is safe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a1749c5b-5d38-4be2-8bbb-f3172692fd3f

📥 Commits

Reviewing files that changed from the base of the PR and between 1ac0f58 and 411ee11.

📒 Files selected for processing (22)
  • constant/context_key.go
  • controller/relay.go
  • middleware/distributor.go
  • model/ability.go
  • model/channel.go
  • model/pricing.go
  • model/task.go
  • pkg/billingexpr/settle.go
  • pkg/billingexpr/types.go
  • relay/common/relay_info.go
  • relay/helper/price.go
  • service/log_info_generate.go
  • service/quota.go
  • service/task_billing.go
  • types/price_data.go
  • web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/features/pricing/lib/price.ts
  • web/default/src/features/pricing/types.ts
  • web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
  • web/default/src/features/usage-logs/types.ts
  • web/default/src/i18n/locales/zh.json

Comment thread web/default/src/features/channels/lib/channel-form.ts Outdated
Comment thread web/default/src/features/pricing/lib/price.ts
Comment thread web/default/src/features/pricing/lib/price.ts Outdated
Comment on lines +220 to +229
if (
other.channel_ratio != null &&
Number.isFinite(other.channel_ratio) &&
other.channel_ratio !== 1
) {
rows.push({
label: t('Channel Ratio'),
value: `${formatRatio(other.channel_ratio)}x`,
})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify 'Channel Ratio' translation exists in all language files

echo "Checking translation for 'Channel Ratio' in all locale files..."

for lang in en zh fr ru ja vi; do
  locale_file="web/default/src/i18n/locales/${lang}.json"
  if [ -f "$locale_file" ]; then
    if grep -q '"Channel Ratio"' "$locale_file"; then
      echo "$lang: translation found"
    else
      echo "$lang: translation MISSING"
    fi
  else
    echo "$lang: locale file not found"
  fi
done

Repository: QuantumNous/new-api

Length of output: 281


Add missing i18n entries for “Channel Ratio”
web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx (lines 220-229) uses t('Channel Ratio'), but the key is missing in locale files for en, fr, ru, ja, and vi (present only in zh). Run bun run i18n:sync from web/default/ (or add the missing keys) to ensure all supported languages render the label.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx`
around lines 220 - 229, The UI uses t('Channel Ratio') in the DetailsDialog rows
push (the block that sets label: t('Channel Ratio')), but that i18n key is
missing in most locale files; add the "Channel Ratio" key with appropriate
translations to all supported locale JSONs (en, fr, ru, ja, vi — matching the
existing keys structure) or run the project's i18n sync command to propagate the
key (e.g., run the i18n:sync script so all locales include the new key), then
verify the DetailsDialog renders the localized label.

@monlor
monlor force-pushed the feat/channel-ratio branch from 411ee11 to a189cde Compare June 13, 2026 11:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@service/text_quota.go`:
- Around line 311-323: The code currently applies summary.ChannelRatio early
(setting summary.UpstreamQuota and mutating summary.Quota) which gets
overwritten later by composeTieredTextQuota; instead, stop applying the channel
ratio until after all tiered/surcharge reconciliation is done: remove or revert
the early mutation of summary.Quota in the ChannelRatio block (leave only
summary.ChannelRatio defaulting logic), ensure composeTieredTextQuota runs and
produces the final pre-channel quota (use or introduce a local variable like
finalQuotaBeforeChannelRatio to hold summary.Quota immediately after tiered
reconciliation/composeTieredTextQuota), then set summary.UpstreamQuota =
finalQuotaBeforeChannelRatio and finally apply ChannelRatio once to compute
summary.Quota; also update other["upstream_quota"] to use summary.UpstreamQuota
so upstream logging reflects the true pre-channel amount.

In
`@web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx`:
- Around line 2563-2590: The ratio input currently converts an empty string to 0
via onChange={(e) => field.onChange(Number(e.target.value))}, which causes an
explicit 0 to be stored instead of falling back to the default in
channel-form.ts (ratio: formData.ratio ?? 1); update the Input's onChange in the
FormField for name='ratio' to normalize empty input to undefined (e.g. if
e.target.value === '' then field.onChange(undefined) else
field.onChange(Number(e.target.value))) so clearing the field does not persist a
0 and allows the existing default logic to apply.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 27af2647-dd75-4429-a826-4bb96fe47025

📥 Commits

Reviewing files that changed from the base of the PR and between 411ee11 and a189cde.

📒 Files selected for processing (23)
  • constant/context_key.go
  • controller/relay.go
  • middleware/distributor.go
  • model/ability.go
  • model/channel.go
  • model/pricing.go
  • model/task.go
  • pkg/billingexpr/settle.go
  • pkg/billingexpr/types.go
  • relay/common/relay_info.go
  • relay/helper/price.go
  • service/log_info_generate.go
  • service/quota.go
  • service/task_billing.go
  • service/text_quota.go
  • types/price_data.go
  • web/default/src/features/channels/components/drawers/channel-mutate-drawer.tsx
  • web/default/src/features/channels/lib/channel-form.ts
  • web/default/src/features/pricing/lib/price.ts
  • web/default/src/features/pricing/types.ts
  • web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
  • web/default/src/features/usage-logs/types.ts
  • web/default/src/i18n/locales/zh.json
✅ Files skipped from review due to trivial changes (2)
  • web/default/src/i18n/locales/zh.json
  • web/default/src/features/usage-logs/types.ts
🚧 Files skipped from review as they are similar to previous changes (13)
  • middleware/distributor.go
  • model/task.go
  • types/price_data.go
  • service/log_info_generate.go
  • web/default/src/features/usage-logs/components/dialogs/details-dialog.tsx
  • controller/relay.go
  • constant/context_key.go
  • pkg/billingexpr/types.go
  • web/default/src/features/channels/lib/channel-form.ts
  • model/ability.go
  • service/task_billing.go
  • service/quota.go
  • model/channel.go

Comment thread service/text_quota.go Outdated
Adds a configurable `ratio` field to channels so that calls routed
through different channels for the same model can carry different
billing multipliers.

Billing formula: quota = tokens × modelRatio × groupRatio × channelRatio

- Backend: Channel.Ratio field (GORM auto-migrate, default 1.0); ratio
  propagated via gin context key set by distributor middleware, read
  directly in ModelPriceHelper/ModelPriceHelperPerCall before
  InitChannelMeta is called (fixes timing bug where ChannelMeta was nil);
  channelRatio applied in PostTextConsumeQuota after all quota sources
  (token-based and tiered) are resolved to avoid tiered-overwrite bug;
  upstream_quota (pre-channelRatio) stored in log other for display;
  audio/WSS/task billing paths updated; log_info_generate emits
  channel_ratio when != 1.0
- Pricing API: AbilityWithChannel now carries channel_ratio/weight;
  updatePricing tracks min/max channel ratio per (model,group) and
  exposes group_channel_ratio_min/max in /api/pricing response
- Frontend: channel form gains a ratio input (min 0.01, clears to 1);
  model marketplace shows price range "$X ~ $Y /M" when channels in the
  same group carry different ratios, single price otherwise; usage-log
  detail dialog shows upstream_cost (before channelRatio) and total cost
  separately when channelRatio != 1; channel ratio 0 treated as 1.0
  consistently (|| 1 instead of ?? 1); zh.json translations added

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@monlor
monlor force-pushed the feat/channel-ratio branch from a189cde to 58dc2e4 Compare June 13, 2026 11:58
@monlor monlor closed this Jun 18, 2026
@Miraaaacle

Copy link
Copy Markdown
image 在阶梯计费中提前处理了渠道倍率会导致双乘,应当只在最终text_quota.go中乘渠道倍率

@monlor

monlor commented Jun 23, 2026

Copy link
Copy Markdown
Author

在阶梯计费中提前处理了渠道倍率会导致双乘,应当只在最终text_quota.go中乘渠道倍率

我自己实际测试的时候 没有被双乘呢。让AI审核了下 你说的问题,好像是不存在的

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants