Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
chenpangpang
open-webui
Commits
110ed674
Commit
110ed674
authored
May 24, 2024
by
Timothy J. Baek
Browse files
feat: unified /models endpoint
parent
4d57e08b
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
166 additions
and
170 deletions
+166
-170
backend/apps/litellm/main.py
backend/apps/litellm/main.py
+0
-8
backend/apps/ollama/main.py
backend/apps/ollama/main.py
+0
-11
backend/apps/openai/main.py
backend/apps/openai/main.py
+7
-12
backend/main.py
backend/main.py
+78
-5
src/lib/apis/index.ts
src/lib/apis/index.ts
+28
-0
src/lib/components/chat/MessageInput/Models.svelte
src/lib/components/chat/MessageInput/Models.svelte
+3
-5
src/lib/components/workspace/Models.svelte
src/lib/components/workspace/Models.svelte
+34
-79
src/lib/constants.ts
src/lib/constants.ts
+1
-1
src/lib/utils/index.ts
src/lib/utils/index.ts
+7
-17
src/routes/(app)/+layout.svelte
src/routes/(app)/+layout.svelte
+0
-24
src/routes/(app)/workspace/+layout.svelte
src/routes/(app)/workspace/+layout.svelte
+2
-2
src/routes/(app)/workspace/+page.svelte
src/routes/(app)/workspace/+page.svelte
+1
-1
src/routes/(app)/workspace/modelfiles/+page.svelte
src/routes/(app)/workspace/modelfiles/+page.svelte
+0
-5
src/routes/(app)/workspace/models/+page.svelte
src/routes/(app)/workspace/models/+page.svelte
+5
-0
src/routes/(app)/workspace/models/create/+page.svelte
src/routes/(app)/workspace/models/create/+page.svelte
+0
-0
src/routes/(app)/workspace/models/edit/+page.svelte
src/routes/(app)/workspace/models/edit/+page.svelte
+0
-0
No files found.
backend/apps/litellm/main.py
View file @
110ed674
...
@@ -242,8 +242,6 @@ async def get_models(user=Depends(get_current_user)):
...
@@ -242,8 +242,6 @@ async def get_models(user=Depends(get_current_user)):
)
)
)
)
for
model
in
data
[
"data"
]:
add_custom_info_to_model
(
model
)
return
data
return
data
except
Exception
as
e
:
except
Exception
as
e
:
...
@@ -284,12 +282,6 @@ async def get_models(user=Depends(get_current_user)):
...
@@ -284,12 +282,6 @@ async def get_models(user=Depends(get_current_user)):
}
}
def
add_custom_info_to_model
(
model
:
dict
):
model
[
"custom_info"
]
=
next
(
(
item
for
item
in
app
.
state
.
MODEL_CONFIG
if
item
.
id
==
model
[
"id"
]),
None
)
@
app
.
get
(
"/model/info"
)
@
app
.
get
(
"/model/info"
)
async
def
get_model_list
(
user
=
Depends
(
get_admin_user
)):
async
def
get_model_list
(
user
=
Depends
(
get_admin_user
)):
return
{
"data"
:
app
.
state
.
CONFIG
[
"model_list"
]}
return
{
"data"
:
app
.
state
.
CONFIG
[
"model_list"
]}
...
...
backend/apps/ollama/main.py
View file @
110ed674
...
@@ -67,8 +67,6 @@ app.state.config = AppConfig()
...
@@ -67,8 +67,6 @@ 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
.
MODEL_CONFIG
=
Models
.
get_all_models
()
app
.
state
.
config
.
ENABLE_OLLAMA_API
=
ENABLE_OLLAMA_API
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
...
@@ -192,21 +190,12 @@ async def get_all_models():
...
@@ -192,21 +190,12 @@ async def get_all_models():
else
:
else
:
models
=
{
"models"
:
[]}
models
=
{
"models"
:
[]}
for
model
in
models
[
"models"
]:
add_custom_info_to_model
(
model
)
app
.
state
.
MODELS
=
{
model
[
"model"
]:
model
for
model
in
models
[
"models"
]}
app
.
state
.
MODELS
=
{
model
[
"model"
]:
model
for
model
in
models
[
"models"
]}
return
models
return
models
def
add_custom_info_to_model
(
model
:
dict
):
model
[
"custom_info"
]
=
next
(
(
item
for
item
in
app
.
state
.
MODEL_CONFIG
if
item
.
id
==
model
[
"model"
]),
None
)
@
app
.
get
(
"/api/tags"
)
@
app
.
get
(
"/api/tags"
)
@
app
.
get
(
"/api/tags/{url_idx}"
)
@
app
.
get
(
"/api/tags/{url_idx}"
)
async
def
get_ollama_tags
(
async
def
get_ollama_tags
(
...
...
backend/apps/openai/main.py
View file @
110ed674
...
@@ -52,8 +52,6 @@ app.state.config = AppConfig()
...
@@ -52,8 +52,6 @@ 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
.
MODEL_CONFIG
=
Models
.
get_all_models
()
app
.
state
.
config
.
ENABLE_OPENAI_API
=
ENABLE_OPENAI_API
app
.
state
.
config
.
ENABLE_OPENAI_API
=
ENABLE_OPENAI_API
app
.
state
.
config
.
OPENAI_API_BASE_URLS
=
OPENAI_API_BASE_URLS
app
.
state
.
config
.
OPENAI_API_BASE_URLS
=
OPENAI_API_BASE_URLS
...
@@ -207,7 +205,13 @@ def merge_models_lists(model_lists):
...
@@ -207,7 +205,13 @@ def merge_models_lists(model_lists):
if
models
is
not
None
and
"error"
not
in
models
:
if
models
is
not
None
and
"error"
not
in
models
:
merged_list
.
extend
(
merged_list
.
extend
(
[
[
{
**
model
,
"urlIdx"
:
idx
}
{
**
model
,
"name"
:
model
[
"id"
],
"owned_by"
:
"openai"
,
"openai"
:
model
,
"urlIdx"
:
idx
,
}
for
model
in
models
for
model
in
models
if
"api.openai.com"
if
"api.openai.com"
not
in
app
.
state
.
config
.
OPENAI_API_BASE_URLS
[
idx
]
not
in
app
.
state
.
config
.
OPENAI_API_BASE_URLS
[
idx
]
...
@@ -250,21 +254,12 @@ async def get_all_models():
...
@@ -250,21 +254,12 @@ async def get_all_models():
)
)
}
}
for
model
in
models
[
"data"
]:
add_custom_info_to_model
(
model
)
log
.
info
(
f
"models:
{
models
}
"
)
log
.
info
(
f
"models:
{
models
}
"
)
app
.
state
.
MODELS
=
{
model
[
"id"
]:
model
for
model
in
models
[
"data"
]}
app
.
state
.
MODELS
=
{
model
[
"id"
]:
model
for
model
in
models
[
"data"
]}
return
models
return
models
def
add_custom_info_to_model
(
model
:
dict
):
model
[
"custom_info"
]
=
next
(
(
item
for
item
in
app
.
state
.
MODEL_CONFIG
if
item
.
id
==
model
[
"id"
]),
None
)
@
app
.
get
(
"/models"
)
@
app
.
get
(
"/models"
)
@
app
.
get
(
"/models/{url_idx}"
)
@
app
.
get
(
"/models/{url_idx}"
)
async
def
get_models
(
url_idx
:
Optional
[
int
]
=
None
,
user
=
Depends
(
get_current_user
)):
async
def
get_models
(
url_idx
:
Optional
[
int
]
=
None
,
user
=
Depends
(
get_current_user
)):
...
...
backend/main.py
View file @
110ed674
...
@@ -19,8 +19,8 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
...
@@ -19,8 +19,8 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
from
starlette.middleware.base
import
BaseHTTPMiddleware
from
starlette.middleware.base
import
BaseHTTPMiddleware
from
starlette.responses
import
StreamingResponse
,
Response
from
starlette.responses
import
StreamingResponse
,
Response
from
apps.ollama.main
import
app
as
ollama_app
from
apps.ollama.main
import
app
as
ollama_app
,
get_all_models
as
get_ollama_models
from
apps.openai.main
import
app
as
openai_app
from
apps.openai.main
import
app
as
openai_app
,
get_all_models
as
get_openai_models
from
apps.litellm.main
import
(
from
apps.litellm.main
import
(
app
as
litellm_app
,
app
as
litellm_app
,
...
@@ -39,7 +39,7 @@ from pydantic import BaseModel
...
@@ -39,7 +39,7 @@ from pydantic import BaseModel
from
typing
import
List
,
Optional
from
typing
import
List
,
Optional
from
apps.web.models.models
import
Models
,
ModelModel
from
apps.web.models.models
import
Models
,
ModelModel
from
utils.utils
import
get_admin_user
from
utils.utils
import
get_admin_user
,
get_verified_user
from
apps.rag.utils
import
rag_messages
from
apps.rag.utils
import
rag_messages
from
config
import
(
from
config
import
(
...
@@ -53,6 +53,8 @@ from config import (
...
@@ -53,6 +53,8 @@ from config import (
FRONTEND_BUILD_DIR
,
FRONTEND_BUILD_DIR
,
CACHE_DIR
,
CACHE_DIR
,
STATIC_DIR
,
STATIC_DIR
,
ENABLE_OPENAI_API
,
ENABLE_OLLAMA_API
,
ENABLE_LITELLM
,
ENABLE_LITELLM
,
ENABLE_MODEL_FILTER
,
ENABLE_MODEL_FILTER
,
MODEL_FILTER_LIST
,
MODEL_FILTER_LIST
,
...
@@ -110,10 +112,13 @@ app = FastAPI(
...
@@ -110,10 +112,13 @@ app = FastAPI(
)
)
app
.
state
.
config
=
AppConfig
()
app
.
state
.
config
=
AppConfig
()
app
.
state
.
config
.
ENABLE_OPENAI_API
=
ENABLE_OPENAI_API
app
.
state
.
config
.
ENABLE_OLLAMA_API
=
ENABLE_OLLAMA_API
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
.
MODEL_CONFIG
=
Models
.
get_all_models
()
app
.
state
.
config
.
WEBHOOK_URL
=
WEBHOOK_URL
app
.
state
.
config
.
WEBHOOK_URL
=
WEBHOOK_URL
...
@@ -249,9 +254,11 @@ async def update_embedding_function(request: Request, call_next):
...
@@ -249,9 +254,11 @@ async def update_embedding_function(request: Request, call_next):
return
response
return
response
# TODO: Deprecate LiteLLM
app
.
mount
(
"/litellm/api"
,
litellm_app
)
app
.
mount
(
"/litellm/api"
,
litellm_app
)
app
.
mount
(
"/ollama"
,
ollama_app
)
app
.
mount
(
"/ollama"
,
ollama_app
)
app
.
mount
(
"/openai
/api
"
,
openai_app
)
app
.
mount
(
"/openai"
,
openai_app
)
app
.
mount
(
"/images/api/v1"
,
images_app
)
app
.
mount
(
"/images/api/v1"
,
images_app
)
app
.
mount
(
"/audio/api/v1"
,
audio_app
)
app
.
mount
(
"/audio/api/v1"
,
audio_app
)
...
@@ -262,6 +269,72 @@ app.mount("/api/v1", webui_app)
...
@@ -262,6 +269,72 @@ app.mount("/api/v1", webui_app)
webui_app
.
state
.
EMBEDDING_FUNCTION
=
rag_app
.
state
.
EMBEDDING_FUNCTION
webui_app
.
state
.
EMBEDDING_FUNCTION
=
rag_app
.
state
.
EMBEDDING_FUNCTION
@
app
.
get
(
"/api/models"
)
async
def
get_models
(
user
=
Depends
(
get_verified_user
)):
openai_models
=
[]
ollama_models
=
[]
if
app
.
state
.
config
.
ENABLE_OPENAI_API
:
openai_models
=
await
get_openai_models
()
openai_app
.
state
.
MODELS
=
openai_models
openai_models
=
openai_models
[
"data"
]
if
app
.
state
.
config
.
ENABLE_OLLAMA_API
:
ollama_models
=
await
get_ollama_models
()
ollama_app
.
state
.
MODELS
=
ollama_models
print
(
ollama_models
)
ollama_models
=
[
{
"id"
:
model
[
"model"
],
"name"
:
model
[
"name"
],
"object"
:
"model"
,
"created"
:
int
(
time
.
time
()),
"owned_by"
:
"ollama"
,
"ollama"
:
model
,
}
for
model
in
ollama_models
[
"models"
]
]
print
(
"openai"
,
openai_models
)
print
(
"ollama"
,
ollama_models
)
models
=
openai_models
+
ollama_models
custom_models
=
Models
.
get_all_models
()
for
custom_model
in
custom_models
:
if
custom_model
.
base_model_id
==
None
:
for
model
in
models
:
if
custom_model
.
id
==
model
[
"id"
]:
model
[
"name"
]
=
custom_model
.
name
model
[
"info"
]
=
custom_model
.
model_dump
()
else
:
models
.
append
(
{
"id"
:
custom_model
.
id
,
"name"
:
custom_model
.
name
,
"object"
:
"model"
,
"created"
:
custom_model
.
created_at
,
"owned_by"
:
"user"
,
"info"
:
custom_model
.
model_dump
(),
}
)
if
app
.
state
.
config
.
ENABLE_MODEL_FILTER
:
if
user
.
role
==
"user"
:
models
=
list
(
filter
(
lambda
model
:
model
[
"id"
]
in
app
.
state
.
config
.
MODEL_FILTER_LIST
,
models
,
)
)
return
{
"data"
:
models
}
return
{
"data"
:
models
}
@
app
.
get
(
"/api/config"
)
@
app
.
get
(
"/api/config"
)
async
def
get_app_config
():
async
def
get_app_config
():
# Checking and Handling the Absence of 'ui' in CONFIG_DATA
# Checking and Handling the Absence of 'ui' in CONFIG_DATA
...
...
src/lib/apis/index.ts
View file @
110ed674
import
{
WEBUI_BASE_URL
}
from
'
$lib/constants
'
;
import
{
WEBUI_BASE_URL
}
from
'
$lib/constants
'
;
export
const
getModels
=
async
(
token
:
string
=
''
)
=>
{
let
error
=
null
;
const
res
=
await
fetch
(
`
${
WEBUI_BASE_URL
}
/api/models`
,
{
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
);
error
=
err
;
return
null
;
});
if
(
error
)
{
throw
error
;
}
return
res
?.
data
??
[];
};
export
const
getBackendConfig
=
async
()
=>
{
export
const
getBackendConfig
=
async
()
=>
{
let
error
=
null
;
let
error
=
null
;
...
...
src/lib/components/chat/MessageInput/Models.svelte
View file @
110ed674
...
@@ -21,10 +21,8 @@
...
@@ -21,10 +21,8 @@
let filteredModels = [];
let filteredModels = [];
$: filteredModels = $models
$: filteredModels = $models
.filter((p) =>
.filter((p) => p.name.includes(prompt.split(' ')?.at(0)?.substring(1) ?? ''))
(p.custom_info?.name ?? p.name).includes(prompt.split(' ')?.at(0)?.substring(1) ?? '')
.sort((a, b) => a.name.localeCompare(b.name));
)
.sort((a, b) => (a.custom_info?.name ?? a.name).localeCompare(b.custom_info?.name ?? b.name));
$: if (prompt) {
$: if (prompt) {
selectedIdx = 0;
selectedIdx = 0;
...
@@ -158,7 +156,7 @@
...
@@ -158,7 +156,7 @@
on:focus={() => {}}
on:focus={() => {}}
>
>
<div class=" font-medium text-black line-clamp-1">
<div class=" font-medium text-black line-clamp-1">
{
model.custom_info?.name ??
model.name}
{model.name}
</div>
</div>
<!-- <div class=" text-xs text-gray-600 line-clamp-1">
<!-- <div class=" text-xs text-gray-600 line-clamp-1">
...
...
src/lib/components/workspace/Model
file
s.svelte
→
src/lib/components/workspace/Models.svelte
View file @
110ed674
...
@@ -5,63 +5,53 @@
...
@@ -5,63 +5,53 @@
import { onMount, getContext } from 'svelte';
import { onMount, getContext } from 'svelte';
import { WEBUI_NAME, modelfiles, settings, user } from '$lib/stores';
import { WEBUI_NAME, modelfiles, models, settings, user } from '$lib/stores';
import { createModel, deleteModel } from '$lib/apis/ollama';
import { addNewModel, deleteModelById, getModels } from '$lib/apis/models';
import { addNewModel, deleteModelById, getModels } from '$lib/apis/models';
import { goto } from '$app/navigation';
import { goto } from '$app/navigation';
import { getAllModels } from '$lib/utils';
const i18n = getContext('i18n');
const i18n = getContext('i18n');
let localModelfiles = [];
let localModelfiles = [];
let importFiles;
let importFiles;
let modelfilesImportInputElement: HTMLInputElement;
let modelfilesImportInputElement: HTMLInputElement;
const deleteModelHandler = async (tagName) => {
let success = null;
success = await deleteModel(localStorage.token, tagName).catch((err) => {
const deleteModelHandler = async (id) => {
toast.error(err);
const res = await deleteModelById(localStorage.token, id);
return null;
});
if (
succes
s) {
if (
re
s) {
toast.success($i18n.t(`Deleted {{tagName}}`, {
tagName
}));
toast.success($i18n.t(`Deleted {{tagName}}`, {
id
}));
}
}
await models.set(await getAllModels(localStorage.token));
return success;
};
const deleteModelfile = async (tagName) => {
await deleteModelHandler(tagName);
await deleteModelById(localStorage.token, tagName);
await modelfiles.set(await getModels(localStorage.token));
};
};
const shareModel
fi
le = async (model
file
) => {
const shareModel
Hand
le
r
= async (model) => {
toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
toast.success($i18n.t('Redirecting you to OpenWebUI Community'));
const url = 'https://openwebui.com';
const url = 'https://openwebui.com';
const tab = await window.open(`${url}/model
file
s/create`, '_blank');
const tab = await window.open(`${url}/models/create`, '_blank');
window.addEventListener(
window.addEventListener(
'message',
'message',
(event) => {
(event) => {
if (event.origin !== url) return;
if (event.origin !== url) return;
if (event.data === 'loaded') {
if (event.data === 'loaded') {
tab.postMessage(JSON.stringify(model
file
), '*');
tab.postMessage(JSON.stringify(model), '*');
}
}
},
},
false
false
);
);
};
};
const
save
Model
file
s = async (model
file
s) => {
const
download
Models = async (models) => {
let blob = new Blob([JSON.stringify(model
file
s)], {
let blob = new Blob([JSON.stringify(models)], {
type: 'application/json'
type: 'application/json'
});
});
saveAs(blob, `model
file
s-export-${Date.now()}.json`);
saveAs(blob, `models-export-${Date.now()}.json`);
};
};
onMount(() => {
onMount(() => {
// Legacy code to sync localModelfiles with models
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
if (localModelfiles) {
if (localModelfiles) {
...
@@ -72,13 +62,13 @@
...
@@ -72,13 +62,13 @@
<svelte:head>
<svelte:head>
<title>
<title>
{$i18n.t('Model
file
s')} | {$WEBUI_NAME}
{$i18n.t('Models')} | {$WEBUI_NAME}
</title>
</title>
</svelte:head>
</svelte:head>
<div class=" text-lg font-semibold mb-3">{$i18n.t('Model
file
s')}</div>
<div class=" text-lg font-semibold mb-3">{$i18n.t('Models')}</div>
<a class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" href="/workspace/model
file
s/create">
<a class=" flex space-x-4 cursor-pointer w-full mb-2 px-3 py-2" href="/workspace/models/create">
<div class=" self-center w-10">
<div class=" self-center w-10">
<div
<div
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
class="w-full h-10 flex justify-center rounded-full bg-transparent dark:bg-gray-700 border border-dashed border-gray-200"
...
@@ -94,26 +84,26 @@
...
@@ -94,26 +84,26 @@
</div>
</div>
<div class=" self-center">
<div class=" self-center">
<div class=" font-bold">{$i18n.t('Create a model
file
')}</div>
<div class=" font-bold">{$i18n.t('Create a model')}</div>
<div class=" text-sm">{$i18n.t('Customize
Ollama
models for a specific purpose')}</div>
<div class=" text-sm">{$i18n.t('Customize models for a specific purpose')}</div>
</div>
</div>
</a>
</a>
<hr class=" dark:border-gray-850" />
<hr class=" dark:border-gray-850" />
<div class=" my-2 mb-5">
<div class=" my-2 mb-5">
{#each $model
file
s as model
file
}
{#each $models as model}
<div
<div
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
class=" flex space-x-4 cursor-pointer w-full px-3 py-2 dark:hover:bg-white/5 hover:bg-black/5 rounded-xl"
>
>
<a
<a
class=" flex flex-1 space-x-4 cursor-pointer w-full"
class=" flex flex-1 space-x-4 cursor-pointer w-full"
href={`/?models=${encodeURIComponent(model
file.tagName
)}`}
href={`/?models=${encodeURIComponent(model
.id
)}`}
>
>
<div class=" self-center w-10">
<div class=" self-center w-10">
<div class=" rounded-full bg-stone-700">
<div class=" rounded-full bg-stone-700">
<img
<img
src={modelfile
.
image
U
rl ?? '/
user
.png'}
src={model
?.meta?.pro
file
_
image
_u
rl ?? '/
favicon
.png'}
alt="modelfile profile"
alt="modelfile profile"
class=" rounded-full w-full h-auto object-cover"
class=" rounded-full w-full h-auto object-cover"
/>
/>
...
@@ -121,9 +111,9 @@
...
@@ -121,9 +111,9 @@
</div>
</div>
<div class=" flex-1 self-center">
<div class=" flex-1 self-center">
<div class=" font-bold capitalize">{model
file.titl
e}</div>
<div class=" font-bold capitalize">{model
.nam
e}</div>
<div class=" text-sm overflow-hidden text-ellipsis line-clamp-1">
<div class=" text-sm overflow-hidden text-ellipsis line-clamp-1">
{model
file.desc
}
{model
?.meta?.description ?? 'No description'
}
</div>
</div>
</div>
</div>
</a>
</a>
...
@@ -131,7 +121,7 @@
...
@@ -131,7 +121,7 @@
<a
<a
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
type="button"
href={`/workspace/model
file
s/edit?tag=${encodeURIComponent(model
file.tagName
)}`}
href={`/workspace/models/edit?tag=${encodeURIComponent(model
.id
)}`}
>
>
<svg
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
...
@@ -153,9 +143,8 @@
...
@@ -153,9 +143,8 @@
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
type="button"
on:click={() => {
on:click={() => {
// console.log(modelfile);
sessionStorage.model = JSON.stringify(model);
sessionStorage.modelfile = JSON.stringify(modelfile);
goto('/workspace/models/create');
goto('/workspace/modelfiles/create');
}}
}}
>
>
<svg
<svg
...
@@ -178,7 +167,7 @@
...
@@ -178,7 +167,7 @@
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
type="button"
on:click={() => {
on:click={() => {
shareModel
fi
le(model
file
);
shareModel
Hand
le
r
(model);
}}
}}
>
>
<svg
<svg
...
@@ -201,7 +190,7 @@
...
@@ -201,7 +190,7 @@
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
class="self-center w-fit text-sm px-2 py-2 dark:text-gray-300 dark:hover:text-white hover:bg-black/5 dark:hover:bg-white/5 rounded-xl"
type="button"
type="button"
on:click={() => {
on:click={() => {
deleteModel
fi
le(model
file.tagName
);
deleteModel
Hand
le
r
(model
.id
);
}}
}}
>
>
<svg
<svg
...
@@ -260,7 +249,7 @@
...
@@ -260,7 +249,7 @@
modelfilesImportInputElement.click();
modelfilesImportInputElement.click();
}}
}}
>
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Model
file
s')}</div>
<div class=" self-center mr-2 font-medium">{$i18n.t('Import Models')}</div>
<div class=" self-center">
<div class=" self-center">
<svg
<svg
...
@@ -281,10 +270,10 @@
...
@@ -281,10 +270,10 @@
<button
<button
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
class="flex text-xs items-center space-x-1 px-3 py-1.5 rounded-xl bg-gray-50 hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700 dark:text-gray-200 transition"
on:click={async () => {
on:click={async () => {
save
Model
file
s($model
file
s);
download
Models($models);
}}
}}
>
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Model
file
s')}</div>
<div class=" self-center mr-2 font-medium">{$i18n.t('Export Models')}</div>
<div class=" self-center">
<div class=" self-center">
<svg
<svg
...
@@ -310,47 +299,13 @@
...
@@ -310,47 +299,13 @@
</div>
</div>
<div class="flex space-x-1">
<div class="flex space-x-1">
<button
class="self-center w-fit text-sm px-3 py-1 border dark:border-gray-600 rounded-xl flex"
on:click={async () => {
for (const modelfile of localModelfiles) {
await addNewModel(localStorage.token, modelfile).catch((error) => {
return null;
});
}
saveModelfiles(localModelfiles);
localStorage.removeItem('modelfiles');
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
await modelfiles.set(await getModels(localStorage.token));
}}
>
<div class=" self-center mr-2 font-medium">{$i18n.t('Sync All')}</div>
<div class=" self-center">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
fill="currentColor"
class="w-3.5 h-3.5"
>
<path
fill-rule="evenodd"
d="M13.836 2.477a.75.75 0 0 1 .75.75v3.182a.75.75 0 0 1-.75.75h-3.182a.75.75 0 0 1 0-1.5h1.37l-.84-.841a4.5 4.5 0 0 0-7.08.932.75.75 0 0 1-1.3-.75 6 6 0 0 1 9.44-1.242l.842.84V3.227a.75.75 0 0 1 .75-.75Zm-.911 7.5A.75.75 0 0 1 13.199 11a6 6 0 0 1-9.44 1.241l-.84-.84v1.371a.75.75 0 0 1-1.5 0V9.591a.75.75 0 0 1 .75-.75H5.35a.75.75 0 0 1 0 1.5H3.98l.841.841a4.5 4.5 0 0 0 7.08-.932.75.75 0 0 1 1.025-.273Z"
clip-rule="evenodd"
/>
</svg>
</div>
</button>
<button
<button
class="self-center w-fit text-sm p-1.5 border dark:border-gray-600 rounded-xl flex"
class="self-center w-fit text-sm p-1.5 border dark:border-gray-600 rounded-xl flex"
on:click={async () => {
on:click={async () => {
save
Model
file
s(localModelfiles);
download
Models(localModelfiles);
localStorage.removeItem('modelfiles');
localStorage.removeItem('modelfiles');
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
localModelfiles = JSON.parse(localStorage.getItem('modelfiles') ?? '[]');
await modelfiles.set(await getModels(localStorage.token));
}}
}}
>
>
<div class=" self-center">
<div class=" self-center">
...
@@ -398,7 +353,7 @@
...
@@ -398,7 +353,7 @@
</div>
</div>
<div class=" self-center">
<div class=" self-center">
<div class=" font-bold">{$i18n.t('Discover a model
file
')}</div>
<div class=" font-bold">{$i18n.t('Discover a model')}</div>
<div class=" text-sm">{$i18n.t('Discover, download, and explore model presets')}</div>
<div class=" text-sm">{$i18n.t('Discover, download, and explore model presets')}</div>
</div>
</div>
</a>
</a>
...
...
src/lib/constants.ts
View file @
110ed674
...
@@ -8,7 +8,7 @@ export const WEBUI_API_BASE_URL = `${WEBUI_BASE_URL}/api/v1`;
...
@@ -8,7 +8,7 @@ export const WEBUI_API_BASE_URL = `${WEBUI_BASE_URL}/api/v1`;
export
const
LITELLM_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/litellm/api`
;
export
const
LITELLM_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/litellm/api`
;
export
const
OLLAMA_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/ollama`
;
export
const
OLLAMA_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/ollama`
;
export
const
OPENAI_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/openai
/api
`
;
export
const
OPENAI_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/openai`
;
export
const
AUDIO_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/audio/api/v1`
;
export
const
AUDIO_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/audio/api/v1`
;
export
const
IMAGES_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/images/api/v1`
;
export
const
IMAGES_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/images/api/v1`
;
export
const
RAG_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/rag/api/v1`
;
export
const
RAG_API_BASE_URL
=
`
${
WEBUI_BASE_URL
}
/rag/api/v1`
;
...
...
src/lib/utils/index.ts
View file @
110ed674
import
{
v4
as
uuidv4
}
from
'
uuid
'
;
import
{
v4
as
uuidv4
}
from
'
uuid
'
;
import
sha256
from
'
js-sha256
'
;
import
sha256
from
'
js-sha256
'
;
import
{
getOllamaModels
}
from
'
$lib/apis/ollama
'
;
import
{
getOpenAIModels
}
from
'
$lib/apis/openai
'
;
import
{
getModels
}
from
'
$lib/apis
'
;
import
{
getLiteLLMModels
}
from
'
$lib/apis/litellm
'
;
export
const
getAllModels
=
async
(
token
:
string
)
=>
{
export
const
getAllModels
=
async
(
token
:
string
)
=>
{
let
models
=
await
Promise
.
all
([
let
models
=
await
getModels
(
token
).
catch
((
error
)
=>
{
getOllamaModels
(
token
).
catch
((
error
)
=>
{
console
.
log
(
error
);
console
.
log
(
error
);
return
null
;
return
null
;
});
}),
getOpenAIModels
(
token
).
catch
((
error
)
=>
{
console
.
log
(
error
);
return
null
;
}),
getLiteLLMModels
(
token
).
catch
((
error
)
=>
{
console
.
log
(
error
);
return
null
;
})
]);
models
=
models
.
filter
((
models
)
=>
models
).
reduce
((
a
,
e
,
i
,
arr
)
=>
a
.
concat
(
e
),
[]);
models
=
models
.
filter
((
models
)
=>
models
).
reduce
((
a
,
e
,
i
,
arr
)
=>
a
.
concat
(
e
),
[]);
console
.
log
(
models
);
return
models
;
return
models
;
};
};
...
...
src/routes/(app)/+layout.svelte
View file @
110ed674
...
@@ -9,7 +9,6 @@
...
@@ -9,7 +9,6 @@
import { getAllModels as _getAllModels } from '$lib/utils';
import { getAllModels as _getAllModels } from '$lib/utils';
import { getOllamaVersion } from '$lib/apis/ollama';
import { getOllamaVersion } from '$lib/apis/ollama';
import { getModels } from '$lib/apis/models';
import { getPrompts } from '$lib/apis/prompts';
import { getPrompts } from '$lib/apis/prompts';
import { getDocs } from '$lib/apis/documents';
import { getDocs } from '$lib/apis/documents';
...
@@ -50,21 +49,6 @@
...
@@ -50,21 +49,6 @@
return _getAllModels(localStorage.token);
return _getAllModels(localStorage.token);
};
};
const setOllamaVersion = async (version: string = '') => {
if (version === '') {
version = await getOllamaVersion(localStorage.token).catch((error) => {
return '';
});
}
ollamaVersion = version;
console.log(ollamaVersion);
if (compareVersion(REQUIRED_OLLAMA_VERSION, ollamaVersion)) {
toast.error(`Ollama Version: ${ollamaVersion !== '' ? ollamaVersion : 'Not Detected'}`);
}
};
onMount(async () => {
onMount(async () => {
if ($user === undefined) {
if ($user === undefined) {
await goto('/auth');
await goto('/auth');
...
@@ -93,9 +77,6 @@
...
@@ -93,9 +77,6 @@
(async () => {
(async () => {
models.set(await getAllModels());
models.set(await getAllModels());
})(),
})(),
(async () => {
modelfiles.set(await getModels(localStorage.token));
})(),
(async () => {
(async () => {
prompts.set(await getPrompts(localStorage.token));
prompts.set(await getPrompts(localStorage.token));
})(),
})(),
...
@@ -107,11 +88,6 @@
...
@@ -107,11 +88,6 @@
})()
})()
]);
]);
modelfiles.subscribe(async () => {
// should fetch models
models.set(await getAllModels());
});
document.addEventListener('keydown', function (event) {
document.addEventListener('keydown', function (event) {
const isCtrlPressed = event.ctrlKey || event.metaKey; // metaKey is for Cmd key on Mac
const isCtrlPressed = event.ctrlKey || event.metaKey; // metaKey is for Cmd key on Mac
// Check if the Shift key is pressed
// Check if the Shift key is pressed
...
...
src/routes/(app)/workspace/+layout.svelte
View file @
110ed674
...
@@ -39,10 +39,10 @@
...
@@ -39,10 +39,10 @@
class="flex scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium rounded-xl bg-transparent/10 p-1"
class="flex scrollbar-none overflow-x-auto w-fit text-center text-sm font-medium rounded-xl bg-transparent/10 p-1"
>
>
<a
<a
class="min-w-fit rounded-lg p-1.5 px-3 {$page.url.pathname.includes('/workspace/model
file
s')
class="min-w-fit rounded-lg p-1.5 px-3 {$page.url.pathname.includes('/workspace/models')
? 'bg-gray-50 dark:bg-gray-850'
? 'bg-gray-50 dark:bg-gray-850'
: ''} transition"
: ''} transition"
href="/workspace/model
file
s">{$i18n.t('Model
file
s')}</a
href="/workspace/models">{$i18n.t('Models')}</a
>
>
<a
<a
...
...
src/routes/(app)/workspace/+page.svelte
View file @
110ed674
...
@@ -3,6 +3,6 @@
...
@@ -3,6 +3,6 @@
import { onMount } from 'svelte';
import { onMount } from 'svelte';
onMount(() => {
onMount(() => {
goto('/workspace/model
file
s');
goto('/workspace/models');
});
});
</script>
</script>
src/routes/(app)/workspace/modelfiles/+page.svelte
deleted
100644 → 0
View file @
4d57e08b
<script>
import Modelfiles from '$lib/components/workspace/Modelfiles.svelte';
</script>
<Modelfiles />
src/routes/(app)/workspace/models/+page.svelte
0 → 100644
View file @
110ed674
<script>
import Models from '$lib/components/workspace/Models.svelte';
</script>
<Models />
src/routes/(app)/workspace/model
file
s/create/+page.svelte
→
src/routes/(app)/workspace/models/create/+page.svelte
View file @
110ed674
File moved
src/routes/(app)/workspace/model
file
s/edit/+page.svelte
→
src/routes/(app)/workspace/models/edit/+page.svelte
View file @
110ed674
File moved
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment