- Service notebook-organizer.service.ts : analyse IA des notes - Endpoint /api/ai/organize-notebook - Dialog avec 4 sections : 1. Résumé de l'état du carnet 2. Tags suggérés (cliquable pour appliquer) 3. Regroupements logiques par catégorie 4. Détection de doublons avec explication - Bouton 'Organiser' (Wand2) dans la barre du carnet - i18n FR/EN complet - Complète les 3 scénarios : Prof (wizard+exercices), Étudiant (wizard+planning), Ingénieur (organisateur)
105 lines
3.6 KiB
TypeScript
105 lines
3.6 KiB
TypeScript
import { getChatProvider } from '../factory'
|
|
import { getSystemConfig } from '@/lib/config'
|
|
|
|
export interface OrganizationSuggestion {
|
|
suggestedTags: Array<{ name: string; noteIds: string[] }>
|
|
duplicates: Array<{ note1Id: string; note1Title: string; note2Id: string; note2Title: string; reason: string }>
|
|
categories: Array<{ name: string; noteIds: string[]; noteTitles: string[] }>
|
|
summary: string
|
|
}
|
|
|
|
export class NotebookOrganizerService {
|
|
async analyze(
|
|
notes: Array<{ id: string; title: string; contentPreview: string }>,
|
|
language?: string
|
|
): Promise<OrganizationSuggestion> {
|
|
const lang = language || 'fr'
|
|
const langName = lang === 'fr' ? 'français' : lang === 'fa' ? 'فارسی' : 'English'
|
|
|
|
const notesList = notes.map(n =>
|
|
`ID: ${n.id}\nTitre: ${n.title}\nAperçu: ${n.contentPreview.slice(0, 200)}`
|
|
).join('\n---\n')
|
|
|
|
const prompt = `Tu es un expert en organisation de connaissances. Analyse ces notes et propose une organisation.
|
|
|
|
LANGUE : ${langName}
|
|
|
|
NOTES DANS LE CARNET :
|
|
${notesList}
|
|
|
|
Analyse les notes et retourne :
|
|
|
|
1. **suggestedTags** — Tags pertinents à appliquer (3-8 tags). Pour chaque tag, liste les IDs des notes qui correspondent.
|
|
2. **duplicates** — Notes qui se chevauchent ou répètent la même information. Pour chaque paire, explique pourquoi.
|
|
3. **categories** — Regroupements logiques (2-5 catégories). Pour chaque catégorie, liste les IDs et titres des notes.
|
|
4. **summary** — Un résumé court de l'état du carnet et des recommandations.
|
|
|
|
FORMAT JSON UNIQUEMENT :
|
|
\`\`\`json
|
|
{
|
|
"suggestedTags": [
|
|
{ "name": "nom-du-tag", "noteIds": ["id1", "id2"] }
|
|
],
|
|
"duplicates": [
|
|
{ "note1Id": "id1", "note1Title": "...", "note2Id": "id2", "note2Title": "...", "reason": "..." }
|
|
],
|
|
"categories": [
|
|
{ "name": "Nom catégorie", "noteIds": ["id1"], "noteTitles": ["Titre"] }
|
|
],
|
|
"summary": "Résumé court..."
|
|
}
|
|
\`\`\`
|
|
|
|
Si aucune note en double n'est trouvée, retourne un array vide pour "duplicates".`
|
|
|
|
const config = await getSystemConfig()
|
|
const provider = getChatProvider(config)
|
|
const raw = await provider.generateText(prompt)
|
|
|
|
return this.parseResponse(raw)
|
|
}
|
|
|
|
private parseResponse(raw: string): OrganizationSuggestion {
|
|
const jsonMatch = raw.match(/```json\s*([\s\S]+?)\s*```/)
|
|
let jsonStr = jsonMatch ? jsonMatch[1] : raw
|
|
|
|
const start = jsonStr.indexOf('{')
|
|
const end = jsonStr.lastIndexOf('}')
|
|
if (start >= 0 && end > start) {
|
|
jsonStr = jsonStr.slice(start, end + 1)
|
|
}
|
|
|
|
try {
|
|
const parsed = JSON.parse(jsonStr)
|
|
return {
|
|
suggestedTags: (parsed.suggestedTags || []).map((t: any) => ({
|
|
name: String(t.name || ''),
|
|
noteIds: Array.isArray(t.noteIds) ? t.noteIds.map(String) : [],
|
|
})),
|
|
duplicates: (parsed.duplicates || []).map((d: any) => ({
|
|
note1Id: String(d.note1Id || ''),
|
|
note1Title: String(d.note1Title || ''),
|
|
note2Id: String(d.note2Id || ''),
|
|
note2Title: String(d.note2Title || ''),
|
|
reason: String(d.reason || ''),
|
|
})),
|
|
categories: (parsed.categories || []).map((c: any) => ({
|
|
name: String(c.name || ''),
|
|
noteIds: Array.isArray(c.noteIds) ? c.noteIds.map(String) : [],
|
|
noteTitles: Array.isArray(c.noteTitles) ? c.noteTitles.map(String) : [],
|
|
})),
|
|
summary: String(parsed.summary || ''),
|
|
}
|
|
} catch {
|
|
return {
|
|
suggestedTags: [],
|
|
duplicates: [],
|
|
categories: [],
|
|
summary: 'Analyse impossible — réessayer plus tard.',
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
export const notebookOrganizerService = new NotebookOrganizerService()
|