docs(pricing): 枚举设计 §4.2/§5.2/§8 同步 mediaPrices v0.4 + 设计文档 §5.2 语法修正
This commit is contained in:
@@ -104,10 +104,9 @@ rule_snapshot TEXT NOT NULL, -- workflow: 选中模式的规则片段
|
||||
"unit": "per_1M",
|
||||
"tiered": false,
|
||||
"rules": [
|
||||
{ "name": "规则名", "match": {...}, "price": {...} }
|
||||
{ "name": "规则名", "match": {...}, "price": {...}, "mediaPrices": {"audio": {...}} }
|
||||
],
|
||||
"currency": "CNY",
|
||||
"discount": null
|
||||
"currency": "CNY"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -127,7 +126,6 @@ rule_snapshot TEXT NOT NULL, -- workflow: 选中模式的规则片段
|
||||
|
||||
| 字段 | 值 | 说明 | 用于 |
|
||||
|---|---|---|---|
|
||||
| `mediaType` | text/audio/video/image | 输入媒体类型 | 视频「输入含/不含视频」、推理「输入含/不含音频」 |
|
||||
| `thinking` | true/false | 思考/非思考模式 | 推理 |
|
||||
| `outputAudio` | true/false | 输出有声/无声 | 视频 |
|
||||
| `outputResolution` | 自由字符串 | 输出分辨率(视频 480p/720p/1080p/2k/4k;图片 512x512/1024x1024) | 视频、图片 |
|
||||
@@ -136,10 +134,11 @@ rule_snapshot TEXT NOT NULL, -- workflow: 选中模式的规则片段
|
||||
**price 计价项**:
|
||||
- token 单位(per_1K/per_1M):`input`(输入单价)、`output`(输出单价)、`cacheHit`(缓存命中输入单价,缺省 0=无优惠)
|
||||
- 非 token 单位(per_1/per_second/per_minute/per_hour/per_char):`unitPrice`(每单位单价)
|
||||
- **mediaPrices 媒体类型价**(可选):`媒体类型 → price` 的 map,键 ∈ {text,audio,video,image}。输入含该媒体时用对应价;否则用默认 `price`(**默认价 = 输入不含以下媒体**)。一个规则可挂多套媒体价;缺 key 即走默认价。
|
||||
|
||||
**tiered 阶梯(分档不累加)**:仅 token 单位;`tiered:true` 表示按输入 token 分档——档位区间相邻不重叠(下档 max+1=上档 min),结算按 promptTokens 命中哪档就整单按哪档 input/output/cacheHit 价;`tiered:false` 规则间靠其他维度区分。
|
||||
|
||||
> 与 model-gateway `PriceConfig` 的关系:不复用其字段结构(`inputAudio/cacheHitAudio/cacheStorageHour` 删除,音频输入差价改由 `mediaType:"audio"` 命中独立规则表达)。规则级/模型级 `discount` 字段保留(本期模型结算未接,仅建模)。
|
||||
> 与 model-gateway `PriceConfig` 的关系:不复用其字段结构(`inputAudio/cacheHitAudio/cacheStorageHour` 删除,音频输入差价改由 `mediaPrices.audio` 表达)。`discount` 废弃(代码无实现)。v0.4 修订全文见 `2026-09-01-pricing-media-price-design.md`。
|
||||
|
||||
**示例**:
|
||||
|
||||
@@ -148,8 +147,8 @@ rule_snapshot TEXT NOT NULL, -- workflow: 选中模式的规则片段
|
||||
{
|
||||
"unit": "per_second", "tiered": false,
|
||||
"rules": [
|
||||
{ "name": "无声-720p-输入不含视频", "match": {"outputAudio": false, "outputResolution": "720p", "mediaType": "text"}, "price": {"unitPrice": 0.8} },
|
||||
{ "name": "有声-1080p-输入含视频", "match": {"outputAudio": true, "outputResolution": "1080p", "mediaType": "video"}, "price": {"unitPrice": 1.5} }
|
||||
{ "name": "无声-720p", "match": {"outputAudio": false, "outputResolution": "720p"}, "price": {"unitPrice": 0.8}, "mediaPrices": {"video": {"unitPrice": 1.0}} },
|
||||
{ "name": "有声-1080p", "match": {"outputAudio": true, "outputResolution": "1080p"}, "price": {"unitPrice": 1.5}, "mediaPrices": {"video": {"unitPrice": 2.0}} }
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -159,10 +158,9 @@ rule_snapshot TEXT NOT NULL, -- workflow: 选中模式的规则片段
|
||||
{
|
||||
"unit": "per_1M", "tiered": true,
|
||||
"rules": [
|
||||
{ "name": "思考-输入≤32000-文本", "match": {"thinking": true, "inputLengthMax": 32000, "mediaType": "text"}, "price": {"input": 0.6, "output": 3.6, "cacheHit": 0.12} },
|
||||
{ "name": "思考-输入32001~128000-文本", "match": {"thinking": true, "inputLengthMin": 32001, "inputLengthMax": 128000, "mediaType": "text"}, "price": {"input": 0.9, "output": 5.4, "cacheHit": 0.18} },
|
||||
{ "name": "思考-输入含音频", "match": {"thinking": true, "mediaType": "audio"}, "price": {"input": 9, "output": 3.6, "cacheHit": 1.8} },
|
||||
{ "name": "非思考-统一价", "match": {"thinking": false}, "price": {"input": 0.3, "output": 1.2, "cacheHit": 0.06} }
|
||||
{ "name": "思考-输入≤32000", "match": {"thinking": true, "inputLengthMax": 32000}, "price": {"input": 0.6, "output": 3.6, "cacheHit": 0.12}, "mediaPrices": {"audio": {"input": 9, "output": 3.6, "cacheHit": 1.8}} },
|
||||
{ "name": "思考-输入32001~128000", "match": {"thinking": true, "inputLengthMin": 32001, "inputLengthMax": 128000}, "price": {"input": 0.9, "output": 5.4, "cacheHit": 0.18}, "mediaPrices": {"audio": {"input": 13.5, "output": 5.4, "cacheHit": 2.7}} },
|
||||
{ "name": "非思考-统一价", "match": {"thinking": false}, "price": {"input": 0.3, "output": 1.2, "cacheHit": 0.06} }
|
||||
]
|
||||
}
|
||||
```
|
||||
@@ -178,7 +176,7 @@ rule_snapshot TEXT NOT NULL, -- workflow: 选中模式的规则片段
|
||||
] }
|
||||
```
|
||||
|
||||
- Save 校验:`unit ∈ {per_1K, per_1M, per_1, per_second, per_minute, per_hour, per_char}`;`tiered:true` 仅 token 单位且 inputLength 档相邻不重叠;match 字段取值合法;price 非负。
|
||||
- Save 校验:`unit ∈ {per_1K, per_1M, per_1, per_second, per_minute, per_hour, per_char}`;`tiered:true` 仅 token 单位且 inputLength 档按下界排序相邻不重叠(上不封顶档须最后);mediaPrices 键 ∈ {text,audio,video,image} 且值非空;match 字段取值合法;price 非负。
|
||||
|
||||
### 4.3 business —— 周期订阅(per_period)
|
||||
|
||||
@@ -207,7 +205,7 @@ per_item | per_second | per_token | per_1K | per_1M | per_1 | per_minute | per_h
|
||||
- **单位计算器**(注册 per_1/per_second/per_minute/per_hour/per_char 五键,base=1/1/60/3600/1,用量源=张数/秒/秒/秒/字数):`cost = 用量/base×unitPrice`。
|
||||
- **阶梯=分档不累加**:tiered 只影响 match 语义(按输入 token 档)与校验(档相邻不重叠),无分段累加逻辑。
|
||||
- **无规则命中 → 报错「无匹配计费规则」**(配置缺失建单即暴露,不静默收 0)。
|
||||
- 折扣:规则级/模型级 `discount` 字段保留(本期模型结算未接,仅建模)。
|
||||
- 折扣:废弃(v0.4 修订为规则级 `mediaPrices`,见 `2026-09-01-pricing-media-price-design.md`)。
|
||||
|
||||
### 5.3 ChargeUsage 扩展(模型计价入参,本期备用)
|
||||
|
||||
@@ -293,7 +291,7 @@ type ChargeUsage struct {
|
||||
| 周期计费用 per_period 通用建模 | 扩月/季只扩 period 允许集合,不改代码结构 |
|
||||
| 阶梯=分档不累加 | 用户确认;匹配统一 rules 首条命中,tiered 仅约束 inputLength 分档校验 |
|
||||
| match 维度全可选 + 首条命中 | 与 model-gateway 移植逻辑一致,规则即优先级 |
|
||||
| 价格项收敛 input/output/cacheHit + unitPrice | 四类模型一套结构;音频输入差价用 mediaType:"audio" 规则表达(删 inputAudio/cacheHitAudio/cacheStorageHour) |
|
||||
| 价格项收敛 input/output/cacheHit + unitPrice | 四类模型一套结构;音频输入差价用 `mediaPrices.audio` 表达(删 inputAudio/cacheHitAudio/cacheStorageHour 与 match.mediaType) |
|
||||
| 输出分辨率自由字符串 | 视频/图片枚举值管理端 UI 下拉提供,DB 不预设 |
|
||||
|
||||
---
|
||||
|
||||
@@ -156,7 +156,7 @@ func validateTieredBands(rules []modelRule) error {
|
||||
```go
|
||||
if len(r.Rules[i].MediaPrices) > 0 {
|
||||
for mt, mp := range r.Rules[i].MediaPrices {
|
||||
if !pricingConsts.ModelMediaSet[mt] {
|
||||
if _, ok := pricingConsts.ModelMediaSet[mt]; !ok {
|
||||
return nil, errors.New("model 费率 mediaPrices 键须为 text/audio/video/image")
|
||||
}
|
||||
if mp == nil {
|
||||
|
||||
Reference in New Issue
Block a user