diff --git a/src/lib/components/chat/Suggestions.svelte b/src/lib/components/chat/Suggestions.svelte new file mode 100644 index 00000000..d64f4aee --- /dev/null +++ b/src/lib/components/chat/Suggestions.svelte @@ -0,0 +1,90 @@ + + +
+ + + + + + + +
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 3e91e723..b32a7196 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -15,12 +15,14 @@ import Navbar from '$lib/components/layout/Navbar.svelte'; import SettingsModal from '$lib/components/chat/SettingsModal.svelte'; + import Suggestions from '$lib/components/chat/Suggestions.svelte'; let API_BASE_URL = BUILD_TIME_API_BASE_URL; let suggestions = ''; // $page.url.searchParams.get('suggestions'); let models = []; let textareaElement; + let showSettings = false; let db; @@ -34,6 +36,9 @@ let prompt = ''; let messages = []; + let stopResponseFlag = false; + let autoScroll = true; + onMount(async () => { let settings = JSON.parse(localStorage.getItem('settings') ?? '{}'); @@ -320,12 +325,12 @@ }; const confirmEditMessage = async (messageIdx) => { - let user_prompt = messages.at(messageIdx).editedContent; + let userPrompt = messages.at(messageIdx).editedContent; messages.splice(messageIdx, messages.length - messageIdx); messages = messages; - await submitPrompt(user_prompt); + await submitPrompt(userPrompt); }; const cancelEditMessage = (messageIdx) => { @@ -390,7 +395,109 @@ return res; }; - const submitPrompt = async (user_prompt) => { + const sendPrompt = async (userPrompt) => { + let responseMessage = { + role: 'assistant', + content: '' + }; + + messages = [...messages, responseMessage]; + window.scrollTo({ top: document.body.scrollHeight }); + + const res = await fetch(`${API_BASE_URL}/generate`, { + method: 'POST', + headers: { + 'Content-Type': 'text/event-stream' + }, + body: JSON.stringify({ + model: selectedModel, + prompt: userPrompt, + system: system ?? undefined, + options: + temperature != null + ? { + temperature: temperature + } + : undefined, + context: + messages.length > 3 && messages.at(-3).context != undefined + ? messages.at(-3).context + : undefined + }) + }); + + const reader = res.body + .pipeThrough(new TextDecoderStream()) + .pipeThrough(splitStream('\n')) + .getReader(); + + while (true) { + const { value, done } = await reader.read(); + if (done || stopResponseFlag) { + if (stopResponseFlag) { + responseMessage.done = true; + messages = messages; + hljs.highlightAll(); + createCopyCodeBlockButton(); + renderLatex(); + } + + break; + } + + try { + let lines = value.split('\n'); + + for (const line of lines) { + if (line !== '') { + console.log(line); + let data = JSON.parse(line); + if (data.done == false) { + if (responseMessage.content == '' && data.response == '\n') { + continue; + } else { + responseMessage.content += data.response; + messages = messages; + } + } else { + responseMessage.done = true; + responseMessage.context = data.context; + messages = messages; + hljs.highlightAll(); + createCopyCodeBlockButton(); + renderLatex(); + } + } + } + } catch (error) { + console.log(error); + } + + if (autoScroll) { + window.scrollTo({ top: document.body.scrollHeight }); + } + + await db.put('chats', { + id: chatId, + title: title === '' ? 'New Chat' : title, + model: selectedModel, + system: system, + options: { + temperature: temperature + }, + timestamp: Date.now(), + messages: messages + }); + } + + stopResponseFlag = false; + await tick(); + if (autoScroll) { + window.scrollTo({ top: document.body.scrollHeight }); + } + }; + + const submitPrompt = async (userPrompt) => { console.log('submitPrompt'); if (selectedModel === '') { @@ -412,105 +519,26 @@ }); chats = await db.getAllFromIndex('chats', 'timestamp'); } + messages = [ ...messages, { role: 'user', - content: user_prompt + content: userPrompt } ]; - prompt = ''; + prompt = ''; textareaElement.style.height = ''; + setTimeout(() => { window.scrollTo({ top: document.body.scrollHeight, behavior: 'smooth' }); }, 50); - let responseMessage = { - role: 'assistant', - content: '' - }; - - messages = [...messages, responseMessage]; - window.scrollTo({ top: document.body.scrollHeight }); - - const res = await fetch(`${API_BASE_URL}/generate`, { - method: 'POST', - headers: { - 'Content-Type': 'text/event-stream' - }, - body: JSON.stringify({ - model: selectedModel, - prompt: user_prompt, - system: system ?? undefined, - options: - temperature != null - ? { - temperature: temperature - } - : undefined, - context: - messages.length > 3 && messages.at(-3).context != undefined - ? messages.at(-3).context - : undefined - }) - }); - - const reader = res.body - .pipeThrough(new TextDecoderStream()) - .pipeThrough(splitStream('\n')) - .getReader(); - - while (true) { - const { value, done } = await reader.read(); - if (done) break; - - try { - let lines = value.split('\n'); - - for (const line of lines) { - if (line !== '') { - console.log(line); - let data = JSON.parse(line); - if (data.done == false) { - if (responseMessage.content == '' && data.response == '\n') { - continue; - } else { - responseMessage.content += data.response; - messages = messages; - } - } else { - responseMessage.done = true; - responseMessage.context = data.context; - messages = messages; - hljs.highlightAll(); - createCopyCodeBlockButton(); - renderLatex(); - } - } - } - } catch (error) { - console.log(error); - } - window.scrollTo({ top: document.body.scrollHeight }); - - await db.put('chats', { - id: chatId, - title: title === '' ? 'New Chat' : title, - model: selectedModel, - system: system, - options: { - temperature: temperature - }, - timestamp: Date.now(), - messages: messages - }); - } - - window.scrollTo({ top: document.body.scrollHeight }); + await sendPrompt(userPrompt); if (messages.length == 2) { - await generateTitle(chatId, user_prompt); + await generateTitle(chatId, userPrompt); } chats = await db.getAllFromIndex('chats', 'timestamp'); } @@ -518,101 +546,23 @@ const regenerateResponse = async () => { console.log('regenerateResponse'); - if (messages.length != 0 && messages.at(-1).done == true) { messages.splice(messages.length - 1, 1); messages = messages; - let lastUserMessage = messages.at(-1); - - let responseMessage = { - role: 'assistant', - content: '' - }; - - messages = [...messages, responseMessage]; - window.scrollTo({ top: document.body.scrollHeight }); - - const res = await fetch(`${API_BASE_URL}/generate`, { - method: 'POST', - headers: { - 'Content-Type': 'text/event-stream' - }, - body: JSON.stringify({ - model: selectedModel, - prompt: lastUserMessage.content, - system: system ?? undefined, - options: - temperature != null - ? { - temperature: temperature - } - : undefined, - context: - messages.length > 3 && messages.at(-3).context != undefined - ? messages.at(-3).context - : undefined - }) - }); - - const reader = res.body - .pipeThrough(new TextDecoderStream()) - .pipeThrough(splitStream('\n')) - .getReader(); - - while (true) { - const { value, done } = await reader.read(); - if (done) break; - - try { - let lines = value.split('\n'); - - for (const line of lines) { - if (line !== '') { - console.log(line); - let data = JSON.parse(line); - if (data.done == false) { - if (responseMessage.content == '' && data.response == '\n') { - continue; - } else { - responseMessage.content += data.response; - messages = messages; - } - } else { - responseMessage.done = true; - responseMessage.context = data.context; - messages = messages; - hljs.highlightAll(); - createCopyCodeBlockButton(); - renderLatex(); - } - } - } - } catch (error) { - console.log(error); - } - window.scrollTo({ top: document.body.scrollHeight }); - } - - window.scrollTo({ top: document.body.scrollHeight }); - await db.put('chats', { - id: chatId, - title: title === '' ? 'New Chat' : title, - model: selectedModel, - system: system, - options: { - temperature: temperature - }, - timestamp: Date.now(), - messages: messages - }); + let userMessage = messages.at(-1); + let userPrompt = userMessage.content; + await sendPrompt(userPrompt); chats = await db.getAllFromIndex('chats', 'timestamp'); } - - console.log(messages); }; - const generateTitle = async (_chatId, user_prompt) => { + const stopResponse = () => { + stopResponseFlag = true; + console.log('stopResponse'); + }; + + const generateTitle = async (_chatId, userPrompt) => { console.log('generateTitle'); const res = await fetch(`${API_BASE_URL}/generate`, { @@ -622,7 +572,7 @@ }, body: JSON.stringify({ model: selectedModel, - prompt: `Generate a brief 3-5 word title for this question, excluding the term 'title.' Then, please reply with only the title: ${user_prompt}`, + prompt: `Generate a brief 3-5 word title for this question, excluding the term 'title.' Then, please reply with only the title: ${userPrompt}`, stream: false }) }) @@ -646,6 +596,12 @@ }; + { + autoScroll = window.innerHeight + window.scrollY >= document.body.offsetHeight - 30; + }} +/> +
{#if messages.length == 0 && suggestions !== 'false'} -
- - - - - - - -
+ {/if} - {#if messages.length != 0 && messages.at(-1).role == 'assistant' && messages.at(-1).done == true} -
- -
+ {#if messages.length != 0 && messages.at(-1).role == 'assistant'} + {#if messages.at(-1).done == true} +
+ +
+ {:else} +
+ +
+ {/if} {/if}