spb/note-spboucher-ai
Public
1import { handler } from "@/lib/api";2import { listModels, refreshDiscovery } from "@/lib/ai/catalog";3import { DEFAULT_ROUTES, getRoutes, TASK_LABELS } from "@/lib/ai/router";4import { db, schema } from "@/db";5import { eq } from "drizzle-orm";6import { z } from "zod";7import { parseBody } from "@/lib/api";8import { audit } from "@/lib/audit";9export const GET = handler(async ({ req }) => {10 const all = new URL(req.url).searchParams.get("all") === "1";11 const models = (await listModels()).filter((m) => all || (m.available && m.enabled && m.category !== "embedding"));12 const providers = await db.select().from(schema.aiProviders);13 const [summary] = await db.select().from(schema.settings).where(eq(schema.settings.key, "ai.benchmark_summary"));14 return Response.json({ models: models.sort((a, b) => a.provider.localeCompare(b.provider) || ((b.benchmark as any)?.mean_score ?? -1) - ((a.benchmark as any)?.mean_score ?? -1)), providers: providers.map((p) => ({ ...p, configured: Boolean(p.id === "openai" ? process.env.OPENAI_API_KEY : process.env.ANTHROPIC_API_KEY) })), routes: await getRoutes(), defaultRoutes: DEFAULT_ROUTES, taskLabels: TASK_LABELS, benchmark: summary?.value ?? null });15});16/** POST { action: "discover" } → live re-discovery; { action: "toggle", id, enabled } ; { action: "routes", routes } ; { action: "budget", usd } */17export const POST = handler(async ({ req, user }) => {18 const b = await parseBody(req, z.object({ action: z.enum(["discover", "toggle", "routes", "budget"]), id: z.string().optional(), enabled: z.boolean().optional(), routes: z.record(z.string(), z.any()).optional(), usd: z.number().min(0).max(10_000).optional() }));19 if (b.action === "discover") { const r = await refreshDiscovery(); await audit(user.id, "ai.discover", undefined, r); return Response.json(r); }20 if (b.action === "toggle" && b.id) { await db.update(schema.aiModels).set({ enabled: Boolean(b.enabled), updatedAt: new Date() }).where(eq(schema.aiModels.id, b.id)); const { invalidateCatalog } = await import("@/lib/ai/catalog"); invalidateCatalog(); await audit(user.id, "ai.model_toggle", { type: "model", id: b.id }, { enabled: b.enabled }); return Response.json({ ok: true }); }21 if (b.action === "routes") { await db.insert(schema.settings).values({ key: "ai.routes", value: b.routes ?? {} }).onConflictDoUpdate({ target: schema.settings.key, set: { value: b.routes ?? {}, updatedAt: new Date() } }); await audit(user.id, "ai.routes_update"); return Response.json({ ok: true }); }22 if (b.action === "budget") { await db.insert(schema.settings).values({ key: "ai.daily_budget_usd", value: b.usd ?? 20 }).onConflictDoUpdate({ target: schema.settings.key, set: { value: b.usd ?? 20, updatedAt: new Date() } }); return Response.json({ ok: true }); }23 return Response.json({ error: "bad request" }, { status: 400 });24});25