Files

475 lines
17 KiB
Go

package webdemo
import (
"encoding/json"
"fmt"
"math"
"net/http"
"sort"
"strconv"
"strings"
"time"
)
func (input *fakeInput) ServeHTTP(response http.ResponseWriter, request *http.Request) {
input.mu.Lock()
defer input.mu.Unlock()
response.Header().Set("Content-Type", "application/json; charset=utf-8")
path := strings.TrimPrefix(request.URL.Path, managementBase)
if request.URL.Path == resourceUI {
path = "/" + strings.TrimSpace(request.URL.Query().Get("view"))
if path == "/usage" {
query := request.URL.Query()
query.Set("page", "1")
query.Set("page_size", "50")
request.URL.RawQuery = query.Encode()
}
}
var payload any
var err error
switch {
case request.Method == http.MethodGet && path == "/usage":
payload = input.usagePage(request)
case request.Method == http.MethodGet && path == "/usage-summary":
payload = input.dashboard()
case request.Method == http.MethodGet && path == "/keys":
payload = input.listKeys(request.URL.Query().Get("include_archived") == "1")
case request.Method == http.MethodPost && path == "/keys":
payload, err = input.createKey(request)
case request.Method == http.MethodPatch && path == "/keys":
payload, err = input.updateKey(request)
case request.Method == http.MethodDelete && path == "/keys":
payload, err = input.archiveKey(request)
case request.Method == http.MethodGet && path == "/key-stats":
payload = input.keyStats(request.URL.Query().Get("id"))
case request.Method == http.MethodGet && path == "/upstreams":
payload = map[string]any{"accounts": input.upstreams}
case request.Method == http.MethodGet && path == "/model-suggestions":
payload = map[string]any{"models": input.models}
case request.Method == http.MethodGet && path == "/billing-ledger":
payload = input.billingLedger(request)
case request.Method == http.MethodGet && path == "/events":
payload = map[string]any{"events": input.events}
case request.Method == http.MethodPost && path == "/billing-reset":
payload, err = input.resetBilling(request)
case request.Method == http.MethodGet && path == "/prices":
payload = map[string]any{"prices": input.prices}
case request.Method == http.MethodPut && path == "/prices":
payload, err = input.putPrice(request)
case request.Method == http.MethodDelete && path == "/prices":
payload, err = input.deletePrice(request)
case request.Method == http.MethodGet && path == "/price-catalog":
payload = input.searchCatalog(request.URL.Query().Get("q"))
case request.Method == http.MethodPost && path == "/prices/import":
payload, err = input.importPrice(request)
case request.Method == http.MethodPost && path == "/price-catalog/refresh":
payload = map[string]any{"catalog": input.catalogInfo(), "changes": []any{}}
case request.Method == http.MethodPost && path == "/price-catalog/apply":
payload = map[string]any{"updated": 0}
default:
writeJSON(response, http.StatusNotFound, map[string]any{"error": map[string]string{"code": "not_found", "message": request.Method + " " + path}})
return
}
if err != nil {
writeJSON(response, http.StatusBadRequest, map[string]any{"error": map[string]string{"code": "fake_input_error", "message": err.Error()}})
return
}
writeJSON(response, http.StatusOK, payload)
}
func writeJSON(response http.ResponseWriter, status int, payload any) {
response.WriteHeader(status)
_ = json.NewEncoder(response).Encode(payload)
}
func decodeBody(request *http.Request, target any) error {
decoder := json.NewDecoder(request.Body)
decoder.UseNumber()
return decoder.Decode(target)
}
func (input *fakeInput) listKeys(includeArchived bool) map[string]any {
keys := make([]fakeKey, 0, len(input.keys))
for _, key := range input.keys {
if includeArchived || key.Status != "archived" {
keys = append(keys, key)
}
}
return map[string]any{"keys": keys}
}
func (input *fakeInput) createKey(request *http.Request) (fakeKey, error) {
var value struct {
Name string `json:"name"`
Secret string `json:"secret"`
RouteMode string `json:"route_mode"`
UpstreamAccountID string `json:"upstream_account_id"`
AllModels bool `json:"all_models"`
ShowInStats *bool `json:"show_in_stats"`
Models []string `json:"models"`
Billing map[string]any `json:"billing"`
}
if err := decodeBody(request, &value); err != nil {
return fakeKey{}, err
}
if strings.TrimSpace(value.Name) == "" {
return fakeKey{}, fmt.Errorf("name is required")
}
if value.Secret == "" {
value.Secret = fmt.Sprintf("demo-generated-%06d", len(input.keys)+1)
}
showInStats := true
if value.ShowInStats != nil {
showInStats = *value.ShowInStats
}
key := fakeKey{ID: fmt.Sprintf("key_demo_%d", len(input.keys)+1), Name: value.Name, Secret: value.Secret, MaskedSecret: maskFakeSecret(value.Secret), Status: "active", RouteMode: value.RouteMode, UpstreamAccountID: value.UpstreamAccountID, AllModels: value.AllModels, ShowInStats: showInStats, Models: value.Models, Billing: normalizeFakeBilling(value.Billing, nil)}
input.keys = append(input.keys, key)
return key, nil
}
func (input *fakeInput) updateKey(request *http.Request) (fakeKey, error) {
var value map[string]any
if err := decodeBody(request, &value); err != nil {
return fakeKey{}, err
}
index := input.keyIndex(fmt.Sprint(value["id"]))
if index < 0 {
return fakeKey{}, fmt.Errorf("key not found")
}
key := input.keys[index]
if name := strings.TrimSpace(fmt.Sprint(value["name"])); name != "" {
key.Name = name
}
if status := strings.TrimSpace(fmt.Sprint(value["status"])); status != "" {
key.Status = status
}
if routeMode := strings.TrimSpace(fmt.Sprint(value["route_mode"])); routeMode != "" {
key.RouteMode = routeMode
}
key.UpstreamAccountID = stringValue(value["upstream_account_id"])
if allModels, ok := value["all_models"].(bool); ok {
key.AllModels = allModels
}
if showInStats, ok := value["show_in_stats"].(bool); ok {
key.ShowInStats = showInStats
}
if models, ok := value["models"].([]any); ok {
key.Models = make([]string, 0, len(models))
for _, model := range models {
key.Models = append(key.Models, fmt.Sprint(model))
}
}
if billing, ok := value["billing"].(map[string]any); ok {
key.Billing = normalizeFakeBilling(billing, key.Billing)
}
input.keys[index] = key
return key, nil
}
func (input *fakeInput) archiveKey(request *http.Request) (map[string]any, error) {
var value map[string]any
if err := decodeBody(request, &value); err != nil {
return nil, err
}
index := input.keyIndex(fmt.Sprint(value["id"]))
if index < 0 {
return nil, fmt.Errorf("key not found")
}
input.keys[index].Status = "archived"
return map[string]any{"archived": true}, nil
}
func (input *fakeInput) keyIndex(id string) int {
for index := range input.keys {
if input.keys[index].ID == id {
return index
}
}
return -1
}
func maskFakeSecret(value string) string {
if len(value) < 6 {
return "******"
}
return value[:2] + "******" + value[len(value)-4:]
}
func normalizeFakeBilling(value, previous map[string]any) map[string]any {
result := map[string]any{"quota_usd": "0", "spent_usd": "0", "lifetime_spent_usd": "0", "balance_usd": "0", "reset_period": "none", "next_reset_at": nil, "max_concurrency": 4, "active_requests": 0, "cycle_started_at": time.Now()}
for key, item := range previous {
result[key] = item
}
for key, item := range value {
result[key] = item
}
quota := toFloat(result["quota_usd"])
spent := toFloat(result["spent_usd"])
result["quota_usd"] = fmt.Sprint(result["quota_usd"])
result["balance_usd"] = fmt.Sprintf("%.6f", quota-spent)
return result
}
func stringValue(value any) string {
if value == nil {
return ""
}
return fmt.Sprint(value)
}
func (input *fakeInput) usagePage(request *http.Request) map[string]any {
query := request.URL.Query()
records := make([]fakeUsage, 0, len(input.usage))
for _, record := range input.usage {
if query.Get("key_id") != "" && query.Get("key_id") != record.ManagedKeyID || query.Get("model") != "" && !strings.Contains(strings.ToLower(record.Model), strings.ToLower(query.Get("model"))) || query.Get("result") != "" && query.Get("result") != usageResult(record) || query.Get("auth_id") != "" && query.Get("auth_id") != record.AuthID || query.Get("endpoint") != "" && query.Get("endpoint") != endpointName(record.Endpoint) || query.Get("request_id") != "" && query.Get("request_id") != record.RequestID {
continue
}
if from := parseTime(query.Get("from")); !from.IsZero() && record.RequestedAt.Before(from) {
continue
}
if to := parseTime(query.Get("to")); !to.IsZero() && !record.RequestedAt.Before(to) {
continue
}
records = append(records, record)
}
pageSize := boundedInt(query.Get("page_size"), 100, 1, 100)
totalPages := int(math.Ceil(float64(len(records)) / float64(pageSize)))
page := boundedInt(query.Get("page"), 1, 1, max(1, totalPages))
start := min((page-1)*pageSize, len(records))
end := min(start+pageSize, len(records))
previous, next := "", ""
if page > 1 {
previous = "fake-previous"
}
if page < totalPages {
next = "fake-next"
}
return map[string]any{"records": records[start:end], "pagination": map[string]any{"page": page, "page_size": pageSize, "total": len(records), "total_pages": totalPages, "previous_cursor": previous, "next_cursor": next}}
}
func usageResult(record fakeUsage) string {
if record.Outcome == "canceled" || record.Outcome == "rejected" || record.Outcome == "failed" {
return record.Outcome
}
return "succeeded"
}
func endpointName(value string) string {
if strings.HasSuffix(value, "/responses/compact") {
return "compact"
}
if strings.HasSuffix(value, "/chat/completions") {
return "chat"
}
return "responses"
}
func parseTime(value string) time.Time {
parsed, _ := time.Parse(time.RFC3339, value)
return parsed
}
func boundedInt(value string, fallback, minimum, maximum int) int {
parsed, err := strconv.Atoi(value)
if err != nil {
return fallback
}
return min(max(parsed, minimum), maximum)
}
func summarize(records []fakeUsage) map[string]any {
var inputTokens, outputTokens, totalTokens int64
var cost float64
for _, record := range records {
inputTokens += record.InputTokens
outputTokens += record.OutputTokens
totalTokens += record.TotalTokens
if record.CostAvailable {
cost += record.CostUSD
}
}
return map[string]any{"requests": len(records), "input_tokens": inputTokens, "output_tokens": outputTokens, "total_tokens": totalTokens, "cost_usd": cost, "cost_micros": int64(math.Round(cost * 1_000_000))}
}
func (input *fakeInput) dashboard() map[string]any {
today := startOfDay(input.now)
todayRecords := filterUsage(input.usage, func(record fakeUsage) bool { return !record.RequestedAt.Before(today) })
users := make([]map[string]any, 0, len(input.keys))
for _, key := range input.keys {
if key.Status == "archived" || !key.ShowInStats {
continue
}
records := filterUsage(input.usage, func(record fakeUsage) bool { return record.ManagedKeyID == key.ID })
current := filterUsage(records, func(record fakeUsage) bool { return !record.RequestedAt.Before(today) })
userDays := make([]map[string]any, 0, 7)
for offset := 6; offset >= 0; offset-- {
start := today.AddDate(0, 0, -offset)
end := start.AddDate(0, 0, 1)
daySummary := summarize(filterUsage(records, func(record fakeUsage) bool {
return !record.RequestedAt.Before(start) && record.RequestedAt.Before(end)
}))
userDays = append(userDays, map[string]any{"date": start.Format("2006-01-02"), "total_tokens": daySummary["total_tokens"], "cost_usd": daySummary["cost_usd"]})
}
var last any
if len(records) > 0 {
last = records[0].RequestedAt
}
users = append(users, map[string]any{"key_id": key.ID, "key_alias": key.Name, "today": summarize(current), "days": userDays, "last_used_at": last})
}
days := make([]map[string]any, 0, 7)
for offset := 6; offset >= 0; offset-- {
start := today.AddDate(0, 0, -offset)
end := start.AddDate(0, 0, 1)
records := filterUsage(input.usage, func(record fakeUsage) bool {
return !record.RequestedAt.Before(start) && record.RequestedAt.Before(end)
})
summary := summarize(records)
days = append(days, map[string]any{"date": start.Format("2006-01-02"), "total_tokens": summary["total_tokens"], "cost_usd": summary["cost_usd"]})
}
return map[string]any{"today": summarize(todayRecords), "users": users, "days": days}
}
func startOfDay(value time.Time) time.Time {
return time.Date(value.Year(), value.Month(), value.Day(), 0, 0, 0, 0, value.Location())
}
func filterUsage(records []fakeUsage, keep func(fakeUsage) bool) []fakeUsage {
result := make([]fakeUsage, 0, len(records))
for _, record := range records {
if keep(record) {
result = append(result, record)
}
}
return result
}
func (input *fakeInput) keyStats(id string) map[string]any {
records := filterUsage(input.usage, func(record fakeUsage) bool { return record.ManagedKeyID == id })
today := startOfDay(input.now)
current := filterUsage(records, func(record fakeUsage) bool { return !record.RequestedAt.Before(today) })
return map[string]any{"stats": map[string]any{"total": summarize(records), "today": summarize(current)}, "recent": records[:min(10, len(records))]}
}
func (input *fakeInput) billingLedger(request *http.Request) map[string]any {
id := request.URL.Query().Get("id")
limit := boundedInt(request.URL.Query().Get("limit"), 50, 1, 100)
entries := make([]fakeLedger, 0, limit)
for _, entry := range input.ledger {
if entry.KeyID == id && len(entries) < limit {
entries = append(entries, entry)
}
}
return map[string]any{"entries": entries}
}
func (input *fakeInput) resetBilling(request *http.Request) (map[string]any, error) {
var value map[string]any
if err := decodeBody(request, &value); err != nil {
return nil, err
}
if all, _ := value["all"].(bool); all {
count := 0
for index := range input.keys {
if input.keys[index].Status == "archived" {
continue
}
input.keys[index].Billing["spent_usd"] = "0"
input.keys[index].Billing["balance_usd"] = fmt.Sprint(input.keys[index].Billing["quota_usd"])
input.keys[index].Billing["cycle_started_at"] = time.Now()
count++
}
return map[string]any{"reset_count": count}, nil
}
index := input.keyIndex(fmt.Sprint(value["id"]))
if index < 0 {
return nil, fmt.Errorf("key not found")
}
input.keys[index].Billing["spent_usd"] = "0"
input.keys[index].Billing["balance_usd"] = fmt.Sprint(input.keys[index].Billing["quota_usd"])
input.keys[index].Billing["cycle_started_at"] = time.Now()
return input.keys[index].Billing, nil
}
func (input *fakeInput) putPrice(request *http.Request) (map[string]any, error) {
var value map[string]any
if err := decodeBody(request, &value); err != nil {
return nil, err
}
model := strings.TrimSpace(fmt.Sprint(value["model"]))
if model == "" {
return nil, fmt.Errorf("model is required")
}
value["source"] = map[string]any{"kind": "manual"}
input.storePrice(model, value)
return value, nil
}
func (input *fakeInput) deletePrice(request *http.Request) (map[string]any, error) {
var value map[string]any
if err := decodeBody(request, &value); err != nil {
return nil, err
}
model := fmt.Sprint(value["model"])
filtered := input.prices[:0]
for _, price := range input.prices {
if fmt.Sprint(price["model"]) != model {
filtered = append(filtered, price)
}
}
input.prices = filtered
return map[string]any{"deleted": model}, nil
}
func (input *fakeInput) storePrice(model string, value map[string]any) {
for index := range input.prices {
if fmt.Sprint(input.prices[index]["model"]) == model {
input.prices[index] = value
return
}
}
input.prices = append(input.prices, value)
sort.Slice(input.prices, func(left, right int) bool {
return fmt.Sprint(input.prices[left]["model"]) < fmt.Sprint(input.prices[right]["model"])
})
}
func (input *fakeInput) catalogInfo() map[string]any {
return map[string]any{"revision": "fake-2026-08-19", "models": len(input.catalog), "fetched_at": input.now}
}
func (input *fakeInput) searchCatalog(query string) map[string]any {
normalized := strings.ToLower(strings.TrimSpace(query))
models := make([]map[string]any, 0, len(input.catalog))
for _, entry := range input.catalog {
values := []any{entry["id"], entry["provider"], entry["provider_name"], entry["model"], entry["model_name"]}
for _, value := range values {
if normalized == "" || strings.Contains(strings.ToLower(fmt.Sprint(value)), normalized) {
models = append(models, entry)
break
}
}
}
return map[string]any{"loaded": true, "catalog": input.catalogInfo(), "models": models}
}
func (input *fakeInput) importPrice(request *http.Request) (map[string]any, error) {
var value map[string]any
if err := decodeBody(request, &value); err != nil {
return nil, err
}
model, catalogID := fmt.Sprint(value["model"]), fmt.Sprint(value["catalog_id"])
for _, entry := range input.catalog {
if fmt.Sprint(entry["id"]) != catalogID {
continue
}
price := map[string]any{"model": model, "base": entry["base"], "fast_pricing_enabled": false, "fast_multiplier": "2.5", "source": map[string]any{"kind": "models.dev", "provider": entry["provider"], "model": entry["model"], "catalog_id": catalogID, "revision": "fake-2026-08-19"}}
if longContext, ok := entry["long_context"]; ok {
price["long_context"] = longContext
}
input.storePrice(model, price)
return price, nil
}
return nil, fmt.Errorf("catalog entry not found")
}