//var stmd = require('stmd'); const messagesContainer = document.getElementById('messages'); const systemInput = document.getElementById('systemMessage'); const messageInput = document.getElementById('messageInput'); var parser = new stmd.DocParser(); var renderer = new stmd.HtmlRenderer(); var cur_idx = 0; const questions = []; const answers = []; var selected_msg = []; messageInput.addEventListener('keydown', (event) => { if (event.key === "Enter" && (event.metaKey || event.ctrlKey)) { sendMessage(); } else if (event.key === "Escape" && (event.metaKey || event.ctrlKey)) { sendAbort(); } }); function messageListener(elem, idx, type) { return () => { elem.classList.toggle('selected'); const e = { id: idx, type: type }; const i = selected_msg.indexOf(e); if (i === -1) selected_msg.push(e); else selected_msg.splice(i, 1); } } async function sendAbort() { fetch('/rkllm_abort', { method: 'POST', body: true }).catch(error => alert(error)) } function _try_highlightAll() { try { hljs.highlightAll(); } catch { /*e*/ } } async function sendMessage() { const messageText = messageInput.value.trim(); if (!messageText) return; messageHTML = renderer.render(parser.parse(`**You:**\n\n${messageText}`)) mess = document.createElement('div'); mess.classList.add('message', 'clearfix'); mess.style.float = "right" mess.innerHTML = messageHTML mess.addEventListener('click', messageListener(mess, cur_idx, 'q')); questions.push(messageText); messagesContainer.appendChild(mess); Array.from(mess.getElementsByTagName('code')).forEach(e => hljs.highlightElement(e)); messageInput.value = ''; messagesContainer.scrollTop = messagesContainer.scrollHeight; // Auto-scroll to bottom const messagesToSend = selected_msg.sort((a,b) => { const sub = a.id-b.id; if (sub === 0) return b.type === 'q' ? 1 : -1; return sub; }).map(m => { const q = m.type === 'q'; return { role: q ? 'user' : 'assistant', content: (q ? questions : answers)[m.id] }}); messagesToSend.push({role:'user', content: messageText}) const sysText = systemInput.value.trim(); const withSysMsg = (sysText ? [{role: 'system', 'content': sysText}] : []).concat(messagesToSend); const response = await fetch('/rkllm_chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ model: "some model", messages: withSysMsg, stream: true }), }); if (!response.ok) { throw new Error('Failed to connect to chat server'); } const reader = response.body.getReader(); let decoder = new TextDecoder('utf-8'); //const name = (Math.random() + 1).toString(36).substring(7); const message = document.createElement('div'); message.classList.add('message', 'clearfix'); message.style.float = 'left'; messagesContainer.appendChild(message); let chunks = ''; function double_try() { function display(n) { const ccs = chunks.split(/\n/).filter(e => e !== ""); const json = JSON.parse(ccs[ccs.length - n]); const text = `${json.choices.map((c) => c.delta.content).join('')}`; while (cur_idx >= answers.length) answers.push(""); answers[cur_idx] = text; message.innerHTML = renderer.render(parser.parse(`**RKLLM**:\n\n${text}`)); Array.from(message.getElementsByTagName('code')).forEach(e => hljs.highlightElement(e)); } const at_bottom = Math.abs(messagesContainer.scrollHeight - messagesContainer.clientHeight - messagesContainer.scrollTop) <= 1;; console.log(messagesContainer.scrollHeight, messagesContainer.scrollTop, messagesContainer.clientHeight); try { display(1); } catch { try { display(2); } catch (e) { console.error(e, chunks); } } finally { if (at_bottom) messagesContainer.scrollTop = messagesContainer.scrollHeight; } } while (true) { const { done, value } = await reader.read(); if (done) break; const chunk = decoder.decode(value, { stream: true }); chunks += chunk.replace('\r', ''); double_try(); } double_try(); message.addEventListener('click', messageListener(message, cur_idx++, 'a')); }