mirror of
https://github.com/open-webui/open-webui
synced 2025-02-20 20:07:28 +00:00
Merge branch 'dev' into fix/share-chat-reactive-loop
This commit is contained in:
commit
ea6f1a0e57
18
.github/workflows/format-build-frontend.yaml
vendored
18
.github/workflows/format-build-frontend.yaml
vendored
@ -37,3 +37,21 @@ jobs:
|
||||
|
||||
- name: Build Frontend
|
||||
run: npm run build
|
||||
|
||||
test-frontend:
|
||||
name: 'Frontend Unit Tests'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run vitest
|
||||
run: npm run test:frontend
|
||||
|
1002
package-lock.json
generated
1002
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,8 @@
|
||||
"format": "prettier --plugin-search-dir --write \"**/*.{js,ts,svelte,css,md,html,json}\"",
|
||||
"format:backend": "black . --exclude \"/venv/\"",
|
||||
"i18n:parse": "i18next --config i18next-parser.config.ts && prettier --write \"src/lib/i18n/**/*.{js,json}\"",
|
||||
"cy:open": "cypress open"
|
||||
"cy:open": "cypress open",
|
||||
"test:frontend": "vitest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
@ -41,7 +42,8 @@
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^5.0.0",
|
||||
"vite": "^4.4.2"
|
||||
"vite": "^4.4.2",
|
||||
"vitest": "^1.6.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
@ -38,7 +38,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col mt-0.5 w-full">
|
||||
<div class="flex flex-col w-full items-center md:items-start">
|
||||
{#each selectedModels as selectedModel, selectedModelIdx}
|
||||
<div class="flex w-full max-w-fit">
|
||||
<div class="overflow-hidden w-full">
|
||||
@ -109,7 +109,7 @@
|
||||
</div>
|
||||
|
||||
{#if showSetDefault}
|
||||
<div class="text-left mt-0.5 ml-1 text-[0.7rem] text-gray-500">
|
||||
<div class="hidden md:absolute text-left mt-0.5 ml-1 text-[0.7rem] text-gray-500">
|
||||
<button on:click={saveDefaultModel}> {$i18n.t('Set as default')}</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
import { cancelOllamaRequest, deleteModel, getOllamaVersion, pullModel } from '$lib/apis/ollama';
|
||||
|
||||
import { user, MODEL_DOWNLOAD_POOL, models } from '$lib/stores';
|
||||
import { user, MODEL_DOWNLOAD_POOL, models, mobile } from '$lib/stores';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { capitalizeFirstLetter, getModels, splitStream } from '$lib/utils';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
@ -201,10 +201,11 @@
|
||||
<ChevronDown className=" self-center ml-2 size-3" strokeWidth="2.5" />
|
||||
</div>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Content
|
||||
class=" z-40 {className} max-w-[calc(100vw-1rem)] justify-start rounded-lg bg-white dark:bg-gray-900 dark:text-white shadow-lg border border-gray-300/30 dark:border-gray-700/50 outline-none "
|
||||
class=" z-40 {className} max-w-[calc(100vw-1rem)] justify-start rounded-xl bg-white dark:bg-gray-850 dark:text-white shadow-lg border border-gray-300/30 dark:border-gray-700/50 outline-none "
|
||||
transition={flyAndScale}
|
||||
side={'bottom-start'}
|
||||
side={$mobile ? 'bottom' : 'bottom-start'}
|
||||
sideOffset={4}
|
||||
>
|
||||
<slot>
|
||||
@ -228,7 +229,7 @@
|
||||
{#each filteredItems as item}
|
||||
<button
|
||||
aria-label="model-item"
|
||||
class="flex w-full text-left font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-none transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-850 rounded-lg cursor-pointer data-[highlighted]:bg-muted"
|
||||
class="flex w-full text-left font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-none transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg cursor-pointer data-[highlighted]:bg-muted"
|
||||
on:click={() => {
|
||||
value = item.value;
|
||||
|
||||
@ -312,7 +313,7 @@
|
||||
|
||||
{#if !(searchValue.trim() in $MODEL_DOWNLOAD_POOL) && searchValue && ollamaVersion && $user.role === 'admin'}
|
||||
<button
|
||||
class="flex w-full font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-none transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-850 rounded-lg cursor-pointer data-[highlighted]:bg-muted"
|
||||
class="flex w-full font-medium line-clamp-1 select-none items-center rounded-button py-2 pl-3 pr-1.5 text-sm text-gray-700 dark:text-gray-100 outline-none transition-all duration-75 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg cursor-pointer data-[highlighted]:bg-muted"
|
||||
on:click={() => {
|
||||
pullModelHandler();
|
||||
}}
|
||||
|
@ -2,7 +2,16 @@
|
||||
import { getContext } from 'svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
|
||||
import { WEBUI_NAME, chatId, modelfiles, settings, showSettings } from '$lib/stores';
|
||||
import {
|
||||
WEBUI_NAME,
|
||||
chatId,
|
||||
mobile,
|
||||
modelfiles,
|
||||
settings,
|
||||
showSettings,
|
||||
showSidebar,
|
||||
user
|
||||
} from '$lib/stores';
|
||||
|
||||
import { slide } from 'svelte/transition';
|
||||
import ShareChatModal from '../chat/ShareChatModal.svelte';
|
||||
@ -10,6 +19,7 @@
|
||||
import Tooltip from '../common/Tooltip.svelte';
|
||||
import Menu from './Navbar/Menu.svelte';
|
||||
import { page } from '$app/stores';
|
||||
import UserMenu from './Sidebar/UserMenu.svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
|
||||
@ -28,8 +38,34 @@
|
||||
|
||||
<ShareChatModal bind:show={showShareChatModal} chatId={$chatId} />
|
||||
<nav id="nav" class=" sticky py-2.5 top-0 flex flex-row justify-center z-30">
|
||||
<div class=" flex max-w-full w-full mx-auto px-5 pt-0.5 md:px-[1.3rem]">
|
||||
<div class=" flex max-w-full w-full mx-auto px-5 pt-0.5 md:px-[1rem]">
|
||||
<div class="flex items-center w-full max-w-full">
|
||||
<div class="{$showSidebar ? 'md:hidden' : ''} mr-3 self-start flex flex-none items-center">
|
||||
<button
|
||||
id="sidebar-toggle-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>
|
||||
<div class="flex-1 overflow-hidden max-w-full">
|
||||
{#if showModelSelector}
|
||||
<ModelSelector bind:selectedModels showSetDefault={!shareEnabled} />
|
||||
@ -37,12 +73,12 @@
|
||||
</div>
|
||||
|
||||
<div class="self-start flex flex-none items-center">
|
||||
<div class="md:hidden flex self-center w-[1px] h-5 mx-2 bg-gray-300 dark:bg-stone-700" />
|
||||
<!-- <div class="md:hidden flex self-center w-[1px] h-5 mx-2 bg-gray-300 dark:bg-stone-700" /> -->
|
||||
|
||||
{#if !shareEnabled}
|
||||
<Tooltip content={$i18n.t('Settings')}>
|
||||
<button
|
||||
class="cursor-pointer p-1.5 flex dark:hover:bg-gray-700 rounded-full transition"
|
||||
class="hidden md:flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-100 dark:hover:bg-gray-850 transition"
|
||||
id="open-settings-button"
|
||||
on:click={async () => {
|
||||
await showSettings.set(!$showSettings);
|
||||
@ -81,9 +117,9 @@
|
||||
}}
|
||||
>
|
||||
<button
|
||||
class="cursor-pointer p-1.5 flex dark:hover:bg-gray-700 rounded-full transition"
|
||||
class="hidden md:flex cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-100 dark:hover:bg-gray-850 transition"
|
||||
id="chat-context-menu-button"
|
||||
>
|
||||
>
|
||||
<div class=" m-auto self-center">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -106,7 +142,9 @@
|
||||
<Tooltip content={$i18n.t('New Chat')}>
|
||||
<button
|
||||
id="new-chat-button"
|
||||
class=" cursor-pointer p-1.5 flex dark:hover:bg-gray-700 rounded-full transition"
|
||||
class=" flex {$showSidebar
|
||||
? 'md:hidden'
|
||||
: ''} cursor-pointer px-2 py-2 rounded-xl hover:bg-gray-100 dark:hover:bg-gray-850 transition"
|
||||
on:click={() => {
|
||||
initNewChat();
|
||||
}}
|
||||
@ -128,6 +166,29 @@
|
||||
</div>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
{#if !$mobile && $user !== undefined}
|
||||
<UserMenu
|
||||
role={$user.role}
|
||||
on:show={(e) => {
|
||||
if (e.detail === 'archived-chat') {
|
||||
// showArchivedChatsModal = true;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<button
|
||||
class=" flex rounded-xl p-1.5 w-full hover:bg-gray-100 dark:hover:bg-gray-850 transition"
|
||||
>
|
||||
<div class=" self-center">
|
||||
<img
|
||||
src={$user.profile_image_url}
|
||||
class=" size-6 object-cover rounded-full"
|
||||
alt="User profile"
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
</UserMenu>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -76,14 +76,14 @@
|
||||
|
||||
<div slot="content">
|
||||
<DropdownMenu.Content
|
||||
class="w-full max-w-[200px] 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-lg"
|
||||
class="w-full max-w-[200px] 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-lg"
|
||||
sideOffset={8}
|
||||
side="bottom"
|
||||
align="end"
|
||||
transition={flyAndScale}
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-850 rounded-md"
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-800 rounded-md"
|
||||
on:click={async () => {
|
||||
await showSettings.set(!$showSettings);
|
||||
}}
|
||||
@ -112,7 +112,7 @@
|
||||
|
||||
{#if shareEnabled}
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-850 rounded-md"
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-800 rounded-md"
|
||||
id="chat-share-button"
|
||||
on:click={() => {
|
||||
shareHandler();
|
||||
@ -141,7 +141,7 @@
|
||||
/> -->
|
||||
<DropdownMenu.Sub>
|
||||
<DropdownMenu.SubTrigger
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-850 rounded-md"
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-800 rounded-md"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -161,12 +161,12 @@
|
||||
<div class="flex items-center">{$i18n.t('Download')}</div>
|
||||
</DropdownMenu.SubTrigger>
|
||||
<DropdownMenu.SubContent
|
||||
class="w-full 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-lg"
|
||||
class="w-full rounded-lg 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-lg"
|
||||
transition={flyAndScale}
|
||||
sideOffset={8}
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-850 rounded-md"
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-800 rounded-md"
|
||||
on:click={() => {
|
||||
downloadTxt();
|
||||
}}
|
||||
@ -175,7 +175,7 @@
|
||||
</DropdownMenu.Item>
|
||||
|
||||
<DropdownMenu.Item
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-850 rounded-md"
|
||||
class="flex gap-2 items-center px-3 py-2 text-sm cursor-pointer dark:hover:bg-gray-800 rounded-md"
|
||||
on:click={() => {
|
||||
downloadPdf();
|
||||
}}
|
||||
|
@ -1,6 +1,15 @@
|
||||
<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
|
||||
} from '$lib/stores';
|
||||
import { onMount, getContext } from 'svelte';
|
||||
|
||||
const i18n = getContext('i18n');
|
||||
@ -183,6 +192,17 @@
|
||||
}}
|
||||
/>
|
||||
|
||||
<!-- 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"
|
||||
@ -193,14 +213,37 @@
|
||||
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 flex justify-between space-x-2">
|
||||
<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>
|
||||
<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 justify-between rounded-xl px-2 py-2 hover:bg-gray-100 dark:hover:bg-gray-850 transition"
|
||||
href="/"
|
||||
on:click={async () => {
|
||||
selectedChatId = null;
|
||||
@ -212,24 +255,12 @@
|
||||
}, 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>
|
||||
|
||||
<div class="self-center">
|
||||
<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"
|
||||
@ -681,43 +712,45 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-2.5">
|
||||
<!-- <hr class=" border-gray-900 mb-1 w-full" /> -->
|
||||
{#if $mobile}
|
||||
<div class="px-2.5">
|
||||
<!-- <hr class=" border-gray-900 mb-1 w-full" /> -->
|
||||
|
||||
<div class="flex flex-col">
|
||||
{#if $user !== undefined}
|
||||
<UserMenu
|
||||
role={$user.role}
|
||||
on:show={(e) => {
|
||||
if (e.detail === 'archived-chat') {
|
||||
showArchivedChatsModal = true;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<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="flex flex-col">
|
||||
{#if $user !== undefined}
|
||||
<UserMenu
|
||||
role={$user.role}
|
||||
on:show={(e) => {
|
||||
if (e.detail === 'archived-chat') {
|
||||
showArchivedChatsModal = 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>
|
||||
</UserMenu>
|
||||
{/if}
|
||||
<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=" 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>
|
||||
</UserMenu>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</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"
|
||||
|
@ -36,14 +36,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-[180px] 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 dark:hover:bg-gray-800 rounded-md"
|
||||
on:click={() => {
|
||||
shareHandler();
|
||||
}}
|
||||
@ -53,7 +53,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 dark:hover:bg-gray-800 rounded-md"
|
||||
on:click={() => {
|
||||
renameHandler();
|
||||
}}
|
||||
@ -63,7 +63,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 dark:hover:bg-gray-800 rounded-md"
|
||||
on:click={() => {
|
||||
deleteHandler();
|
||||
}}
|
||||
|
@ -28,7 +28,7 @@
|
||||
|
||||
<slot name="content">
|
||||
<DropdownMenu.Content
|
||||
class="w-full max-w-[240px] rounded-lg p-1 py-1 border border-gray-850 z-50 bg-gray-900 text-white text-sm"
|
||||
class="w-full max-w-[240px] rounded-lg p-1 py-1 border border-gray-300/30 dark:border-gray-700/50 z-50 bg-gray-850 text-white text-sm"
|
||||
sideOffset={8}
|
||||
side="bottom"
|
||||
align="start"
|
||||
|
@ -1,8 +1,8 @@
|
||||
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`;
|
||||
|
||||
|
@ -1,34 +1,34 @@
|
||||
{
|
||||
"'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' o '-1' per nessuna scadenza.",
|
||||
"(Beta)": "(Beta)",
|
||||
"(e.g. `sh webui.sh --api`)": "",
|
||||
"(e.g. `sh webui.sh --api`)": "(p.e. `sh webui.sh --api`)",
|
||||
"(latest)": "(ultima)",
|
||||
"{{modelName}} is thinking...": "{{modelName}} sta pensando...",
|
||||
"{{user}}'s Chats": "",
|
||||
"{{user}}'s Chats": "{{user}} Chat",
|
||||
"{{webUIName}} Backend Required": "{{webUIName}} Backend richiesto",
|
||||
"a user": "un utente",
|
||||
"About": "Informazioni",
|
||||
"Account": "Account",
|
||||
"Accurate information": "",
|
||||
"Accurate information": "Informazioni accurate",
|
||||
"Add a model": "Aggiungi un modello",
|
||||
"Add a model tag name": "Aggiungi un nome tag del modello",
|
||||
"Add a short description about what this modelfile does": "Aggiungi una breve descrizione di ciò che fa questo file modello",
|
||||
"Add a short title for this prompt": "Aggiungi un titolo breve per questo prompt",
|
||||
"Add a tag": "Aggiungi un tag",
|
||||
"Add custom prompt": "",
|
||||
"Add custom prompt": "Aggiungi un prompt custom",
|
||||
"Add Docs": "Aggiungi documenti",
|
||||
"Add Files": "Aggiungi file",
|
||||
"Add message": "Aggiungi messaggio",
|
||||
"Add Model": "",
|
||||
"Add Tags": "aggiungi tag",
|
||||
"Add User": "",
|
||||
"Add Model": "Aggiungi modello",
|
||||
"Add Tags": "Aggiungi tag",
|
||||
"Add User": "Aggiungi utente",
|
||||
"Adjusting these settings will apply changes universally to all users.": "La modifica di queste impostazioni applicherà le modifiche universalmente a tutti gli utenti.",
|
||||
"admin": "amministratore",
|
||||
"Admin Panel": "Pannello di amministrazione",
|
||||
"Admin Settings": "Impostazioni amministratore",
|
||||
"Advanced Parameters": "Parametri avanzati",
|
||||
"all": "tutti",
|
||||
"All Documents": "",
|
||||
"All Documents": "Tutti i documenti",
|
||||
"All Users": "Tutti gli utenti",
|
||||
"Allow": "Consenti",
|
||||
"Allow Chat Deletion": "Consenti l'eliminazione della chat",
|
||||
@ -36,32 +36,32 @@
|
||||
"Already have an account?": "Hai già un account?",
|
||||
"an assistant": "un assistente",
|
||||
"and": "e",
|
||||
"and create a new shared link.": "",
|
||||
"and create a new shared link.": "e crea un nuovo link condiviso.",
|
||||
"API Base URL": "URL base API",
|
||||
"API Key": "Chiave API",
|
||||
"API Key created.": "",
|
||||
"API keys": "",
|
||||
"API Key created.": "Chiave API creata.",
|
||||
"API keys": "Chiavi API",
|
||||
"API RPM": "API RPM",
|
||||
"April": "",
|
||||
"Archive": "",
|
||||
"April": "Aprile",
|
||||
"Archive": "Archivio",
|
||||
"Archived Chats": "Chat archiviate",
|
||||
"are allowed - Activate this command by typing": "sono consentiti - Attiva questo comando digitando",
|
||||
"Are you sure?": "Sei sicuro?",
|
||||
"Attach file": "",
|
||||
"Attention to detail": "",
|
||||
"Attach file": "Allega file",
|
||||
"Attention to detail": "Attenzione ai dettagli",
|
||||
"Audio": "Audio",
|
||||
"August": "",
|
||||
"August": "Agosto",
|
||||
"Auto-playback response": "Riproduzione automatica della risposta",
|
||||
"Auto-send input after 3 sec.": "Invio automatico dell'input dopo 3 secondi.",
|
||||
"AUTOMATIC1111 Base URL": "URL base AUTOMATIC1111",
|
||||
"AUTOMATIC1111 Base URL is required.": "L'URL base AUTOMATIC1111 è obbligatorio.",
|
||||
"available!": "disponibile!",
|
||||
"Back": "Indietro",
|
||||
"Bad Response": "",
|
||||
"before": "",
|
||||
"Being lazy": "",
|
||||
"Bad Response": "Risposta non valida",
|
||||
"before": "prima",
|
||||
"Being lazy": "Essere pigri",
|
||||
"Builder Mode": "Modalità costruttore",
|
||||
"Bypass SSL verification for Websites": "",
|
||||
"Bypass SSL verification for Websites": "Aggira la verifica SSL per i siti web",
|
||||
"Cancel": "Annulla",
|
||||
"Categories": "Categorie",
|
||||
"Change Password": "Cambia password",
|
||||
@ -78,66 +78,66 @@
|
||||
"Chunk Size": "Dimensione chunk",
|
||||
"Citation": "Citazione",
|
||||
"Click here for help.": "Clicca qui per aiuto.",
|
||||
"Click here to": "",
|
||||
"Click here to": "Clicca qui per",
|
||||
"Click here to check other modelfiles.": "Clicca qui per controllare altri file modello.",
|
||||
"Click here to select": "Clicca qui per selezionare",
|
||||
"Click here to select a csv file.": "",
|
||||
"Click here to select a csv file.": "Clicca qui per selezionare un file csv.",
|
||||
"Click here to select documents.": "Clicca qui per selezionare i documenti.",
|
||||
"click here.": "clicca qui.",
|
||||
"Click on the user role button to change a user's role.": "Clicca sul pulsante del ruolo utente per modificare il ruolo di un utente.",
|
||||
"Close": "Chiudi",
|
||||
"Collection": "Collezione",
|
||||
"ComfyUI": "",
|
||||
"ComfyUI Base URL": "",
|
||||
"ComfyUI Base URL is required.": "",
|
||||
"ComfyUI": "ComfyUI",
|
||||
"ComfyUI Base URL": "URL base ComfyUI",
|
||||
"ComfyUI Base URL is required.": "L'URL base ComfyUI è obbligatorio.",
|
||||
"Command": "Comando",
|
||||
"Confirm Password": "Conferma password",
|
||||
"Connections": "Connessioni",
|
||||
"Content": "Contenuto",
|
||||
"Context Length": "Lunghezza contesto",
|
||||
"Continue Response": "",
|
||||
"Continue Response": "Continua risposta",
|
||||
"Conversation Mode": "Modalità conversazione",
|
||||
"Copied shared chat URL to clipboard!": "",
|
||||
"Copy": "",
|
||||
"Copied shared chat URL to clipboard!": "URL della chat condivisa copiato negli appunti!",
|
||||
"Copy": "Copia",
|
||||
"Copy last code block": "Copia ultimo blocco di codice",
|
||||
"Copy last response": "Copia ultima risposta",
|
||||
"Copy Link": "",
|
||||
"Copy Link": "Copia link",
|
||||
"Copying to clipboard was successful!": "Copia negli appunti riuscita!",
|
||||
"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':": "Crea una frase concisa di 3-5 parole come intestazione per la seguente query, aderendo rigorosamente al limite di 3-5 parole ed evitando l'uso della parola 'titolo':",
|
||||
"Create a modelfile": "Crea un file modello",
|
||||
"Create Account": "Crea account",
|
||||
"Create new key": "",
|
||||
"Create new secret key": "",
|
||||
"Create new key": "Crea nuova chiave",
|
||||
"Create new secret key": "Crea nuova chiave segreta",
|
||||
"Created at": "Creato il",
|
||||
"Created At": "",
|
||||
"Created At": "Creato il",
|
||||
"Current Model": "Modello corrente",
|
||||
"Current Password": "Password corrente",
|
||||
"Custom": "Personalizzato",
|
||||
"Customize Ollama models for a specific purpose": "Personalizza i modelli Ollama per uno scopo specifico",
|
||||
"Dark": "Scuro",
|
||||
"Dashboard": "",
|
||||
"Dashboard": "Pannello di controllo",
|
||||
"Database": "Database",
|
||||
"DD/MM/YYYY HH:mm": "DD/MM/YYYY HH:mm",
|
||||
"December": "",
|
||||
"December": "Dicembre",
|
||||
"Default": "Predefinito",
|
||||
"Default (Automatic1111)": "Predefinito (Automatic1111)",
|
||||
"Default (SentenceTransformers)": "",
|
||||
"Default (SentenceTransformers)": "Predefinito (SentenceTransformers)",
|
||||
"Default (Web API)": "Predefinito (API Web)",
|
||||
"Default model updated": "Modello predefinito aggiornato",
|
||||
"Default Prompt Suggestions": "Suggerimenti prompt predefiniti",
|
||||
"Default User Role": "Ruolo utente predefinito",
|
||||
"delete": "elimina",
|
||||
"Delete": "",
|
||||
"Delete": "Elimina",
|
||||
"Delete a model": "Elimina un modello",
|
||||
"Delete chat": "Elimina chat",
|
||||
"Delete Chat": "",
|
||||
"Delete Chats": "Elimina chat",
|
||||
"delete this link": "",
|
||||
"Delete User": "",
|
||||
"Delete Chat": "Elimina chat",
|
||||
"Delete Chats": "Elimina le chat",
|
||||
"delete this link": "elimina questo link",
|
||||
"Delete User": "Elimina utente",
|
||||
"Deleted {{deleteModelTag}}": "Eliminato {{deleteModelTag}}",
|
||||
"Deleted {{tagName}}": "",
|
||||
"Deleted {{tagName}}": "Eliminato {{tagName}}",
|
||||
"Description": "Descrizione",
|
||||
"Didn't fully follow instructions": "",
|
||||
"Didn't fully follow instructions": "Non ha seguito completamente le istruzioni",
|
||||
"Disabled": "Disabilitato",
|
||||
"Discover a modelfile": "Scopri un file modello",
|
||||
"Discover a prompt": "Scopri un prompt",
|
||||
@ -150,28 +150,28 @@
|
||||
"does not make any external connections, and your data stays securely on your locally hosted server.": "non effettua connessioni esterne e i tuoi dati rimangono al sicuro sul tuo server ospitato localmente.",
|
||||
"Don't Allow": "Non consentire",
|
||||
"Don't have an account?": "Non hai un account?",
|
||||
"Don't like the style": "",
|
||||
"Download": "",
|
||||
"Download canceled": "",
|
||||
"Don't like the style": "Non ti piace lo stile",
|
||||
"Download": "Scarica",
|
||||
"Download canceled": "Scaricamento annullato",
|
||||
"Download Database": "Scarica database",
|
||||
"Drop any files here to add to the conversation": "Trascina qui i file da aggiungere alla conversazione",
|
||||
"e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "ad esempio '30s','10m'. Le unità di tempo valide sono 's', 'm', 'h'.",
|
||||
"Edit": "",
|
||||
"Edit": "Modifica",
|
||||
"Edit Doc": "Modifica documento",
|
||||
"Edit User": "Modifica utente",
|
||||
"Email": "Email",
|
||||
"Embedding Model": "",
|
||||
"Embedding Model Engine": "",
|
||||
"Embedding model set to \"{{embedding_model}}\"": "",
|
||||
"Embedding Model": "Modello di embedding",
|
||||
"Embedding Model Engine": "Motore del modello di embedding",
|
||||
"Embedding model set to \"{{embedding_model}}\"": "Modello di embedding impostato su \"{{embedding_model}}\"",
|
||||
"Enable Chat History": "Abilita cronologia chat",
|
||||
"Enable New Sign Ups": "Abilita nuove iscrizioni",
|
||||
"Enabled": "Abilitato",
|
||||
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "",
|
||||
"Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Assicurati che il tuo file CSV includa 4 colonne in questo ordine: Nome, Email, Password, Ruolo.",
|
||||
"Enter {{role}} message here": "Inserisci il messaggio per {{role}} qui",
|
||||
"Enter Chunk Overlap": "Inserisci la sovrapposizione chunk",
|
||||
"Enter Chunk Size": "Inserisci la dimensione chunk",
|
||||
"Enter Image Size (e.g. 512x512)": "Inserisci la dimensione dell'immagine (ad esempio 512x512)",
|
||||
"Enter language codes": "",
|
||||
"Enter language codes": "Inserisci i codici lingua",
|
||||
"Enter LiteLLM API Base URL (litellm_params.api_base)": "Inserisci l'URL base dell'API LiteLLM (litellm_params.api_base)",
|
||||
"Enter LiteLLM API Key (litellm_params.api_key)": "Inserisci la chiave API LiteLLM (litellm_params.api_key)",
|
||||
"Enter LiteLLM API RPM (litellm_params.rpm)": "Inserisci LiteLLM API RPM (litellm_params.rpm)",
|
||||
@ -179,45 +179,45 @@
|
||||
"Enter Max Tokens (litellm_params.max_tokens)": "Inserisci Max Tokens (litellm_params.max_tokens)",
|
||||
"Enter model tag (e.g. {{modelTag}})": "Inserisci il tag del modello (ad esempio {{modelTag}})",
|
||||
"Enter Number of Steps (e.g. 50)": "Inserisci il numero di passaggi (ad esempio 50)",
|
||||
"Enter Score": "",
|
||||
"Enter Score": "Inserisci il punteggio",
|
||||
"Enter stop sequence": "Inserisci la sequenza di arresto",
|
||||
"Enter Top K": "Inserisci Top K",
|
||||
"Enter URL (e.g. http://127.0.0.1:7860/)": "Inserisci URL (ad esempio http://127.0.0.1:7860/)",
|
||||
"Enter URL (e.g. http://localhost:11434)": "",
|
||||
"Enter URL (e.g. http://localhost:11434)": "Inserisci URL (ad esempio http://localhost:11434)",
|
||||
"Enter Your Email": "Inserisci la tua email",
|
||||
"Enter Your Full Name": "Inserisci il tuo nome completo",
|
||||
"Enter Your Password": "Inserisci la tua password",
|
||||
"Enter Your Role": "",
|
||||
"Enter Your Role": "Inserisci il tuo ruolo",
|
||||
"Experimental": "Sperimentale",
|
||||
"Export All Chats (All Users)": "Esporta tutte le chat (tutti gli utenti)",
|
||||
"Export Chats": "Esporta chat",
|
||||
"Export Documents Mapping": "Esporta mappatura documenti",
|
||||
"Export Modelfiles": "Esporta file modello",
|
||||
"Export Prompts": "Esporta prompt",
|
||||
"Failed to create API Key.": "",
|
||||
"Failed to create API Key.": "Impossibile creare la chiave API.",
|
||||
"Failed to read clipboard contents": "Impossibile leggere il contenuto degli appunti",
|
||||
"February": "",
|
||||
"Feel free to add specific details": "",
|
||||
"February": "Febbraio",
|
||||
"Feel free to add specific details": "Sentiti libero/a di aggiungere dettagli specifici",
|
||||
"File Mode": "Modalità file",
|
||||
"File not found.": "File non trovato.",
|
||||
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "",
|
||||
"Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Rilevato spoofing delle impronte digitali: impossibile utilizzare le iniziali come avatar. Ripristino all'immagine del profilo predefinita.",
|
||||
"Fluidly stream large external response chunks": "Trasmetti in modo fluido blocchi di risposta esterni di grandi dimensioni",
|
||||
"Focus chat input": "Metti a fuoco l'input della chat",
|
||||
"Followed instructions perfectly": "",
|
||||
"Followed instructions perfectly": "Ha seguito le istruzioni alla perfezione",
|
||||
"Format your variables using square brackets like this:": "Formatta le tue variabili usando parentesi quadre come questa:",
|
||||
"From (Base Model)": "Da (modello base)",
|
||||
"Full Screen Mode": "Modalità a schermo intero",
|
||||
"General": "Generale",
|
||||
"General Settings": "Impostazioni generali",
|
||||
"Generation Info": "",
|
||||
"Good Response": "",
|
||||
"has no conversations.": "",
|
||||
"Generation Info": "Informazioni generazione",
|
||||
"Good Response": "Buona risposta",
|
||||
"has no conversations.": "non ha conversazioni.",
|
||||
"Hello, {{name}}": "Ciao, {{name}}",
|
||||
"Help": "",
|
||||
"Help": "Aiuto",
|
||||
"Hide": "Nascondi",
|
||||
"Hide Additional Params": "Nascondi parametri aggiuntivi",
|
||||
"How can I help you today?": "Come posso aiutarti oggi?",
|
||||
"Hybrid Search": "",
|
||||
"Hybrid Search": "Ricerca ibrida",
|
||||
"Image Generation (Experimental)": "Generazione di immagini (sperimentale)",
|
||||
"Image Generation Engine": "Motore di generazione immagini",
|
||||
"Image Settings": "Impostazioni immagine",
|
||||
@ -226,21 +226,21 @@
|
||||
"Import Documents Mapping": "Importa mappatura documenti",
|
||||
"Import Modelfiles": "Importa file modello",
|
||||
"Import Prompts": "Importa prompt",
|
||||
"Include `--api` flag when running stable-diffusion-webui": "",
|
||||
"Input commands": "",
|
||||
"Include `--api` flag when running stable-diffusion-webui": "Includi il flag `--api` quando esegui stable-diffusion-webui",
|
||||
"Input commands": "Comandi di input",
|
||||
"Interface": "Interfaccia",
|
||||
"Invalid Tag": "",
|
||||
"January": "",
|
||||
"Invalid Tag": "Tag non valido",
|
||||
"January": "Gennaio",
|
||||
"join our Discord for help.": "unisciti al nostro Discord per ricevere aiuto.",
|
||||
"JSON": "JSON",
|
||||
"July": "",
|
||||
"June": "",
|
||||
"July": "Luglio",
|
||||
"June": "Giugno",
|
||||
"JWT Expiration": "Scadenza JWT",
|
||||
"JWT Token": "Token JWT",
|
||||
"Keep Alive": "Mantieni attivo",
|
||||
"Keyboard shortcuts": "Scorciatoie da tastiera",
|
||||
"Language": "Lingua",
|
||||
"Last Active": "",
|
||||
"Last Active": "Ultima attività",
|
||||
"Light": "Chiaro",
|
||||
"Listening...": "Ascolto...",
|
||||
"LLMs can make mistakes. Verify important information.": "Gli LLM possono commettere errori. Verifica le informazioni importanti.",
|
||||
@ -249,22 +249,22 @@
|
||||
"Manage LiteLLM Models": "Gestisci modelli LiteLLM",
|
||||
"Manage Models": "Gestisci modelli",
|
||||
"Manage Ollama Models": "Gestisci modelli Ollama",
|
||||
"March": "",
|
||||
"March": "Marzo",
|
||||
"Max Tokens": "Max token",
|
||||
"Maximum of 3 models can be downloaded simultaneously. Please try again later.": "È possibile scaricare un massimo di 3 modelli contemporaneamente. Riprova più tardi.",
|
||||
"May": "",
|
||||
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "",
|
||||
"Minimum Score": "",
|
||||
"May": "Maggio",
|
||||
"Messages you send after creating your link won't be shared. Users with the URL will beable to view the shared chat.": "I messaggi che invii dopo aver creato il tuo link non verranno condivisi. Gli utenti con l'URL potranno visualizzare la chat condivisa.",
|
||||
"Minimum Score": "Punteggio minimo",
|
||||
"Mirostat": "Mirostat",
|
||||
"Mirostat Eta": "Mirostat Eta",
|
||||
"Mirostat Tau": "Mirostat Tau",
|
||||
"MMMM DD, YYYY": "MMMM DD, YYYY",
|
||||
"MMMM DD, YYYY HH:mm": "",
|
||||
"MMMM DD, YYYY HH:mm": "MMMM DD, YYYY HH:mm",
|
||||
"Model '{{modelName}}' has been successfully downloaded.": "Il modello '{{modelName}}' è stato scaricato con successo.",
|
||||
"Model '{{modelTag}}' is already in queue for downloading.": "Il modello '{{modelTag}}' è già in coda per il download.",
|
||||
"Model {{modelId}} not found": "Modello {{modelId}} non trovato",
|
||||
"Model {{modelName}} already exists.": "Il modello {{modelName}} esiste già.",
|
||||
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "",
|
||||
"Model filesystem path detected. Model shortname is required for update, cannot continue.": "Percorso del filesystem del modello rilevato. Il nome breve del modello è richiesto per l'aggiornamento, impossibile continuare.",
|
||||
"Model Name": "Nome modello",
|
||||
"Model not selected": "Modello non selezionato",
|
||||
"Model Tag Name": "Nome tag del modello",
|
||||
@ -275,7 +275,7 @@
|
||||
"Modelfile Content": "Contenuto del file modello",
|
||||
"Modelfiles": "File modello",
|
||||
"Models": "Modelli",
|
||||
"More": "",
|
||||
"More": "Altro",
|
||||
"My Documents": "I miei documenti",
|
||||
"My Modelfiles": "I miei file modello",
|
||||
"My Prompts": "I miei prompt",
|
||||
@ -284,19 +284,19 @@
|
||||
"Name your modelfile": "Assegna un nome al tuo file modello",
|
||||
"New Chat": "Nuova chat",
|
||||
"New Password": "Nuova password",
|
||||
"No results found": "",
|
||||
"No results found": "Nessun risultato trovato",
|
||||
"No source available": "Nessuna fonte disponibile",
|
||||
"Not factually correct": "",
|
||||
"Not factually correct": "Non corretto dal punto di vista fattuale",
|
||||
"Not sure what to add?": "Non sei sicuro di cosa aggiungere?",
|
||||
"Not sure what to write? Switch to": "Non sei sicuro di cosa scrivere? Passa a",
|
||||
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "",
|
||||
"Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Nota: se imposti un punteggio minimo, la ricerca restituirà solo i documenti con un punteggio maggiore o uguale al punteggio minimo.",
|
||||
"Notifications": "Notifiche desktop",
|
||||
"November": "",
|
||||
"October": "",
|
||||
"November": "Novembre",
|
||||
"October": "Ottobre",
|
||||
"Off": "Disattivato",
|
||||
"Okay, Let's Go!": "Ok, andiamo!",
|
||||
"OLED Dark": "",
|
||||
"Ollama": "",
|
||||
"OLED Dark": "OLED scuro",
|
||||
"Ollama": "Ollama",
|
||||
"Ollama Base URL": "URL base Ollama",
|
||||
"Ollama Version": "Versione Ollama",
|
||||
"On": "Attivato",
|
||||
@ -309,52 +309,52 @@
|
||||
"Open AI": "Open AI",
|
||||
"Open AI (Dall-E)": "Open AI (Dall-E)",
|
||||
"Open new chat": "Apri nuova chat",
|
||||
"OpenAI": "",
|
||||
"OpenAI": "OpenAI",
|
||||
"OpenAI API": "API OpenAI",
|
||||
"OpenAI API Config": "",
|
||||
"OpenAI API Config": "Configurazione API OpenAI",
|
||||
"OpenAI API Key is required.": "La chiave API OpenAI è obbligatoria.",
|
||||
"OpenAI URL/Key required.": "",
|
||||
"OpenAI URL/Key required.": "URL/Chiave OpenAI obbligatori.",
|
||||
"or": "o",
|
||||
"Other": "",
|
||||
"Overview": "",
|
||||
"Other": "Altro",
|
||||
"Overview": "Panoramica",
|
||||
"Parameters": "Parametri",
|
||||
"Password": "Password",
|
||||
"PDF document (.pdf)": "",
|
||||
"PDF document (.pdf)": "Documento PDF (.pdf)",
|
||||
"PDF Extract Images (OCR)": "Estrazione immagini PDF (OCR)",
|
||||
"pending": "in sospeso",
|
||||
"Permission denied when accessing microphone: {{error}}": "Autorizzazione negata durante l'accesso al microfono: {{error}}",
|
||||
"Plain text (.txt)": "",
|
||||
"Plain text (.txt)": "Testo normale (.txt)",
|
||||
"Playground": "Terreno di gioco",
|
||||
"Positive attitude": "",
|
||||
"Previous 30 days": "",
|
||||
"Previous 7 days": "",
|
||||
"Profile Image": "",
|
||||
"Prompt": "",
|
||||
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "",
|
||||
"Positive attitude": "Attitudine positiva",
|
||||
"Previous 30 days": "Ultimi 30 giorni",
|
||||
"Previous 7 days": "Ultimi 7 giorni",
|
||||
"Profile Image": "Immagine del profilo",
|
||||
"Prompt": "Prompt",
|
||||
"Prompt (e.g. Tell me a fun fact about the Roman Empire)": "Prompt (ad esempio Dimmi un fatto divertente sull'Impero Romano)",
|
||||
"Prompt Content": "Contenuto del prompt",
|
||||
"Prompt suggestions": "Suggerimenti prompt",
|
||||
"Prompts": "Prompt",
|
||||
"Pull \"{{searchValue}}\" from Ollama.com": "",
|
||||
"Pull \"{{searchValue}}\" from Ollama.com": "Estrai \"{{searchValue}}\" da Ollama.com",
|
||||
"Pull a model from Ollama.com": "Estrai un modello da Ollama.com",
|
||||
"Pull Progress": "Avanzamento estrazione",
|
||||
"Query Params": "Parametri query",
|
||||
"RAG Template": "Modello RAG",
|
||||
"Raw Format": "Formato raw",
|
||||
"Read Aloud": "",
|
||||
"Read Aloud": "Leggi ad alta voce",
|
||||
"Record voice": "Registra voce",
|
||||
"Redirecting you to OpenWebUI Community": "Reindirizzamento alla comunità OpenWebUI",
|
||||
"Refused when it shouldn't have": "",
|
||||
"Regenerate": "",
|
||||
"Refused when it shouldn't have": "Rifiutato quando non avrebbe dovuto",
|
||||
"Regenerate": "Rigenera",
|
||||
"Release Notes": "Note di rilascio",
|
||||
"Remove": "",
|
||||
"Remove Model": "",
|
||||
"Rename": "",
|
||||
"Remove": "Rimuovi",
|
||||
"Remove Model": "Rimuovi modello",
|
||||
"Rename": "Rinomina",
|
||||
"Repeat Last N": "Ripeti ultimi N",
|
||||
"Repeat Penalty": "Penalità di ripetizione",
|
||||
"Request Mode": "Modalità richiesta",
|
||||
"Reranking Model": "",
|
||||
"Reranking model disabled": "",
|
||||
"Reranking model set to \"{{reranking_model}}\"": "",
|
||||
"Reranking Model": "Modello di riclassificazione",
|
||||
"Reranking model disabled": "Modello di riclassificazione disabilitato",
|
||||
"Reranking model set to \"{{reranking_model}}\"": "Modello di riclassificazione impostato su \"{{reranking_model}}\"",
|
||||
"Reset Vector Storage": "Reimposta archivio vettoriale",
|
||||
"Response AutoCopy to Clipboard": "Copia automatica della risposta negli appunti",
|
||||
"Role": "Ruolo",
|
||||
@ -369,7 +369,7 @@
|
||||
"Scan complete!": "Scansione completata!",
|
||||
"Scan for documents from {{path}}": "Cerca documenti da {{path}}",
|
||||
"Search": "Cerca",
|
||||
"Search a model": "",
|
||||
"Search a model": "Cerca un modello",
|
||||
"Search Documents": "Cerca documenti",
|
||||
"Search Prompts": "Cerca prompt",
|
||||
"See readme.md for instructions": "Vedi readme.md per le istruzioni",
|
||||
@ -378,35 +378,35 @@
|
||||
"Select a mode": "Seleziona una modalità",
|
||||
"Select a model": "Seleziona un modello",
|
||||
"Select an Ollama instance": "Seleziona un'istanza Ollama",
|
||||
"Select model": "",
|
||||
"Select model": "Seleziona modello",
|
||||
"Send a Message": "Invia un messaggio",
|
||||
"Send message": "Invia messaggio",
|
||||
"September": "",
|
||||
"September": "Settembre",
|
||||
"Server connection verified": "Connessione al server verificata",
|
||||
"Set as default": "Imposta come predefinito",
|
||||
"Set Default Model": "Imposta modello predefinito",
|
||||
"Set embedding model (e.g. {{model}})": "",
|
||||
"Set embedding model (e.g. {{model}})": "Imposta modello di embedding (ad esempio {{model}})",
|
||||
"Set Image Size": "Imposta dimensione immagine",
|
||||
"Set Model": "Imposta modello",
|
||||
"Set reranking model (e.g. {{model}})": "",
|
||||
"Set reranking model (e.g. {{model}})": "Imposta modello di riclassificazione (ad esempio {{model}})",
|
||||
"Set Steps": "Imposta passaggi",
|
||||
"Set Title Auto-Generation Model": "Imposta modello di generazione automatica del titolo",
|
||||
"Set Voice": "Imposta voce",
|
||||
"Settings": "Impostazioni",
|
||||
"Settings saved successfully!": "Impostazioni salvate con successo!",
|
||||
"Share": "",
|
||||
"Share Chat": "",
|
||||
"Share": "Condividi",
|
||||
"Share Chat": "Condividi chat",
|
||||
"Share to OpenWebUI Community": "Condividi con la comunità OpenWebUI",
|
||||
"short-summary": "riassunto-breve",
|
||||
"Show": "Mostra",
|
||||
"Show Additional Params": "Mostra parametri aggiuntivi",
|
||||
"Show shortcuts": "Mostra",
|
||||
"Showcased creativity": "",
|
||||
"Showcased creativity": "Creatività messa in mostra",
|
||||
"sidebar": "barra laterale",
|
||||
"Sign in": "Accedi",
|
||||
"Sign Out": "Esci",
|
||||
"Sign up": "Registrati",
|
||||
"Signing in": "",
|
||||
"Signing in": "Accesso in corso",
|
||||
"Source": "Fonte",
|
||||
"Speech recognition error: {{error}}": "Errore di riconoscimento vocale: {{error}}",
|
||||
"Speech-to-Text Engine": "Motore da voce a testo",
|
||||
@ -414,37 +414,37 @@
|
||||
"Stop Sequence": "Sequenza di arresto",
|
||||
"STT Settings": "Impostazioni STT",
|
||||
"Submit": "Invia",
|
||||
"Subtitle (e.g. about the Roman Empire)": "",
|
||||
"Subtitle (e.g. about the Roman Empire)": "Sottotitolo (ad esempio sull'Impero Romano)",
|
||||
"Success": "Successo",
|
||||
"Successfully updated.": "Aggiornato con successo.",
|
||||
"Suggested": "",
|
||||
"Suggested": "Suggerito",
|
||||
"Sync All": "Sincronizza tutto",
|
||||
"System": "Sistema",
|
||||
"System Prompt": "Prompt di sistema",
|
||||
"Tags": "Tag",
|
||||
"Tell us more:": "",
|
||||
"Tell us more:": "Raccontaci di più:",
|
||||
"Temperature": "Temperatura",
|
||||
"Template": "Modello",
|
||||
"Text Completion": "Completamento del testo",
|
||||
"Text-to-Speech Engine": "Motore da testo a voce",
|
||||
"Tfs Z": "Tfs Z",
|
||||
"Thanks for your feedback!": "",
|
||||
"The score should be a value between 0.0 (0%) and 1.0 (100%).": "",
|
||||
"Thanks for your feedback!": "Grazie per il tuo feedback!",
|
||||
"The score should be a value between 0.0 (0%) and 1.0 (100%).": "Il punteggio dovrebbe essere un valore compreso tra 0.0 (0%) e 1.0 (100%).",
|
||||
"Theme": "Tema",
|
||||
"This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Ciò garantisce che le tue preziose conversazioni siano salvate in modo sicuro nel tuo database backend. Grazie!",
|
||||
"This setting does not sync across browsers or devices.": "Questa impostazione non si sincronizza tra browser o dispositivi.",
|
||||
"Thorough explanation": "",
|
||||
"Thorough explanation": "Spiegazione dettagliata",
|
||||
"Tip: Update multiple variable slots consecutively by pressing the tab key in the chat input after each replacement.": "Suggerimento: aggiorna più slot di variabili consecutivamente premendo il tasto tab nell'input della chat dopo ogni sostituzione.",
|
||||
"Title": "Titolo",
|
||||
"Title (e.g. Tell me a fun fact)": "",
|
||||
"Title (e.g. Tell me a fun fact)": "Titolo (ad esempio Dimmi un fatto divertente)",
|
||||
"Title Auto-Generation": "Generazione automatica del titolo",
|
||||
"Title cannot be an empty string.": "",
|
||||
"Title cannot be an empty string.": "Il titolo non può essere una stringa vuota.",
|
||||
"Title Generation Prompt": "Prompt di generazione del titolo",
|
||||
"to": "a",
|
||||
"To access the available model names for downloading,": "Per accedere ai nomi dei modelli disponibili per il download,",
|
||||
"To access the GGUF models available for downloading,": "Per accedere ai modelli GGUF disponibili per il download,",
|
||||
"to chat input.": "all'input della chat.",
|
||||
"Today": "",
|
||||
"Today": "Oggi",
|
||||
"Toggle settings": "Attiva/disattiva impostazioni",
|
||||
"Toggle sidebar": "Attiva/disattiva barra laterale",
|
||||
"Top K": "Top K",
|
||||
@ -454,7 +454,7 @@
|
||||
"Type Hugging Face Resolve (Download) URL": "Digita l'URL di Hugging Face Resolve (Download)",
|
||||
"Uh-oh! There was an issue connecting to {{provider}}.": "Uh-oh! Si è verificato un problema durante la connessione a {{provider}}.",
|
||||
"Unknown File Type '{{file_type}}', but accepting and treating as plain text": "Tipo di file sconosciuto '{{file_type}}', ma accettato e trattato come testo normale",
|
||||
"Update and Copy Link": "",
|
||||
"Update and Copy Link": "Aggiorna e copia link",
|
||||
"Update password": "Aggiorna password",
|
||||
"Upload a GGUF model": "Carica un modello GGUF",
|
||||
"Upload files": "Carica file",
|
||||
@ -462,7 +462,7 @@
|
||||
"URL Mode": "Modalità URL",
|
||||
"Use '#' in the prompt input to load and select your documents.": "Usa '#' nell'input del prompt per caricare e selezionare i tuoi documenti.",
|
||||
"Use Gravatar": "Usa Gravatar",
|
||||
"Use Initials": "",
|
||||
"Use Initials": "Usa iniziali",
|
||||
"user": "utente",
|
||||
"User Permissions": "Autorizzazioni utente",
|
||||
"Users": "Utenti",
|
||||
@ -471,11 +471,11 @@
|
||||
"variable": "variabile",
|
||||
"variable to have them replaced with clipboard content.": "variabile per farli sostituire con il contenuto degli appunti.",
|
||||
"Version": "Versione",
|
||||
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "",
|
||||
"Warning: If you update or change your embedding model, you will need to re-import all documents.": "Attenzione: se aggiorni o cambi il tuo modello di embedding, dovrai reimportare tutti i documenti.",
|
||||
"Web": "Web",
|
||||
"Web Loader Settings": "",
|
||||
"Web Params": "",
|
||||
"Webhook URL": "",
|
||||
"Web Loader Settings": "Impostazioni del caricatore Web",
|
||||
"Web Params": "Parametri Web",
|
||||
"Webhook URL": "URL webhook",
|
||||
"WebUI Add-ons": "Componenti aggiuntivi WebUI",
|
||||
"WebUI Settings": "Impostazioni WebUI",
|
||||
"WebUI will make requests to": "WebUI effettuerà richieste a",
|
||||
@ -484,12 +484,12 @@
|
||||
"Whisper (Local)": "Whisper (locale)",
|
||||
"Write a prompt suggestion (e.g. Who are you?)": "Scrivi un suggerimento per il prompt (ad esempio Chi sei?)",
|
||||
"Write a summary in 50 words that summarizes [topic or keyword].": "Scrivi un riassunto in 50 parole che riassume [argomento o parola chiave].",
|
||||
"Yesterday": "",
|
||||
"Yesterday": "Ieri",
|
||||
"You": "Tu",
|
||||
"You have no archived conversations.": "",
|
||||
"You have shared this chat": "",
|
||||
"You have no archived conversations.": "Non hai conversazioni archiviate.",
|
||||
"You have shared this chat": "Hai condiviso questa chat",
|
||||
"You're a helpful assistant.": "Sei un assistente utile.",
|
||||
"You're now logged in.": "Ora hai effettuato l'accesso.",
|
||||
"Youtube": "",
|
||||
"Youtube Loader Settings": ""
|
||||
"Youtube": "Youtube",
|
||||
"Youtube Loader Settings": "Impostazioni del caricatore Youtube"
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ export const user: Writable<SessionUser | undefined> = writable(undefined);
|
||||
// Frontend
|
||||
export const MODEL_DOWNLOAD_POOL = writable({});
|
||||
|
||||
export const mobile = writable(false);
|
||||
|
||||
export const theme = writable('system');
|
||||
export const chatId = writable('');
|
||||
|
||||
|
66
src/lib/utils/index.test.ts
Normal file
66
src/lib/utils/index.test.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { promptTemplate } from '$lib/utils/index';
|
||||
import { expect, test } from 'vitest';
|
||||
|
||||
test('promptTemplate correctly replaces {{prompt}} placeholder', () => {
|
||||
const template = 'Hello {{prompt}}!';
|
||||
const prompt = 'world';
|
||||
const expected = 'Hello world!';
|
||||
const actual = promptTemplate(template, prompt);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
test('promptTemplate correctly replaces {{prompt:start:<length>}} placeholder', () => {
|
||||
const template = 'Hello {{prompt:start:3}}!';
|
||||
const prompt = 'world';
|
||||
const expected = 'Hello wor!';
|
||||
const actual = promptTemplate(template, prompt);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
test('promptTemplate correctly replaces {{prompt:end:<length>}} placeholder', () => {
|
||||
const template = 'Hello {{prompt:end:3}}!';
|
||||
const prompt = 'world';
|
||||
const expected = 'Hello rld!';
|
||||
const actual = promptTemplate(template, prompt);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
test('promptTemplate correctly replaces {{prompt:middletruncate:<length>}} placeholder when prompt length is greater than length', () => {
|
||||
const template = 'Hello {{prompt:middletruncate:4}}!';
|
||||
const prompt = 'world';
|
||||
const expected = 'Hello wo...ld!';
|
||||
const actual = promptTemplate(template, prompt);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
test('promptTemplate correctly replaces {{prompt:middletruncate:<length>}} placeholder when prompt length is less than or equal to length', () => {
|
||||
const template = 'Hello {{prompt:middletruncate:5}}!';
|
||||
const prompt = 'world';
|
||||
const expected = 'Hello world!';
|
||||
const actual = promptTemplate(template, prompt);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
test('promptTemplate returns original template when no placeholders are present', () => {
|
||||
const template = 'Hello world!';
|
||||
const prompt = 'world';
|
||||
const expected = 'Hello world!';
|
||||
const actual = promptTemplate(template, prompt);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
test('promptTemplate does not replace placeholders inside of replaced placeholders', () => {
|
||||
const template = 'Hello {{prompt}}!';
|
||||
const prompt = 'World, {{prompt}} injection';
|
||||
const expected = 'Hello World, {{prompt}} injection!';
|
||||
const actual = promptTemplate(template, prompt);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
test('promptTemplate correctly replaces multiple placeholders', () => {
|
||||
const template = 'Hello {{prompt}}! This is {{prompt:start:3}}!';
|
||||
const prompt = 'world';
|
||||
const expected = 'Hello world! This is wor!';
|
||||
const actual = promptTemplate(template, prompt);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
@ -472,22 +472,39 @@ export const blobToFile = (blob, fileName) => {
|
||||
return file;
|
||||
};
|
||||
|
||||
export const promptTemplate = (template: string, prompt: string) => {
|
||||
prompt = prompt.replace(/{{prompt}}|{{prompt:start:\d+}}|{{prompt:end:\d+}}/g, '');
|
||||
|
||||
template = template.replace(/{{prompt}}/g, prompt);
|
||||
|
||||
// Replace all instances of {{prompt:start:<length>}} with the first <length> characters of the prompt
|
||||
template = template.replace(/{{prompt:start:(\d+)}}/g, (match, length) =>
|
||||
prompt.substring(0, parseInt(length))
|
||||
/**
|
||||
* This function is used to replace placeholders in a template string with the provided prompt.
|
||||
* The placeholders can be in the following formats:
|
||||
* - `{{prompt}}`: This will be replaced with the entire prompt.
|
||||
* - `{{prompt:start:<length>}}`: This will be replaced with the first <length> characters of the prompt.
|
||||
* - `{{prompt:end:<length>}}`: This will be replaced with the last <length> characters of the prompt.
|
||||
* - `{{prompt:middletruncate:<length>}}`: This will be replaced with the prompt truncated to <length> characters, with '...' in the middle.
|
||||
*
|
||||
* @param {string} template - The template string containing placeholders.
|
||||
* @param {string} prompt - The string to replace the placeholders with.
|
||||
* @returns {string} The template string with the placeholders replaced by the prompt.
|
||||
*/
|
||||
export const promptTemplate = (template: string, prompt: string): string => {
|
||||
return template.replace(
|
||||
/{{prompt}}|{{prompt:start:(\d+)}}|{{prompt:end:(\d+)}}|{{prompt:middletruncate:(\d+)}}/g,
|
||||
(match, startLength, endLength, middleLength) => {
|
||||
if (match === '{{prompt}}') {
|
||||
return prompt;
|
||||
} else if (match.startsWith('{{prompt:start:')) {
|
||||
return prompt.substring(0, startLength);
|
||||
} else if (match.startsWith('{{prompt:end:')) {
|
||||
return prompt.slice(-endLength);
|
||||
} else if (match.startsWith('{{prompt:middletruncate:')) {
|
||||
if (prompt.length <= middleLength) {
|
||||
return prompt;
|
||||
}
|
||||
const start = prompt.slice(0, Math.ceil(middleLength / 2));
|
||||
const end = prompt.slice(-Math.floor(middleLength / 2));
|
||||
return `${start}...${end}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
);
|
||||
|
||||
// Replace all instances of {{prompt:end:<length>}} with the last <length> characters of the prompt
|
||||
template = template.replace(/{{prompt:end:(\d+)}}/g, (match, length) =>
|
||||
prompt.slice(-parseInt(length))
|
||||
);
|
||||
|
||||
return template;
|
||||
};
|
||||
|
||||
export const approximateToHumanReadable = (nanoseconds: number) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script>
|
||||
import { onMount, tick, setContext } from 'svelte';
|
||||
import { config, user, theme, WEBUI_NAME } from '$lib/stores';
|
||||
import { config, user, theme, WEBUI_NAME, mobile } from '$lib/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { Toaster, toast } from 'svelte-sonner';
|
||||
|
||||
@ -18,9 +18,22 @@
|
||||
setContext('i18n', i18n);
|
||||
|
||||
let loaded = false;
|
||||
const BREAKPOINT = 1024;
|
||||
|
||||
onMount(async () => {
|
||||
theme.set(localStorage.theme);
|
||||
|
||||
mobile.set(window.innerWidth < BREAKPOINT);
|
||||
const onResize = () => {
|
||||
if (window.innerWidth < BREAKPOINT) {
|
||||
mobile.set(true);
|
||||
} else {
|
||||
mobile.set(false);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('resize', onResize);
|
||||
|
||||
let backendConfig = null;
|
||||
try {
|
||||
backendConfig = await getBackendConfig();
|
||||
@ -67,6 +80,10 @@
|
||||
|
||||
document.getElementById('splash-screen')?.remove();
|
||||
loaded = true;
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('resize', onResize);
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user