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:
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -188,22 +188,7 @@ func extractSeriesHeading(line string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func tryParseTencentPlan(lines []string, start int, series string) (tencentPlan, int, bool) {
|
func tryParseTencentPlan(lines []string, start int, series string) (tencentPlan, int, bool) {
|
||||||
if start+4 >= len(lines) {
|
if !looksLikeTencentPlan(lines, start) {
|
||||||
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], "元/月") {
|
|
||||||
return tencentPlan{}, start, false
|
return tencentPlan{}, start, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +201,7 @@ func tryParseTencentPlan(lines []string, start int, series string) (tencentPlan,
|
|||||||
}
|
}
|
||||||
|
|
||||||
nextIndex := start + 4
|
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]
|
plan.Scene = lines[start+5]
|
||||||
nextIndex = 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, "### ") {
|
if strings.HasPrefix(line, "## ") || strings.HasPrefix(line, "### ") {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if isTencentPlanName(line) && i+1 < len(lines) && isTencentPlanTier(lines[i+1]) {
|
if looksLikeTencentPlan(lines, i) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if i+1 < len(lines) && isTencentModelID(lines[i+1]) && !isReservedTencentLine(line) {
|
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
|
return model, nextIndex, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func isTencentPlanName(line string) bool {
|
|
||||||
switch line {
|
|
||||||
case "体验套餐", "基础套餐", "进阶套餐", "专业套餐":
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isTencentPlanTier(line string) bool {
|
func isTencentPlanTier(line string) bool {
|
||||||
return strings.HasPrefix(line, "(") && strings.HasSuffix(line, ")")
|
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 {
|
func isReservedTencentLine(line string) bool {
|
||||||
if strings.HasPrefix(line, "#") {
|
if strings.HasPrefix(line, "#") {
|
||||||
return true
|
return true
|
||||||
|
|||||||
27
scripts/testdata/tencent_token_plan_promo_sample.txt
vendored
Normal file
27
scripts/testdata/tencent_token_plan_promo_sample.txt
vendored
Normal 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
|
||||||
|
文本生成
|
||||||
Reference in New Issue
Block a user