mirror of
https://github.com/open-webui/open-webui
synced 2025-06-26 18:26:48 +00:00
enh/refac: ollama advanced params
This commit is contained in:
parent
ad80643774
commit
8f68b25510
@ -1323,7 +1323,7 @@ async def generate_chat_completion(
|
||||
prefix_id = api_config.get("prefix_id", None)
|
||||
if prefix_id:
|
||||
payload["model"] = payload["model"].replace(f"{prefix_id}.", "")
|
||||
# payload["keep_alive"] = -1 # keep alive forever
|
||||
|
||||
return await send_post_request(
|
||||
url=f"{url}/api/chat",
|
||||
payload=json.dumps(payload),
|
||||
|
@ -698,13 +698,8 @@ def apply_params_to_form_data(form_data, model):
|
||||
params = deep_update(params, custom_params)
|
||||
|
||||
if model.get("ollama"):
|
||||
# Ollama specific parameters
|
||||
form_data["options"] = params
|
||||
|
||||
if "format" in params:
|
||||
form_data["format"] = params["format"]
|
||||
|
||||
if "keep_alive" in params:
|
||||
form_data["keep_alive"] = params["keep_alive"]
|
||||
else:
|
||||
if isinstance(params, dict):
|
||||
for key, value in params.items():
|
||||
|
@ -175,14 +175,26 @@ def apply_model_params_to_body_ollama(params: dict, form_data: dict) -> dict:
|
||||
"num_thread": int,
|
||||
}
|
||||
|
||||
# Extract keep_alive from options if it exists
|
||||
if "options" in form_data and "keep_alive" in form_data["options"]:
|
||||
form_data["keep_alive"] = form_data["options"]["keep_alive"]
|
||||
del form_data["options"]["keep_alive"]
|
||||
def parse_json(value: str) -> dict:
|
||||
"""
|
||||
Parses a JSON string into a dictionary, handling potential JSONDecodeError.
|
||||
"""
|
||||
try:
|
||||
return json.loads(value)
|
||||
except Exception as e:
|
||||
return value
|
||||
|
||||
if "options" in form_data and "format" in form_data["options"]:
|
||||
form_data["format"] = form_data["options"]["format"]
|
||||
del form_data["options"]["format"]
|
||||
ollama_root_params = {
|
||||
"format": lambda x: parse_json(x),
|
||||
"keep_alive": lambda x: parse_json(x),
|
||||
"think": bool,
|
||||
}
|
||||
|
||||
for key, value in ollama_root_params.items():
|
||||
if (param := params.get(key, None)) is not None:
|
||||
# Copy the parameter to new name then delete it, to prevent Ollama warning of invalid option provided
|
||||
form_data[key] = value(param)
|
||||
del params[key]
|
||||
|
||||
return apply_model_params_to_body(params, form_data, mappings)
|
||||
|
||||
@ -279,36 +291,46 @@ def convert_payload_openai_to_ollama(openai_payload: dict) -> dict:
|
||||
openai_payload.get("messages")
|
||||
)
|
||||
ollama_payload["stream"] = openai_payload.get("stream", False)
|
||||
|
||||
if "tools" in openai_payload:
|
||||
ollama_payload["tools"] = openai_payload["tools"]
|
||||
|
||||
if "format" in openai_payload:
|
||||
ollama_payload["format"] = openai_payload["format"]
|
||||
|
||||
# If there are advanced parameters in the payload, format them in Ollama's options field
|
||||
if openai_payload.get("options"):
|
||||
ollama_payload["options"] = openai_payload["options"]
|
||||
ollama_options = openai_payload["options"]
|
||||
|
||||
def parse_json(value: str) -> dict:
|
||||
"""
|
||||
Parses a JSON string into a dictionary, handling potential JSONDecodeError.
|
||||
"""
|
||||
try:
|
||||
return json.loads(value)
|
||||
except Exception as e:
|
||||
return value
|
||||
|
||||
ollama_root_params = {
|
||||
"format": lambda x: parse_json(x),
|
||||
"keep_alive": lambda x: parse_json(x),
|
||||
"think": bool,
|
||||
}
|
||||
|
||||
# Ollama's options field can contain parameters that should be at the root level.
|
||||
for key, value in ollama_root_params.items():
|
||||
if (param := ollama_options.get(key, None)) is not None:
|
||||
# Copy the parameter to new name then delete it, to prevent Ollama warning of invalid option provided
|
||||
ollama_payload[key] = value(param)
|
||||
del ollama_options[key]
|
||||
|
||||
# Re-Mapping OpenAI's `max_tokens` -> Ollama's `num_predict`
|
||||
if "max_tokens" in ollama_options:
|
||||
ollama_options["num_predict"] = ollama_options["max_tokens"]
|
||||
del ollama_options[
|
||||
"max_tokens"
|
||||
] # To prevent Ollama warning of invalid option provided
|
||||
del ollama_options["max_tokens"]
|
||||
|
||||
# Ollama lacks a "system" prompt option. It has to be provided as a direct parameter, so we copy it down.
|
||||
# Comment: Not sure why this is needed, but we'll keep it for compatibility.
|
||||
if "system" in ollama_options:
|
||||
ollama_payload["system"] = ollama_options["system"]
|
||||
del ollama_options[
|
||||
"system"
|
||||
] # To prevent Ollama warning of invalid option provided
|
||||
|
||||
# Extract keep_alive from options if it exists
|
||||
if "keep_alive" in ollama_options:
|
||||
ollama_payload["keep_alive"] = ollama_options["keep_alive"]
|
||||
del ollama_options["keep_alive"]
|
||||
del ollama_options["system"]
|
||||
|
||||
# If there is the "stop" parameter in the openai_payload, remap it to the ollama_payload.options
|
||||
if "stop" in openai_payload:
|
||||
|
@ -1642,9 +1642,6 @@
|
||||
params: {
|
||||
...$settings?.params,
|
||||
...params,
|
||||
|
||||
format: $settings.requestFormat ?? undefined,
|
||||
keep_alive: $settings.keepAlive ?? undefined,
|
||||
stop:
|
||||
(params?.stop ?? $settings?.params?.stop ?? undefined)
|
||||
? (params?.stop.split(',').map((token) => token.trim()) ?? $settings.params.stop).map(
|
||||
|
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import Switch from '$lib/components/common/Switch.svelte';
|
||||
import Textarea from '$lib/components/common/Textarea.svelte';
|
||||
import Tooltip from '$lib/components/common/Tooltip.svelte';
|
||||
import Plus from '$lib/components/icons/Plus.svelte';
|
||||
import { getContext } from 'svelte';
|
||||
@ -34,6 +35,9 @@
|
||||
repeat_penalty: null,
|
||||
use_mmap: null,
|
||||
use_mlock: null,
|
||||
think: null,
|
||||
format: null,
|
||||
keep_alive: null,
|
||||
num_keep: null,
|
||||
num_ctx: null,
|
||||
num_batch: null,
|
||||
@ -1092,6 +1096,76 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class=" py-0.5 w-full justify-between">
|
||||
<Tooltip
|
||||
content={$i18n.t(
|
||||
'This option enables or disables the use of the Ollama Think feature, which allows the model to think before generating a response. When enabled, the model can take a moment to process the conversation context and generate a more thoughtful response.'
|
||||
)}
|
||||
placement="top-start"
|
||||
className="inline-tooltip"
|
||||
>
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">
|
||||
{'think'} ({$i18n.t('Ollama')})
|
||||
</div>
|
||||
<button
|
||||
class="p-1 px-3 text-xs flex rounded-sm transition"
|
||||
on:click={() => {
|
||||
params.think = (params?.think ?? null) === null ? true : params.think ? false : null;
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{#if params.think === true}
|
||||
<span class="ml-2 self-center">{$i18n.t('On')}</span>
|
||||
{:else if params.think === false}
|
||||
<span class="ml-2 self-center">{$i18n.t('Off')}</span>
|
||||
{:else}
|
||||
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
||||
<div class=" py-0.5 w-full justify-between">
|
||||
<Tooltip
|
||||
content={$i18n.t(
|
||||
'This option enables or disables the use of the Ollama Think feature, which allows the model to think before generating a response. When enabled, the model can take a moment to process the conversation context and generate a more thoughtful response.'
|
||||
)}
|
||||
placement="top-start"
|
||||
className="inline-tooltip"
|
||||
>
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">
|
||||
{'format'} ({$i18n.t('Ollama')})
|
||||
</div>
|
||||
<button
|
||||
class="p-1 px-3 text-xs flex rounded-sm transition"
|
||||
on:click={() => {
|
||||
params.format = (params?.format ?? null) === null ? 'json' : null;
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{#if (params?.format ?? null) === null}
|
||||
<span class="ml-2 self-center">{$i18n.t('Default')}</span>
|
||||
{:else}
|
||||
<span class="ml-2 self-center">{$i18n.t('JSON')}</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
|
||||
{#if (params?.format ?? null) !== null}
|
||||
<div class="flex mt-0.5 space-x-2">
|
||||
<Textarea
|
||||
className="w-full text-sm bg-transparent outline-hidden"
|
||||
placeholder={$i18n.t('e.g. "json" or a JSON schema')}
|
||||
bind:value={params.format}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class=" py-0.5 w-full justify-between">
|
||||
<Tooltip
|
||||
content={$i18n.t(
|
||||
@ -1368,6 +1442,46 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class=" py-0.5 w-full justify-between">
|
||||
<Tooltip
|
||||
content={$i18n.t(
|
||||
'This option controls how long the model will stay loaded into memory following the request (default: 5m)'
|
||||
)}
|
||||
placement="top-start"
|
||||
className="inline-tooltip"
|
||||
>
|
||||
<div class=" py-0.5 flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">
|
||||
{'keep_alive'} ({$i18n.t('Ollama')})
|
||||
</div>
|
||||
<button
|
||||
class="p-1 px-3 text-xs flex rounded-sm transition"
|
||||
on:click={() => {
|
||||
params.keep_alive = (params?.keep_alive ?? null) === null ? '5m' : null;
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{#if (params?.keep_alive ?? 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>
|
||||
</Tooltip>
|
||||
|
||||
{#if (params?.keep_alive ?? null) !== null}
|
||||
<div class="flex mt-0.5 space-x-2">
|
||||
<input
|
||||
class="w-full text-sm bg-transparent outline-hidden"
|
||||
type="text"
|
||||
placeholder={$i18n.t("e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.")}
|
||||
bind:value={params.keep_alive}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if custom && admin}
|
||||
<div class="flex flex-col justify-center">
|
||||
{#each Object.keys(params?.custom_params ?? {}) as key}
|
||||
|
@ -10,12 +10,11 @@
|
||||
|
||||
import AdvancedParams from './Advanced/AdvancedParams.svelte';
|
||||
import Textarea from '$lib/components/common/Textarea.svelte';
|
||||
|
||||
export let saveSettings: Function;
|
||||
export let getModels: Function;
|
||||
|
||||
// General
|
||||
let themes = ['dark', 'light', 'rose-pine dark', 'rose-pine-dawn light', 'oled-dark'];
|
||||
let themes = ['dark', 'light', 'oled-dark'];
|
||||
let selectedTheme = 'system';
|
||||
|
||||
let languages: Awaited<ReturnType<typeof getLanguages>> = [];
|
||||
@ -40,10 +39,6 @@
|
||||
}
|
||||
};
|
||||
|
||||
// Advanced
|
||||
let requestFormat = null;
|
||||
let keepAlive: string | null = null;
|
||||
|
||||
let params = {
|
||||
// Advanced
|
||||
stream_response: null,
|
||||
@ -71,37 +66,7 @@
|
||||
num_gpu: null
|
||||
};
|
||||
|
||||
const validateJSON = (json) => {
|
||||
try {
|
||||
const obj = JSON.parse(json);
|
||||
|
||||
if (obj && typeof obj === 'object') {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {}
|
||||
return false;
|
||||
};
|
||||
|
||||
const toggleRequestFormat = async () => {
|
||||
if (requestFormat === null) {
|
||||
requestFormat = 'json';
|
||||
} else {
|
||||
requestFormat = null;
|
||||
}
|
||||
|
||||
saveSettings({ requestFormat: requestFormat !== null ? requestFormat : undefined });
|
||||
};
|
||||
|
||||
const saveHandler = async () => {
|
||||
if (requestFormat !== null && requestFormat !== 'json') {
|
||||
if (validateJSON(requestFormat) === false) {
|
||||
toast.error($i18n.t('Invalid JSON schema'));
|
||||
return;
|
||||
} else {
|
||||
requestFormat = JSON.parse(requestFormat);
|
||||
}
|
||||
}
|
||||
|
||||
saveSettings({
|
||||
system: system !== '' ? system : undefined,
|
||||
params: {
|
||||
@ -130,15 +95,12 @@
|
||||
use_mmap: params.use_mmap !== null ? params.use_mmap : undefined,
|
||||
use_mlock: params.use_mlock !== null ? params.use_mlock : undefined,
|
||||
num_thread: params.num_thread !== null ? params.num_thread : undefined,
|
||||
num_gpu: params.num_gpu !== null ? params.num_gpu : undefined
|
||||
},
|
||||
keepAlive: keepAlive ? (isNaN(keepAlive) ? keepAlive : parseInt(keepAlive)) : undefined,
|
||||
requestFormat: requestFormat !== null ? requestFormat : undefined
|
||||
num_gpu: params.num_gpu !== null ? params.num_gpu : undefined,
|
||||
keep_alive: params.keep_alive !== null ? params.keep_alive : undefined,
|
||||
format: params.format !== null ? params.format : undefined
|
||||
}
|
||||
});
|
||||
dispatch('save');
|
||||
|
||||
requestFormat =
|
||||
typeof requestFormat === 'object' ? JSON.stringify(requestFormat, null, 2) : requestFormat;
|
||||
};
|
||||
|
||||
onMount(async () => {
|
||||
@ -149,14 +111,6 @@
|
||||
notificationEnabled = $settings.notificationEnabled ?? false;
|
||||
system = $settings.system ?? '';
|
||||
|
||||
requestFormat = $settings.requestFormat ?? null;
|
||||
if (requestFormat !== null && requestFormat !== 'json') {
|
||||
requestFormat =
|
||||
typeof requestFormat === 'object' ? JSON.stringify(requestFormat, null, 2) : requestFormat;
|
||||
}
|
||||
|
||||
keepAlive = $settings.keepAlive ?? null;
|
||||
|
||||
params = { ...params, ...$settings.params };
|
||||
params.stop = $settings?.params?.stop ? ($settings?.params?.stop ?? []).join(',') : null;
|
||||
});
|
||||
@ -335,77 +289,6 @@
|
||||
|
||||
{#if showAdvanced}
|
||||
<AdvancedParams admin={$user?.role === 'admin'} bind:params />
|
||||
<hr class=" border-gray-100 dark:border-gray-850" />
|
||||
|
||||
<div class=" 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-sm 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 text-sm dark:text-gray-300 dark:bg-gray-850 outline-hidden"
|
||||
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=" flex w-full justify-between">
|
||||
<div class=" self-center text-xs font-medium">{$i18n.t('Request Mode')}</div>
|
||||
|
||||
<button
|
||||
class="p-1 px-3 text-xs flex rounded-sm transition"
|
||||
on:click={() => {
|
||||
toggleRequestFormat();
|
||||
}}
|
||||
>
|
||||
{#if requestFormat === null}
|
||||
<span class="ml-2 self-center"> {$i18n.t('Default')} </span>
|
||||
{:else}
|
||||
<!-- <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>
|
||||
|
||||
{#if requestFormat !== null}
|
||||
<div class="flex mt-1 space-x-2">
|
||||
<Textarea
|
||||
className="w-full text-sm dark:text-gray-300 dark:bg-gray-900 outline-hidden"
|
||||
placeholder={$i18n.t('e.g. "json" or a JSON schema')}
|
||||
bind:value={requestFormat}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
Loading…
Reference in New Issue
Block a user