//go:build llm_script && !scripts_pkg package main import ( "database/sql" "encoding/json" "flag" "fmt" "io" "net/http" "os" "sort" "strings" "time" ) const ( defaultHuaweiMaaSPricingURL = "https://portal.huaweicloud.com/api/calculator/rest/cbc/portalcalculatornodeservice/v4/api/productInfo?urlPath=maas&language=zh-cn&sign=common" defaultHuaweiMaaSPricingSourceURL = "https://support.huaweicloud.com/price-maas/price-maas-0002.html" ) type huaweiMaaSPricingImportConfig struct { URL string Fixture string DryRun bool Timeout time.Duration } type huaweiMaaSPricingEnvelope struct { Product map[string][]huaweiMaaSPricingRow `json:"product"` } type huaweiMaaSPricingRow struct { ResourceSpecCode string `json:"resourceSpecCode"` ResourceSpecType string `json:"resourceSpecType"` ModelName string `json:"Model Name"` PlanList []huaweiMaaSPricingPlan `json:"planList"` } type huaweiMaaSPricingPlan struct { UsageFactor string `json:"usageFactor"` Amount float64 `json:"amount"` } func main() { loadSubscriptionImportEnv() var url string var fixture string var dryRun bool var timeoutSeconds int flag.StringVar(&url, "url", defaultHuaweiMaaSPricingURL, "华为云 MaaS 官方价格 JSON API") flag.StringVar(&fixture, "fixture", "", "华为云 MaaS 价格样例文件") flag.BoolVar(&dryRun, "dry-run", false, "仅解析并打印摘要,不写入数据库") flag.IntVar(&timeoutSeconds, "timeout", 20, "请求超时(秒)") flag.Parse() cfg := huaweiMaaSPricingImportConfig{URL: url, Fixture: fixture, DryRun: dryRun, Timeout: time.Duration(timeoutSeconds) * time.Second} var db *sql.DB var err error if !cfg.DryRun { db, err = subscriptionImportDB() if err != nil { fmt.Fprintf(os.Stderr, "open db: %v\n", err) os.Exit(1) } defer db.Close() } if err := runHuaweiMaaSPricingImport(cfg, db, os.Stdout); err != nil { fmt.Fprintf(os.Stderr, "import_huawei_maas_pricing: %v\n", err) os.Exit(1) } } func runHuaweiMaaSPricingImport(cfg huaweiMaaSPricingImportConfig, db *sql.DB, out io.Writer) error { client := &http.Client{Timeout: cfg.Timeout} raw, err := fetchRawPricingPage(cfg.URL, cfg.Fixture, client) if err != nil { return err } records, err := parseHuaweiMaaSPricingCatalog(raw) if err != nil { return err } records = dedupeOfficialPricingRecords(records) if cfg.DryRun { _, err = fmt.Fprintf(out, "source=huawei-maas-pricing-import models=%d operator=%s dry_run=true\n", len(records), records[0].OperatorName) return err } if db == nil { return fmt.Errorf("db is required when dry-run=false") } if err := upsertOfficialPricingRecords(db, records, "huawei-maas-pricing-import"); err != nil { return err } var tableRows int if err := db.QueryRow(`SELECT COUNT(*) FROM region_pricing`).Scan(&tableRows); err != nil { return fmt.Errorf("count region_pricing: %w", err) } _, err = fmt.Fprintf(out, "source=huawei-maas-pricing-import models=%d operator=%s table_rows=%d dry_run=false\n", len(records), records[0].OperatorName, tableRows) return err } func parseHuaweiMaaSPricingCatalog(raw string) ([]officialPricingRecord, error) { var envelope huaweiMaaSPricingEnvelope if err := json.Unmarshal([]byte(raw), &envelope); err != nil { return nil, fmt.Errorf("parse huawei maas pricing json: %w", err) } items := envelope.Product["modelarts_modelarts.tokens"] if len(items) == 0 { return nil, fmt.Errorf("unexpected huawei maas pricing content") } type grouped struct { providerType string modelName string inputs []float64 outputs []float64 } byCode := map[string]*grouped{} for _, item := range items { entry := byCode[item.ResourceSpecCode] if entry == nil { entry = &grouped{providerType: item.ResourceSpecType, modelName: firstNonEmptyText(item.ModelName, item.ResourceSpecCode)} byCode[item.ResourceSpecCode] = entry } for _, plan := range item.PlanList { switch { case strings.HasPrefix(plan.UsageFactor, "input"): entry.inputs = append(entry.inputs, plan.Amount) case strings.HasPrefix(plan.UsageFactor, "output"): entry.outputs = append(entry.outputs, plan.Amount) } } } keys := make([]string, 0, len(byCode)) for code := range byCode { keys = append(keys, code) } sort.Strings(keys) records := make([]officialPricingRecord, 0, len(keys)) for _, code := range keys { entry := byCode[code] if len(entry.inputs) == 0 || len(entry.outputs) == 0 { continue } sort.Float64s(entry.inputs) sort.Float64s(entry.outputs) providerName := normalizeHuaweiMaaSProvider(entry.providerType, entry.modelName) providerNameCn, providerCountry, providerWebsite := providerMetadata(providerName) records = append(records, officialPricingRecord{ ModelID: normalizeExternalID("huawei-maas", entry.modelName), ModelName: entry.modelName, ProviderName: providerName, ProviderNameCn: providerNameCn, ProviderCountry: providerCountry, ProviderWebsite: providerWebsite, OperatorName: "Huawei Cloud MaaS", OperatorNameCn: "华为云 MaaS", OperatorCountry: "CN", OperatorWebsite: "https://www.huaweicloud.com/product/maas.html", OperatorType: "official", Region: "CN", Currency: "CNY", InputPrice: entry.inputs[0], OutputPrice: entry.outputs[0], SourceURL: defaultHuaweiMaaSPricingSourceURL, ModelSourceURL: defaultHuaweiMaaSPricingSourceURL, DateConfidence: "unknown", DateSourceKind: "official_pricing", Modality: detectModality(entry.modelName), }) } if len(records) == 0 { return nil, fmt.Errorf("no huawei maas input/output pricing rows found") } return records, nil } func normalizeHuaweiMaaSProvider(providerType string, modelName string) string { switch strings.ToLower(strings.TrimSpace(providerType)) { case "deepseek": return "DeepSeek" case "qwen", "multimodalunderstanding": return "Qwen" case "glm": return "Zhipu AI" case "longcat": return "LongCat" default: lower := strings.ToLower(modelName) switch { case strings.Contains(lower, "deepseek"): return "DeepSeek" case strings.Contains(lower, "qwen"): return "Qwen" case strings.Contains(lower, "glm"): return "Zhipu AI" default: return strings.TrimSpace(providerType) } } }