Claude
Fix pasted-source bug: actually generate a pipeline instead of relabeling the demo
9dc9b9a unverified | "use client"; | |
| import { useEffect, useState } from "react"; | |
| import { Send, Sparkles } from "lucide-react"; | |
| type ChatMessage = { role: "user" | "assistant"; content: string }; | |
| const SUGGESTIONS = [ | |
| "Why is the LLM stage tiered B instead of A?", | |
| "Walk me through the End-of-Speech Pop risk on Avatar.", | |
| "What would it take to fix the Failure 3 cascade?", | |
| ]; | |
| export default function ExpertChat({ | |
| selectedNodeId, | |
| seedQuestion, | |
| onSeedConsumed, | |
| }: { | |
| selectedNodeId: string | null; | |
| seedQuestion?: string | null; | |
| onSeedConsumed?: () => void; | |
| }) { | |
| const [messages, setMessages] = useState<ChatMessage[]>([]); | |
| const [input, setInput] = useState(""); | |
| const [loading, setLoading] = useState(false); | |
| const [error, setError] = useState<string | null>(null); | |
| async function send(text?: string) { | |
| const content = (text ?? input).trim(); | |
| if (!content || loading) return; | |
| const next = [...messages, { role: "user" as const, content }]; | |
| setMessages(next); | |
| setInput(""); | |
| setLoading(true); | |
| setError(null); | |
| try { | |
| const res = await fetch("/api/expert", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ messages: next, selectedNodeId }), | |
| }); | |
| const data = await res.json(); | |
| if (!res.ok) throw new Error(data.error || "Request failed"); | |
| setMessages([...next, { role: "assistant", content: data.text }]); | |
| } catch (err) { | |
| setError(err instanceof Error ? err.message : "Something went wrong."); | |
| } finally { | |
| setLoading(false); | |
| } | |
| } | |
| useEffect(() => { | |
| if (!seedQuestion) return; | |
| send(seedQuestion); | |
| onSeedConsumed?.(); | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| }, [seedQuestion]); | |
| return ( | |
| <div className="flex flex-col h-full"> | |
| <div className="flex-1 overflow-y-auto p-4 flex flex-col gap-3"> | |
| {messages.length === 0 && ( | |
| <div className="flex flex-col gap-2"> | |
| <div className="flex items-center gap-2 text-sm text-[var(--muted)]"> | |
| <Sparkles size={14} className="text-[var(--accent-teal)]" /> | |
| Samantha audits this pipeline against 5 failure modes: Uncanny Valley, | |
| End-of-Speech Pop, Cascaded Latency, VRAM Death, and the VASA-1 Problem. | |
| </div> | |
| <div className="flex flex-col gap-1.5 mt-2"> | |
| {SUGGESTIONS.map((s) => ( | |
| <button | |
| key={s} | |
| onClick={() => send(s)} | |
| className="text-left text-xs text-[var(--muted)] border border-[var(--panel-border)] rounded-lg px-2.5 py-2 hover:text-white hover:border-white/20 transition" | |
| > | |
| {s} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| )} | |
| {messages.map((m, i) => ( | |
| <div | |
| key={i} | |
| className={`text-sm rounded-lg px-3 py-2 max-w-[92%] whitespace-pre-wrap ${ | |
| m.role === "user" | |
| ? "self-end bg-[var(--accent-blue)]/20 border border-[var(--accent-blue)]/30" | |
| : "self-start glass-panel" | |
| }`} | |
| > | |
| {m.content} | |
| </div> | |
| ))} | |
| {loading && ( | |
| <div className="self-start text-xs text-[var(--muted)] px-3">Thinking…</div> | |
| )} | |
| {error && ( | |
| <div className="self-start text-xs text-red-300/90 px-3">{error}</div> | |
| )} | |
| </div> | |
| <div className="p-3 border-t border-[var(--panel-border)]"> | |
| <div className="glass-pill rounded-xl px-3 py-2 flex items-center gap-2"> | |
| <input | |
| value={input} | |
| onChange={(e) => setInput(e.target.value)} | |
| onKeyDown={(e) => e.key === "Enter" && send()} | |
| placeholder="Ask Samantha…" | |
| className="flex-1 bg-transparent outline-none text-sm placeholder:text-[var(--muted)]" | |
| /> | |
| <button | |
| onClick={() => send()} | |
| disabled={loading} | |
| className="accent-send size-7 rounded-full flex items-center justify-center text-white disabled:opacity-50" | |
| aria-label="Send" | |
| > | |
| <Send size={13} /> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |