mirror of
https://github.com/open-webui/open-webui.git
synced 2026-10-29 06:32:52 +00:00
refac
This commit is contained in:
parent
1184d36c13
commit
b4a58be193
9 changed files with 189 additions and 30 deletions
|
|
@ -852,6 +852,18 @@ class ChatTable:
|
|||
except Exception:
|
||||
return
|
||||
|
||||
async def update_chat_params_by_id(self, id: str, params: dict) -> ChatModel | None:
|
||||
async with self._chat_transaction(id) as (_, chat):
|
||||
if chat is None:
|
||||
return None
|
||||
|
||||
stored = chat.chat or {}
|
||||
chat.chat = {
|
||||
**stored,
|
||||
'params': self._clean_null_bytes({**(stored.get('params') or {}), **params}),
|
||||
}
|
||||
return ChatModel.model_validate(chat)
|
||||
|
||||
async def update_chat_variables_by_id(
|
||||
self,
|
||||
id: str,
|
||||
|
|
|
|||
|
|
@ -1482,6 +1482,39 @@ async def update_chat_by_id(
|
|||
)
|
||||
|
||||
|
||||
############################
|
||||
# UpdateChatParams
|
||||
############################
|
||||
|
||||
|
||||
@router.patch('/{id}/params', response_model=dict)
|
||||
async def update_chat_params(
|
||||
request: Request,
|
||||
id: str,
|
||||
form_data: dict,
|
||||
user=Depends(get_verified_user),
|
||||
db: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
if not await Chats.get_chat_by_id_and_user_id(id, user.id, db=db):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
|
||||
)
|
||||
|
||||
chat = await Chats.update_chat_params_by_id(id, form_data)
|
||||
if chat is None:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND)
|
||||
|
||||
await publish_event(
|
||||
request,
|
||||
EVENTS.CHAT_UPDATED,
|
||||
actor=user,
|
||||
subject_id=id,
|
||||
data={'title': chat.title},
|
||||
)
|
||||
return chat.chat['params']
|
||||
|
||||
|
||||
############################
|
||||
# UpdateChatMessageById
|
||||
############################
|
||||
|
|
|
|||
|
|
@ -1315,6 +1315,23 @@ export const updateChatById = async (
|
|||
return res;
|
||||
};
|
||||
|
||||
export const updateChatParams = async (
|
||||
token: string,
|
||||
id: string,
|
||||
params: Record<string, unknown>
|
||||
) => {
|
||||
const res = await fetch(`${WEBUI_API_BASE_URL}/chats/${id}/params`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...(token && { authorization: `Bearer ${token}` })
|
||||
},
|
||||
body: JSON.stringify(params)
|
||||
});
|
||||
if (!res.ok) throw getErrorDetail(await res.json());
|
||||
return res.json();
|
||||
};
|
||||
|
||||
export const compactChatById = async (token: string, id: string, model?: string | null) => {
|
||||
let error = null;
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@
|
|||
importChats,
|
||||
resolveChatMessageToolCall,
|
||||
updateChatById,
|
||||
updateChatParams,
|
||||
updateChatFolderIdById
|
||||
} from '$lib/apis/chats';
|
||||
import type { FilesystemFile } from '$lib/apis/terminal';
|
||||
|
|
@ -518,20 +519,13 @@
|
|||
tool_approval_mode
|
||||
}
|
||||
});
|
||||
await saveParam('tool_approval_mode', tool_approval_mode);
|
||||
await updateUserSettings(localStorage.token, { ui: { params: $settings.params } }).catch(
|
||||
(err) => {
|
||||
console.error('[tool permissions settings]', err);
|
||||
}
|
||||
);
|
||||
|
||||
if (!isShared && $chatId && !$temporaryChatEnabled && !isTemporaryChatId($chatId)) {
|
||||
const res = await updateChatById(localStorage.token, $chatId, { params }).catch((err) => {
|
||||
console.error('[tool permissions chat]', err);
|
||||
return null;
|
||||
});
|
||||
if (res) chat = res;
|
||||
}
|
||||
|
||||
if (tool_approval_mode === 'full') {
|
||||
if (isTemporaryChatId($chatId)) {
|
||||
if (browserApprovalMode !== 'full') return;
|
||||
|
|
@ -882,7 +876,7 @@
|
|||
}
|
||||
|
||||
let saveControlsTimer;
|
||||
$: if (!loading && !$temporaryChatEnabled && $chatId && params && chatFiles) {
|
||||
$: if (!loading && !$temporaryChatEnabled && $chatId && chatFiles) {
|
||||
clearTimeout(saveControlsTimer);
|
||||
saveControlsTimer = setTimeout(saveControls, 400);
|
||||
}
|
||||
|
|
@ -3216,6 +3210,29 @@
|
|||
|
||||
const chatActionHandler = async (_chatId, actionId, modelId, responseMessageId, event = null) => {
|
||||
const messages = createMessagesList(history, responseMessageId);
|
||||
let changed = false;
|
||||
const actionSocket = $socket;
|
||||
const onEvent = (event) => {
|
||||
if (event.chat_id !== _chatId || event.message_id !== responseMessageId) return;
|
||||
const { type, data } = event.data ?? {};
|
||||
// These events are UI-only or already persisted by get_event_emitter.
|
||||
if (
|
||||
[
|
||||
'notification',
|
||||
'confirmation',
|
||||
'input',
|
||||
'status',
|
||||
'message',
|
||||
'replace',
|
||||
'files',
|
||||
'embeds'
|
||||
].includes(type) ||
|
||||
(['source', 'citation'].includes(type) && data?.type == null)
|
||||
)
|
||||
return;
|
||||
changed = true;
|
||||
};
|
||||
actionSocket?.on('events', onEvent);
|
||||
|
||||
const res = await chatAction(localStorage.token, actionId, {
|
||||
model: modelId,
|
||||
|
|
@ -3232,16 +3249,23 @@
|
|||
chat_id: _chatId,
|
||||
session_id: $socket?.id,
|
||||
id: responseMessageId
|
||||
}).catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
messages.at(-1).error = { content: error };
|
||||
return null;
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
if ($chatId === _chatId && history.messages[responseMessageId]) {
|
||||
history.messages[responseMessageId].error = { content: error };
|
||||
changed = true;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
.finally(() => actionSocket?.off('events', onEvent));
|
||||
|
||||
if (res !== null && res.messages) {
|
||||
if ($chatId !== _chatId) return;
|
||||
|
||||
if (res?.messages) {
|
||||
// Update chat history with the new messages
|
||||
for (const message of res.messages) {
|
||||
history.messages[message.id] = {
|
||||
const updated = {
|
||||
...history.messages[message.id],
|
||||
...(history.messages[message.id].content !== message.content
|
||||
? { originalContent: history.messages[message.id].content }
|
||||
|
|
@ -3251,16 +3275,19 @@
|
|||
: {}),
|
||||
...message
|
||||
};
|
||||
if (!equal(history.messages[message.id], updated)) {
|
||||
history.messages[message.id] = updated;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($chatId == _chatId) {
|
||||
if (changed) {
|
||||
if (!$temporaryChatEnabled) {
|
||||
chat = await updateChatById(localStorage.token, _chatId, {
|
||||
models: selectedModels,
|
||||
messages: messages,
|
||||
messages: createMessagesList(history, responseMessageId),
|
||||
history: history,
|
||||
params: params,
|
||||
files: chatFiles
|
||||
});
|
||||
|
||||
|
|
@ -4465,9 +4492,7 @@
|
|||
// chat completion request. Files are now persisted
|
||||
// by the backend at chat creation time.
|
||||
if (Object.keys(params).length > 0) {
|
||||
await updateChatById(localStorage.token, res.chat_id, {
|
||||
params: params
|
||||
});
|
||||
await updateChatParams(localStorage.token, res.chat_id, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4751,21 +4776,26 @@
|
|||
models: selectedModels,
|
||||
history: history,
|
||||
messages: createMessagesList(history, history.currentId),
|
||||
params: params,
|
||||
files: chatFiles
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const saveParam = async (key: string, value: unknown) => {
|
||||
if (isShared || !$chatId || $temporaryChatEnabled || isTemporaryChatId($chatId)) return;
|
||||
await updateChatParams(localStorage.token, $chatId, { [key]: value }).catch((error) => {
|
||||
toast.error(`${error}`);
|
||||
});
|
||||
};
|
||||
|
||||
const saveControls = async () => {
|
||||
if (isShared) return;
|
||||
if (!$chatId || $temporaryChatEnabled) return;
|
||||
const loaded = chat?.chat ?? {};
|
||||
if (equal(params, loaded.params ?? {}) && equal(chatFiles, loaded.files ?? [])) return;
|
||||
if (equal(chatFiles, loaded.files ?? [])) return;
|
||||
|
||||
const res = await updateChatById(localStorage.token, $chatId, {
|
||||
params,
|
||||
files: chatFiles
|
||||
}).catch((err) => {
|
||||
console.error('[controls autosave]', err);
|
||||
|
|
@ -5490,6 +5520,7 @@
|
|||
bind:history
|
||||
bind:chatFiles
|
||||
bind:params
|
||||
onParamChange={saveParam}
|
||||
bind:files
|
||||
chatId={$chatId}
|
||||
chatUser={chatOwner}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
export let chatFiles = [];
|
||||
export let params = {};
|
||||
export let onParamChange: (key: string, value: unknown) => void = () => {};
|
||||
|
||||
export let bridge: import('$lib/utils/realtime').RealtimeCall;
|
||||
export let callMode = 'current';
|
||||
|
|
@ -307,7 +308,7 @@
|
|||
{:else if activeTab === 'files' && codeInterpreterEnabled}
|
||||
<PyodideFileNav />
|
||||
{:else}
|
||||
<Controls embed={true} {models} bind:chatFiles bind:params />
|
||||
<Controls embed={true} {models} bind:chatFiles bind:params {onParamChange} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -437,7 +438,7 @@
|
|||
{:else if activeTab === 'files' && codeInterpreterEnabled}
|
||||
<PyodideFileNav overlay={dragged} />
|
||||
{:else}
|
||||
<Controls embed={true} {models} bind:chatFiles bind:params />
|
||||
<Controls embed={true} {models} bind:chatFiles bind:params {onParamChange} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
import { user, settings } from '$lib/stores';
|
||||
export let models = [];
|
||||
export let chatFiles = [];
|
||||
export let params = {};
|
||||
export let params: Record<string, any> = {};
|
||||
export let onParamChange: (key: string, value: unknown) => void = () => {};
|
||||
export let embed = false;
|
||||
|
||||
// Persist collapsible section open/close state
|
||||
|
|
@ -118,6 +119,7 @@
|
|||
<div class="pt-1 pb-1" slot="content">
|
||||
<textarea
|
||||
bind:value={params.system}
|
||||
on:change={() => onParamChange('system', params.system)}
|
||||
class={($settings?.highContrastMode ?? false)
|
||||
? systemPromptTextareaClass
|
||||
: compactSystemPromptTextareaClass}
|
||||
|
|
@ -139,7 +141,12 @@
|
|||
>
|
||||
<div class="pt-1 pb-1 text-xs" slot="content">
|
||||
<div>
|
||||
<AdvancedParams admin={$user?.role === 'admin'} custom={true} bind:params />
|
||||
<AdvancedParams
|
||||
admin={$user?.role === 'admin'}
|
||||
custom={true}
|
||||
bind:params
|
||||
{onParamChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Collapsible>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
const i18n = getContext<Writable<i18nType>>('i18n');
|
||||
|
||||
export let onChange: (params: any) => void = () => {};
|
||||
export let onParamChange: (key: string, value: unknown) => void = () => {};
|
||||
|
||||
export let admin = false;
|
||||
export let custom = false;
|
||||
|
|
@ -89,12 +90,14 @@
|
|||
{max}
|
||||
step={rangeStep}
|
||||
bind:value={params[key]}
|
||||
on:change={() => onParamChange(key, params[key] ?? null)}
|
||||
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<input
|
||||
bind:value={params[key]}
|
||||
on:change={() => onParamChange(key, params[key] ?? null)}
|
||||
type="number"
|
||||
aria-label={label}
|
||||
class=" bg-transparent text-center w-14"
|
||||
|
|
@ -132,6 +135,7 @@
|
|||
: params.stream_response
|
||||
? false
|
||||
: null;
|
||||
onParamChange('stream_response', params.stream_response);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
|
|
@ -166,6 +170,7 @@
|
|||
on:click={() => {
|
||||
params.stream_delta_chunk_size =
|
||||
(params?.stream_delta_chunk_size ?? null) === null ? 1 : null;
|
||||
onParamChange('stream_delta_chunk_size', params.stream_delta_chunk_size);
|
||||
}}
|
||||
>
|
||||
{#if (params?.stream_delta_chunk_size ?? null) === null}
|
||||
|
|
@ -210,6 +215,7 @@
|
|||
on:click={() => {
|
||||
params.compact_token_threshold =
|
||||
(params?.compact_token_threshold ?? null) === null ? 80000 : null;
|
||||
onParamChange('compact_token_threshold', params.compact_token_threshold);
|
||||
}}
|
||||
>
|
||||
{#if (params?.compact_token_threshold ?? null) === null}
|
||||
|
|
@ -232,6 +238,8 @@
|
|||
)}
|
||||
placeholder={$i18n.t('Enter token threshold')}
|
||||
bind:value={params.compact_token_threshold}
|
||||
on:change={() =>
|
||||
onParamChange('compact_token_threshold', params.compact_token_threshold ?? null)}
|
||||
autocomplete="off"
|
||||
min="1"
|
||||
step="1"
|
||||
|
|
@ -264,6 +272,7 @@
|
|||
} else {
|
||||
params.function_calling = null;
|
||||
}
|
||||
onParamChange('function_calling', params.function_calling);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
|
|
@ -304,6 +313,7 @@
|
|||
} else {
|
||||
params.reasoning_tags = null;
|
||||
}
|
||||
onParamChange('reasoning_tags', params.reasoning_tags);
|
||||
}}
|
||||
>
|
||||
{#if (params?.reasoning_tags ?? null) === null}
|
||||
|
|
@ -328,6 +338,7 @@
|
|||
aria-label={$i18n.t('Start Tag')}
|
||||
placeholder={$i18n.t('Start Tag')}
|
||||
bind:value={params.reasoning_tags[0]}
|
||||
on:change={() => onParamChange('reasoning_tags', params.reasoning_tags ?? null)}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -339,6 +350,7 @@
|
|||
aria-label={$i18n.t('End Tag')}
|
||||
placeholder={$i18n.t('End Tag')}
|
||||
bind:value={params.reasoning_tags[1]}
|
||||
on:change={() => onParamChange('reasoning_tags', params.reasoning_tags ?? null)}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -364,6 +376,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.seed = (params?.seed ?? null) === null ? 0 : null;
|
||||
onParamChange('seed', params.seed);
|
||||
}}
|
||||
>
|
||||
{#if (params?.seed ?? null) === null}
|
||||
|
|
@ -384,6 +397,7 @@
|
|||
aria-label={$i18n.t('settings.personal.general.parameters.seed.label')}
|
||||
placeholder={$i18n.t('Enter Seed')}
|
||||
bind:value={params.seed}
|
||||
on:change={() => onParamChange('seed', params.seed ?? null)}
|
||||
autocomplete="off"
|
||||
min="0"
|
||||
/>
|
||||
|
|
@ -410,6 +424,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.stop = (params?.stop ?? null) === null ? '' : null;
|
||||
onParamChange('stop', params.stop);
|
||||
}}
|
||||
>
|
||||
{#if (params?.stop ?? null) === null}
|
||||
|
|
@ -430,6 +445,7 @@
|
|||
aria-label={$i18n.t('settings.personal.general.parameters.stopSequence.label')}
|
||||
placeholder={$i18n.t('Enter stop sequence')}
|
||||
bind:value={params.stop}
|
||||
on:change={() => onParamChange('stop', params.stop ?? null)}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -454,6 +470,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.temperature = (params?.temperature ?? null) === null ? 0.8 : null;
|
||||
onParamChange('temperature', params.temperature);
|
||||
}}
|
||||
>
|
||||
{#if (params?.temperature ?? null) === null}
|
||||
|
|
@ -493,6 +510,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.reasoning_effort = (params?.reasoning_effort ?? null) === null ? 'medium' : null;
|
||||
onParamChange('reasoning_effort', params.reasoning_effort);
|
||||
}}
|
||||
>
|
||||
{#if (params?.reasoning_effort ?? null) === null}
|
||||
|
|
@ -513,6 +531,7 @@
|
|||
aria-label={$i18n.t('settings.personal.general.parameters.reasoningEffort.label')}
|
||||
placeholder={$i18n.t('Enter reasoning effort')}
|
||||
bind:value={params.reasoning_effort}
|
||||
on:change={() => onParamChange('reasoning_effort', params.reasoning_effort ?? null)}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -539,6 +558,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.logit_bias = (params?.logit_bias ?? null) === null ? '' : null;
|
||||
onParamChange('logit_bias', params.logit_bias);
|
||||
}}
|
||||
>
|
||||
{#if (params?.logit_bias ?? null) === null}
|
||||
|
|
@ -561,6 +581,7 @@
|
|||
'Enter comma-separated "token:bias_value" pairs (example: 5432:100, 413:-100)'
|
||||
)}
|
||||
bind:value={params.logit_bias}
|
||||
on:change={() => onParamChange('logit_bias', params.logit_bias ?? null)}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -588,6 +609,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.max_tokens = (params?.max_tokens ?? null) === null ? 128 : null;
|
||||
onParamChange('max_tokens', params.max_tokens);
|
||||
}}
|
||||
>
|
||||
{#if (params?.max_tokens ?? null) === null}
|
||||
|
|
@ -631,6 +653,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.top_k = (params?.top_k ?? null) === null ? 40 : null;
|
||||
onParamChange('top_k', params.top_k);
|
||||
}}
|
||||
>
|
||||
{#if (params?.top_k ?? null) === null}
|
||||
|
|
@ -653,6 +676,7 @@
|
|||
step="1"
|
||||
value={params.top_k}
|
||||
on:input={setTopK}
|
||||
on:change={() => onParamChange('top_k', params.top_k ?? null)}
|
||||
class="w-full h-2 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -666,6 +690,7 @@
|
|||
max="1000"
|
||||
step="1"
|
||||
on:input={setTopK}
|
||||
on:change={() => onParamChange('top_k', params.top_k ?? null)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -692,6 +717,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.top_p = (params?.top_p ?? null) === null ? 0.9 : null;
|
||||
onParamChange('top_p', params.top_p);
|
||||
}}
|
||||
>
|
||||
{#if (params?.top_p ?? null) === null}
|
||||
|
|
@ -733,6 +759,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.min_p = (params?.min_p ?? null) === null ? 0.0 : null;
|
||||
onParamChange('min_p', params.min_p);
|
||||
}}
|
||||
>
|
||||
{#if (params?.min_p ?? null) === null}
|
||||
|
|
@ -775,6 +802,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.frequency_penalty = (params?.frequency_penalty ?? null) === null ? 1.1 : null;
|
||||
onParamChange('frequency_penalty', params.frequency_penalty);
|
||||
}}
|
||||
>
|
||||
{#if (params?.frequency_penalty ?? null) === null}
|
||||
|
|
@ -817,6 +845,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.presence_penalty = (params?.presence_penalty ?? null) === null ? 0.0 : null;
|
||||
onParamChange('presence_penalty', params.presence_penalty);
|
||||
}}
|
||||
>
|
||||
{#if (params?.presence_penalty ?? null) === null}
|
||||
|
|
@ -856,6 +885,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.mirostat = (params?.mirostat ?? null) === null ? 0 : null;
|
||||
onParamChange('mirostat', params.mirostat);
|
||||
}}
|
||||
>
|
||||
{#if (params?.mirostat ?? null) === null}
|
||||
|
|
@ -898,6 +928,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.mirostat_eta = (params?.mirostat_eta ?? null) === null ? 0.1 : null;
|
||||
onParamChange('mirostat_eta', params.mirostat_eta);
|
||||
}}
|
||||
>
|
||||
{#if (params?.mirostat_eta ?? null) === null}
|
||||
|
|
@ -940,6 +971,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.mirostat_tau = (params?.mirostat_tau ?? null) === null ? 5.0 : null;
|
||||
onParamChange('mirostat_tau', params.mirostat_tau);
|
||||
}}
|
||||
>
|
||||
{#if (params?.mirostat_tau ?? null) === null}
|
||||
|
|
@ -980,6 +1012,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.repeat_last_n = (params?.repeat_last_n ?? null) === null ? 64 : null;
|
||||
onParamChange('repeat_last_n', params.repeat_last_n);
|
||||
}}
|
||||
>
|
||||
{#if (params?.repeat_last_n ?? null) === null}
|
||||
|
|
@ -1023,6 +1056,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.tfs_z = (params?.tfs_z ?? null) === null ? 1 : null;
|
||||
onParamChange('tfs_z', params.tfs_z);
|
||||
}}
|
||||
>
|
||||
{#if (params?.tfs_z ?? null) === null}
|
||||
|
|
@ -1065,6 +1099,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.repeat_penalty = (params?.repeat_penalty ?? null) === null ? 1.1 : null;
|
||||
onParamChange('repeat_penalty', params.repeat_penalty);
|
||||
}}
|
||||
>
|
||||
{#if (params?.repeat_penalty ?? null) === null}
|
||||
|
|
@ -1107,6 +1142,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.use_mmap = (params?.use_mmap ?? null) === null ? true : null;
|
||||
onParamChange('use_mmap', params.use_mmap);
|
||||
}}
|
||||
>
|
||||
{#if (params?.use_mmap ?? null) === null}
|
||||
|
|
@ -1126,6 +1162,7 @@
|
|||
<div class=" pr-2">
|
||||
<Switch
|
||||
bind:state={params.use_mmap}
|
||||
on:change={(event) => onParamChange('use_mmap', event.detail)}
|
||||
ariaLabel={$i18n.t('settings.personal.general.parameters.useMmap.label')}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -1153,6 +1190,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.use_mlock = (params?.use_mlock ?? null) === null ? true : null;
|
||||
onParamChange('use_mlock', params.use_mlock);
|
||||
}}
|
||||
>
|
||||
{#if (params?.use_mlock ?? null) === null}
|
||||
|
|
@ -1173,6 +1211,7 @@
|
|||
<div class=" pr-2">
|
||||
<Switch
|
||||
bind:state={params.use_mlock}
|
||||
on:change={(event) => onParamChange('use_mlock', event.detail)}
|
||||
ariaLabel={$i18n.t('settings.personal.general.parameters.useMlock.label')}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -1207,6 +1246,7 @@
|
|||
} else {
|
||||
params.think = null;
|
||||
}
|
||||
onParamChange('think', params.think);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
|
|
@ -1232,6 +1272,7 @@
|
|||
aria-label={`${$i18n.t('settings.personal.general.parameters.think.label')} (${$i18n.t('settings.personal.general.parameters.ollama.label')})`}
|
||||
placeholder={$i18n.t("e.g. 'low', 'medium', 'high'")}
|
||||
bind:value={params.think}
|
||||
on:change={() => onParamChange('think', params.think ?? null)}
|
||||
autocomplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -1257,6 +1298,7 @@
|
|||
class="p-1 px-3 text-xs flex rounded-sm transition font-normal text-gray-900 dark:text-gray-100"
|
||||
on:click={() => {
|
||||
params.format = (params?.format ?? null) === null ? 'json' : null;
|
||||
onParamChange('format', params.format);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
|
|
@ -1276,6 +1318,7 @@
|
|||
ariaLabel={`${$i18n.t('settings.personal.general.parameters.format.label')} (${$i18n.t('settings.personal.general.parameters.ollama.label')})`}
|
||||
placeholder={$i18n.t('e.g. "json" or a JSON schema')}
|
||||
bind:value={params.format}
|
||||
on:change={() => onParamChange('format', params.format ?? null)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
@ -1303,6 +1346,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.num_keep = (params?.num_keep ?? null) === null ? 24 : null;
|
||||
onParamChange('num_keep', params.num_keep);
|
||||
}}
|
||||
>
|
||||
{#if (params?.num_keep ?? null) === null}
|
||||
|
|
@ -1347,6 +1391,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.num_ctx = (params?.num_ctx ?? null) === null ? 2048 : null;
|
||||
onParamChange('num_ctx', params.num_ctx);
|
||||
}}
|
||||
>
|
||||
{#if (params?.num_ctx ?? null) === null}
|
||||
|
|
@ -1393,6 +1438,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.num_batch = (params?.num_batch ?? null) === null ? 512 : null;
|
||||
onParamChange('num_batch', params.num_batch);
|
||||
}}
|
||||
>
|
||||
{#if (params?.num_batch ?? null) === null}
|
||||
|
|
@ -1440,6 +1486,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.num_thread = (params?.num_thread ?? null) === null ? 2 : null;
|
||||
onParamChange('num_thread', params.num_thread);
|
||||
}}
|
||||
>
|
||||
{#if (params?.num_thread ?? null) === null}
|
||||
|
|
@ -1485,6 +1532,7 @@
|
|||
type="button"
|
||||
on:click={() => {
|
||||
params.num_gpu = (params?.num_gpu ?? null) === null ? 0 : null;
|
||||
onParamChange('num_gpu', params.num_gpu);
|
||||
}}
|
||||
>
|
||||
{#if (params?.num_gpu ?? null) === null}
|
||||
|
|
@ -1528,6 +1576,7 @@
|
|||
class="p-1 px-3 text-xs flex rounded-sm transition font-normal text-gray-900 dark:text-gray-100"
|
||||
on:click={() => {
|
||||
params.keep_alive = (params?.keep_alive ?? null) === null ? '5m' : null;
|
||||
onParamChange('keep_alive', params.keep_alive);
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
|
|
@ -1548,13 +1597,17 @@
|
|||
aria-label={`${$i18n.t('settings.personal.general.parameters.keepAlive.label')} (${$i18n.t('settings.personal.general.parameters.ollama.label')})`}
|
||||
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
|
||||
bind:value={params.keep_alive}
|
||||
on:change={() => onParamChange('keep_alive', params.keep_alive ?? null)}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if custom && admin}
|
||||
<CustomParams bind:value={params.custom_params} />
|
||||
<CustomParams
|
||||
bind:value={params.custom_params}
|
||||
onChange={(value) => onParamChange('custom_params', value)}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
const i18n = getContext<Writable<I18n>>('i18n');
|
||||
export let compact = false;
|
||||
export let value: Record<string, unknown> = {};
|
||||
export let onChange: (value: Record<string, unknown>) => void = () => {};
|
||||
const id = `custom-params-${uuidv4()}`;
|
||||
|
||||
// Suggestions only; support depends on the provider and model.
|
||||
|
|
@ -94,6 +95,7 @@
|
|||
value[name] = value[key];
|
||||
delete value[key];
|
||||
value = { ...value };
|
||||
onChange(value);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
|
@ -113,6 +115,7 @@
|
|||
placeholder={compact ? $i18n.t('e.g. 0.7') : $i18n.t('Custom Parameter Value')}
|
||||
value={typeof value[key] === 'object' ? JSON.stringify(value[key]) : value[key]}
|
||||
on:input={(event) => (value = { ...value, [key]: event.currentTarget.value })}
|
||||
on:change={() => onChange(value)}
|
||||
/>
|
||||
{#if options.length}
|
||||
<datalist id={`${id}-values-${index}`}>
|
||||
|
|
@ -131,6 +134,7 @@
|
|||
on:click={() => {
|
||||
delete value[key];
|
||||
value = { ...value };
|
||||
onChange(value);
|
||||
}}
|
||||
>
|
||||
{#if compact}<XMark className="size-3" />{:else}{$i18n.t('Remove')}{/if}
|
||||
|
|
|
|||
|
|
@ -95,4 +95,5 @@
|
|||
resize();
|
||||
}}
|
||||
on:blur={onBlur}
|
||||
on:change
|
||||
></textarea>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue