mirror of
https://git.mirrors.martin98.com/https://github.com/open-webui/open-webui
synced 2025-08-16 21:36:01 +08:00
feat: toggleable ollama
This commit is contained in:
parent
af022947be
commit
21ca55dd30
@ -43,6 +43,7 @@ from utils.utils import (
|
|||||||
from config import (
|
from config import (
|
||||||
SRC_LOG_LEVELS,
|
SRC_LOG_LEVELS,
|
||||||
OLLAMA_BASE_URLS,
|
OLLAMA_BASE_URLS,
|
||||||
|
ENABLE_OLLAMA_API,
|
||||||
ENABLE_MODEL_FILTER,
|
ENABLE_MODEL_FILTER,
|
||||||
MODEL_FILTER_LIST,
|
MODEL_FILTER_LIST,
|
||||||
UPLOAD_DIR,
|
UPLOAD_DIR,
|
||||||
@ -67,6 +68,8 @@ app.state.config = AppConfig()
|
|||||||
app.state.config.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER
|
app.state.config.ENABLE_MODEL_FILTER = ENABLE_MODEL_FILTER
|
||||||
app.state.config.MODEL_FILTER_LIST = MODEL_FILTER_LIST
|
app.state.config.MODEL_FILTER_LIST = MODEL_FILTER_LIST
|
||||||
|
|
||||||
|
|
||||||
|
app.state.config.ENABLE_OLLAMA_API = ENABLE_OLLAMA_API
|
||||||
app.state.config.OLLAMA_BASE_URLS = OLLAMA_BASE_URLS
|
app.state.config.OLLAMA_BASE_URLS = OLLAMA_BASE_URLS
|
||||||
app.state.MODELS = {}
|
app.state.MODELS = {}
|
||||||
|
|
||||||
@ -96,6 +99,21 @@ async def get_status():
|
|||||||
return {"status": True}
|
return {"status": True}
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/config")
|
||||||
|
async def get_config(user=Depends(get_admin_user)):
|
||||||
|
return {"ENABLE_OLLAMA_API": app.state.config.ENABLE_OLLAMA_API}
|
||||||
|
|
||||||
|
|
||||||
|
class OllamaConfigForm(BaseModel):
|
||||||
|
enable_ollama_api: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/config/update")
|
||||||
|
async def update_config(form_data: OllamaConfigForm, user=Depends(get_admin_user)):
|
||||||
|
app.state.config.ENABLE_OLLAMA_API = form_data.enable_ollama_api
|
||||||
|
return {"ENABLE_OLLAMA_API": app.state.config.ENABLE_OLLAMA_API}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/urls")
|
@app.get("/urls")
|
||||||
async def get_ollama_api_urls(user=Depends(get_admin_user)):
|
async def get_ollama_api_urls(user=Depends(get_admin_user)):
|
||||||
return {"OLLAMA_BASE_URLS": app.state.config.OLLAMA_BASE_URLS}
|
return {"OLLAMA_BASE_URLS": app.state.config.OLLAMA_BASE_URLS}
|
||||||
@ -156,14 +174,23 @@ def merge_models_lists(model_lists):
|
|||||||
|
|
||||||
async def get_all_models():
|
async def get_all_models():
|
||||||
log.info("get_all_models()")
|
log.info("get_all_models()")
|
||||||
tasks = [fetch_url(f"{url}/api/tags") for url in app.state.config.OLLAMA_BASE_URLS]
|
|
||||||
responses = await asyncio.gather(*tasks)
|
|
||||||
|
|
||||||
models = {
|
if app.state.config.ENABLE_OLLAMA_API:
|
||||||
"models": merge_models_lists(
|
tasks = [
|
||||||
map(lambda response: response["models"] if response else None, responses)
|
fetch_url(f"{url}/api/tags") for url in app.state.config.OLLAMA_BASE_URLS
|
||||||
)
|
]
|
||||||
}
|
responses = await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
models = {
|
||||||
|
"models": merge_models_lists(
|
||||||
|
map(
|
||||||
|
lambda response: response["models"] if response else None, responses
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
else:
|
||||||
|
models = {"models": []}
|
||||||
|
|
||||||
app.state.MODELS = {model["model"]: model for model in models["models"]}
|
app.state.MODELS = {model["model"]: model for model in models["models"]}
|
||||||
|
|
||||||
|
@ -384,6 +384,13 @@ if not os.path.exists(LITELLM_CONFIG_PATH):
|
|||||||
# OLLAMA_BASE_URL
|
# OLLAMA_BASE_URL
|
||||||
####################################
|
####################################
|
||||||
|
|
||||||
|
|
||||||
|
ENABLE_OLLAMA_API = PersistentConfig(
|
||||||
|
"ENABLE_OLLAMA_API",
|
||||||
|
"ollama.enable",
|
||||||
|
os.environ.get("ENABLE_OLLAMA_API", "True").lower() == "true",
|
||||||
|
)
|
||||||
|
|
||||||
OLLAMA_API_BASE_URL = os.environ.get(
|
OLLAMA_API_BASE_URL = os.environ.get(
|
||||||
"OLLAMA_API_BASE_URL", "http://localhost:11434/api"
|
"OLLAMA_API_BASE_URL", "http://localhost:11434/api"
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,73 @@
|
|||||||
import { OLLAMA_API_BASE_URL } from '$lib/constants';
|
import { OLLAMA_API_BASE_URL } from '$lib/constants';
|
||||||
import { promptTemplate } from '$lib/utils';
|
import { promptTemplate } from '$lib/utils';
|
||||||
|
|
||||||
|
export const getOllamaConfig = async (token: string = '') => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${OLLAMA_API_BASE_URL}/config`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token && { authorization: `Bearer ${token}` })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) throw await res.json();
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
if ('detail' in err) {
|
||||||
|
error = err.detail;
|
||||||
|
} else {
|
||||||
|
error = 'Server connection failed';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateOllamaConfig = async (token: string = '', enable_ollama_api: boolean) => {
|
||||||
|
let error = null;
|
||||||
|
|
||||||
|
const res = await fetch(`${OLLAMA_API_BASE_URL}/config/update`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
...(token && { authorization: `Bearer ${token}` })
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
enable_ollama_api: enable_ollama_api
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (!res.ok) throw await res.json();
|
||||||
|
return res.json();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
if ('detail' in err) {
|
||||||
|
error = err.detail;
|
||||||
|
} else {
|
||||||
|
error = 'Server connection failed';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
export const getOllamaUrls = async (token: string = '') => {
|
export const getOllamaUrls = async (token: string = '') => {
|
||||||
let error = null;
|
let error = null;
|
||||||
|
|
||||||
|
@ -3,7 +3,13 @@
|
|||||||
import { createEventDispatcher, onMount, getContext } from 'svelte';
|
import { createEventDispatcher, onMount, getContext } from 'svelte';
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
import { getOllamaUrls, getOllamaVersion, updateOllamaUrls } from '$lib/apis/ollama';
|
import {
|
||||||
|
getOllamaConfig,
|
||||||
|
getOllamaUrls,
|
||||||
|
getOllamaVersion,
|
||||||
|
updateOllamaConfig,
|
||||||
|
updateOllamaUrls
|
||||||
|
} from '$lib/apis/ollama';
|
||||||
import {
|
import {
|
||||||
getOpenAIConfig,
|
getOpenAIConfig,
|
||||||
getOpenAIKeys,
|
getOpenAIKeys,
|
||||||
@ -26,6 +32,7 @@
|
|||||||
let OPENAI_API_BASE_URLS = [''];
|
let OPENAI_API_BASE_URLS = [''];
|
||||||
|
|
||||||
let ENABLE_OPENAI_API = false;
|
let ENABLE_OPENAI_API = false;
|
||||||
|
let ENABLE_OLLAMA_API = false;
|
||||||
|
|
||||||
const updateOpenAIHandler = async () => {
|
const updateOpenAIHandler = async () => {
|
||||||
OPENAI_API_BASE_URLS = await updateOpenAIUrls(localStorage.token, OPENAI_API_BASE_URLS);
|
OPENAI_API_BASE_URLS = await updateOpenAIUrls(localStorage.token, OPENAI_API_BASE_URLS);
|
||||||
@ -50,10 +57,13 @@
|
|||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if ($user.role === 'admin') {
|
if ($user.role === 'admin') {
|
||||||
OLLAMA_BASE_URLS = await getOllamaUrls(localStorage.token);
|
const ollamaConfig = await getOllamaConfig(localStorage.token);
|
||||||
|
const openaiConfig = await getOpenAIConfig(localStorage.token);
|
||||||
|
|
||||||
const config = await getOpenAIConfig(localStorage.token);
|
ENABLE_OPENAI_API = openaiConfig.ENABLE_OPENAI_API;
|
||||||
ENABLE_OPENAI_API = config.ENABLE_OPENAI_API;
|
ENABLE_OLLAMA_API = ollamaConfig.ENABLE_OLLAMA_API;
|
||||||
|
|
||||||
|
OLLAMA_BASE_URLS = await getOllamaUrls(localStorage.token);
|
||||||
|
|
||||||
OPENAI_API_BASE_URLS = await getOpenAIUrls(localStorage.token);
|
OPENAI_API_BASE_URLS = await getOpenAIUrls(localStorage.token);
|
||||||
OPENAI_API_KEYS = await getOpenAIKeys(localStorage.token);
|
OPENAI_API_KEYS = await getOpenAIKeys(localStorage.token);
|
||||||
@ -161,95 +171,108 @@
|
|||||||
|
|
||||||
<hr class=" dark:border-gray-700" />
|
<hr class=" dark:border-gray-700" />
|
||||||
|
|
||||||
<div>
|
<div class="pr-1.5 space-y-2">
|
||||||
<div class=" mb-2.5 text-sm font-medium">{$i18n.t('Ollama Base URL')}</div>
|
<div class="flex justify-between items-center text-sm">
|
||||||
<div class="flex w-full gap-1.5">
|
<div class=" font-medium">{$i18n.t('Ollama API')}</div>
|
||||||
<div class="flex-1 flex flex-col gap-2">
|
|
||||||
{#each OLLAMA_BASE_URLS as url, idx}
|
|
||||||
<div class="flex gap-1.5">
|
|
||||||
<input
|
|
||||||
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
|
||||||
placeholder={$i18n.t('Enter URL (e.g. http://localhost:11434)')}
|
|
||||||
bind:value={url}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="self-center flex items-center">
|
<div class="mt-1">
|
||||||
{#if idx === 0}
|
<Switch
|
||||||
<button
|
bind:state={ENABLE_OLLAMA_API}
|
||||||
class="px-1"
|
on:change={async () => {
|
||||||
on:click={() => {
|
updateOllamaConfig(localStorage.token, ENABLE_OLLAMA_API);
|
||||||
OLLAMA_BASE_URLS = [...OLLAMA_BASE_URLS, ''];
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
{:else}
|
|
||||||
<button
|
|
||||||
class="px-1"
|
|
||||||
on:click={() => {
|
|
||||||
OLLAMA_BASE_URLS = OLLAMA_BASE_URLS.filter((url, urlIdx) => idx !== urlIdx);
|
|
||||||
}}
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 16 16"
|
|
||||||
fill="currentColor"
|
|
||||||
class="w-4 h-4"
|
|
||||||
>
|
|
||||||
<path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="">
|
|
||||||
<button
|
|
||||||
class="p-2.5 bg-gray-200 hover:bg-gray-300 dark:bg-gray-850 dark:hover:bg-gray-800 rounded-lg transition"
|
|
||||||
on:click={() => {
|
|
||||||
updateOllamaUrlsHandler();
|
|
||||||
}}
|
}}
|
||||||
type="button"
|
/>
|
||||||
>
|
|
||||||
<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="M15.312 11.424a5.5 5.5 0 01-9.201 2.466l-.312-.311h2.433a.75.75 0 000-1.5H3.989a.75.75 0 00-.75.75v4.242a.75.75 0 001.5 0v-2.43l.31.31a7 7 0 0011.712-3.138.75.75 0 00-1.449-.39zm1.23-3.723a.75.75 0 00.219-.53V2.929a.75.75 0 00-1.5 0V5.36l-.31-.31A7 7 0 003.239 8.188a.75.75 0 101.448.389A5.5 5.5 0 0113.89 6.11l.311.31h-2.432a.75.75 0 000 1.5h4.243a.75.75 0 00.53-.219z"
|
|
||||||
clip-rule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{#if ENABLE_OLLAMA_API}
|
||||||
|
<div class="flex w-full gap-1.5">
|
||||||
|
<div class="flex-1 flex flex-col gap-2">
|
||||||
|
{#each OLLAMA_BASE_URLS as url, idx}
|
||||||
|
<div class="flex gap-1.5">
|
||||||
|
<input
|
||||||
|
class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"
|
||||||
|
placeholder={$i18n.t('Enter URL (e.g. http://localhost:11434)')}
|
||||||
|
bind:value={url}
|
||||||
|
/>
|
||||||
|
|
||||||
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
|
<div class="self-center flex items-center">
|
||||||
{$i18n.t('Trouble accessing Ollama?')}
|
{#if idx === 0}
|
||||||
<a
|
<button
|
||||||
class=" text-gray-300 font-medium underline"
|
class="px-1"
|
||||||
href="https://github.com/open-webui/open-webui#troubleshooting"
|
on:click={() => {
|
||||||
target="_blank"
|
OLLAMA_BASE_URLS = [...OLLAMA_BASE_URLS, ''];
|
||||||
>
|
}}
|
||||||
{$i18n.t('Click here for help.')}
|
type="button"
|
||||||
</a>
|
>
|
||||||
</div>
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8.75 3.75a.75.75 0 0 0-1.5 0v3.5h-3.5a.75.75 0 0 0 0 1.5h3.5v3.5a.75.75 0 0 0 1.5 0v-3.5h3.5a.75.75 0 0 0 0-1.5h-3.5v-3.5Z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button
|
||||||
|
class="px-1"
|
||||||
|
on:click={() => {
|
||||||
|
OLLAMA_BASE_URLS = OLLAMA_BASE_URLS.filter((url, urlIdx) => idx !== urlIdx);
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="currentColor"
|
||||||
|
class="w-4 h-4"
|
||||||
|
>
|
||||||
|
<path d="M3.75 7.25a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex">
|
||||||
|
<button
|
||||||
|
class="self-center p-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-900 dark:hover:bg-gray-850 rounded-lg transition"
|
||||||
|
on:click={() => {
|
||||||
|
updateOllamaUrlsHandler();
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<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="M15.312 11.424a5.5 5.5 0 01-9.201 2.466l-.312-.311h2.433a.75.75 0 000-1.5H3.989a.75.75 0 00-.75.75v4.242a.75.75 0 001.5 0v-2.43l.31.31a7 7 0 0011.712-3.138.75.75 0 00-1.449-.39zm1.23-3.723a.75.75 0 00.219-.53V2.929a.75.75 0 00-1.5 0V5.36l-.31-.31A7 7 0 003.239 8.188a.75.75 0 101.448.389A5.5 5.5 0 0113.89 6.11l.311.31h-2.432a.75.75 0 000 1.5h4.243a.75.75 0 00.53-.219z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2 text-xs text-gray-400 dark:text-gray-500">
|
||||||
|
{$i18n.t('Trouble accessing Ollama?')}
|
||||||
|
<a
|
||||||
|
class=" text-gray-300 font-medium underline"
|
||||||
|
href="https://github.com/open-webui/open-webui#troubleshooting"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
{$i18n.t('Click here for help.')}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user