/** * Public Share Card Generator * * Renders a shareable SVG image showing your gateway savings — useful for * social posts, blog headers, README badges. Tokens are rounded; no * personally identifying information leaks (caller IDs, model names etc. * are NOT included). Just headline numbers + brand. * * Output is always a valid SVG so it can be embedded as `` * or downloaded directly. */ import type { Pool } from 'pg'; import { getComprehensiveSavings } from './savings-calculator.js'; import { getBuddyState } from './gamification.js'; function fmtNum(n: number): string { if (n >= 1_000_000) return (n / 1_000_000).toFixed(1) + 'M'; if (n >= 1_000) return (n / 1_000).toFixed(1) + 'K'; return Math.round(n).toString(); } function fmtCost(c: number): string { if (c < 0.01) return `$${c.toFixed(6)}`; if (c < 1) return `$${c.toFixed(4)}`; return `$${c.toFixed(2)}`; } function escSvg(s: string): string { return s.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } export type ShareCardPeriod = 'day' | 'week' | 'month' | 'all'; export type ShareCardTheme = 'dark' | 'light'; const PERIOD_HOURS: Record = { day: 24, week: 168, month: 720, all: 24 * 365 * 5, }; export async function generateShareCard( db: Pool, opts: { period?: ShareCardPeriod; theme?: ShareCardTheme } = {} ): Promise { const period: ShareCardPeriod = opts.period ?? 'month'; const theme: ShareCardTheme = opts.theme ?? 'dark'; const hours = PERIOD_HOURS[period]; const [savings, buddy] = await Promise.all([ getComprehensiveSavings(db, hours), getBuddyState(db, 'gateway'), ]); // Theme palette const palette = theme === 'dark' ? { bg: '#0a0a0a', surface: '#161616', text: '#e8e8e8', dim: '#888888', accent: '#d4ff00', accentDim: '#8aa800', border: '#2a2a2a', } : { bg: '#f4f7fa', surface: '#ffffff', text: '#24313d', dim: '#667684', accent: '#0f766e', accentDim: '#8ab9b5', border: '#d6e0e7', }; const periodLabel = period === 'day' ? 'Last 24 hours' : period === 'week' ? 'Last 7 days' : period === 'month' ? 'Last 30 days' : 'All-time'; const W = 1200, H = 630; // Open Graph standard const totalTokens = savings.totalTokensSaved; const totalCost = savings.totalCostSaved; const reqCount = savings.totals.requests; const efficacy = savings.costWithoutGateway > 0 ? ((savings.costWithoutGateway - savings.costWithGateway) / savings.costWithoutGateway) * 100 : 0; // Source-bar widths const total = Math.max(0.0000001, savings.totalCostSaved); const wCache = (savings.bySource.cache.cost / total) * 100; const wComp = (savings.bySource.compression.cost / total) * 100; const wSub = (savings.bySource.subscriptionBridge.cost / total) * 100; const wLocal = (savings.bySource.localRouting.cost / total) * 100; const wRace = (savings.bySource.raceMode.cost / total) * 100; return ` llm.gateway — ${escSvg(periodLabel)} CONTEXT-X.ORG tokens prevented · ${escSvg(periodLabel.toLowerCase())} ${fmtNum(totalTokens)} ${fmtCost(totalCost)} saved · ${fmtNum(reqCount)} calls · ${efficacy.toFixed(1)}% efficiency savings sources · 5-axis breakdown ${(() => { let x = 0; const segs: string[] = []; const w = W - 96; const pieces = [ { p: wCache, c: '#d4ff00', label: '⚡' }, { p: wComp, c: '#2dd4bf', label: '🗜' }, { p: wSub, c: '#60a5fa', label: '🌉' }, { p: wLocal, c: '#a78bfa', label: '🏠' }, { p: wRace, c: '#f97316', label: '🏁' }, ]; for (const piece of pieces) { const segW = (piece.p / 100) * w; if (segW > 0.5) { segs.push(``); } x += segW; } return segs.join(''); })()} cache compression subscription bridges local routing race mode ${escSvg(buddy.species)} · Lv.${buddy.level} · ${buddy.streakDays}d streak — routing AI traffic since ${escSvg(new Date().toISOString().split('T')[0])} `; }