From e9cca320b40025a892436a9791902af85a426ad3 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Oct 2026 22:02:23 +0400 Subject: [PATCH] refac --- backend/open_webui/main.py | 4 +- backend/open_webui/utils/payload.py | 10 ++-- src/lib/components/chat/Chat.svelte | 4 +- src/lib/components/chat/MessageInput.svelte | 3 +- .../chat/MessageInput/ModelControls.svelte | 51 +++++++++++++------ src/lib/components/chat/Placeholder.svelte | 2 - 6 files changed, 45 insertions(+), 29 deletions(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 4a83f94a2c..6daa06fbb9 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1197,7 +1197,7 @@ async def chat_completion( request_params = {key: value for key, value in (form_data.get('params') or {}).items() if value is not None} model_controls = request_params.pop('model_controls', {}) if not isinstance(model_controls, dict): - raise HTTPException(400, 'Model control selections must be keyed by model.') + raise HTTPException(400, 'Model control options must be keyed by model.') model_controls = {} if form_data.get('automation_id') else model_controls if any(model_controls.values()) and user.role != 'admin': permissions = await Config.get('user.permissions') @@ -1205,7 +1205,7 @@ async def chat_completion( if not await has_permission(user.id, permission, permissions): raise HTTPException(403, 'You cannot change model parameters.') if missing_base_model and model_controls.get(model_id): - raise HTTPException(400, 'Model control selections cannot be applied to the fallback model.') + raise HTTPException(400, 'Model control options cannot be applied to the fallback model.') if model_info_params or request_params: form_data['params'] = merge_model_params(model_info_params, request_params) diff --git a/backend/open_webui/utils/payload.py b/backend/open_webui/utils/payload.py index c07b882a0f..372c107e0f 100644 --- a/backend/open_webui/utils/payload.py +++ b/backend/open_webui/utils/payload.py @@ -17,15 +17,15 @@ from open_webui.utils.task import prompt_template, prompt_variables_template log = logging.getLogger(__name__) -def apply_model_controls(params: dict, controls: dict, selections: dict) -> dict: +def apply_model_controls(params: dict, controls: dict, model_options: dict) -> dict: """Expand approved choices into ordinary Custom Params before normal request processing.""" - if not isinstance(selections, dict): - raise HTTPException(400, 'Model control selections must be an object.') - for key, choice in selections.items(): + if not isinstance(model_options, dict): + raise HTTPException(400, 'Model control options must be an object.') + for key, choice in model_options.items(): if key not in controls or not isinstance(choice, str) or choice not in controls[key]['options']: raise HTTPException(400, f'Model control {key}: the selected option is no longer available.') for key, control in controls.items(): - choice = selections.get(key, control.get('default')) + choice = model_options.get(key, control.get('default')) if choice is not None: params['custom_params'] = deep_update( deepcopy(params.get('custom_params') or {}), deepcopy(control['options'][choice]['params']) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 648a513354..c6c4076345 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -3636,6 +3636,7 @@ params: { ...$settings?.params, ...params, + model_controls: $settings?.params?.model_controls ?? {}, stop: getStopTokens() }, @@ -4504,7 +4505,6 @@ class=" pb-2 {dragged ? 'z-0' : 'z-10'}" > {}; export let forkHandler: Function = () => {}; export let chatId = ''; - export let params = {}; export let contextUsage = null; export let contextCompactionEnabled = false; export let embedded = false; @@ -2618,7 +2617,7 @@ triggerClassName="items-center gap-1.5 rounded-lg pl-2 pr-1.5 py-1 text-[0.8125rem] font-normal text-gray-600 transition-colors duration-100 hover:bg-gray-50/40 hover:text-gray-700 dark:text-gray-300 dark:hover:bg-gray-800/40 dark:hover:text-gray-200" /> - + {#if isActive && prompt === '' && files.length === 0}
diff --git a/src/lib/components/chat/MessageInput/ModelControls.svelte b/src/lib/components/chat/MessageInput/ModelControls.svelte index 621b335ecd..08a38ab9f0 100644 --- a/src/lib/components/chat/MessageInput/ModelControls.svelte +++ b/src/lib/components/chat/MessageInput/ModelControls.svelte @@ -5,6 +5,8 @@ import DropdownMenu from '$lib/components/common/DropdownMenu.svelte'; import DropdownSub from '$lib/components/common/DropdownSub.svelte'; import type { ModelControl } from '$lib/apis'; + import { updateUserSettings } from '$lib/apis/users'; + import { toast } from 'svelte-sonner'; import ChevronRight from '$lib/components/icons/ChevronRight.svelte'; import ChevronLeft from '$lib/components/icons/ChevronLeft.svelte'; import Check from '$lib/components/icons/Check.svelte'; @@ -14,7 +16,8 @@ const i18n: any = getContext('i18n'); export let selectedModels: string[] = []; - export let params: Record = {}; + let saving = false; + $: modelControls = $settings?.params?.model_controls ?? {}; let active: { model: Model; key: string; @@ -43,18 +46,36 @@ $: selectedClass = $settings?.highContrastMode ? 'bg-gray-200 dark:bg-gray-800' : 'bg-gray-50/70 dark:bg-gray-800/60'; - const select = (modelId: string, controlId: string, value: string) => { - const selections = { ...params.model_controls?.[modelId] }; - if (value) selections[controlId] = value; - else delete selections[controlId]; - params = { ...params, model_controls: { ...params.model_controls, [modelId]: selections } }; + const select = async (modelId: string, controlId: string, value: string) => { + const previous = modelControls; + const modelOptions = { ...modelControls[modelId] }; + if (value) modelOptions[controlId] = value; + else delete modelOptions[controlId]; + settings.set({ + ...$settings, + params: { + ...$settings.params, + model_controls: { ...modelControls, [modelId]: modelOptions } + } + }); + saving = true; + try { + if (!(await updateUserSettings(localStorage.token, { ui: { params: $settings.params } }))) { + throw new Error($i18n.t('Failed to save settings')); + } + } catch (error) { + settings.set({ ...$settings, params: { ...$settings.params, model_controls: previous } }); + toast.error(String(error)); + } finally { + saving = false; + } }; {#snippet summary(model: Model, key: string, control: ModelControl)} {control.label} - {control.options[params.model_controls?.[model.id]?.[key] ?? control.default ?? '']?.label ?? + {control.options[modelControls[model.id]?.[key] ?? control.default ?? '']?.label ?? $i18n.t('Default')} @@ -69,28 +90,28 @@ {#each Object.entries(control.options) as [value, option] (value)} {/each} {/snippet} diff --git a/src/lib/components/chat/Placeholder.svelte b/src/lib/components/chat/Placeholder.svelte index cd627c3637..603861eae8 100644 --- a/src/lib/components/chat/Placeholder.svelte +++ b/src/lib/components/chat/Placeholder.svelte @@ -47,7 +47,6 @@ export let history; export let prompt = ''; - export let params = {}; export let files = []; export let messageInput = null; @@ -242,7 +241,6 @@
{#if !($selectedFolder && folderReadOnly)}