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.
This commit is contained in:
phamnazage-jpg
2026-05-15 22:41:02 +08:00
parent d5d18e987e
commit 0ee181a4a7
4 changed files with 104 additions and 49 deletions

View File

@@ -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)
}
}

View File

@@ -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() {

View File

@@ -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

View File

@@ -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
文本生成