import { NextRequest, NextResponse } from 'next/server' import { auth } from '@/auth' import prisma from '@/lib/prisma' import { clusteringService } from '@/lib/ai/services/clustering.service' import { bridgeNotesService } from '@/lib/ai/services/bridge-notes.service' /** * GET /api/clusters * Get all clusters for the current user. */ export async function GET(request: NextRequest) { try { const session = await auth() if (!session?.user?.id) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const userId = session.user.id // Check for cached results const cached = await clusteringService.getCachedClusters(userId) if (cached) { return NextResponse.json({ clusters: cached, cached: true, totalNotes: cached.reduce((sum, c) => sum + c.noteIds.length, 0) }) } // No cached results, check if user has enough notes const notesCount = await prisma.note.count({ where: { userId, trashedAt: null } }) if (notesCount < 10) { return NextResponse.json({ clusters: [], message: 'Need at least 10 notes to generate clusters', totalNotes: notesCount }) } // Trigger background recalculation return NextResponse.json({ clusters: [], message: 'Calculating clusters... Please check back later', totalNotes: notesCount }) } catch (error) { console.error('Error fetching clusters:', error) return NextResponse.json( { error: 'Failed to fetch clusters' }, { status: 500 } ) } } /** * POST /api/clusters/recalculate * Trigger a full recalculation of clusters and bridge notes. */ export async function POST(request: NextRequest) { try { const session = await auth() if (!session?.user?.id) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const userId = session.user.id const body = await request.json() const force = body.force === true // Check if recalculation is needed const shouldRecalc = force || await clusteringService.shouldRecalculate(userId) if (!shouldRecalc) { const cached = await clusteringService.getCachedClusters(userId) if (cached) { return NextResponse.json({ clusters: cached, cached: true, message: 'Using cached results (data has not changed significantly)' }) } } // Perform clustering const results = await clusteringService.clusterNotes(userId) if (results.clusters.length === 0) { return NextResponse.json({ clusters: [], message: 'Could not generate clusters. Need more diverse notes.', noiseCount: results.noiseCount }) } // Generate cluster names for (const cluster of results.clusters) { cluster.name = await clusteringService.generateClusterName(cluster.clusterId, userId) } // Save results await clusteringService.saveClusteringResults(userId, results) // Detect and save bridge notes const bridgeNotes = await bridgeNotesService.detectBridgeNotes(userId) await bridgeNotesService.saveBridgeNotes(userId, bridgeNotes) return NextResponse.json({ clusters: results.clusters, bridgeNotes: bridgeNotes.slice(0, 10), // Return top 10 totalNotes: results.clusters.reduce((sum, c) => sum + c.noteIds.length, 0) + results.noiseCount, noiseCount: results.noiseCount, message: `Generated ${results.clusters.length} clusters` }) } catch (error) { console.error('Error recalculating clusters:', error) return NextResponse.json( { error: 'Failed to recalculate clusters' }, { status: 500 } ) } }