v1.8.0: bge-m3 embeddings, qwen3 LLM, retrieval fixes, input validation, memory poisoning fix
This commit is contained in:
+82
-10
@@ -224,8 +224,25 @@ header { animation:slideDown 350ms var(--ease-out) both; }
|
||||
}
|
||||
.reveal { opacity:1; transform:none; }
|
||||
}
|
||||
|
||||
/* Sticky footer — no layout impact */
|
||||
#sticky-footer { position: sticky; top: 100vh; }
|
||||
|
||||
.stream-cursor {
|
||||
display: inline-block;
|
||||
width: 2px;
|
||||
background: var(--color-primary, #4eded3);
|
||||
margin-right: 1px;
|
||||
border-radius: 1px;
|
||||
animation: blink 0.75s step-end infinite;
|
||||
vertical-align: text-bottom;
|
||||
height: 1.1em;
|
||||
}
|
||||
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0} }
|
||||
</style>
|
||||
<script src="/static/analytics.js" defer></script>
|
||||
<link rel="privacy-policy" href="https://rag.afaqzaid.com/privacy"/>
|
||||
<meta name="description" content="AfakZaid RAG — AI-powered scholarly research platform. Search and query Arabic books and documents."/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -462,19 +479,65 @@ async function doQuery() {
|
||||
const box = document.getElementById('answer-box');
|
||||
const meta = document.getElementById('answer-meta');
|
||||
wrap.classList.remove('hidden');
|
||||
box.textContent = '...'; meta.innerHTML = '';
|
||||
box.textContent = ''; meta.innerHTML = '';
|
||||
|
||||
// Blinking cursor while streaming
|
||||
let cursor = document.createElement('span');
|
||||
cursor.className = 'stream-cursor';
|
||||
cursor.textContent = '|';
|
||||
box.appendChild(cursor);
|
||||
|
||||
try {
|
||||
const headers = {'Content-Type':'application/json','X-API-Key':API_KEY};
|
||||
if(userToken) headers['Authorization'] = 'Bearer '+userToken;
|
||||
const r = await fetch('/query',{method:'POST',headers,body:JSON.stringify({query:q,session_id:'web-'+(currentUser?.id||'guest')})});
|
||||
const d = await r.json();
|
||||
box.textContent = d.answer;
|
||||
meta.innerHTML = [
|
||||
`<span class="glass px-3 py-1 rounded-full text-xs text-primary font-bold">${d.llm}</span>`,
|
||||
`<span class="glass px-3 py-1 rounded-full text-xs text-secondary">${((d.confidence||0)*100).toFixed(0)}% ثقة</span>`,
|
||||
...(d.books_used||[]).map(b=>`<span class="glass px-3 py-1 rounded-full text-xs text-on-surface-variant">${b}</span>`)
|
||||
].join('');
|
||||
} catch(e){ box.textContent='خطأ: '+e.message; }
|
||||
|
||||
const r = await fetch('/query/stream', {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: JSON.stringify({query:q, session_id:'web-'+(currentUser?.id||'guest')})
|
||||
});
|
||||
|
||||
if (!r.ok) throw new Error(`HTTP ${r.status}`);
|
||||
|
||||
const reader = r.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buf = '';
|
||||
|
||||
while (true) {
|
||||
const {done, value} = await reader.read();
|
||||
if (done) break;
|
||||
buf += decoder.decode(value, {stream: true});
|
||||
|
||||
// Process complete SSE lines
|
||||
const lines = buf.split('\n');
|
||||
buf = lines.pop(); // keep incomplete last line
|
||||
|
||||
for (const line of lines) {
|
||||
if (!line.startsWith('data: ')) continue;
|
||||
const raw = line.slice(6).trim();
|
||||
if (raw === '[DONE]') break;
|
||||
|
||||
try {
|
||||
const frame = JSON.parse(raw);
|
||||
if (frame.t === 'token') {
|
||||
// Insert token before cursor
|
||||
cursor.before(document.createTextNode(frame.v));
|
||||
box.scrollTop = box.scrollHeight;
|
||||
} else if (frame.t === 'meta') {
|
||||
const m = frame.v;
|
||||
meta.innerHTML = [
|
||||
`<span class="glass px-3 py-1 rounded-full text-xs text-primary font-bold">${m.llm||''}</span>`,
|
||||
`<span class="glass px-3 py-1 rounded-full text-xs text-secondary">${((m.confidence||0)*100).toFixed(0)}% ثقة</span>`,
|
||||
...(m.books_used||[]).map(b=>`<span class="glass px-3 py-1 rounded-full text-xs text-on-surface-variant">${b}</span>`)
|
||||
].join('');
|
||||
}
|
||||
} catch(_) {}
|
||||
}
|
||||
}
|
||||
} catch(e) { box.textContent = 'خطأ: ' + e.message; }
|
||||
|
||||
// Remove cursor
|
||||
cursor.remove();
|
||||
btn.disabled = false;
|
||||
btn.style.animation = '';
|
||||
btn.innerHTML = '<span class="msym text-lg">search</span> بحث';
|
||||
@@ -544,5 +607,14 @@ loadStats();
|
||||
loadBooks();
|
||||
setInterval(loadStats, 30000);
|
||||
</script>
|
||||
|
||||
<footer id="sticky-footer" style="text-align:center;padding:20px;margin-top:16px;font-size:12px;color:#888;border-top:1px solid rgba(255,255,255,0.06)">
|
||||
<a href="https://rag.afaqzaid.com/privacy" rel="privacy-policy" style="color:#888;text-decoration:none;margin:0 8px">سياسة الخصوصية</a>
|
||||
•
|
||||
<a href="https://rag.afaqzaid.com/terms" style="color:#888;text-decoration:none;margin:0 8px">شروط الخدمة</a>
|
||||
•
|
||||
<span style="margin:0 8px">© 2026 أفاق زيد</span>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user