"use client"; import { useEffect, useRef, useState } from "react"; import { usePathname } from "next/navigation"; interface Msg { role: "user" | "assistant"; content: string; } export default function AskBBAI() { const pathname = usePathname(); const [open, setOpen] = useState(false); const [input, setInput] = useState(""); const [busy, setBusy] = useState(false); const [messages, setMessages] = useState([ { role: "assistant", content: "Hi — I'm AV Beat AI. Ask me anything about pro AV, live production, or display technology. I'll cite sources from the AV Beat archive.", }, ]); const [err, setErr] = useState(null); const drawerRef = useRef(null); const inputRef = useRef(null); useEffect(() => { if (!open) return; inputRef.current?.focus(); const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") setOpen(false); }; document.addEventListener("keydown", onKey); return () => document.removeEventListener("keydown", onKey); }, [open]); if (pathname?.startsWith("/forum")) return null; async function send() { const q = input.trim(); if (!q || busy) return; setErr(null); setInput(""); const next = [...messages, { role: "user" as const, content: q }]; setMessages(next); setBusy(true); try { const r = await fetch("/api/ask-bb-ai", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ messages: next }), }); if (!r.ok) { const body = await r.json().catch(() => ({})); setErr(body.error || `HTTP ${r.status}`); setBusy(false); return; } const data = await r.json(); setMessages([...next, { role: "assistant", content: data.reply || "(no response)" }]); } catch (e: any) { setErr(e.message || String(e)); } finally { setBusy(false); } } return ( <> {!open && ( )} {open && (

AV Beat AI

{messages.map((m, i) => (
))} {busy && (
Thinking…
)} {err &&
{err}
}
setInput(e.target.value)} onKeyDown={(e) => e.key === "Enter" && send()} placeholder="Ask about an event, a vendor, a workflow…" disabled={busy} className="flex-1 bg-[#111] border border-[#DCE6F2] rounded px-3 py-2 text-sm text-[#e5e7eb] focus:border-[var(--color-text-info,#60a5fa)] focus:outline-none" />

30 messages/hour · cites AV Beat archive

)} ); } function escapeHtml(s: string): string { return s.replace(/&/g, "&").replace(//g, ">"); } function linkifyMarkdown(s: string): string { let out = escapeHtml(s); out = out.replace( /\[([^\]]+)\]\(([^)]+)\)/g, '$1' ); out = out.replace(/\n/g, "
"); return out; }