Fix dashboard: always use hybrid (no HNSW dependency), 15s timeout, error display
The search hung because pure AI mode calls HNSW which is RAM-only — gone after every lakehouse restart. Now ALL AI/hybrid searches go through the /search endpoint which uses brute-force when HNSW isn't loaded. Added 15s AbortController timeout so fetch never hangs. Added window.onerror handler to show JS errors on page. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5c93338f40
commit
e7e988dcc0
@ -104,6 +104,11 @@ body{font-family:'Inter','SF Pro',system-ui,sans-serif;background:#0a0a0f;color:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
window.onerror = function(msg, url, line) {
|
||||||
|
document.body.insertAdjacentHTML('afterbegin',
|
||||||
|
'<div style="background:#7f1d1d;color:#fca5a5;padding:12px;font-size:12px">JS Error: ' + msg + ' (line ' + line + ')</div>');
|
||||||
|
};
|
||||||
|
|
||||||
const base = window.location.pathname.replace(/\/+$/, '');
|
const base = window.location.pathname.replace(/\/+$/, '');
|
||||||
const GW = window.location.origin + base;
|
const GW = window.location.origin + base;
|
||||||
let mode = 'ai';
|
let mode = 'ai';
|
||||||
@ -139,9 +144,10 @@ async function doSearch() {
|
|||||||
|
|
||||||
const t0 = Date.now();
|
const t0 = Date.now();
|
||||||
|
|
||||||
// If ANY filter is set, always use hybrid — filters only work through SQL
|
// ALWAYS use hybrid for AI modes — it handles filters AND works even
|
||||||
const hasFilters = state || role || rel > 0.5;
|
// when HNSW isn't loaded (falls back to brute-force). Pure HNSW mode
|
||||||
const effectiveMode = (mode === 'crm') ? 'crm' : (hasFilters ? 'hybrid' : mode);
|
// hangs when the RAM index isn't built.
|
||||||
|
const effectiveMode = (mode === 'crm') ? 'crm' : 'hybrid';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let data;
|
let data;
|
||||||
@ -159,33 +165,29 @@ async function doSearch() {
|
|||||||
data = await r.json();
|
data = await r.json();
|
||||||
renderCRMResults(data, query, Date.now() - t0);
|
renderCRMResults(data, query, Date.now() - t0);
|
||||||
|
|
||||||
} else if (effectiveMode === 'ai') {
|
|
||||||
// Pure AI vector search — no filters, just meaning
|
|
||||||
const r = await fetch(GW + '/api/vectors/hnsw/search', {
|
|
||||||
method: 'POST', headers: {'Content-Type': 'application/json'},
|
|
||||||
body: JSON.stringify({index_name: 'workers_500k_v1', query: query, top_k: 10})
|
|
||||||
});
|
|
||||||
data = await r.json();
|
|
||||||
renderAIResults(data, query, Date.now() - t0);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Hybrid — SQL filters enforce structure, AI ranks by relevance
|
// Hybrid — SQL filters enforce structure, AI ranks by relevance
|
||||||
|
// Always works — uses brute-force when HNSW isn't loaded
|
||||||
let filter = "CAST(reliability AS DOUBLE) >= " + rel;
|
let filter = "CAST(reliability AS DOUBLE) >= " + rel;
|
||||||
if (state) filter += " AND state = '" + state + "'";
|
if (state) filter += " AND state = '" + state + "'";
|
||||||
if (role) filter += " AND role = '" + role + "'";
|
if (role) filter += " AND role = '" + role + "'";
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeout = setTimeout(function() { controller.abort(); }, 15000);
|
||||||
const r = await fetch(GW + '/search', {
|
const r = await fetch(GW + '/search', {
|
||||||
method: 'POST', headers: {'Content-Type': 'application/json'},
|
method: 'POST', headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
question: query, index_name: 'workers_500k_v1',
|
question: query, index_name: 'workers_500k_v1',
|
||||||
sql_filter: filter, dataset: 'workers_500k',
|
sql_filter: filter, dataset: 'workers_500k',
|
||||||
id_column: 'worker_id', top_k: 10, generate: false
|
id_column: 'worker_id', top_k: 10, generate: false
|
||||||
})
|
}),
|
||||||
|
signal: controller.signal
|
||||||
});
|
});
|
||||||
|
clearTimeout(timeout);
|
||||||
data = await r.json();
|
data = await r.json();
|
||||||
renderHybridResults(data, query, Date.now() - t0);
|
renderHybridResults(data, query, Date.now() - t0);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
document.getElementById('results').innerHTML = '<div class="empty">Error: ' + e.message + '</div>';
|
document.getElementById('results').innerHTML = '<div class="empty">Search error: ' + e.message + '<br><br>If filters were set, try Hybrid mode. If the search is slow, the AI index may be loading — try again in 10 seconds.</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user