Unverified Commit 92c98eda authored by Timothy Jaeryang Baek's avatar Timothy Jaeryang Baek Committed by GitHub
Browse files

Merge pull request #1781 from open-webui/dev

0.1.122
parents 1092ee9c 85df019c
...@@ -193,7 +193,7 @@ ...@@ -193,7 +193,7 @@
<div class=" mt-2 mb-1 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
id="save-edit-message-button" id="save-edit-message-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-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg-lg"
on:click={() => { on:click={() => {
editMessageConfirmHandler(); editMessageConfirmHandler();
}} }}
......
...@@ -125,7 +125,7 @@ ...@@ -125,7 +125,7 @@
<div class="flex justify-end pt-3 text-sm font-medium"> <div class="flex justify-end pt-3 text-sm font-medium">
<button <button
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded" class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
on:click={() => { on:click={() => {
saveSettings({ saveSettings({
options: { options: {
......
...@@ -147,8 +147,8 @@ ...@@ -147,8 +147,8 @@
<option value="dark">🌑 {$i18n.t('Dark')}</option> <option value="dark">🌑 {$i18n.t('Dark')}</option>
<option value="oled-dark">🌃 {$i18n.t('OLED Dark')}</option> <option value="oled-dark">🌃 {$i18n.t('OLED Dark')}</option>
<option value="light">☀️ {$i18n.t('Light')}</option> <option value="light">☀️ {$i18n.t('Light')}</option>
<option value="rose-pine dark">🪻 {$i18n.t('Rosé Pine')}</option> <!-- <option value="rose-pine dark">🪻 {$i18n.t('Rosé Pine')}</option>
<option value="rose-pine-dawn light">🌷 {$i18n.t('Rosé Pine Dawn')}</option> <option value="rose-pine-dawn light">🌷 {$i18n.t('Rosé Pine Dawn')}</option> -->
</select> </select>
</div> </div>
</div> </div>
......
...@@ -161,7 +161,7 @@ ...@@ -161,7 +161,7 @@
<div class="flex justify-end pt-5 text-sm font-medium"> <div class="flex justify-end pt-5 text-sm font-medium">
<button <button
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded" class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
type="submit" type="submit"
> >
{$i18n.t('Save')} {$i18n.t('Save')}
......
...@@ -158,7 +158,7 @@ ...@@ -158,7 +158,7 @@
<div class="flex justify-end pt-5 text-sm font-medium"> <div class="flex justify-end pt-5 text-sm font-medium">
<button <button
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded" class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
type="submit" type="submit"
> >
{$i18n.t('Save')} {$i18n.t('Save')}
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
updateQuerySettings, updateQuerySettings,
resetVectorDB, resetVectorDB,
getEmbeddingConfig, getEmbeddingConfig,
updateEmbeddingConfig updateEmbeddingConfig,
getRerankingConfig,
updateRerankingConfig
} from '$lib/apis/rag'; } from '$lib/apis/rag';
import { documents, models } from '$lib/stores'; import { documents, models } from '$lib/stores';
...@@ -23,11 +25,13 @@ ...@@ -23,11 +25,13 @@
let scanDirLoading = false; let scanDirLoading = false;
let updateEmbeddingModelLoading = false; let updateEmbeddingModelLoading = false;
let updateRerankingModelLoading = false;
let showResetConfirm = false; let showResetConfirm = false;
let embeddingEngine = ''; let embeddingEngine = '';
let embeddingModel = ''; let embeddingModel = '';
let rerankingModel = '';
let OpenAIKey = ''; let OpenAIKey = '';
let OpenAIUrl = ''; let OpenAIUrl = '';
...@@ -38,7 +42,9 @@ ...@@ -38,7 +42,9 @@
let querySettings = { let querySettings = {
template: '', template: '',
k: 4 r: 0.0,
k: 4,
hybrid: false
}; };
const scanHandler = async () => { const scanHandler = async () => {
...@@ -115,6 +121,29 @@ ...@@ -115,6 +121,29 @@
} }
}; };
const rerankingModelUpdateHandler = async () => {
console.log('Update reranking model attempt:', rerankingModel);
updateRerankingModelLoading = true;
const res = await updateRerankingConfig(localStorage.token, {
reranking_model: rerankingModel
}).catch(async (error) => {
toast.error(error);
await setRerankingConfig();
return null;
});
updateRerankingModelLoading = false;
if (res) {
console.log('rerankingModelUpdateHandler:', res);
if (res.status === true) {
toast.success($i18n.t('Reranking model set to "{{reranking_model}}"', res), {
duration: 1000 * 10
});
}
}
};
const submitHandler = async () => { const submitHandler = async () => {
const res = await updateRAGConfig(localStorage.token, { const res = await updateRAGConfig(localStorage.token, {
pdf_extract_images: pdfExtractImages, pdf_extract_images: pdfExtractImages,
...@@ -138,6 +167,20 @@ ...@@ -138,6 +167,20 @@
} }
}; };
const setRerankingConfig = async () => {
const rerankingConfig = await getRerankingConfig(localStorage.token);
if (rerankingConfig) {
rerankingModel = rerankingConfig.reranking_model;
}
};
const toggleHybridSearch = async () => {
querySettings.hybrid = !querySettings.hybrid;
querySettings = await updateQuerySettings(localStorage.token, querySettings);
};
onMount(async () => { onMount(async () => {
const res = await getRAGConfig(localStorage.token); const res = await getRAGConfig(localStorage.token);
...@@ -149,6 +192,7 @@ ...@@ -149,6 +192,7 @@
} }
await setEmbeddingConfig(); await setEmbeddingConfig();
await setRerankingConfig();
querySettings = await getQuerySettings(localStorage.token); querySettings = await getQuerySettings(localStorage.token);
}); });
...@@ -165,6 +209,24 @@ ...@@ -165,6 +209,24 @@
<div> <div>
<div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div> <div class=" mb-2 text-sm font-medium">{$i18n.t('General Settings')}</div>
<div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Hybrid Search')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
on:click={() => {
toggleHybridSearch();
}}
type="button"
>
{#if querySettings.hybrid === 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 class=" flex w-full justify-between"> <div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Embedding Model Engine')}</div> <div class=" self-center text-xs font-medium">{$i18n.t('Embedding Model Engine')}</div>
<div class="flex items-center relative"> <div class="flex items-center relative">
...@@ -349,6 +411,75 @@ ...@@ -349,6 +411,75 @@
<hr class=" dark:border-gray-700 my-3" /> <hr class=" dark:border-gray-700 my-3" />
{#if querySettings.hybrid === true}
<div class=" ">
<div class=" mb-2 text-sm font-medium">{$i18n.t('Update Reranking Model')}</div>
<div class="flex w-full">
<div class="flex-1 mr-2">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
placeholder={$i18n.t('Update reranking model (e.g. {{model}})', {
model: rerankingModel.slice(-40)
})}
bind:value={rerankingModel}
/>
</div>
<button
class="px-2.5 bg-gray-100 hover:bg-gray-200 text-gray-800 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-100 rounded-lg transition"
on:click={() => {
rerankingModelUpdateHandler();
}}
disabled={updateRerankingModelLoading}
>
{#if updateRerankingModelLoading}
<div class="self-center">
<svg
class=" w-4 h-4"
viewBox="0 0 24 24"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
><style>
.spinner_ajPY {
transform-origin: center;
animation: spinner_AtaB 0.75s infinite linear;
}
@keyframes spinner_AtaB {
100% {
transform: rotate(360deg);
}
}
</style><path
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
opacity=".25"
/><path
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
class="spinner_ajPY"
/></svg
>
</div>
{:else}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M8.75 2.75a.75.75 0 0 0-1.5 0v5.69L5.03 6.22a.75.75 0 0 0-1.06 1.06l3.5 3.5a.75.75 0 0 0 1.06 0l3.5-3.5a.75.75 0 0 0-1.06-1.06L8.75 8.44V2.75Z"
/>
<path
d="M3.5 9.75a.75.75 0 0 0-1.5 0v1.5A2.75 2.75 0 0 0 4.75 14h6.5A2.75 2.75 0 0 0 14 11.25v-1.5a.75.75 0 0 0-1.5 0v1.5c0 .69-.56 1.25-1.25 1.25h-6.5c-.69 0-1.25-.56-1.25-1.25v-1.5Z"
/>
</svg>
{/if}
</button>
</div>
</div>
<hr class=" dark:border-gray-700 my-3" />
{/if}
<div class=" flex w-full justify-between"> <div class=" flex w-full justify-between">
<div class=" self-center text-xs font-medium"> <div class=" self-center text-xs font-medium">
{$i18n.t('Scan for documents from {{path}}', { path: '/data/docs' })} {$i18n.t('Scan for documents from {{path}}', { path: '/data/docs' })}
...@@ -473,6 +604,28 @@ ...@@ -473,6 +604,28 @@
</div> </div>
</div> </div>
{#if querySettings.hybrid === true}
<div class=" flex">
<div class=" flex w-full justify-between">
<div class="self-center text-xs font-medium flex-1">
{$i18n.t('Relevance Threshold')}
</div>
<div class="self-center p-3">
<input
class=" w-full rounded-lg py-1.5 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="number"
step="0.01"
placeholder={$i18n.t('Enter Relevance Threshold')}
bind:value={querySettings.r}
autocomplete="off"
min="0.0"
/>
</div>
</div>
</div>
{/if}
<div> <div>
<div class=" mb-2.5 text-sm font-medium">{$i18n.t('RAG Template')}</div> <div class=" mb-2.5 text-sm font-medium">{$i18n.t('RAG Template')}</div>
<textarea <textarea
...@@ -581,7 +734,7 @@ ...@@ -581,7 +734,7 @@
</div> </div>
<div class="flex justify-end pt-3 text-sm font-medium"> <div class="flex justify-end pt-3 text-sm font-medium">
<button <button
class=" px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-gray-100 transition rounded" class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
type="submit" type="submit"
> >
{$i18n.t('Save')} {$i18n.t('Save')}
......
<script lang="ts">
export let className = 'size-4';
export let strokeWidth = '1.5';
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width={strokeWidth}
stroke="currentColor"
class={className}
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.625 12a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H8.25m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H12m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 0 1-2.555-.337A5.972 5.972 0 0 1 5.41 20.97a5.969 5.969 0 0 1-.474-.065 4.48 4.48 0 0 0 .978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25Z"
/>
</svg>
<script lang="ts">
export let className = 'size-4';
export let strokeWidth = '1.5';
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width={strokeWidth}
stroke="currentColor"
class={className}
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M20.25 8.511c.884.284 1.5 1.128 1.5 2.097v4.286c0 1.136-.847 2.1-1.98 2.193-.34.027-.68.052-1.02.072v3.091l-3-3c-1.354 0-2.694-.055-4.02-.163a2.115 2.115 0 0 1-.825-.242m9.345-8.334a2.126 2.126 0 0 0-.476-.095 48.64 48.64 0 0 0-8.048 0c-1.131.094-1.976 1.057-1.976 2.192v4.286c0 .837.46 1.58 1.155 1.951m9.345-8.334V6.637c0-1.621-1.152-3.026-2.76-3.235A48.455 48.455 0 0 0 11.25 3c-2.115 0-4.198.137-6.24.402-1.608.209-2.76 1.614-2.76 3.235v6.226c0 1.621 1.152 3.026 2.76 3.235.577.075 1.157.14 1.74.194V21l4.155-4.155"
/>
</svg>
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
import fileSaver from 'file-saver'; import fileSaver from 'file-saver';
const { saveAs } = fileSaver; const { saveAs } = fileSaver;
import { jsPDF } from 'jspdf';
import { showSettings } from '$lib/stores'; import { showSettings } from '$lib/stores';
import { flyAndScale } from '$lib/utils/transitions'; import { flyAndScale } from '$lib/utils/transitions';
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
import ArchiveBox from '../icons/ArchiveBox.svelte'; import ArchiveBox from '../icons/ArchiveBox.svelte';
import ArchivedChatsModal from './Sidebar/ArchivedChatsModal.svelte'; import ArchivedChatsModal from './Sidebar/ArchivedChatsModal.svelte';
const BREAKPOINT = 1024;
let show = false; let show = false;
let navElement; let navElement;
...@@ -49,9 +50,7 @@ ...@@ -49,9 +50,7 @@
let isEditing = false; let isEditing = false;
onMount(async () => { onMount(async () => {
if (window.innerWidth > 1024) { show = window.innerWidth > BREAKPOINT;
show = true;
}
await chats.set(await getChatList(localStorage.token)); await chats.set(await getChatList(localStorage.token));
let touchstartX = 0; let touchstartX = 0;
...@@ -79,12 +78,20 @@ ...@@ -79,12 +78,20 @@
checkDirection(); checkDirection();
}; };
const onResize = () => {
if (show && window.innerWidth < BREAKPOINT) {
show = false;
}
};
document.addEventListener('touchstart', onTouchStart); document.addEventListener('touchstart', onTouchStart);
document.addEventListener('touchend', onTouchEnd); document.addEventListener('touchend', onTouchEnd);
window.addEventListener('resize', onResize);
return () => { return () => {
document.removeEventListener('touchstart', onTouchStart); document.removeEventListener('touchstart', onTouchStart);
document.removeEventListener('touchend', onTouchEnd); document.removeEventListener('touchend', onTouchEnd);
document.removeEventListener('resize', onResize);
}; };
}); });
...@@ -172,7 +179,7 @@ ...@@ -172,7 +179,7 @@
<div class="px-2 flex justify-center space-x-2"> <div class="px-2 flex justify-center space-x-2">
<a <a
id="sidebar-new-chat-button" id="sidebar-new-chat-button"
class="flex-grow flex justify-between rounded-xl px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-900 transition" class="flex-grow flex justify-between rounded-xl px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-900 transition"
href="/" href="/"
on:click={async () => { on:click={async () => {
selectedChatId = null; selectedChatId = null;
...@@ -217,7 +224,7 @@ ...@@ -217,7 +224,7 @@
{#if $user?.role === 'admin'} {#if $user?.role === 'admin'}
<div class="px-2 flex justify-center mt-0.5"> <div class="px-2 flex justify-center mt-0.5">
<a <a
class="flex-grow flex space-x-3 rounded-xl px-3.5 py-2 hover:bg-gray-200 dark:hover:bg-gray-900 transition" class="flex-grow flex space-x-3 rounded-xl px-3.5 py-2 hover:bg-gray-100 dark:hover:bg-gray-900 transition"
href="/modelfiles" href="/modelfiles"
on:click={() => { on:click={() => {
selectedChatId = null; selectedChatId = null;
...@@ -249,7 +256,7 @@ ...@@ -249,7 +256,7 @@
<div class="px-2 flex justify-center"> <div class="px-2 flex justify-center">
<a <a
class="flex-grow flex space-x-3 rounded-xl px-3.5 py-2 hover:bg-gray-200 dark:hover:bg-gray-900 transition" class="flex-grow flex space-x-3 rounded-xl px-3.5 py-2 hover:bg-gray-100 dark:hover:bg-gray-900 transition"
href="/prompts" href="/prompts"
on:click={() => { on:click={() => {
selectedChatId = null; selectedChatId = null;
...@@ -281,7 +288,7 @@ ...@@ -281,7 +288,7 @@
<div class="px-2 flex justify-center mb-1"> <div class="px-2 flex justify-center mb-1">
<a <a
class="flex-grow flex space-x-3 rounded-xl px-3.5 py-2 hover:bg-gray-200 dark:hover:bg-gray-900 transition" class="flex-grow flex space-x-3 rounded-xl px-3.5 py-2 hover:bg-gray-100 dark:hover:bg-gray-900 transition"
href="/documents" href="/documents"
on:click={() => { on:click={() => {
selectedChatId = null; selectedChatId = null;
...@@ -328,7 +335,7 @@ ...@@ -328,7 +335,7 @@
<div class="mt-3"> <div class="mt-3">
<button <button
class="flex justify-center items-center space-x-1.5 px-3 py-2.5 rounded-lg text-xs bg-gray-200 hover:bg-gray-300 transition text-gray-800 font-medium w-full" class="flex justify-center items-center space-x-1.5 px-3 py-2.5 rounded-lg text-xs bg-gray-100 hover:bg-gray-200 transition text-gray-800 font-medium w-full"
type="button" type="button"
on:click={() => { on:click={() => {
saveSettings({ saveSettings({
...@@ -438,7 +445,7 @@ ...@@ -438,7 +445,7 @@
class=" w-full flex justify-between rounded-xl px-3 py-2 {chat.id === $chatId || class=" w-full flex justify-between rounded-xl px-3 py-2 {chat.id === $chatId ||
chat.id === chatTitleEditId || chat.id === chatTitleEditId ||
chat.id === chatDeleteId chat.id === chatDeleteId
? 'bg-gray-300 dark:bg-gray-900' ? 'bg-gray-200 dark:bg-gray-900'
: chat.id === selectedChatId : chat.id === selectedChatId
? 'bg-gray-100 dark:bg-gray-950' ? 'bg-gray-100 dark:bg-gray-950'
: 'group-hover:bg-gray-100 dark:group-hover:bg-gray-950'} whitespace-nowrap text-ellipsis" : 'group-hover:bg-gray-100 dark:group-hover:bg-gray-950'} whitespace-nowrap text-ellipsis"
...@@ -450,7 +457,7 @@ ...@@ -450,7 +457,7 @@
class=" w-full flex justify-between rounded-xl px-3 py-2 {chat.id === $chatId || class=" w-full flex justify-between rounded-xl px-3 py-2 {chat.id === $chatId ||
chat.id === chatTitleEditId || chat.id === chatTitleEditId ||
chat.id === chatDeleteId chat.id === chatDeleteId
? 'bg-gray-300 dark:bg-gray-900' ? 'bg-gray-200 dark:bg-gray-900'
: chat.id === selectedChatId : chat.id === selectedChatId
? 'bg-gray-100 dark:bg-gray-950' ? 'bg-gray-100 dark:bg-gray-950'
: ' group-hover:bg-gray-100 dark:group-hover:bg-gray-950'} whitespace-nowrap text-ellipsis" : ' group-hover:bg-gray-100 dark:group-hover:bg-gray-950'} whitespace-nowrap text-ellipsis"
...@@ -473,14 +480,14 @@ ...@@ -473,14 +480,14 @@
<div <div
class=" class="
{chat.id === $chatId || chat.id === chatTitleEditId || chat.id === chatDeleteId {chat.id === $chatId || chat.id === chatTitleEditId || chat.id === chatDeleteId
? 'from-gray-300 dark:from-gray-900' ? 'from-gray-200 dark:from-gray-900'
: chat.id === selectedChatId : chat.id === selectedChatId
? 'from-gray-100 dark:from-gray-950' ? 'from-gray-100 dark:from-gray-950'
: 'invisible group-hover:visible from-gray-100 dark:from-gray-950'} : 'invisible group-hover:visible from-gray-100 dark:from-gray-950'}
absolute right-[10px] top-[10px] pr-2 pl-5 bg-gradient-to-l from-80% absolute right-[10px] top-[10px] pr-2 pl-5 bg-gradient-to-l from-80%
to-transparent" to-transparent"
> >
{#if chatTitleEditId === chat.id} {#if chatTitleEditId === chat.id}
...@@ -628,7 +635,7 @@ ...@@ -628,7 +635,7 @@
<div class="flex flex-col"> <div class="flex flex-col">
{#if $user !== undefined} {#if $user !== undefined}
<button <button
class=" flex rounded-xl py-3 px-3.5 w-full hover:bg-gray-200 dark:hover:bg-gray-900 transition" class=" flex rounded-xl py-3 px-3.5 w-full hover:bg-gray-100 dark:hover:bg-gray-900 transition"
on:click={() => { on:click={() => {
showDropdown = !showDropdown; showDropdown = !showDropdown;
}} }}
......
...@@ -69,9 +69,9 @@ ...@@ -69,9 +69,9 @@
{#if chats.length > 0} {#if chats.length > 0}
<div class="text-left text-sm w-full mb-4 max-h-[22rem] overflow-y-scroll"> <div class="text-left text-sm w-full mb-4 max-h-[22rem] overflow-y-scroll">
<div class="relative overflow-x-auto"> <div class="relative overflow-x-auto">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400 table-auto"> <table class="w-full text-sm text-left text-gray-600 dark:text-gray-400 table-auto">
<thead <thead
class="text-xs text-gray-700 uppercase bg-transparent dark:text-gray-200 border-b-2 border-gray-800" class="text-xs text-gray-700 uppercase bg-transparent dark:text-gray-200 border-b-2 dark:border-gray-800"
> >
<tr> <tr>
<th scope="col" class="px-3 py-2"> {$i18n.t('Name')} </th> <th scope="col" class="px-3 py-2"> {$i18n.t('Name')} </th>
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
<tbody> <tbody>
{#each chats as chat, idx} {#each chats as chat, idx}
<tr <tr
class="bg-white {idx !== chats.length - 1 && class="bg-transparent {idx !== chats.length - 1 &&
'border-b'} dark:bg-gray-900 dark:border-gray-850 text-xs" 'border-b'} dark:bg-gray-900 dark:border-gray-850 text-xs"
> >
<td class="px-3 py-1 w-2/3"> <td class="px-3 py-1 w-2/3">
......
This diff is collapsed.
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
"available!": "¡disponible!", "available!": "¡disponible!",
"Back": "Vuelve atrás", "Back": "Vuelve atrás",
"Builder Mode": "Modo de Constructor", "Builder Mode": "Modo de Constructor",
"Cancel": "Cancela", "Cancel": "Cancelar",
"Categories": "Categorías", "Categories": "Categorías",
"Change Password": "Cambia la Contraseña", "Change Password": "Cambia la Contraseña",
"Chat": "Chat", "Chat": "Chat",
...@@ -152,6 +152,7 @@ ...@@ -152,6 +152,7 @@
"File Mode": "Modo de archivo", "File Mode": "Modo de archivo",
"File not found.": "Archivo no encontrado.", "File not found.": "Archivo no encontrado.",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Se detectó suplantación de huellas: No se pueden usar las iniciales como avatar. Por defecto se utiliza la imagen de perfil predeterminada.", "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Se detectó suplantación de huellas: No se pueden usar las iniciales como avatar. Por defecto se utiliza la imagen de perfil predeterminada.",
"Fluidly stream large external response chunks": "Transmita con fluidez grandes fragmentos de respuesta externa",
"Focus chat input": "Enfoca la entrada del chat", "Focus chat input": "Enfoca la entrada del chat",
"Format your variables using square brackets like this:": "Formatee sus variables usando corchetes así:", "Format your variables using square brackets like this:": "Formatee sus variables usando corchetes así:",
"From (Base Model)": "Desde (Modelo Base)", "From (Base Model)": "Desde (Modelo Base)",
......
...@@ -7,6 +7,10 @@ ...@@ -7,6 +7,10 @@
"code": "bg-BG", "code": "bg-BG",
"title": "Bulgarian (BG)" "title": "Bulgarian (BG)"
}, },
{
"code": "bn-BD",
"title": "Banlga (বাংলা)"
},
{ {
"code": "ca-ES", "code": "ca-ES",
"title": "Catalan" "title": "Catalan"
......
...@@ -120,6 +120,7 @@ ...@@ -120,6 +120,7 @@
"Edit Doc": "Belgeyi Düzenle", "Edit Doc": "Belgeyi Düzenle",
"Edit User": "Kullanıcıyı Düzenle", "Edit User": "Kullanıcıyı Düzenle",
"Email": "E-posta", "Email": "E-posta",
"Embedding model: {{embedding_model}}": "Gömme modeli: {{embedding_model}}",
"Enable Chat History": "Sohbet Geçmişini Etkinleştir", "Enable Chat History": "Sohbet Geçmişini Etkinleştir",
"Enable New Sign Ups": "Yeni Kayıtları Etkinleştir", "Enable New Sign Ups": "Yeni Kayıtları Etkinleştir",
"Enabled": "Etkin", "Enabled": "Etkin",
...@@ -150,6 +151,8 @@ ...@@ -150,6 +151,8 @@
"Failed to read clipboard contents": "Pano içeriği okunamadı", "Failed to read clipboard contents": "Pano içeriği okunamadı",
"File Mode": "Dosya Modu", "File Mode": "Dosya Modu",
"File not found.": "Dosya bulunamadı.", "File not found.": "Dosya bulunamadı.",
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Parmak izi sahteciliği tespit edildi: Avatar olarak baş harfler kullanılamıyor. Varsayılan profil resmine dönülüyor.",
"Fluidly stream large external response chunks": "Büyük harici yanıt chunklarını akıcı bir şekilde yayınlayın",
"Focus chat input": "Sohbet girişine odaklan", "Focus chat input": "Sohbet girişine odaklan",
"Format your variables using square brackets like this:": "Değişkenlerinizi şu şekilde kare parantezlerle biçimlendirin:", "Format your variables using square brackets like this:": "Değişkenlerinizi şu şekilde kare parantezlerle biçimlendirin:",
"From (Base Model)": "(Temel Model)'den", "From (Base Model)": "(Temel Model)'den",
...@@ -193,8 +196,11 @@ ...@@ -193,8 +196,11 @@
"MMMM DD, YYYY": "DD MMMM YYYY", "MMMM DD, YYYY": "DD MMMM YYYY",
"Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' başarıyla indirildi.", "Model '{{modelName}}' has been successfully downloaded.": "'{{modelName}}' başarıyla indirildi.",
"Model '{{modelTag}}' is already in queue for downloading.": "'{{modelTag}}' zaten indirme sırasında.", "Model '{{modelTag}}' is already in queue for downloading.": "'{{modelTag}}' zaten indirme sırasında.",
"Model {{embedding_model}} update complete!": "Model {{embedding_model}} güncellemesi tamamlandı!",
"Model {{embedding_model}} update failed or not required!": "Model {{embedding_model}} güncellemesi başarısız oldu veya gerekli değil!",
"Model {{modelId}} not found": "{{modelId}} bulunamadı", "Model {{modelId}} not found": "{{modelId}} bulunamadı",
"Model {{modelName}} already exists.": "{{modelName}} zaten mevcut.", "Model {{modelName}} already exists.": "{{modelName}} zaten mevcut.",
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Model dosya sistemi yolu algılandı. Güncelleme için model kısa adı gerekli, devam edilemiyor.",
"Model Name": "Model Adı", "Model Name": "Model Adı",
"Model not selected": "Model seçilmedi", "Model not selected": "Model seçilmedi",
"Model Tag Name": "Model Etiket Adı", "Model Tag Name": "Model Etiket Adı",
...@@ -332,7 +338,10 @@ ...@@ -332,7 +338,10 @@
"TTS Settings": "TTS Ayarları", "TTS Settings": "TTS Ayarları",
"Type Hugging Face Resolve (Download) URL": "Hugging Face Resolve (Download) URL'sini Yazın", "Type Hugging Face Resolve (Download) URL": "Hugging Face Resolve (Download) URL'sini Yazın",
"Uh-oh! There was an issue connecting to {{provider}}.": "Ah! {{provider}}'a bağlanırken bir sorun oluştu.", "Uh-oh! There was an issue connecting to {{provider}}.": "Ah! {{provider}}'a bağlanırken bir sorun oluştu.",
"Understand that updating or changing your embedding model requires reset of the vector database and re-import of all documents. You have been warned!": "Gömme modelinizi güncellemenin veya değiştirmenin, vektör veritabanının sıfırlanmasını ve tüm belgelerin yeniden içe aktarılmasını gerektirdiğini anlayın. Uyarıldın!",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Bilinmeyen Dosya Türü '{{file_type}}', ancak düz metin olarak kabul ediliyor ve işleniyor", "Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Bilinmeyen Dosya Türü '{{file_type}}', ancak düz metin olarak kabul ediliyor ve işleniyor",
"Update": "Güncelleme",
"Update embedding model {{embedding_model}}": "Gömme modelini güncelle: {{embedding_model}}",
"Update password": "Parolayı Güncelle", "Update password": "Parolayı Güncelle",
"Upload a GGUF model": "Bir GGUF modeli yükle", "Upload a GGUF model": "Bir GGUF modeli yükle",
"Upload files": "Dosyaları Yükle", "Upload files": "Dosyaları Yükle",
...@@ -340,6 +349,7 @@ ...@@ -340,6 +349,7 @@
"URL Mode": "URL Modu", "URL Mode": "URL Modu",
"Use '#' in the prompt input to load and select your documents.": "Belgelerinizi yüklemek ve seçmek için promptda '#' kullanın.", "Use '#' in the prompt input to load and select your documents.": "Belgelerinizi yüklemek ve seçmek için promptda '#' kullanın.",
"Use Gravatar": "Gravatar Kullan", "Use Gravatar": "Gravatar Kullan",
"Use Initials": "Baş Harfleri Kullan",
"user": "kullanıcı", "user": "kullanıcı",
"User Permissions": "Kullanıcı İzinleri", "User Permissions": "Kullanıcı İzinleri",
"Users": "Kullanıcılar", "Users": "Kullanıcılar",
......
...@@ -341,7 +341,7 @@ ...@@ -341,7 +341,7 @@
"Use '#' in the prompt input to load and select your documents.": "Для введення промтів до веб-сторінок (URL) або вибору документів, будь ласка, використовуйте символ '#'.", "Use '#' in the prompt input to load and select your documents.": "Для введення промтів до веб-сторінок (URL) або вибору документів, будь ласка, використовуйте символ '#'.",
"Use Gravatar": "Змінити аватар", "Use Gravatar": "Змінити аватар",
"user": "користувач", "user": "користувач",
"User Permissions": "Дозволи користувача", "User Permissions": "Права користувача",
"Users": "Користувачі", "Users": "Користувачі",
"Utilize": "Використовувати", "Utilize": "Використовувати",
"Valid time units:": "Дійсні одиниці часу:", "Valid time units:": "Дійсні одиниці часу:",
......
...@@ -5,20 +5,20 @@ ...@@ -5,20 +5,20 @@
"(latest)": "", "(latest)": "",
"{{modelName}} is thinking...": "{{modelName}} 正在思考...", "{{modelName}} is thinking...": "{{modelName}} 正在思考...",
"{{webUIName}} Backend Required": "需要 {{webUIName}} 后端", "{{webUIName}} Backend Required": "需要 {{webUIName}} 后端",
"a user": "", "a user": "用户",
"About": "关于", "About": "关于",
"Account": "账户", "Account": "账户",
"Action": "操作", "Action": "操作",
"Add a model": "添加模型", "Add a model": "添加模型",
"Add a model tag name": "添加模型标签名称", "Add a model tag name": "添加模型标签名称",
"Add a short description about what this modelfile does": "添加关于此模型文件功能的简短描述", "Add a short description about what this modelfile does": "为这个模型文件添加一段简短描述",
"Add a short title for this prompt": "为这个提示添加一个简短的标题", "Add a short title for this prompt": "为这个提示添加一个简短的标题",
"Add a tag": "", "Add a tag": "添加标签",
"Add Docs": "添加文档", "Add Docs": "添加文档",
"Add Files": "添加文件", "Add Files": "添加文件",
"Add message": "添加消息", "Add message": "添加消息",
"add tags": "添加标签", "add tags": "添加标签",
"Adjusting these settings will apply changes universally to all users.": "调整这些设置将对所有用户普遍应用更改。", "Adjusting these settings will apply changes universally to all users.": "调整这些设置将对所有用户应用更改。",
"admin": "管理员", "admin": "管理员",
"Admin Panel": "管理员面板", "Admin Panel": "管理员面板",
"Admin Settings": "管理员设置", "Admin Settings": "管理员设置",
...@@ -26,15 +26,15 @@ ...@@ -26,15 +26,15 @@
"all": "所有", "all": "所有",
"All Users": "所有用户", "All Users": "所有用户",
"Allow": "允许", "Allow": "允许",
"Allow Chat Deletion": "允许删除聊天", "Allow Chat Deletion": "允许删除聊天记录",
"alphanumeric characters and hyphens": "字母数字字符和连字符", "alphanumeric characters and hyphens": "字母数字字符和连字符",
"Already have an account?": "已经有账户了吗?", "Already have an account?": "已经有账户了吗?",
"an assistant": "", "an assistant": "助手",
"and": "和", "and": "和",
"API Base URL": "API 基础 URL", "API Base URL": "API 基础 URL",
"API Key": "API 密钥", "API Key": "API 密钥",
"API RPM": "API RPM", "API RPM": "API RPM",
"are allowed - Activate this command by typing": "允许 - 通过输入激活命令", "are allowed - Activate this command by typing": "允许 - 通过输入激活这个命令",
"Are you sure?": "你确定吗?", "Are you sure?": "你确定吗?",
"Audio": "音频", "Audio": "音频",
"Auto-playback response": "自动播放回应", "Auto-playback response": "自动播放回应",
...@@ -43,21 +43,21 @@ ...@@ -43,21 +43,21 @@
"AUTOMATIC1111 Base URL is required.": "需要 AUTOMATIC1111 基础 URL。", "AUTOMATIC1111 Base URL is required.": "需要 AUTOMATIC1111 基础 URL。",
"available!": "可用!", "available!": "可用!",
"Back": "返回", "Back": "返回",
"Builder Mode": "构建模式", "Builder Mode": "构建模式",
"Cancel": "取消", "Cancel": "取消",
"Categories": "分类", "Categories": "分类",
"Change Password": "更改密码", "Change Password": "更改密码",
"Chat": "聊天", "Chat": "聊天",
"Chat History": "聊天历史", "Chat History": "聊天历史",
"Chat History is off for this browser.": "此浏览器已关闭聊天历史。", "Chat History is off for this browser.": "此浏览器已关闭聊天历史功能。",
"Chats": "聊天", "Chats": "聊天",
"Check Again": "再次检查", "Check Again": "再次检查",
"Check for updates": "检查更新", "Check for updates": "检查更新",
"Checking for updates...": "正在检查更新...", "Checking for updates...": "正在检查更新...",
"Choose a model before saving...": "保存前选择一个模型...", "Choose a model before saving...": "保存前选择一个模型...",
"Chunk Overlap": "块重叠", "Chunk Overlap": "块重叠(Chunk Overlap)",
"Chunk Params": "块参数", "Chunk Params": "块参数(Chunk Params)",
"Chunk Size": "块大小", "Chunk Size": "块大小(Chunk Size)",
"Click here for help.": "点击这里获取帮助。", "Click here for help.": "点击这里获取帮助。",
"Click here to check other modelfiles.": "点击这里检查其他模型文件。", "Click here to check other modelfiles.": "点击这里检查其他模型文件。",
"Click here to select": "点击这里选择", "Click here to select": "点击这里选择",
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
"Current Model": "当前模型", "Current Model": "当前模型",
"Current Password": "当前密码", "Current Password": "当前密码",
"Custom": "自定义", "Custom": "自定义",
"Customize Ollama models for a specific purpose": "为特定目的定制Ollama模型", "Customize Ollama models for a specific purpose": "定制特定用途的Ollama模型",
"Dark": "暗色", "Dark": "暗色",
"Database": "数据库", "Database": "数据库",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm", "DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
"Discover a prompt": "探索提示词", "Discover a prompt": "探索提示词",
"Discover, download, and explore custom prompts": "发现、下载并探索自定义提示词", "Discover, download, and explore custom prompts": "发现、下载并探索自定义提示词",
"Discover, download, and explore model presets": "发现、下载并探索模型预设", "Discover, download, and explore model presets": "发现、下载并探索模型预设",
"Display the username instead of You in the Chat": "在聊天中显示用户名而不是“”", "Display the username instead of You in the Chat": "在聊天中显示用户名而不是“”",
"Document": "文档", "Document": "文档",
"Document Settings": "文档设置", "Document Settings": "文档设置",
"Documents": "文档", "Documents": "文档",
...@@ -115,7 +115,7 @@ ...@@ -115,7 +115,7 @@
"Don't have an account?": "没有账户?", "Don't have an account?": "没有账户?",
"Download as a File": "下载为文件", "Download as a File": "下载为文件",
"Download Database": "下载数据库", "Download Database": "下载数据库",
"Drop any files here to add to the conversation": "将任何文件拖到这里以添加到对话中", "Drop any files here to add to the conversation": "拖动文件到此处以添加到对话中",
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "例如 '30s','10m'。有效的时间单位是's', 'm', 'h'。", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "例如 '30s','10m'。有效的时间单位是's', 'm', 'h'。",
"Edit Doc": "编辑文档", "Edit Doc": "编辑文档",
"Edit User": "编辑用户", "Edit User": "编辑用户",
...@@ -123,21 +123,21 @@ ...@@ -123,21 +123,21 @@
"Enable Chat History": "启用聊天历史", "Enable Chat History": "启用聊天历史",
"Enable New Sign Ups": "启用新注册", "Enable New Sign Ups": "启用新注册",
"Enabled": "启用", "Enabled": "启用",
"Enter {{role}} message here": "", "Enter {{role}} message here": "在此处输入 {{role}} 信息",
"Enter API Key": "", "Enter API Key": "输入API密匙",
"Enter Chunk Overlap": "", "Enter Chunk Overlap": "输入块重叠(Chunk Overlap)",
"Enter Chunk Size": "", "Enter Chunk Size": "输入块大小(Chunk Size)",
"Enter Image Size (e.g. 512x512)": "", "Enter Image Size (e.g. 512x512)": "输入图片大小(例如 512x512)",
"Enter LiteLLM API Base URL (litellm_params.api_base)": "", "Enter LiteLLM API Base URL (litellm_params.api_base)": "输入 LiteLLM API 基本 URL (litellm_params.api_base)",
"Enter LiteLLM API Key (litellm_params.api_key)": "", "Enter LiteLLM API Key (litellm_params.api_key)": "输入 LiteLLM API 密匙 (litellm_params.api_key)",
"Enter LiteLLM API RPM (litellm_params.rpm)": "", "Enter LiteLLM API RPM (litellm_params.rpm)": "输入 LiteLLM API 速率限制 (litellm_params.rpm)",
"Enter LiteLLM Model (litellm_params.model)": "", "Enter LiteLLM Model (litellm_params.model)": "输入 LiteLLM 模型 (litellm_params.model)",
"Enter Max Tokens (litellm_params.max_tokens)": "", "Enter Max Tokens (litellm_params.max_tokens)": "输入模型的 Max Tokens (litellm_params.max_tokens)",
"Enter model tag (e.g. {{modelTag}})": "", "Enter model tag (e.g. {{modelTag}})": "输入模型标签(例如{{modelTag}})",
"Enter Number of Steps (e.g. 50)": "", "Enter Number of Steps (e.g. 50)": "输入步数(例如50)",
"Enter stop sequence": "输入停止序列", "Enter stop sequence": "输入停止序列",
"Enter Top K": "", "Enter Top K": "输入 Top K",
"Enter URL (e.g. http://127.0.0.1:7860/)": "", "Enter URL (e.g. http://127.0.0.1:7860/)": "输入 URL (例如 http://127.0.0.1:7860/)",
"Enter Your Email": "输入您的电子邮件", "Enter Your Email": "输入您的电子邮件",
"Enter Your Full Name": "输入您的全名", "Enter Your Full Name": "输入您的全名",
"Enter Your Password": "输入您的密码", "Enter Your Password": "输入您的密码",
...@@ -159,7 +159,7 @@ ...@@ -159,7 +159,7 @@
"Hello, {{name}}": "你好,{{name}}", "Hello, {{name}}": "你好,{{name}}",
"Hide": "隐藏", "Hide": "隐藏",
"Hide Additional Params": "隐藏额外参数", "Hide Additional Params": "隐藏额外参数",
"How can I help you today?": "今天我如何能帮到你?", "How can I help you today?": "今天能帮你做什么?",
"Image Generation (Experimental)": "图像生成(实验性)", "Image Generation (Experimental)": "图像生成(实验性)",
"Image Generation Engine": "图像生成引擎", "Image Generation Engine": "图像生成引擎",
"Image Settings": "图像设置", "Image Settings": "图像设置",
...@@ -179,14 +179,14 @@ ...@@ -179,14 +179,14 @@
"Language": "语言", "Language": "语言",
"Light": "浅色", "Light": "浅色",
"Listening...": "监听中...", "Listening...": "监听中...",
"LLMs can make mistakes. Verify important information.": "大型语言模型可能会犯错。验证重要信息。", "LLMs can make mistakes. Verify important information.": "LLM可能会生成错误信息,请验证重要信息。",
"Made by OpenWebUI Community": "由OpenWebUI社区制作", "Made by OpenWebUI Community": "由OpenWebUI社区制作",
"Make sure to enclose them with": "确保将它们包含在内", "Make sure to enclose them with": "确保将它们包含在内",
"Manage LiteLLM Models": "管理LiteLLM模型", "Manage LiteLLM Models": "管理LiteLLM模型",
"Manage Models": "", "Manage Models": "管理模型",
"Manage Ollama Models": "管理Ollama模型", "Manage Ollama Models": "管理Ollama模型",
"Max Tokens": "最大令牌数", "Max Tokens": "最大令牌数",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多可以同时下载3个模型请稍后试。", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多可以同时下载3个模型请稍后试。",
"Mirostat": "Mirostat", "Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta", "Mirostat Eta": "Mirostat Eta",
"Mirostat Tau": "Mirostat Tau", "Mirostat Tau": "Mirostat Tau",
...@@ -198,8 +198,8 @@ ...@@ -198,8 +198,8 @@
"Model Name": "模型名称", "Model Name": "模型名称",
"Model not selected": "未选择模型", "Model not selected": "未选择模型",
"Model Tag Name": "模型标签名称", "Model Tag Name": "模型标签名称",
"Model Whitelisting": "", "Model Whitelisting": "白名单模型",
"Model(s) Whitelisted": "", "Model(s) Whitelisted": "模型已加入白名单",
"Modelfile": "模型文件", "Modelfile": "模型文件",
"Modelfile Advanced Settings": "模型文件高级设置", "Modelfile Advanced Settings": "模型文件高级设置",
"Modelfile Content": "模型文件内容", "Modelfile Content": "模型文件内容",
...@@ -207,7 +207,7 @@ ...@@ -207,7 +207,7 @@
"Models": "模型", "Models": "模型",
"My Documents": "我的文档", "My Documents": "我的文档",
"My Modelfiles": "我的模型文件", "My Modelfiles": "我的模型文件",
"My Prompts": "我的提示", "My Prompts": "我的提示",
"Name": "名称", "Name": "名称",
"Name Tag": "名称标签", "Name Tag": "名称标签",
"Name your modelfile": "命名你的模型文件", "Name your modelfile": "命名你的模型文件",
...@@ -221,7 +221,7 @@ ...@@ -221,7 +221,7 @@
"Ollama Version": "Ollama 版本", "Ollama Version": "Ollama 版本",
"On": "开", "On": "开",
"Only": "仅", "Only": "仅",
"Only alphanumeric characters and hyphens are allowed in the command string.": "命令字符串中只允许使用字母数字字符和连字符。", "Only alphanumeric characters and hyphens are allowed in the command string.": "命令字符串中只允许使用英文字母数字(0-9)以及连字符(-)。",
"Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "哎呀!请稍等!您的文件仍在处理中。我们正在将它们做得尽善尽美,请耐心等待,一旦准备好我们会通知您。", "Oops! Hold tight! Your files are still in the processing oven. We're cooking them up to perfection. Please be patient and we'll let you know once they're ready.": "哎呀!请稍等!您的文件仍在处理中。我们正在将它们做得尽善尽美,请耐心等待,一旦准备好我们会通知您。",
"Oops! Looks like the URL is invalid. Please double-check and try again.": "哎呀!看起来 URL 无效。请仔细检查后再试一次。", "Oops! Looks like the URL is invalid. Please double-check and try again.": "哎呀!看起来 URL 无效。请仔细检查后再试一次。",
"Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "哎呀!您正在使用不支持的方法(仅限前端)。请从后端提供 WebUI。", "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "哎呀!您正在使用不支持的方法(仅限前端)。请从后端提供 WebUI。",
...@@ -235,10 +235,10 @@ ...@@ -235,10 +235,10 @@
"or": "或", "or": "或",
"Parameters": "参数", "Parameters": "参数",
"Password": "密码", "Password": "密码",
"PDF Extract Images (OCR)": "", "PDF Extract Images (OCR)": "PDF图像处理(使用OCR)",
"pending": "待定", "pending": "待定",
"Permission denied when accessing microphone: {{error}}": "访问麦克风时权限被拒绝:{{error}}", "Permission denied when accessing microphone: {{error}}": "访问麦克风时权限被拒绝:{{error}}",
"Playground": "游乐场", "Playground": "Playground",
"Profile": "个人资料", "Profile": "个人资料",
"Prompt Content": "提示词内容", "Prompt Content": "提示词内容",
"Prompt suggestions": "提示词建议", "Prompt suggestions": "提示词建议",
...@@ -255,7 +255,7 @@ ...@@ -255,7 +255,7 @@
"Repeat Penalty": "重复惩罚", "Repeat Penalty": "重复惩罚",
"Request Mode": "请求模式", "Request Mode": "请求模式",
"Reset Vector Storage": "重置向量存储", "Reset Vector Storage": "重置向量存储",
"Response AutoCopy to Clipboard": "响应自动复制到剪贴板", "Response AutoCopy to Clipboard": "自动复制回答到剪贴板",
"Role": "角色", "Role": "角色",
"Rosé Pine": "Rosé Pine", "Rosé Pine": "Rosé Pine",
"Rosé Pine Dawn": "Rosé Pine Dawn", "Rosé Pine Dawn": "Rosé Pine Dawn",
...@@ -263,7 +263,7 @@ ...@@ -263,7 +263,7 @@
"Save & Create": "保存并创建", "Save & Create": "保存并创建",
"Save & Submit": "保存并提交", "Save & Submit": "保存并提交",
"Save & Update": "保存并更新", "Save & Update": "保存并更新",
"Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "直接将聊天记录保存到浏览器存储中不再受支持。请点击下面的按钮下载并删除您的聊天记录。别担心,您可以通过轻松地将聊天记录重新导入到后端", "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "不再支持直接将聊天记录保存到浏览器存储中。请点击下面的按钮下载并删除您的聊天记录。别担心,您可以通过轻松地将聊天记录重新导入到后端",
"Scan": "扫描", "Scan": "扫描",
"Scan complete!": "扫描完成!", "Scan complete!": "扫描完成!",
"Scan for documents from {{path}}": "从 {{path}} 扫描文档", "Scan for documents from {{path}}": "从 {{path}} 扫描文档",
...@@ -275,10 +275,10 @@ ...@@ -275,10 +275,10 @@
"Seed": "种子", "Seed": "种子",
"Select a mode": "选择一个模式", "Select a mode": "选择一个模式",
"Select a model": "选择一个模型", "Select a model": "选择一个模型",
"Select an Ollama instance": "", "Select an Ollama instance": "选择一个Ollama实例",
"Send a Message": "发送消息", "Send a Message": "发送消息",
"Send message": "发送消息", "Send message": "发送消息",
"Server connection verified": "服务器连接已验证", "Server connection verified": "已验证服务器连接",
"Set as default": "设为默认", "Set as default": "设为默认",
"Set Default Model": "设置默认模型", "Set Default Model": "设置默认模型",
"Set Image Size": "设置图片大小", "Set Image Size": "设置图片大小",
...@@ -286,7 +286,7 @@ ...@@ -286,7 +286,7 @@
"Set Title Auto-Generation Model": "设置标题自动生成模型", "Set Title Auto-Generation Model": "设置标题自动生成模型",
"Set Voice": "设置声音", "Set Voice": "设置声音",
"Settings": "设置", "Settings": "设置",
"Settings saved successfully!": "", "Settings saved successfully!": "设置已保存",
"Share to OpenWebUI Community": "分享到OpenWebUI社区", "Share to OpenWebUI Community": "分享到OpenWebUI社区",
"short-summary": "简短总结", "short-summary": "简短总结",
"Show": "显示", "Show": "显示",
...@@ -316,10 +316,10 @@ ...@@ -316,10 +316,10 @@
"Theme": "主题", "Theme": "主题",
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "这确保了您宝贵的对话被安全保存到后端数据库中。谢谢!", "This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "这确保了您宝贵的对话被安全保存到后端数据库中。谢谢!",
"This setting does not sync across browsers or devices.": "此设置不会在浏览器或设备之间同步。", "This setting does not sync across browsers or devices.": "此设置不会在浏览器或设备之间同步。",
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "提示:在每次替换后,在聊天输入中按Tab键可以连续更新多个变量。", "Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "提示:在每次替换后,在聊天输入中按Tab键可以连续更新多个变量。",
"Title": "标题", "Title": "标题",
"Title Auto-Generation": "标题自动生成", "Title Auto-Generation": "标题自动生成",
"Title Generation Prompt": "标题生成提示", "Title Generation Prompt": "自动生成标题的提示",
"to": "到", "to": "到",
"To access the available model names for downloading,": "要访问可下载的模型名称,", "To access the available model names for downloading,": "要访问可下载的模型名称,",
"To access the GGUF models available for downloading,": "要访问可下载的GGUF模型,", "To access the GGUF models available for downloading,": "要访问可下载的GGUF模型,",
...@@ -331,9 +331,9 @@ ...@@ -331,9 +331,9 @@
"Trouble accessing Ollama?": "访问Ollama时遇到问题?", "Trouble accessing Ollama?": "访问Ollama时遇到问题?",
"TTS Settings": "文本转语音设置", "TTS Settings": "文本转语音设置",
"Type Hugging Face Resolve (Download) URL": "输入Hugging Face解析(下载)URL", "Type Hugging Face Resolve (Download) URL": "输入Hugging Face解析(下载)URL",
"Uh-oh! There was an issue connecting to {{provider}}.": "哦哦!连接到{{provider}}时出现问题。", "Uh-oh! There was an issue connecting to {{provider}}.": "哎呀!连接到{{provider}}时出现问题。",
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "未知文件类型'{{file_type}}',但接受并视为纯文本", "Unknown File Type '{{file_type}}', but accepting and treating as plain text": "未知文件类型'{{file_type}}',视为纯文本进行处理",
"Update password": "", "Update password": "更新密码",
"Upload a GGUF model": "上传一个GGUF模型", "Upload a GGUF model": "上传一个GGUF模型",
"Upload files": "上传文件", "Upload files": "上传文件",
"Upload Progress": "上传进度", "Upload Progress": "上传进度",
...@@ -347,17 +347,17 @@ ...@@ -347,17 +347,17 @@
"Valid time units:": "有效时间单位:", "Valid time units:": "有效时间单位:",
"variable": "变量", "variable": "变量",
"variable to have them replaced with clipboard content.": "变量将被剪贴板内容替换。", "variable to have them replaced with clipboard content.": "变量将被剪贴板内容替换。",
"Version": "", "Version": "版本",
"Web": "网页", "Web": "网页",
"WebUI Add-ons": "WebUI 插件", "WebUI Add-ons": "WebUI 插件",
"WebUI Settings": "WebUI 设置", "WebUI Settings": "WebUI 设置",
"WebUI will make requests to": "", "WebUI will make requests to": "WebUI将请求",
"What’s New in": "最新变化", "What’s New in": "最新变化",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "当历史记录被关闭时,这个浏览器上的新聊天不会出现在你任何设备的历史记录中。", "When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "当历史记录被关闭时,这个浏览器上的新聊天不会出现在你任何设备的历史记录中。",
"Whisper (Local)": "私语(本地)", "Whisper (Local)": "Whisper(本地)",
"Write a prompt suggestion (e.g. Who are you?)": "写一个提示建议(例如:你是谁?)", "Write a prompt suggestion (e.g. Who are you?)": "写一个提示建议(例如:你是谁?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "用50个字写一个总结[主题或关键词]。", "Write a summary in 50 words that summarizes [topic or keyword].": "用50个字写一个总结[主题或关键词]。",
"You": "你", "You": "你",
"You're a helpful assistant.": "你是一个有帮助的助手。", "You're a helpful assistant.": "你是一个有帮助的助手。",
"You're now logged in.": "你现在已经登录。" "You're now logged in.": "登录。"
} }
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { getOllamaModels, getOllamaVersion } from '$lib/apis/ollama'; import { getModels as _getModels } from '$lib/utils';
import { getOllamaVersion } from '$lib/apis/ollama';
import { getModelfiles } from '$lib/apis/modelfiles'; import { getModelfiles } from '$lib/apis/modelfiles';
import { getPrompts } from '$lib/apis/prompts'; import { getPrompts } from '$lib/apis/prompts';
import { getOpenAIModels } from '$lib/apis/openai';
import { getLiteLLMModels } from '$lib/apis/litellm';
import { getDocs } from '$lib/apis/documents'; import { getDocs } from '$lib/apis/documents';
import { getAllChatTags } from '$lib/apis/chats'; import { getAllChatTags } from '$lib/apis/chats';
...@@ -47,26 +47,7 @@ ...@@ -47,26 +47,7 @@
let showShortcuts = false; let showShortcuts = false;
const getModels = async () => { const getModels = async () => {
let models = await Promise.all([ return _getModels(localStorage.token);
await getOllamaModels(localStorage.token).catch((error) => {
console.log(error);
return null;
}),
await getOpenAIModels(localStorage.token).catch((error) => {
console.log(error);
return null;
}),
await getLiteLLMModels(localStorage.token).catch((error) => {
console.log(error);
return null;
})
]);
models = models
.filter((models) => models)
.reduce((a, e, i, arr) => a.concat(e, ...(i < arr.length - 1 ? [{ name: 'hr' }] : [])), []);
return models;
}; };
const setOllamaVersion = async (version: string = '') => { const setOllamaVersion = async (version: string = '') => {
...@@ -195,128 +176,128 @@ ...@@ -195,128 +176,128 @@
}); });
</script> </script>
{#if loaded} <div class=" hidden lg:flex fixed bottom-0 right-0 px-3 py-3 z-10">
<div class=" hidden lg:flex fixed bottom-0 right-0 px-3 py-3 z-10"> <Tooltip content="Help" placement="left">
<Tooltip content="Help" placement="left"> <button
<button id="show-shortcuts-button"
id="show-shortcuts-button" bind:this={showShortcutsButtonElement}
bind:this={showShortcutsButtonElement} class="text-gray-600 dark:text-gray-300 bg-gray-300/20 w-6 h-6 flex items-center justify-center text-xs rounded-full"
class="text-gray-600 dark:text-gray-300 bg-gray-300/20 w-6 h-6 flex items-center justify-center text-xs rounded-full" on:click={() => {
on:click={() => { showShortcuts = !showShortcuts;
showShortcuts = !showShortcuts; }}
}} >
> ?
? </button>
</button> </Tooltip>
</Tooltip> </div>
</div>
<ShortcutsModal bind:show={showShortcuts} />
<ShortcutsModal bind:show={showShortcuts} />
<div class="app relative">
<div class="app relative"> <div
{#if !['user', 'admin'].includes($user.role)} class=" text-gray-700 dark:text-gray-100 bg-white dark:bg-gray-900 min-h-screen overflow-auto flex flex-row"
<div class="fixed w-full h-full flex z-50"> >
<div {#if loaded}
class="absolute w-full h-full backdrop-blur-md bg-white/20 dark:bg-gray-900/50 flex justify-center" {#if !['user', 'admin'].includes($user.role)}
> <div class="fixed w-full h-full flex z-50">
<div class="m-auto pb-44 flex flex-col justify-center"> <div
<div class="max-w-md"> class="absolute w-full h-full backdrop-blur-md bg-white/20 dark:bg-gray-900/50 flex justify-center"
<div class="text-center dark:text-white text-2xl font-medium z-50"> >
Account Activation Pending<br /> Contact Admin for WebUI Access <div class="m-auto pb-44 flex flex-col justify-center">
</div> <div class="max-w-md">
<div class="text-center dark:text-white text-2xl font-medium z-50">
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full"> Account Activation Pending<br /> Contact Admin for WebUI Access
Your account status is currently pending activation. To access the WebUI, please </div>
reach out to the administrator. Admins can manage user statuses from the Admin
Panel. <div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
</div> Your account status is currently pending activation. To access the WebUI, please
reach out to the administrator. Admins can manage user statuses from the Admin
<div class=" mt-6 mx-auto relative group w-fit"> Panel.
<button </div>
class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 transition font-medium text-sm"
on:click={async () => { <div class=" mt-6 mx-auto relative group w-fit">
location.href = '/'; <button
}} class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 text-gray-700 transition font-medium text-sm"
> on:click={async () => {
{$i18n.t('Check Again')} location.href = '/';
</button> }}
>
<button {$i18n.t('Check Again')}
class="text-xs text-center w-full mt-2 text-gray-400 underline" </button>
on:click={async () => {
localStorage.removeItem('token'); <button
location.href = '/auth'; class="text-xs text-center w-full mt-2 text-gray-400 underline"
}}>{$i18n.t('Sign Out')}</button on:click={async () => {
> localStorage.removeItem('token');
location.href = '/auth';
}}>{$i18n.t('Sign Out')}</button
>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> {:else if localDBChats.length > 0}
{:else if localDBChats.length > 0} <div class="fixed w-full h-full flex z-50">
<div class="fixed w-full h-full flex z-50"> <div
<div class="absolute w-full h-full backdrop-blur-md bg-white/20 dark:bg-gray-900/50 flex justify-center"
class="absolute w-full h-full backdrop-blur-md bg-white/20 dark:bg-gray-900/50 flex justify-center" >
> <div class="m-auto pb-44 flex flex-col justify-center">
<div class="m-auto pb-44 flex flex-col justify-center"> <div class="max-w-md">
<div class="max-w-md"> <div class="text-center dark:text-white text-2xl font-medium z-50">
<div class="text-center dark:text-white text-2xl font-medium z-50"> Important Update<br /> Action Required for Chat Log Storage
Important Update<br /> Action Required for Chat Log Storage </div>
</div>
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full">
<div class=" mt-4 text-center text-sm dark:text-gray-200 w-full"> {$i18n.t(
{$i18n.t( "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through"
"Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through" )}
)} <span class="font-semibold dark:text-white"
<span class="font-semibold dark:text-white" >{$i18n.t('Settings')} > {$i18n.t('Chats')} > {$i18n.t('Import Chats')}</span
>{$i18n.t('Settings')} > {$i18n.t('Chats')} > {$i18n.t('Import Chats')}</span >. {$i18n.t(
>. {$i18n.t( 'This ensures that your valuable conversations are securely saved to your backend database. Thank you!'
'This ensures that your valuable conversations are securely saved to your backend database. Thank you!' )}
)} </div>
</div>
<div class=" mt-6 mx-auto relative group w-fit">
<div class=" mt-6 mx-auto relative group w-fit"> <button
<button class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 transition font-medium text-sm"
class="relative z-20 flex px-5 py-2 rounded-full bg-white border border-gray-100 dark:border-none hover:bg-gray-100 transition font-medium text-sm" on:click={async () => {
on:click={async () => { let blob = new Blob([JSON.stringify(localDBChats)], {
let blob = new Blob([JSON.stringify(localDBChats)], { type: 'application/json'
type: 'application/json' });
}); saveAs(blob, `chat-export-${Date.now()}.json`);
saveAs(blob, `chat-export-${Date.now()}.json`);
const tx = DB.transaction('chats', 'readwrite');
const tx = DB.transaction('chats', 'readwrite'); await Promise.all([tx.store.clear(), tx.done]);
await Promise.all([tx.store.clear(), tx.done]); await deleteDB('Chats');
await deleteDB('Chats');
localDBChats = [];
localDBChats = []; }}
}} >
> Download & Delete
Download & Delete </button>
</button>
<button
<button class="text-xs text-center w-full mt-2 text-gray-400 underline"
class="text-xs text-center w-full mt-2 text-gray-400 underline" on:click={async () => {
on:click={async () => { localDBChats = [];
localDBChats = []; }}>{$i18n.t('Close')}</button
}}>{$i18n.t('Close')}</button >
> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> {/if}
{/if}
<div
class=" text-gray-700 dark:text-gray-100 bg-white dark:bg-gray-900 min-h-screen overflow-auto flex flex-row"
>
<Sidebar /> <Sidebar />
<SettingsModal bind:show={$showSettings} /> <SettingsModal bind:show={$showSettings} />
<ChangelogModal bind:show={$showChangelog} /> <ChangelogModal bind:show={$showChangelog} />
<slot /> <slot />
</div> {/if}
</div> </div>
{/if} </div>
<style> <style>
.loading { .loading {
......
...@@ -351,7 +351,13 @@ ...@@ -351,7 +351,13 @@
model: model, model: model,
messages: messagesBody, messages: messagesBody,
options: { options: {
...($settings.options ?? {}) ...($settings.options ?? {}),
stop:
$settings?.options?.stop ?? undefined
? $settings.options.stop.map((str) =>
decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"'))
)
: undefined
}, },
format: $settings.requestFormat ?? undefined, format: $settings.requestFormat ?? undefined,
keep_alive: $settings.keepAlive ?? undefined, keep_alive: $settings.keepAlive ?? undefined,
...@@ -532,7 +538,7 @@ ...@@ -532,7 +538,7 @@
console.log(model); console.log(model);
const res = await generateOpenAIChatCompletion( const [res, controller] = await generateOpenAIChatCompletion(
localStorage.token, localStorage.token,
{ {
model: model.id, model: model.id,
...@@ -576,7 +582,12 @@ ...@@ -576,7 +582,12 @@
}) })
})), })),
seed: $settings?.options?.seed ?? undefined, seed: $settings?.options?.seed ?? undefined,
stop: $settings?.options?.stop ?? undefined, stop:
$settings?.options?.stop ?? undefined
? $settings?.options?.stop.map((str) =>
decodeURIComponent(JSON.parse('"' + str.replace(/\"/g, '\\"') + '"'))
)
: undefined,
temperature: $settings?.options?.temperature ?? undefined, temperature: $settings?.options?.temperature ?? undefined,
top_p: $settings?.options?.top_p ?? undefined, top_p: $settings?.options?.top_p ?? undefined,
num_ctx: $settings?.options?.num_ctx ?? undefined, num_ctx: $settings?.options?.num_ctx ?? undefined,
...@@ -608,6 +619,11 @@ ...@@ -608,6 +619,11 @@
if (done || stopResponseFlag || _chatId !== $chatId) { if (done || stopResponseFlag || _chatId !== $chatId) {
responseMessage.done = true; responseMessage.done = true;
messages = messages; messages = messages;
if (stopResponseFlag) {
controller.abort('User: Stop Response');
}
break; break;
} }
......
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment