update frontend
This commit is contained in:
+41
-8
@@ -1,5 +1,14 @@
|
||||
const API = '';
|
||||
let currentSession = null;
|
||||
let sendTime = 0;
|
||||
|
||||
// Configure marked
|
||||
marked.setOptions({
|
||||
breaks: true,
|
||||
gfm: true,
|
||||
headerIds: false,
|
||||
mangle: false,
|
||||
});
|
||||
|
||||
// DOM
|
||||
const sessionList = document.getElementById('session-list');
|
||||
@@ -97,14 +106,17 @@ async function sendMessage() {
|
||||
scrollToBottom();
|
||||
btnSend.disabled = true;
|
||||
|
||||
sendTime = performance.now();
|
||||
|
||||
try {
|
||||
const data = await api(`/api/sessions/${currentSession.id}/messages`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ content: text }),
|
||||
});
|
||||
|
||||
const elapsed = ((performance.now() - sendTime) / 1000).toFixed(1);
|
||||
typingEl.remove();
|
||||
appendMessage('assistant', data.content, data.sources);
|
||||
appendMessage('assistant', data.content, data.sources, elapsed);
|
||||
scrollToBottom();
|
||||
loadSessions();
|
||||
} catch (e) {
|
||||
@@ -117,7 +129,15 @@ async function sendMessage() {
|
||||
}
|
||||
}
|
||||
|
||||
function appendMessage(role, content, sources = null) {
|
||||
function renderMarkdown(text) {
|
||||
try {
|
||||
return marked.parse(text || '');
|
||||
} catch {
|
||||
return esc(text);
|
||||
}
|
||||
}
|
||||
|
||||
function appendMessage(role, content, sources = null, elapsed = null) {
|
||||
// Remove empty state if present
|
||||
const empty = messages.querySelector('.empty-state');
|
||||
if (empty) empty.remove();
|
||||
@@ -125,14 +145,27 @@ function appendMessage(role, content, sources = null) {
|
||||
const div = document.createElement('div');
|
||||
div.className = `message ${role}`;
|
||||
|
||||
let html = `<div class="bubble">${esc(content)}</div>`;
|
||||
let html = '';
|
||||
|
||||
if (role === 'assistant') {
|
||||
html += `<div class="bubble">${renderMarkdown(content)}</div>`;
|
||||
} else {
|
||||
html += `<div class="bubble">${esc(content)}</div>`;
|
||||
}
|
||||
|
||||
// Sources + timing
|
||||
const metaParts = [];
|
||||
if (sources && sources.length > 0) {
|
||||
html += `<div class="sources">`;
|
||||
sources.forEach(s => {
|
||||
html += `<a class="source-chip" href="${esc(s.url)}" target="_blank" title="${esc(s.title)}">${esc(s.title.substring(0, 40))}</a>`;
|
||||
});
|
||||
html += `</div>`;
|
||||
const chips = sources.map(s =>
|
||||
`<a class="source-chip" href="${esc(s.url)}" target="_blank" title="${esc(s.title)}">${esc(s.title.substring(0, 40))}</a>`
|
||||
).join('');
|
||||
metaParts.push(`<div class="sources">${chips}</div>`);
|
||||
}
|
||||
if (elapsed !== null && role === 'assistant') {
|
||||
metaParts.push(`<div class="msg-meta"><span class="timing">⚡ ${elapsed}s</span></div>`);
|
||||
}
|
||||
if (metaParts.length) {
|
||||
html += metaParts.join('');
|
||||
}
|
||||
|
||||
div.innerHTML = html;
|
||||
|
||||
Reference in New Issue
Block a user