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.
104 lines
2.8 KiB
Go
104 lines
2.8 KiB
Go
//go:build llm_script
|
||
|
||
package main
|
||
|
||
import (
|
||
"database/sql"
|
||
"flag"
|
||
"fmt"
|
||
"io"
|
||
"net/http"
|
||
"os"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
const defaultCUCloudCatalogURL = "https://www.cucloud.cn/act/CloudAI.html"
|
||
|
||
func main() {
|
||
loadSubscriptionImportEnv()
|
||
|
||
var url string
|
||
var fixture string
|
||
var dryRun bool
|
||
var timeoutSeconds int
|
||
|
||
flag.StringVar(&url, "url", defaultCUCloudCatalogURL, "联通云智算专区 URL")
|
||
flag.StringVar(&fixture, "fixture", "", "联通云智算专区样例文件")
|
||
flag.BoolVar(&dryRun, "dry-run", false, "仅校验并打印摘要,不写入数据库")
|
||
flag.IntVar(&timeoutSeconds, "timeout", 20, "请求超时(秒)")
|
||
flag.Parse()
|
||
|
||
cfg := catalogVerificationImportConfig{
|
||
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 := runCUCloudCatalogImport(cfg, db, os.Stdout); err != nil {
|
||
fmt.Fprintf(os.Stderr, "import_cucloud_catalog: %v\n", err)
|
||
os.Exit(1)
|
||
}
|
||
}
|
||
|
||
func parseCUCloudCatalog(raw string) ([]catalogVerificationRecord, error) {
|
||
if !strings.Contains(raw, "AICP") {
|
||
return nil, fmt.Errorf("cucloud AICP marker not found")
|
||
}
|
||
if !strings.Contains(raw, "AI应用开发平台") && !strings.Contains(raw, "AI 应用开发平台") {
|
||
return nil, fmt.Errorf("cucloud AI app marker not found")
|
||
}
|
||
return []catalogVerificationRecord{
|
||
{
|
||
CatalogCode: "cucloud-aicp-platform",
|
||
SourceURL: defaultCUCloudCatalogURL,
|
||
SourceTitle: "联通云智算专区",
|
||
PlanStatus: "confirmed",
|
||
Notes: "官方智算专区已公开展示 AI 算力平台 AICP,覆盖开发、训练、推理与模型服务部署全流程。",
|
||
},
|
||
{
|
||
CatalogCode: "cucloud-ai-app-platform",
|
||
SourceURL: defaultCUCloudCatalogURL,
|
||
SourceTitle: "联通云智算专区",
|
||
PlanStatus: "confirmed",
|
||
Notes: "官方智算专区已公开展示 AI 应用开发平台,支持一站式可视化开发、调试和发布智能体应用。",
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
func runCUCloudCatalogImport(cfg catalogVerificationImportConfig, db *sql.DB, out io.Writer) error {
|
||
client := &http.Client{Timeout: cfg.Timeout}
|
||
raw, err := fetchSubscriptionPage(cfg.URL, cfg.Fixture, client)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
records, err := parseCUCloudCatalog(raw)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if cfg.DryRun {
|
||
_, err = fmt.Fprintf(out, "source=cucloud-catalog-import entries=%d dry_run=true\n", len(records))
|
||
return err
|
||
}
|
||
if db == nil {
|
||
return fmt.Errorf("db is required when dry-run=false")
|
||
}
|
||
if err := upsertCatalogVerificationRecords(db, records); err != nil {
|
||
return err
|
||
}
|
||
_, err = fmt.Fprintf(out, "source=cucloud-catalog-import entries=%d dry_run=false\n", len(records))
|
||
return err
|
||
}
|