feat: AI Overview recherche + AI Writer inline streaming
- AI Overview : synthèse IA en haut des résultats de recherche (Ctrl+K) - Service search-overview.service.ts - Endpoint /api/ai/search-overview - Carte 'Réponse IA' avec Sparkles en haut du panneau gauche - Pur additif, ne modifie pas le classement des résultats - AI Writer inline : slash menu → 'Écrire avec l'IA' → champ inline - Mode 'write' dans paragraph-refactor.service.ts - Streaming paragraphe par paragraphe (120ms delay) - Nettoyage HTML (espaces vides supprimés) - Ref synchrone pour éviter fermeture du menu pendant la frappe - Fix: index slashCommands AI Writer corrigé - Fix: Loader2 import manquant - i18n FR/EN
This commit is contained in:
57
memento-note/lib/ai/services/search-overview.service.ts
Normal file
57
memento-note/lib/ai/services/search-overview.service.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { getChatProvider } from '../factory'
|
||||
import { getSystemConfig } from '@/lib/config'
|
||||
|
||||
export interface SearchOverviewResult {
|
||||
answer: string
|
||||
hasRelevantInfo: boolean
|
||||
}
|
||||
|
||||
export class SearchOverviewService {
|
||||
async generate(
|
||||
query: string,
|
||||
results: Array<{ title: string; snippet: string }>,
|
||||
language?: string
|
||||
): Promise<SearchOverviewResult> {
|
||||
if (results.length === 0) {
|
||||
return { answer: '', hasRelevantInfo: false }
|
||||
}
|
||||
|
||||
const lang = language || 'fr'
|
||||
const langName = lang === 'fr' ? 'français' : lang === 'fa' ? 'فارسی' : 'English'
|
||||
|
||||
const topResults = results.slice(0, 8)
|
||||
const context = topResults.map((r, i) =>
|
||||
`[Note ${i + 1}: ${r.title}]\n${r.snippet.slice(0, 300)}`
|
||||
).join('\n\n---\n\n')
|
||||
|
||||
const prompt = `Tu es un assistant de recherche. Réponds à la question de l'utilisateur en te basant UNIQUEMENT sur les notes fournies ci-dessous.
|
||||
|
||||
LANGUE DE RÉPONSE : ${langName}
|
||||
|
||||
QUESTION : "${query}"
|
||||
|
||||
NOTES TROUVÉES :
|
||||
${context}
|
||||
|
||||
RÈGLES :
|
||||
- Réponds en ${langName} UNIQUEMENT
|
||||
- Sois concis : 2-4 phrases maximum
|
||||
- Si les notes contiennent l'info, réponds directement
|
||||
- Si les notes ne contiennent PAS l'info, réponds exactement : "NO_RELEVANT_INFO"
|
||||
- Ne dis pas "selon les notes" — réponds naturellement
|
||||
- Cite les titres des notes pertinentes entre parenthèses à la fin si utile`
|
||||
|
||||
const config = await getSystemConfig()
|
||||
const provider = getChatProvider(config)
|
||||
const raw = await provider.generateText(prompt)
|
||||
|
||||
const answer = raw.trim()
|
||||
if (answer === 'NO_RELEVANT_INFO' || answer.length < 10) {
|
||||
return { answer: '', hasRelevantInfo: false }
|
||||
}
|
||||
|
||||
return { answer, hasRelevantInfo: true }
|
||||
}
|
||||
}
|
||||
|
||||
export const searchOverviewService = new SearchOverviewService()
|
||||
Reference in New Issue
Block a user