import { NextRequest, NextResponse } from 'next/server' import { photoService } from '@/lib/photo-service' import { imageClassifier } from '@/lib/image-classifier' import { existsSync } from 'fs' interface ClassifyRequest { photoId?: string photoIds?: string[] minConfidence?: number dryRun?: boolean // Just return classifications without saving customLabels?: string[] maxResults?: number categories?: { general?: string[] time?: string[] weather?: string[] subjects?: string[] locations?: string[] style?: string[] seasons?: string[] } } export async function POST(request: NextRequest) { try { const body: ClassifyRequest = await request.json() if (!body.photoId && !body.photoIds) { return NextResponse.json( { error: 'Either photoId or photoIds must be provided' }, { status: 400 } ) } // Initialize classifier if not already done console.log('[CLASSIFY API] Initializing image classifier...') await imageClassifier.initialize() const photoIds = body.photoId ? [body.photoId] : body.photoIds! const minConfidence = body.minConfidence || 0.3 const dryRun = body.dryRun || false // Build classifier configuration const classifierConfig = { minConfidence, maxResults: body.maxResults, customLabels: body.customLabels, categories: body.categories } const results = [] for (const photoId of photoIds) { try { console.log(`[CLASSIFY API] Processing photo: ${photoId}`) // Get photo from database const photo = photoService.getPhoto(photoId) if (!photo) { console.warn(`[CLASSIFY API] Photo not found: ${photoId}`) results.push({ photoId, error: 'Photo not found', success: false }) continue } // Try to get cached thumbnail first, fall back to file path let imageSource: string | Buffer = photo.filepath const thumbnailBlob = photoService.getCachedThumbnail(photoId, 200) // Use 200px thumbnail for classification if (thumbnailBlob) { console.log(`[CLASSIFY API] Using cached thumbnail for classification: ${photo.filename}`) imageSource = thumbnailBlob } else { // Check if file exists for fallback if (!existsSync(photo.filepath)) { console.warn(`[CLASSIFY API] Photo file not found and no thumbnail: ${photo.filepath}`) results.push({ photoId, error: 'Photo file not found and no cached thumbnail', success: false, filepath: photo.filepath }) continue } console.log(`[CLASSIFY API] Using original file for classification (no thumbnail): ${photo.filepath}`) } // Classify the image with configuration const sourceDesc = thumbnailBlob ? `thumbnail for ${photo.filename}` : photo.filepath console.log(`[CLASSIFY API] Classifying image: ${sourceDesc}`) const classifications = await imageClassifier.classifyImage(imageSource, body.customLabels, classifierConfig) // Filter by confidence (already done by classifyImage, but keep for backward compatibility) const filteredTags = classifications .map(result => ({ name: result.label, confidence: result.score })) if (dryRun) { // Just return the classifications without saving results.push({ photoId, filename: photo.filename, classifications: filteredTags, success: true, dryRun: true }) } else { // Save tags to database const addedCount = photoService.addPhotoTags(photoId, filteredTags) results.push({ photoId, filename: photo.filename, classificationsFound: classifications.length, tagsAdded: addedCount, tags: filteredTags, success: true }) console.log(`[CLASSIFY API] Added ${addedCount} tags to photo: ${photo.filename}`) } } catch (error) { console.error(`[CLASSIFY API] Error processing photo ${photoId}:`, error) results.push({ photoId, error: error instanceof Error ? error.message : 'Unknown error', success: false }) } } const successful = results.filter(r => r.success).length const failed = results.filter(r => !r.success).length console.log(`[CLASSIFY API] Completed: ${successful} successful, ${failed} failed`) return NextResponse.json({ results, summary: { total: photoIds.length, successful, failed, config: classifierConfig, dryRun } }) } catch (error) { console.error('[CLASSIFY API] Error:', error) return NextResponse.json( { error: 'Failed to classify images' }, { status: 500 } ) } } // Health check endpoint export async function GET() { try { const isReady = imageClassifier.isReady() return NextResponse.json({ status: 'ok', classifierReady: isReady, message: isReady ? 'Classifier ready' : 'Classifier not initialized' }) } catch (error) { return NextResponse.json( { error: 'Service unavailable' }, { status: 500 } ) } }