150 lines · 4.2 KB · TypeScript
RawDownload
// CRITICAL"use client"; import { useCallback, useEffect, useMemo, useState } from "react";import api from "@/lib/api";import type { PeakMetrics, SortDirection, SortField, UsageStats } from "@/lib/types"; export function useUsage() {  const [stats, setStats] = useState<UsageStats | null>(null);  const [peakMetrics, setPeakMetrics] = useState<Map<string, PeakMetrics>>(new Map());  const [loading, setLoading] = useState(true);  const [error, setError] = useState<string | null>(null);  const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set());  const [sortField, setSortField] = useState<SortField>("success");  const [sortDirection, setSortDirection] = useState<SortDirection>("desc");   const loadStats = useCallback(async () => {    try {      setLoading(true);      setError(null);      const [usageData, peakData] = await Promise.all([api.getUsageStats(), api.getPeakMetrics()]);      setStats(usageData);       if (peakData.metrics) {        const metricsMap = new Map<string, PeakMetrics>();        for (const metric of peakData.metrics) {          metricsMap.set(metric.model_id, metric);        }        setPeakMetrics(metricsMap);      }    } catch (e) {      setError((e as Error).message);    } finally {      setLoading(false);    }  }, []);   useEffect(() => {    loadStats();  }, [loadStats]);   const dailyByModel = useMemo(() => {    if (!stats || !stats.daily_by_model || !Array.isArray(stats.daily_by_model)) {      return new Map<string, Map<string, { date: string; model: string; total_tokens: number }>>();    }    const grouped = new Map<string, Map<string, (typeof stats.daily_by_model)[0]>>();    for (const entry of stats.daily_by_model) {      if (!grouped.has(entry.model)) {        grouped.set(entry.model, new Map());      }      grouped.get(entry.model)!.set(entry.date, entry);    }    return grouped;  }, [stats]);   const modelsForChart = useMemo(() => {    if (!stats) return [];    return [...stats.by_model].sort((a, b) => b.total_tokens - a.total_tokens).map((m) => m.model);  }, [stats]);   const sortedModels = useMemo(() => {    if (!stats) return [];    const sorted = [...stats.by_model];    sorted.sort((a, b) => {      let aVal: number | string;      let bVal: number | string;       switch (sortField) {        case "model":          aVal = a.model.toLowerCase();          bVal = b.model.toLowerCase();          break;        case "requests":          aVal = a.requests;          bVal = b.requests;          break;        case "tokens":          aVal = a.total_tokens;          bVal = b.total_tokens;          break;        case "success":          aVal = a.success_rate;          bVal = b.success_rate;          break;        case "latency":          aVal = a.avg_latency_ms;          bVal = b.avg_latency_ms;          break;        case "ttft":          aVal = a.avg_ttft_ms;          bVal = b.avg_ttft_ms;          break;        case "speed":          aVal = a.tokens_per_sec ?? 0;          bVal = b.tokens_per_sec ?? 0;          break;        default:          return 0;      }       if (typeof aVal === "string" && typeof bVal === "string") {        return sortDirection === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);      }      return sortDirection === "asc"        ? (aVal as number) - (bVal as number)        : (bVal as number) - (aVal as number);    });    return sorted;  }, [sortField, sortDirection, stats]);   const handleSort = useCallback(    (field: SortField) => {      if (sortField === field) {        setSortDirection(sortDirection === "asc" ? "desc" : "asc");      } else {        setSortField(field);        setSortDirection("desc");      }    },    [sortDirection, sortField],  );   const toggleRow = useCallback((model: string) => {    setExpandedRows((prev) => {      const next = new Set(prev);      if (next.has(model)) {        next.delete(model);      } else {        next.add(model);      }      return next;    });  }, []);   return {    stats,    peakMetrics,    loading,    error,    expandedRows,    sortField,    sortDirection,    loadStats,    dailyByModel,    modelsForChart,    sortedModels,    handleSort,    toggleRow,  };}