// src/Chat.jsx — chat thread with messages, sources, photo galleries, follow-ups const FLOWS = () => window.ALCY_DATA.FLOWS; // Map a free-form question to a canned flow id. Falls back to "forges". function routeQuestion(q) { const s = q.toLowerCase(); if (s.includes("forge") && (s.includes("photo") || s.includes("montre") || s.includes("voir"))) return "forgesPhotos"; if (s.includes("forge") || s.includes("devos") || s.includes("lemaire")) return "forges"; if (s.includes("paris") || s.includes("roubaix") || s.includes("vélo") || s.includes("velo") || s.includes("course")) return "paris"; if (s.includes("école") || s.includes("ecole") || s.includes("classe") || s.includes("dubois")) return "ecolePhotos"; return "forges"; } const MessageBubble = ({ msg }) => { // Convert simple markdown-ish: **bold**, • bullets, \n const renderText = (t) => t.split("\n").map((line, i) => { const parts = line.split(/(\*\*[^*]+\*\*)/g).map((p, j) => p.startsWith("**") && p.endsWith("**") ? {p.slice(2, -2)} : {p} ); return
{parts}
; }); return (
{msg.role === "alcy" &&
}
{msg.typing ? (
) : ( <> {renderText(msg.text)} {msg.photos && (
{msg.photos.slice(0, 6).map((p) => ( ))}
)} {msg.sources && msg.sources.length > 0 && (
✦ Sources · {msg.sources.length} document{msg.sources.length > 1 ? "s" : ""}
{msg.sources.map((s, i) => )}
)} {msg.followups && msg.followups.length > 0 && (
{msg.followups.map((f, i) => ( ))}
)} )}
{!msg.typing && msg.time && (
{msg.time}
)}
); }; const Chat = ({ messages, onAsk, onFollowup, kid }) => { const [text, setText] = React.useState(""); const threadRef = React.useRef(null); React.useEffect(() => { const el = threadRef.current; if (el) el.scrollTop = el.scrollHeight; }, [messages]); const submit = (q) => { const v = (q || text).trim(); if (!v) return; onAsk(v); setText(""); }; return (
{messages.map((m, i) => ( ))}
{ e.preventDefault(); submit(); }} > setText(e.target.value)} placeholder={kid ? "Pose une autre question…" : "Posez une autre question à Alcy…"} />
⌘ K · raccourcis {kid ? "Tu peux écrire comme tu parles, Alcy comprend !" : "Alcy cite ses sources : photos, documents et témoignages du fonds local."} Connecté à 1 842 documents
); }; Object.assign(window, { Chat, routeQuestion });