189 lines
7.2 KiB
Go
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, " ")
|
||
|
|
}
|