Fetch-Good-Boi / static /debug-panel.jsx
ElisaTrippetti's picture
Update static/debug-panel.jsx
3717ec3 verified
// debug-panel.jsx — floating developer panel shared across all variants.
// Surfaces: recent turns, source tracking, backend, latency, and the
// full keyword-lookup table.
function DebugPanel({ debug, onClose, palette, font }) {
const [tab, setTab] = React.useState("turns");
return (
<div style={{
position: "absolute", right: 16, bottom: 16, top: 16,
width: 380, maxWidth: "44vw",
background: palette.bg, color: palette.fg,
border: `1px solid ${palette.muted}`,
borderRadius: 10,
fontFamily: font, fontSize: 12,
display: "flex", flexDirection: "column",
boxShadow: "0 10px 30px rgba(0,0,0,.35)",
zIndex: 50,
overflow: "hidden",
}}>
<div style={{
padding: "8px 12px",
borderBottom: `1px solid ${palette.muted}`,
display: "flex", alignItems: "center", justifyContent: "space-between",
}}>
<div style={{ display: "flex", gap: 10, alignItems: "center" }}>
<span style={{ color: palette.accent }}></span>
<span style={{ letterSpacing: 0.8, textTransform: "uppercase", fontSize: 11 }}>
fetch good boi / debug
</span>
</div>
<button onClick={onClose} aria-label="Close debug panel" style={{
background: "transparent", border: "none", color: palette.dim,
cursor: "pointer", fontSize: 14, padding: "0 4px",
}}>×</button>
</div>
<div style={{
display: "flex", gap: 2,
padding: "6px 10px 0",
borderBottom: `1px solid ${palette.muted}`,
}}>
{[
{ id: "turns", label: "turns" },
{ id: "keywords", label: "keywords" },
{ id: "about", label: "about" },
].map(t => (
<button key={t.id} onClick={() => setTab(t.id)} style={{
background: "transparent",
color: tab === t.id ? palette.fg : palette.dim,
borderBottom: tab === t.id ? `2px solid ${palette.accent}` : "2px solid transparent",
border: "none", borderRadius: 0,
padding: "6px 8px",
fontFamily: "inherit", fontSize: 12, cursor: "pointer",
}}>{t.label}</button>
))}
</div>
<div style={{ flex: 1, overflowY: "auto", padding: 12 }}>
{tab === "turns" && <DebugLog debug={debug} palette={palette} />}
{tab === "keywords" && <DebugKB palette={palette} />}
{tab === "about" && <DebugAbout palette={palette} />}
</div>
</div>
);
}
function DebugLog({ debug, palette }) {
if (debug.length === 0) {
return (
<div style={{ color: palette.dim, fontStyle: "italic", padding: "8px 4px" }}>
No turns yet. Ask Fetch something.
</div>
);
}
return (
<div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
{debug.map((d, i) => (
<div key={i} style={{
border: `1px solid ${palette.muted}`,
borderRadius: 6,
padding: 8,
}}>
<div style={{ color: palette.dim, fontSize: 12, display: "flex", justifyContent: "space-between", marginBottom: 4 }}>
<span>{new Date(d.t).toLocaleTimeString()}</span>
<span>{d.backend} · {d.ms}ms</span>
</div>
<div style={{ marginBottom: 4 }}>
<span style={{ color: palette.dim }}>user&gt; </span>
{d.user}
</div>
<div style={{ marginBottom: 4 }}>
<span style={{ color: palette.accent }}>fetch&gt; </span>
{d.reply}
</div>
<div style={{ color: palette.dim, fontSize: 12 }}>
{"source: "}
<span style={{
color: d.source === "error" ? "#ff6b6b"
: d.source === "fallback" ? palette.dim
: palette.accent,
}}>
{d.source === "fact" ? `fact · ${d.fact?.keyword}` : d.source || "unknown"}
</span>
</div>
</div>
))}
</div>
);
}
function DebugKB({ palette }) {
return (
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
<div style={{ color: palette.dim, marginBottom: 4 }}>
{FETCH_KNOWLEDGE_BASE.length} keywords · first match wins
</div>
{FETCH_KNOWLEDGE_BASE.map(([k, v]) => (
<div key={k} style={{
border: `1px solid ${palette.muted}`,
borderRadius: 6,
padding: 8,
}}>
<div style={{ color: palette.accent, marginBottom: 3 }}>{k}</div>
<div style={{ color: palette.fg, lineHeight: 1.4 }}>{v}</div>
</div>
))}
</div>
);
}
function DebugAbout({ palette }) {
return (
<div style={{ lineHeight: 1.6, color: palette.fg, display: "flex", flexDirection: "column", gap: 10 }}>
<div>Fetch Good Boi is a dog-loving chatbot backed by BlenderBot-400M-distill running on CPU.</div>
<div>Responses use a keyword lookup layer — if a fact matches the query, it's prepended to the prompt. BlenderBot then generates a reply within a four-turn context window. Fallbacks cover anything the model returns too short or empty. If the backend fails, the browser falls back to keyword lookup automatically.</div>
<div>The demo version runs separately as a <a href="https://huggingface.co/spaces/ElisaTrippetti/Fetch-Pup" target="_blank" rel="noopener noreferrer" style={{ color: palette.accent, textDecoration: "underline" }}>static Space</a>.</div>
<div>Fetch Good Boi runs on CPU, so responses may take a few seconds.</div>
<div style={{ color: palette.dim }}>Designed with Claude Design · Built with Claude Code</div>
</div>
);
}
Object.assign(window, { DebugPanel });