Files
klarbild/src/pages/api/admin/stats.ts
T
till 25d0a5cd97 feat: Bibliothek + Admin
- Bibliothek: grid, before/after slider, rename, download, folder assign, delete, multi-select
- Admin: stats+costs, OpenRouter key (masked/encrypted), budget, defaults, Picdrop config+test,
  models (list/add from OpenRouter/set default/delete), users (add/set password)
- api: items/:id PATCH+DELETE, folders CRUD, admin/{settings,stats,models,test-picdrop,users}
- lib/picdrop.ts (SFTP/FTPS test+upload, temp->rename)
2026-07-23 15:22:12 +00:00

26 lines
1.3 KiB
TypeScript

import type { APIRoute } from 'astro';
import { query, one } from '../../../lib/db';
export const prerender = false;
export const GET: APIRoute = async () => {
const total = await one<{ n: string }>(`SELECT count(*)::text n FROM items WHERE status='done'`);
const failed = await one<{ n: string }>(`SELECT count(*)::text n FROM items WHERE status='failed'`);
const cost = async (days: number | null) => (await one<{ c: string }>(
`SELECT COALESCE(sum(cost),0)::text c FROM items WHERE cost IS NOT NULL` +
(days ? ` AND created_at > now() - interval '${days} days'` : ''))
)?.c || '0';
const byModel = await query(`SELECT COALESCE(model_used,'—') m, count(*)::int n, COALESCE(sum(cost),0)::float c
FROM items WHERE status='done' GROUP BY 1 ORDER BY n DESC`);
const last = await one<{ t: string }>(`SELECT max(created_at)::text t FROM items`);
const totalN = Number(total?.n || 0), failedN = Number(failed?.n || 0);
return new Response(JSON.stringify({
total: totalN, failed: failedN,
error_rate: totalN + failedN ? Math.round((failedN / (totalN + failedN)) * 100) : 0,
cost_today: Number(await cost(1)), cost_7: Number(await cost(7)),
cost_30: Number(await cost(30)), cost_all: Number(await cost(null)),
by_model: byModel, last_activity: last?.t || null,
}), { headers: { 'Content-Type': 'application/json' } });
};