import { getSystemConfig } from '@/lib/config' import { getChatProvider } from '@/lib/ai/factory' export type FlashcardStyle = 'qa' | 'cloze' | 'concept' export interface GeneratedFlashcard { front: string back: string type: FlashcardStyle } const STYLE_HINTS: Record = { qa: 'question/answer pairs — front is a clear question, back is a concise answer', cloze: 'fill-in-the-blank — front uses ___ for the missing word(s), back is the complete sentence', concept: 'term/definition — front is a term or concept name, back is its definition', } function parseFlashcardsJson(raw: string, style: FlashcardStyle): GeneratedFlashcard[] { const trimmed = raw.trim() const arrayMatch = trimmed.match(/\[[\s\S]*\]/) if (!arrayMatch) return [] try { const parsed = JSON.parse(arrayMatch[0]) as unknown if (!Array.isArray(parsed)) return [] return parsed .map((item) => { if (!item || typeof item !== 'object') return null const obj = item as Record const front = typeof obj.front === 'string' ? obj.front.trim() : '' const back = typeof obj.back === 'string' ? obj.back.trim() : '' const type = (typeof obj.type === 'string' ? obj.type : style) as FlashcardStyle if (!front || !back) return null return { front: front.slice(0, 500), back: back.slice(0, 800), type: ['qa', 'cloze', 'concept'].includes(type) ? type : style, } }) .filter((c): c is GeneratedFlashcard => c !== null) } catch { return [] } } export async function generateFlashcardsFromNote(params: { title: string textContent: string count: number style: FlashcardStyle language?: string }): Promise { const count = Math.min(20, Math.max(5, params.count)) const excerpt = params.textContent.slice(0, 8000) const lang = params.language && params.language !== 'auto' ? params.language : 'same as source' const config = await getSystemConfig() const provider = getChatProvider(config) const prompt = `You create study flashcards from personal notes for spaced repetition. Note title: ${params.title || 'Untitled'} Language: ${lang} Style: ${params.style} — ${STYLE_HINTS[params.style]} Source content: ${excerpt} Generate exactly ${count} flashcards. Use the same language as the source. Respond with ONLY a JSON array (no markdown): [ { "front": "...", "back": "...", "type": "${params.style}" } ] Rules: - Each card tests one distinct fact from the note - Front and back must be self-contained - No duplicate cards - Cloze cards must include ___ on the front` const raw = await provider.generateText(prompt) const cards = parseFlashcardsJson(raw, params.style) if (cards.length === 0) { throw new Error('Could not parse flashcards from AI response') } return cards.slice(0, count) }