Files
llm-intelligence/scripts/minimax_subscription_lib.go
phamnazage-jpg 958245537a feat(imports): add real pricing and subscription collectors
Add plan catalog and subscription schema support, seed baselines, and real importers for core domestic subscriptions plus stable official pricing sources.

This commit also hardens the shared fetch layers so the importers can support live collection and database writes instead of relying on manual placeholders alone.
2026-05-15 22:32:57 +08:00

189 lines
7.2 KiB
Go

//go:build llm_script
package main
import (
"fmt"
"regexp"
"strings"
)
const defaultMinimaxTokenPlanURL = "https://platform.minimax.io/docs/guides/pricing-token-plan"
type minimaxPlanSpec struct {
billingCycle string
priceUnit string
blockPattern string
modelScope []string
tiers []string
planCodes []string
planNames []string
quotaUnit string
}
func parseMinimaxTokenPlans(raw string) ([]subscriptionImportRecord, error) {
publishedAt, known := publishedAtFromText(raw)
normalized := normalizeMinimaxTokenPlanText(raw)
specs := []minimaxPlanSpec{
{
billingCycle: "monthly",
priceUnit: "USD/month",
blockPattern: `Monthly.*?Starter\s+Plus\s+Max\s+Price\s+\$([\d,]+)\s*/month\s+\$([\d,]+)\s*/month\s+\$([\d,]+)\s*/month\s+M2\.7\s+([\d,]+)\s+requests/5hrs\s+([\d,]+)\s+requests/5hrs\s+([\d,]+)\s+requests/5hrs`,
modelScope: []string{"MiniMax-M2.7"},
tiers: []string{"Starter", "Plus", "Max"},
planCodes: []string{"minimax-token-plan-starter", "minimax-token-plan-plus", "minimax-token-plan-max"},
planNames: []string{"MiniMax Token Plan Starter", "MiniMax Token Plan Plus", "MiniMax Token Plan Max"},
quotaUnit: "requests/5hrs",
},
{
billingCycle: "monthly",
priceUnit: "USD/month",
blockPattern: `Monthly.*?Highspeed Plans\s+Plus-Highspeed\s+Max-Highspeed\s+Ultra-Highspeed\s+Price\s+\$([\d,]+)\s*/month\s+\$([\d,]+)\s*/month\s+\$([\d,]+)\s*/month\s+M2\.7-highspeed\s+([\d,]+)\s+requests/5hrs\s+([\d,]+)\s+requests/5hrs\s+([\d,]+)\s+requests/5hrs`,
modelScope: []string{"MiniMax-M2.7-Highspeed"},
tiers: []string{"Plus-Highspeed", "Max-Highspeed", "Ultra-Highspeed"},
planCodes: []string{"minimax-token-plan-plus-highspeed", "minimax-token-plan-max-highspeed", "minimax-token-plan-ultra-highspeed"},
planNames: []string{"MiniMax Token Plan Plus-Highspeed", "MiniMax Token Plan Max-Highspeed", "MiniMax Token Plan Ultra-Highspeed"},
quotaUnit: "requests/5hrs",
},
{
billingCycle: "yearly",
priceUnit: "USD/year",
blockPattern: `Yearly.*?Starter\s+Plus\s+Max\s+Price\s+\$([\d,]+)\s*/year\s+\$([\d,]+)\s*/year\s+\$([\d,]+)\s*/year\s+M2\.7\s+([\d,]+)\s+requests/5hrs\s+([\d,]+)\s+requests/5hrs\s+([\d,]+)\s+requests/5hrs`,
modelScope: []string{"MiniMax-M2.7"},
tiers: []string{"Starter-Yearly", "Plus-Yearly", "Max-Yearly"},
planCodes: []string{"minimax-token-plan-starter-yearly", "minimax-token-plan-plus-yearly", "minimax-token-plan-max-yearly"},
planNames: []string{"MiniMax Token Plan Starter Yearly", "MiniMax Token Plan Plus Yearly", "MiniMax Token Plan Max Yearly"},
quotaUnit: "requests/5hrs",
},
{
billingCycle: "yearly",
priceUnit: "USD/year",
blockPattern: `Yearly.*?Highspeed Plans\s+Plus-Highspeed\s+Max-Highspeed\s+Ultra-Highspeed\s+Price\s+\$([\d,]+)\s*/year\s+\$([\d,]+)\s*/year\s+\$([\d,]+)\s*/year\s+M2\.7-highspeed\s+([\d,]+)\s+requests/5hrs\s+([\d,]+)\s+requests/5hrs\s+([\d,]+)\s+requests/5hrs`,
modelScope: []string{"MiniMax-M2.7-Highspeed"},
tiers: []string{"Plus-Highspeed-Yearly", "Max-Highspeed-Yearly", "Ultra-Highspeed-Yearly"},
planCodes: []string{"minimax-token-plan-plus-highspeed-yearly", "minimax-token-plan-max-highspeed-yearly", "minimax-token-plan-ultra-highspeed-yearly"},
planNames: []string{"MiniMax Token Plan Plus-Highspeed Yearly", "MiniMax Token Plan Max-Highspeed Yearly", "MiniMax Token Plan Ultra-Highspeed Yearly"},
quotaUnit: "requests/5hrs",
},
}
var records []subscriptionImportRecord
for _, spec := range specs {
parsed, err := parseMinimaxPlanBlock(normalized, spec, publishedAt)
if err != nil {
return nil, err
}
records = append(records, parsed...)
}
standardNotes := extractMinimaxNotes(normalized, []string{
"Speech 2.8",
"image-01",
"Hailuo-2.3-Fast",
"Hailuo-2.3",
"Music-2.6",
})
for i := range records {
records[i].PublishedAtKnown = known
if strings.Contains(records[i].PlanCode, "highspeed") {
records[i].Notes = joinNonEmptyNotes(records[i].Notes, "高速版覆盖 MiniMax-M2.7-Highspeed。")
continue
}
records[i].Notes = joinNonEmptyNotes(records[i].Notes, standardNotes)
}
return records, nil
}
func parseMinimaxPlanBlock(raw string, spec minimaxPlanSpec, publishedAt string) ([]subscriptionImportRecord, error) {
match := regexp.MustCompile(spec.blockPattern).FindStringSubmatch(raw)
if len(match) != 7 {
return nil, fmt.Errorf("unexpected minimax %s block", spec.billingCycle)
}
records := make([]subscriptionImportRecord, 0, 3)
for i := range spec.tiers {
records = append(records, subscriptionImportRecord{
ProviderName: "MiniMax",
ProviderNameCn: "MiniMax",
ProviderCountry: "CN",
ProviderWebsite: "https://platform.minimax.io",
OperatorName: "MiniMax",
OperatorNameCn: "MiniMax",
OperatorCountry: "CN",
OperatorWebsite: "https://platform.minimax.io/docs/guides/pricing-overview",
OperatorType: "official",
PlanFamily: "token_plan",
PlanCode: spec.planCodes[i],
PlanName: spec.planNames[i],
Tier: spec.tiers[i],
BillingCycle: spec.billingCycle,
Currency: "USD",
ListPrice: mustParseSubscriptionPrice(match[i+1]),
PriceUnit: spec.priceUnit,
QuotaValue: mustParseSubscriptionInt64(match[i+4]),
QuotaUnit: spec.quotaUnit,
PlanScope: "Token Plan",
ModelScope: append([]string(nil), spec.modelScope...),
SourceURL: defaultMinimaxTokenPlanURL,
PublishedAt: publishedAt,
EffectiveDate: effectiveDateFromPublishedAt(publishedAt),
PublishedAtKnown: true,
})
}
return records, nil
}
func normalizeMinimaxTokenPlanText(raw string) string {
replacer := strings.NewReplacer(
"High-Speed", "Highspeed",
"High Speed", "Highspeed",
"Max-High-Speed", "Max-Highspeed",
"Ultra-High-Speed", "Ultra-Highspeed",
"Plus `Cost-Effective`", "Plus",
"Max `Extra Large`", "Max",
"Starter `Save $20`", "Starter",
"Plus `Save $40`", "Plus",
"Max `Save $100`", "Max",
"Plus-Highspeed `Save $80`", "Plus-Highspeed",
"Max-Highspeed `Save $160`", "Max-Highspeed",
"Ultra-Highspeed `Save $300`", "Ultra-Highspeed",
"Subscribe Now Standard Plans:", "",
"Subscribe Now", "",
"Standard Plans:", "",
"Highspeed Plans:", "Highspeed Plans",
)
normalized := replacer.Replace(raw)
normalized = strings.ReplaceAll(normalized, "\r\n", "\n")
normalized = strings.ReplaceAll(normalized, "\r", "\n")
normalized = strings.ReplaceAll(normalized, "|", " ")
normalized = strings.ReplaceAll(normalized, "---", " ")
normalized = regexp.MustCompile(`\s+`).ReplaceAllString(normalized, " ")
return strings.TrimSpace(normalized)
}
func extractMinimaxNotes(raw string, markers []string) string {
var hits []string
for _, marker := range markers {
if strings.Contains(raw, marker) {
hits = append(hits, marker)
}
}
if len(hits) == 0 {
return ""
}
return "附带配额包含 " + strings.Join(hits, " / ") + "。"
}
func joinNonEmptyNotes(parts ...string) string {
filtered := make([]string, 0, len(parts))
for _, part := range parts {
part = strings.TrimSpace(part)
if part == "" {
continue
}
filtered = append(filtered, part)
}
return strings.Join(filtered, " ")
}