forked from open-webui/open-webui
Merge pull request #186 from ollama-webui/dev
feat: `/chat` route support
This commit is contained in:
commit
a7bec01d7b
4 changed files with 377 additions and 303 deletions
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
## Connection Errors
|
## Connection Errors
|
||||||
|
|
||||||
|
Make sure you have the **latest version of Ollama** installed before proceeding with the installation. You can find the latest version of Ollama at [https://ollama.ai/](https://ollama.ai/).
|
||||||
|
|
||||||
If you encounter difficulties connecting to the Ollama server, please follow these steps to diagnose and resolve the issue:
|
If you encounter difficulties connecting to the Ollama server, please follow these steps to diagnose and resolve the issue:
|
||||||
|
|
||||||
**1. Verify Ollama Server Configuration**
|
**1. Verify Ollama Server Configuration**
|
||||||
|
@ -43,5 +45,6 @@ docker run --platform linux/amd64 -d -p 3000:8080 -e OLLAMA_API_BASE_URL=http://
|
||||||
```
|
```
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
[Change Docker Desktop Settings on Mac](https://docs.docker.com/desktop/settings/mac/) Search for "x86" in that page.
|
[Change Docker Desktop Settings on Mac](https://docs.docker.com/desktop/settings/mac/) Search for "x86" in that page.
|
||||||
[Run x86 (Intel) and ARM based images on Apple Silicon (M1) Macs?](https://forums.docker.com/t/run-x86-intel-and-arm-based-images-on-apple-silicon-m1-macs/117123)
|
[Run x86 (Intel) and ARM based images on Apple Silicon (M1) Macs?](https://forums.docker.com/t/run-x86-intel-and-arm-based-images-on-apple-silicon-m1-macs/117123)
|
||||||
|
|
|
@ -162,7 +162,15 @@
|
||||||
const editMessageHandler = async (messageId) => {
|
const editMessageHandler = async (messageId) => {
|
||||||
// let editMessage = history.messages[messageId];
|
// let editMessage = history.messages[messageId];
|
||||||
history.messages[messageId].edit = true;
|
history.messages[messageId].edit = true;
|
||||||
|
history.messages[messageId].originalContent = history.messages[messageId].content;
|
||||||
history.messages[messageId].editedContent = history.messages[messageId].content;
|
history.messages[messageId].editedContent = history.messages[messageId].content;
|
||||||
|
|
||||||
|
await tick();
|
||||||
|
|
||||||
|
const editElement = document.getElementById(`message-edit-${messageId}`);
|
||||||
|
|
||||||
|
editElement.style.height = '';
|
||||||
|
editElement.style.height = `${editElement.scrollHeight}px`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const confirmEditMessage = async (messageId) => {
|
const confirmEditMessage = async (messageId) => {
|
||||||
|
@ -195,6 +203,11 @@
|
||||||
await sendPrompt(userPrompt, userMessageId, $chatId);
|
await sendPrompt(userPrompt, userMessageId, $chatId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const confirmEditResponseMessage = async (messageId) => {
|
||||||
|
history.messages[messageId].edit = false;
|
||||||
|
history.messages[messageId].content = history.messages[messageId].editedContent;
|
||||||
|
};
|
||||||
|
|
||||||
const cancelEditMessage = (messageId) => {
|
const cancelEditMessage = (messageId) => {
|
||||||
history.messages[messageId].edit = false;
|
history.messages[messageId].edit = false;
|
||||||
history.messages[messageId].editedContent = undefined;
|
history.messages[messageId].editedContent = undefined;
|
||||||
|
@ -415,19 +428,15 @@
|
||||||
{#if message?.edit === true}
|
{#if message?.edit === true}
|
||||||
<div class=" w-full">
|
<div class=" w-full">
|
||||||
<textarea
|
<textarea
|
||||||
|
id="message-edit-{message.id}"
|
||||||
class=" bg-transparent outline-none w-full resize-none"
|
class=" bg-transparent outline-none w-full resize-none"
|
||||||
bind:value={history.messages[message.id].editedContent}
|
bind:value={history.messages[message.id].editedContent}
|
||||||
on:input={(e) => {
|
on:input={(e) => {
|
||||||
e.target.style.height = '';
|
|
||||||
e.target.style.height = `${e.target.scrollHeight}px`;
|
|
||||||
}}
|
|
||||||
on:focus={(e) => {
|
|
||||||
e.target.style.height = '';
|
|
||||||
e.target.style.height = `${e.target.scrollHeight}px`;
|
e.target.style.height = `${e.target.scrollHeight}px`;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class=" mt-2 flex justify-center space-x-2 text-sm font-medium">
|
<div class=" mt-2 mb-1 flex justify-center space-x-2 text-sm font-medium">
|
||||||
<button
|
<button
|
||||||
class="px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded-lg"
|
class="px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded-lg"
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
|
@ -609,199 +618,239 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{/if}
|
||||||
<div class="w-full">
|
|
||||||
{@html marked(message.content.replace('\\\\', '\\\\\\'))}
|
|
||||||
|
|
||||||
{#if message.done}
|
{#if message.role === 'assistant'}
|
||||||
<div class=" flex justify-start space-x-1 -mt-2">
|
<div>
|
||||||
{#if message.parentId !== null && message.parentId in history.messages && (history.messages[message.parentId]?.childrenIds.length ?? 0) > 1}
|
{#if message?.edit === true}
|
||||||
<div class="flex self-center">
|
<div class=" w-full">
|
||||||
<button
|
<textarea
|
||||||
class="self-center"
|
id="message-edit-{message.id}"
|
||||||
on:click={() => {
|
class=" bg-transparent outline-none w-full resize-none"
|
||||||
showPreviousMessage(message);
|
bind:value={history.messages[message.id].editedContent}
|
||||||
}}
|
on:input={(e) => {
|
||||||
>
|
e.target.style.height = `${e.target.scrollHeight}px`;
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="text-xs font-bold self-center">
|
|
||||||
{history.messages[message.parentId].childrenIds.indexOf(message.id) +
|
|
||||||
1} / {history.messages[message.parentId].childrenIds.length}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="self-center"
|
|
||||||
on:click={() => {
|
|
||||||
showNextMessage(message);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<!-- <button
|
|
||||||
class="invisible group-hover:visible p-1 rounded dark:hover:bg-gray-800 transition"
|
|
||||||
on:click={() => {
|
|
||||||
editMessageHandler(message.id);
|
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button> -->
|
|
||||||
|
|
||||||
<button
|
<div class=" mt-2 mb-1 flex justify-center space-x-2 text-sm font-medium">
|
||||||
class="{messageIdx + 1 === messages.length
|
|
||||||
? 'visible'
|
|
||||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
|
||||||
on:click={() => {
|
|
||||||
copyToClipboard(message.content);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="{messageIdx + 1 === messages.length
|
|
||||||
? 'visible'
|
|
||||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
|
||||||
on:click={() => {
|
|
||||||
rateMessage(messageIdx, 1);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
stroke="currentColor"
|
|
||||||
fill="none"
|
|
||||||
stroke-width="2"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
class="w-4 h-4"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
><path
|
|
||||||
d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="{messageIdx + 1 === messages.length
|
|
||||||
? 'visible'
|
|
||||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
|
||||||
on:click={() => {
|
|
||||||
rateMessage(messageIdx, -1);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
stroke="currentColor"
|
|
||||||
fill="none"
|
|
||||||
stroke-width="2"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
class="w-4 h-4"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
><path
|
|
||||||
d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"
|
|
||||||
/></svg
|
|
||||||
>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="{messageIdx + 1 === messages.length
|
|
||||||
? 'visible'
|
|
||||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
|
||||||
on:click={() => {
|
|
||||||
speakMessage(message.content);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M19.114 5.636a9 9 0 010 12.728M16.463 8.288a5.25 5.25 0 010 7.424M6.75 8.25l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 012.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{#if messageIdx + 1 === messages.length}
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
class="px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded-lg"
|
||||||
class="{messageIdx + 1 === messages.length
|
on:click={() => {
|
||||||
? 'visible'
|
confirmEditResponseMessage(message.id);
|
||||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
}}
|
||||||
on:click={regenerateResponse}
|
|
||||||
>
|
>
|
||||||
<svg
|
Save
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
</button>
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
<button
|
||||||
stroke-width="1.5"
|
class=" px-4 py-2 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-100 transition outline outline-1 outline-gray-200 dark:outline-gray-600 rounded-lg"
|
||||||
stroke="currentColor"
|
on:click={() => {
|
||||||
class="w-4 h-4"
|
cancelEditMessage(message.id);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<div class="w-full">
|
||||||
|
{@html marked(message.content.replace('\\\\', '\\\\\\'))}
|
||||||
|
|
||||||
|
{#if message.done}
|
||||||
|
<div class=" flex justify-start space-x-1 -mt-2">
|
||||||
|
{#if message.parentId !== null && message.parentId in history.messages && (history.messages[message.parentId]?.childrenIds.length ?? 0) > 1}
|
||||||
|
<div class="flex self-center">
|
||||||
|
<button
|
||||||
|
class="self-center"
|
||||||
|
on:click={() => {
|
||||||
|
showPreviousMessage(message);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div class="text-xs font-bold self-center">
|
||||||
|
{history.messages[message.parentId].childrenIds.indexOf(
|
||||||
|
message.id
|
||||||
|
) + 1} / {history.messages[message.parentId].childrenIds.length}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="self-center"
|
||||||
|
on:click={() => {
|
||||||
|
showNextMessage(message);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="{messageIdx + 1 === messages.length
|
||||||
|
? 'visible'
|
||||||
|
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
||||||
|
on:click={() => {
|
||||||
|
editMessageHandler(message.id);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<path
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="{messageIdx + 1 === messages.length
|
||||||
|
? 'visible'
|
||||||
|
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
||||||
|
on:click={() => {
|
||||||
|
copyToClipboard(message.content);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="{messageIdx + 1 === messages.length
|
||||||
|
? 'visible'
|
||||||
|
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
||||||
|
on:click={() => {
|
||||||
|
rateMessage(messageIdx, 1);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
|
class="w-4 h-4"
|
||||||
/>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
</svg>
|
><path
|
||||||
</button>
|
d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="{messageIdx + 1 === messages.length
|
||||||
|
? 'visible'
|
||||||
|
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
||||||
|
on:click={() => {
|
||||||
|
rateMessage(messageIdx, -1);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="none"
|
||||||
|
stroke-width="2"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
class="w-4 h-4"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
><path
|
||||||
|
d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="{messageIdx + 1 === messages.length
|
||||||
|
? 'visible'
|
||||||
|
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
||||||
|
on:click={() => {
|
||||||
|
speakMessage(message.content);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M19.114 5.636a9 9 0 010 12.728M16.463 8.288a5.25 5.25 0 010 7.424M6.75 8.25l4.72-4.72a.75.75 0 011.28.53v15.88a.75.75 0 01-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.01 9.01 0 012.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{#if messageIdx + 1 === messages.length}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="{messageIdx + 1 === messages.length
|
||||||
|
? 'visible'
|
||||||
|
: 'invisible group-hover:visible'} p-1 rounded dark:hover:bg-gray-800 transition"
|
||||||
|
on:click={regenerateResponse}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -76,6 +76,13 @@
|
||||||
selectedModels = $page.url.searchParams.get('models')
|
selectedModels = $page.url.searchParams.get('models')
|
||||||
? $page.url.searchParams.get('models')?.split(',')
|
? $page.url.searchParams.get('models')?.split(',')
|
||||||
: $settings.models ?? [''];
|
: $settings.models ?? [''];
|
||||||
|
|
||||||
|
let _settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
|
||||||
|
console.log(_settings);
|
||||||
|
settings.set({
|
||||||
|
...$settings,
|
||||||
|
..._settings
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////
|
//////////////////////////
|
||||||
|
@ -118,38 +125,11 @@
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await tick();
|
||||||
|
|
||||||
window.scrollTo({ top: document.body.scrollHeight });
|
window.scrollTo({ top: document.body.scrollHeight });
|
||||||
|
|
||||||
const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/generate`, {
|
// const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/generate`, {
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'text/event-stream',
|
|
||||||
...($settings.authHeader && { Authorization: $settings.authHeader }),
|
|
||||||
...($user && { Authorization: `Bearer ${localStorage.token}` })
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
model: model,
|
|
||||||
prompt: userPrompt,
|
|
||||||
system: $settings.system ?? undefined,
|
|
||||||
options: {
|
|
||||||
seed: $settings.seed ?? undefined,
|
|
||||||
temperature: $settings.temperature ?? undefined,
|
|
||||||
repeat_penalty: $settings.repeat_penalty ?? undefined,
|
|
||||||
top_k: $settings.top_k ?? undefined,
|
|
||||||
top_p: $settings.top_p ?? undefined,
|
|
||||||
num_ctx: $settings.num_ctx ?? undefined,
|
|
||||||
...($settings.options ?? {})
|
|
||||||
},
|
|
||||||
format: $settings.requestFormat ?? undefined,
|
|
||||||
context:
|
|
||||||
history.messages[parentId] !== null &&
|
|
||||||
history.messages[parentId].parentId in history.messages
|
|
||||||
? history.messages[history.messages[parentId].parentId]?.context ?? undefined
|
|
||||||
: undefined
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/chat`, {
|
|
||||||
// method: 'POST',
|
// method: 'POST',
|
||||||
// headers: {
|
// headers: {
|
||||||
// 'Content-Type': 'text/event-stream',
|
// 'Content-Type': 'text/event-stream',
|
||||||
|
@ -158,17 +138,8 @@
|
||||||
// },
|
// },
|
||||||
// body: JSON.stringify({
|
// body: JSON.stringify({
|
||||||
// model: model,
|
// model: model,
|
||||||
// messages: [
|
// prompt: userPrompt,
|
||||||
// $settings.system
|
// system: $settings.system ?? undefined,
|
||||||
// ? {
|
|
||||||
// role: 'system',
|
|
||||||
// content: $settings.system
|
|
||||||
// }
|
|
||||||
// : undefined,
|
|
||||||
// ...messages
|
|
||||||
// ]
|
|
||||||
// .filter((message) => message)
|
|
||||||
// .map((message) => ({ role: message.role, content: message.content })),
|
|
||||||
// options: {
|
// options: {
|
||||||
// seed: $settings.seed ?? undefined,
|
// seed: $settings.seed ?? undefined,
|
||||||
// temperature: $settings.temperature ?? undefined,
|
// temperature: $settings.temperature ?? undefined,
|
||||||
|
@ -178,10 +149,48 @@
|
||||||
// num_ctx: $settings.num_ctx ?? undefined,
|
// num_ctx: $settings.num_ctx ?? undefined,
|
||||||
// ...($settings.options ?? {})
|
// ...($settings.options ?? {})
|
||||||
// },
|
// },
|
||||||
// format: $settings.requestFormat ?? undefined
|
// format: $settings.requestFormat ?? undefined,
|
||||||
|
// context:
|
||||||
|
// history.messages[parentId] !== null &&
|
||||||
|
// history.messages[parentId].parentId in history.messages
|
||||||
|
// ? history.messages[history.messages[parentId].parentId]?.context ?? undefined
|
||||||
|
// : undefined
|
||||||
// })
|
// })
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/chat`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/event-stream',
|
||||||
|
...($settings.authHeader && { Authorization: $settings.authHeader }),
|
||||||
|
...($user && { Authorization: `Bearer ${localStorage.token}` })
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: model,
|
||||||
|
messages: [
|
||||||
|
$settings.system
|
||||||
|
? {
|
||||||
|
role: 'system',
|
||||||
|
content: $settings.system
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
...messages
|
||||||
|
]
|
||||||
|
.filter((message) => message)
|
||||||
|
.map((message) => ({ role: message.role, content: message.content })),
|
||||||
|
options: {
|
||||||
|
seed: $settings.seed ?? undefined,
|
||||||
|
temperature: $settings.temperature ?? undefined,
|
||||||
|
repeat_penalty: $settings.repeat_penalty ?? undefined,
|
||||||
|
top_k: $settings.top_k ?? undefined,
|
||||||
|
top_p: $settings.top_p ?? undefined,
|
||||||
|
num_ctx: $settings.num_ctx ?? undefined,
|
||||||
|
...($settings.options ?? {})
|
||||||
|
},
|
||||||
|
format: $settings.requestFormat ?? undefined
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
const reader = res.body
|
const reader = res.body
|
||||||
.pipeThrough(new TextDecoderStream())
|
.pipeThrough(new TextDecoderStream())
|
||||||
.pipeThrough(splitStream('\n'))
|
.pipeThrough(splitStream('\n'))
|
||||||
|
@ -189,12 +198,9 @@
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const { value, done } = await reader.read();
|
const { value, done } = await reader.read();
|
||||||
if (done || stopResponseFlag) {
|
if (done || stopResponseFlag || _chatId !== $chatId) {
|
||||||
if (stopResponseFlag) {
|
responseMessage.done = true;
|
||||||
responseMessage.done = true;
|
messages = messages;
|
||||||
messages = messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,18 +211,28 @@
|
||||||
if (line !== '') {
|
if (line !== '') {
|
||||||
console.log(line);
|
console.log(line);
|
||||||
let data = JSON.parse(line);
|
let data = JSON.parse(line);
|
||||||
|
|
||||||
|
if ('detail' in data) {
|
||||||
|
throw data;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.done == false) {
|
if (data.done == false) {
|
||||||
if (responseMessage.content == '' && data.response == '\n') {
|
if (responseMessage.content == '' && data.message.content == '\n') {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
responseMessage.content += data.response;
|
responseMessage.content += data.message.content;
|
||||||
messages = messages;
|
messages = messages;
|
||||||
}
|
}
|
||||||
} else if ('detail' in data) {
|
|
||||||
throw data;
|
|
||||||
} else {
|
} else {
|
||||||
responseMessage.done = true;
|
responseMessage.done = true;
|
||||||
responseMessage.context = data.context;
|
responseMessage.context = data.context ?? null;
|
||||||
|
responseMessage.info = {
|
||||||
|
total_duration: data.total_duration,
|
||||||
|
prompt_eval_count: data.prompt_eval_count,
|
||||||
|
prompt_eval_duration: data.prompt_eval_duration,
|
||||||
|
eval_count: data.eval_count,
|
||||||
|
eval_duration: data.eval_duration
|
||||||
|
};
|
||||||
messages = messages;
|
messages = messages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,12 +340,9 @@
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const { value, done } = await reader.read();
|
const { value, done } = await reader.read();
|
||||||
if (done || stopResponseFlag) {
|
if (done || stopResponseFlag || _chatId !== $chatId) {
|
||||||
if (stopResponseFlag) {
|
responseMessage.done = true;
|
||||||
responseMessage.done = true;
|
messages = messages;
|
||||||
messages = messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -152,38 +152,11 @@
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await tick();
|
||||||
|
|
||||||
window.scrollTo({ top: document.body.scrollHeight });
|
window.scrollTo({ top: document.body.scrollHeight });
|
||||||
|
|
||||||
const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/generate`, {
|
// const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/generate`, {
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'text/event-stream',
|
|
||||||
...($settings.authHeader && { Authorization: $settings.authHeader }),
|
|
||||||
...($user && { Authorization: `Bearer ${localStorage.token}` })
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
model: model,
|
|
||||||
prompt: userPrompt,
|
|
||||||
system: $settings.system ?? undefined,
|
|
||||||
options: {
|
|
||||||
seed: $settings.seed ?? undefined,
|
|
||||||
temperature: $settings.temperature ?? undefined,
|
|
||||||
repeat_penalty: $settings.repeat_penalty ?? undefined,
|
|
||||||
top_k: $settings.top_k ?? undefined,
|
|
||||||
top_p: $settings.top_p ?? undefined,
|
|
||||||
num_ctx: $settings.num_ctx ?? undefined,
|
|
||||||
...($settings.options ?? {})
|
|
||||||
},
|
|
||||||
format: $settings.requestFormat ?? undefined,
|
|
||||||
context:
|
|
||||||
history.messages[parentId] !== null &&
|
|
||||||
history.messages[parentId].parentId in history.messages
|
|
||||||
? history.messages[history.messages[parentId].parentId]?.context ?? undefined
|
|
||||||
: undefined
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/chat`, {
|
|
||||||
// method: 'POST',
|
// method: 'POST',
|
||||||
// headers: {
|
// headers: {
|
||||||
// 'Content-Type': 'text/event-stream',
|
// 'Content-Type': 'text/event-stream',
|
||||||
|
@ -192,17 +165,8 @@
|
||||||
// },
|
// },
|
||||||
// body: JSON.stringify({
|
// body: JSON.stringify({
|
||||||
// model: model,
|
// model: model,
|
||||||
// messages: [
|
// prompt: userPrompt,
|
||||||
// $settings.system
|
// system: $settings.system ?? undefined,
|
||||||
// ? {
|
|
||||||
// role: 'system',
|
|
||||||
// content: $settings.system
|
|
||||||
// }
|
|
||||||
// : undefined,
|
|
||||||
// ...messages
|
|
||||||
// ]
|
|
||||||
// .filter((message) => message)
|
|
||||||
// .map((message) => ({ role: message.role, content: message.content })),
|
|
||||||
// options: {
|
// options: {
|
||||||
// seed: $settings.seed ?? undefined,
|
// seed: $settings.seed ?? undefined,
|
||||||
// temperature: $settings.temperature ?? undefined,
|
// temperature: $settings.temperature ?? undefined,
|
||||||
|
@ -212,10 +176,48 @@
|
||||||
// num_ctx: $settings.num_ctx ?? undefined,
|
// num_ctx: $settings.num_ctx ?? undefined,
|
||||||
// ...($settings.options ?? {})
|
// ...($settings.options ?? {})
|
||||||
// },
|
// },
|
||||||
// format: $settings.requestFormat ?? undefined
|
// format: $settings.requestFormat ?? undefined,
|
||||||
|
// context:
|
||||||
|
// history.messages[parentId] !== null &&
|
||||||
|
// history.messages[parentId].parentId in history.messages
|
||||||
|
// ? history.messages[history.messages[parentId].parentId]?.context ?? undefined
|
||||||
|
// : undefined
|
||||||
// })
|
// })
|
||||||
// });
|
// });
|
||||||
|
|
||||||
|
const res = await fetch(`${$settings?.API_BASE_URL ?? OLLAMA_API_BASE_URL}/chat`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'text/event-stream',
|
||||||
|
...($settings.authHeader && { Authorization: $settings.authHeader }),
|
||||||
|
...($user && { Authorization: `Bearer ${localStorage.token}` })
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: model,
|
||||||
|
messages: [
|
||||||
|
$settings.system
|
||||||
|
? {
|
||||||
|
role: 'system',
|
||||||
|
content: $settings.system
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
...messages
|
||||||
|
]
|
||||||
|
.filter((message) => message)
|
||||||
|
.map((message) => ({ role: message.role, content: message.content })),
|
||||||
|
options: {
|
||||||
|
seed: $settings.seed ?? undefined,
|
||||||
|
temperature: $settings.temperature ?? undefined,
|
||||||
|
repeat_penalty: $settings.repeat_penalty ?? undefined,
|
||||||
|
top_k: $settings.top_k ?? undefined,
|
||||||
|
top_p: $settings.top_p ?? undefined,
|
||||||
|
num_ctx: $settings.num_ctx ?? undefined,
|
||||||
|
...($settings.options ?? {})
|
||||||
|
},
|
||||||
|
format: $settings.requestFormat ?? undefined
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
const reader = res.body
|
const reader = res.body
|
||||||
.pipeThrough(new TextDecoderStream())
|
.pipeThrough(new TextDecoderStream())
|
||||||
.pipeThrough(splitStream('\n'))
|
.pipeThrough(splitStream('\n'))
|
||||||
|
@ -223,12 +225,9 @@
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const { value, done } = await reader.read();
|
const { value, done } = await reader.read();
|
||||||
if (done || stopResponseFlag) {
|
if (done || stopResponseFlag || _chatId !== $chatId) {
|
||||||
if (stopResponseFlag) {
|
responseMessage.done = true;
|
||||||
responseMessage.done = true;
|
messages = messages;
|
||||||
messages = messages;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,18 +238,28 @@
|
||||||
if (line !== '') {
|
if (line !== '') {
|
||||||
console.log(line);
|
console.log(line);
|
||||||
let data = JSON.parse(line);
|
let data = JSON.parse(line);
|
||||||
|
|
||||||
|
if ('detail' in data) {
|
||||||
|
throw data;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.done == false) {
|
if (data.done == false) {
|
||||||
if (responseMessage.content == '' && data.response == '\n') {
|
if (responseMessage.content == '' && data.message.content == '\n') {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
responseMessage.content += data.response;
|
responseMessage.content += data.message.content;
|
||||||
messages = messages;
|
messages = messages;
|
||||||
}
|
}
|
||||||
} else if ('detail' in data) {
|
|
||||||
throw data;
|
|
||||||
} else {
|
} else {
|
||||||
responseMessage.done = true;
|
responseMessage.done = true;
|
||||||
responseMessage.context = data.context;
|
responseMessage.context = data.context ?? null;
|
||||||
|
responseMessage.info = {
|
||||||
|
total_duration: data.total_duration,
|
||||||
|
prompt_eval_count: data.prompt_eval_count,
|
||||||
|
prompt_eval_duration: data.prompt_eval_duration,
|
||||||
|
eval_count: data.eval_count,
|
||||||
|
eval_duration: data.eval_duration
|
||||||
|
};
|
||||||
messages = messages;
|
messages = messages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue