Learning loop + smart search on datalake page

Learning Loop:
- /intelligence/learn endpoint logs search→selection as playbook entry
- /intelligence/activity returns learning stats, patterns, and recent activity
- Call/SMS buttons trigger logSelection() — records what query led to what pick
- "System Learning" card on main page shows searches logged, patterns detected,
  and recent activity feed with timestamps
- Every search-selection pair becomes institutional knowledge stored in the lakehouse

Smart Search on Main Page:
- doSearch() now routes through /intelligence/chat (smart NL parser)
- Extracts role, city, state, availability, reliability from natural language
- Shows understanding tags so staffer sees what the system parsed
- Returns workers with ZIP codes, availability %, reliability %, archetype
- "reliable forklift operator available in Nashville" → 10 Nashville forklift
  operators with ZIP codes, all 86-98% reliable, all available — 372ms

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-04-17 19:59:07 -05:00
co-authored by Claude Opus 4.6
parent df71ac7156
commit bba5b826a3
2 changed files with 156 additions and 13 deletions
+35
View File
@@ -1034,6 +1034,41 @@ tr:hover{background:#111827}
return new Response(Bun.file(import.meta.dir + "/console.html"));
}
// Intelligence: Log a search → selection as a learned pattern
if (url.pathname === "/intelligence/learn" && req.method === "POST") {
const b = await json();
const csv = `timestamp,operation,approach,result,context\n"${new Date().toISOString()}","search: ${(b.query||"").replace(/"/g,'""')}","${(b.filters||"").replace(/"/g,'""')}","selected: ${(b.worker_name||"").replace(/"/g,'""')} (${b.worker_id||""})","role=${b.worker_role||""} state=${b.worker_state||""} city=${b.worker_city||""}"`;
const form = new FormData();
form.append("file", new Blob([csv], { type: "text/csv" }), "playbook.csv");
await fetch(`${BASE}/ingest/file?name=successful_playbooks`, { method: "POST", body: form });
return ok({ learned: true, pattern: `"${b.query}" → ${b.worker_name}` });
}
// Intelligence: Activity feed — what the system has learned
if (url.pathname === "/intelligence/activity" && req.method === "POST") {
const start = Date.now();
const [playbooksR, searchCountR, simCountR] = await Promise.all([
api("POST", "/query/sql", { sql: "SELECT * FROM successful_playbooks ORDER BY timestamp DESC LIMIT 20" }).catch(() => ({ rows: [] })),
api("POST", "/query/sql", { sql: "SELECT COUNT(*) cnt FROM successful_playbooks WHERE operation LIKE 'search:%'" }).catch(() => ({ rows: [{ cnt: 0 }] })),
api("POST", "/query/sql", { sql: "SELECT COUNT(*) cnt FROM successful_playbooks WHERE operation LIKE 'week_simulation%'" }).catch(() => ({ rows: [{ cnt: 0 }] })),
]);
// Extract learned patterns — which workers get picked for which queries
const patterns: Record<string, number> = {};
for (const p of (playbooksR.rows || [])) {
if (p.operation?.startsWith("search:")) {
const key = p.operation.replace("search: ", "").trim();
patterns[key] = (patterns[key] || 0) + 1;
}
}
return ok({
playbooks: playbooksR.rows || [],
search_count: searchCountR.rows?.[0]?.cnt || 0,
sim_count: simCountR.rows?.[0]?.cnt || 0,
learned_patterns: Object.entries(patterns).map(([q, c]) => ({ query: q, times: c })).sort((a, b) => b.times - a.times),
duration_ms: Date.now() - start,
});
}
// Intelligence Brief — parallel analytics across 500K profiles
if (url.pathname === "/intelligence/brief" && req.method === "POST") {
const start = Date.now();