import { prisma } from '@/lib/prisma' import { getAIProvider } from '@/lib/ai/factory' import type { Notebook } from '@/lib/types' export class NotebookSuggestionService { /** * Suggest the most appropriate notebook for a note * @param noteContent - Content of the note * @param userId - User ID (for fetching user's notebooks) * @returns Suggested notebook or null (if no good match) */ async suggestNotebook(noteContent: string, userId: string): Promise { // 1. Get all notebooks for this user const notebooks = await prisma.notebook.findMany({ where: { userId }, include: { labels: true, _count: { select: { notes: true }, }, }, orderBy: { order: 'asc' }, }) if (notebooks.length === 0) { return null // No notebooks to suggest } // 2. Build prompt for AI (always in French - interface language) const prompt = this.buildPrompt(noteContent, notebooks) // 3. Call AI try { const provider = getAIProvider() const response = await provider.generateText(prompt) const suggestedName = response.trim().toUpperCase() // 5. Find matching notebook const suggestedNotebook = notebooks.find(nb => nb.name.toUpperCase() === suggestedName ) // If AI says "NONE" or no match, return null if (suggestedName === 'NONE' || !suggestedNotebook) { return null } return suggestedNotebook as Notebook } catch (error) { console.error('Failed to suggest notebook:', error) return null } } /** * Build the AI prompt for notebook suggestion (always in French - interface language) */ private buildPrompt(noteContent: string, notebooks: any[]): string { const notebookList = notebooks .map(nb => { const labels = nb.labels.map((l: any) => l.name).join(', ') const count = nb._count?.notes || 0 return `- ${nb.name} (${count} notes)${labels ? ` [labels: ${labels}]` : ''}` }) .join('\n') return ` Tu es un assistant qui suggère à quel carnet une note devrait appartenir. CONTENU DE LA NOTE : ${noteContent.substring(0, 500)} CARNETS DISPONIBLES : ${notebookList} TÂCHE : Analyse le contenu de la note (peu importe la langue) et suggère le carnet le PLUS approprié pour cette note. Considère : 1. Le sujet/thème de la note (LE PLUS IMPORTANT) 2. Les labels existants dans chaque carnet 3. Le nombre de notes (préfère les carnets avec du contenu connexe) GUIDES DE CLASSIFICATION : - SPORT/EXERCICE/ACHATS/COURSSES → Carnet Personnel - LOISIRS/PASSIONS/SORTIES → Carnet Personnel - SANTÉ/FITNESS/MÉDECIN → Carnet Personnel ou Santé - FAMILLE/AMIS → Carnet Personnel - TRAVAIL/RÉUNIONS/PROJETS/CLIENTS → Carnet Travail - CODING/TECH/DÉVELOPPEMENT → Carnet Travail ou Code - FINANCES/FACTURES/BANQUE → Carnet Personnel ou Finances RÈGLES : - Retourne SEULEMENT le nom du carnet, EXACTEMENT comme indiqué ci-dessus (insensible à la casse) - Si aucune bonne correspondance n'existe, retourne "NONE" - Si la note est trop générique/vague, retourne "NONE" - N'inclus pas d'explications ou de texte supplémentaire Exemples : - "Réunion avec Jean sur le planning du projet" → carnet "Travail" - "Liste de courses ou achat de vêtements" → carnet "Personnel" - "Script Python pour analyse de données" → carnet "Code" - "Séance de sport ou fitness" → carnet "Personnel" - "Achat d'une chemise et d'un jean" → carnet "Personnel" Ta suggestion : `.trim() } /** * Batch suggest notebooks for multiple notes (IA3) * @param noteContents - Array of note contents * @param userId - User ID * @returns Map of note index -> suggested notebook */ async suggestNotebooksBatch( noteContents: string[], userId: string ): Promise> { const results = new Map() // For efficiency, we could batch this into a single AI call // For now, process sequentially (could be parallelized) for (let i = 0; i < noteContents.length; i++) { const suggestion = await this.suggestNotebook(noteContents[i], userId) results.set(i, suggestion) } return results } /** * Get notebook suggestion confidence score * (For future UI enhancement: show confidence level) */ async suggestNotebookWithConfidence( noteContent: string, userId: string ): Promise<{ notebook: Notebook | null; confidence: number }> { // This could use logprobs from OpenAI API to calculate confidence // For now, return binary confidence const notebook = await this.suggestNotebook(noteContent, userId) return { notebook, confidence: notebook ? 0.8 : 0, // Fixed confidence for now } } } // Export singleton instance export const notebookSuggestionService = new NotebookSuggestionService()