feat(region_pricing): 扩展非 token 统一计费字段,支持语音按字符/秒计费
- 新增 region_pricing.pricing_mode / price_unit / flat_price 字段 - 新增 migration 016_region_pricing_non_token_units.sql - officialPricingRecord 新增 PricingMode/PriceUnit/FlatPrice 字段 - detectModality 新增 audio 模态检测(voice/audio/speech) - providerMetadata 新增 BAAI/ByteDance/China Mobile 元数据 - import_mobile_cloud_pricing.go: 解析语音计费表(CosyVoice/SenseVoice) - CosyVoice: 2元/万字符 → pricingMode=flat, priceUnit=10k_characters - SenseVoice: 0.0007元/秒 → pricingMode=flat, priceUnit=second - mobileCloudProviderName 新增 cosyvoice/sensevoice → Alibaba 映射 - cmd/server: modelResponse 新增 pricingMode/priceUnit/flatPrice,API 字段说明同步更新 - 新增 TestModelsHandlerReturnsFlatPricingFields 测试
This commit is contained in:
@@ -34,6 +34,9 @@ type officialPricingRecord struct {
|
||||
OperatorType string
|
||||
Region string
|
||||
Currency string
|
||||
PricingMode string
|
||||
PriceUnit string
|
||||
FlatPrice float64
|
||||
InputPrice float64
|
||||
OutputPrice float64
|
||||
ContextLength int
|
||||
@@ -81,16 +84,21 @@ func upsertOfficialPricingRecords(db *sql.DB, records []officialPricingRecord, b
|
||||
_, err = db.Exec(
|
||||
`INSERT INTO region_pricing (
|
||||
model_id, operator_id, region, currency,
|
||||
pricing_mode, price_unit, flat_price,
|
||||
input_price_per_mtok, output_price_per_mtok,
|
||||
is_free, effective_date, source_url, source_type,
|
||||
free_quota, free_limitations, rate_limit
|
||||
) VALUES (
|
||||
$1, $2, $3, $4,
|
||||
$5, $6, $7, CURRENT_DATE, $8, $9,
|
||||
$10, $11, $12
|
||||
$5, $6, $7,
|
||||
$8, $9, $10, CURRENT_DATE, $11, $12,
|
||||
$13, $14, $15
|
||||
)
|
||||
ON CONFLICT (model_id, operator_id, region, currency, effective_date)
|
||||
DO UPDATE SET
|
||||
pricing_mode = EXCLUDED.pricing_mode,
|
||||
price_unit = EXCLUDED.price_unit,
|
||||
flat_price = EXCLUDED.flat_price,
|
||||
input_price_per_mtok = EXCLUDED.input_price_per_mtok,
|
||||
output_price_per_mtok = EXCLUDED.output_price_per_mtok,
|
||||
is_free = EXCLUDED.is_free,
|
||||
@@ -101,6 +109,7 @@ func upsertOfficialPricingRecords(db *sql.DB, records []officialPricingRecord, b
|
||||
rate_limit = EXCLUDED.rate_limit,
|
||||
updated_at = CURRENT_TIMESTAMP`,
|
||||
modelID, operatorID, record.Region, record.Currency,
|
||||
fallbackPricingMode(record.PricingMode), fallbackPriceUnit(record.PriceUnit), nullIfZeroFloat(record.FlatPrice),
|
||||
record.InputPrice, record.OutputPrice, record.IsFree, record.SourceURL, sourceType,
|
||||
nullIfBlank(freeQuota), freeLimitations, rateLimit,
|
||||
)
|
||||
@@ -260,6 +269,29 @@ func fallbackModality(raw string) string {
|
||||
return value
|
||||
}
|
||||
|
||||
func fallbackPricingMode(raw string) string {
|
||||
value := strings.TrimSpace(raw)
|
||||
if value == "" {
|
||||
return "input_output"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func fallbackPriceUnit(raw string) string {
|
||||
value := strings.TrimSpace(raw)
|
||||
if value == "" {
|
||||
return "million_tokens"
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func nullIfZeroFloat(value float64) any {
|
||||
if value == 0 {
|
||||
return nil
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func fetchRawPricingPage(url string, fixture string, client *http.Client) (string, error) {
|
||||
return fetchRawPricingPageWithOptions(url, fixture, client, officialPricingFetchOptions{
|
||||
AcceptLanguage: "zh-CN,zh;q=0.9,en;q=0.8",
|
||||
@@ -399,6 +431,8 @@ func detectModality(modelName string) string {
|
||||
switch {
|
||||
case strings.Contains(lower, "coder"), strings.Contains(lower, "code"):
|
||||
return "code"
|
||||
case strings.Contains(lower, "voice"), strings.Contains(lower, "audio"), strings.Contains(lower, "speech"):
|
||||
return "audio"
|
||||
case strings.Contains(lower, "vision"), strings.Contains(lower, "vl"), strings.Contains(lower, "omni"), strings.Contains(lower, "multi"), strings.Contains(lower, "live"):
|
||||
return "multimodal"
|
||||
default:
|
||||
@@ -414,8 +448,14 @@ func providerMetadata(providerName string) (string, string, string) {
|
||||
return "亚马逊", "US", "https://aws.amazon.com"
|
||||
case "Anthropic":
|
||||
return "Anthropic", "US", "https://www.anthropic.com"
|
||||
case "BAAI":
|
||||
return "智源", "CN", "https://www.baai.ac.cn"
|
||||
case "Baidu":
|
||||
return "百度", "CN", "https://cloud.baidu.com"
|
||||
case "ByteDance":
|
||||
return "字节跳动", "CN", "https://www.volcengine.com"
|
||||
case "China Mobile":
|
||||
return "中国移动", "CN", "https://ecloud.10086.cn"
|
||||
case "Cloudflare":
|
||||
return "Cloudflare", "US", "https://www.cloudflare.com"
|
||||
case "Cohere":
|
||||
|
||||
Reference in New Issue
Block a user