Commit 06657034 authored by Jun Siang Cheah's avatar Jun Siang Cheah
Browse files

Merge branch 'dev' into feat/model-config

parents 0f50c12c ba61f87a
<script lang="ts">
import { goto } from '$app/navigation';
import { user, chats, settings, showSettings, chatId, tags, showSidebar } from '$lib/stores';
import {
user,
chats,
settings,
showSettings,
chatId,
tags,
showSidebar,
mobile,
showArchivedChats
} from '$lib/stores';
import { onMount, getContext } from 'svelte';
const i18n = getContext('i18n');
......@@ -22,8 +32,9 @@
import ShareChatModal from '../chat/ShareChatModal.svelte';
import ArchiveBox from '../icons/ArchiveBox.svelte';
import ArchivedChatsModal from './Sidebar/ArchivedChatsModal.svelte';
import UserMenu from './Sidebar/UserMenu.svelte';
const BREAKPOINT = 1024;
const BREAKPOINT = 768;
let show = false;
let navElement;
......@@ -39,7 +50,6 @@
let chatTitleEditId = null;
let chatTitle = '';
let showArchivedChatsModal = false;
let showShareChatModal = false;
let showDropdown = false;
let isEditing = false;
......@@ -66,7 +76,24 @@
}
});
mobile;
const onResize = () => {
if ($showSidebar && window.innerWidth < BREAKPOINT) {
showSidebar.set(false);
}
};
onMount(async () => {
mobile.subscribe((e) => {
if ($showSidebar && e) {
showSidebar.set(false);
}
if (!$showSidebar && !e) {
showSidebar.set(true);
}
});
showSidebar.set(window.innerWidth > BREAKPOINT);
await chats.set(await getChatList(localStorage.token));
......@@ -96,20 +123,12 @@
checkDirection();
};
const onResize = () => {
if ($showSidebar && window.innerWidth < BREAKPOINT) {
showSidebar.set(false);
}
};
window.addEventListener('touchstart', onTouchStart);
window.addEventListener('touchend', onTouchEnd);
window.addEventListener('resize', onResize);
return () => {
window.removeEventListener('touchstart', onTouchStart);
window.removeEventListener('touchend', onTouchEnd);
window.removeEventListener('resize', onResize);
};
});
......@@ -176,31 +195,43 @@
<ShareChatModal bind:show={showShareChatModal} chatId={shareChatId} />
<ArchivedChatsModal
bind:show={showArchivedChatsModal}
bind:show={$showArchivedChats}
on:change={async () => {
await chats.set(await getChatList(localStorage.token));
}}
/>
<!-- svelte-ignore a11y-no-static-element-interactions -->
{#if $showSidebar}
<div
class=" fixed md:hidden z-40 top-0 right-0 left-0 bottom-0 bg-black/60 w-full min-h-screen h-screen flex justify-center overflow-hidden overscroll-contain"
on:mousedown={() => {
showSidebar.set(!$showSidebar);
}}
/>
{/if}
<div
bind:this={navElement}
id="sidebar"
class="h-screen max-h-[100dvh] min-h-screen {$showSidebar
? 'lg:relative w-[260px]'
class="h-screen max-h-[100dvh] min-h-screen select-none {$showSidebar
? 'md:relative w-[260px]'
: '-translate-x-[260px] w-[0px]'} bg-gray-50 text-gray-900 dark:bg-gray-950 dark:text-gray-200 text-sm transition fixed z-50 top-0 left-0 rounded-r-2xl
"
data-state={$showSidebar}
>
<div
class="py-2.5 my-auto flex flex-col justify-between h-screen max-h-[100dvh] w-[260px] {$showSidebar
class="py-2.5 my-auto flex flex-col justify-between h-screen max-h-[100dvh] w-[260px] z-50 {$showSidebar
? ''
: 'invisible'}"
>
<div class="px-2 flex justify-center space-x-2">
<div class="px-2.5 flex justify-between space-x-1 text-gray-600 dark:text-gray-400">
<a
id="sidebar-new-chat-button"
class="flex-grow flex justify-between rounded-xl px-4 py-2 hover:bg-gray-100 dark:hover:bg-gray-900 transition"
class="flex flex-1 justify-between rounded-xl px-2 py-2 hover:bg-gray-100 dark:hover:bg-gray-850 transition"
href="/"
draggable="false"
on:click={async () => {
selectedChatId = null;
......@@ -208,27 +239,29 @@
const newChatButton = document.getElementById('new-chat-button');
setTimeout(() => {
newChatButton?.click();
if ($mobile) {
showSidebar.set(false);
}
}, 0);
}}
>
<div class="flex self-center">
<div class="self-center mr-1.5">
<img
src="{WEBUI_BASE_URL}/static/favicon.png"
class=" size-6 -translate-x-1.5 rounded-full"
alt="logo"
/>
</div>
<div class=" self-center font-medium text-sm">{$i18n.t('New Chat')}</div>
<div class="self-center mx-1.5">
<img
src="{WEBUI_BASE_URL}/static/favicon.png"
class=" size-6 -translate-x-1.5 rounded-full"
alt="logo"
/>
</div>
<div class="self-center">
<div class=" self-center font-medium text-sm text-gray-850 dark:text-white">
{$i18n.t('New Chat')}
</div>
<div class="self-center ml-auto">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-4 h-4"
class="size-5"
>
<path
d="M5.433 13.917l1.262-3.155A4 4 0 017.58 9.42l6.92-6.918a2.121 2.121 0 013 3l-6.92 6.918c-.383.383-.84.685-1.343.886l-3.154 1.262a.5.5 0 01-.65-.65z"
......@@ -239,17 +272,42 @@
</svg>
</div>
</a>
<button
class=" cursor-pointer px-2 py-2 flex rounded-xl hover:bg-gray-100 dark:hover:bg-gray-850 transition"
on:click={() => {
showSidebar.set(!$showSidebar);
}}
>
<div class=" m-auto self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
class="size-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25H12"
/>
</svg>
</div>
</button>
</div>
{#if $user?.role === 'admin'}
<div class="px-2 flex justify-center mt-0.5">
<div class="px-2.5 flex justify-center text-gray-800 dark:text-gray-200">
<a
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"
class="flex-grow flex space-x-3 rounded-xl px-2.5 py-2 hover:bg-gray-100 dark:hover:bg-gray-900 transition"
href="/workspace"
on:click={() => {
selectedChatId = null;
chatId.set('');
}}
draggable="false"
>
<div class="self-center">
<svg
......@@ -258,7 +316,7 @@
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
class="w-4 h-4"
class="size-[1.1rem]"
>
<path
stroke-linecap="round"
......@@ -269,71 +327,7 @@
</div>
<div class="flex self-center">
<div class=" self-center font-medium text-sm">{$i18n.t('Modelfiles')}</div>
</div>
</a>
</div>
<div class="px-2 flex justify-center">
<a
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"
on:click={() => {
selectedChatId = null;
chatId.set('');
}}
>
<div class="self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
/>
</svg>
</div>
<div class="flex self-center">
<div class=" self-center font-medium text-sm">{$i18n.t('Prompts')}</div>
</div>
</a>
</div>
<div class="px-2 flex justify-center mb-1">
<a
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"
on:click={() => {
selectedChatId = null;
chatId.set('');
}}
>
<div class="self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 0 0-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 0 1-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H9.75"
/>
</svg>
</div>
<div class="flex self-center">
<div class=" self-center font-medium text-sm">{$i18n.t('Documents')}</div>
<div class=" self-center font-medium text-sm">{$i18n.t('Workspace')}</div>
</div>
</a>
</div>
......@@ -383,9 +377,9 @@
</div>
{/if}
<div class="px-2 mt-1 mb-2 flex justify-center space-x-2">
<div class="flex w-full" id="chat-search">
<div class="self-center pl-3 py-2 rounded-l-xl bg-white dark:bg-gray-950">
<div class="px-2 mt-0.5 mb-2 flex justify-center space-x-2">
<div class="flex w-full rounded-xl" id="chat-search">
<div class="self-center pl-3 py-2 rounded-l-xl bg-transparent">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
......@@ -401,7 +395,7 @@
</div>
<input
class="w-full rounded-r-xl py-1.5 pl-2.5 pr-4 text-sm dark:text-gray-300 dark:bg-gray-950 outline-none"
class="w-full rounded-r-xl py-1.5 pl-2.5 pr-4 text-sm bg-transparent dark:text-gray-300 outline-none"
placeholder={$i18n.t('Search')}
bind:value={search}
on:focus={() => {
......@@ -412,9 +406,9 @@
</div>
{#if $tags.length > 0}
<div class="px-2.5 mt-0.5 mb-2 flex gap-1 flex-wrap">
<div class="px-2.5 mb-2 flex gap-1 flex-wrap">
<button
class="px-2.5 text-xs font-medium bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-800 transition rounded-full"
class="px-2.5 text-xs font-medium bg-gray-50 dark:bg-gray-900 dark:hover:bg-gray-800 transition rounded-full"
on:click={async () => {
await chats.set(await getChatList(localStorage.token));
}}
......@@ -423,7 +417,7 @@
</button>
{#each $tags as tag}
<button
class="px-2.5 text-xs font-medium bg-gray-100 dark:bg-gray-900 dark:hover:bg-gray-800 transition rounded-full"
class="px-2.5 text-xs font-medium bg-gray-50 dark:bg-gray-900 dark:hover:bg-gray-800 transition rounded-full"
on:click={async () => {
let chatIds = await getChatListByTagName(localStorage.token, tag.name);
if (chatIds.length === 0) {
......@@ -439,7 +433,7 @@
</div>
{/if}
<div class="pl-2 my-2 flex-1 flex flex-col space-y-1 overflow-y-auto scrollbar-none">
<div class="pl-2 my-2 flex-1 flex flex-col space-y-1 overflow-y-auto scrollbar-hidden">
{#each filteredChatList as chat, idx}
{#if idx === 0 || (idx > 0 && chat.time_range !== filteredChatList[idx - 1].time_range)}
<div
......@@ -494,7 +488,7 @@
href="/c/{chat.id}"
on:click={() => {
selectedChatId = chat.id;
if (window.innerWidth < 1024) {
if ($mobile) {
showSidebar.set(false);
}
}}
......@@ -609,6 +603,9 @@
shareChatId = selectedChatId;
showShareChatModal = true;
}}
archiveChatHandler={() => {
archiveChatHandler(chat.id);
}}
renameHandler={() => {
chatTitle = chat.title;
chatTitleEditId = chat.id;
......@@ -640,18 +637,6 @@
</button>
</ChatMenu>
<Tooltip content={$i18n.t('Archive')}>
<button
aria-label="Archive"
class=" self-center dark:hover:text-white transition"
on:click={() => {
archiveChatHandler(chat.id);
}}
>
<ArchiveBox />
</button>
</Tooltip>
{#if chat.id === $chatId}
<button
id="delete-chat-button"
......@@ -685,171 +670,38 @@
<div class="flex flex-col">
{#if $user !== undefined}
<button
class=" flex rounded-xl py-3 px-3.5 w-full hover:bg-gray-100 dark:hover:bg-gray-900 transition"
on:click={() => {
showDropdown = !showDropdown;
<UserMenu
role={$user.role}
on:show={(e) => {
if (e.detail === 'archived-chat') {
showArchivedChats.set(true);
}
}}
>
<div class=" self-center mr-3">
<img
src={$user.profile_image_url}
class=" max-w-[30px] object-cover rounded-full"
alt="User profile"
/>
</div>
<div class=" self-center font-semibold">{$user.name}</div>
</button>
{#if showDropdown}
<div
id="dropdownDots"
class="absolute z-40 bottom-[70px] rounded-lg shadow w-[240px] bg-white dark:bg-gray-900"
transition:fade|slide={{ duration: 100 }}
<button
class=" flex rounded-xl py-3 px-3.5 w-full hover:bg-gray-100 dark:hover:bg-gray-900 transition"
on:click={() => {
showDropdown = !showDropdown;
}}
>
<div class="p-1 py-2 w-full">
{#if $user.role === 'admin'}
<button
class="flex rounded-md py-2.5 px-3.5 w-full hover:bg-gray-100 dark:hover:bg-gray-800 transition"
on:click={() => {
goto('/admin');
showDropdown = false;
}}
>
<div class=" self-center mr-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-5 h-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
</div>
<div class=" self-center font-medium">{$i18n.t('Admin Panel')}</div>
</button>
<button
class="flex rounded-md py-2.5 px-3.5 w-full hover:bg-gray-100 dark:hover:bg-gray-800 transition"
on:click={() => {
goto('/playground');
showDropdown = false;
}}
>
<div class=" self-center mr-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-5 h-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m6.75 7.5 3 2.25-3 2.25m4.5 0h3m-9 8.25h13.5A2.25 2.25 0 0 0 21 18V6a2.25 2.25 0 0 0-2.25-2.25H5.25A2.25 2.25 0 0 0 3 6v12a2.25 2.25 0 0 0 2.25 2.25Z"
/>
</svg>
</div>
<div class=" self-center font-medium">{$i18n.t('Playground')}</div>
</button>
{/if}
<button
class="flex rounded-md py-2.5 px-3.5 w-full hover:bg-gray-100 dark:hover:bg-gray-800 transition"
on:click={() => {
showArchivedChatsModal = true;
showDropdown = false;
}}
>
<div class=" self-center mr-3">
<ArchiveBox className="size-5" strokeWidth="1.5" />
</div>
<div class=" self-center font-medium">{$i18n.t('Archived Chats')}</div>
</button>
<button
class="flex rounded-md py-2.5 px-3.5 w-full hover:bg-gray-100 dark:hover:bg-gray-800 transition"
on:click={async () => {
await showSettings.set(true);
showDropdown = false;
}}
>
<div class=" self-center mr-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-5 h-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
</div>
<div class=" self-center font-medium">{$i18n.t('Settings')}</div>
</button>
</div>
<hr class=" dark:border-gray-800 m-0 p-0" />
<div class="p-1 py-2 w-full">
<button
class="flex rounded-md py-2.5 px-3.5 w-full hover:bg-gray-100 dark:hover:bg-gray-800 transition"
on:click={() => {
localStorage.removeItem('token');
location.href = '/auth';
showDropdown = false;
}}
>
<div class=" self-center mr-3">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
fill-rule="evenodd"
d="M3 4.25A2.25 2.25 0 015.25 2h5.5A2.25 2.25 0 0113 4.25v2a.75.75 0 01-1.5 0v-2a.75.75 0 00-.75-.75h-5.5a.75.75 0 00-.75.75v11.5c0 .414.336.75.75.75h5.5a.75.75 0 00.75-.75v-2a.75.75 0 011.5 0v2A2.25 2.25 0 0110.75 18h-5.5A2.25 2.25 0 013 15.75V4.25z"
clip-rule="evenodd"
/>
<path
fill-rule="evenodd"
d="M6 10a.75.75 0 01.75-.75h9.546l-1.048-.943a.75.75 0 111.004-1.114l2.5 2.25a.75.75 0 010 1.114l-2.5 2.25a.75.75 0 11-1.004-1.114l1.048-.943H6.75A.75.75 0 016 10z"
clip-rule="evenodd"
/>
</svg>
</div>
<div class=" self-center font-medium">{$i18n.t('Sign Out')}</div>
</button>
<div class=" self-center mr-3">
<img
src={$user.profile_image_url}
class=" max-w-[30px] object-cover rounded-full"
alt="User profile"
/>
</div>
</div>
{/if}
<div class=" self-center font-semibold">{$user.name}</div>
</button>
</UserMenu>
{/if}
</div>
</div>
</div>
<div
<!-- <div
id="sidebar-handle"
class="fixed left-0 top-[50dvh] -translate-y-1/2 transition-transform translate-x-[255px] md:translate-x-[260px] rotate-0"
class=" hidden md:fixed left-0 top-[50dvh] -translate-y-1/2 transition-transform translate-x-[255px] md:translate-x-[260px] rotate-0"
>
<Tooltip
placement="right"
......@@ -882,16 +734,16 @@
</span>
</button>
</Tooltip>
</div>
</div> -->
</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>
......@@ -9,10 +9,12 @@
import Tooltip from '$lib/components/common/Tooltip.svelte';
import Tags from '$lib/components/chat/Tags.svelte';
import Share from '$lib/components/icons/Share.svelte';
import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
const i18n = getContext('i18n');
export let shareHandler: Function;
export let archiveChatHandler: Function;
export let renameHandler: Function;
export let deleteHandler: Function;
export let onClose: Function;
......@@ -36,14 +38,14 @@
<div slot="content">
<DropdownMenu.Content
class="w-full max-w-[180px] rounded-lg px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-900 dark:text-white shadow"
class="w-full max-w-[160px] rounded-xl px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow"
sideOffset={-2}
side="bottom"
align="start"
transition={flyAndScale}
>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer dark:hover:bg-gray-850 rounded-md"
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
shareHandler();
}}
......@@ -53,7 +55,7 @@
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer dark:hover:bg-gray-850 rounded-md"
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
renameHandler();
}}
......@@ -63,7 +65,17 @@
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer dark:hover:bg-gray-850 rounded-md"
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
archiveChatHandler();
}}
>
<ArchiveBox strokeWidth="2" />
<div class="flex items-center">{$i18n.t('Archive')}</div>
</DropdownMenu.Item>
<DropdownMenu.Item
class="flex gap-2 items-center px-3 py-2 text-sm font-medium cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-800 rounded-md"
on:click={() => {
deleteHandler();
}}
......
<script lang="ts">
import { DropdownMenu } from 'bits-ui';
import { createEventDispatcher, getContext } from 'svelte';
import { flyAndScale } from '$lib/utils/transitions';
import { goto } from '$app/navigation';
import ArchiveBox from '$lib/components/icons/ArchiveBox.svelte';
import { showSettings } from '$lib/stores';
import { fade, slide } from 'svelte/transition';
const i18n = getContext('i18n');
export let show = false;
export let role = '';
export let className = 'max-w-[240px]';
const dispatch = createEventDispatcher();
</script>
<DropdownMenu.Root
bind:open={show}
onOpenChange={(state) => {
dispatch('change', state);
}}
>
<DropdownMenu.Trigger>
<slot />
</DropdownMenu.Trigger>
<slot name="content">
<DropdownMenu.Content
class="w-full {className} text-sm rounded-xl px-1 py-1.5 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-white dark:bg-gray-850 dark:text-white shadow"
sideOffset={8}
side="bottom"
align="start"
transition={(e) => fade(e, { duration: 100 })}
>
<button
class="flex rounded-md py-2 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition"
on:click={async () => {
await showSettings.set(true);
show = false;
}}
>
<div class=" self-center mr-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-5 h-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z"
/>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
</div>
<div class=" self-center font-medium">{$i18n.t('Settings')}</div>
</button>
<button
class="flex rounded-md py-2 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition"
on:click={() => {
dispatch('show', 'archived-chat');
show = false;
}}
>
<div class=" self-center mr-3">
<ArchiveBox className="size-5" strokeWidth="1.5" />
</div>
<div class=" self-center font-medium">{$i18n.t('Archived Chats')}</div>
</button>
{#if role === 'admin'}
<button
class="flex rounded-md py-2 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition"
on:click={() => {
goto('/admin');
show = false;
}}
>
<div class=" self-center mr-3">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-5 h-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z"
/>
</svg>
</div>
<div class=" self-center font-medium">{$i18n.t('Admin Panel')}</div>
</button>
{/if}
<hr class=" dark:border-gray-800 my-2 p-0" />
<button
class="flex rounded-md py-2 px-3 w-full hover:bg-gray-50 dark:hover:bg-gray-800 transition"
on:click={() => {
localStorage.removeItem('token');
location.href = '/auth';
show = false;
}}
>
<div class=" self-center mr-3">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
fill-rule="evenodd"
d="M3 4.25A2.25 2.25 0 015.25 2h5.5A2.25 2.25 0 0113 4.25v2a.75.75 0 01-1.5 0v-2a.75.75 0 00-.75-.75h-5.5a.75.75 0 00-.75.75v11.5c0 .414.336.75.75.75h5.5a.75.75 0 00.75-.75v-2a.75.75 0 011.5 0v2A2.25 2.25 0 0110.75 18h-5.5A2.25 2.25 0 013 15.75V4.25z"
clip-rule="evenodd"
/>
<path
fill-rule="evenodd"
d="M6 10a.75.75 0 01.75-.75h9.546l-1.048-.943a.75.75 0 111.004-1.114l2.5 2.25a.75.75 0 010 1.114l-2.5 2.25a.75.75 0 11-1.004-1.114l1.048-.943H6.75A.75.75 0 016 10z"
clip-rule="evenodd"
/>
</svg>
</div>
<div class=" self-center font-medium">{$i18n.t('Sign Out')}</div>
</button>
<!-- <DropdownMenu.Item class="flex items-center px-3 py-2 text-sm font-medium">
<div class="flex items-center">Profile</div>
</DropdownMenu.Item> -->
</DropdownMenu.Content>
</slot>
</DropdownMenu.Root>
<script lang="ts">
import { toast } from 'svelte-sonner';
import fileSaver from 'file-saver';
const { saveAs } = fileSaver;
import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, documents } from '$lib/stores';
import { createNewDoc, deleteDocByName, getDocs } from '$lib/apis/documents';
import { SUPPORTED_FILE_TYPE, SUPPORTED_FILE_EXTENSIONS } from '$lib/constants';
import { uploadDocToVectorDB } from '$lib/apis/rag';
import { transformFileName } from '$lib/utils';
import Checkbox from '$lib/components/common/Checkbox.svelte';
import EditDocModal from '$lib/components/documents/EditDocModal.svelte';
import AddFilesPlaceholder from '$lib/components/AddFilesPlaceholder.svelte';
import SettingsModal from '$lib/components/documents/SettingsModal.svelte';
import AddDocModal from '$lib/components/documents/AddDocModal.svelte';
const i18n = getContext('i18n');
let importFiles = '';
let inputFiles = '';
let query = '';
let documentsImportInputElement: HTMLInputElement;
let tags = [];
let showSettingsModal = false;
let showAddDocModal = false;
let showEditDocModal = false;
let selectedDoc;
let selectedTag = '';
let dragged = false;
const deleteDoc = async (name) => {
await deleteDocByName(localStorage.token, name);
await documents.set(await getDocs(localStorage.token));
};
const deleteDocs = async (docs) => {
const res = await Promise.all(
docs.map(async (doc) => {
return await deleteDocByName(localStorage.token, doc.name);
})
);
await documents.set(await getDocs(localStorage.token));
};
const uploadDoc = async (file) => {
const res = await uploadDocToVectorDB(localStorage.token, '', file).catch((error) => {
toast.error(error);
return null;
});
if (res) {
await createNewDoc(
localStorage.token,
res.collection_name,
res.filename,
transformFileName(res.filename),
res.filename
).catch((error) => {
toast.error(error);
return null;
});
await documents.set(await getDocs(localStorage.token));
}
};
onMount(() => {
documents.subscribe((docs) => {
tags = docs.reduce((a, e, i, arr) => {
return [...new Set([...a, ...(e?.content?.tags ?? []).map((tag) => tag.name)])];
}, []);
});
const dropZone = document.querySelector('body');
const onDragOver = (e) => {
e.preventDefault();
dragged = true;
};
const onDragLeave = () => {
dragged = false;
};
const onDrop = async (e) => {
e.preventDefault();
if (e.dataTransfer?.files) {
let reader = new FileReader();
reader.onload = (event) => {
files = [
...files,
{
type: 'image',
url: `${event.target.result}`
}
];
};
const inputFiles = e.dataTransfer?.files;
if (inputFiles && inputFiles.length > 0) {
for (const file of inputFiles) {
console.log(file, file.name.split('.').at(-1));
if (
SUPPORTED_FILE_TYPE.includes(file['type']) ||
SUPPORTED_FILE_EXTENSIONS.includes(file.name.split('.').at(-1))
) {
uploadDoc(file);
} else {
toast.error(
`Unknown File Type '${file['type']}', but accepting and treating as plain text`
);
uploadDoc(file);
}
}
} else {
toast.error($i18n.t(`File not found.`));
}
}
dragged = false;
};
dropZone?.addEventListener('dragover', onDragOver);
dropZone?.addEventListener('drop', onDrop);
dropZone?.addEventListener('dragleave', onDragLeave);
return () => {
dropZone?.removeEventListener('dragover', onDragOver);
dropZone?.removeEventListener('drop', onDrop);
dropZone?.removeEventListener('dragleave', onDragLeave);
};
});
let filteredDocs;
$: filteredDocs = $documents.filter(
(doc) =>
(selectedTag === '' ||
(doc?.content?.tags ?? []).map((tag) => tag.name).includes(selectedTag)) &&
(query === '' || doc.name.includes(query))
);
</script>
<svelte:head>
<title>
{$i18n.t('Documents')} | {$WEBUI_NAME}
</title>
</svelte:head>
{#if dragged}
<div
class="fixed w-full h-full flex z-50 touch-none pointer-events-none"
id="dropzone"
role="region"
aria-label="Drag and Drop Container"
>
<div class="absolute rounded-xl w-full h-full backdrop-blur bg-gray-800/40 flex justify-center">
<div class="m-auto pt-64 flex flex-col justify-center">
<div class="max-w-md">
<AddFilesPlaceholder>
<div class=" mt-2 text-center text-sm dark:text-gray-200 w-full">
Drop any files here to add to my documents
</div>
</AddFilesPlaceholder>
</div>
</div>
</div>
</div>
{/if}
{#key selectedDoc}
<EditDocModal bind:show={showEditDocModal} {selectedDoc} />
{/key}
<AddDocModal bind:show={showAddDocModal} />
<SettingsModal bind:show={showSettingsModal} />
<div class="mb-3">
<div class="flex justify-between items-center">
<div class=" text-lg font-semibold self-center">{$i18n.t('Documents')}</div>
<div>
<button
class="flex items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 transition"
type="button"
on:click={() => {
showSettingsModal = !showSettingsModal;
}}
>
<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="M6.955 1.45A.5.5 0 0 1 7.452 1h1.096a.5.5 0 0 1 .497.45l.17 1.699c.484.12.94.312 1.356.562l1.321-1.081a.5.5 0 0 1 .67.033l.774.775a.5.5 0 0 1 .034.67l-1.08 1.32c.25.417.44.873.561 1.357l1.699.17a.5.5 0 0 1 .45.497v1.096a.5.5 0 0 1-.45.497l-1.699.17c-.12.484-.312.94-.562 1.356l1.082 1.322a.5.5 0 0 1-.034.67l-.774.774a.5.5 0 0 1-.67.033l-1.322-1.08c-.416.25-.872.44-1.356.561l-.17 1.699a.5.5 0 0 1-.497.45H7.452a.5.5 0 0 1-.497-.45l-.17-1.699a4.973 4.973 0 0 1-1.356-.562L4.108 13.37a.5.5 0 0 1-.67-.033l-.774-.775a.5.5 0 0 1-.034-.67l1.08-1.32a4.971 4.971 0 0 1-.561-1.357l-1.699-.17A.5.5 0 0 1 1 8.548V7.452a.5.5 0 0 1 .45-.497l1.699-.17c.12-.484.312-.94.562-1.356L2.629 4.107a.5.5 0 0 1 .034-.67l.774-.774a.5.5 0 0 1 .67-.033L5.43 3.71a4.97 4.97 0 0 1 1.356-.561l.17-1.699ZM6 8c0 .538.212 1.026.558 1.385l.057.057a2 2 0 0 0 2.828-2.828l-.058-.056A2 2 0 0 0 6 8Z"
clip-rule="evenodd"
/>
</svg>
<div class=" text-xs">{$i18n.t('Document Settings')}</div>
</button>
</div>
</div>
<div class=" text-gray-500 text-xs mt-1">
ⓘ {$i18n.t("Use '#' in the prompt input to load and select your documents.")}
</div>
</div>
<div class=" flex w-full space-x-2">
<div class="flex flex-1">
<div class=" self-center ml-1 mr-3">
<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="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
clip-rule="evenodd"
/>
</svg>
</div>
<input
class=" w-full text-sm pr-4 py-1 rounded-r-xl outline-none bg-transparent"
bind:value={query}
placeholder={$i18n.t('Search Documents')}
/>
</div>
<div>
<button
class=" px-2 py-2 rounded-xl border border-gray-200 dark:border-gray-600 dark:border-0 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 transition font-medium text-sm flex items-center space-x-1"
on:click={() => {
showAddDocModal = true;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
/>
</svg>
</button>
</div>
</div>
<!-- <div>
<div
class="my-3 py-16 rounded-lg border-2 border-dashed dark:border-gray-600 {dragged &&
' dark:bg-gray-700'} "
role="region"
on:drop={onDrop}
on:dragover={onDragOver}
on:dragleave={onDragLeave}
>
<div class=" pointer-events-none">
<div class="text-center dark:text-white text-2xl font-semibold z-50">{$i18n.t('Add Files')}</div>
<div class=" mt-2 text-center text-sm dark:text-gray-200 w-full">
Drop any files here to add to my documents
</div>
</div>
</div>
</div> -->
<hr class=" dark:border-gray-850 my-2.5" />
{#if tags.length > 0}
<div class="px-2.5 pt-1 flex gap-1 flex-wrap">
<div class="ml-0.5 pr-3 my-auto flex items-center">
<Checkbox
state={filteredDocs.filter((doc) => doc?.selected === 'checked').length ===
filteredDocs.length
? 'checked'
: 'unchecked'}
indeterminate={filteredDocs.filter((doc) => doc?.selected === 'checked').length > 0 &&
filteredDocs.filter((doc) => doc?.selected === 'checked').length !== filteredDocs.length}
on:change={(e) => {
if (e.detail === 'checked') {
filteredDocs = filteredDocs.map((doc) => ({ ...doc, selected: 'checked' }));
} else if (e.detail === 'unchecked') {
filteredDocs = filteredDocs.map((doc) => ({ ...doc, selected: 'unchecked' }));
}
}}
/>
</div>
{#if filteredDocs.filter((doc) => doc?.selected === 'checked').length === 0}
<button
class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white"
on:click={async () => {
selectedTag = '';
// await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}}
>
<div class=" text-xs font-medium self-center line-clamp-1">{$i18n.t('all')}</div>
</button>
{#each tags as tag}
<button
class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white"
on:click={async () => {
selectedTag = tag;
// await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}}
>
<div class=" text-xs font-medium self-center line-clamp-1">
#{tag}
</div>
</button>
{/each}
{:else}
<div class="flex-1 flex w-full justify-between items-center">
<div class="text-xs font-medium py-0.5 self-center mr-1">
{filteredDocs.filter((doc) => doc?.selected === 'checked').length} Selected
</div>
<div class="flex gap-1">
<!-- <button
class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white"
on:click={async () => {
selectedTag = '';
// await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}}
>
<div class=" text-xs font-medium self-center line-clamp-1">add tags</div>
</button> -->
<button
class="px-2 py-0.5 space-x-1 flex h-fit items-center rounded-full transition bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:text-white"
on:click={async () => {
deleteDocs(filteredDocs.filter((doc) => doc.selected === 'checked'));
// await chats.set(await getChatListByTagName(localStorage.token, tag.name));
}}
>
<div class=" text-xs font-medium self-center line-clamp-1">
{$i18n.t('delete')}
</div>
</button>
</div>
</div>
{/if}
</div>
{/if}
<div class="my-3 mb-5">
{#each filteredDocs as doc}
<button
class=" flex space-x-4 cursor-pointer text-left w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
on:click={() => {
if (doc?.selected === 'checked') {
doc.selected = 'unchecked';
} else {
doc.selected = 'checked';
}
}}
>
<div class="my-auto flex items-center">
<Checkbox state={doc?.selected ?? 'unchecked'} />
</div>
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
<div class=" flex items-center space-x-3">
<div class="p-2.5 bg-red-400 text-white rounded-lg">
{#if doc}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="w-6 h-6"
>
<path
fill-rule="evenodd"
d="M5.625 1.5c-1.036 0-1.875.84-1.875 1.875v17.25c0 1.035.84 1.875 1.875 1.875h12.75c1.035 0 1.875-.84 1.875-1.875V12.75A3.75 3.75 0 0 0 16.5 9h-1.875a1.875 1.875 0 0 1-1.875-1.875V5.25A3.75 3.75 0 0 0 9 1.5H5.625ZM7.5 15a.75.75 0 0 1 .75-.75h7.5a.75.75 0 0 1 0 1.5h-7.5A.75.75 0 0 1 7.5 15Zm.75 2.25a.75.75 0 0 0 0 1.5H12a.75.75 0 0 0 0-1.5H8.25Z"
clip-rule="evenodd"
/>
<path
d="M12.971 1.816A5.23 5.23 0 0 1 14.25 5.25v1.875c0 .207.168.375.375.375H16.5a5.23 5.23 0 0 1 3.434 1.279 9.768 9.768 0 0 0-6.963-6.963Z"
/>
</svg>
{:else}
<svg
class=" w-6 h-6 translate-y-[0.5px]"
fill="currentColor"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
><style>
.spinner_qM83 {
animation: spinner_8HQG 1.05s infinite;
}
.spinner_oXPr {
animation-delay: 0.1s;
}
.spinner_ZTLf {
animation-delay: 0.2s;
}
@keyframes spinner_8HQG {
0%,
57.14% {
animation-timing-function: cubic-bezier(0.33, 0.66, 0.66, 1);
transform: translate(0);
}
28.57% {
animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.33);
transform: translateY(-6px);
}
100% {
transform: translate(0);
}
}
</style><circle class="spinner_qM83" cx="4" cy="12" r="2.5" /><circle
class="spinner_qM83 spinner_oXPr"
cx="12"
cy="12"
r="2.5"
/><circle class="spinner_qM83 spinner_ZTLf" cx="20" cy="12" r="2.5" /></svg
>
{/if}
</div>
<div class=" self-center flex-1">
<div class=" font-bold line-clamp-1">#{doc.name} ({doc.filename})</div>
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
{doc.title}
</div>
</div>
</div>
</div>
<div class="flex flex-row space-x-1 self-center">
<button
class="self-center w-fit text-sm z-20 px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={async (e) => {
e.stopPropagation();
showEditDocModal = !showEditDocModal;
selectedDoc = doc;
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
/>
</svg>
</button>
<!-- <button
class="self-center w-fit text-sm px-2 py-2 border dark:border-gray-600 rounded-xl"
type="button"
on:click={() => {
console.log('download file');
}}
>
<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>
</button> -->
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={(e) => {
e.stopPropagation();
deleteDoc(doc.name);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
</div>
</button>
{/each}
</div>
<div class=" flex justify-end w-full mb-2">
<div class="flex space-x-2">
<input
id="documents-import-input"
bind:this={documentsImportInputElement}
bind:files={importFiles}
type="file"
accept=".json"
hidden
on:change={() => {
console.log(importFiles);
const reader = new FileReader();
reader.onload = async (event) => {
const savedDocs = JSON.parse(event.target.result);
console.log(savedDocs);
for (const doc of savedDocs) {
await createNewDoc(
localStorage.token,
doc.collection_name,
doc.filename,
doc.name,
doc.title
).catch((error) => {
toast.error(error);
return null;
});
}
await documents.set(await getDocs(localStorage.token));
};
reader.readAsText(importFiles[0]);
}}
/>
<button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={() => {
documentsImportInputElement.click();
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Documents Mapping')}</div>
<div class=" self-center">
<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="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 9.5a.75.75 0 0 1-.75-.75V8.06l-.72.72a.75.75 0 0 1-1.06-1.06l2-2a.75.75 0 0 1 1.06 0l2 2a.75.75 0 1 1-1.06 1.06l-.72-.72v2.69a.75.75 0 0 1-.75.75Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
<button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={async () => {
let blob = new Blob([JSON.stringify($documents)], {
type: 'application/json'
});
saveAs(blob, `documents-mapping-export-${Date.now()}.json`);
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Documents Mapping')}</div>
<div class=" self-center">
<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="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 3.5a.75.75 0 0 1 .75.75v2.69l.72-.72a.75.75 0 1 1 1.06 1.06l-2 2a.75.75 0 0 1-1.06 0l-2-2a.75.75 0 0 1 1.06-1.06l.72.72V6.25A.75.75 0 0 1 8 5.5Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
</div>
</div>
<script lang="ts">
import { toast } from 'svelte-sonner';
import fileSaver from 'file-saver';
const { saveAs } = fileSaver;
import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, modelfiles, settings, user } from '$lib/stores';
import { createModel, deleteModel } from '$lib/apis/ollama';
import {
createNewModelfile,
deleteModelfileByTagName,
getModelfiles
} from '$lib/apis/modelfiles';
import { goto } from '$app/navigation';
const i18n = getContext('i18n');
let localModelfiles = [];
let importFiles;
let modelfilesImportInputElement: HTMLInputElement;
const deleteModelHandler = async (tagName) => {
let success = null;
success = await deleteModel(localStorage.token, tagName).catch((err) => {
toast.error(err);
return null;
});
if (success) {
toast.success($i18n.t(`Deleted {{tagName}}`, { tagName }));
}
return success;
};
const deleteModelfile = async (tagName) => {
await deleteModelHandler(tagName);
await deleteModelfileByTagName(localStorage.token, tagName);
await modelfiles.set(await getModelfiles(localStorage.token));
};
const shareModelfile = async (modelfile) => {
toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
const url = 'https://openwebui.com';
const tab = await window.open(`${url}/modelfiles/create`, '_blank');
window.addEventListener(
'message',
(event) => {
if (event.origin !== url) return;
if (event.data === 'loaded') {
tab.postMessage(JSON.stringify(modelfile), '*');
}
},
false
);
};
const saveModelfiles = async (modelfiles) => {
let blob = new Blob([JSON.stringify(modelfiles)], {
type: 'application/json'
});
saveAs(blob, `modelfiles-export-${Date.now()}.json`);
};
onMount(() => {
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
if (localModelfiles) {
console.log(localModelfiles);
}
});
</script>
<svelte:head>
<title>
{$i18n.t('Modelfiles')} | {$WEBUI_NAME}
</title>
</svelte:head>
<div class=" text-lg font-semibold mb-3">{$i18n.t('Modelfiles')}</div>
<a class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" href="/workspace/modelfiles/create">
<div class=" self-center w-10">
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6">
<path
fill-rule="evenodd"
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
<div class=" self-center">
<div class=" font-bold">{$i18n.t('Create a modelfile')}</div>
<div class=" text-sm">{$i18n.t('Customize Ollama models for a specific purpose')}</div>
</div>
</a>
<hr class=" dark:border-gray-850" />
<div class=" my-2 mb-5">
{#each $modelfiles as modelfile}
<div
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
>
<a
class=" flex flex-1 space-x-4 cursor-pointer w-full"
href={`/?models=${encodeURIComponent(modelfile.tagName)}`}
>
<div class=" self-center w-10">
<div class=" rounded-full bg-stone-700">
<img
src={modelfile.imageUrl ?? '/user.png'}
alt="modelfile profile"
class=" rounded-full w-full h-auto object-cover"
/>
</div>
</div>
<div class=" flex-1 self-center">
<div class=" font-bold capitalize">{modelfile.title}</div>
<div class=" text-sm overflow-hidden text-ellipsis line-clamp-1">
{modelfile.desc}
</div>
</div>
</a>
<div class="flex flex-row space-x-1 self-center">
<a
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
href={`/workspace/modelfiles/edit?tag=${encodeURIComponent(modelfile.tagName)}`}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L6.832 19.82a4.5 4.5 0 0 1-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 0 1 1.13-1.897L16.863 4.487Zm0 0L19.5 7.125"
/>
</svg>
</a>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
// console.log(modelfile);
sessionStorage.modelfile = JSON.stringify(modelfile);
goto('/workspace/modelfiles/create');
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 0 0-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 0 1-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H9.75"
/>
</svg>
</button>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
shareModelfile(modelfile);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M7.217 10.907a2.25 2.25 0 1 0 0 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186 9.566-5.314m-9.566 7.5 9.566 5.314m0 0a2.25 2.25 0 1 0 3.935 2.186 2.25 2.25 0 0 0-3.935-2.186Zm0-12.814a2.25 2.25 0 1 0 3.933-2.185 2.25 2.25 0 0 0-3.933 2.185Z"
/>
</svg>
</button>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
deleteModelfile(modelfile.tagName);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0"
/>
</svg>
</button>
</div>
</div>
{/each}
</div>
<div class=" flex justify-end w-full mb-3">
<div class="flex space-x-1">
<input
id="modelfiles-import-input"
bind:this={modelfilesImportInputElement}
bind:files={importFiles}
type="file"
accept=".json"
hidden
on:change={() => {
console.log(importFiles);
let reader = new FileReader();
reader.onload = async (event) => {
let savedModelfiles = JSON.parse(event.target.result);
console.log(savedModelfiles);
for (const modelfile of savedModelfiles) {
await createNewModelfile(localStorage.token, modelfile).catch((error) => {
return null;
});
}
await modelfiles.set(await getModelfiles(localStorage.token));
};
reader.readAsText(importFiles[0]);
}}
/>
<button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={() => {
modelfilesImportInputElement.click();
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Modelfiles')}</div>
<div class=" self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-3.5 h-3.5"
>
<path
fill-rule="evenodd"
d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 9.5a.75.75 0 0 1-.75-.75V8.06l-.72.72a.75.75 0 0 1-1.06-1.06l2-2a.75.75 0 0 1 1.06 0l2 2a.75.75 0 1 1-1.06 1.06l-.72-.72v2.69a.75.75 0 0 1-.75.75Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
<button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={async () => {
saveModelfiles($modelfiles);
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Modelfiles')}</div>
<div class=" self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-3.5 h-3.5"
>
<path
fill-rule="evenodd"
d="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 3.5a.75.75 0 0 1 .75.75v2.69l.72-.72a.75.75 0 1 1 1.06 1.06l-2 2a.75.75 0 0 1-1.06 0l-2-2a.75.75 0 0 1 1.06-1.06l.72.72V6.25A.75.75 0 0 1 8 5.5Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
</div>
{#if localModelfiles.length > 0}
<div class="flex">
<div class=" self-center text-sm font-medium mr-4">
{localModelfiles.length} Local Modelfiles Detected
</div>
<div class="flex space-x-1">
<button
class="self-center w-fit text-sm px-3 py-1 border dark:border-gray-600 rounded-xl flex"
on:click={async () => {
for (const modelfile of localModelfiles) {
await createNewModelfile(localStorage.token, modelfile).catch((error) => {
return null;
});
}
saveModelfiles(localModelfiles);
localStorage.removeItem('modelfiles');
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
await modelfiles.set(await getModelfiles(localStorage.token));
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Sync All')}</div>
<div class=" self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-3.5 h-3.5"
>
<path
fill-rule="evenodd"
d="M13.836 2.477a.75.75 0 0 1 .75.75v3.182a.75.75 0 0 1-.75.75h-3.182a.75.75 0 0 1 0-1.5h1.37l-.84-.841a4.5 4.5 0 0 0-7.08.932.75.75 0 0 1-1.3-.75 6 6 0 0 1 9.44-1.242l.842.84V3.227a.75.75 0 0 1 .75-.75Zm-.911 7.5A.75.75 0 0 1 13.199 11a6 6 0 0 1-9.44 1.241l-.84-.84v1.371a.75.75 0 0 1-1.5 0V9.591a.75.75 0 0 1 .75-.75H5.35a.75.75 0 0 1 0 1.5H3.98l.841.841a4.5 4.5 0 0 0 7.08-.932.75.75 0 0 1 1.025-.273Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
<button
class="self-center w-fit text-sm p-1.5 border dark:border-gray-600 rounded-xl flex"
on:click={async () => {
saveModelfiles(localModelfiles);
localStorage.removeItem('modelfiles');
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
await modelfiles.set(await getModelfiles(localStorage.token));
}}
>
<div class=" self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</div>
</button>
</div>
</div>
{/if}
</div>
<div class=" my-16">
<div class=" text-lg font-semibold mb-3">{$i18n.t('Made by OpenWebUI Community')}</div>
<a
class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2"
href="https://openwebui.com/"
target="_blank"
>
<div class=" self-center w-10">
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6">
<path
fill-rule="evenodd"
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
<div class=" self-center">
<div class=" font-bold">{$i18n.t('Discover a modelfile')}</div>
<div class=" text-sm">{$i18n.t('Discover, download, and explore model presets')}</div>
</div>
</a>
</div>
......@@ -268,75 +268,74 @@
</title>
</svelte:head>
<div class="min-h-screen max-h-[100dvh] w-full flex justify-center dark:text-white">
<div class=" flex flex-col justify-between w-full overflow-y-auto h-[100dvh]">
<div class="max-w-2xl mx-auto w-full px-3 md:px-0 my-10 h-full">
<div class=" flex flex-col h-full">
<div class="flex flex-col justify-between mb-2.5 gap-1">
<div class="flex justify-between items-center gap-2">
<div class=" text-2xl font-semibold self-center flex">
{$i18n.t('Playground')}
<span class=" text-xs text-gray-500 self-center ml-1">{$i18n.t('(Beta)')}</span>
</div>
<div>
<button
class=" flex items-center gap-0.5 text-xs px-2.5 py-0.5 rounded-lg {mode ===
'chat' && 'text-sky-600 dark:text-sky-200 bg-sky-200/30'} {mode === 'complete' &&
'text-green-600 dark:text-green-200 bg-green-200/30'} "
on:click={() => {
if (mode === 'complete') {
mode = 'chat';
} else {
mode = 'complete';
}
}}
>
{#if mode === 'complete'}
{$i18n.t('Text Completion')}
{:else if mode === 'chat'}
{$i18n.t('Chat')}
{/if}
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-3 h-3"
>
<path
fill-rule="evenodd"
d="M5.22 10.22a.75.75 0 0 1 1.06 0L8 11.94l1.72-1.72a.75.75 0 1 1 1.06 1.06l-2.25 2.25a.75.75 0 0 1-1.06 0l-2.25-2.25a.75.75 0 0 1 0-1.06ZM10.78 5.78a.75.75 0 0 1-1.06 0L8 4.06 6.28 5.78a.75.75 0 0 1-1.06-1.06l2.25-2.25a.75.75 0 0 1 1.06 0l2.25 2.25a.75.75 0 0 1 0 1.06Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
</div>
<div class=" flex flex-col justify-between w-full overflow-y-auto h-full">
<div class="mx-auto w-full md:px-0 h-full">
<div class=" flex flex-col h-full">
<div class="flex flex-col justify-between mb-2.5 gap-1">
<div class="flex justify-between items-center gap-2">
<div class=" text-lg font-semibold self-center flex">
{$i18n.t('Playground')}
<span class=" text-xs text-gray-500 self-center ml-1">{$i18n.t('(Beta)')}</span>
</div>
<div class="flex flex-col gap-1 w-full">
<div class="flex w-full">
<div class="overflow-hidden w-full">
<div class="max-w-full">
<Selector
placeholder={$i18n.t('Select a model')}
items={$models
.filter((model) => model.name !== 'hr')
.map((model) => ({
value: model.id,
label: model.custom_info?.name ?? model.name,
info: model
}))}
bind:value={selectedModelId}
className="w-[42rem]"
<div>
<button
class=" flex items-center gap-0.5 text-xs px-2.5 py-0.5 rounded-lg {mode === 'chat' &&
'text-sky-600 dark:text-sky-200 bg-sky-200/30'} {mode === 'complete' &&
'text-green-600 dark:text-green-200 bg-green-200/30'} "
on:click={() => {
if (mode === 'complete') {
mode = 'chat';
} else {
mode = 'complete';
}
}}
>
{#if mode === 'complete'}
{$i18n.t('Text Completion')}
{:else if mode === 'chat'}
{$i18n.t('Chat')}
{/if}
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-3 h-3"
>
<path
fill-rule="evenodd"
d="M5.22 10.22a.75.75 0 0 1 1.06 0L8 11.94l1.72-1.72a.75.75 0 1 1 1.06 1.06l-2.25 2.25a.75.75 0 0 1-1.06 0l-2.25-2.25a.75.75 0 0 1 0-1.06ZM10.78 5.78a.75.75 0 0 1-1.06 0L8 4.06 6.28 5.78a.75.75 0 0 1-1.06-1.06l2.25-2.25a.75.75 0 0 1 1.06 0l2.25 2.25a.75.75 0 0 1 0 1.06Z"
clip-rule="evenodd"
/>
</div>
</svg>
</div>
</button>
</div>
</div>
<div class="flex flex-col gap-1 w-full">
<div class="flex w-full">
<div class="overflow-hidden w-full">
<div class="max-w-full">
<Selector
placeholder={$i18n.t('Select a model')}
items={$models
.filter((model) => model.name !== 'hr')
.map((model) => ({
value: model.id,
label: model.name,
info: model
}))}
bind:value={selectedModelId}
className="w-[42rem]"
/>
</div>
</div>
</div>
<!-- <button
<!-- <button
class=" self-center dark:hover:text-gray-300"
id="open-settings-button"
on:click={async () => {}}
......@@ -361,67 +360,66 @@
/>
</svg>
</button> -->
</div>
</div>
</div>
{#if mode === 'chat'}
<div class="p-1">
<div class="p-3 outline outline-1 outline-gray-200 dark:outline-gray-800 rounded-lg">
<div class=" text-sm font-medium">{$i18n.t('System')}</div>
{#if mode === 'chat'}
<div class="p-1">
<div class="p-3 outline outline-1 outline-gray-200 dark:outline-gray-800 rounded-lg">
<div class=" text-sm font-medium">{$i18n.t('System')}</div>
<textarea
id="system-textarea"
class="w-full h-full bg-transparent resize-none outline-none text-sm"
bind:value={system}
placeholder={$i18n.t("You're a helpful assistant.")}
rows="4"
/>
</div>
</div>
{/if}
<div
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0"
id="messages-container"
bind:this={messagesContainerElement}
>
<div class=" h-full w-full flex flex-col">
<div class="flex-1 p-1">
{#if mode === 'complete'}
<textarea
id="system-textarea"
class="w-full h-full bg-transparent resize-none outline-none text-sm"
bind:value={system}
id="text-completion-textarea"
bind:this={textCompletionAreaElement}
class="w-full h-full p-3 bg-transparent outline outline-1 outline-gray-200 dark:outline-gray-800 resize-none rounded-lg text-sm"
bind:value={text}
placeholder={$i18n.t("You're a helpful assistant.")}
rows="4"
/>
</div>
</div>
{/if}
<div
class=" pb-2.5 flex flex-col justify-between w-full flex-auto overflow-auto h-0"
id="messages-container"
bind:this={messagesContainerElement}
>
<div class=" h-full w-full flex flex-col">
<div class="flex-1 p-1">
{#if mode === 'complete'}
<textarea
id="text-completion-textarea"
bind:this={textCompletionAreaElement}
class="w-full h-full p-3 bg-transparent outline outline-1 outline-gray-200 dark:outline-gray-800 resize-none rounded-lg text-sm"
bind:value={text}
placeholder={$i18n.t("You're a helpful assistant.")}
/>
{:else if mode === 'chat'}
<ChatCompletion bind:messages />
{/if}
</div>
{:else if mode === 'chat'}
<ChatCompletion bind:messages />
{/if}
</div>
</div>
</div>
<div class="pb-2">
{#if !loading}
<button
class="px-3 py-1.5 text-sm font-medium bg-emerald-600 hover:bg-emerald-700 text-gray-50 transition rounded-lg"
on:click={() => {
submitHandler();
}}
>
{$i18n.t('Submit')}
</button>
{:else}
<button
class="px-3 py-1.5 text-sm font-medium bg-gray-100 hover:bg-gray-200 text-gray-900 transition rounded-lg"
on:click={() => {
stopResponse();
}}
>
{$i18n.t('Cancel')}
</button>
{/if}
</div>
<div class="pb-3">
{#if !loading}
<button
class="px-3 py-1.5 text-sm font-medium bg-emerald-600 hover:bg-emerald-700 text-gray-50 transition rounded-lg"
on:click={() => {
submitHandler();
}}
>
{$i18n.t('Submit')}
</button>
{:else}
<button
class="px-3 py-1.5 text-sm font-medium bg-gray-100 hover:bg-gray-200 text-gray-900 transition rounded-lg"
on:click={() => {
stopResponse();
}}
>
{$i18n.t('Cancel')}
</button>
{/if}
</div>
</div>
</div>
......
<script lang="ts">
import { toast } from 'svelte-sonner';
import fileSaver from 'file-saver';
const { saveAs } = fileSaver;
import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, prompts } from '$lib/stores';
import { createNewPrompt, deletePromptByCommand, getPrompts } from '$lib/apis/prompts';
import { error } from '@sveltejs/kit';
import { goto } from '$app/navigation';
const i18n = getContext('i18n');
let importFiles = '';
let query = '';
let promptsImportInputElement: HTMLInputElement;
const sharePrompt = async (prompt) => {
toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
const url = 'https://openwebui.com';
const tab = await window.open(`${url}/prompts/create`, '_blank');
window.addEventListener(
'message',
(event) => {
if (event.origin !== url) return;
if (event.data === 'loaded') {
tab.postMessage(JSON.stringify(prompt), '*');
}
},
false
);
};
const deletePrompt = async (command) => {
await deletePromptByCommand(localStorage.token, command);
await prompts.set(await getPrompts(localStorage.token));
};
</script>
<svelte:head>
<title>
{$i18n.t('Prompts')} | {$WEBUI_NAME}
</title>
</svelte:head>
<div class="mb-3 flex justify-between items-center">
<div class=" text-lg font-semibold self-center">{$i18n.t('Prompts')}</div>
</div>
<div class=" flex w-full space-x-2">
<div class="flex flex-1">
<div class=" self-center ml-1 mr-3">
<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="M9 3.5a5.5 5.5 0 100 11 5.5 5.5 0 000-11zM2 9a7 7 0 1112.452 4.391l3.328 3.329a.75.75 0 11-1.06 1.06l-3.329-3.328A7 7 0 012 9z"
clip-rule="evenodd"
/>
</svg>
</div>
<input
class=" w-full text-sm pr-4 py-1 rounded-r-xl outline-none bg-transparent"
bind:value={query}
placeholder={$i18n.t('Search Prompts')}
/>
</div>
<div>
<a
class=" px-2 py-2 rounded-xl border border-gray-200 dark:border-gray-600 dark:border-0 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 transition font-medium text-sm flex items-center space-x-1"
href="/workspace/prompts/create"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-4 h-4"
>
<path
d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
/>
</svg>
</a>
</div>
</div>
<hr class=" dark:border-gray-850 my-2.5" />
<div class="my-3 mb-5">
{#each $prompts.filter((p) => query === '' || p.command.includes(query)) as prompt}
<div
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
>
<div class=" flex flex-1 space-x-4 cursor-pointer w-full">
<a href={`/workspace/prompts/edit?command=${encodeURIComponent(prompt.command)}`}>
<div class=" flex-1 self-center pl-5">
<div class=" font-bold">{prompt.command}</div>
<div class=" text-xs overflow-hidden text-ellipsis line-clamp-1">
{prompt.title}
</div>
</div>
</a>
</div>
<div class="flex flex-row space-x-1 self-center">
<a
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
href={`/workspace/prompts/edit?command=${encodeURIComponent(prompt.command)}`}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L6.832 19.82a4.5 4.5 0 01-1.897 1.13l-2.685.8.8-2.685a4.5 4.5 0 011.13-1.897L16.863 4.487zm0 0L19.5 7.125"
/>
</svg>
</a>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
// console.log(modelfile);
sessionStorage.prompt = JSON.stringify(prompt);
goto('/workspace/prompts/create');
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 0 1-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 0 1 1.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 0 0-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 0 1-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 0 0-3.375-3.375h-1.5a1.125 1.125 0 0 1-1.125-1.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H9.75"
/>
</svg>
</button>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
sharePrompt(prompt);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M7.217 10.907a2.25 2.25 0 100 2.186m0-2.186c.18.324.283.696.283 1.093s-.103.77-.283 1.093m0-2.186l9.566-5.314m-9.566 7.5l9.566 5.314m0 0a2.25 2.25 0 103.935 2.186 2.25 2.25 0 00-3.935-2.186zm0-12.814a2.25 2.25 0 103.933-2.185 2.25 2.25 0 00-3.933 2.185z"
/>
</svg>
</button>
<button
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
on:click={() => {
deletePrompt(prompt.command);
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-4 h-4"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
/>
</svg>
</button>
</div>
</div>
{/each}
</div>
<div class=" flex justify-end w-full mb-3">
<div class="flex space-x-2">
<input
id="prompts-import-input"
bind:this={promptsImportInputElement}
bind:files={importFiles}
type="file"
accept=".json"
hidden
on:change={() => {
console.log(importFiles);
const reader = new FileReader();
reader.onload = async (event) => {
const savedPrompts = JSON.parse(event.target.result);
console.log(savedPrompts);
for (const prompt of savedPrompts) {
await createNewPrompt(
localStorage.token,
prompt.command.charAt(0) === '/' ? prompt.command.slice(1) : prompt.command,
prompt.title,
prompt.content
).catch((error) => {
toast.error(error);
return null;
});
}
await prompts.set(await getPrompts(localStorage.token));
};
reader.readAsText(importFiles[0]);
}}
/>
<button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={() => {
promptsImportInputElement.click();
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Prompts')}</div>
<div class=" self-center">
<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="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 9.5a.75.75 0 0 1-.75-.75V8.06l-.72.72a.75.75 0 0 1-1.06-1.06l2-2a.75.75 0 0 1 1.06 0l2 2a.75.75 0 1 1-1.06 1.06l-.72-.72v2.69a.75.75 0 0 1-.75.75Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
<button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={async () => {
// promptsImportInputElement.click();
let blob = new Blob([JSON.stringify($prompts)], {
type: 'application/json'
});
saveAs(blob, `prompts-export-${Date.now()}.json`);
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Prompts')}</div>
<div class=" self-center">
<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="M4 2a1.5 1.5 0 0 0-1.5 1.5v9A1.5 1.5 0 0 0 4 14h8a1.5 1.5 0 0 0 1.5-1.5V6.621a1.5 1.5 0 0 0-.44-1.06L9.94 2.439A1.5 1.5 0 0 0 8.878 2H4Zm4 3.5a.75.75 0 0 1 .75.75v2.69l.72-.72a.75.75 0 1 1 1.06 1.06l-2 2a.75.75 0 0 1-1.06 0l-2-2a.75.75 0 0 1 1.06-1.06l.72.72V6.25A.75.75 0 0 1 8 5.5Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
<!-- <button
on:click={() => {
loadDefaultPrompts();
}}
>
dd
</button> -->
</div>
</div>
<div class=" my-16">
<div class=" text-lg font-semibold mb-3">{$i18n.t('Made by OpenWebUI Community')}</div>
<a
class=" flex space-x-4 cursor-pointer w-full mb-3 px-3 py-2"
href="https://openwebui.com/?type=prompts"
target="_blank"
>
<div class=" self-center w-10">
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6">
<path
fill-rule="evenodd"
d="M12 3.75a.75.75 0 01.75.75v6.75h6.75a.75.75 0 010 1.5h-6.75v6.75a.75.75 0 01-1.5 0v-6.75H4.5a.75.75 0 010-1.5h6.75V4.5a.75.75 0 01.75-.75z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
<div class=" self-center">
<div class=" font-bold">{$i18n.t('Discover a prompt')}</div>
<div class=" text-sm">{$i18n.t('Discover, download, and explore custom prompts')}</div>
</div>
</a>
</div>
import { dev } from '$app/environment';
import { browser, dev } from '$app/environment';
// import { version } from '../../package.json';
export const APP_NAME = 'Open WebUI';
export const WEBUI_BASE_URL = dev ? `http://${location.hostname}:8080` : ``;
export const WEBUI_BASE_URL = browser ? (dev ? `http://${location.hostname}:8080` : ``) : ``;
export const WEBUI_API_BASE_URL = `${WEBUI_BASE_URL}/api/v1`;
......
......@@ -37,7 +37,7 @@ const createIsLoadingStore = (i18n: i18nType) => {
return isLoading;
};
export const initI18n = (defaultLocale: string) => {
export const initI18n = (defaultLocale: string | undefined) => {
let detectionOrder = defaultLocale
? ['querystring', 'localStorage']
: ['querystring', 'localStorage', 'navigator'];
......
{
"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "",
"(Beta)": "(تجريبي)",
"(e.g. `sh webui.sh --api`)": "(مثال `sh webui.sh --api`)",
"(e.g. `sh webui.sh --api`)": "( `sh webui.sh --api`مثال)",
"(latest)": "(الأخير)",
"{{modelName}} is thinking...": "{{modelName}} ...يفكر",
"{{user}}'s Chats": "{{user}}' الدردشات",
"{{webUIName}} Backend Required": "",
"{{webUIName}} Backend Required": "{{webUIName}} مطلوب",
"a user": "المستخدم",
"About": "عن",
"Account": "الحساب",
......@@ -15,20 +15,20 @@
"Add a short description about what this modelfile does": "أضف وصفًا قصيرًا حول ما يفعله ملف الموديل هذا",
"Add a short title for this prompt": "أضف عنوانًا قصيرًا لبداء المحادثة",
"Add a tag": "أضافة تاق",
"Add custom prompt": "",
"Add custom prompt": "أضافة مطالبة مخصصه",
"Add Docs": "إضافة المستندات",
"Add Files": "إضافة ملفات",
"Add message": "اضافة رسالة",
"Add Model": "اضافة موديل",
"Add Tags": "اضافة تاق",
"Add User": "اضافة مستخدم",
"Adjusting these settings will apply changes universally to all users.": "سيؤدي ضبط هذه الإعدادات إلى تطبيق التغييرات بشكل عام على كافة المستخدمين.",
"Adjusting these settings will apply changes universally to all users.": "سيؤدي ضبط هذه الإعدادات إلى تطبيق التغييرات بشكل عام على كافة المستخدمين",
"admin": "المشرف",
"Admin Panel": "لوحة التحكم",
"Admin Settings": "اعدادات المشرف",
"Advanced Parameters": "التعليمات المتقدمة",
"all": "الكل",
"All Documents": "",
"All Documents": "جميع الملفات",
"All Users": "جميع المستخدمين",
"Allow": "يسمح",
"Allow Chat Deletion": "يستطيع حذف المحادثات",
......@@ -42,32 +42,34 @@
"API Key created.": "API تم أنشاء المفتاح",
"API keys": "API المفاتيح",
"API RPM": "API RPM",
"April": "",
"April": "أبريل",
"Archive": "الأرشيف",
"Archived Chats": "الأرشيف المحادثات",
"are allowed - Activate this command by typing": "مسموح - قم بتنشيط هذا الأمر عن طريق الكتابة",
"Are you sure?": "هل أنت متأكد ؟",
"Attach file": "",
"Attach file": "أرفق ملف",
"Attention to detail": "انتبه للتفاصيل",
"Audio": "صوتي",
"August": "",
"August": "أغسطس",
"Auto-playback response": "استجابة التشغيل التلقائي",
"Auto-send input after 3 sec.": "إرسال تلقائي للإدخال بعد 3 ثوانٍ.",
"Auto-send input after 3 sec.": "إرسال تلقائي للإدخال بعد 3 ثواني.",
"AUTOMATIC1111 Base URL": "AUTOMATIC1111 الرابط الرئيسي",
"AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 الرابط مطلوب",
"available!": "متاح",
"Back": "خلف",
"Bad Response": "استجابة خطاء",
"before": "",
"before": "قبل",
"Being lazy": "كون كسول",
"Beta": "",
"Builder Mode": "بناء الموديل",
"Bypass SSL verification for Websites": "",
"Cancel": "اللغاء",
"Categories": "التصنيفات",
"Change Password": "تغير الباسورد",
"Chat": "المحادثة",
"Chat Bubble UI": "",
"Chat History": "تاريخ المحادثة",
"Chat History is off for this browser.": "سجل الدردشة معطل لهذا المتصفح.",
"Chat History is off for this browser.": "سجل الدردشة معطل لهذا المتصفح",
"Chats": "المحادثات",
"Check Again": "تحقق مرة اخرى",
"Check for updates": "تحقق من التحديثات",
......@@ -76,13 +78,13 @@
"Chunk Overlap": "Chunk تداخل",
"Chunk Params": "Chunk المتغيرات",
"Chunk Size": "Chunk حجم",
"Citation": "",
"Citation": "اقتباس",
"Click here for help.": "أضغط هنا للمساعدة",
"Click here to": "",
"Click here to check other modelfiles.": "انقر هنا للتحقق من ملفات الموديلات الأخرى.",
"Click here to": "أضغط هنا الانتقال",
"Click here to check other modelfiles.": "انقر هنا للتحقق من ملفات الموديلات الأخرى",
"Click here to select": "أضغط هنا للاختيار",
"Click here to select a csv file.": "أضغط هنا للاختيار ملف csv",
"Click here to select documents.": "انقر هنا لاختيار المستندات.",
"Click here to select documents.": "انقر هنا لاختيار المستندات",
"click here.": "أضغط هنا",
"Click on the user role button to change a user's role.": "أضغط على أسم الصلاحيات لتغيرها للمستخدم",
"Close": "أغلق",
......@@ -97,17 +99,17 @@
"Context Length": "طول السياق",
"Continue Response": "متابعة الرد",
"Conversation Mode": "وضع المحادثة",
"Copied shared chat URL to clipboard!": "تم نسخ عنوان URL للدردشة المشتركة إلى الحافظة!",
"Copied shared chat URL to clipboard!": "تم نسخ عنوان URL للدردشة المشتركة إلى الحافظة",
"Copy": "نسخ",
"Copy last code block": "انسخ كتلة التعليمات البرمجية الأخيرة",
"Copy last response": "انسخ الرد الأخير",
"Copy Link": "أنسخ الرابط",
"Copying to clipboard was successful!": "تم النسخ إلى الحافظة بنجاح!",
"Copying to clipboard was successful!": "تم النسخ إلى الحافظة بنجاح",
"Create a concise, 3-5 word phrase as a header for the following query, strictly adhering to the 3-5 word limit and avoiding the use of the word 'title':": "قم بإنشاء عبارة موجزة مكونة من 3-5 كلمات كرأس للاستعلام التالي، مع الالتزام الصارم بالحد الأقصى لعدد الكلمات الذي يتراوح بين 3-5 كلمات وتجنب استخدام الكلمة 'عنوان':",
"Create a modelfile": "إنشاء ملف نموذجي",
"Create Account": "إنشاء حساب",
"Create new key": "",
"Create new secret key": "",
"Create new key": "عمل مفتاح جديد",
"Create new secret key": "عمل سر جديد",
"Created at": "أنشئت في",
"Created At": "أنشئت من",
"Current Model": "الموديل المختار",
......@@ -116,27 +118,26 @@
"Custom": "مخصص",
"Customize Ollama models for a specific purpose": "تخصيص الموديل Ollama لغرض محدد",
"Dark": "مظلم",
"Dashboard": "",
"Dashboard": "لوحة التحكم",
"Database": "قاعدة البيانات",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
"December": "",
"December": "ديسمبر",
"Default": "الإفتراضي",
"Default (Automatic1111)": "الإفتراضي (Automatic1111)",
"Default (SentenceTransformers)": "الإفتراضي (SentenceTransformers)",
"Default (Web API)": "الإفتراضي (Web API)",
"Default (Automatic1111)": "(Automatic1111) الإفتراضي",
"Default (SentenceTransformers)": "(SentenceTransformers) الإفتراضي",
"Default (Web API)": "(Web API) الإفتراضي",
"Default model updated": "الإفتراضي تحديث الموديل",
"Default Prompt Suggestions": "الإفتراضي Prompt الاقتراحات",
"Default User Role": "الإفتراضي صلاحيات المستخدم",
"delete": "حذف",
"Delete": "حذف.",
"Delete": "حذف",
"Delete a model": "حذف الموديل",
"Delete chat": "حذف المحادثه",
"Delete Chat": "حذف المحادثه.",
"Delete Chats": "حذ المحادثات",
"delete this link": "",
"Delete Chats": "حذف المحادثات",
"delete this link": "أحذف هذا الرابط",
"Delete User": "حذف المستخدم",
"Deleted {{deleteModelTag}}": "حذف {{deleteModelTag}}",
"Deleted {{tagName}}": "حذف {{tagName}}",
"Deleted {{deleteModelTag}}": "{{deleteModelTag}} حذف",
"Deleted {{tagName}}": "{{tagName}} حذف",
"Description": "وصف",
"Didn't fully follow instructions": "لم أتبع التعليمات بشكل كامل",
"Disabled": "تعطيل",
......@@ -153,7 +154,7 @@
"Don't have an account?": "ليس لديك حساب؟",
"Don't like the style": "لا أحب النمط",
"Download": "تحميل",
"Download canceled": "",
"Download canceled": "تم اللغاء التحميل",
"Download Database": "تحميل قاعدة البيانات",
"Drop any files here to add to the conversation": "أسقط أية ملفات هنا لإضافتها إلى المحادثة",
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "e.g. '30s','10m'. الوحدات الزمنية الصالحة هي 's', 'm', 'h'.",
......@@ -171,16 +172,16 @@
"Enter {{role}} message here": "أدخل رسالة {{role}} هنا",
"Enter Chunk Overlap": "أدخل Chunk المتداخل",
"Enter Chunk Size": "أدخل Chunk الحجم",
"Enter Image Size (e.g. 512x512)": "أدخل حجم الصورة (e.g. 512x512)",
"Enter language codes": "",
"Enter Image Size (e.g. 512x512)": "(e.g. 512x512) أدخل حجم الصورة ",
"Enter language codes": "أدخل كود اللغة",
"Enter LiteLLM API Base URL (litellm_params.api_base)": "أدخل عنوان URL الأساسي لواجهة برمجة تطبيقات LiteLLM (litellm_params.api_base)",
"Enter LiteLLM API Key (litellm_params.api_key)": "أدخل مفتاح LiteLLM API (litellm_params.api_key)",
"Enter LiteLLM API RPM (litellm_params.rpm)": "أدخل LiteLLM API RPM (litllm_params.rpm)",
"Enter LiteLLM Model (litellm_params.model)": "أدخل LiteLLM الموديل (litellm_params.model)",
"Enter Max Tokens (litellm_params.max_tokens)": "أدخل أكثر Tokens (litellm_params.max_tokens)",
"Enter Model Display Name": "",
"Enter model tag (e.g. {{modelTag}})": "أدخل الموديل تاق (e.g. {{modelTag}})",
"Enter Number of Steps (e.g. 50)": "أدخل عدد الخطوات (e.g. 50)",
"Enter model tag (e.g. {{modelTag}})": "(e.g. {{modelTag}}) أدخل الموديل تاق",
"Enter Number of Steps (e.g. 50)": "(e.g. 50) أدخل عدد الخطوات",
"Enter Score": "أدخل النتيجة",
"Enter stop sequence": "أدخل تسلسل التوقف",
"Enter Top K": "Enter Top K",
......@@ -198,7 +199,7 @@
"Export Prompts": "مطالبات التصدير",
"Failed to create API Key.": "فشل في إنشاء مفتاح API.",
"Failed to read clipboard contents": "فشل في قراءة محتويات الحافظة",
"February": "",
"February": "فبراير",
"Feel free to add specific details": "لا تتردد في إضافة تفاصيل محددة",
"File Mode": "وضع الملف",
"File not found.": "لم يتم العثور على الملف.",
......@@ -213,9 +214,10 @@
"General Settings": "الاعدادات العامة",
"Generation Info": "معلومات الجيل",
"Good Response": "استجابة جيدة",
"h:mm a": "",
"has no conversations.": "ليس لديه محادثات.",
"Hello, {{name}}": "مرحبا, {{name}}",
"Help": "",
"Hello, {{name}}": " {{name}} مرحبا",
"Help": "مساعدة",
"Hide": "أخفاء",
"Hide Additional Params": "إخفاء المعلمات الإضافية",
"How can I help you today?": "كيف استطيع مساعدتك اليوم؟",
......@@ -231,13 +233,13 @@
"Include `--api` flag when running stable-diffusion-webui": "قم بتضمين علامة `-api` عند تشغيل Stable-diffusion-webui",
"Input commands": "",
"Interface": "واجهه المستخدم",
"Invalid Tag": "",
"Invalid Tag": "تاق غير صالحة",
"Is Model Vision Capable": "",
"January": "",
"January": "يناير",
"join our Discord for help.": "انضم إلى Discord للحصول على المساعدة.",
"JSON": "JSON",
"July": "",
"June": "",
"July": "يوليو",
"June": "يونيو",
"JWT Expiration": "JWT تجريبي",
"JWT Token": "JWT Token",
"Keep Alive": "Keep Alive",
......@@ -245,19 +247,20 @@
"Language": "اللغة",
"Last Active": "آخر نشاط",
"Light": "فاتح",
"Listening...": "جاري الاستماع...",
"LLMs can make mistakes. Verify important information.": "يمكن أن يرتكب LLM الأخطاء. التحقق من المعلومات الهامة.",
"Made by OpenWebUI Community": "تم إنشاؤه بواسطة مجتمع OpenWebUI",
"Listening...": "جاري الاستماع",
"LLMs can make mistakes. Verify important information.": "يمكن أن تصدر بعض الأخطاء. لذلك يجب التحقق من المعلومات المهمة",
"Made by OpenWebUI Community": "OpenWebUI تم إنشاؤه بواسطة مجتمع ",
"Make sure to enclose them with": "تأكد من إرفاقها",
"Manage LiteLLM Models": "إدارة نماذج LiteLLM",
"Manage LiteLLM Models": "LiteLLM إدارة نماذج ",
"Manage Model Information": "",
"Manage Models": "إدارة النماذج",
"Manage Ollama Models": "إدارة موديلات Ollama",
"Manage Ollama Models": "Ollama إدارة موديلات ",
"March": "",
"Max Tokens": "Max Tokens",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "يمكن تنزيل 3 نماذج كحد أقصى في وقت واحد. الرجاء معاودة المحاولة في وقت لاحق.",
"May": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "لن تتم مشاركة الرسائل التي ترسلها بعد إنشاء الرابط الخاص بك. سيتمكن المستخدمون الذين لديهم عنوان URL من عرض الدردشة المشتركة.",
"Minimum Score": "الحد الأدنى من النقاط",
"Mirostat": "Mirostat",
"Mirostat Eta": "Mirostat Eta",
......@@ -267,7 +270,7 @@
"Model '{{modelName}}' has been successfully downloaded.": "موديل '{{modelName}}'تم تحميله بنجاح",
"Model '{{modelTag}}' is already in queue for downloading.": "موديل '{{modelTag}}' جاري تحميلة الرجاء الانتظار",
"Model {{modelId}} not found": "موديل {{modelId}} لم يوجد",
"Model {{modelName}} already exists.": "موديل {{modelName}} موجود",
"Model {{modelName}} already exists.": "موجود {{modelName}} موديل ",
"Model {{modelName}} is not vision capable": "",
"Model Description": "",
"Model Display Name": "",
......@@ -285,24 +288,21 @@
"Modelfiles": "ملفات الموديل",
"Models": "الموديلات",
"More": "المزيد",
"My Documents": "مستنداتي",
"My Modelfiles": "ملفاتي النموذجية",
"My Prompts": "مطالباتي",
"Name": "الأسم",
"Name Tag": "أسم التاق",
"Name your modelfile": "قم بتسمية ملف النموذج الخاص بك",
"New Chat": "دردشة جديدة",
"New Password": "كلمة المرور الجديدة",
"No": "",
"No results found": "",
"No source available": "",
"No results found": "لا توجد نتايج",
"No source available": "لا يوجد مصدر متاح",
"Not factually correct": "ليس صحيحا من حيث الواقع",
"Not sure what to add?": "لست متأكدا ما يجب إضافته؟",
"Not sure what to write? Switch to": "لست متأكدا ماذا أكتب؟ التبديل إلى",
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "ملاحظة: إذا قمت بتعيين الحد الأدنى من النقاط، فلن يؤدي البحث إلا إلى إرجاع المستندات التي لها نقاط أكبر من أو تساوي الحد الأدنى من النقاط.",
"Notifications": "إشعارات",
"November": "",
"October": "",
"November": "نوفمبر",
"October": "اكتوبر",
"Off": "أغلاق",
"Okay, Let's Go!": "حسنا دعنا نذهب!",
"OLED Dark": "OLED داكن",
......@@ -316,50 +316,51 @@
"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 من الواجهة الخلفية.",
"Open": "فتح",
"Open AI": "فتح AI",
"Open AI (Dall-E)": "فتح AI (Dall-E)",
"Open AI": "AI فتح",
"Open AI (Dall-E)": "AI (Dall-E) فتح",
"Open new chat": "فتح محادثة جديده",
"OpenAI": "OpenAI",
"OpenAI API": "OpenAI API",
"OpenAI API Config": "OpenAI API إعدادات",
"OpenAI API Key is required.": "مطلوب مفتاح OpenAI API.",
"OpenAI URL/Key required.": "مطلوب عنوان URL/مفتاح OpenAI.",
"OpenAI API Key is required.": "OpenAI API.مطلوب مفتاح ",
"OpenAI URL/Key required.": "URL/مفتاح OpenAI.مطلوب عنوان ",
"or": "أو",
"Other": "آخر",
"Overview": "",
"Overview": "عرض",
"Parameters": "Parameters",
"Password": "الباسورد",
"PDF document (.pdf)": "PDF ملف (.pdf)",
"PDF Extract Images (OCR)": "PDF أستخرج الصور (OCR)",
"pending": "قيد الانتظار",
"Permission denied when accessing microphone: {{error}}": "تم رفض الإذن عند الوصول إلى الميكروفون: {{error}}",
"Permission denied when accessing microphone: {{error}}": "{{error}} تم رفض الإذن عند الوصول إلى الميكروفون ",
"Personalization": "",
"Plain text (.txt)": "نص عادي (.txt)",
"Playground": "مكان التجربة",
"Positive attitude": "موقف ايجابي",
"Previous 30 days": "",
"Previous 7 days": "",
"Previous 30 days": "أخر 30 يوم",
"Previous 7 days": "أخر 7 أيام",
"Profile Image": "صورة الملف الشخصي",
"Prompt": "",
"Prompt": "مطالبة",
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "موجه (على سبيل المثال: أخبرني بحقيقة ممتعة عن الإمبراطورية الرومانية)",
"Prompt Content": "محتوى عاجل",
"Prompt suggestions": "اقتراحات سريعة",
"Prompts": "حث",
"Pull \"{{searchValue}}\" from Ollama.com": "",
"Pull a model from Ollama.com": "سحب الموديل من Ollama.com",
"Prompts": "مطالبات",
"Pull \"{{searchValue}}\" from Ollama.com": "Ollama.com \"{{searchValue}}\" أسحب من ",
"Pull a model from Ollama.com": "Ollama.com سحب الموديل من ",
"Pull Progress": "سحب التقدم",
"Query Params": "Query Params",
"RAG Template": "RAG تنمبلت",
"Raw Format": "Raw فورمات",
"Read Aloud": "أقراء لي",
"Record voice": "سجل صوت",
"Redirecting you to OpenWebUI Community": "إعادة توجيهك إلى مجتمع OpenWebUI",
"Redirecting you to OpenWebUI Community": "OpenWebUI إعادة توجيهك إلى مجتمع ",
"Refused when it shouldn't have": "رفض عندما لا ينبغي أن يكون",
"Regenerate": "تجديد",
"Release Notes": "ملاحظات الإصدار",
"Remove": "إزالة",
"Remove Model": "",
"Rename": "",
"Repeat Last N": "كرر آخر N",
"Remove Model": "حذف الموديل",
"Rename": "إعادة تسمية",
"Repeat Last N": "N كرر آخر",
"Repeat Penalty": "كرر المخالفة",
"Request Mode": "وضع الطلب",
"Reranking Model": "",
......@@ -372,27 +373,27 @@
"Rosé Pine Dawn": "Rosé Pine Dawn",
"Save": "حفظ",
"Save & Create": "حفظ وإنشاء",
"Save & Submit": "حفظ وإرسال",
"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": "لم يعد حفظ سجلات الدردشة مباشرة في مساحة تخزين متصفحك مدعومًا. يرجى تخصيص بعض الوقت لتنزيل وحذف سجلات الدردشة الخاصة بك عن طريق النقر على الزر أدناه. لا تقلق، يمكنك بسهولة إعادة استيراد سجلات الدردشة الخاصة بك إلى الواجهة الخلفية من خلاله",
"Scan": "مسح",
"Scan complete!": "تم المسح",
"Scan for documents from {{path}}": " مسح على الملفات من {{path}}",
"Scan for documents from {{path}}": "{{path}} مسح على الملفات من",
"Search": "البحث",
"Search a model": "البحث عن موديل",
"Search Documents": "البحث المستندات",
"Search Prompts": "أبحث حث",
"See readme.md for instructions": "راجع readme.md للحصول على التعليمات",
"See readme.md for instructions": "readme.md للحصول على التعليمات",
"See what's new": "ما الجديد",
"Seed": "Seed",
"Select a mode": "أختار موديل",
"Select a model": "أختار الموديل",
"Select an Ollama instance": "أختار سيرفر Ollama",
"Select model": "",
"Select an Ollama instance": "أختار سيرفر ",
"Select model": " أختار موديل",
"Selected model does not support image inputs.": "",
"Send a Message": "أرسل رسالة.",
"Send message": "أرسل رسالة",
"September": "",
"Send": "",
"Send a Message": "يُرجى إدخال طلبك هنا",
"Send message": "يُرجى إدخال طلبك هنا.",
"September": "سبتمبر",
"Server connection verified": "تم التحقق من اتصال الخادم",
"Set as default": "الافتراضي",
"Set Default Model": "تفعيد الموديل الافتراضي",
......@@ -407,7 +408,7 @@
"Settings saved successfully!": "تم حفظ الاعدادات بنجاح",
"Share": "كشاركة",
"Share Chat": "مشاركة الدردشة",
"Share to OpenWebUI Community": "شارك في مجتمع OpenWebUI",
"Share to OpenWebUI Community": "OpenWebUI شارك في مجتمع",
"short-summary": "ملخص قصير",
"Show": "عرض",
"Show Additional Params": "إظهار المعلمات الإضافية",
......@@ -418,17 +419,17 @@
"Sign Out": "تسجيل الخروج",
"Sign up": "تسجيل",
"Signing in": "جاري الدخول",
"Source": "",
"Speech recognition error: {{error}}": "خطأ في التعرف على الكلام: {{error}}",
"Source": "المصدر",
"Speech recognition error: {{error}}": "{{error}} خطأ في التعرف على الكلام",
"Speech-to-Text Engine": "محرك تحويل الكلام إلى نص",
"SpeechRecognition API is not supported in this browser.": "API SpeechRecognition غير مدعومة في هذا المتصفح.",
"Stop Sequence": "وقف التسلسل",
"STT Settings": "STT اعدادات",
"Submit": "إرسال",
"Subtitle (e.g. about the Roman Empire)": "الترجمة (e.g. about the Roman Empire)",
"Subtitle (e.g. about the Roman Empire)": "(e.g. about the Roman Empire) الترجمة",
"Success": "نجاح",
"Successfully updated.": "تم التحديث بنجاح.",
"Suggested": "",
"Successfully updated.": "تم التحديث بنجاح",
"Suggested": "مقترحات",
"Sync All": "مزامنة الكل",
"System": "النظام",
"System Prompt": "محادثة النظام",
......@@ -447,33 +448,33 @@
"Thorough explanation": "شرح شامل",
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "ملاحضة: قم بتحديث عدة فتحات متغيرة على التوالي عن طريق الضغط على مفتاح tab في مدخلات الدردشة بعد كل استبدال.",
"Title": "العنوان",
"Title (e.g. Tell me a fun fact)": "العناون (e.g. Tell me a fun fact)",
"Title (e.g. Tell me a fun fact)": "(e.g. Tell me a fun fact) العناون",
"Title Auto-Generation": "توليد تلقائي للعنوان",
"Title cannot be an empty string.": "",
"Title cannot be an empty string.": "العنوان مطلوب",
"Title Generation Prompt": "موجه إنشاء العنوان",
"to": "الى",
"To access the available model names for downloading,": "للوصول إلى أسماء الموديلات المتاحة للتنزيل،",
"To access the GGUF models available for downloading,": "للوصول إلى الموديلات GGUF المتاحة للتنزيل،",
"to chat input.": "الى كتابة المحادثه",
"Today": "",
"Today": "اليوم",
"Toggle settings": "فتح وأغلاق الاعدادات",
"Toggle sidebar": "فتح وأغلاق الشريط الجانبي",
"Top K": "Top K",
"Top P": "Top P",
"Trouble accessing Ollama?": "هل تواجه مشكلة في الوصول إلى Olma؟",
"Trouble accessing Ollama?": "هل تواجه مشكلة في الوصول",
"TTS Settings": "TTS اعدادات",
"Type Hugging Face Resolve (Download) URL": "اكتب عنوان 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}}', ولكن القبول والتعامل كنص عادي ",
"Update and Copy Link": "تحديث ونسخ الرابط",
"Update password": "تحديث كلمة المرور",
"Upload a GGUF model": "رفع موديل نوع GGUF",
"Upload a GGUF model": "GGUF رفع موديل نوع",
"Upload files": "رفع الملفات",
"Upload Progress": "جاري التحميل",
"URL Mode": "رابط الموديل",
"Use '#' in the prompt input to load and select your documents.": "أستخدم '#' في المحادثة لربطهامن المستندات",
"Use Gravatar": "أستخدم Gravatar",
"Use Initials": "أستخدم Initials",
"Use Gravatar": "Gravatar أستخدم",
"Use Initials": "Initials أستخدم",
"user": "مستخدم",
"User Permissions": "صلاحيات المستخدم",
"Users": "المستخدمين",
......@@ -493,13 +494,14 @@
"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.": "عند إيقاف تشغيل السجل، لن تظهر الدردشات الجديدة على هذا المتصفح في سجلك على أي من أجهزتك.",
"Whisper (Local)": "Whisper (Local)",
"Workspace": "",
"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 كلمة يلخص [الموضوع أو الكلمة الرئيسية]",
"Yes": "",
"Yesterday": "",
"You": "أنت",
"You have no archived conversations.": "",
"You have shared this chat": "",
"Yesterday": "أمس",
"You": "",
"You have no archived conversations.": "لا تملك محادثات محفوظه",
"You have shared this chat": "تم مشاركة هذه المحادثة",
"You're a helpful assistant.": "مساعدك المفيد هنا",
"You're now logged in.": "لقد قمت الآن بتسجيل الدخول.",
"Youtube": "Youtube",
......
......@@ -60,12 +60,14 @@
"Bad Response": "",
"before": "",
"Being lazy": "",
"Beta": "",
"Builder Mode": "Режим на Създаване",
"Bypass SSL verification for Websites": "",
"Cancel": "Отказ",
"Categories": "Категории",
"Change Password": "Промяна на Парола",
"Chat": "Чат",
"Chat Bubble UI": "",
"Chat History": "Чат История",
"Chat History is off for this browser.": "Чат История е изключен за този браузър.",
"Chats": "Чатове",
......@@ -76,7 +78,7 @@
"Chunk Overlap": "Chunk Overlap",
"Chunk Params": "Chunk Params",
"Chunk Size": "Chunk Size",
"Citation": "",
"Citation": "Цитат",
"Click here for help.": "Натиснете тук за помощ.",
"Click here to": "",
"Click here to check other modelfiles.": "Натиснете тук за проверка на други моделфайлове.",
......@@ -118,7 +120,6 @@
"Dark": "Тъмен",
"Dashboard": "",
"Database": "База данни",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
"December": "",
"Default": "По подразбиране",
"Default (Automatic1111)": "По подразбиране (Automatic1111)",
......@@ -213,6 +214,7 @@
"General Settings": "Основни Настройки",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Hello, {{name}}": "Здравей, {{name}}",
"Help": "",
......@@ -257,6 +259,7 @@
"Max Tokens": "Max Tokens",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимум 3 модели могат да бъдат сваляни едновременно. Моля, опитайте отново по-късно.",
"May": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "",
"Mirostat": "Mirostat",
......@@ -285,9 +288,6 @@
"Modelfiles": "Модфайлове",
"Models": "Модели",
"More": "",
"My Documents": "Мои документи",
"My Modelfiles": "Мои модфайлове",
"My Prompts": "Мои промптове",
"Name": "Име",
"Name Tag": "Име Таг",
"Name your modelfile": "Име на модфайла",
......@@ -295,7 +295,7 @@
"New Password": "Нова парола",
"No": "",
"No results found": "",
"No source available": "",
"No source available": "Няма наличен източник",
"Not factually correct": "",
"Not sure what to add?": "Не сте сигурни, какво да добавите?",
"Not sure what to write? Switch to": "Не сте сигурни, какво да напишете? Превключете към",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "PDF Extract Images (OCR)",
"pending": "в очакване",
"Permission denied when accessing microphone: {{error}}": "Permission denied when accessing microphone: {{error}}",
"Personalization": "",
"Plain text (.txt)": "",
"Playground": "Плейграунд",
"Positive attitude": "",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "Rosé Pine Dawn",
"Save": "Запис",
"Save & Create": "Запис & Създаване",
"Save & Submit": "Запис & Изпращане",
"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": "Запазването на чат логове директно в хранилището на вашия браузър вече не се поддържа. Моля, отделете малко време, за да изтеглите и изтриете чат логовете си, като щракнете върху бутона по-долу. Не се притеснявайте, можете лесно да импортирате отново чат логовете си в бекенда чрез",
"Scan": "Сканиране",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "Изберете Ollama инстанция",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "Изпращане на Съобщение",
"Send message": "Изпращане на съобщение",
"September": "",
......@@ -418,7 +419,7 @@
"Sign Out": "Изход",
"Sign up": "Регистрация",
"Signing in": "",
"Source": "",
"Source": "Източник",
"Speech recognition error: {{error}}": "Speech recognition error: {{error}}",
"Speech-to-Text Engine": "Speech-to-Text Engine",
"SpeechRecognition API is not supported in this browser.": "SpeechRecognition API is not supported in this browser.",
......@@ -493,11 +494,12 @@
"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.": "Когато историята е изключена, нови чатове в този браузър ще не се показват в историята на никои от вашия профил.",
"Whisper (Local)": "Whisper (Локален)",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "Напиши предложение за промпт (напр. Кой сте вие?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Напиши описание в 50 знака, което описва [тема или ключова дума].",
"Yes": "",
"Yesterday": "",
"You": "Вие",
"You": "",
"You have no archived conversations.": "",
"You have shared this chat": "",
"You're a helpful assistant.": "Вие сте полезен асистент.",
......
......@@ -60,12 +60,14 @@
"Bad Response": "",
"before": "",
"Being lazy": "",
"Beta": "",
"Builder Mode": "বিল্ডার মোড",
"Bypass SSL verification for Websites": "",
"Cancel": "বাতিল",
"Categories": "ক্যাটাগরিসমূহ",
"Change Password": "পাসওয়ার্ড পরিবর্তন করুন",
"Chat": "চ্যাট",
"Chat Bubble UI": "",
"Chat History": "চ্যাট হিস্টোরি",
"Chat History is off for this browser.": "এই ব্রাউজারের জন্য চ্যাট হিস্টোরি বন্ধ আছে",
"Chats": "চ্যাটসমূহ",
......@@ -76,7 +78,7 @@
"Chunk Overlap": "চাঙ্ক ওভারল্যাপ",
"Chunk Params": "চাঙ্ক প্যারামিটার্স",
"Chunk Size": "চাঙ্ক সাইজ",
"Citation": "",
"Citation": "উদ্ধৃতি",
"Click here for help.": "সাহায্যের জন্য এখানে ক্লিক করুন",
"Click here to": "",
"Click here to check other modelfiles.": "অন্যান্য মডেলফাইল চেক করার জন্য এখানে ক্লিক করুন",
......@@ -118,7 +120,6 @@
"Dark": "ডার্ক",
"Dashboard": "",
"Database": "ডেটাবেজ",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
"December": "",
"Default": "ডিফল্ট",
"Default (Automatic1111)": "ডিফল্ট (Automatic1111)",
......@@ -213,6 +214,7 @@
"General Settings": "সাধারণ সেটিংসমূহ",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Hello, {{name}}": "হ্যালো, {{name}}",
"Help": "",
......@@ -257,6 +259,7 @@
"Max Tokens": "সর্বোচ্চ টোকন",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "একসঙ্গে সর্বোচ্চ তিনটি মডেল ডাউনলোড করা যায়। দয়া করে পরে আবার চেষ্টা করুন।",
"May": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "",
"Mirostat": "Mirostat",
......@@ -285,9 +288,6 @@
"Modelfiles": "মডেলফাইলসমূহ",
"Models": "মডেলসমূহ",
"More": "",
"My Documents": "আমার ডকুমেন্টসমূহ",
"My Modelfiles": "আমার মডেলফাইলসমূহ",
"My Prompts": "আমার প্রম্পটসমূহ",
"Name": "নাম",
"Name Tag": "নামের ট্যাগ",
"Name your modelfile": "আপনার মডেলফাইলের নাম দিন",
......@@ -295,7 +295,7 @@
"New Password": "নতুন পাসওয়ার্ড",
"No": "",
"No results found": "",
"No source available": "",
"No source available": "কোন উৎস পাওয়া যায়নি",
"Not factually correct": "",
"Not sure what to add?": "কী যুক্ত করতে হবে নিশ্চিত না?",
"Not sure what to write? Switch to": "কী লিখতে হবে নিশ্চিত না? পরিবর্তন করুন:",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "পিডিএফ এর ছবি থেকে লেখা বের করুন (OCR)",
"pending": "অপেক্ষমান",
"Permission denied when accessing microphone: {{error}}": "মাইক্রোফোন ব্যবহারের অনুমতি পাওয়া যায়নি: {{error}}",
"Personalization": "",
"Plain text (.txt)": "",
"Playground": "খেলাঘর",
"Positive attitude": "",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "ভোরের রোজ পাইন",
"Save": "সংরক্ষণ",
"Save & Create": "সংরক্ষণ এবং তৈরি করুন",
"Save & Submit": "সংরক্ষণ এবং সাবমিট করুন",
"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": "মাধ্যমে",
"Scan": "স্ক্যান",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "একটি Ollama ইন্সট্যান্স নির্বাচন করুন",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "একটি মেসেজ পাঠান",
"Send message": "মেসেজ পাঠান",
"September": "",
......@@ -418,7 +419,7 @@
"Sign Out": "সাইন আউট",
"Sign up": "সাইন আপ",
"Signing in": "",
"Source": "",
"Source": "উৎস",
"Speech recognition error: {{error}}": "স্পিচ রিকগনিশনে সমস্যা: {{error}}",
"Speech-to-Text Engine": "স্পিচ-টু-টেক্সট ইঞ্জিন",
"SpeechRecognition API is not supported in this browser.": "এই ব্রাউজার স্পিচরিকগনিশন এপিআই সাপোর্ট করে না।",
......@@ -493,11 +494,12 @@
"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.": "যদি হিস্টোরি বন্ধ থাকে তাহলে এই ব্রাউজারের নতুন চ্যাটগুলো আপনার কোন ডিভাইসের হিস্টোরিতেই দেখা যাবে না।",
"Whisper (Local)": "Whisper (লোকাল)",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "একটি প্রম্পট সাজেশন লিখুন (যেমন Who are you?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "৫০ শব্দের মধ্যে [topic or keyword] এর একটি সারসংক্ষেপ লিখুন।",
"Yes": "",
"Yesterday": "",
"You": "আপনি",
"You": "",
"You have no archived conversations.": "",
"You have shared this chat": "",
"You're a helpful assistant.": "আপনি একজন উপকারী এসিস্ট্যান্ট",
......
......@@ -60,12 +60,14 @@
"Bad Response": "",
"before": "",
"Being lazy": "",
"Beta": "",
"Builder Mode": "Mode Constructor",
"Bypass SSL verification for Websites": "",
"Cancel": "Cancel·la",
"Categories": "Categories",
"Change Password": "Canvia la Contrasenya",
"Chat": "Xat",
"Chat Bubble UI": "",
"Chat History": "Històric del Xat",
"Chat History is off for this browser.": "L'historial de xat està desactivat per a aquest navegador.",
"Chats": "Xats",
......@@ -76,7 +78,7 @@
"Chunk Overlap": "Solapament de Blocs",
"Chunk Params": "Paràmetres de Blocs",
"Chunk Size": "Mida del Bloc",
"Citation": "",
"Citation": "Citació",
"Click here for help.": "Fes clic aquí per ajuda.",
"Click here to": "",
"Click here to check other modelfiles.": "Fes clic aquí per comprovar altres fitxers de model.",
......@@ -118,7 +120,6 @@
"Dark": "Fosc",
"Dashboard": "",
"Database": "Base de Dades",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
"December": "",
"Default": "Per defecte",
"Default (Automatic1111)": "Per defecte (Automatic1111)",
......@@ -213,6 +214,7 @@
"General Settings": "Configuració General",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Hello, {{name}}": "Hola, {{name}}",
"Help": "",
......@@ -257,6 +259,7 @@
"Max Tokens": "Màxim de Tokens",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Es poden descarregar un màxim de 3 models simultàniament. Si us plau, prova-ho més tard.",
"May": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "",
"Mirostat": "Mirostat",
......@@ -285,9 +288,6 @@
"Modelfiles": "Fitxers de Model",
"Models": "Models",
"More": "",
"My Documents": "Els Meus Documents",
"My Modelfiles": "Els Meus Fitxers de Model",
"My Prompts": "Els Meus Prompts",
"Name": "Nom",
"Name Tag": "Etiqueta de Nom",
"Name your modelfile": "Nomena el teu fitxer de model",
......@@ -295,7 +295,7 @@
"New Password": "Nova Contrasenya",
"No": "",
"No results found": "",
"No source available": "",
"No source available": "Sense font disponible",
"Not factually correct": "",
"Not sure what to add?": "No estàs segur del que afegir?",
"Not sure what to write? Switch to": "No estàs segur del que escriure? Canvia a",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "Extreu Imatges de PDF (OCR)",
"pending": "pendent",
"Permission denied when accessing microphone: {{error}}": "Permís denegat en accedir al micròfon: {{error}}",
"Personalization": "",
"Plain text (.txt)": "",
"Playground": "Zona de Jocs",
"Positive attitude": "",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "Albada Rosé Pine",
"Save": "Guarda",
"Save & Create": "Guarda i Crea",
"Save & Submit": "Guarda i Envia",
"Save & Update": "Guarda i Actualitza",
"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": "Guardar registres de xat directament a l'emmagatzematge del teu navegador ja no és suportat. Si us plau, pren un moment per descarregar i eliminar els teus registres de xat fent clic al botó de sota. No et preocupis, pots reimportar fàcilment els teus registres de xat al backend a través de",
"Scan": "Escaneja",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "Selecciona una instància d'Ollama",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "Envia un Missatge",
"Send message": "Envia missatge",
"September": "",
......@@ -418,7 +419,7 @@
"Sign Out": "Tanca sessió",
"Sign up": "Registra't",
"Signing in": "",
"Source": "",
"Source": "Font",
"Speech recognition error: {{error}}": "Error de reconeixement de veu: {{error}}",
"Speech-to-Text Engine": "Motor de Veu a Text",
"SpeechRecognition API is not supported in this browser.": "L'API de Reconèixer Veu no és compatible amb aquest navegador.",
......@@ -493,11 +494,12 @@
"What’s New in": "Què hi ha de Nou en",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Quan l'historial està desactivat, els nous xats en aquest navegador no apareixeran en el teu historial en cap dels teus dispositius.",
"Whisper (Local)": "Whisper (Local)",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "Escriu una suggerència de prompt (p. ex. Qui ets tu?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Escriu un resum en 50 paraules que resumeixi [tema o paraula clau].",
"Yes": "",
"Yesterday": "",
"You": "Tu",
"You": "",
"You have no archived conversations.": "",
"You have shared this chat": "",
"You're a helpful assistant.": "Ets un assistent útil.",
......
......@@ -60,12 +60,14 @@
"Bad Response": "Schlechte Antwort",
"before": "bereits geteilt",
"Being lazy": "Faul sein",
"Beta": "",
"Builder Mode": "Builder Modus",
"Bypass SSL verification for Websites": "Bypass SSL-Verifizierung für Websites",
"Cancel": "Abbrechen",
"Categories": "Kategorien",
"Change Password": "Passwort ändern",
"Chat": "Chat",
"Chat Bubble UI": "",
"Chat History": "Chat Verlauf",
"Chat History is off for this browser.": "Chat Verlauf ist für diesen Browser ausgeschaltet.",
"Chats": "Chats",
......@@ -118,7 +120,6 @@
"Dark": "Dunkel",
"Dashboard": "Dashboard",
"Database": "Datenbank",
"DD/MM/YYYY HH:mm": "DD.MM.YYYY HH:mm",
"December": "Dezember",
"Default": "Standard",
"Default (Automatic1111)": "Standard (Automatic1111)",
......@@ -213,6 +214,7 @@
"General Settings": "Allgemeine Einstellungen",
"Generation Info": "Generierungsinformationen",
"Good Response": "Gute Antwort",
"h:mm a": "",
"has no conversations.": "hat keine Unterhaltungen.",
"Hello, {{name}}": "Hallo, {{name}}",
"Help": "Hilfe",
......@@ -257,6 +259,7 @@
"Max Tokens": "Maximale Tokens",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Es können maximal 3 Modelle gleichzeitig heruntergeladen werden. Bitte versuche es später erneut.",
"May": "Mai",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "Fortlaudende Nachrichten in diesem Chat werden nicht automatisch geteilt. Benutzer mit dem Link können den Chat einsehen.",
"Minimum Score": "Mindestscore",
"Mirostat": "Mirostat",
......@@ -285,9 +288,6 @@
"Modelfiles": "Modelfiles",
"Models": "Modelle",
"More": "Mehr",
"My Documents": "Meine Dokumente",
"My Modelfiles": "Meine Modelfiles",
"My Prompts": "Meine Prompts",
"Name": "Name",
"Name Tag": "Namens-Tag",
"Name your modelfile": "Benenne dein modelfile",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "Text von Bildern aus PDFs extrahieren (OCR)",
"pending": "ausstehend",
"Permission denied when accessing microphone: {{error}}": "Zugriff auf das Mikrofon verweigert: {{error}}",
"Personalization": "",
"Plain text (.txt)": "Nur Text (.txt)",
"Playground": "Testumgebung",
"Positive attitude": "Positive Einstellung",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "Rosé Pine Dawn",
"Save": "Speichern",
"Save & Create": "Speichern und erstellen",
"Save & Submit": "Speichern und senden",
"Save & Update": "Speichern und aktualisieren",
"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": "Das direkte Speichern von Chat-Protokollen im Browser-Speicher wird nicht mehr unterstützt. Bitte nimm dir einen Moment Zeit, um deine Chat-Protokolle herunterzuladen und zu löschen, indem du auf die Schaltfläche unten klickst. Keine Sorge, du kannst deine Chat-Protokolle problemlos über das Backend wieder importieren.",
"Scan": "Scannen",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "Eine Ollama Instanz auswählen",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "Eine Nachricht senden",
"Send message": "Nachricht senden",
"September": "September",
......@@ -493,11 +494,12 @@
"What’s New in": "Was gibt's Neues in",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Wenn die Historie ausgeschaltet ist, werden neue Chats nicht in deiner Historie auf deine Geräte angezeigt.",
"Whisper (Local)": "Whisper (Lokal)",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "Gebe einen Prompt-Vorschlag ein (z.B. Wer bist du?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Schreibe eine kurze Zusammenfassung in 50 Wörtern, die [Thema oder Schlüsselwort] zusammenfasst.",
"Yes": "",
"Yesterday": "Gestern",
"You": "Du",
"You": "",
"You have no archived conversations.": "Du hast keine archivierten Unterhaltungen.",
"You have shared this chat": "Du hast diesen Chat",
"You're a helpful assistant.": "Du bist ein hilfreicher Assistent.",
......
......@@ -60,12 +60,14 @@
"Bad Response": "",
"before": "",
"Being lazy": "",
"Beta": "",
"Builder Mode": "Builder Mode",
"Bypass SSL verification for Websites": "",
"Cancel": "Cancel",
"Categories": "Categories",
"Change Password": "Change Password",
"Chat": "Chat",
"Chat Bubble UI": "",
"Chat History": "Chat History",
"Chat History is off for this browser.": "Chat History off for this browser. Such sadness.",
"Chats": "Chats",
......@@ -118,7 +120,6 @@
"Dark": "Dark",
"Dashboard": "",
"Database": "Database",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
"December": "",
"Default": "Default",
"Default (Automatic1111)": "Default (Automatic1111)",
......@@ -213,6 +214,7 @@
"General Settings": "General Doge Settings",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Hello, {{name}}": "Much helo, {{name}}",
"Help": "",
......@@ -257,6 +259,7 @@
"Max Tokens": "Max Tokens",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximum of 3 models can be downloaded simultaneously. Please try again later.",
"May": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "",
"Mirostat": "Mirostat",
......@@ -285,9 +288,6 @@
"Modelfiles": "Modelfiles",
"Models": "Wowdels",
"More": "",
"My Documents": "My Doguments",
"My Modelfiles": "My Modelfiles",
"My Prompts": "My Promptos",
"Name": "Name",
"Name Tag": "Name Tag",
"Name your modelfile": "Name your modelfile",
......@@ -295,7 +295,7 @@
"New Password": "New Barkword",
"No": "",
"No results found": "",
"No source available": "",
"No source available": "No source available",
"Not factually correct": "",
"Not sure what to add?": "Not sure what to add?",
"Not sure what to write? Switch to": "Not sure what to write? Switch to",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "PDF Extract Wowmages (OCR)",
"pending": "pending",
"Permission denied when accessing microphone: {{error}}": "Permission denied when accessing microphone: {{error}}",
"Personalization": "",
"Plain text (.txt)": "",
"Playground": "Playground",
"Positive attitude": "",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "Rosé Pine Dawn",
"Save": "Save much wow",
"Save & Create": "Save & Create much create",
"Save & Submit": "Save & Submit very submit",
"Save & Update": "Save & Update much 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 in browser storage not support anymore. Pls download and delete your chat logs by click button below. Much easy re-import to backend through",
"Scan": "Scan much scan",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "Select an Ollama instance very choose",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "Send a Message much message",
"Send message": "Send message very send",
"September": "",
......@@ -418,7 +419,7 @@
"Sign Out": "Sign Out much logout",
"Sign up": "Sign up much join",
"Signing in": "",
"Source": "",
"Source": "Source",
"Speech recognition error: {{error}}": "Speech recognition error: {{error}} so error",
"Speech-to-Text Engine": "Speech-to-Text Engine much speak",
"SpeechRecognition API is not supported in this browser.": "SpeechRecognition API is not supported in this browser. Much sad.",
......@@ -493,11 +494,12 @@
"What’s New in": "What’s New in much new",
"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. Much history.",
"Whisper (Local)": "Whisper (Local) much whisper",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "Write a prompt suggestion (e.g. Who are you?) much suggest",
"Write a summary in 50 words that summarizes [topic or keyword].": "Write a summary in 50 words that summarizes [topic or keyword]. Much summarize.",
"Yes": "",
"Yesterday": "",
"You": "You very you",
"You": "",
"You have no archived conversations.": "",
"You have shared this chat": "",
"You're a helpful assistant.": "You're a helpful assistant. Much helpful.",
......
......@@ -60,12 +60,14 @@
"Bad Response": "",
"before": "",
"Being lazy": "",
"Beta": "",
"Builder Mode": "",
"Bypass SSL verification for Websites": "",
"Cancel": "",
"Categories": "",
"Change Password": "",
"Chat": "",
"Chat Bubble UI": "",
"Chat History": "",
"Chat History is off for this browser.": "",
"Chats": "",
......@@ -118,7 +120,6 @@
"Dark": "",
"Dashboard": "",
"Database": "",
"DD/MM/YYYY HH:mm": "",
"December": "",
"Default": "",
"Default (Automatic1111)": "",
......@@ -213,6 +214,7 @@
"General Settings": "",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Hello, {{name}}": "",
"Help": "",
......@@ -257,6 +259,7 @@
"Max Tokens": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "",
"May": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "",
"Mirostat": "",
......@@ -285,9 +288,6 @@
"Modelfiles": "",
"Models": "",
"More": "",
"My Documents": "",
"My Modelfiles": "",
"My Prompts": "",
"Name": "",
"Name Tag": "",
"Name your modelfile": "",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "",
"pending": "",
"Permission denied when accessing microphone: {{error}}": "",
"Personalization": "",
"Plain text (.txt)": "",
"Playground": "",
"Positive attitude": "",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "",
"Save": "",
"Save & Create": "",
"Save & Submit": "",
"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": "",
"Scan": "",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "",
"Send message": "",
"September": "",
......@@ -493,6 +494,7 @@
"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.": "",
"Whisper (Local)": "",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "",
"Write a summary in 50 words that summarizes [topic or keyword].": "",
"Yes": "",
......
......@@ -60,12 +60,14 @@
"Bad Response": "",
"before": "",
"Being lazy": "",
"Beta": "",
"Builder Mode": "",
"Bypass SSL verification for Websites": "",
"Cancel": "",
"Categories": "",
"Change Password": "",
"Chat": "",
"Chat Bubble UI": "",
"Chat History": "",
"Chat History is off for this browser.": "",
"Chats": "",
......@@ -118,7 +120,6 @@
"Dark": "",
"Dashboard": "",
"Database": "",
"DD/MM/YYYY HH:mm": "",
"December": "",
"Default": "",
"Default (Automatic1111)": "",
......@@ -213,6 +214,7 @@
"General Settings": "",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Hello, {{name}}": "",
"Help": "",
......@@ -257,6 +259,7 @@
"Max Tokens": "",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "",
"May": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "",
"Mirostat": "",
......@@ -285,9 +288,6 @@
"Modelfiles": "",
"Models": "",
"More": "",
"My Documents": "",
"My Modelfiles": "",
"My Prompts": "",
"Name": "",
"Name Tag": "",
"Name your modelfile": "",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "",
"pending": "",
"Permission denied when accessing microphone: {{error}}": "",
"Personalization": "",
"Plain text (.txt)": "",
"Playground": "",
"Positive attitude": "",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "",
"Save": "",
"Save & Create": "",
"Save & Submit": "",
"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": "",
"Scan": "",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "",
"Send message": "",
"September": "",
......@@ -493,6 +494,7 @@
"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.": "",
"Whisper (Local)": "",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "",
"Write a summary in 50 words that summarizes [topic or keyword].": "",
"Yes": "",
......
......@@ -60,12 +60,14 @@
"Bad Response": "",
"before": "",
"Being lazy": "",
"Beta": "",
"Builder Mode": "Modo de Constructor",
"Bypass SSL verification for Websites": "",
"Cancel": "Cancelar",
"Categories": "Categorías",
"Change Password": "Cambia la Contraseña",
"Chat": "Chat",
"Chat Bubble UI": "",
"Chat History": "Historial del Chat",
"Chat History is off for this browser.": "El Historial del Chat está apagado para este navegador.",
"Chats": "Chats",
......@@ -76,7 +78,7 @@
"Chunk Overlap": "Superposición de fragmentos",
"Chunk Params": "Parámetros de fragmentos",
"Chunk Size": "Tamaño de fragmentos",
"Citation": "",
"Citation": "Cita",
"Click here for help.": "Presiona aquí para obtener ayuda.",
"Click here to": "",
"Click here to check other modelfiles.": "Presiona aquí para consultar otros modelfiles.",
......@@ -118,7 +120,6 @@
"Dark": "Oscuro",
"Dashboard": "",
"Database": "Base de datos",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
"December": "",
"Default": "Por defecto",
"Default (Automatic1111)": "Por defecto (Automatic1111)",
......@@ -213,6 +214,7 @@
"General Settings": "Opciones Generales",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Hello, {{name}}": "Hola, {{name}}",
"Help": "",
......@@ -257,6 +259,7 @@
"Max Tokens": "Máximo de Tokens",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Se pueden descargar un máximo de 3 modelos simultáneamente. Por favor, inténtelo de nuevo más tarde.",
"May": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "",
"Mirostat": "Mirostat",
......@@ -285,9 +288,6 @@
"Modelfiles": "Modelfiles",
"Models": "Modelos",
"More": "",
"My Documents": "Mis Documentos",
"My Modelfiles": "Mis Modelfiles",
"My Prompts": "Mis Prompts",
"Name": "Nombre",
"Name Tag": "Nombre de etiqueta",
"Name your modelfile": "Nombra tu modelfile",
......@@ -295,7 +295,7 @@
"New Password": "Nueva Contraseña",
"No": "",
"No results found": "",
"No source available": "",
"No source available": "No hay fuente disponible",
"Not factually correct": "",
"Not sure what to add?": "¿No sabes qué añadir?",
"Not sure what to write? Switch to": "¿No sabes qué escribir? Cambia a",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "Extraer imágenes de PDF (OCR)",
"pending": "pendiente",
"Permission denied when accessing microphone: {{error}}": "Permiso denegado al acceder al micrófono: {{error}}",
"Personalization": "",
"Plain text (.txt)": "",
"Playground": "Patio de juegos",
"Positive attitude": "",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "Rosé Pine Dawn",
"Save": "Guardar",
"Save & Create": "Guardar y Crear",
"Save & Submit": "Guardar y Enviar",
"Save & Update": "Guardar y Actualizar",
"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": "Ya no se admite guardar registros de chat directamente en el almacenamiento de su navegador. Tómese un momento para descargar y eliminar sus registros de chat haciendo clic en el botón a continuación. No te preocupes, puedes volver a importar fácilmente tus registros de chat al backend a través de",
"Scan": "Escanear",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "Seleccione una instancia de Ollama",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "Enviar un Mensaje",
"Send message": "Enviar Mensaje",
"September": "",
......@@ -418,7 +419,7 @@
"Sign Out": "Cerrar sesión",
"Sign up": "Crear una cuenta",
"Signing in": "",
"Source": "",
"Source": "Fuente",
"Speech recognition error: {{error}}": "Error de reconocimiento de voz: {{error}}",
"Speech-to-Text Engine": "Motor de voz a texto",
"SpeechRecognition API is not supported in this browser.": "La API SpeechRecognition no es compatible con este navegador.",
......@@ -493,11 +494,12 @@
"What’s New in": "Novedades en",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Cuando el historial está desactivado, los nuevos chats en este navegador no aparecerán en el historial de ninguno de sus dispositivos..",
"Whisper (Local)": "Whisper (Local)",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "Escribe una sugerencia para un prompt (por ejemplo, ¿quién eres?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Escribe un resumen en 50 palabras que resuma [tema o palabra clave].",
"Yes": "",
"Yesterday": "",
"You": "Usted",
"You": "",
"You have no archived conversations.": "",
"You have shared this chat": "",
"You're a helpful assistant.": "Eres un asistente útil.",
......
......@@ -60,12 +60,14 @@
"Bad Response": "",
"before": "",
"Being lazy": "",
"Beta": "",
"Builder Mode": "حالت سازنده",
"Bypass SSL verification for Websites": "",
"Cancel": "لغو",
"Categories": "دسته\u200cبندی\u200cها",
"Change Password": "تغییر رمز عبور",
"Chat": "گپ",
"Chat Bubble UI": "",
"Chat History": "تاریخچه\u200cی گفتگو",
"Chat History is off for this browser.": "سابقه گپ برای این مرورگر خاموش است.",
"Chats": "گپ\u200cها",
......@@ -76,7 +78,7 @@
"Chunk Overlap": "همپوشانی تکه",
"Chunk Params": "پارامترهای تکه",
"Chunk Size": "اندازه تکه",
"Citation": "",
"Citation": "استناد",
"Click here for help.": "برای کمک اینجا را کلیک کنید.",
"Click here to": "",
"Click here to check other modelfiles.": "برای بررسی سایر فایل\u200cهای مدل اینجا را کلیک کنید.",
......@@ -118,7 +120,6 @@
"Dark": "تیره",
"Dashboard": "",
"Database": "پایگاه داده",
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
"December": "",
"Default": "پیشفرض",
"Default (Automatic1111)": "پیشفرض (Automatic1111)",
......@@ -213,6 +214,7 @@
"General Settings": "تنظیمات عمومی",
"Generation Info": "",
"Good Response": "",
"h:mm a": "",
"has no conversations.": "",
"Hello, {{name}}": "سلام، {{name}}",
"Help": "",
......@@ -257,6 +259,7 @@
"Max Tokens": "حداکثر توکن",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "حداکثر 3 مدل را می توان به طور همزمان دانلود کرد. لطفاً بعداً دوباره امتحان کنید.",
"May": "",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
"Minimum Score": "",
"Mirostat": "Mirostat",
......@@ -285,9 +288,6 @@
"Modelfiles": "فایل\u200cهای مدل",
"Models": "مدل\u200cها",
"More": "",
"My Documents": "اسناد من",
"My Modelfiles": "فایل\u200cهای مدل من",
"My Prompts": "پرامپت\u200cهای من",
"Name": "نام",
"Name Tag": "نام تگ",
"Name your modelfile": "فایل مدل را نام\u200cگذاری کنید",
......@@ -295,7 +295,7 @@
"New Password": "رمز عبور جدید",
"No": "",
"No results found": "",
"No source available": "",
"No source available": "منبعی در دسترس نیست",
"Not factually correct": "",
"Not sure what to add?": "مطمئن نیستید چه چیزی را اضافه کنید؟",
"Not sure what to write? Switch to": "مطمئن نیستید چه بنویسید؟ تغییر به",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "استخراج تصاویر از PDF (OCR)",
"pending": "در انتظار",
"Permission denied when accessing microphone: {{error}}": "هنگام دسترسی به میکروفون، اجازه داده نشد: {{error}}",
"Personalization": "",
"Plain text (.txt)": "",
"Playground": "زمین بازی",
"Positive attitude": "",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "Rosé Pine Dawn",
"Save": "ذخیره",
"Save & Create": "ذخیره و ایجاد",
"Save & Submit": "ذخیره و ارسال",
"Save & Update": "ذخیره و به\u200cروزرسانی",
"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": "ذخیره گزارش\u200cهای چت مستقیماً در حافظه مرورگر شما دیگر پشتیبانی نمی\u200cشود. لطفاً با کلیک بر روی دکمه زیر، چند لحظه برای دانلود و حذف گزارش های چت خود وقت بگذارید. نگران نباشید، شما به راحتی می توانید گزارش های چت خود را از طریق بکند دوباره وارد کنید",
"Scan": "اسکن",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "انتخاب یک نمونه از اولاما",
"Select model": "",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "ارسال یک پیام",
"Send message": "ارسال پیام",
"September": "",
......@@ -418,7 +419,7 @@
"Sign Out": "خروج",
"Sign up": "ثبت نام",
"Signing in": "",
"Source": "",
"Source": "منبع",
"Speech recognition error: {{error}}": "خطای تشخیص گفتار: {{error}}",
"Speech-to-Text Engine": "موتور گفتار به متن",
"SpeechRecognition API is not supported in this browser.": "API تشخیص گفتار در این مرورگر پشتیبانی نمی شود.",
......@@ -493,11 +494,12 @@
"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.": "وقتی سابقه خاموش است، چت\u200cهای جدید در این مرورگر در سابقه شما در هیچ یک از دستگاه\u200cهایتان ظاهر نمی\u200cشوند.",
"Whisper (Local)": "ویسپر (محلی)",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "یک پیشنهاد پرامپت بنویسید (مثلاً شما کی هستید؟)",
"Write a summary in 50 words that summarizes [topic or keyword].": "خلاصه ای در 50 کلمه بنویسید که [موضوع یا کلمه کلیدی] را خلاصه کند.",
"Yes": "",
"Yesterday": "",
"You": "شما",
"You": "",
"You have no archived conversations.": "",
"You have shared this chat": "",
"You're a helpful assistant.": "تو یک دستیار سودمند هستی.",
......
......@@ -60,12 +60,14 @@
"Bad Response": "Epäkelpo vastaus",
"before": "ennen",
"Being lazy": "Oli laiska",
"Beta": "",
"Builder Mode": "Rakentajan tila",
"Bypass SSL verification for Websites": "Ohita SSL-varmennus verkkosivustoille",
"Cancel": "Peruuta",
"Categories": "Kategoriat",
"Change Password": "Vaihda salasana",
"Chat": "Keskustelu",
"Chat Bubble UI": "",
"Chat History": "Keskusteluhistoria",
"Chat History is off for this browser.": "Keskusteluhistoria on pois päältä tällä selaimella.",
"Chats": "Keskustelut",
......@@ -118,7 +120,6 @@
"Dark": "Tumma",
"Dashboard": "Kojelauta",
"Database": "Tietokanta",
"DD/MM/YYYY HH:mm": "DD.MM.YYYY HH:mm",
"December": "joulukuu",
"Default": "Oletus",
"Default (Automatic1111)": "Oletus (AUTOMATIC1111)",
......@@ -213,6 +214,7 @@
"General Settings": "Yleisasetukset",
"Generation Info": "Generointitiedot",
"Good Response": "Hyvä vastaus",
"h:mm a": "",
"has no conversations.": "ei ole keskusteluja.",
"Hello, {{name}}": "Terve, {{name}}",
"Help": "Apua",
......@@ -257,6 +259,7 @@
"Max Tokens": "Maksimitokenit",
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Enintään 3 mallia voidaan ladata samanaikaisesti. Yritä myöhemmin uudelleen.",
"May": "toukokuu",
"Memory": "",
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "Viestejä, jotka lähetät luotuasi linkin, ei jaeta. Käyttäjät, joilla on tämä osoite voivat tarkastella jaettua keskustelua.",
"Minimum Score": "Vähimmäispisteet",
"Mirostat": "Mirostat",
......@@ -285,9 +288,6 @@
"Modelfiles": "Mallitiedostot",
"Models": "Mallit",
"More": "Lisää",
"My Documents": "Omat asiakirjat",
"My Modelfiles": "Omat mallitiedostot",
"My Prompts": "Omat kehotteet",
"Name": "Nimi",
"Name Tag": "Nimitagi",
"Name your modelfile": "Nimeä mallitiedostosi",
......@@ -333,6 +333,7 @@
"PDF Extract Images (OCR)": "PDF-tiedoston kuvien erottelu (OCR)",
"pending": "odottaa",
"Permission denied when accessing microphone: {{error}}": "Mikrofonin käyttöoikeus evätty: {{error}}",
"Personalization": "",
"Plain text (.txt)": "Pelkkä teksti (.txt)",
"Playground": "Leikkipaikka",
"Positive attitude": "Positiivinen asenne",
......@@ -372,7 +373,6 @@
"Rosé Pine Dawn": "Aamuinen Rosee-mänty",
"Save": "Tallenna",
"Save & Create": "Tallenna ja luo",
"Save & Submit": "Tallenna ja lähetä",
"Save & Update": "Tallenna ja päivitä",
"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": "Keskustelulokien tallentaminen suoraan selaimen tallennustilaan ei ole enää tuettua. Lataa ja poista keskustelulokit napsauttamalla alla olevaa painiketta. Älä huoli, voit helposti tuoda keskustelulokit takaisin backendiin",
"Scan": "Skannaa",
......@@ -390,6 +390,7 @@
"Select an Ollama instance": "Valitse Ollama-instanssi",
"Select model": "Valitse malli",
"Selected model does not support image inputs.": "",
"Send": "",
"Send a Message": "Lähetä viesti",
"Send message": "Lähetä viesti",
"September": "syyskuu",
......@@ -493,11 +494,12 @@
"What’s New in": "Mitä uutta",
"When history is turned off, new chats on this browser won't appear in your history on any of your devices.": "Kun historia on pois päältä, uudet keskustelut tässä selaimessa eivät näy historiassasi millään laitteellasi.",
"Whisper (Local)": "Whisper (paikallinen)",
"Workspace": "",
"Write a prompt suggestion (e.g. Who are you?)": "Kirjoita ehdotettu kehote (esim. Kuka olet?)",
"Write a summary in 50 words that summarizes [topic or keyword].": "Kirjoita 50 sanan yhteenveto, joka tiivistää [aihe tai avainsana].",
"Yes": "",
"Yesterday": "Eilen",
"You": "Sinä",
"You": "",
"You have no archived conversations.": "Sinulla ei ole arkistoituja keskusteluja.",
"You have shared this chat": "Olet jakanut tämän keskustelun",
"You're a helpful assistant.": "Olet avulias apulainen.",
......
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