From 0ee181a4a73a11c6d11853b642b6cbf14a3795f2 Mon Sep 17 00:00:00 2001 From: phamnazage-jpg Date: Fri, 15 May 2026 22:41:02 +0800 Subject: [PATCH] fix(tencent): detect promotional token plans Relax the Tencent catalog plan matcher so monthly promotional plans are parsed by structure instead of a hard-coded plan-name list. This keeps first-month promotional packages in the catalog and adds a regression sample plus parser test coverage. --- scripts/fetch_tencent_catalog_test.go | 30 +++++++++++ scripts/import_tencent_subscription.go | 44 ++++++++-------- scripts/tencent_catalog_lib.go | 52 +++++++++---------- .../tencent_token_plan_promo_sample.txt | 27 ++++++++++ 4 files changed, 104 insertions(+), 49 deletions(-) create mode 100644 scripts/testdata/tencent_token_plan_promo_sample.txt diff --git a/scripts/fetch_tencent_catalog_test.go b/scripts/fetch_tencent_catalog_test.go index f699947..0e7d156 100644 --- a/scripts/fetch_tencent_catalog_test.go +++ b/scripts/fetch_tencent_catalog_test.go @@ -96,3 +96,33 @@ func TestRunTencentCatalogDryRunPrintsSummary(t *testing.T) { } } } + +func TestParseTencentCatalogExtractsPromotionalPlans(t *testing.T) { + raw, err := os.ReadFile(filepath.Join("testdata", "tencent_token_plan_promo_sample.txt")) + if err != nil { + t.Fatalf("读取促销样例失败: %v", err) + } + + catalog, err := parseTencentCatalog(string(raw)) + if err != nil { + t.Fatalf("parseTencentCatalog 失败: %v", err) + } + + if len(catalog.Plans) != 2 { + t.Fatalf("期望 2 个套餐,实际 %d", len(catalog.Plans)) + } + + first := catalog.Plans[0] + if first.Series != "通用 Token Plan" { + t.Fatalf("套餐系列错误: %q", first.Series) + } + if first.Tier != "首月活动版" { + t.Fatalf("促销套餐档位错误: %q", first.Tier) + } + if first.Price != "19元/月" { + t.Fatalf("促销套餐价格错误: %q", first.Price) + } + if first.Scene != "首购用户首月优惠,次月恢复标准价。" { + t.Fatalf("促销套餐说明错误: %q", first.Scene) + } +} diff --git a/scripts/import_tencent_subscription.go b/scripts/import_tencent_subscription.go index 6115ae2..c70df5b 100644 --- a/scripts/import_tencent_subscription.go +++ b/scripts/import_tencent_subscription.go @@ -26,30 +26,30 @@ type importTencentSubscriptionConfig struct { } type subscriptionPlanRow struct { - ProviderName string - ProviderCN string + ProviderName string + ProviderCN string ProviderCountry string - OperatorName string - OperatorCN string + OperatorName string + OperatorCN string OperatorCountry string - OperatorType string - PlanFamily string - PlanCode string - PlanName string - Tier string - BillingCycle string - Currency string - ListPrice float64 - PriceUnit string - QuotaValue int64 - QuotaUnit string - ContextWindow int - PlanScope string - ModelScope string - SourceURL string - PublishedAt string - EffectiveDate string - Notes string + OperatorType string + PlanFamily string + PlanCode string + PlanName string + Tier string + BillingCycle string + Currency string + ListPrice float64 + PriceUnit string + QuotaValue int64 + QuotaUnit string + ContextWindow int + PlanScope string + ModelScope string + SourceURL string + PublishedAt string + EffectiveDate string + Notes string } func main() { diff --git a/scripts/tencent_catalog_lib.go b/scripts/tencent_catalog_lib.go index 2fdb764..cab0f27 100644 --- a/scripts/tencent_catalog_lib.go +++ b/scripts/tencent_catalog_lib.go @@ -188,22 +188,7 @@ func extractSeriesHeading(line string) string { } func tryParseTencentPlan(lines []string, start int, series string) (tencentPlan, int, bool) { - if start+4 >= len(lines) { - return tencentPlan{}, start, false - } - if !isTencentPlanName(lines[start]) { - return tencentPlan{}, start, false - } - if !isTencentPlanTier(lines[start+1]) { - return tencentPlan{}, start, false - } - if !strings.Contains(lines[start+2], "订阅月") { - return tencentPlan{}, start, false - } - if !strings.Contains(lines[start+3], "Tokens") { - return tencentPlan{}, start, false - } - if !strings.Contains(lines[start+4], "元/月") { + if !looksLikeTencentPlan(lines, start) { return tencentPlan{}, start, false } @@ -216,7 +201,7 @@ func tryParseTencentPlan(lines []string, start int, series string) (tencentPlan, } nextIndex := start + 4 - if start+5 < len(lines) && !strings.HasPrefix(lines[start+5], "### ") && !isTencentPlanName(lines[start+5]) { + if start+5 < len(lines) && !strings.HasPrefix(lines[start+5], "### ") && !looksLikeTencentPlan(lines, start+5) { plan.Scene = lines[start+5] nextIndex = start + 5 } @@ -247,7 +232,7 @@ func tryParseTencentModel(lines []string, start int, series string) (tencentMode if strings.HasPrefix(line, "## ") || strings.HasPrefix(line, "### ") { break } - if isTencentPlanName(line) && i+1 < len(lines) && isTencentPlanTier(lines[i+1]) { + if looksLikeTencentPlan(lines, i) { break } if i+1 < len(lines) && isTencentModelID(lines[i+1]) && !isReservedTencentLine(line) { @@ -262,19 +247,32 @@ func tryParseTencentModel(lines []string, start int, series string) (tencentMode return model, nextIndex, true } -func isTencentPlanName(line string) bool { - switch line { - case "体验套餐", "基础套餐", "进阶套餐", "专业套餐": - return true - default: - return false - } -} - func isTencentPlanTier(line string) bool { return strings.HasPrefix(line, "(") && strings.HasSuffix(line, ")") } +func looksLikeTencentPlan(lines []string, start int) bool { + if start+4 >= len(lines) { + return false + } + if isReservedTencentLine(lines[start]) { + return false + } + if isTencentModelID(lines[start]) { + return false + } + if !isTencentPlanTier(lines[start+1]) { + return false + } + if !strings.Contains(lines[start+2], "订阅月") { + return false + } + if !strings.Contains(lines[start+3], "Tokens") { + return false + } + return strings.Contains(lines[start+4], "元/月") +} + func isReservedTencentLine(line string) bool { if strings.HasPrefix(line, "#") { return true diff --git a/scripts/testdata/tencent_token_plan_promo_sample.txt b/scripts/testdata/tencent_token_plan_promo_sample.txt new file mode 100644 index 0000000..1ec2775 --- /dev/null +++ b/scripts/testdata/tencent_token_plan_promo_sample.txt @@ -0,0 +1,27 @@ +# Token Plan 个人版套餐概览 +最近更新时间:2026-05-14 09:00:00 + +## 通用 Token Plan 套餐 +### 套餐详情 +首月活动套餐 +(首月活动版) +每订阅月 +3500万 Tokens +19元/月 +首购用户首月优惠,次月恢复标准价。 + +基础套餐 +(Standard) +每订阅月 +1亿 Tokens +99元/月 +日常使用,高性价比。 + +### 可用模型 +GLM-5 +glm-5 +深度思考、文本生成 + +Hunyuan-T1 +hunyuan-t1 +文本生成