chore: clean up repo for public release
- Remove BMAD framework, IDE configs, dev screenshots, test files, internal docs, and backup files - Rename keep-notes/ to memento-note/ - Update all references from keep-notes to memento-note - Add Apache 2.0 license with Commons Clause (non-commercial restriction) - Add clean .gitignore and .env.docker.example
This commit is contained in:
381
memento-note/lib/ai/services/notebook-summary.service.ts
Normal file
381
memento-note/lib/ai/services/notebook-summary.service.ts
Normal file
@@ -0,0 +1,381 @@
|
||||
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,
|
||||
trashedAt: null,
|
||||
},
|
||||
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()
|
||||
Reference in New Issue
Block a user