|
@@ -1,14 +1,17 @@
|
|
<script lang="ts">
|
|
<script lang="ts">
|
|
- import { goto } from '$app/navigation';
|
|
|
|
|
|
+ import { toast } from 'svelte-sonner';
|
|
|
|
|
|
|
|
+ import { goto } from '$app/navigation';
|
|
import { onMount, tick, getContext } from 'svelte';
|
|
import { onMount, tick, getContext } from 'svelte';
|
|
|
|
|
|
- import { toast } from 'svelte-sonner';
|
|
|
|
-
|
|
|
|
- import { OLLAMA_API_BASE_URL, OPENAI_API_BASE_URL, WEBUI_API_BASE_URL } from '$lib/constants';
|
|
|
|
- import { WEBUI_NAME, config, user, models, settings } from '$lib/stores';
|
|
|
|
|
|
+ import {
|
|
|
|
+ OLLAMA_API_BASE_URL,
|
|
|
|
+ OPENAI_API_BASE_URL,
|
|
|
|
+ WEBUI_API_BASE_URL,
|
|
|
|
+ WEBUI_BASE_URL
|
|
|
|
+ } from '$lib/constants';
|
|
|
|
+ import { WEBUI_NAME, config, user, models, settings, showSidebar } from '$lib/stores';
|
|
|
|
|
|
- import { generateChatCompletion } from '$lib/apis/ollama';
|
|
|
|
import { generateOpenAIChatCompletion } from '$lib/apis/openai';
|
|
import { generateOpenAIChatCompletion } from '$lib/apis/openai';
|
|
|
|
|
|
import { splitStream } from '$lib/utils';
|
|
import { splitStream } from '$lib/utils';
|
|
@@ -17,17 +20,13 @@
|
|
|
|
|
|
const i18n = getContext('i18n');
|
|
const i18n = getContext('i18n');
|
|
|
|
|
|
- let mode = 'chat';
|
|
|
|
let loaded = false;
|
|
let loaded = false;
|
|
- let text = '';
|
|
|
|
|
|
|
|
let selectedModelId = '';
|
|
let selectedModelId = '';
|
|
-
|
|
|
|
let loading = false;
|
|
let loading = false;
|
|
let stopResponseFlag = false;
|
|
let stopResponseFlag = false;
|
|
|
|
|
|
let messagesContainerElement: HTMLDivElement;
|
|
let messagesContainerElement: HTMLDivElement;
|
|
- let textCompletionAreaElement: HTMLTextAreaElement;
|
|
|
|
|
|
|
|
let system = '';
|
|
let system = '';
|
|
let messages = [
|
|
let messages = [
|
|
@@ -38,7 +37,7 @@
|
|
];
|
|
];
|
|
|
|
|
|
const scrollToBottom = () => {
|
|
const scrollToBottom = () => {
|
|
- const element = mode === 'chat' ? messagesContainerElement : textCompletionAreaElement;
|
|
|
|
|
|
+ const element = messagesContainerElement;
|
|
|
|
|
|
if (element) {
|
|
if (element) {
|
|
element.scrollTop = element?.scrollHeight;
|
|
element.scrollTop = element?.scrollHeight;
|
|
@@ -50,64 +49,6 @@
|
|
console.log('stopResponse');
|
|
console.log('stopResponse');
|
|
};
|
|
};
|
|
|
|
|
|
- const textCompletionHandler = async () => {
|
|
|
|
- const model = $models.find((model) => model.id === selectedModelId);
|
|
|
|
-
|
|
|
|
- const [res, controller] = await generateOpenAIChatCompletion(
|
|
|
|
- localStorage.token,
|
|
|
|
- {
|
|
|
|
- model: model.id,
|
|
|
|
- stream: true,
|
|
|
|
- messages: [
|
|
|
|
- {
|
|
|
|
- role: 'assistant',
|
|
|
|
- content: text
|
|
|
|
- }
|
|
|
|
- ]
|
|
|
|
- },
|
|
|
|
- model?.owned_by === 'openai' ? `${OPENAI_API_BASE_URL}` : `${OLLAMA_API_BASE_URL}/v1`
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- if (res && res.ok) {
|
|
|
|
- const reader = res.body
|
|
|
|
- .pipeThrough(new TextDecoderStream())
|
|
|
|
- .pipeThrough(splitStream('\n'))
|
|
|
|
- .getReader();
|
|
|
|
-
|
|
|
|
- while (true) {
|
|
|
|
- const { value, done } = await reader.read();
|
|
|
|
- if (done || stopResponseFlag) {
|
|
|
|
- if (stopResponseFlag) {
|
|
|
|
- controller.abort('User: Stop Response');
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- try {
|
|
|
|
- let lines = value.split('\n');
|
|
|
|
-
|
|
|
|
- for (const line of lines) {
|
|
|
|
- if (line !== '') {
|
|
|
|
- if (line === 'data: [DONE]') {
|
|
|
|
- // responseMessage.done = true;
|
|
|
|
- console.log('done');
|
|
|
|
- } else {
|
|
|
|
- let data = JSON.parse(line.replace(/^data: /, ''));
|
|
|
|
- console.log(data);
|
|
|
|
-
|
|
|
|
- text += data.choices[0].delta.content ?? '';
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } catch (error) {
|
|
|
|
- console.log(error);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- scrollToBottom();
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
const chatCompletionHandler = async () => {
|
|
const chatCompletionHandler = async () => {
|
|
const model = $models.find((model) => model.id === selectedModelId);
|
|
const model = $models.find((model) => model.id === selectedModelId);
|
|
|
|
|
|
@@ -126,7 +67,7 @@
|
|
...messages
|
|
...messages
|
|
].filter((message) => message)
|
|
].filter((message) => message)
|
|
},
|
|
},
|
|
- model?.owned_by === 'openai' ? `${OPENAI_API_BASE_URL}` : `${OLLAMA_API_BASE_URL}/v1`
|
|
|
|
|
|
+ `${WEBUI_BASE_URL}/api`
|
|
);
|
|
);
|
|
|
|
|
|
let responseMessage;
|
|
let responseMessage;
|
|
@@ -199,12 +140,7 @@
|
|
const submitHandler = async () => {
|
|
const submitHandler = async () => {
|
|
if (selectedModelId) {
|
|
if (selectedModelId) {
|
|
loading = true;
|
|
loading = true;
|
|
-
|
|
|
|
- if (mode === 'complete') {
|
|
|
|
- await textCompletionHandler();
|
|
|
|
- } else if (mode === 'chat') {
|
|
|
|
- await chatCompletionHandler();
|
|
|
|
- }
|
|
|
|
|
|
+ await chatCompletionHandler();
|
|
|
|
|
|
loading = false;
|
|
loading = false;
|
|
stopResponseFlag = false;
|
|
stopResponseFlag = false;
|
|
@@ -227,12 +163,6 @@
|
|
});
|
|
});
|
|
</script>
|
|
</script>
|
|
|
|
|
|
-<svelte:head>
|
|
|
|
- <title>
|
|
|
|
- {$i18n.t('Playground')} | {$WEBUI_NAME}
|
|
|
|
- </title>
|
|
|
|
-</svelte:head>
|
|
|
|
-
|
|
|
|
<div class=" flex flex-col justify-between w-full overflow-y-auto h-full">
|
|
<div class=" flex flex-col justify-between w-full overflow-y-auto h-full">
|
|
<div class="mx-auto w-full md:px-0 h-full">
|
|
<div class="mx-auto w-full md:px-0 h-full">
|
|
<div class=" flex flex-col h-full">
|
|
<div class=" flex flex-col h-full">
|
|
@@ -252,61 +182,22 @@
|
|
/>
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
-
|
|
|
|
- <div class="flex-shrink-0">
|
|
|
|
- <button
|
|
|
|
- class=" flex items-center gap-0.5 text-xs px-2.5 py-0.5 rounded-lg {mode ===
|
|
|
|
- 'chat' && 'text-sky-600 dark:text-sky-200 bg-sky-200/30'} {mode === 'complete' &&
|
|
|
|
- 'text-green-600 dark:text-green-200 bg-green-200/30'} "
|
|
|
|
- on:click={() => {
|
|
|
|
- if (mode === 'complete') {
|
|
|
|
- mode = 'chat';
|
|
|
|
- } else {
|
|
|
|
- mode = 'complete';
|
|
|
|
- }
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- {#if mode === 'complete'}
|
|
|
|
- {$i18n.t('Text Completion')}
|
|
|
|
- {:else if mode === 'chat'}
|
|
|
|
- {$i18n.t('Chat')}
|
|
|
|
- {/if}
|
|
|
|
-
|
|
|
|
- <div>
|
|
|
|
- <svg
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
- viewBox="0 0 16 16"
|
|
|
|
- fill="currentColor"
|
|
|
|
- class="w-3 h-3"
|
|
|
|
- >
|
|
|
|
- <path
|
|
|
|
- fill-rule="evenodd"
|
|
|
|
- d="M5.22 10.22a.75.75 0 0 1 1.06 0L8 11.94l1.72-1.72a.75.75 0 1 1 1.06 1.06l-2.25 2.25a.75.75 0 0 1-1.06 0l-2.25-2.25a.75.75 0 0 1 0-1.06ZM10.78 5.78a.75.75 0 0 1-1.06 0L8 4.06 6.28 5.78a.75.75 0 0 1-1.06-1.06l2.25-2.25a.75.75 0 0 1 1.06 0l2.25 2.25a.75.75 0 0 1 0 1.06Z"
|
|
|
|
- clip-rule="evenodd"
|
|
|
|
- />
|
|
|
|
- </svg>
|
|
|
|
- </div>
|
|
|
|
- </button>
|
|
|
|
- </div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
- {#if mode === 'chat'}
|
|
|
|
- <div class="p-1">
|
|
|
|
- <div class="p-3 outline outline-1 outline-gray-200 dark:outline-gray-800 rounded-lg">
|
|
|
|
- <div class=" text-sm font-medium">{$i18n.t('System')}</div>
|
|
|
|
- <textarea
|
|
|
|
- id="system-textarea"
|
|
|
|
- class="w-full h-full bg-transparent resize-none outline-none text-sm"
|
|
|
|
- bind:value={system}
|
|
|
|
- placeholder={$i18n.t("You're a helpful assistant.")}
|
|
|
|
- rows="4"
|
|
|
|
- />
|
|
|
|
- </div>
|
|
|
|
|
|
+ <div class="p-1">
|
|
|
|
+ <div class="p-3 outline outline-1 outline-gray-200 dark:outline-gray-800 rounded-lg">
|
|
|
|
+ <div class=" text-sm font-medium">{$i18n.t('System')}</div>
|
|
|
|
+ <textarea
|
|
|
|
+ id="system-textarea"
|
|
|
|
+ class="w-full h-full bg-transparent resize-none outline-none text-sm"
|
|
|
|
+ bind:value={system}
|
|
|
|
+ placeholder={$i18n.t("You're a helpful assistant.")}
|
|
|
|
+ rows="4"
|
|
|
|
+ />
|
|
</div>
|
|
</div>
|
|
- {/if}
|
|
|
|
-
|
|
|
|
|
|
+ </div>
|
|
<div
|
|
<div
|
|
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0"
|
|
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0"
|
|
id="messages-container"
|
|
id="messages-container"
|
|
@@ -314,17 +205,7 @@
|
|
>
|
|
>
|
|
<div class=" h-full w-full flex flex-col">
|
|
<div class=" h-full w-full flex flex-col">
|
|
<div class="flex-1 p-1">
|
|
<div class="flex-1 p-1">
|
|
- {#if mode === 'complete'}
|
|
|
|
- <textarea
|
|
|
|
- id="text-completion-textarea"
|
|
|
|
- bind:this={textCompletionAreaElement}
|
|
|
|
- class="w-full h-full p-3 bg-transparent outline outline-1 outline-gray-200 dark:outline-gray-800 resize-none rounded-lg text-sm"
|
|
|
|
- bind:value={text}
|
|
|
|
- placeholder={$i18n.t("You're a helpful assistant.")}
|
|
|
|
- />
|
|
|
|
- {:else if mode === 'chat'}
|
|
|
|
- <ChatCompletion bind:messages />
|
|
|
|
- {/if}
|
|
|
|
|
|
+ <ChatCompletion bind:messages />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|