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:
89
scripts/import_mobile_cloud_pricing_test.go
Normal file
89
scripts/import_mobile_cloud_pricing_test.go
Normal file
@@ -0,0 +1,89 @@
|
||||
//go:build llm_script
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestResolveMobileCloudPricingArticle(t *testing.T) {
|
||||
raw := `{"code":200,"data":{"children":[{"articleTitle":"其他文档","articleId":1,"articleContentPublished":"x"},{"children":[{"articleTitle":"预置模型服务-token按量计费","articleId":91592,"articleContentPublished":"64ec46cbfd7c535db501aff43df5a788"}]}]}}`
|
||||
articleID, contentPublished, err := resolveMobileCloudPricingArticle(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("resolveMobileCloudPricingArticle 返回错误: %v", err)
|
||||
}
|
||||
if articleID != 91592 || contentPublished != "64ec46cbfd7c535db501aff43df5a788" {
|
||||
t.Fatalf("解析价格文章失败: articleID=%d contentPublished=%q", articleID, contentPublished)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMobileCloudPricingHTMLBuildsRecords(t *testing.T) {
|
||||
raw, err := os.ReadFile(filepath.Join("testdata", "mobile_cloud_pricing_sample.html"))
|
||||
if err != nil {
|
||||
t.Fatalf("读取 fixture 失败: %v", err)
|
||||
}
|
||||
records, err := parseMobileCloudPricingHTML(string(raw), "https://ecloud.10086.cn/op-help-center/doc/article/91592")
|
||||
if err != nil {
|
||||
t.Fatalf("parseMobileCloudPricingHTML 返回错误: %v", err)
|
||||
}
|
||||
if len(records) != 8 {
|
||||
t.Fatalf("期望 8 条移动云价格记录,实际 %d", len(records))
|
||||
}
|
||||
recordMap := make(map[string]officialPricingRecord, len(records))
|
||||
for _, record := range records {
|
||||
recordMap[record.ModelID] = record
|
||||
}
|
||||
if recordMap["mobile-cloud-huabei-huhehaote-minimax-m2-5"].Region != "华北-呼和浩特" {
|
||||
t.Fatalf("华北 MiniMax region 错误: %+v", recordMap["mobile-cloud-huabei-huhehaote-minimax-m2-5"])
|
||||
}
|
||||
if recordMap["mobile-cloud-huabei-huhehaote-deepseek-v3-0324"].InputPrice != 2 || recordMap["mobile-cloud-huabei-huhehaote-deepseek-v3-0324"].OutputPrice != 8 {
|
||||
t.Fatalf("DeepSeek-V3-0324 价格错误: %+v", recordMap["mobile-cloud-huabei-huhehaote-deepseek-v3-0324"])
|
||||
}
|
||||
if recordMap["mobile-cloud-huabei-huhehaote-qwq-32b"].ProviderName != "Qwen" || recordMap["mobile-cloud-huabei-huhehaote-qwq-32b"].OutputPrice != 6 {
|
||||
t.Fatalf("QwQ-32B provider/价格错误: %+v", recordMap["mobile-cloud-huabei-huhehaote-qwq-32b"])
|
||||
}
|
||||
if recordMap["mobile-cloud-huabei-huhehaote-bge-m3"].ProviderName != "BAAI" || recordMap["mobile-cloud-huabei-huhehaote-bge-m3"].InputPrice != 0.5 || recordMap["mobile-cloud-huabei-huhehaote-bge-m3"].OutputPrice != 0.5 {
|
||||
t.Fatalf("bge-m3 平价 token 记录错误: %+v", recordMap["mobile-cloud-huabei-huhehaote-bge-m3"])
|
||||
}
|
||||
cosyVoice, ok := recordMap["mobile-cloud-huabei-huhehaote-cosyvoice"]
|
||||
if !ok {
|
||||
t.Fatalf("缺少 CosyVoice 语音计费记录")
|
||||
}
|
||||
if cosyVoice.ProviderName != "Alibaba" || cosyVoice.Modality != "audio" || cosyVoice.PricingMode != "flat" || cosyVoice.FlatPrice != 2 || cosyVoice.PriceUnit != "10k_characters" {
|
||||
t.Fatalf("CosyVoice 语音计费记录错误: %+v", cosyVoice)
|
||||
}
|
||||
senseVoice, ok := recordMap["mobile-cloud-huabei-huhehaote-sensevoice"]
|
||||
if !ok {
|
||||
t.Fatalf("缺少 SenseVoice 语音计费记录")
|
||||
}
|
||||
if senseVoice.ProviderName != "Alibaba" || senseVoice.Modality != "audio" || senseVoice.PricingMode != "flat" || senseVoice.FlatPrice != 0.0007 || senseVoice.PriceUnit != "second" {
|
||||
t.Fatalf("SenseVoice 语音计费记录错误: %+v", senseVoice)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunMobileCloudPricingImportDryRunPrintsSummary(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
err := runMobileCloudPricingImport(mobileCloudPricingImportConfig{
|
||||
OutlineTreeURL: defaultMobileCloudOutlineTreeURL,
|
||||
Fixture: filepath.Join("testdata", "mobile_cloud_pricing_sample.html"),
|
||||
DryRun: true,
|
||||
}, nil, &out)
|
||||
if err != nil {
|
||||
t.Fatalf("runMobileCloudPricingImport 返回错误: %v", err)
|
||||
}
|
||||
output := out.String()
|
||||
for _, want := range []string{
|
||||
"source=mobile-cloud-pricing-import",
|
||||
"models=8",
|
||||
"operator=Mobile Cloud",
|
||||
"dry_run=true",
|
||||
} {
|
||||
if !strings.Contains(output, want) {
|
||||
t.Fatalf("输出缺少 %q,实际: %q", want, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user