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

Merge remote-tracking branch 'upstream/dev' into feat/include-git-hash-everywhere

parents 4fdb26fd 7b81271b
......@@ -13,8 +13,6 @@
export let parentMessage;
export let selectedModelfiles;
export let updateChatMessages: Function;
export let confirmEditResponseMessage: Function;
export let rateMessage: Function;
......@@ -130,7 +128,6 @@
>
<ResponseMessage
message={groupedMessages[model].messages[groupedMessagesIdx[model]]}
modelfiles={selectedModelfiles}
siblings={groupedMessages[model].messages.map((m) => m.id)}
isLastMessage={true}
{updateChatMessages}
......
<script lang="ts">
import { WEBUI_BASE_URL } from '$lib/constants';
import { user } from '$lib/stores';
import { config, user, models as _models } from '$lib/stores';
import { onMount, getContext } from 'svelte';
import { blur, fade } from 'svelte/transition';
......@@ -9,23 +9,20 @@
const i18n = getContext('i18n');
export let modelIds = [];
export let models = [];
export let modelfiles = [];
export let submitPrompt;
export let suggestionPrompts;
let mounted = false;
let modelfile = null;
let selectedModelIdx = 0;
$: modelfile =
models[selectedModelIdx] in modelfiles ? modelfiles[models[selectedModelIdx]] : null;
$: if (models.length > 0) {
$: if (modelIds.length > 0) {
selectedModelIdx = models.length - 1;
}
$: models = modelIds.map((id) => $_models.find((m) => m.id === id));
onMount(() => {
mounted = true;
});
......@@ -41,25 +38,14 @@
selectedModelIdx = modelIdx;
}}
>
{#if model in modelfiles}
<img
crossorigin="anonymous"
src={modelfiles[model]?.imageUrl ?? `${WEBUI_BASE_URL}/static/favicon.png`}
alt="modelfile"
class=" size-[2.7rem] rounded-full border-[1px] border-gray-200 dark:border-none"
draggable="false"
/>
{:else}
<img
crossorigin="anonymous"
src={$i18n.language === 'dg-DG'
? `/doge.png`
: `${WEBUI_BASE_URL}/static/favicon.png`}
class=" size-[2.7rem] rounded-full border-[1px] border-gray-200 dark:border-none"
alt="logo"
draggable="false"
/>
{/if}
<img
crossorigin="anonymous"
src={model?.info?.meta?.profile_image_url ??
($i18n.language === 'dg-DG' ? `/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)}
class=" size-[2.7rem] rounded-full border-[1px] border-gray-200 dark:border-none"
alt="logo"
draggable="false"
/>
</button>
{/each}
</div>
......@@ -70,23 +56,32 @@
>
<div>
<div class=" capitalize line-clamp-1" in:fade={{ duration: 200 }}>
{#if modelfile}
{modelfile.title}
{#if models[selectedModelIdx]?.info}
{models[selectedModelIdx]?.info?.name}
{:else}
{$i18n.t('Hello, {{name}}', { name: $user.name })}
{/if}
</div>
<div in:fade={{ duration: 200, delay: 200 }}>
{#if modelfile}
<div class="mt-0.5 text-base font-normal text-gray-500 dark:text-gray-400">
{modelfile.desc}
{#if models[selectedModelIdx]?.info}
<div class="mt-0.5 text-base font-normal text-gray-500 dark:text-gray-400 line-clamp-3">
{models[selectedModelIdx]?.info?.meta?.description}
</div>
{#if modelfile.user}
{#if models[selectedModelIdx]?.info?.meta?.user}
<div class="mt-0.5 text-sm font-normal text-gray-400 dark:text-gray-500">
By <a href="https://openwebui.com/m/{modelfile.user.username}"
>{modelfile.user.name ? modelfile.user.name : `@${modelfile.user.username}`}</a
>
By
{#if models[selectedModelIdx]?.info?.meta?.user.community}
<a
href="https://openwebui.com/m/{models[selectedModelIdx]?.info?.meta?.user
.username}"
>{models[selectedModelIdx]?.info?.meta?.user.name
? models[selectedModelIdx]?.info?.meta?.user.name
: `@${models[selectedModelIdx]?.info?.meta?.user.username}`}</a
>
{:else}
{models[selectedModelIdx]?.info?.meta?.user.name}
{/if}
</div>
{/if}
{:else}
......@@ -99,7 +94,11 @@
</div>
<div class=" w-full" in:fade={{ duration: 200, delay: 300 }}>
<Suggestions {suggestionPrompts} {submitPrompt} />
<Suggestions
suggestionPrompts={models[selectedModelIdx]?.info?.meta?.suggestion_prompts ??
$config.default_prompt_suggestions}
{submitPrompt}
/>
</div>
</div>
{/key}
......@@ -14,7 +14,7 @@
const dispatch = createEventDispatcher();
import { config, settings } from '$lib/stores';
import { config, models, settings } from '$lib/stores';
import { synthesizeOpenAISpeech } from '$lib/apis/audio';
import { imageGenerations } from '$lib/apis/images';
import {
......@@ -34,7 +34,6 @@
import RateComment from './RateComment.svelte';
import CitationsModal from '$lib/components/chat/Messages/CitationsModal.svelte';
export let modelfiles = [];
export let message;
export let siblings;
......@@ -52,6 +51,9 @@
export let continueGeneration: Function;
export let regenerateResponse: Function;
let model = null;
$: model = $models.find((m) => m.id === message.model);
let edit = false;
let editedContent = '';
let editTextAreaElement: HTMLTextAreaElement;
......@@ -78,6 +80,13 @@
return `<code>${code.replaceAll('&amp;', '&')}</code>`;
};
// Open all links in a new tab/window (from https://github.com/markedjs/marked/issues/655#issuecomment-383226346)
const origLinkRenderer = renderer.link;
renderer.link = (href, title, text) => {
const html = origLinkRenderer.call(renderer, href, title, text);
return html.replace(/^<a /, '<a target="_blank" rel="nofollow" ');
};
const { extensions, ...defaults } = marked.getDefaults() as marked.MarkedOptions & {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
extensions: any;
......@@ -338,17 +347,13 @@
dir={$settings.chatDirection}
>
<ProfileImage
src={modelfiles[message.model]?.imageUrl ??
src={model?.info?.meta?.profile_image_url ??
($i18n.language === 'dg-DG' ? `/doge.png` : `${WEBUI_BASE_URL}/static/favicon.png`)}
/>
<div class="w-full overflow-hidden pl-1">
<Name>
{#if message.model in modelfiles}
{modelfiles[message.model]?.title}
{:else}
{message.model ? ` ${message.model}` : ''}
{/if}
{model?.name ?? message.model}
{#if message.timestamp}
<span
......@@ -442,8 +447,8 @@
{#if token.type === 'code'}
<CodeBlock
id={`${message.id}-${tokenIdx}`}
lang={token.lang}
code={revertSanitizedResponseContent(token.text)}
lang={token?.lang ?? ''}
code={revertSanitizedResponseContent(token?.text ?? '')}
/>
{:else}
{@html marked.parse(token.raw, {
......@@ -688,7 +693,7 @@
</button>
</Tooltip>
{#if $config.images && !readOnly}
{#if $config.enable_image_generation && !readOnly}
<Tooltip content="Generate Image" placement="bottom">
<button
class="{isLastMessage
......
......@@ -4,7 +4,7 @@
import { tick, createEventDispatcher, getContext } from 'svelte';
import Name from './Name.svelte';
import ProfileImage from './ProfileImage.svelte';
import { modelfiles, settings } from '$lib/stores';
import { models, settings } from '$lib/stores';
import Tooltip from '$lib/components/common/Tooltip.svelte';
import { user as _user } from '$lib/stores';
......@@ -60,8 +60,7 @@
{#if !($settings?.chatBubble ?? true)}
<ProfileImage
src={message.user
? $modelfiles.find((modelfile) => modelfile.tagName === message.user)?.imageUrl ??
'/user.png'
? $models.find((m) => m.id === message.user)?.info?.meta?.profile_image_url ?? '/user.png'
: user?.profile_image_url ?? '/user.png'}
/>
{/if}
......@@ -70,12 +69,8 @@
<div>
<Name>
{#if message.user}
{#if $modelfiles.map((modelfile) => modelfile.tagName).includes(message.user)}
{$modelfiles.find((modelfile) => modelfile.tagName === message.user)?.title}
{:else}
{$i18n.t('You')}
<span class=" text-gray-500 text-sm font-medium">{message?.user ?? ''}</span>
{/if}
{$i18n.t('You')}
<span class=" text-gray-500 text-sm font-medium">{message?.user ?? ''}</span>
{:else if $settings.showUsername || $_user.name !== user.name}
{user.name}
{:else}
......
......@@ -45,13 +45,11 @@
<div class="mr-1 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
}))}
items={$models.map((model) => ({
value: model.id,
label: model.name,
model: model
}))}
bind:value={selectedModel}
/>
</div>
......
......@@ -12,7 +12,9 @@
import { user, MODEL_DOWNLOAD_POOL, models, mobile } from '$lib/stores';
import { toast } from 'svelte-sonner';
import { capitalizeFirstLetter, getModels, splitStream } from '$lib/utils';
import { capitalizeFirstLetter, sanitizeResponseContent, splitStream } from '$lib/utils';
import { getModels } from '$lib/apis';
import Tooltip from '$lib/components/common/Tooltip.svelte';
const i18n = getContext('i18n');
......@@ -23,7 +25,12 @@
export let searchEnabled = true;
export let searchPlaceholder = $i18n.t('Search a model');
export let items = [{ value: 'mango', label: 'Mango' }];
export let items: {
label: string;
value: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
} = [];
export let className = 'w-[30rem]';
......@@ -239,19 +246,37 @@
}}
>
<div class="flex items-center gap-2">
<div class="line-clamp-1">
{item.label}
<span class=" text-xs font-medium text-gray-600 dark:text-gray-400"
>{item.info?.details?.parameter_size ?? ''}</span
>
<div class="flex items-center">
<div class="line-clamp-1">
{item.label}
</div>
{#if item.model.owned_by === 'ollama' && (item.model.ollama?.details?.parameter_size ?? '') !== ''}
<div class="flex ml-1 items-center">
<Tooltip
content={`${
item.model.ollama?.details?.quantization_level
? item.model.ollama?.details?.quantization_level + ' '
: ''
}${
item.model.ollama?.size
? `(${(item.model.ollama?.size / 1024 ** 3).toFixed(1)}GB)`
: ''
}`}
className="self-end"
>
<span class=" text-xs font-medium text-gray-600 dark:text-gray-400"
>{item.model.ollama?.details?.parameter_size ?? ''}</span
>
</Tooltip>
</div>
{/if}
</div>
<!-- {JSON.stringify(item.info)} -->
{#if item.info.external}
<Tooltip content={item.info?.source ?? 'External'}>
<div class=" mr-2">
{#if item.model.owned_by === 'openai'}
<Tooltip content={`${'External'}`}>
<div class="">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
......@@ -271,15 +296,15 @@
</svg>
</div>
</Tooltip>
{:else}
{/if}
{#if item.model?.info?.meta?.description}
<Tooltip
content={`${
item.info?.details?.quantization_level
? item.info?.details?.quantization_level + ' '
: ''
}${item.info.size ? `(${(item.info.size / 1024 ** 3).toFixed(1)}GB)` : ''}`}
content={`${sanitizeResponseContent(
item.model?.info?.meta?.description
).replaceAll('\n', '<br>')}`}
>
<div class=" mr-2">
<div class="">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
......
<script lang="ts">
import { createEventDispatcher, onMount, getContext } from 'svelte';
import AdvancedParams from './Advanced/AdvancedParams.svelte';
const i18n = getContext('i18n');
const dispatch = createEventDispatcher();
export let saveSettings: Function;
// Advanced
let requestFormat = '';
let keepAlive = null;
let options = {
// Advanced
seed: 0,
temperature: '',
repeat_penalty: '',
repeat_last_n: '',
mirostat: '',
mirostat_eta: '',
mirostat_tau: '',
top_k: '',
top_p: '',
stop: '',
tfs_z: '',
num_ctx: '',
num_predict: ''
};
const toggleRequestFormat = async () => {
if (requestFormat === '') {
requestFormat = 'json';
} else {
requestFormat = '';
}
saveSettings({ requestFormat: requestFormat !== '' ? requestFormat : undefined });
};
onMount(() => {
let settings = JSON.parse(localStorage.getItem('settings') ?? '{}');
requestFormat = settings.requestFormat ?? '';
keepAlive = settings.keepAlive ?? null;
options.seed = settings.seed ?? 0;
options.temperature = settings.temperature ?? '';
options.repeat_penalty = settings.repeat_penalty ?? '';
options.top_k = settings.top_k ?? '';
options.top_p = settings.top_p ?? '';
options.num_ctx = settings.num_ctx ?? '';
options = { ...options, ...settings.options };
options.stop = (settings?.options?.stop ?? []).join(',');
});
</script>
<div class="flex flex-col h-full justify-between text-sm">
<div class=" space-y-3 pr-1.5 overflow-y-scroll max-h-80">
<div class=" text-sm font-medium">{$i18n.t('Parameters')}</div>
<AdvancedParams bind:options />
<hr class=" dark:border-gray-700" />
<div class=" py-1 w-full justify-between">
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Keep Alive')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
keepAlive = keepAlive === null ? '5m' : null;
}}
>
{#if keepAlive === null}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if keepAlive !== null}
<div class="flex mt-1 space-x-2">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
bind:value={keepAlive}
/>
</div>
{/if}
</div>
<div>
<div class=" py-1 flex w-full justify-between">
<div class=" self-center text-sm font-medium">{$i18n.t('Request Mode')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
on:click={() => {
toggleRequestFormat();
}}
>
{#if requestFormat === ''}
<span class="ml-2 self-center"> {$i18n.t('Default')} </span>
{:else if requestFormat === 'json'}
<!-- <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-4 h-4 self-center"
>
<path
d="M10 2a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 2zM10 15a.75.75 0 01.75.75v1.5a.75.75 0 01-1.5 0v-1.5A.75.75 0 0110 15zM10 7a3 3 0 100 6 3 3 0 000-6zM15.657 5.404a.75.75 0 10-1.06-1.06l-1.061 1.06a.75.75 0 001.06 1.06l1.06-1.06zM6.464 14.596a.75.75 0 10-1.06-1.06l-1.06 1.06a.75.75 0 001.06 1.06l1.06-1.06zM18 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 0118 10zM5 10a.75.75 0 01-.75.75h-1.5a.75.75 0 010-1.5h1.5A.75.75 0 015 10zM14.596 15.657a.75.75 0 001.06-1.06l-1.06-1.061a.75.75 0 10-1.06 1.06l1.06 1.06zM5.404 6.464a.75.75 0 001.06-1.06l-1.06-1.06a.75.75 0 10-1.061 1.06l1.06 1.06z"
/>
</svg> -->
<span class="ml-2 self-center">{$i18n.t('JSON')}</span>
{/if}
</button>
</div>
</div>
</div>
<div class="flex justify-end pt-3 text-sm font-medium">
<button
class=" px-4 py-2 bg-emerald-700 hover:bg-emerald-800 text-gray-100 transition rounded-lg"
on:click={() => {
saveSettings({
options: {
seed: (options.seed !== 0 ? options.seed : undefined) ?? undefined,
stop: options.stop !== '' ? options.stop.split(',').filter((e) => e) : undefined,
temperature: options.temperature !== '' ? options.temperature : undefined,
repeat_penalty: options.repeat_penalty !== '' ? options.repeat_penalty : undefined,
repeat_last_n: options.repeat_last_n !== '' ? options.repeat_last_n : undefined,
mirostat: options.mirostat !== '' ? options.mirostat : undefined,
mirostat_eta: options.mirostat_eta !== '' ? options.mirostat_eta : undefined,
mirostat_tau: options.mirostat_tau !== '' ? options.mirostat_tau : undefined,
top_k: options.top_k !== '' ? options.top_k : undefined,
top_p: options.top_p !== '' ? options.top_p : undefined,
tfs_z: options.tfs_z !== '' ? options.tfs_z : undefined,
num_ctx: options.num_ctx !== '' ? options.num_ctx : undefined,
num_predict: options.num_predict !== '' ? options.num_predict : undefined
},
keepAlive: keepAlive ? (isNaN(keepAlive) ? keepAlive : parseInt(keepAlive)) : undefined
});
dispatch('save');
}}
>
{$i18n.t('Save')}
</button>
</div>
</div>
<script lang="ts">
import { getContext } from 'svelte';
import { getContext, createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
const i18n = getContext('i18n');
export let options = {
export let params = {
// Advanced
seed: 0,
stop: '',
stop: null,
temperature: '',
repeat_penalty: '',
frequency_penalty: '',
repeat_last_n: '',
mirostat: '',
mirostat_eta: '',
......@@ -17,40 +19,86 @@
top_p: '',
tfs_z: '',
num_ctx: '',
num_predict: ''
max_tokens: '',
template: null
};
let customFieldName = '';
let customFieldValue = '';
$: if (params) {
dispatch('change', params);
}
</script>
<div class=" space-y-3 text-xs">
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Seed')}</div>
<div class=" flex-1 self-center">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="number"
placeholder="Enter Seed"
bind:value={options.seed}
autocomplete="off"
min="0"
/>
</div>
<div class=" space-y-1 text-xs">
<div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Seed')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
params.seed = (params?.seed ?? null) === null ? 0 : null;
}}
>
{#if (params?.seed ?? null) === null}
<span class="ml-2 self-center"> {$i18n.t('Default')} </span>
{:else}
<span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
{/if}
</button>
</div>
</div>
<div>
<div class=" py-0.5 flex w-full justify-between">
<div class=" w-20 text-xs font-medium self-center">{$i18n.t('Stop Sequence')}</div>
<div class=" flex-1 self-center">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={$i18n.t('Enter stop sequence')}
bind:value={options.stop}
autocomplete="off"
/>
{#if (params?.seed ?? null) !== null}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="number"
placeholder="Enter Seed"
bind:value={params.seed}
autocomplete="off"
min="0"
/>
</div>
</div>
{/if}
</div>
<div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Stop Sequence')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
params.stop = (params?.stop ?? null) === null ? '' : null;
}}
>
{#if (params?.stop ?? null) === null}
<span class="ml-2 self-center"> {$i18n.t('Default')} </span>
{:else}
<span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
{/if}
</button>
</div>
{#if (params?.stop ?? null) !== null}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
type="text"
placeholder={$i18n.t('Enter stop sequence')}
bind:value={params.stop}
autocomplete="off"
/>
</div>
</div>
{/if}
</div>
<div class=" py-0.5 w-full justify-between">
......@@ -61,10 +109,10 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.temperature = options.temperature === '' ? 0.8 : '';
params.temperature = (params?.temperature ?? '') === '' ? 0.8 : '';
}}
>
{#if options.temperature === ''}
{#if (params?.temperature ?? '') === ''}
<span class="ml-2 self-center"> {$i18n.t('Default')} </span>
{:else}
<span class="ml-2 self-center"> {$i18n.t('Custom')} </span>
......@@ -72,7 +120,7 @@
</button>
</div>
{#if options.temperature !== ''}
{#if (params?.temperature ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -81,13 +129,13 @@
min="0"
max="1"
step="0.05"
bind:value={options.temperature}
bind:value={params.temperature}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.temperature}
bind:value={params.temperature}
type="number"
class=" bg-transparent text-center w-14"
min="0"
......@@ -107,18 +155,18 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.mirostat = options.mirostat === '' ? 0 : '';
params.mirostat = (params?.mirostat ?? '') === '' ? 0 : '';
}}
>
{#if options.mirostat === ''}
{#if (params?.mirostat ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.mirostat !== ''}
{#if (params?.mirostat ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -127,13 +175,13 @@
min="0"
max="2"
step="1"
bind:value={options.mirostat}
bind:value={params.mirostat}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.mirostat}
bind:value={params.mirostat}
type="number"
class=" bg-transparent text-center w-14"
min="0"
......@@ -153,18 +201,18 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.mirostat_eta = options.mirostat_eta === '' ? 0.1 : '';
params.mirostat_eta = (params?.mirostat_eta ?? '') === '' ? 0.1 : '';
}}
>
{#if options.mirostat_eta === ''}
{#if (params?.mirostat_eta ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.mirostat_eta !== ''}
{#if (params?.mirostat_eta ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -173,13 +221,13 @@
min="0"
max="1"
step="0.05"
bind:value={options.mirostat_eta}
bind:value={params.mirostat_eta}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.mirostat_eta}
bind:value={params.mirostat_eta}
type="number"
class=" bg-transparent text-center w-14"
min="0"
......@@ -199,10 +247,10 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.mirostat_tau = options.mirostat_tau === '' ? 5.0 : '';
params.mirostat_tau = (params?.mirostat_tau ?? '') === '' ? 5.0 : '';
}}
>
{#if options.mirostat_tau === ''}
{#if (params?.mirostat_tau ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
......@@ -210,7 +258,7 @@
</button>
</div>
{#if options.mirostat_tau !== ''}
{#if (params?.mirostat_tau ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -219,13 +267,13 @@
min="0"
max="10"
step="0.5"
bind:value={options.mirostat_tau}
bind:value={params.mirostat_tau}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.mirostat_tau}
bind:value={params.mirostat_tau}
type="number"
class=" bg-transparent text-center w-14"
min="0"
......@@ -245,18 +293,18 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.top_k = options.top_k === '' ? 40 : '';
params.top_k = (params?.top_k ?? '') === '' ? 40 : '';
}}
>
{#if options.top_k === ''}
{#if (params?.top_k ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.top_k !== ''}
{#if (params?.top_k ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -265,13 +313,13 @@
min="0"
max="100"
step="0.5"
bind:value={options.top_k}
bind:value={params.top_k}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.top_k}
bind:value={params.top_k}
type="number"
class=" bg-transparent text-center w-14"
min="0"
......@@ -291,18 +339,18 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.top_p = options.top_p === '' ? 0.9 : '';
params.top_p = (params?.top_p ?? '') === '' ? 0.9 : '';
}}
>
{#if options.top_p === ''}
{#if (params?.top_p ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.top_p !== ''}
{#if (params?.top_p ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -311,13 +359,13 @@
min="0"
max="1"
step="0.05"
bind:value={options.top_p}
bind:value={params.top_p}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.top_p}
bind:value={params.top_p}
type="number"
class=" bg-transparent text-center w-14"
min="0"
......@@ -331,24 +379,24 @@
<div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Repeat Penalty')}</div>
<div class=" self-center text-xs font-medium">{$i18n.t('Frequencey Penalty')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.repeat_penalty = options.repeat_penalty === '' ? 1.1 : '';
params.frequency_penalty = (params?.frequency_penalty ?? '') === '' ? 1.1 : '';
}}
>
{#if options.repeat_penalty === ''}
{#if (params?.frequency_penalty ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.repeat_penalty !== ''}
{#if (params?.frequency_penalty ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -357,13 +405,13 @@
min="0"
max="2"
step="0.05"
bind:value={options.repeat_penalty}
bind:value={params.frequency_penalty}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.repeat_penalty}
bind:value={params.frequency_penalty}
type="number"
class=" bg-transparent text-center w-14"
min="0"
......@@ -383,18 +431,18 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.repeat_last_n = options.repeat_last_n === '' ? 64 : '';
params.repeat_last_n = (params?.repeat_last_n ?? '') === '' ? 64 : '';
}}
>
{#if options.repeat_last_n === ''}
{#if (params?.repeat_last_n ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.repeat_last_n !== ''}
{#if (params?.repeat_last_n ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -403,13 +451,13 @@
min="-1"
max="128"
step="1"
bind:value={options.repeat_last_n}
bind:value={params.repeat_last_n}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.repeat_last_n}
bind:value={params.repeat_last_n}
type="number"
class=" bg-transparent text-center w-14"
min="-1"
......@@ -429,18 +477,18 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.tfs_z = options.tfs_z === '' ? 1 : '';
params.tfs_z = (params?.tfs_z ?? '') === '' ? 1 : '';
}}
>
{#if options.tfs_z === ''}
{#if (params?.tfs_z ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.tfs_z !== ''}
{#if (params?.tfs_z ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -449,13 +497,13 @@
min="0"
max="2"
step="0.05"
bind:value={options.tfs_z}
bind:value={params.tfs_z}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div>
<input
bind:value={options.tfs_z}
bind:value={params.tfs_z}
type="number"
class=" bg-transparent text-center w-14"
min="0"
......@@ -475,18 +523,18 @@
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.num_ctx = options.num_ctx === '' ? 2048 : '';
params.num_ctx = (params?.num_ctx ?? '') === '' ? 2048 : '';
}}
>
{#if options.num_ctx === ''}
{#if (params?.num_ctx ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.num_ctx !== ''}
{#if (params?.num_ctx ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -495,13 +543,13 @@
min="-1"
max="10240000"
step="1"
bind:value={options.num_ctx}
bind:value={params.num_ctx}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div class="">
<input
bind:value={options.num_ctx}
bind:value={params.num_ctx}
type="number"
class=" bg-transparent text-center w-14"
min="-1"
......@@ -513,24 +561,24 @@
</div>
<div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Max Tokens')}</div>
<div class=" self-center text-xs font-medium">{$i18n.t('Max Tokens (num_predict)')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
options.num_predict = options.num_predict === '' ? 128 : '';
params.max_tokens = (params?.max_tokens ?? '') === '' ? 128 : '';
}}
>
{#if options.num_predict === ''}
{#if (params?.max_tokens ?? '') === ''}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if options.num_predict !== ''}
{#if (params?.max_tokens ?? '') !== ''}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<input
......@@ -539,13 +587,13 @@
min="-2"
max="16000"
step="1"
bind:value={options.num_predict}
bind:value={params.max_tokens}
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>
</div>
<div class="">
<input
bind:value={options.num_predict}
bind:value={params.max_tokens}
type="number"
class=" bg-transparent text-center w-14"
min="-2"
......@@ -556,4 +604,36 @@
</div>
{/if}
</div>
<div class=" py-0.5 w-full justify-between">
<div class="flex w-full justify-between">
<div class=" self-center text-xs font-medium">{$i18n.t('Template')}</div>
<button
class="p-1 px-3 text-xs flex rounded transition"
type="button"
on:click={() => {
params.template = (params?.template ?? null) === null ? '' : null;
}}
>
{#if (params?.template ?? null) === null}
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
{:else}
<span class="ml-2 self-center">{$i18n.t('Custom')}</span>
{/if}
</button>
</div>
{#if (params?.template ?? null) !== null}
<div class="flex mt-0.5 space-x-2">
<div class=" flex-1">
<textarea
class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg -mb-1"
placeholder="Write your model template content here"
rows="4"
bind:value={params.template}
/>
</div>
</div>
{/if}
</div>
</div>
......@@ -41,21 +41,21 @@
let requestFormat = '';
let keepAlive = null;
let options = {
let params = {
// Advanced
seed: 0,
temperature: '',
repeat_penalty: '',
frequency_penalty: '',
repeat_last_n: '',
mirostat: '',
mirostat_eta: '',
mirostat_tau: '',
top_k: '',
top_p: '',
stop: '',
stop: null,
tfs_z: '',
num_ctx: '',
num_predict: ''
max_tokens: ''
};
const toggleRequestFormat = async () => {
......@@ -80,14 +80,14 @@
requestFormat = settings.requestFormat ?? '';
keepAlive = settings.keepAlive ?? null;
options.seed = settings.seed ?? 0;
options.temperature = settings.temperature ?? '';
options.repeat_penalty = settings.repeat_penalty ?? '';
options.top_k = settings.top_k ?? '';
options.top_p = settings.top_p ?? '';
options.num_ctx = settings.num_ctx ?? '';
options = { ...options, ...settings.options };
options.stop = (settings?.options?.stop ?? []).join(',');
params.seed = settings.seed ?? 0;
params.temperature = settings.temperature ?? '';
params.frequency_penalty = settings.frequency_penalty ?? '';
params.top_k = settings.top_k ?? '';
params.top_p = settings.top_p ?? '';
params.num_ctx = settings.num_ctx ?? '';
params = { ...params, ...settings.params };
params.stop = settings?.params?.stop ? (settings?.params?.stop ?? []).join(',') : null;
});
const applyTheme = (_theme: string) => {
......@@ -228,7 +228,7 @@
</div>
{#if showAdvanced}
<AdvancedParams bind:options />
<AdvancedParams bind:params />
<hr class=" dark:border-gray-700" />
<div class=" py-1 w-full justify-between">
......@@ -300,20 +300,21 @@
on:click={() => {
saveSettings({
system: system !== '' ? system : undefined,
options: {
seed: (options.seed !== 0 ? options.seed : undefined) ?? undefined,
stop: options.stop !== '' ? options.stop.split(',').filter((e) => e) : undefined,
temperature: options.temperature !== '' ? options.temperature : undefined,
repeat_penalty: options.repeat_penalty !== '' ? options.repeat_penalty : undefined,
repeat_last_n: options.repeat_last_n !== '' ? options.repeat_last_n : undefined,
mirostat: options.mirostat !== '' ? options.mirostat : undefined,
mirostat_eta: options.mirostat_eta !== '' ? options.mirostat_eta : undefined,
mirostat_tau: options.mirostat_tau !== '' ? options.mirostat_tau : undefined,
top_k: options.top_k !== '' ? options.top_k : undefined,
top_p: options.top_p !== '' ? options.top_p : undefined,
tfs_z: options.tfs_z !== '' ? options.tfs_z : undefined,
num_ctx: options.num_ctx !== '' ? options.num_ctx : undefined,
num_predict: options.num_predict !== '' ? options.num_predict : undefined
params: {
seed: (params.seed !== 0 ? params.seed : undefined) ?? undefined,
stop: params.stop ? params.stop.split(',').filter((e) => e) : undefined,
temperature: params.temperature !== '' ? params.temperature : undefined,
frequency_penalty:
params.frequency_penalty !== '' ? params.frequency_penalty : undefined,
repeat_last_n: params.repeat_last_n !== '' ? params.repeat_last_n : undefined,
mirostat: params.mirostat !== '' ? params.mirostat : undefined,
mirostat_eta: params.mirostat_eta !== '' ? params.mirostat_eta : undefined,
mirostat_tau: params.mirostat_tau !== '' ? params.mirostat_tau : undefined,
top_k: params.top_k !== '' ? params.top_k : undefined,
top_p: params.top_p !== '' ? params.top_p : undefined,
tfs_z: params.tfs_z !== '' ? params.tfs_z : undefined,
num_ctx: params.num_ctx !== '' ? params.num_ctx : undefined,
max_tokens: params.max_tokens !== '' ? params.max_tokens : undefined
},
keepAlive: keepAlive ? (isNaN(keepAlive) ? keepAlive : parseInt(keepAlive)) : undefined
});
......
......@@ -3,7 +3,7 @@
import { toast } from 'svelte-sonner';
import { models, settings, user } from '$lib/stores';
import { getModels as _getModels } from '$lib/utils';
import { getModels as _getModels } from '$lib/apis';
import Modal from '../common/Modal.svelte';
import Account from './Settings/Account.svelte';
......
<script lang="ts">
import { getContext, onMount } from 'svelte';
import { models } from '$lib/stores';
import { toast } from 'svelte-sonner';
import { deleteSharedChatById, getChatById, shareChatById } from '$lib/apis/chats';
import { modelfiles } from '$lib/stores';
import { copyToClipboard } from '$lib/utils';
import Modal from '../common/Modal.svelte';
......@@ -43,9 +43,7 @@
tab.postMessage(
JSON.stringify({
chat: _chat,
modelfiles: $modelfiles.filter((modelfile) =>
_chat.models.includes(modelfile.tagName)
)
models: $models.filter((m) => _chat.models.includes(m.id))
}),
'*'
);
......
......@@ -29,6 +29,7 @@
dispatch('change', _state);
}
}}
type="button"
>
<div class="top-0 left-0 absolute w-full flex justify-center">
{#if _state === 'checked'}
......
<script lang="ts">
export let className: string = '';
export let className: string = 'size-5';
</script>
<div class="flex justify-center text-center {className}">
<svg class="size-5" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"
<div class="flex justify-center text-center">
<svg class={className} viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"
><style>
.spinner_ajPY {
transform-origin: center;
......
......@@ -5,6 +5,7 @@
export let placement = 'top';
export let content = `I'm a tooltip!`;
export let touch = true;
export let className = 'flex';
let tooltipElement;
let tooltipInstance;
......@@ -29,6 +30,6 @@
});
</script>
<div bind:this={tooltipElement} aria-label={content} class="flex">
<div bind:this={tooltipElement} aria-label={content} class={className}>
<slot />
</div>
......@@ -6,7 +6,6 @@
WEBUI_NAME,
chatId,
mobile,
modelfiles,
settings,
showArchivedChats,
showSettings,
......
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