feat(audit): add pricing signature guards and reporting
Add snapshot, signature, and drift guard support for Vertex AI, Cloudflare Workers AI, and Perplexity API, backed by a queryable audit table and recent-window view. This commit also wires the audit query layer into daily signal materialization and report generation so structure drift becomes a first-class signal instead of a log-only artifact.
This commit is contained in:
108
scripts/cloudflare_pricing_lib.go
Normal file
108
scripts/cloudflare_pricing_lib.go
Normal file
@@ -0,0 +1,108 @@
|
||||
//go:build llm_script
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultCloudflarePricingFetchURL = "https://developers.cloudflare.com/workers-ai/platform/pricing/index.md"
|
||||
defaultCloudflarePricingSourceURL = "https://developers.cloudflare.com/workers-ai/platform/pricing/"
|
||||
)
|
||||
|
||||
func parseCloudflarePricingCatalog(raw string) ([]officialPricingRecord, error) {
|
||||
section, ok := extractCloudflareLLMPricingSection(raw)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected cloudflare pricing content")
|
||||
}
|
||||
|
||||
lines := strings.Split(section, "\n")
|
||||
records := make([]officialPricingRecord, 0)
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if !strings.HasPrefix(line, "| @cf/") {
|
||||
continue
|
||||
}
|
||||
parts := strings.Split(line, "|")
|
||||
if len(parts) < 4 {
|
||||
continue
|
||||
}
|
||||
modelPath := strings.Trim(strings.TrimSpace(parts[1]), "`")
|
||||
priceCell := strings.TrimSpace(parts[2])
|
||||
prices := extractCloudflarePrices(priceCell)
|
||||
if len(prices) < 2 {
|
||||
continue
|
||||
}
|
||||
providerName := providerFromModelPath(strings.TrimPrefix(modelPath, "@cf/"))
|
||||
providerNameCn, providerCountry, providerWebsite := providerMetadata(providerName)
|
||||
record := officialPricingRecord{
|
||||
ModelID: normalizeExternalID("cloudflare", modelPath),
|
||||
ModelName: modelPath,
|
||||
ProviderName: providerName,
|
||||
ProviderNameCn: providerNameCn,
|
||||
ProviderCountry: providerCountry,
|
||||
ProviderWebsite: providerWebsite,
|
||||
OperatorName: "Cloudflare Workers AI",
|
||||
OperatorNameCn: "Cloudflare Workers AI",
|
||||
OperatorCountry: "US",
|
||||
OperatorWebsite: "https://developers.cloudflare.com/workers-ai/",
|
||||
OperatorType: "cloud",
|
||||
Region: "global",
|
||||
Currency: "USD",
|
||||
InputPrice: prices[0],
|
||||
OutputPrice: prices[1],
|
||||
SourceURL: defaultCloudflarePricingSourceURL,
|
||||
ModelSourceURL: defaultCloudflarePricingSourceURL,
|
||||
DateConfidence: "unknown",
|
||||
DateSourceKind: "official_pricing",
|
||||
Modality: detectModality(modelPath),
|
||||
}
|
||||
record.IsFree = record.InputPrice == 0 && record.OutputPrice == 0
|
||||
records = append(records, record)
|
||||
}
|
||||
if len(records) == 0 {
|
||||
return nil, fmt.Errorf("no cloudflare llm pricing rows found")
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func extractCloudflarePrices(raw string) []float64 {
|
||||
fields := strings.Split(raw, "$")
|
||||
prices := make([]float64, 0, 3)
|
||||
for _, field := range fields[1:] {
|
||||
value := strings.TrimSpace(field)
|
||||
end := strings.Index(value, " per ")
|
||||
if end == -1 {
|
||||
continue
|
||||
}
|
||||
prices = append(prices, mustParseSubscriptionPrice(value[:end]))
|
||||
}
|
||||
return prices
|
||||
}
|
||||
|
||||
func extractCloudflareLLMPricingSection(raw string) (string, bool) {
|
||||
lines := strings.Split(raw, "\n")
|
||||
start := -1
|
||||
end := len(lines)
|
||||
for i, line := range lines {
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if !strings.HasPrefix(trimmed, "## ") {
|
||||
continue
|
||||
}
|
||||
title := strings.ToLower(strings.TrimSpace(strings.TrimPrefix(trimmed, "## ")))
|
||||
if start == -1 {
|
||||
if strings.Contains(title, "llm") && strings.Contains(title, "pricing") {
|
||||
start = i
|
||||
}
|
||||
continue
|
||||
}
|
||||
end = i
|
||||
break
|
||||
}
|
||||
if start == -1 {
|
||||
return "", false
|
||||
}
|
||||
return strings.Join(lines[start:end], "\n"), true
|
||||
}
|
||||
Reference in New Issue
Block a user