import { NextResponse } from 'next/server'; import { getAdminAuth, getAdminDb } from '@/lib/firebase/admin'; import { getAlloyDbClient } from '@/lib/db/alloydb'; import { GeminiLlmClient } from '@/lib/ai/gemini-client'; import { z } from 'zod'; const ThemeGroupingSchema = z.object({ themes: z.array(z.object({ theme: z.string().describe('A short, descriptive theme name (2-4 words)'), description: z.string().describe('A brief description of what this theme represents'), insightIds: z.array(z.string()).describe('Array of insight IDs that belong to this theme'), })), }); export async function POST( request: Request, { params }: { params: Promise<{ projectId: string }> } ) { try { const { projectId } = await params; // Authentication (skip in development if no auth header) const authHeader = request.headers.get('Authorization'); const isDevelopment = process.env.NODE_ENV === 'development'; if (!isDevelopment || authHeader?.startsWith('Bearer ')) { if (!authHeader?.startsWith('Bearer ')) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const token = authHeader.substring(7); const auth = getAdminAuth(); const decoded = await auth.verifyIdToken(token); if (!decoded?.uid) { return NextResponse.json({ error: 'Invalid token' }, { status: 401 }); } } // Get insights from request body const { insights } = await request.json(); if (!insights || insights.length === 0) { return NextResponse.json({ success: true, themes: [], }); } console.log('[API /knowledge/themes] Grouping', insights.length, 'insights into themes'); // Prepare insights for AI analysis const insightsContext = insights.map((insight: any, index: number) => `[${insight.id}] ${insight.content?.substring(0, 200) || insight.title}` ).join('\n\n'); // Use AI to group insights into themes const llm = new GeminiLlmClient(); const systemPrompt = `You are an expert at analyzing and categorizing information. Given a list of insights/knowledge chunks, group them into meaningful themes. Each theme should represent a coherent topic or concept. Aim for 3-7 themes depending on the diversity of content.`; const userPrompt = `Analyze these insights and group them into themes: ${insightsContext} Group these insights into themes. Each insight ID is in brackets at the start of each line. Return the themes with their associated insight IDs.`; try { const result = await llm.structuredCall({ model: 'gemini', systemPrompt, messages: [{ role: 'user', content: userPrompt }], schema: ThemeGroupingSchema, temperature: 0.3, }); console.log('[API /knowledge/themes] Generated', result.themes.length, 'themes'); return NextResponse.json({ success: true, themes: result.themes, }); } catch (aiError) { console.error('[API /knowledge/themes] AI grouping failed:', aiError); // Fallback: create a single "Ungrouped" theme with all insights return NextResponse.json({ success: true, themes: [{ theme: 'All Insights', description: 'Ungrouped insights', insightIds: insights.map((i: any) => i.id), }], }); } } catch (error) { console.error('[API /knowledge/themes] Error:', error); return NextResponse.json( { error: 'Failed to group insights into themes', details: error instanceof Error ? error.message : String(error) }, { status: 500 } ); } }