Keep/keep-notes/lib/ai/services/notebook-summary.service.ts
2026-02-15 17:38:16 +01:00

381 lines
11 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { prisma } from '@/lib/prisma'
import { getAIProvider } from '@/lib/ai/factory'
import { getSystemConfig } from '@/lib/config'
export interface NotebookSummary {
notebookId: string
notebookName: string
notebookIcon: string | null
summary: string // Markdown formatted summary
stats: {
totalNotes: number
totalLabels: number
labelsUsed: string[]
}
generatedAt: Date
}
/**
* Service for generating AI-powered notebook summaries
* (Story 5.6 - IA6)
*/
export class NotebookSummaryService {
/**
* Generate a summary for a notebook
* @param notebookId - Notebook ID
* @param userId - User ID (for authorization)
* @returns Notebook summary or null
*/
async generateSummary(notebookId: string, userId: string, language: string = 'en'): Promise<NotebookSummary | null> {
// 1. Get notebook with notes and labels
const notebook = await prisma.notebook.findFirst({
where: {
id: notebookId,
userId,
},
include: {
labels: {
select: {
id: true,
name: true,
},
},
_count: {
select: { notes: true },
},
},
})
if (!notebook) {
throw new Error('Notebook not found')
}
// Get all notes in this notebook
const notes = await prisma.note.findMany({
where: {
notebookId,
userId,
},
select: {
id: true,
title: true,
content: true,
createdAt: true,
updatedAt: true,
labelRelations: {
select: {
name: true,
},
},
},
orderBy: {
updatedAt: 'desc',
},
take: 100, // Limit to 100 most recent notes for summary
})
if (notes.length === 0) {
return null
}
// 2. Generate summary using AI
const summary = await this.generateAISummary(notes, notebook, language)
// 3. Get labels used in this notebook
const labelsUsed = Array.from(
new Set(
notes.flatMap(note =>
note.labelRelations.map(l => l.name)
)
)
)
return {
notebookId: notebook.id,
notebookName: notebook.name,
notebookIcon: notebook.icon,
summary,
stats: {
totalNotes: notebook._count.notes,
totalLabels: notebook.labels.length,
labelsUsed,
},
generatedAt: new Date(),
}
}
/**
* Use AI to generate notebook summary
*/
private async generateAISummary(notes: any[], notebook: any, language: string): Promise<string> {
// Build notes summary for AI
const notesSummary = notes
.map((note, index) => {
const title = note.title || 'Sans titre'
const content = note.content.substring(0, 200) // Limit content length
const labels = note.labelRelations.map((l: any) => l.name).join(', ')
const date = new Date(note.createdAt).toLocaleDateString('fr-FR')
return `[${index + 1}] **${title}** (${date})
${labels ? `Labels: ${labels}` : ''}
${content}...`
})
.join('\n\n')
const prompt = this.buildPrompt(notesSummary, notebook.name, language)
try {
const config = await getSystemConfig()
const provider = getAIProvider(config)
const summary = await provider.generateText(prompt)
return summary.trim()
} catch (error) {
console.error('Failed to generate notebook summary:', error)
throw error
}
}
/**
* Build prompt for AI (localized)
*/
private buildPrompt(notesSummary: string, notebookName: string, language: string = 'en'): string {
const instructions: Record<string, string> = {
fr: `
Tu es un assistant qui génère des synthèses structurées de carnets de notes.
CARNET: ${notebookName}
NOTES DU CARNET:
${notesSummary}
TÂCHE:
Génère une synthèse structurée et organisée de ce carnet en analysant toutes les notes.
FORMAT DE LA RÉPONSE (Markdown avec emojis):
# 📊 Synthèse du Carnet ${notebookName}
## 🌍 Thèmes Principaux
• Identifie 3-5 thèmes récurrents ou sujets abordés
## 📝 Statistiques
• Nombre total de notes analysées
• Principales catégories de contenu
## 📅 Éléments Temporels
• Dates ou périodes importantes mentionnées
• Événements planifiés vs passés
## ⚠️ Points d'Attention / Actions Requises
• Tâches ou actions identifiées dans les notes
• Rappels ou échéances importantes
• Éléments nécessitant une attention particulière
## 💡 Insights Clés
• Résumé des informations les plus importantes
• Tendances ou patterns observés
• Connexions entre les différentes notes
RÈGLES:
- Utilise le format Markdown avec emojis comme dans l'exemple
- Sois concis et organise l'information de manière claire
- Identifie les vraies tendances, ne pas inventer d'informations
- Si une section n'est pas pertinente, utilise "N/A" ou omets-la
- Ton: professionnel mais accessible
- TA RÉPONSE DOIT ÊTRE EN FRANÇAIS
Ta réponse :
`.trim(),
en: `
You are an assistant that generates structured summaries of notebooks.
NOTEBOOK: ${notebookName}
NOTEBOOK NOTES:
${notesSummary}
TASK:
Generate a structured and organized summary of this notebook by analyzing all notes.
RESPONSE FORMAT (Markdown with emojis):
# 📊 Summary of Notebook ${notebookName}
## 🌍 Main Themes
• Identify 3-5 recurring themes or topics covered
## 📝 Statistics
• Total number of notes analyzed
• Main content categories
## 📅 Temporal Elements
• Important dates or periods mentioned
• Planned vs past events
## ⚠️ Action Items / Attention Points
• Tasks or actions identified in notes
• Important reminders or deadlines
• Items requiring special attention
## 💡 Key Insights
• Summary of most important information
• Observed trends or patterns
• Connections between different notes
RULES:
- Use Markdown format with emojis as in the example
- Be concise and organize information clearly
- Identify real trends, do not invent information
- If a section is not relevant, use "N/A" or omit it
- Tone: professional but accessible
- YOUR RESPONSE MUST BE IN ENGLISH
Your response:
`.trim(),
fa: `
شما یک دستیار هستید که خلاصه‌های ساختاریافته از دفترچه‌های یادداشت تولید می‌کنید.
دفترچه: ${notebookName}
یادداشت‌های دفترچه:
${notesSummary}
وظیفه:
یک خلاصه ساختاریافته و منظم از این دفترچه با تحلیل تمام یادداشت‌ها تولید کنید.
فرمت پاسخ (مارک‌داون با ایموجی):
# 📊 خلاصه دفترچه ${notebookName}
## 🌍 موضوعات اصلی
• ۳-۵ موضوع تکرارشونده یا مبحث پوشش داده شده را شناسایی کنید
## 📝 آمار
• تعداد کل یادداشت‌های تحلیل شده
• دسته‌بندی‌های اصلی محتوا
## 📅 عناصر زمانی
• تاریخ‌ها یا دوره‌های مهم ذکر شده
• رویدادهای برنامه‌ریزی شده در مقابل گذشته
## ⚠️ موارد اقدام / نقاط توجه
• وظایف یا اقدامات شناسایی شده در یادداشت‌ها
• یادآوری‌ها یا مهلت‌های مهم
• مواردی که نیاز به توجه ویژه دارند
## 💡 بینش‌های کلیدی
• خلاصه مهم‌ترین اطلاعات
• روندها یا الگوهای مشاهده شده
• ارتباطات بین یادداشت‌های مختلف
قوانین:
- از فرمت مارک‌داون با ایموجی مانند مثال استفاده کنید
- مختصر باشید و اطلاعات را به وضوح سازماندهی کنید
- روندهای واقعی را شناسایی کنید، اطلاعات اختراع نکنید
- اگر بخش مرتبط نیست، از "N/A" استفاده کنید یا آن را حذف کنید
- لحن: حرفه‌ای اما قابل دسترس
- پاسخ شما باید به زبان فارسی باشد
پاسخ شما:
`.trim(),
es: `
Eres un asistente que genera resúmenes estructurados de cuadernos de notas.
CUADERNO: ${notebookName}
NOTAS DEL CUADERNO:
${notesSummary}
TAREA:
Genera un resumen estructurado y organizado de este cuaderno analizando todas las notas.
FORMATO DE RESPUESTA (Markdown con emojis):
# 📊 Resumen del Cuaderno ${notebookName}
## 🌍 Temas Principales
• Identifica 3-5 temas recurrentes o tópicos cubiertos
## 📝 Estadísticas
• Número total de notas analizadas
• Categorías principales de contenido
## 📅 Elementos Temporales
• Fechas o periodos importantes mencionados
• Eventos planificados vs pasados
## ⚠️ Puntos de Atención / Acciones Requeridas
• Tareas o acciones identificadas en las notas
• Recordatorios o plazos importantes
• Elementos que requieren atención especial
## 💡 Insights Clave
• Resumen de la información más importante
• Tendencias o patrones observados
• Conexiones entre las diferentes notas
REGLAS:
- Usa formato Markdown con emojis como en el ejemplo
- Sé conciso y organiza la información claramente
- Identifica tendencias reales, no inventes información
- Si una sección no es relevante, usa "N/A" u omítela
- Tono: profesional pero accesible
- TU RESPUESTA DEBE SER EN ESPAÑOL
Tu respuesta:
`.trim(),
de: `
Du bist ein Assistent, der strukturierte Zusammenfassungen von Notizbüchern erstellt.
NOTIZBUCH: ${notebookName}
NOTIZBUCH-NOTIZEN:
${notesSummary}
AUFGABE:
Erstelle eine strukturierte und organisierte Zusammenfassung dieses Notizbuchs, indem du alle Notizen analysierst.
ANTWORTFORMAT (Markdown mit Emojis):
# 📊 Zusammenfassung des Notizbuchs ${notebookName}
## 🌍 Hauptthemen
• Identifiziere 3-5 wiederkehrende Themen
## 📝 Statistiken
• Gesamtzahl der analysierten Notizen
• Hauptinhaltkategorien
## 📅 Zeitliche Elemente
• Wichtige erwähnte Daten oder Zeiträume
• Geplante vs. vergangene Ereignisse
## ⚠️ Handlungspunkte / Aufmerksamkeitspunkte
• In Notizen identifizierte Aufgaben oder Aktionen
• Wichtige Erinnerungen oder Fristen
• Elemente, die besondere Aufmerksamkeit erfordern
## 💡 Wichtige Erkenntnisse
• Zusammenfassung der wichtigsten Informationen
• Beobachtete Trends oder Muster
• Verbindungen zwischen verschiedenen Notizen
REGELN:
- Verwende Markdown-Format mit Emojis wie im Beispiel
- Sei prägnant und organisiere Informationen klar
- Identifiziere echte Trends, erfinde keine Informationen
- Wenn ein Abschnitt nicht relevant ist, verwende "N/A" oder lass ihn weg
- Ton: professionell aber zugänglich
- DEINE ANTWORT MUSS AUF DEUTSCH SEIN
Deine Antwort:
`.trim()
}
return instructions[language] || instructions['en'] || instructions['fr']
}
}
// Export singleton instance
export const notebookSummaryService = new NotebookSummaryService()