mirror of
https://github.com/perstarkse/minne.git
synced 2026-06-12 17:24:26 +02:00
7b850769c9
Avoid nested forms in the scratchpad editor, centralize modal lifecycle in modal.js, return HTMX partials from archive, and add template compile plus layout snapshots.
55 lines
2.4 KiB
HTML
55 lines
2.4 KiB
HTML
<div class="chat chat-end">
|
|
<div class="chat-bubble markdown-content" data-content="{{ user_message.content|escape }}">
|
|
{{ user_message.content|escape }}
|
|
</div>
|
|
</div>
|
|
<div class="chat chat-start">
|
|
<div id="ai-stream-{{user_message.id}}" data-message-id="{{user_message.id}}" hx-ext="sse"
|
|
sse-connect="/chat/response-stream?message_id={{user_message.id}}" sse-close="close_stream"
|
|
hx-swap="beforeend">
|
|
<div class="chat-bubble">
|
|
<span class="loading loading-dots loading-sm" data-stream-spinner></span>
|
|
<div class="markdown-content" id="ai-message-content-{{user_message.id}}" sse-swap="chat_message"></div>
|
|
</div>
|
|
<div sse-swap="references"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Single delegated listener set; message identity comes from data-message-id.
|
|
(function () {
|
|
if (window.__streamHandlersInit) return;
|
|
window.__streamHandlersInit = true;
|
|
window.markdownBuffer = window.markdownBuffer || {};
|
|
|
|
document.body.addEventListener('htmx:sseBeforeMessage', function (e) {
|
|
const root = e.detail.elt.closest('[data-message-id]');
|
|
if (!root) return;
|
|
const msgId = root.dataset.messageId;
|
|
const spinner = root.querySelector('[data-stream-spinner]');
|
|
if (spinner) spinner.style.display = 'none';
|
|
const el = document.getElementById('ai-message-content-' + msgId);
|
|
if (e.detail.elt !== el) return;
|
|
e.preventDefault();
|
|
window.markdownBuffer[msgId] = (window.markdownBuffer[msgId] || '') + (e.detail.data || '');
|
|
el.innerHTML = marked.parse(window.markdownBuffer[msgId].replace(/\\n/g, '\n'));
|
|
if (typeof window.scrollChatToBottom === "function") window.scrollChatToBottom();
|
|
});
|
|
|
|
document.body.addEventListener('htmx:sseClose', function (e) {
|
|
const streamEl = e.target.closest('[data-message-id]');
|
|
if (!streamEl) return;
|
|
const msgId = streamEl.dataset.messageId;
|
|
const el = document.getElementById('ai-message-content-' + msgId);
|
|
if (el && window.markdownBuffer[msgId]) {
|
|
el.innerHTML = marked.parse(window.markdownBuffer[msgId].replace(/\\n/g, '\n'));
|
|
delete window.markdownBuffer[msgId];
|
|
if (typeof window.scrollChatToBottom === "function") window.scrollChatToBottom();
|
|
}
|
|
streamEl.removeAttribute('sse-connect');
|
|
streamEl.removeAttribute('sse-close');
|
|
streamEl.removeAttribute('hx-ext');
|
|
});
|
|
})();
|
|
</script>
|