import { getChatProvider } from '../factory' import { getSystemConfig } from '@/lib/config' import { extractPublishImageUrls } from '@/lib/publish/process-note-html' import { transformEditorBlocksForPublish } from '@/lib/publish/transform-editor-blocks' import type { PublishEnhanceSpec, PublishRewriteSpec, PublishTemplateId } from '@/lib/publish/types' const TEMPLATE_HINTS: Record = { magazine: `Chapô accrocheur + une citation mise en avant (pullQuote). Style journalistique.`, brief: `Résumé exécutif dense + 3 à 5 points clés (keyPoints). Ton professionnel actionnable.`, essay: `Épigraphe inspirante + chapô réfléchi. Ton littéraire mais clair.`, } /* ─── MODE ÉDITORIAL (pas de réécriture) ─────────────────────────────────── */ export class PublishEnhanceService { async enhance( title: string, noteContent: string, template: PublishTemplateId, language: string, ): Promise { const imageUrls = extractPublishImageUrls(noteContent) const plainText = noteContent .replace(/<[^>]+>/g, ' ') .replace(/ /g, ' ') .replace(/\s+/g, ' ') .trim() .slice(0, 6000) const langName = language === 'fr' ? 'français' : language === 'fa' ? 'فارسی' : 'English' const imageHint = imageUrls.length > 0 ? `La note contient ${imageUrls.length} image(s) — elles sont affichées automatiquement.` : '' const prompt = `Tu es un éditeur web. Rédige UNIQUEMENT l'habillage éditorial d'une page publique. TITRE : "${title || 'Sans titre'}" LANGUE : ${langName} STYLE : ${TEMPLATE_HINTS[template]} ${imageHint} CONTENU (pour contexte) : ${plainText} Réponds en JSON strict, sans markdown : { "summary": "chapô 2-3 phrases", "pullQuote": "phrase marquante (magazine)", "epigraph": "ouverture courte (essay)", "keyPoints": ["point 1", "point 2", "point 3"] }` const config = await getSystemConfig() const provider = getChatProvider(config) const raw = await provider.generateText(prompt) return this.parseEnhanceResponse(raw, plainText) } private parseEnhanceResponse(raw: string, fallback: string): PublishEnhanceSpec { const jsonMatch = raw.match(/```json\s*([\s\S]+?)\s*```/) let jsonStr = jsonMatch ? jsonMatch[1] : raw const s = jsonStr.indexOf('{') const e = jsonStr.lastIndexOf('}') if (s >= 0 && e > s) jsonStr = jsonStr.slice(s, e + 1) try { const p = JSON.parse(jsonStr) return { summary: String(p.summary || '').trim() || fallback.slice(0, 280), pullQuote: p.pullQuote ? String(p.pullQuote).trim() : undefined, epigraph: p.epigraph ? String(p.epigraph).trim() : undefined, keyPoints: Array.isArray(p.keyPoints) ? p.keyPoints.map((k: unknown) => String(k).trim()).filter(Boolean).slice(0, 6) : undefined, } } catch { return { summary: fallback.slice(0, 280) } } } /* ─── MODE RÉÉCRITURE WEB ─────────────────────────────────────────────── */ async rewrite( title: string, noteContent: string, template: PublishTemplateId, language: string, ): Promise { const langName = language === 'fr' ? 'français' : language === 'fa' ? 'فارسی' : 'English' const plainText = noteContent .replace(/<[^>]+>/g, ' ') .replace(/ /g, ' ') .replace(/\s+/g, ' ') .trim() .slice(0, 8000) // Corps = transformation déterministe du HTML éditeur (exercices, toggles, callouts…) const structuredBody = transformEditorBlocksForPublish(noteContent) const prompt = `Tu es un éditeur web. Analyse ce contenu de note et rédige UNIQUEMENT l'habillage éditorial. Langue : ${langName} Titre : "${title || 'Sans titre'}" Style : ${TEMPLATE_HINTS[template]} Le corps HTML est déjà structuré (exercices, définitions, toggles) — tu ne réécris PAS le corps. CONTENU (texte) : ${plainText} Réponds en JSON strict, sans markdown : { "contentType": "article|exercises|tutorial|reference|mixed", "summary": "chapô 1-2 phrases percutantes" }` const config = await getSystemConfig() const provider = getChatProvider(config) const raw = await provider.generateText(prompt) return this.parseRewriteResponse(raw, title, plainText, structuredBody) } private parseRewriteResponse( raw: string, title: string, fallback: string, structuredBody: string, ): PublishRewriteSpec { const jsonMatch = raw.match(/```json\s*([\s\S]+?)\s*```/) let jsonStr = jsonMatch ? jsonMatch[1] : raw const s = jsonStr.indexOf('{') const e = jsonStr.lastIndexOf('}') if (s >= 0 && e > s) jsonStr = jsonStr.slice(s, e + 1) try { const p = JSON.parse(jsonStr) return { contentType: ['article', 'exercises', 'tutorial', 'reference', 'mixed'].includes(p.contentType) ? p.contentType : 'article', summary: String(p.summary || '').trim() || '', body: structuredBody || `

${fallback.slice(0, 500)}

`, } } catch { return { contentType: 'article', summary: '', body: structuredBody || `

${title}

${fallback.slice(0, 600)}

`, } } } } export const publishEnhanceService = new PublishEnhanceService()