feat(integrations): add NextJS LLM/Grafana integration + enable dashboard embedding

This commit is contained in:
2026-08-31 20:22:26 -07:00
parent 1af9232613
commit 4af000c6ae
6 changed files with 719 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
/**
* NextJS API Route Examples
*
* Copy these to your NextJS app's pages/api/ or app/api/ directory
*/
// ═══════════════════════════════════════════════════════════════════════════════
// pages/api/chat.ts (Pages Router)
// ═══════════════════════════════════════════════════════════════════════════════
/*
import type { NextApiRequest, NextApiResponse } from 'next';
import { chat, streamChat, type Message } from '@/lib/llm-client';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
const { messages, model = 'reasoning', stream = false } = req.body;
if (!messages || !Array.isArray(messages)) {
return res.status(400).json({ error: 'messages required' });
}
try {
if (stream) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
for await (const chunk of streamChat({ model, messages })) {
res.write(`data: ${JSON.stringify({ content: chunk })}\n\n`);
}
res.write('data: [DONE]\n\n');
res.end();
} else {
const response = await chat({ model, messages });
res.json(response);
}
} catch (err) {
res.status(500).json({ error: err instanceof Error ? err.message : 'Unknown error' });
}
}
*/
// ═══════════════════════════════════════════════════════════════════════════════
// app/api/chat/route.ts (App Router)
// ═══════════════════════════════════════════════════════════════════════════════
/*
import { NextRequest } from 'next/server';
import { chat, createStreamResponse, type Model, type Message } from '@/lib/llm-client';
export async function POST(req: NextRequest) {
const { messages, model = 'reasoning', stream = false } = await req.json();
if (!messages || !Array.isArray(messages)) {
return Response.json({ error: 'messages required' }, { status: 400 });
}
if (stream) {
return createStreamResponse({ model, messages });
}
const response = await chat({ model, messages });
return Response.json(response);
}
*/
// ═══════════════════════════════════════════════════════════════════════════════
// app/api/metrics/route.ts (App Router - Grafana proxy)
// ═══════════════════════════════════════════════════════════════════════════════
/*
import { NextRequest } from 'next/server';
import { getLLMMetrics, getDashboard } from '@/lib/grafana-client';
export async function GET(req: NextRequest) {
const { searchParams } = new URL(req.url);
const type = searchParams.get('type') || 'metrics';
try {
if (type === 'dashboard') {
const dashboard = await getDashboard('llm-frontend');
return Response.json(dashboard);
}
const metrics = await getLLMMetrics();
return Response.json(metrics);
} catch (err) {
return Response.json(
{ error: err instanceof Error ? err.message : 'Unknown error' },
{ status: 500 }
);
}
}
*/
export {};