Merge branch 'dev' of https://github.com/open-webui/open-webui into feat/rtl-layout-chat-support
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { onMount, tick, getContext } from 'svelte';
|
||||
import { modelfiles, settings, showSidebar } from '$lib/stores';
|
||||
import { mobile, modelfiles, settings, showSidebar } from '$lib/stores';
|
||||
import { blobToFile, calculateSHA256, findWordIndices } from '$lib/utils';
|
||||
|
||||
import {
|
||||
@@ -412,7 +412,7 @@
|
||||
{#if dragged}
|
||||
<div
|
||||
class="fixed {$showSidebar
|
||||
? 'left-0 lg:left-[260px] lg:w-[calc(100%-260px)]'
|
||||
? 'left-0 md:left-[260px] md:w-[calc(100%-260px)]'
|
||||
: 'left-0'} w-full h-full flex z-50 touch-none pointer-events-none"
|
||||
id="dropzone"
|
||||
role="region"
|
||||
@@ -428,9 +428,9 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="fixed bottom-0 {$showSidebar ? 'left-0 lg:left-[260px]' : 'left-0'} right-0">
|
||||
<div class="fixed bottom-0 {$showSidebar ? 'left-0 md:left-[260px]' : 'left-0'} right-0">
|
||||
<div class="w-full">
|
||||
<div class="px-2.5 lg:px-16 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
|
||||
<div class="px-2.5 md:px-16 -mb-0.5 mx-auto inset-x-0 bg-transparent flex justify-center">
|
||||
<div class="flex flex-col max-w-5xl w-full">
|
||||
<div class="relative">
|
||||
{#if autoScroll === false && messages.length > 0}
|
||||
@@ -535,7 +535,7 @@
|
||||
</div>
|
||||
|
||||
<div class="bg-white dark:bg-gray-900">
|
||||
<div class="max-w-6xl px-2.5 lg:px-16 mx-auto inset-x-0">
|
||||
<div class="max-w-6xl px-2.5 md:px-16 mx-auto inset-x-0">
|
||||
<div class=" pb-2">
|
||||
<input
|
||||
bind:this={filesInputElement}
|
||||
@@ -755,7 +755,7 @@
|
||||
<textarea
|
||||
id="chat-textarea"
|
||||
bind:this={chatTextAreaElement}
|
||||
class="scrollbar-none dark:bg-gray-900 dark:text-gray-100 outline-none w-full py-3 px-3 {fileUploadEnabled
|
||||
class="scrollbar-hidden dark:bg-gray-900 dark:text-gray-100 outline-none w-full py-3 px-3 {fileUploadEnabled
|
||||
? ''
|
||||
: ' pl-4'} rounded-xl resize-none h-[48px]"
|
||||
placeholder={chatInputPlaceholder !== ''
|
||||
@@ -766,7 +766,7 @@
|
||||
bind:value={prompt}
|
||||
on:keypress={(e) => {
|
||||
if (
|
||||
window.innerWidth > 1024 ||
|
||||
!$mobile ||
|
||||
!(
|
||||
'ontouchstart' in window ||
|
||||
navigator.maxTouchPoints > 0 ||
|
||||
@@ -1047,12 +1047,12 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.scrollbar-none:active::-webkit-scrollbar-thumb,
|
||||
.scrollbar-none:focus::-webkit-scrollbar-thumb,
|
||||
.scrollbar-none:hover::-webkit-scrollbar-thumb {
|
||||
.scrollbar-hidden:active::-webkit-scrollbar-thumb,
|
||||
.scrollbar-hidden:focus::-webkit-scrollbar-thumb,
|
||||
.scrollbar-hidden:hover::-webkit-scrollbar-thumb {
|
||||
visibility: visible;
|
||||
}
|
||||
.scrollbar-none::-webkit-scrollbar-thumb {
|
||||
.scrollbar-hidden::-webkit-scrollbar-thumb {
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -309,31 +309,33 @@
|
||||
copyToClipboard={copyToClipboardWithToast}
|
||||
/>
|
||||
{:else}
|
||||
<ResponseMessage
|
||||
{message}
|
||||
modelfiles={selectedModelfiles}
|
||||
siblings={history.messages[message.parentId]?.childrenIds ?? []}
|
||||
isLastMessage={messageIdx + 1 === messages.length}
|
||||
{readOnly}
|
||||
{updateChatMessages}
|
||||
{confirmEditResponseMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{rateMessage}
|
||||
copyToClipboard={copyToClipboardWithToast}
|
||||
{continueGeneration}
|
||||
{regenerateResponse}
|
||||
on:save={async (e) => {
|
||||
console.log('save', e);
|
||||
{#key message.id}
|
||||
<ResponseMessage
|
||||
{message}
|
||||
modelfiles={selectedModelfiles}
|
||||
siblings={history.messages[message.parentId]?.childrenIds ?? []}
|
||||
isLastMessage={messageIdx + 1 === messages.length}
|
||||
{readOnly}
|
||||
{updateChatMessages}
|
||||
{confirmEditResponseMessage}
|
||||
{showPreviousMessage}
|
||||
{showNextMessage}
|
||||
{rateMessage}
|
||||
copyToClipboard={copyToClipboardWithToast}
|
||||
{continueGeneration}
|
||||
{regenerateResponse}
|
||||
on:save={async (e) => {
|
||||
console.log('save', e);
|
||||
|
||||
const message = e.detail;
|
||||
history.messages[message.id] = message;
|
||||
await updateChatById(localStorage.token, chatId, {
|
||||
messages: messages,
|
||||
history: history
|
||||
});
|
||||
}}
|
||||
/>
|
||||
const message = e.detail;
|
||||
history.messages[message.id] = message;
|
||||
await updateChatById(localStorage.token, chatId, {
|
||||
messages: messages,
|
||||
history: history
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{/key}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
<div class="flex flex-col md:flex-row w-full px-6 pb-5 md:space-x-4">
|
||||
<div
|
||||
class="flex flex-col w-full dark:text-gray-200 overflow-y-scroll max-h-[22rem] scrollbar-none"
|
||||
class="flex flex-col w-full dark:text-gray-200 overflow-y-scroll max-h-[22rem] scrollbar-hidden"
|
||||
>
|
||||
{#each mergedDocuments as document, documentIdx}
|
||||
<div class="flex flex-col w-full">
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<div class=" self-center font-bold mb-0.5 capitalize line-clamp-1 contents">
|
||||
<div class=" self-center font-bold mb-0.5 line-clamp-1 contents">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,6 @@
|
||||
export let src = '/user.png';
|
||||
</script>
|
||||
|
||||
<div class={$settings?.chatDirection === 'LTR' ? "mr-4" : "ml-4"}>
|
||||
<img {src} class=" max-w-[28px] object-cover rounded-full" alt="profile" draggable="false" />
|
||||
<div class={$settings?.chatDirection === 'LTR' ? "mr-3" : "ml-3"}>>
|
||||
<img {src} class=" w-8 object-cover rounded-full" alt="profile" draggable="false" />
|
||||
</div>
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
let selectedReason = null;
|
||||
let comment = '';
|
||||
|
||||
$: if (message.annotation.rating === 1) {
|
||||
$: if (message?.annotation?.rating === 1) {
|
||||
reasons = LIKE_REASONS;
|
||||
} else if (message.annotation.rating === -1) {
|
||||
} else if (message?.annotation?.rating === -1) {
|
||||
reasons = DISLIKE_REASONS;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,8 +65,8 @@
|
||||
let generatingImage = false;
|
||||
|
||||
let showRateComment = false;
|
||||
|
||||
let showCitationModal = false;
|
||||
|
||||
let selectedCitation = null;
|
||||
|
||||
$: tokens = marked.lexer(sanitizeResponseContent(message.content));
|
||||
@@ -338,7 +338,7 @@
|
||||
($i18n.language === 'dg-DG' ? `/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)}
|
||||
/>
|
||||
|
||||
<div class="w-full overflow-hidden">
|
||||
<div class="w-full overflow-hidden pl-1">
|
||||
<Name>
|
||||
{#if message.model in modelfiles}
|
||||
{modelfiles[message.model]?.title}
|
||||
@@ -347,8 +347,10 @@
|
||||
{/if}
|
||||
|
||||
{#if message.timestamp}
|
||||
<span class=" invisible group-hover:visible text-gray-400 text-xs font-medium">
|
||||
{dayjs(message.timestamp * 1000).format($i18n.t('DD/MM/YYYY HH:mm'))}
|
||||
<span
|
||||
class=" self-center invisible group-hover:visible text-gray-400 text-xs font-medium uppercase"
|
||||
>
|
||||
{dayjs(message.timestamp * 1000).format($i18n.t('h:mm a'))}
|
||||
</span>
|
||||
{/if}
|
||||
</Name>
|
||||
@@ -370,7 +372,7 @@
|
||||
>
|
||||
<div>
|
||||
{#if edit === true}
|
||||
<div class=" w-full">
|
||||
<div class="w-full bg-gray-50 dark:bg-gray-800 rounded-3xl px-5 py-3 my-2">
|
||||
<textarea
|
||||
id="message-edit-{message.id}"
|
||||
bind:this={editTextAreaElement}
|
||||
@@ -382,24 +384,26 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class=" mt-2 mb-1 flex justify-center space-x-2 text-sm font-medium">
|
||||
<div class=" mt-2 mb-1 flex justify-end space-x-1.5 text-sm font-medium">
|
||||
<button
|
||||
class="px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
|
||||
on:click={() => {
|
||||
editMessageConfirmHandler();
|
||||
}}
|
||||
>
|
||||
{$i18n.t('Save')}
|
||||
</button>
|
||||
|
||||
<button
|
||||
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"
|
||||
id="close-edit-message-button"
|
||||
class=" px-4 py-2 bg-gray-900 hover:bg-gray-850 text-gray-100 transition rounded-3xl"
|
||||
on:click={() => {
|
||||
cancelEditMessage();
|
||||
}}
|
||||
>
|
||||
{$i18n.t('Cancel')}
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="save-edit-message-button"
|
||||
class="px-4 py-2 bg-white hover:bg-gray-100 text-gray-800 transition rounded-3xl"
|
||||
on:click={() => {
|
||||
editMessageConfirmHandler();
|
||||
}}
|
||||
>
|
||||
{$i18n.t('Save')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
@@ -476,7 +480,7 @@
|
||||
<div class="bg-white dark:bg-gray-700 rounded-full size-4">
|
||||
{idx + 1}
|
||||
</div>
|
||||
<div class=" mx-2">
|
||||
<div class="flex-1 mx-2 line-clamp-1">
|
||||
{citation.source.name}
|
||||
</div>
|
||||
</button>
|
||||
@@ -487,50 +491,56 @@
|
||||
|
||||
{#if message.done || siblings.length > 1}
|
||||
<div
|
||||
class=" flex justify-start space-x-1 overflow-x-auto buttons text-gray-700 dark:text-gray-500"
|
||||
class=" flex justify-start overflow-x-auto buttons text-gray-600 dark:text-gray-500"
|
||||
>
|
||||
{#if siblings.length > 1}
|
||||
<div class="flex self-center min-w-fit">
|
||||
<div class="flex self-center">
|
||||
<button
|
||||
class="self-center dark:hover:text-white hover:text-black transition"
|
||||
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||
on:click={() => {
|
||||
showPreviousMessage(message);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.5"
|
||||
class="size-3.5"
|
||||
>
|
||||
<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"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.75 19.5 8.25 12l7.5-7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="text-xs font-bold self-center min-w-fit dark:text-gray-100">
|
||||
{siblings.indexOf(message.id) + 1} / {siblings.length}
|
||||
<div
|
||||
class="text-sm tracking-widest font-semibold self-center dark:text-gray-100"
|
||||
>
|
||||
{siblings.indexOf(message.id) + 1}/{siblings.length}
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="self-center dark:hover:text-white hover:text-black transition"
|
||||
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||
on:click={() => {
|
||||
showNextMessage(message);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.5"
|
||||
class="size-3.5"
|
||||
>
|
||||
<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"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m8.25 4.5 7.5 7.5-7.5 7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
@@ -543,7 +553,7 @@
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
editMessageHandler();
|
||||
}}
|
||||
@@ -552,7 +562,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -570,7 +580,7 @@
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition copy-response-button"
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition copy-response-button"
|
||||
on:click={() => {
|
||||
copyToClipboard(message.content);
|
||||
}}
|
||||
@@ -579,7 +589,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -592,83 +602,12 @@
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
{#if !readOnly}
|
||||
<Tooltip content={$i18n.t('Good Response')} placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded {message?.annotation
|
||||
?.rating === 1
|
||||
? 'bg-gray-100 dark:bg-gray-800'
|
||||
: ''} dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
rateMessage(message.id, 1);
|
||||
showRateComment = true;
|
||||
|
||||
window.setTimeout(() => {
|
||||
document
|
||||
.getElementById(`message-feedback-${message.id}`)
|
||||
?.scrollIntoView();
|
||||
}, 0);
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content={$i18n.t('Bad Response')} placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded {message?.annotation
|
||||
?.rating === -1
|
||||
? 'bg-gray-100 dark:bg-gray-800'
|
||||
: ''} dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
rateMessage(message.id, -1);
|
||||
showRateComment = true;
|
||||
window.setTimeout(() => {
|
||||
document
|
||||
.getElementById(`message-feedback-${message.id}`)
|
||||
?.scrollIntoView();
|
||||
}, 0);
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
<Tooltip content={$i18n.t('Read Aloud')} placement="bottom">
|
||||
<button
|
||||
id="speak-button-{message.id}"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
if (!loadingSpeech) {
|
||||
toggleSpeakMessage(message);
|
||||
@@ -715,7 +654,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -730,7 +669,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -749,7 +688,7 @@
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
if (!generatingImage) {
|
||||
generateImage(message);
|
||||
@@ -796,7 +735,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -816,7 +755,7 @@
|
||||
<button
|
||||
class=" {isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition whitespace-pre-wrap"
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition whitespace-pre-wrap"
|
||||
on:click={() => {
|
||||
console.log(message);
|
||||
}}
|
||||
@@ -826,7 +765,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -840,13 +779,84 @@
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
{#if !readOnly}
|
||||
<Tooltip content={$i18n.t('Good Response')} placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg {message
|
||||
?.annotation?.rating === 1
|
||||
? 'bg-gray-100 dark:bg-gray-800'
|
||||
: ''} dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
rateMessage(message.id, 1);
|
||||
showRateComment = true;
|
||||
|
||||
window.setTimeout(() => {
|
||||
document
|
||||
.getElementById(`message-feedback-${message.id}`)
|
||||
?.scrollIntoView();
|
||||
}, 0);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-width="2.3"
|
||||
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>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip content={$i18n.t('Bad Response')} placement="bottom">
|
||||
<button
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg {message
|
||||
?.annotation?.rating === -1
|
||||
? 'bg-gray-100 dark:bg-gray-800'
|
||||
: ''} dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
rateMessage(message.id, -1);
|
||||
showRateComment = true;
|
||||
window.setTimeout(() => {
|
||||
document
|
||||
.getElementById(`message-feedback-${message.id}`)
|
||||
?.scrollIntoView();
|
||||
}, 0);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
stroke="currentColor"
|
||||
fill="none"
|
||||
stroke-width="2.3"
|
||||
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>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
{#if isLastMessage && !readOnly}
|
||||
<Tooltip content={$i18n.t('Continue Response')} placement="bottom">
|
||||
<button
|
||||
type="button"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition regenerate-response-button"
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button"
|
||||
on:click={() => {
|
||||
continueGeneration();
|
||||
}}
|
||||
@@ -855,7 +865,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -878,14 +888,14 @@
|
||||
type="button"
|
||||
class="{isLastMessage
|
||||
? 'visible'
|
||||
: 'invisible group-hover:visible'} p-1 rounded dark:hover:text-white hover:text-black transition regenerate-response-button"
|
||||
: 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition regenerate-response-button"
|
||||
on:click={regenerateResponse}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -902,7 +912,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if showRateComment}
|
||||
{#if message.done && showRateComment}
|
||||
<RateComment
|
||||
messageId={message.id}
|
||||
bind:show={showRateComment}
|
||||
|
||||
@@ -54,49 +54,55 @@
|
||||
};
|
||||
</script>
|
||||
|
||||
<div class=" flex w-full" dir="{$settings.chatDirection}">
|
||||
<ProfileImage
|
||||
src={message.user
|
||||
? $modelfiles.find((modelfile) => modelfile.tagName === message.user)?.imageUrl ?? '/user.png'
|
||||
: user?.profile_image_url ?? '/user.png'}
|
||||
/>
|
||||
|
||||
<div class=" flex w-full user-message" dir="{$settings.chatDirection}">
|
||||
{#if !($settings?.chatBubble ?? true)}
|
||||
<ProfileImage
|
||||
src={message.user
|
||||
? $modelfiles.find((modelfile) => modelfile.tagName === message.user)?.imageUrl ??
|
||||
'/user.png'
|
||||
: user?.profile_image_url ?? '/user.png'}
|
||||
/>
|
||||
{/if}
|
||||
<div class="w-full overflow-hidden">
|
||||
<div class="user-message">
|
||||
<Name>
|
||||
{#if message.user}
|
||||
{#if $modelfiles.map((modelfile) => modelfile.tagName).includes(message.user)}
|
||||
{$modelfiles.find((modelfile) => modelfile.tagName === message.user)?.title}
|
||||
{#if !($settings?.chatBubble ?? true)}
|
||||
<div>
|
||||
<Name>
|
||||
{#if message.user}
|
||||
{#if $modelfiles.map((modelfile) => modelfile.tagName).includes(message.user)}
|
||||
{$modelfiles.find((modelfile) => modelfile.tagName === message.user)?.title}
|
||||
{:else}
|
||||
{$i18n.t('You')}
|
||||
<span class=" text-gray-500 text-sm font-medium">{message?.user ?? ''}</span>
|
||||
{/if}
|
||||
{:else if $settings.showUsername}
|
||||
{user.name}
|
||||
{:else}
|
||||
{$i18n.t('You')}
|
||||
<span class=" text-gray-500 text-sm font-medium">{message?.user ?? ''}</span>
|
||||
{/if}
|
||||
{:else if $settings.showUsername}
|
||||
{user.name}
|
||||
{:else}
|
||||
{$i18n.t('You')}
|
||||
{/if}
|
||||
|
||||
{#if message.timestamp}
|
||||
<span class=" invisible group-hover:visible text-gray-400 text-xs font-medium">
|
||||
{dayjs(message.timestamp * 1000).format($i18n.t('DD/MM/YYYY HH:mm'))}
|
||||
</span>
|
||||
{/if}
|
||||
</Name>
|
||||
</div>
|
||||
{#if message.timestamp}
|
||||
<span
|
||||
class=" invisible group-hover:visible text-gray-400 text-xs font-medium uppercase"
|
||||
>
|
||||
{dayjs(message.timestamp * 1000).format($i18n.t('h:mm a'))}
|
||||
</span>
|
||||
{/if}
|
||||
</Name>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="prose chat-{message.role} w-full max-w-full dark:prose-invert prose-headings:my-0 prose-p:my-0 prose-p:-mb-4 prose-pre:my-0 prose-table:my-0 prose-blockquote:my-0 prose-img:my-0 prose-ul:-my-4 prose-ol:-my-4 prose-li:-my-3 prose-ul:-mb-6 prose-ol:-mb-6 prose-li:-mb-4 whitespace-pre-line"
|
||||
class="prose chat-{message.role} w-full max-w-full flex flex-col justify-end dark:prose-invert prose-headings:my-0 prose-p:my-0 prose-p:-mb-4 prose-pre:my-0 prose-table:my-0 prose-blockquote:my-0 prose-img:my-0 prose-ul:-my-4 prose-ol:-my-4 prose-li:-my-3 prose-ul:-mb-6 prose-ol:-mb-6 prose-li:-mb-4 whitespace-pre-line"
|
||||
>
|
||||
{#if message.files}
|
||||
<div class="my-2.5 w-full flex overflow-x-auto gap-2 flex-wrap">
|
||||
<div class="mt-2.5 mb-1 w-full flex flex-col justify-end overflow-x-auto gap-1 flex-wrap">
|
||||
{#each message.files as file}
|
||||
<div>
|
||||
<div class={$settings?.chatBubble ?? true ? 'self-end' : ''}>
|
||||
{#if file.type === 'image'}
|
||||
<img src={file.url} alt="input" class=" max-h-96 rounded-lg" draggable="false" />
|
||||
{:else if file.type === 'doc'}
|
||||
<button
|
||||
class="h-16 w-[15rem] flex items-center space-x-3 px-2.5 dark:bg-gray-600 rounded-xl border border-gray-200 dark:border-none text-left"
|
||||
class="h-16 w-72 flex items-center space-x-3 px-2.5 dark:bg-gray-850 rounded-xl border border-gray-200 dark:border-none text-left"
|
||||
type="button"
|
||||
on:click={() => {
|
||||
if (file?.url) {
|
||||
@@ -132,7 +138,7 @@
|
||||
</button>
|
||||
{:else if file.type === 'collection'}
|
||||
<button
|
||||
class="h-16 w-[15rem] flex items-center space-x-3 px-2.5 dark:bg-gray-600 rounded-xl border border-gray-200 dark:border-none text-left"
|
||||
class="h-16 w-72 flex items-center space-x-3 px-2.5 dark:bg-gray-600 rounded-xl border border-gray-200 dark:border-none text-left"
|
||||
type="button"
|
||||
>
|
||||
<div class="p-2.5 bg-red-400 text-white rounded-lg">
|
||||
@@ -166,7 +172,7 @@
|
||||
{/if}
|
||||
|
||||
{#if edit === true}
|
||||
<div class=" w-full">
|
||||
<div class=" w-full bg-gray-50 dark:bg-gray-800 rounded-3xl px-5 py-3 mb-2">
|
||||
<textarea
|
||||
id="message-edit-{message.id}"
|
||||
bind:this={messageEditTextAreaElement}
|
||||
@@ -190,85 +196,104 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<div class=" mt-2 mb-1 flex justify-center space-x-2 text-sm font-medium">
|
||||
<button
|
||||
id="save-edit-message-button"
|
||||
class="px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
|
||||
on:click={() => {
|
||||
editMessageConfirmHandler();
|
||||
}}
|
||||
>
|
||||
{$i18n.t('Save & Submit')}
|
||||
</button>
|
||||
|
||||
<div class=" mt-2 mb-1 flex justify-end space-x-1.5 text-sm font-medium">
|
||||
<button
|
||||
id="close-edit-message-button"
|
||||
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"
|
||||
class=" px-4 py-2 bg-gray-900 hover:bg-gray-850 text-gray-100 transition rounded-3xl"
|
||||
on:click={() => {
|
||||
cancelEditMessage();
|
||||
}}
|
||||
>
|
||||
{$i18n.t('Cancel')}
|
||||
</button>
|
||||
|
||||
<button
|
||||
id="save-edit-message-button"
|
||||
class="px-4 py-2 bg-white hover:bg-gray-100 text-gray-800 transition rounded-3xl"
|
||||
on:click={() => {
|
||||
editMessageConfirmHandler();
|
||||
}}
|
||||
>
|
||||
{$i18n.t('Send')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="w-full">
|
||||
<pre id="user-message">{message.content}</pre>
|
||||
<div class="flex {$settings?.chatBubble ?? true ? 'justify-end' : ''} mb-2">
|
||||
<div
|
||||
class="rounded-3xl {$settings?.chatBubble ?? true
|
||||
? `max-w-[90%] px-5 py-2 bg-gray-50 dark:bg-gray-850 ${
|
||||
message.files ? 'rounded-tr-lg' : ''
|
||||
}`
|
||||
: ''} "
|
||||
>
|
||||
<pre id="user-message">{message.content}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=" flex justify-start space-x-1 text-gray-700 dark:text-gray-500">
|
||||
{#if siblings.length > 1}
|
||||
<div class="flex self-center">
|
||||
<button
|
||||
class="self-center dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
showPreviousMessage(message);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
<div
|
||||
class=" flex {$settings?.chatBubble ?? true
|
||||
? 'justify-end'
|
||||
: ''} text-gray-600 dark:text-gray-500"
|
||||
>
|
||||
{#if !($settings?.chatBubble ?? true)}
|
||||
{#if siblings.length > 1}
|
||||
<div class="flex self-center">
|
||||
<button
|
||||
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||
on:click={() => {
|
||||
showPreviousMessage(message);
|
||||
}}
|
||||
>
|
||||
<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>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.5"
|
||||
class="size-3.5"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.75 19.5 8.25 12l7.5-7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="text-xs font-bold self-center dark:text-gray-100">
|
||||
{siblings.indexOf(message.id) + 1} / {siblings.length}
|
||||
<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
|
||||
{siblings.indexOf(message.id) + 1}/{siblings.length}
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||
on:click={() => {
|
||||
showNextMessage(message);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.5"
|
||||
class="size-3.5"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m8.25 4.5 7.5 7.5-7.5 7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="self-center dark:hover:text-white hover:text-black transition"
|
||||
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}
|
||||
{/if}
|
||||
|
||||
{#if !readOnly}
|
||||
<Tooltip content={$i18n.t('Edit')} placement="bottom">
|
||||
<button
|
||||
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition edit-user-message-button"
|
||||
class="invisible group-hover:visible p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition edit-user-message-button"
|
||||
on:click={() => {
|
||||
editMessageHandler();
|
||||
}}
|
||||
@@ -277,7 +302,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -293,7 +318,7 @@
|
||||
|
||||
<Tooltip content={$i18n.t('Copy')} placement="bottom">
|
||||
<button
|
||||
class="invisible group-hover:visible p-1 rounded dark:hover:text-white hover:text-black transition"
|
||||
class="invisible group-hover:visible p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition"
|
||||
on:click={() => {
|
||||
copyToClipboard(message.content);
|
||||
}}
|
||||
@@ -302,7 +327,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="2"
|
||||
stroke-width="2.3"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
@@ -340,6 +365,60 @@
|
||||
</button>
|
||||
</Tooltip>
|
||||
{/if}
|
||||
|
||||
{#if $settings?.chatBubble ?? true}
|
||||
{#if siblings.length > 1}
|
||||
<div class="flex self-center">
|
||||
<button
|
||||
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||
on:click={() => {
|
||||
showPreviousMessage(message);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.5"
|
||||
class="size-3.5"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15.75 19.5 8.25 12l7.5-7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<div class="text-sm tracking-widest font-semibold self-center dark:text-gray-100">
|
||||
{siblings.indexOf(message.id) + 1}/{siblings.length}
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="self-center p-1 hover:bg-black/5 dark:hover:bg-white/5 dark:hover:text-white hover:text-black rounded-md transition"
|
||||
on:click={() => {
|
||||
showNextMessage(message);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
stroke-width="2.5"
|
||||
class="size-3.5"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m8.25 4.5 7.5 7.5-7.5 7.5"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import { Collapsible } from 'bits-ui';
|
||||
|
||||
import { setDefaultModels } from '$lib/apis/configs';
|
||||
import { models, showSettings, settings, user } from '$lib/stores';
|
||||
import { models, showSettings, settings, user, mobile } from '$lib/stores';
|
||||
import { onMount, tick, getContext } from 'svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import Selector from './ModelSelector/Selector.svelte';
|
||||
@@ -38,7 +38,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col mt-0.5 w-full">
|
||||
<div class="flex flex-col w-full items-center md:items-start">
|
||||
{#each selectedModels as selectedModel, selectedModelIdx}
|
||||
<div class="flex w-full max-w-fit">
|
||||
<div class="overflow-hidden w-full">
|
||||
@@ -108,7 +108,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
{#if showSetDefault}
|
||||
{#if showSetDefault && !$mobile}
|
||||
<div class="text-left mt-0.5 ml-1 text-[0.7rem] text-gray-500">
|
||||
<button on:click={saveDefaultModel}> {$i18n.t('Set as default')}</button>
|
||||
</div>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
import { cancelOllamaRequest, deleteModel, getOllamaVersion, pullModel } from '$lib/apis/ollama';
|
||||
|
||||
import { user, MODEL_DOWNLOAD_POOL, models } from '$lib/stores';
|
||||
import { user, MODEL_DOWNLOAD_POOL, models, mobile } from '$lib/stores';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { capitalizeFirstLetter, getModels, splitStream } from '$lib/utils';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
export let items = [{ value: 'mango', label: 'Mango' }];
|
||||
|
||||
export let className = ' w-[32rem]';
|
||||
export let className = ' w-[30rem]';
|
||||
|
||||
let show = false;
|
||||
|
||||
@@ -201,10 +201,11 @@
|
||||
<ChevronDown className=" self-center ml-2 size-3" strokeWidth="2.5" />
|
||||
</div>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content
|
||||
class=" z-40 {className} max-w-[calc(100vw-1rem)] justify-start rounded-lg bg-white dark:bg-gray-900 dark:text-white shadow-lg border border-gray-300/30 dark:border-gray-700/50 outline-none "
|
||||
class=" z-40 {className} max-w-[calc(100vw-1rem)] justify-start rounded-xl bg-white dark:bg-gray-850 dark:text-white shadow-lg border border-gray-300/30 dark:border-gray-700/50 outline-none "
|
||||
transition={flyAndScale}
|
||||
side={'bottom-start'}
|
||||
side={$mobile ? 'bottom' : 'bottom-start'}
|
||||
sideOffset={4}
|
||||
>
|
||||
<slot>
|
||||
@@ -224,11 +225,11 @@
|
||||
<hr class="border-gray-100 dark:border-gray-800" />
|
||||
{/if}
|
||||
|
||||
<div class="px-3 my-2 max-h-72 overflow-y-auto scrollbar-none">
|
||||
<div class="px-3 my-2 max-h-64 overflow-y-auto scrollbar-hidden">
|
||||
{#each filteredItems as item}
|
||||
<button
|
||||
aria-label="model-item"
|
||||
class="flex w-full text-left font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-none transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-850 rounded-lg cursor-pointer data-[highlighted]:bg-muted"
|
||||
class="flex w-full text-left font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-none transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg cursor-pointer data-[highlighted]:bg-muted"
|
||||
on:click={() => {
|
||||
value = item.value;
|
||||
|
||||
@@ -312,7 +313,7 @@
|
||||
|
||||
{#if !(searchValue.trim() in $MODEL_DOWNLOAD_POOL) && searchValue && ollamaVersion && $user.role === 'admin'}
|
||||
<button
|
||||
class="flex w-full font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-none transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-850 rounded-lg cursor-pointer data-[highlighted]:bg-muted"
|
||||
class="flex w-full font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-none transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg cursor-pointer data-[highlighted]:bg-muted"
|
||||
on:click={() => {
|
||||
pullModelHandler();
|
||||
}}
|
||||
@@ -406,12 +407,12 @@
|
||||
</DropdownMenu.Root>
|
||||
|
||||
<style>
|
||||
.scrollbar-none:active::-webkit-scrollbar-thumb,
|
||||
.scrollbar-none:focus::-webkit-scrollbar-thumb,
|
||||
.scrollbar-none:hover::-webkit-scrollbar-thumb {
|
||||
.scrollbar-hidden:active::-webkit-scrollbar-thumb,
|
||||
.scrollbar-hidden:focus::-webkit-scrollbar-thumb,
|
||||
.scrollbar-hidden:hover::-webkit-scrollbar-thumb {
|
||||
visibility: visible;
|
||||
}
|
||||
.scrollbar-none::-webkit-scrollbar-thumb {
|
||||
.scrollbar-hidden::-webkit-scrollbar-thumb {
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col h-full justify-between text-sm">
|
||||
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[22rem]">
|
||||
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[25rem]">
|
||||
<input
|
||||
id="profile-image-input"
|
||||
bind:this={profileImageInputElement}
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
{#if keepAlive !== null}
|
||||
<div class="flex mt-1 space-x-2">
|
||||
<input
|
||||
class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600"
|
||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
type="text"
|
||||
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
|
||||
bind:value={keepAlive}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Seed')}</div>
|
||||
<div class=" flex-1 self-center">
|
||||
<input
|
||||
class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600"
|
||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
type="number"
|
||||
placeholder="Enter Seed"
|
||||
bind:value={options.seed}
|
||||
@@ -43,7 +43,7 @@
|
||||
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Stop Sequence')}</div>
|
||||
<div class=" flex-1 self-center">
|
||||
<input
|
||||
class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600"
|
||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
type="text"
|
||||
placeholder={$i18n.t('Enter stop sequence')}
|
||||
bind:value={options.stop}
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
dispatch('save');
|
||||
}}
|
||||
>
|
||||
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[22rem]">
|
||||
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[25rem]">
|
||||
<div>
|
||||
<div class=" mb-1 text-sm font-medium">{$i18n.t('STT Settings')}</div>
|
||||
|
||||
@@ -345,7 +345,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end pt-3 text-sm font-medium">
|
||||
<div class="flex justify-end text-sm font-medium">
|
||||
<button
|
||||
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
|
||||
type="submit"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
dispatch('save');
|
||||
}}
|
||||
>
|
||||
<div class=" pr-1.5 overflow-y-scroll max-h-[22rem] space-y-3">
|
||||
<div class=" pr-1.5 overflow-y-scroll max-h-[25rem] space-y-3">
|
||||
<div class=" space-y-3">
|
||||
<div class="mt-2 space-y-2 pr-1.5">
|
||||
<div class="flex justify-between items-center text-sm">
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col h-full justify-between text-sm">
|
||||
<div class=" pr-1.5 overflow-y-scroll max-h-[22rem]">
|
||||
<div class=" pr-1.5 overflow-y-scroll max-h-[25rem]">
|
||||
<div class="">
|
||||
<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Settings')}</div>
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
{#if keepAlive !== null}
|
||||
<div class="flex mt-1 space-x-2">
|
||||
<input
|
||||
class="w-full rounded py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-800 outline-none border border-gray-100 dark:border-gray-600"
|
||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||
type="text"
|
||||
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
|
||||
bind:value={keepAlive}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
// Interface
|
||||
let promptSuggestions = [];
|
||||
let showUsername = false;
|
||||
let chatBubble = true;
|
||||
let chatDirection: 'LTR' | 'RTL' = 'LTR';
|
||||
|
||||
const toggleSplitLargeChunks = async () => {
|
||||
@@ -34,6 +35,11 @@
|
||||
saveSettings({ fullScreenMode: fullScreenMode });
|
||||
};
|
||||
|
||||
const toggleChatBubble = async () => {
|
||||
chatBubble = !chatBubble;
|
||||
saveSettings({ chatBubble: chatBubble });
|
||||
};
|
||||
|
||||
const toggleShowUsername = async () => {
|
||||
showUsername = !showUsername;
|
||||
saveSettings({ showUsername: showUsername });
|
||||
@@ -111,6 +117,7 @@
|
||||
|
||||
responseAutoCopy = settings.responseAutoCopy ?? false;
|
||||
showUsername = settings.showUsername ?? false;
|
||||
chatBubble = settings.chatBubble ?? true;
|
||||
fullScreenMode = settings.fullScreenMode ?? false;
|
||||
splitLargeChunks = settings.splitLargeChunks ?? false;
|
||||
chatDirection = settings.chatDirection ?? 'LTR';
|
||||
@@ -124,10 +131,30 @@
|
||||
dispatch('save');
|
||||
}}
|
||||
>
|
||||
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[22rem]">
|
||||
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-[25rem]">
|
||||
<div>
|
||||
<div class=" mb-1 text-sm font-medium">{$i18n.t('WebUI Add-ons')}</div>
|
||||
|
||||
<div>
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">{$i18n.t('Chat Bubble UI')}</div>
|
||||
|
||||
<button
|
||||
class="p-1 px-3 text-xs flex rounded transition"
|
||||
on:click={() => {
|
||||
toggleChatBubble();
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{#if chatBubble === true}
|
||||
<span class="ml-2 self-center">{$i18n.t('On')}</span>
|
||||
{:else}
|
||||
<span class="ml-2 self-center">{$i18n.t('Off')}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">{$i18n.t('Title Auto-Generation')}</div>
|
||||
@@ -308,7 +335,7 @@
|
||||
{#if $user.role === 'admin'}
|
||||
<hr class=" dark:border-gray-700" />
|
||||
|
||||
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
|
||||
<div class=" space-y-3 pr-1.5">
|
||||
<div class="flex w-full justify-between mb-2">
|
||||
<div class=" self-center text-sm font-semibold">
|
||||
{$i18n.t('Default Prompt Suggestions')}
|
||||
|
||||
@@ -165,6 +165,32 @@
|
||||
<div class=" self-center">{$i18n.t('Interface')}</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||
'interface'
|
||||
? 'bg-gray-200 dark:bg-gray-700'
|
||||
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
|
||||
on:click={() => {
|
||||
selectedTab = 'interface';
|
||||
}}
|
||||
>
|
||||
<div class=" self-center mr-2">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
d="M2 4.25A2.25 2.25 0 0 1 4.25 2h7.5A2.25 2.25 0 0 1 14 4.25v5.5A2.25 2.25 0 0 1 11.75 12h-1.312c.1.128.21.248.328.36a.75.75 0 0 1 .234.545v.345a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1-.75-.75v-.345a.75.75 0 0 1 .234-.545c.118-.111.228-.232.328-.36H4.25A2.25 2.25 0 0 1 2 9.75v-5.5Zm2.25-.75a.75.75 0 0 0-.75.75v4.5c0 .414.336.75.75.75h7.5a.75.75 0 0 0 .75-.75v-4.5a.75.75 0 0 0-.75-.75h-7.5Z"
|
||||
clip-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class=" self-center">{$i18n.t('Interface')}</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||
'audio'
|
||||
@@ -298,7 +324,7 @@
|
||||
<div class=" self-center">{$i18n.t('About')}</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex-1 md:min-h-[25rem]">
|
||||
<div class="flex-1 md:min-h-[28rem]">
|
||||
{#if selectedTab === 'general'}
|
||||
<General
|
||||
{getModels}
|
||||
|
||||
@@ -57,10 +57,23 @@
|
||||
|
||||
export let show = false;
|
||||
|
||||
const isDifferentChat = (_chat) => {
|
||||
if (!chat) {
|
||||
return true;
|
||||
}
|
||||
if (!_chat) {
|
||||
return false;
|
||||
}
|
||||
return chat.id !== _chat.id || chat.share_id !== _chat.share_id;
|
||||
}
|
||||
|
||||
$: if (show) {
|
||||
(async () => {
|
||||
if (chatId) {
|
||||
chat = await getChatById(localStorage.token, chatId);
|
||||
const _chat = await getChatById(localStorage.token, chatId);
|
||||
if (isDifferentChat(_chat)) {
|
||||
chat = _chat;
|
||||
}
|
||||
} else {
|
||||
chat = null;
|
||||
console.log(chat);
|
||||
@@ -137,6 +150,7 @@
|
||||
<button
|
||||
class=" self-center flex items-center gap-1 px-3.5 py-2 rounded-xl text-sm font-medium bg-emerald-600 hover:bg-emerald-500 text-white"
|
||||
type="button"
|
||||
id="copy-and-share-chat-button"
|
||||
on:click={async () => {
|
||||
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user