seroxdesigncleand0badd58 months agoHistory
293 lines · 10.5 KB · TypeScript
RawDownload
// CRITICALimport Database from "bun:sqlite";import { resolve } from "node:path";import { calcChange } from "./usage-utilities"; export const getUsageFromChatDatabase = (dataDirectory: string): Record<string, unknown> | null => {  let db: Database | null = null;  try {    const chatDatabasePath = resolve(dataDirectory, "chats.db");    db = new Database(chatDatabasePath, { readonly: true });    const tableCheck = db      .query<{ name: string }, []>(        `SELECT name FROM sqlite_master WHERE type='table' AND name='chat_messages'`,      )      .get();    if (!tableCheck) return null;     const totals =      db        .query<{          total_requests: number;          prompt_tokens: number;          completion_tokens: number;          unique_sessions: number;        }, []>(`      SELECT        SUM(CASE WHEN role = 'assistant' THEN 1 ELSE 0 END) as total_requests,        COALESCE(SUM(CASE WHEN role = 'assistant' THEN          CASE WHEN request_total_input_tokens > 0 THEN request_total_input_tokens ELSE COALESCE(request_prompt_tokens, 0) END        ELSE 0 END), 0) as prompt_tokens,        COALESCE(SUM(CASE WHEN role = 'assistant' THEN COALESCE(request_completion_tokens, 0) ELSE 0 END), 0) as completion_tokens,        COUNT(DISTINCT session_id) as unique_sessions      FROM chat_messages    `)        .get() ?? { total_requests: 0, prompt_tokens: 0, completion_tokens: 0, unique_sessions: 0 };     if (totals.total_requests === 0) {      return null;    }     const byModel =      db        .query<{          model: string;          requests: number;          total_tokens: number;          prompt_tokens: number;          completion_tokens: number;          avg_tokens: number;        }, []>(`      SELECT        COALESCE(model, '') as model,        COUNT(*) as requests,        COALESCE(SUM(CASE WHEN request_total_input_tokens > 0 THEN request_total_input_tokens ELSE COALESCE(request_prompt_tokens, 0) END), 0) as prompt_tokens,        COALESCE(SUM(COALESCE(request_completion_tokens, 0)), 0) as completion_tokens,        COALESCE(SUM(COALESCE(request_completion_tokens, 0)), 0) + COALESCE(SUM(CASE WHEN request_total_input_tokens > 0 THEN request_total_input_tokens ELSE COALESCE(request_prompt_tokens, 0) END), 0) as total_tokens,        AVG(COALESCE(request_completion_tokens, 0) + COALESCE(request_total_input_tokens, request_prompt_tokens, 0)) as avg_tokens      FROM chat_messages      WHERE role = 'assistant'      GROUP BY model      ORDER BY total_tokens DESC      LIMIT 25    `)        .all() ?? [];     const daily =      db        .query<{          date: string;          requests: number;          prompt_tokens: number;          completion_tokens: number;          total_tokens: number;        }, []>(`      SELECT        DATE(created_at) as date,        COUNT(*) as requests,        COALESCE(SUM(CASE WHEN request_total_input_tokens > 0 THEN request_total_input_tokens ELSE COALESCE(request_prompt_tokens, 0) END), 0) as prompt_tokens,        COALESCE(SUM(COALESCE(request_completion_tokens, 0)), 0) as completion_tokens,        COALESCE(SUM(COALESCE(request_completion_tokens, 0)), 0) + COALESCE(SUM(CASE WHEN request_total_input_tokens > 0 THEN request_total_input_tokens ELSE COALESCE(request_prompt_tokens, 0) END), 0) as total_tokens      FROM chat_messages      WHERE role = 'assistant' AND DATE(created_at) >= DATE('now', '-14 days')      GROUP BY DATE(created_at)      ORDER BY date DESC    `)        .all() ?? [];     const dailyByModel =      db        .query<{          date: string;          model: string;          requests: number;          prompt_tokens: number;          completion_tokens: number;          total_tokens: number;        }, []>(`      SELECT        DATE(created_at) as date,        COALESCE(model, '') as model,        COUNT(*) as requests,        COALESCE(SUM(CASE WHEN request_total_input_tokens > 0 THEN request_total_input_tokens ELSE COALESCE(request_prompt_tokens, 0) END), 0) as prompt_tokens,        COALESCE(SUM(COALESCE(request_completion_tokens, 0)), 0) as completion_tokens,        COALESCE(SUM(COALESCE(request_completion_tokens, 0)), 0) + COALESCE(SUM(CASE WHEN request_total_input_tokens > 0 THEN request_total_input_tokens ELSE COALESCE(request_prompt_tokens, 0) END), 0) as total_tokens      FROM chat_messages      WHERE role = 'assistant' AND DATE(created_at) >= DATE('now', '-14 days')      GROUP BY DATE(created_at), model      ORDER BY date DESC    `)        .all() ?? [];     const hourly =      db        .query<{          hour: number;          requests: number;          tokens: number;        }, []>(`      SELECT        CAST(strftime('%H', created_at) AS INTEGER) as hour,        COUNT(*) as requests,        COALESCE(SUM(COALESCE(request_completion_tokens, 0) + COALESCE(request_total_input_tokens, request_prompt_tokens, 0)), 0) as tokens      FROM chat_messages      WHERE role = 'assistant'      GROUP BY strftime('%H', created_at)      ORDER BY hour    `)        .all() ?? [];     const peakDays =      db        .query<{          date: string;          requests: number;          tokens: number;        }, []>(`      SELECT        DATE(created_at) as date,        COUNT(*) as requests,        COALESCE(SUM(COALESCE(request_completion_tokens, 0) + COALESCE(request_total_input_tokens, request_prompt_tokens, 0)), 0) as tokens      FROM chat_messages      WHERE role = 'assistant'      GROUP BY DATE(created_at)      ORDER BY requests DESC      LIMIT 5    `)        .all() ?? [];     const peakHours =      db        .query<{          hour: number;          requests: number;        }, []>(`      SELECT        CAST(strftime('%H', created_at) AS INTEGER) as hour,        COUNT(*) as requests      FROM chat_messages      WHERE role = 'assistant' AND DATE(created_at) >= DATE('now', '-7 days')      GROUP BY strftime('%H', created_at)      ORDER BY requests DESC      LIMIT 5    `)        .all() ?? [];     const recent =      db        .query<{          last_24h_requests: number;          prev_24h_requests: number;          last_24h_tokens: number;          last_hour_requests: number;        }, []>(`      SELECT        SUM(CASE WHEN datetime(created_at) >= datetime('now', '-24 hours') THEN 1 ELSE 0 END) as last_24h_requests,        SUM(CASE WHEN datetime(created_at) >= datetime('now', '-48 hours') AND datetime(created_at) < datetime('now', '-24 hours') THEN 1 ELSE 0 END) as prev_24h_requests,        SUM(CASE WHEN datetime(created_at) >= datetime('now', '-24 hours')          THEN COALESCE(request_completion_tokens, 0) + COALESCE(request_total_input_tokens, request_prompt_tokens, 0)          ELSE 0 END) as last_24h_tokens,        SUM(CASE WHEN datetime(created_at) >= datetime('now', '-1 hour') THEN 1 ELSE 0 END) as last_hour_requests      FROM chat_messages      WHERE role = 'assistant'    `)        .get() ?? { last_24h_requests: 0, prev_24h_requests: 0, last_24h_tokens: 0, last_hour_requests: 0 };     const totalTokens = totals.prompt_tokens + totals.completion_tokens;    const avgTokens = totals.total_requests ? Math.round(totalTokens / totals.total_requests) : 0;    const avgPrompt = totals.total_requests ? Math.round(totals.prompt_tokens / totals.total_requests) : 0;    const avgCompletion = totals.total_requests      ? Math.round(totals.completion_tokens / totals.total_requests)      : 0;     return {      totals: {        total_tokens: totalTokens,        prompt_tokens: totals.prompt_tokens,        completion_tokens: totals.completion_tokens,        total_requests: totals.total_requests,        successful_requests: totals.total_requests,        failed_requests: 0,        success_rate: totals.total_requests ? 100 : 0,        unique_sessions: totals.unique_sessions,        unique_users: 0,      },      latency: {        avg_ms: 0,        p50_ms: 0,        p95_ms: 0,        p99_ms: 0,        min_ms: 0,        max_ms: 0,      },      ttft: { avg_ms: 0, p50_ms: 0, p95_ms: 0, p99_ms: 0 },      tokens_per_request: {        avg: avgTokens,        avg_prompt: avgPrompt,        avg_completion: avgCompletion,        max: 0,        p50: 0,        p95: 0,      },      cache: { hits: 0, misses: 0, hit_tokens: 0, miss_tokens: 0, hit_rate: 0 },      week_over_week: {        this_week: { requests: 0, tokens: 0, successful: 0 },        last_week: { requests: 0, tokens: 0, successful: 0 },        change_pct: { requests: null, tokens: null },      },      recent_activity: {        last_hour_requests: recent.last_hour_requests,        last_24h_requests: recent.last_24h_requests,        prev_24h_requests: recent.prev_24h_requests,        last_24h_tokens: recent.last_24h_tokens,        change_24h_pct: calcChange(recent.last_24h_requests, recent.prev_24h_requests),      },      peak_days: peakDays.map((row) => ({        date: row.date,        requests: row.requests,        tokens: row.tokens,      })),      peak_hours: peakHours.map((row) => ({        hour: row.hour,        requests: row.requests,      })),      by_model: byModel.map((row) => ({        model: row.model || "unknown",        requests: row.requests,        successful: row.requests,        success_rate: row.requests ? 100 : 0,        total_tokens: row.total_tokens,        prompt_tokens: row.prompt_tokens,        completion_tokens: row.completion_tokens,        avg_tokens: Math.round(row.avg_tokens ?? 0),        avg_latency_ms: 0,        p50_latency_ms: 0,        avg_ttft_ms: 0,        tokens_per_sec: null,        prefill_tps: null,        generation_tps: null,      })),      daily: daily.map((row) => ({        date: row.date,        requests: row.requests,        successful: row.requests,        success_rate: row.requests ? 100 : 0,        total_tokens: row.total_tokens,        prompt_tokens: row.prompt_tokens,        completion_tokens: row.completion_tokens,        avg_latency_ms: 0,      })),      daily_by_model: dailyByModel.map((row) => ({        date: row.date,        model: row.model || "unknown",        requests: row.requests,        successful: row.requests,        success_rate: row.requests ? 100 : 0,        total_tokens: row.total_tokens,        prompt_tokens: row.prompt_tokens,        completion_tokens: row.completion_tokens,      })),      hourly_pattern: hourly.map((row) => ({        hour: row.hour,        requests: row.requests,        successful: row.requests,        tokens: row.tokens,      })),    };  } catch (error) {    console.error("[Usage] Error fetching usage stats from chats DB:", error);    return null;  } finally {    if (db) db.close();  }};