import { Language } from '../types' import { FAQEntry } from './types' import { PRESENTER_FAQ } from './presenter-faq' /** * Match a user query against pre-cached FAQ entries. * Returns the best match if score exceeds threshold, or null for LLM fallback. */ export function matchFAQ(query: string, lang: Language): FAQEntry | null { const matches = matchFAQMultiple(query, lang, 1) return matches.length > 0 ? matches[0] : null } /** * Match a user query and return the top N relevant FAQ entries as context. * Used to feed multiple relevant FAQs into the LLM prompt. */ export function matchFAQMultiple(query: string, lang: Language, maxResults: number = 3): FAQEntry[] { const normalized = query.toLowerCase().trim() const queryWords = normalized.split(/\s+/) const scored: { entry: FAQEntry; score: number }[] = [] for (const entry of PRESENTER_FAQ) { let score = 0 // Check keyword matches for (const keyword of entry.keywords) { const kwLower = keyword.toLowerCase() if (kwLower.includes(' ')) { if (normalized.includes(kwLower)) { score += 3 * entry.priority / 10 } } else { if (queryWords.some(w => w === kwLower || w.startsWith(kwLower) || kwLower.startsWith(w))) { score += 1 } if (normalized.includes(kwLower)) { score += 0.5 } } } // Check question text overlap const questionText = lang === 'de' ? entry.question_de : entry.question_en const questionWords = questionText.toLowerCase().split(/\s+/) const overlapCount = queryWords.filter(w => w.length > 2 && questionWords.some(qw => qw.includes(w) || w.includes(qw)) ).length if (overlapCount >= 2) { score += overlapCount * 0.5 } score *= (entry.priority / 10) if (score >= 1.0) { scored.push({ entry, score }) } } // Sort by score descending, return top N scored.sort((a, b) => b.score - a.score) return scored.slice(0, maxResults).map(s => s.entry) } /** * Get FAQ answer text in the requested language */ export function getFAQAnswer(entry: FAQEntry, lang: Language): string { return lang === 'de' ? entry.answer_de : entry.answer_en } /** * Build a context string from multiple FAQ matches for LLM injection */ export function buildFAQContext(entries: FAQEntry[], lang: Language): string { if (entries.length === 0) return '' const parts = entries.map((entry, idx) => { const q = lang === 'de' ? entry.question_de : entry.question_en const a = lang === 'de' ? entry.answer_de : entry.answer_en return `### Relevante Information ${idx + 1}: ${q}\n${a}` }) return `\n\n## Vorrecherchierte Antworten (nutze diese als Basis, kombiniere bei Bedarf)\n${parts.join('\n\n')}\n\nWICHTIG: Formuliere die Antwort in deinen eigenen Worten als natürlichen Fließtext. Kombiniere die Informationen wenn die Frage mehrere Themen berührt. Antworte nicht mit Bulletlisten.` }