ElisaTrippetti commited on
Commit
b819eec
·
verified ·
1 Parent(s): 506b1dc

Upload 5 files

Browse files
Files changed (2) hide show
  1. chat-engine.jsx +20 -13
  2. debug-panel.jsx +33 -2
chat-engine.jsx CHANGED
@@ -36,18 +36,22 @@ const FALLBACKS = [
36
 
37
  const INTENTS = [
38
  {
 
39
  patterns: [/\b(hi|hello|hey)\b/i, /good (morning|afternoon|evening)/i],
40
  response: "Hi! I'm Fetch Pup. Ask me something about dogs, or try the suggestions below.",
41
  },
42
  {
 
43
  patterns: [/how are you/i, /how('s| is) it going/i, /what'?s up/i],
44
  response: "Tail's wagging, thanks for asking! Got a dog question for me?",
45
  },
46
  {
 
47
  patterns: [/what can you do/i, /what do you (know|do)/i, /\bhelp\b/i],
48
  response: "I know a bunch of dog facts. Ask a question or try the suggestions — I'll do my best.",
49
  },
50
  {
 
51
  patterns: [/who are you/i, /what are you/i],
52
  response: "I'm Fetch Pup — a static chatbot demo. No model running, just intent matching and keyword lookup. But I know my dogs!",
53
  },
@@ -56,7 +60,7 @@ const INTENTS = [
56
  function matchIntent(query) {
57
  const q = query || "";
58
  for (const intent of INTENTS) {
59
- if (intent.patterns.some(p => p.test(q))) return intent.response;
60
  }
61
  return null;
62
  }
@@ -121,7 +125,7 @@ function buildPrompt(history, userInput, fact, personality) {
121
 
122
  async function generateReply({ userInput, history, backend, personality }) {
123
  const intent = matchIntent(userInput);
124
- if (intent) return { text: intent, fact: null };
125
 
126
  const fact = retrieveFact(userInput);
127
 
@@ -131,9 +135,9 @@ async function generateReply({ userInput, history, backend, personality }) {
131
  const raw = await window.claude.complete(prompt);
132
  const text = (raw || "").trim().replace(/^Bot:\s*/i, "").split("\nUser:")[0].trim();
133
  if (!text || text.split(/\s+/).length <= 2) {
134
- return { text: pickFallback(), fact };
135
  }
136
- return { text, fact };
137
  } catch (err) {
138
  console.warn("Fetch: claude backend failed, falling back.", err);
139
  // fall through to local path
@@ -141,8 +145,8 @@ async function generateReply({ userInput, history, backend, personality }) {
141
  }
142
 
143
  // Local / offline / HF-static path: keyword fact wins, else fallback.
144
- if (fact) return { text: fact.fact, fact };
145
- return { text: pickFallback(), fact };
146
  }
147
 
148
  // Hook: owns conversation state + send/clear + rotating suggestions.
@@ -171,12 +175,14 @@ function useFetchChat({ backend = "claude", personality = "subtle" } = {}) {
171
  setPending(true);
172
 
173
  const t0 = performance.now();
174
- const { text, fact } = await generateReply({
175
- userInput,
176
- history: priorHistory,
177
- backend,
178
- personality,
179
- });
 
 
180
  const ms = Math.round(performance.now() - t0);
181
 
182
  setMessages(prev => prev.map(m =>
@@ -185,7 +191,7 @@ function useFetchChat({ backend = "claude", personality = "subtle" } = {}) {
185
  : m
186
  ));
187
  setDebug(prev => [
188
- { t: Date.now(), user: userInput, reply: text, fact, ms, backend },
189
  ...prev,
190
  ].slice(0, 20));
191
  setPending(false);
@@ -228,4 +234,5 @@ Object.assign(window, {
228
  retrieveFact,
229
  FETCH_KNOWLEDGE_BASE: KNOWLEDGE_BASE,
230
  FETCH_SUGGESTIONS: SUGGESTIONS,
 
231
  });
 
36
 
37
  const INTENTS = [
38
  {
39
+ label: "greeting",
40
  patterns: [/\b(hi|hello|hey)\b/i, /good (morning|afternoon|evening)/i],
41
  response: "Hi! I'm Fetch Pup. Ask me something about dogs, or try the suggestions below.",
42
  },
43
  {
44
+ label: "small talk",
45
  patterns: [/how are you/i, /how('s| is) it going/i, /what'?s up/i],
46
  response: "Tail's wagging, thanks for asking! Got a dog question for me?",
47
  },
48
  {
49
+ label: "capability",
50
  patterns: [/what can you do/i, /what do you (know|do)/i, /\bhelp\b/i],
51
  response: "I know a bunch of dog facts. Ask a question or try the suggestions — I'll do my best.",
52
  },
53
  {
54
+ label: "identity",
55
  patterns: [/who are you/i, /what are you/i],
56
  response: "I'm Fetch Pup — a static chatbot demo. No model running, just intent matching and keyword lookup. But I know my dogs!",
57
  },
 
60
  function matchIntent(query) {
61
  const q = query || "";
62
  for (const intent of INTENTS) {
63
+ if (intent.patterns.some(p => p.test(q))) return intent;
64
  }
65
  return null;
66
  }
 
125
 
126
  async function generateReply({ userInput, history, backend, personality }) {
127
  const intent = matchIntent(userInput);
128
+ if (intent) return { text: intent.response, fact: null, source: "intent", label: intent.label };
129
 
130
  const fact = retrieveFact(userInput);
131
 
 
135
  const raw = await window.claude.complete(prompt);
136
  const text = (raw || "").trim().replace(/^Bot:\s*/i, "").split("\nUser:")[0].trim();
137
  if (!text || text.split(/\s+/).length <= 2) {
138
+ return { text: pickFallback(), fact, source: "fallback" };
139
  }
140
+ return { text, fact, source: "model" };
141
  } catch (err) {
142
  console.warn("Fetch: claude backend failed, falling back.", err);
143
  // fall through to local path
 
145
  }
146
 
147
  // Local / offline / HF-static path: keyword fact wins, else fallback.
148
+ if (fact) return { text: fact.fact, fact, source: "fact" };
149
+ return { text: pickFallback(), fact: null, source: "fallback" };
150
  }
151
 
152
  // Hook: owns conversation state + send/clear + rotating suggestions.
 
175
  setPending(true);
176
 
177
  const t0 = performance.now();
178
+ let result;
179
+ try {
180
+ result = await generateReply({ userInput, history: priorHistory, backend, personality });
181
+ } catch (err) {
182
+ console.error("Fetch: generateReply failed.", err);
183
+ result = { text: "Something went wrong. Please try again.", fact: null, source: "error" };
184
+ }
185
+ const { text, fact, source, label } = result;
186
  const ms = Math.round(performance.now() - t0);
187
 
188
  setMessages(prev => prev.map(m =>
 
191
  : m
192
  ));
193
  setDebug(prev => [
194
+ { t: Date.now(), user: userInput, reply: text, fact, source, label, ms, backend },
195
  ...prev,
196
  ].slice(0, 20));
197
  setPending(false);
 
234
  retrieveFact,
235
  FETCH_KNOWLEDGE_BASE: KNOWLEDGE_BASE,
236
  FETCH_SUGGESTIONS: SUGGESTIONS,
237
+ FETCH_INTENTS: INTENTS,
238
  });
debug-panel.jsx CHANGED
@@ -41,6 +41,7 @@ function DebugPanel({ debug, onClose, palette, font }) {
41
  }}>
42
  {[
43
  { id: "turns", label: "turns" },
 
44
  { id: "keywords", label: "keywords" },
45
  { id: "about", label: "about" },
46
  ].map(t => (
@@ -57,6 +58,7 @@ function DebugPanel({ debug, onClose, palette, font }) {
57
 
58
  <div style={{ flex: 1, overflowY: "auto", padding: 12 }}>
59
  {tab === "turns" && <DebugLog debug={debug} palette={palette} />}
 
60
  {tab === "keywords" && <DebugKB palette={palette} />}
61
  {tab === "about" && <DebugAbout palette={palette} />}
62
  </div>
@@ -92,8 +94,17 @@ function DebugLog({ debug, palette }) {
92
  <span style={{ color: palette.accent }}>reply&gt; </span>
93
  {d.reply}
94
  </div>
95
- <div style={{ color: palette.dim, fontSize: 10 }}>
96
- fact: {d.fact ? <span style={{ color: palette.accent }}>matched "{d.fact.keyword}"</span> : "none"}
 
 
 
 
 
 
 
 
 
97
  </div>
98
  </div>
99
  ))}
@@ -121,6 +132,26 @@ function DebugKB({ palette }) {
121
  );
122
  }
123
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
  function DebugAbout({ palette }) {
125
  return (
126
  <div style={{ lineHeight: 1.6, color: palette.fg, display: "flex", flexDirection: "column", gap: 10 }}>
 
41
  }}>
42
  {[
43
  { id: "turns", label: "turns" },
44
+ { id: "intents", label: "intents" },
45
  { id: "keywords", label: "keywords" },
46
  { id: "about", label: "about" },
47
  ].map(t => (
 
58
 
59
  <div style={{ flex: 1, overflowY: "auto", padding: 12 }}>
60
  {tab === "turns" && <DebugLog debug={debug} palette={palette} />}
61
+ {tab === "intents" && <DebugIntents palette={palette} />}
62
  {tab === "keywords" && <DebugKB palette={palette} />}
63
  {tab === "about" && <DebugAbout palette={palette} />}
64
  </div>
 
94
  <span style={{ color: palette.accent }}>reply&gt; </span>
95
  {d.reply}
96
  </div>
97
+ <div style={{ color: palette.dim, fontSize: 11 }}>
98
+ {"source: "}
99
+ <span style={{
100
+ color: d.source === "error" ? "#ff6b6b"
101
+ : d.source === "fallback" ? palette.dim
102
+ : palette.accent,
103
+ }}>
104
+ {d.source === "fact" ? `fact · ${d.fact?.keyword}`
105
+ : d.source === "intent" ? `intent · ${d.label}`
106
+ : d.source || "unknown"}
107
+ </span>
108
  </div>
109
  </div>
110
  ))}
 
132
  );
133
  }
134
 
135
+ function DebugIntents({ palette }) {
136
+ return (
137
+ <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
138
+ <div style={{ color: palette.dim, marginBottom: 4 }}>
139
+ {FETCH_INTENTS.length} intents · first match wins
140
+ </div>
141
+ {FETCH_INTENTS.map(intent => (
142
+ <div key={intent.label} style={{
143
+ border: `1px solid ${palette.muted}`,
144
+ borderRadius: 6,
145
+ padding: 8,
146
+ }}>
147
+ <div style={{ color: palette.accent, marginBottom: 3 }}>{intent.label}</div>
148
+ <div style={{ color: palette.fg, lineHeight: 1.4 }}>{intent.response}</div>
149
+ </div>
150
+ ))}
151
+ </div>
152
+ );
153
+ }
154
+
155
  function DebugAbout({ palette }) {
156
  return (
157
  <div style={{ lineHeight: 1.6, color: palette.fg, display: "flex", flexDirection: "column", gap: 10 }}>