mirror of
https://github.com/open-webui/open-webui
synced 2025-02-20 12:00:22 +00:00
refac: settings
This commit is contained in:
parent
bb15eb016e
commit
d90e138773
@ -10,6 +10,9 @@
|
|||||||
import { toast } from 'svelte-sonner';
|
import { toast } from 'svelte-sonner';
|
||||||
import Pipelines from './Settings/Pipelines.svelte';
|
import Pipelines from './Settings/Pipelines.svelte';
|
||||||
import Audio from './Settings/Audio.svelte';
|
import Audio from './Settings/Audio.svelte';
|
||||||
|
import Images from './Settings/Images.svelte';
|
||||||
|
import Interface from './Settings/Interface.svelte';
|
||||||
|
import Models from './Settings/Models.svelte';
|
||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
@ -46,6 +49,32 @@
|
|||||||
<div class=" self-center">{$i18n.t('General')}</div>
|
<div class=" self-center">{$i18n.t('General')}</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||||
|
'models'
|
||||||
|
? 'bg-gray-200 dark:bg-gray-700'
|
||||||
|
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
|
||||||
|
on:click={() => {
|
||||||
|
selectedTab = 'models';
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class=" self-center mr-2">
|
||||||
|
<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="M10 1c3.866 0 7 1.79 7 4s-3.134 4-7 4-7-1.79-7-4 3.134-4 7-4zm5.694 8.13c.464-.264.91-.583 1.306-.952V10c0 2.21-3.134 4-7 4s-7-1.79-7-4V8.178c.396.37.842.688 1.306.953C5.838 10.006 7.854 10.5 10 10.5s4.162-.494 5.694-1.37zM3 13.179V15c0 2.21 3.134 4 7 4s7-1.79 7-4v-1.822c-.396.37-.842.688-1.306.953-1.532.875-3.548 1.369-5.694 1.369s-4.162-.494-5.694-1.37A7.009 7.009 0 013 13.179z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class=" self-center">{$i18n.t('Models')}</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||||
'users'
|
'users'
|
||||||
@ -70,6 +99,32 @@
|
|||||||
<div class=" self-center">{$i18n.t('Users')}</div>
|
<div class=" self-center">{$i18n.t('Users')}</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||||
|
'interface'
|
||||||
|
? 'bg-gray-200 dark:bg-gray-700'
|
||||||
|
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
|
||||||
|
on:click={() => {
|
||||||
|
selectedTab = 'interface';
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class=" self-center mr-2">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M2 4.25A2.25 2.25 0 0 1 4.25 2h7.5A2.25 2.25 0 0 1 14 4.25v5.5A2.25 2.25 0 0 1 11.75 12h-1.312c.1.128.21.248.328.36a.75.75 0 0 1 .234.545v.345a.75.75 0 0 1-.75.75h-4.5a.75.75 0 0 1-.75-.75v-.345a.75.75 0 0 1 .234-.545c.118-.111.228-.232.328-.36H4.25A2.25 2.25 0 0 1 2 9.75v-5.5Zm2.25-.75a.75.75 0 0 0-.75.75v4.5c0 .414.336.75.75.75h7.5a.75.75 0 0 0 .75-.75v-4.5a.75.75 0 0 0-.75-.75h-7.5Z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class=" self-center">{$i18n.t('Interface')}</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||||
'audio'
|
'audio'
|
||||||
@ -97,6 +152,32 @@
|
|||||||
<div class=" self-center">{$i18n.t('Audio')}</div>
|
<div class=" self-center">{$i18n.t('Audio')}</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||||
|
'images'
|
||||||
|
? 'bg-gray-200 dark:bg-gray-700'
|
||||||
|
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
|
||||||
|
on:click={() => {
|
||||||
|
selectedTab = 'images';
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class=" self-center mr-2">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M2 4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4Zm10.5 5.707a.5.5 0 0 0-.146-.353l-1-1a.5.5 0 0 0-.708 0L9.354 9.646a.5.5 0 0 1-.708 0L6.354 7.354a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0-.146.353V12a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V9.707ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div class=" self-center">{$i18n.t('Images')}</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||||
'banners'
|
'banners'
|
||||||
@ -192,18 +273,32 @@
|
|||||||
toast.success($i18n.t('Settings saved successfully!'));
|
toast.success($i18n.t('Settings saved successfully!'));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{:else if selectedTab === 'models'}
|
||||||
|
<Models />
|
||||||
{:else if selectedTab === 'users'}
|
{:else if selectedTab === 'users'}
|
||||||
<Users
|
<Users
|
||||||
saveHandler={() => {
|
saveHandler={() => {
|
||||||
toast.success($i18n.t('Settings saved successfully!'));
|
toast.success($i18n.t('Settings saved successfully!'));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{:else if selectedTab === 'interface'}
|
||||||
|
<Interface
|
||||||
|
on:save={() => {
|
||||||
|
toast.success($i18n.t('Settings saved successfully!'));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{:else if selectedTab === 'audio'}
|
{:else if selectedTab === 'audio'}
|
||||||
<Audio
|
<Audio
|
||||||
saveHandler={() => {
|
saveHandler={() => {
|
||||||
toast.success($i18n.t('Settings saved successfully!'));
|
toast.success($i18n.t('Settings saved successfully!'));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
{:else if selectedTab === 'images'}
|
||||||
|
<Images
|
||||||
|
on:save={() => {
|
||||||
|
toast.success($i18n.t('Settings saved successfully!'));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
{:else if selectedTab === 'db'}
|
{:else if selectedTab === 'db'}
|
||||||
<Database
|
<Database
|
||||||
saveHandler={() => {
|
saveHandler={() => {
|
||||||
|
@ -23,8 +23,6 @@
|
|||||||
|
|
||||||
const i18n = getContext('i18n');
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
export let saveSettings: Function;
|
|
||||||
|
|
||||||
let loading = false;
|
let loading = false;
|
||||||
|
|
||||||
let imageGenerationEngine = '';
|
let imageGenerationEngine = '';
|
205
src/lib/components/admin/Settings/Interface.svelte
Normal file
205
src/lib/components/admin/Settings/Interface.svelte
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { getBackendConfig } from '$lib/apis';
|
||||||
|
import { setDefaultPromptSuggestions } from '$lib/apis/configs';
|
||||||
|
import { config, models, settings, user } from '$lib/stores';
|
||||||
|
import { createEventDispatcher, onMount, getContext } from 'svelte';
|
||||||
|
import { toast } from 'svelte-sonner';
|
||||||
|
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
const i18n = getContext('i18n');
|
||||||
|
|
||||||
|
let taskModel = '';
|
||||||
|
let taskModelExternal = '';
|
||||||
|
|
||||||
|
let titleGenerationPrompt = '';
|
||||||
|
let promptSuggestions = [];
|
||||||
|
|
||||||
|
const updateInterfaceHandler = async () => {
|
||||||
|
promptSuggestions = await setDefaultPromptSuggestions(localStorage.token, promptSuggestions);
|
||||||
|
await config.set(await getBackendConfig());
|
||||||
|
};
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
taskModel = $settings?.title?.model ?? '';
|
||||||
|
taskModelExternal = $settings?.title?.modelExternal ?? '';
|
||||||
|
titleGenerationPrompt =
|
||||||
|
$settings?.title?.prompt ??
|
||||||
|
`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': {{prompt}}`;
|
||||||
|
|
||||||
|
promptSuggestions = $config?.default_prompt_suggestions;
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<form
|
||||||
|
class="flex flex-col h-full justify-between space-y-3 text-sm"
|
||||||
|
on:submit|preventDefault={() => {
|
||||||
|
updateInterfaceHandler();
|
||||||
|
dispatch('save');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class=" space-y-3 pr-1.5 overflow-y-scroll">
|
||||||
|
<div>
|
||||||
|
<div class=" mb-2.5 text-sm font-medium flex">
|
||||||
|
<div class=" mr-1">{$i18n.t('Set Task Model')}</div>
|
||||||
|
<Tooltip
|
||||||
|
content={$i18n.t(
|
||||||
|
'A task model is used when performing tasks such as generating titles for chats and web search queries'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<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="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="flex w-full gap-2 pr-2">
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class=" text-xs mb-1">{$i18n.t('Local Models')}</div>
|
||||||
|
<select
|
||||||
|
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||||
|
bind:value={taskModel}
|
||||||
|
placeholder={$i18n.t('Select a model')}
|
||||||
|
>
|
||||||
|
<option value="" selected>{$i18n.t('Current Model')}</option>
|
||||||
|
{#each $models.filter((m) => m.owned_by === 'ollama') as model}
|
||||||
|
<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
|
||||||
|
{model.name}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-1">
|
||||||
|
<div class=" text-xs mb-1">{$i18n.t('External Models')}</div>
|
||||||
|
<select
|
||||||
|
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||||
|
bind:value={taskModelExternal}
|
||||||
|
placeholder={$i18n.t('Select a model')}
|
||||||
|
>
|
||||||
|
<option value="" selected>{$i18n.t('Current Model')}</option>
|
||||||
|
{#each $models as model}
|
||||||
|
<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
|
||||||
|
{model.name}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3 mr-2">
|
||||||
|
<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Title Generation Prompt')}</div>
|
||||||
|
<textarea
|
||||||
|
bind:value={titleGenerationPrompt}
|
||||||
|
class="w-full rounded-lg p-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none resize-none"
|
||||||
|
rows="3"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if $user.role === 'admin'}
|
||||||
|
<hr class=" dark:border-gray-700" />
|
||||||
|
|
||||||
|
<div class=" space-y-3 pr-1.5">
|
||||||
|
<div class="flex w-full justify-between mb-2">
|
||||||
|
<div class=" self-center text-sm font-semibold">
|
||||||
|
{$i18n.t('Default Prompt Suggestions')}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="p-1 px-3 text-xs flex rounded transition"
|
||||||
|
type="button"
|
||||||
|
on:click={() => {
|
||||||
|
if (promptSuggestions.length === 0 || promptSuggestions.at(-1).content !== '') {
|
||||||
|
promptSuggestions = [...promptSuggestions, { content: '', title: ['', ''] }];
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col space-y-1">
|
||||||
|
{#each promptSuggestions as prompt, promptIdx}
|
||||||
|
<div class=" flex border dark:border-gray-600 rounded-lg">
|
||||||
|
<div class="flex flex-col flex-1">
|
||||||
|
<div class="flex border-b dark:border-gray-600 w-full">
|
||||||
|
<input
|
||||||
|
class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
||||||
|
placeholder={$i18n.t('Title (e.g. Tell me a fun fact)')}
|
||||||
|
bind:value={prompt.title[0]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
||||||
|
placeholder={$i18n.t('Subtitle (e.g. about the Roman Empire)')}
|
||||||
|
bind:value={prompt.title[1]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input
|
||||||
|
class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
||||||
|
placeholder={$i18n.t('Prompt (e.g. Tell me a fun fact about the Roman Empire)')}
|
||||||
|
bind:value={prompt.content}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="px-2"
|
||||||
|
type="button"
|
||||||
|
on:click={() => {
|
||||||
|
promptSuggestions.splice(promptIdx, 1);
|
||||||
|
promptSuggestions = promptSuggestions;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 20 20"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if promptSuggestions.length > 0}
|
||||||
|
<div class="text-xs text-left w-full mt-2">
|
||||||
|
{$i18n.t('Adjusting these settings will apply changes universally to all users.')}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex justify-end text-sm font-medium">
|
||||||
|
<button
|
||||||
|
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{$i18n.t('Save')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
1078
src/lib/components/admin/Settings/Models.svelte
Normal file
1078
src/lib/components/admin/Settings/Models.svelte
Normal file
File diff suppressed because it is too large
Load Diff
@ -14,15 +14,11 @@
|
|||||||
// Addons
|
// Addons
|
||||||
let titleAutoGenerate = true;
|
let titleAutoGenerate = true;
|
||||||
let responseAutoCopy = false;
|
let responseAutoCopy = false;
|
||||||
let titleAutoGenerateModel = '';
|
|
||||||
let titleAutoGenerateModelExternal = '';
|
|
||||||
let widescreenMode = false;
|
let widescreenMode = false;
|
||||||
let titleGenerationPrompt = '';
|
|
||||||
let splitLargeChunks = false;
|
let splitLargeChunks = false;
|
||||||
|
|
||||||
// Interface
|
// Interface
|
||||||
let defaultModelId = '';
|
let defaultModelId = '';
|
||||||
let promptSuggestions = [];
|
|
||||||
let showUsername = false;
|
let showUsername = false;
|
||||||
let chatBubble = true;
|
let chatBubble = true;
|
||||||
let chatDirection: 'LTR' | 'RTL' = 'LTR';
|
let chatDirection: 'LTR' | 'RTL' = 'LTR';
|
||||||
@ -85,34 +81,13 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateInterfaceHandler = async () => {
|
const updateInterfaceHandler = async () => {
|
||||||
if ($user.role === 'admin') {
|
|
||||||
promptSuggestions = await setDefaultPromptSuggestions(localStorage.token, promptSuggestions);
|
|
||||||
await config.set(await getBackendConfig());
|
|
||||||
}
|
|
||||||
|
|
||||||
saveSettings({
|
saveSettings({
|
||||||
title: {
|
|
||||||
...$settings.title,
|
|
||||||
model: titleAutoGenerateModel !== '' ? titleAutoGenerateModel : undefined,
|
|
||||||
modelExternal:
|
|
||||||
titleAutoGenerateModelExternal !== '' ? titleAutoGenerateModelExternal : undefined,
|
|
||||||
prompt: titleGenerationPrompt ? titleGenerationPrompt : undefined
|
|
||||||
},
|
|
||||||
models: [defaultModelId]
|
models: [defaultModelId]
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if ($user.role === 'admin') {
|
|
||||||
promptSuggestions = $config?.default_prompt_suggestions;
|
|
||||||
}
|
|
||||||
|
|
||||||
titleAutoGenerate = $settings?.title?.auto ?? true;
|
titleAutoGenerate = $settings?.title?.auto ?? true;
|
||||||
titleAutoGenerateModel = $settings?.title?.model ?? '';
|
|
||||||
titleAutoGenerateModelExternal = $settings?.title?.modelExternal ?? '';
|
|
||||||
titleGenerationPrompt =
|
|
||||||
$settings?.title?.prompt ??
|
|
||||||
`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': {{prompt}}`;
|
|
||||||
responseAutoCopy = $settings.responseAutoCopy ?? false;
|
responseAutoCopy = $settings.responseAutoCopy ?? false;
|
||||||
showUsername = $settings.showUsername ?? false;
|
showUsername = $settings.showUsername ?? false;
|
||||||
chatBubble = $settings.chatBubble ?? true;
|
chatBubble = $settings.chatBubble ?? true;
|
||||||
@ -304,162 +279,6 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr class=" dark:border-gray-850" />
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div class=" mb-2.5 text-sm font-medium flex">
|
|
||||||
<div class=" mr-1">{$i18n.t('Set Task Model')}</div>
|
|
||||||
<Tooltip
|
|
||||||
content={$i18n.t(
|
|
||||||
'A task model is used when performing tasks such as generating titles for chats and web search queries'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<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="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<div class="flex w-full gap-2 pr-2">
|
|
||||||
<div class="flex-1">
|
|
||||||
<div class=" text-xs mb-1">{$i18n.t('Local Models')}</div>
|
|
||||||
<select
|
|
||||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
|
||||||
bind:value={titleAutoGenerateModel}
|
|
||||||
placeholder={$i18n.t('Select a model')}
|
|
||||||
>
|
|
||||||
<option value="" selected>{$i18n.t('Current Model')}</option>
|
|
||||||
{#each $models.filter((m) => m.owned_by === 'ollama') as model}
|
|
||||||
<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
|
|
||||||
{model.name}
|
|
||||||
</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex-1">
|
|
||||||
<div class=" text-xs mb-1">{$i18n.t('External Models')}</div>
|
|
||||||
<select
|
|
||||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
|
||||||
bind:value={titleAutoGenerateModelExternal}
|
|
||||||
placeholder={$i18n.t('Select a model')}
|
|
||||||
>
|
|
||||||
<option value="" selected>{$i18n.t('Current Model')}</option>
|
|
||||||
{#each $models as model}
|
|
||||||
<option value={model.id} class="bg-gray-100 dark:bg-gray-700">
|
|
||||||
{model.name}
|
|
||||||
</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-3 mr-2">
|
|
||||||
<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Title Generation Prompt')}</div>
|
|
||||||
<textarea
|
|
||||||
bind:value={titleGenerationPrompt}
|
|
||||||
class="w-full rounded-lg p-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none resize-none"
|
|
||||||
rows="3"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if $user.role === 'admin'}
|
|
||||||
<hr class=" dark:border-gray-700" />
|
|
||||||
|
|
||||||
<div class=" space-y-3 pr-1.5">
|
|
||||||
<div class="flex w-full justify-between mb-2">
|
|
||||||
<div class=" self-center text-sm font-semibold">
|
|
||||||
{$i18n.t('Default Prompt Suggestions')}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="p-1 px-3 text-xs flex rounded transition"
|
|
||||||
type="button"
|
|
||||||
on:click={() => {
|
|
||||||
if (promptSuggestions.length === 0 || promptSuggestions.at(-1).content !== '') {
|
|
||||||
promptSuggestions = [...promptSuggestions, { content: '', title: ['', ''] }];
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M10.75 4.75a.75.75 0 00-1.5 0v4.5h-4.5a.75.75 0 000 1.5h4.5v4.5a.75.75 0 001.5 0v-4.5h4.5a.75.75 0 000-1.5h-4.5v-4.5z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col space-y-1">
|
|
||||||
{#each promptSuggestions as prompt, promptIdx}
|
|
||||||
<div class=" flex border dark:border-gray-600 rounded-lg">
|
|
||||||
<div class="flex flex-col flex-1">
|
|
||||||
<div class="flex border-b dark:border-gray-600 w-full">
|
|
||||||
<input
|
|
||||||
class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
|
||||||
placeholder={$i18n.t('Title (e.g. Tell me a fun fact)')}
|
|
||||||
bind:value={prompt.title[0]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<input
|
|
||||||
class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
|
||||||
placeholder={$i18n.t('Subtitle (e.g. about the Roman Empire)')}
|
|
||||||
bind:value={prompt.title[1]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input
|
|
||||||
class="px-3 py-1.5 text-xs w-full bg-transparent outline-none border-r dark:border-gray-600"
|
|
||||||
placeholder={$i18n.t('Prompt (e.g. Tell me a fun fact about the Roman Empire)')}
|
|
||||||
bind:value={prompt.content}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button
|
|
||||||
class="px-2"
|
|
||||||
type="button"
|
|
||||||
on:click={() => {
|
|
||||||
promptSuggestions.splice(promptIdx, 1);
|
|
||||||
promptSuggestions = promptSuggestions;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#if promptSuggestions.length > 0}
|
|
||||||
<div class="text-xs text-left w-full mt-2">
|
|
||||||
{$i18n.t('Adjusting these settings will apply changes universally to all users.')}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end text-sm font-medium">
|
<div class="flex justify-end text-sm font-medium">
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
import Audio from './Settings/Audio.svelte';
|
import Audio from './Settings/Audio.svelte';
|
||||||
import Chats from './Settings/Chats.svelte';
|
import Chats from './Settings/Chats.svelte';
|
||||||
import Connections from './Settings/Connections.svelte';
|
import Connections from './Settings/Connections.svelte';
|
||||||
import Images from './Settings/Images.svelte';
|
|
||||||
import User from '../icons/User.svelte';
|
import User from '../icons/User.svelte';
|
||||||
import Personalization from './Settings/Personalization.svelte';
|
import Personalization from './Settings/Personalization.svelte';
|
||||||
import { updateUserSettings } from '$lib/apis/users';
|
import { updateUserSettings } from '$lib/apis/users';
|
||||||
@ -114,32 +113,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class=" self-center">{$i18n.t('Connections')}</div>
|
<div class=" self-center">{$i18n.t('Connections')}</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
|
||||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
|
||||||
'models'
|
|
||||||
? 'bg-gray-200 dark:bg-gray-700'
|
|
||||||
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
|
|
||||||
on:click={() => {
|
|
||||||
selectedTab = 'models';
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class=" self-center mr-2">
|
|
||||||
<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="M10 1c3.866 0 7 1.79 7 4s-3.134 4-7 4-7-1.79-7-4 3.134-4 7-4zm5.694 8.13c.464-.264.91-.583 1.306-.952V10c0 2.21-3.134 4-7 4s-7-1.79-7-4V8.178c.396.37.842.688 1.306.953C5.838 10.006 7.854 10.5 10 10.5s4.162-.494 5.694-1.37zM3 13.179V15c0 2.21 3.134 4 7 4s7-1.79 7-4v-1.822c-.396.37-.842.688-1.306.953-1.532.875-3.548 1.369-5.694 1.369s-4.162-.494-5.694-1.37A7.009 7.009 0 013 13.179z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div class=" self-center">{$i18n.t('Models')}</div>
|
|
||||||
</button>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@ -210,34 +183,6 @@
|
|||||||
<div class=" self-center">{$i18n.t('Audio')}</div>
|
<div class=" self-center">{$i18n.t('Audio')}</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{#if $user.role === 'admin'}
|
|
||||||
<button
|
|
||||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
|
||||||
'images'
|
|
||||||
? 'bg-gray-200 dark:bg-gray-700'
|
|
||||||
: ' hover:bg-gray-300 dark:hover:bg-gray-800'}"
|
|
||||||
on:click={() => {
|
|
||||||
selectedTab = 'images';
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class=" self-center mr-2">
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M2 4a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V4Zm10.5 5.707a.5.5 0 0 0-.146-.353l-1-1a.5.5 0 0 0-.708 0L9.354 9.646a.5.5 0 0 1-.708 0L6.354 7.354a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0-.146.353V12a.5.5 0 0 0 .5.5h8a.5.5 0 0 0 .5-.5V9.707ZM12 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div class=" self-center">{$i18n.t('Images')}</div>
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<button
|
<button
|
||||||
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
class="px-2.5 py-2.5 min-w-fit rounded-lg flex-1 md:flex-none flex text-right transition {selectedTab ===
|
||||||
'chats'
|
'chats'
|
||||||
@ -325,8 +270,6 @@
|
|||||||
toast.success($i18n.t('Settings saved successfully!'));
|
toast.success($i18n.t('Settings saved successfully!'));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{:else if selectedTab === 'models'}
|
|
||||||
<Models {getModels} />
|
|
||||||
{:else if selectedTab === 'connections'}
|
{:else if selectedTab === 'connections'}
|
||||||
<Connections
|
<Connections
|
||||||
{getModels}
|
{getModels}
|
||||||
@ -355,13 +298,6 @@
|
|||||||
toast.success($i18n.t('Settings saved successfully!'));
|
toast.success($i18n.t('Settings saved successfully!'));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{:else if selectedTab === 'images'}
|
|
||||||
<Images
|
|
||||||
{saveSettings}
|
|
||||||
on:save={() => {
|
|
||||||
toast.success($i18n.t('Settings saved successfully!'));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{:else if selectedTab === 'chats'}
|
{:else if selectedTab === 'chats'}
|
||||||
<Chats {saveSettings} />
|
<Chats {saveSettings} />
|
||||||
{:else if selectedTab === 'account'}
|
{:else if selectedTab === 'account'}
|
||||||
|
Loading…
Reference in New Issue
Block a user