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.
158 lines
6.5 KiB
Go
158 lines
6.5 KiB
Go
//go:build llm_script
|
||
|
||
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"regexp"
|
||
"strings"
|
||
)
|
||
|
||
const defaultHuaweiPackagePlanURL = "https://support.huaweicloud.com/price-maas/price-maas-0002.html"
|
||
|
||
func parseHuaweiPackageCatalog(raw string) ([]subscriptionImportRecord, error) {
|
||
publishedAt, known := publishedAtFromText(raw)
|
||
type packDef struct {
|
||
QuotaRaw string
|
||
BillingCycle string
|
||
CodeSuffix string
|
||
ReadableCycle string
|
||
}
|
||
packs := []packDef{
|
||
{QuotaRaw: "100万", BillingCycle: "monthly", CodeSuffix: "100w-1m", ReadableCycle: "1个月"},
|
||
{QuotaRaw: "1000万", BillingCycle: "monthly", CodeSuffix: "1000w-1m", ReadableCycle: "1个月"},
|
||
{QuotaRaw: "1亿", BillingCycle: "quarterly", CodeSuffix: "1y-3m", ReadableCycle: "3个月"},
|
||
{QuotaRaw: "10亿", BillingCycle: "quarterly", CodeSuffix: "10y-3m", ReadableCycle: "3个月"},
|
||
}
|
||
|
||
records := make([]subscriptionImportRecord, 0, 8)
|
||
for _, modelVersion := range []string{"1", "2"} {
|
||
modelLabel := "DeepSeek-V3." + modelVersion
|
||
versionCode := strings.ReplaceAll("v3."+modelVersion, ".", "-")
|
||
foundForModel := 0
|
||
for _, pack := range packs {
|
||
quotaValue := parseHuaweiTokenQuota(pack.QuotaRaw)
|
||
price, found := findHuaweiPackPrice(raw, modelLabel, pack.QuotaRaw, pack.ReadableCycle)
|
||
if !found {
|
||
continue
|
||
}
|
||
records = append(records, subscriptionImportRecord{
|
||
ProviderName: "Huawei",
|
||
ProviderNameCn: "华为",
|
||
ProviderCountry: "CN",
|
||
ProviderWebsite: "https://www.huaweicloud.com",
|
||
OperatorName: "Huawei Cloud",
|
||
OperatorNameCn: "华为云",
|
||
OperatorCountry: "CN",
|
||
OperatorWebsite: "https://support.huaweicloud.com",
|
||
OperatorType: "cloud",
|
||
PlanFamily: "package_plan",
|
||
PlanCode: fmt.Sprintf("huawei-deepseek-%s-package-%s", versionCode, pack.CodeSuffix),
|
||
PlanName: fmt.Sprintf("华为云 MaaS %s 套餐包 %s", modelLabel, pack.QuotaRaw),
|
||
Tier: modelLabel,
|
||
BillingCycle: pack.BillingCycle,
|
||
Currency: "CNY",
|
||
ListPrice: price,
|
||
PriceUnit: "CNY/pack",
|
||
QuotaValue: quotaValue,
|
||
QuotaUnit: "tokens/pack",
|
||
PlanScope: "MaaS 文本生成模型套餐包",
|
||
ModelScope: []string{modelLabel},
|
||
SourceURL: defaultHuaweiPackagePlanURL,
|
||
PublishedAt: publishedAt,
|
||
EffectiveDate: effectiveDateFromPublishedAt(publishedAt),
|
||
Notes: fmt.Sprintf("官方套餐包,有效期 %s,仅抵扣 %s Token 用量。", pack.ReadableCycle, modelLabel),
|
||
PublishedAtKnown: known,
|
||
})
|
||
foundForModel++
|
||
}
|
||
_ = foundForModel
|
||
}
|
||
if len(records) == 0 {
|
||
return nil, fmt.Errorf("no huawei package plan matched from source page")
|
||
}
|
||
return records, nil
|
||
}
|
||
|
||
func fallbackHuaweiPackageCatalog() []subscriptionImportRecord {
|
||
publishedAt := "2026-05-14 00:00:00"
|
||
effectiveDate := "2026-05-14"
|
||
type packRow struct {
|
||
ModelScope string
|
||
VersionCode string
|
||
QuotaValue int64
|
||
QuotaLabel string
|
||
BillingCycle string
|
||
CodeSuffix string
|
||
Price float64
|
||
ReadableCycle string
|
||
}
|
||
packs := []packRow{
|
||
{ModelScope: "DeepSeek-V3.1", VersionCode: "v3-1", QuotaValue: 1000000, QuotaLabel: "100万", BillingCycle: "monthly", CodeSuffix: "100w-1m", Price: 5.6, ReadableCycle: "1个月"},
|
||
{ModelScope: "DeepSeek-V3.1", VersionCode: "v3-1", QuotaValue: 10000000, QuotaLabel: "1000万", BillingCycle: "monthly", CodeSuffix: "1000w-1m", Price: 56, ReadableCycle: "1个月"},
|
||
{ModelScope: "DeepSeek-V3.1", VersionCode: "v3-1", QuotaValue: 100000000, QuotaLabel: "1亿", BillingCycle: "quarterly", CodeSuffix: "1y-3m", Price: 558, ReadableCycle: "3个月"},
|
||
{ModelScope: "DeepSeek-V3.1", VersionCode: "v3-1", QuotaValue: 1000000000, QuotaLabel: "10亿", BillingCycle: "quarterly", CodeSuffix: "10y-3m", Price: 5598, ReadableCycle: "3个月"},
|
||
{ModelScope: "DeepSeek-V3.2", VersionCode: "v3-2", QuotaValue: 1000000, QuotaLabel: "100万", BillingCycle: "monthly", CodeSuffix: "100w-1m", Price: 2.2, ReadableCycle: "1个月"},
|
||
{ModelScope: "DeepSeek-V3.2", VersionCode: "v3-2", QuotaValue: 10000000, QuotaLabel: "1000万", BillingCycle: "monthly", CodeSuffix: "1000w-1m", Price: 22, ReadableCycle: "1个月"},
|
||
{ModelScope: "DeepSeek-V3.2", VersionCode: "v3-2", QuotaValue: 100000000, QuotaLabel: "1亿", BillingCycle: "quarterly", CodeSuffix: "1y-3m", Price: 219, ReadableCycle: "3个月"},
|
||
{ModelScope: "DeepSeek-V3.2", VersionCode: "v3-2", QuotaValue: 1000000000, QuotaLabel: "10亿", BillingCycle: "quarterly", CodeSuffix: "10y-3m", Price: 2199, ReadableCycle: "3个月"},
|
||
}
|
||
|
||
records := make([]subscriptionImportRecord, 0, len(packs))
|
||
for _, pack := range packs {
|
||
records = append(records, subscriptionImportRecord{
|
||
ProviderName: "Huawei",
|
||
ProviderNameCn: "华为",
|
||
ProviderCountry: "CN",
|
||
ProviderWebsite: "https://www.huaweicloud.com",
|
||
OperatorName: "Huawei Cloud",
|
||
OperatorNameCn: "华为云",
|
||
OperatorCountry: "CN",
|
||
OperatorWebsite: "https://support.huaweicloud.com",
|
||
OperatorType: "cloud",
|
||
PlanFamily: "package_plan",
|
||
PlanCode: fmt.Sprintf("huawei-deepseek-%s-package-%s", pack.VersionCode, pack.CodeSuffix),
|
||
PlanName: fmt.Sprintf("华为云 MaaS %s 套餐包 %s", pack.ModelScope, pack.QuotaLabel),
|
||
Tier: pack.ModelScope,
|
||
BillingCycle: pack.BillingCycle,
|
||
Currency: "CNY",
|
||
ListPrice: pack.Price,
|
||
PriceUnit: "CNY/pack",
|
||
QuotaValue: pack.QuotaValue,
|
||
QuotaUnit: "tokens/pack",
|
||
PlanScope: "MaaS 文本生成模型套餐包",
|
||
ModelScope: []string{pack.ModelScope},
|
||
SourceURL: defaultHuaweiPackagePlanURL,
|
||
PublishedAt: publishedAt,
|
||
EffectiveDate: effectiveDate,
|
||
Notes: fmt.Sprintf("官方价格页动态渲染,当前回退至最近核验的官方快照;有效期 %s,仅抵扣 %s Token 用量。", pack.ReadableCycle, pack.ModelScope),
|
||
PublishedAtKnown: true,
|
||
})
|
||
}
|
||
return records
|
||
}
|
||
|
||
func findHuaweiPackPrice(raw string, modelLabel string, quotaRaw string, cycle string) (float64, bool) {
|
||
pattern := regexp.MustCompile(`(?s)` + regexp.QuoteMeta(modelLabel) + `.*?` + regexp.QuoteMeta(quotaRaw) + `.*?` + regexp.QuoteMeta(cycle) + `.*?([\d.]+)`)
|
||
match := pattern.FindStringSubmatch(raw)
|
||
if len(match) != 2 {
|
||
return 0, false
|
||
}
|
||
return mustParseSubscriptionPrice(match[1]), true
|
||
}
|
||
|
||
func parseHuaweiTokenQuota(raw string) int64 {
|
||
switch strings.TrimSpace(raw) {
|
||
case "100万":
|
||
return 1000000
|
||
case "1000万":
|
||
return 10000000
|
||
case "1亿":
|
||
return 100000000
|
||
case "10亿":
|
||
return 1000000000
|
||
default:
|
||
return 0
|
||
}
|
||
}
|