mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-04 16:13:47 +00:00
fix(usage): repair cost analytics and display precision - Automatic OpenRouter pricing sync with cost backfill for traces/snapshots/events - Live usage data merging for current-hour dashboard accuracy - 2-decimal API cost formatting across usage/overview pages - Comprehensive test coverage (PG, SQLite, HTTP, UI) Merged by github-maintain automation.
62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
package pricing
|
|
|
|
import (
|
|
"context"
|
|
"log/slog"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
const DefaultOpenRouterCatalogSyncInterval = 24 * time.Hour
|
|
|
|
func StartOpenRouterCatalogAutoSync(ctx context.Context, s store.UsageCapStore, interval time.Duration, onSync ...func(context.Context, int)) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
if interval <= 0 {
|
|
interval = DefaultOpenRouterCatalogSyncInterval
|
|
}
|
|
client := &http.Client{Timeout: 30 * time.Second}
|
|
go func() {
|
|
syncOpenRouterCatalog(ctx, s, client, firstOpenRouterSyncHook(onSync))
|
|
ticker := time.NewTicker(interval)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
syncOpenRouterCatalog(ctx, s, client, firstOpenRouterSyncHook(onSync))
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
func firstOpenRouterSyncHook(hooks []func(context.Context, int)) func(context.Context, int) {
|
|
if len(hooks) == 0 {
|
|
return nil
|
|
}
|
|
return hooks[0]
|
|
}
|
|
|
|
func syncOpenRouterCatalog(ctx context.Context, s store.UsageCapStore, client *http.Client, onSync func(context.Context, int)) {
|
|
syncCtx, cancel := context.WithTimeout(ctx, 45*time.Second)
|
|
defer cancel()
|
|
entries, err := FetchOpenRouterCatalog(syncCtx, client)
|
|
if err != nil {
|
|
slog.Warn("usage_pricing.openrouter_auto_sync_failed", "error", err)
|
|
return
|
|
}
|
|
count, err := s.UpsertPricingCatalog(syncCtx, entries)
|
|
if err != nil {
|
|
slog.Warn("usage_pricing.openrouter_auto_store_failed", "error", err)
|
|
return
|
|
}
|
|
slog.Info("usage_pricing.openrouter_auto_synced", "count", count)
|
|
if onSync != nil {
|
|
onSync(ctx, count)
|
|
}
|
|
}
|