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
e76a444e
Commit
e76a444e
authored
May 09, 2024
by
Jun Siang Cheah
Browse files
feat: allow model config via config.json
parent
df3675aa
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
367 additions
and
122 deletions
+367
-122
backend/apps/litellm/main.py
backend/apps/litellm/main.py
+18
-1
backend/apps/ollama/main.py
backend/apps/ollama/main.py
+14
-1
backend/apps/openai/main.py
backend/apps/openai/main.py
+12
-1
backend/apps/web/routers/configs.py
backend/apps/web/routers/configs.py
+24
-0
backend/config.py
backend/config.py
+2
-0
backend/main.py
backend/main.py
+1
-0
src/lib/apis/litellm/index.ts
src/lib/apis/litellm/index.ts
+2
-1
src/lib/apis/openai/index.ts
src/lib/apis/openai/index.ts
+6
-1
src/lib/components/admin/Settings/Users.svelte
src/lib/components/admin/Settings/Users.svelte
+1
-1
src/lib/components/chat/MessageInput.svelte
src/lib/components/chat/MessageInput.svelte
+20
-6
src/lib/components/chat/MessageInput/Models.svelte
src/lib/components/chat/MessageInput/Models.svelte
+7
-3
src/lib/components/chat/Messages/ResponseMessage.svelte
src/lib/components/chat/Messages/ResponseMessage.svelte
+1
-1
src/lib/components/chat/ModelSelector.svelte
src/lib/components/chat/ModelSelector.svelte
+1
-1
src/lib/components/chat/ModelSelector/Selector.svelte
src/lib/components/chat/ModelSelector/Selector.svelte
+8
-2
src/lib/components/chat/Settings/Interface.svelte
src/lib/components/chat/Settings/Interface.svelte
+5
-2
src/lib/components/chat/Settings/Models.svelte
src/lib/components/chat/Settings/Models.svelte
+99
-12
src/lib/components/documents/Settings/General.svelte
src/lib/components/documents/Settings/General.svelte
+4
-1
src/lib/stores/index.ts
src/lib/stores/index.ts
+30
-9
src/routes/(app)/+page.svelte
src/routes/(app)/+page.svelte
+57
-40
src/routes/(app)/c/[id]/+page.svelte
src/routes/(app)/c/[id]/+page.svelte
+55
-39
No files found.
backend/apps/litellm/main.py
View file @
e76a444e
...
@@ -18,7 +18,7 @@ from pydantic import BaseModel, ConfigDict
...
@@ -18,7 +18,7 @@ from pydantic import BaseModel, ConfigDict
from
typing
import
Optional
,
List
from
typing
import
Optional
,
List
from
utils.utils
import
get_verified_user
,
get_current_user
,
get_admin_user
from
utils.utils
import
get_verified_user
,
get_current_user
,
get_admin_user
from
config
import
SRC_LOG_LEVELS
,
ENV
from
config
import
SRC_LOG_LEVELS
,
ENV
,
MODEL_CONFIG
from
constants
import
MESSAGES
from
constants
import
MESSAGES
import
os
import
os
...
@@ -67,6 +67,7 @@ with open(LITELLM_CONFIG_DIR, "r") as file:
...
@@ -67,6 +67,7 @@ with open(LITELLM_CONFIG_DIR, "r") as file:
app
.
state
.
ENABLE
=
ENABLE_LITELLM
app
.
state
.
ENABLE
=
ENABLE_LITELLM
app
.
state
.
CONFIG
=
litellm_config
app
.
state
.
CONFIG
=
litellm_config
app
.
state
.
MODEL_CONFIG
=
MODEL_CONFIG
.
get
(
"litellm"
,
[])
# Global variable to store the subprocess reference
# Global variable to store the subprocess reference
background_process
=
None
background_process
=
None
...
@@ -238,6 +239,8 @@ async def get_models(user=Depends(get_current_user)):
...
@@ -238,6 +239,8 @@ 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
:
...
@@ -258,6 +261,14 @@ async def get_models(user=Depends(get_current_user)):
...
@@ -258,6 +261,14 @@ async def get_models(user=Depends(get_current_user)):
"object"
:
"model"
,
"object"
:
"model"
,
"created"
:
int
(
time
.
time
()),
"created"
:
int
(
time
.
time
()),
"owned_by"
:
"openai"
,
"owned_by"
:
"openai"
,
"custom_info"
:
next
(
(
item
for
item
in
app
.
state
.
MODEL_CONFIG
if
item
[
"name"
]
==
model
[
"model_name"
]
),
{},
),
}
}
for
model
in
app
.
state
.
CONFIG
[
"model_list"
]
for
model
in
app
.
state
.
CONFIG
[
"model_list"
]
],
],
...
@@ -270,6 +281,12 @@ async def get_models(user=Depends(get_current_user)):
...
@@ -270,6 +281,12 @@ 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
[
"name"
]
==
model
[
"id"
]),
{}
)
@
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 @
e76a444e
...
@@ -46,6 +46,7 @@ from config import (
...
@@ -46,6 +46,7 @@ from config import (
ENABLE_MODEL_FILTER
,
ENABLE_MODEL_FILTER
,
MODEL_FILTER_LIST
,
MODEL_FILTER_LIST
,
UPLOAD_DIR
,
UPLOAD_DIR
,
MODEL_CONFIG
,
)
)
from
utils.misc
import
calculate_sha256
from
utils.misc
import
calculate_sha256
...
@@ -64,6 +65,7 @@ app.add_middleware(
...
@@ -64,6 +65,7 @@ app.add_middleware(
app
.
state
.
ENABLE_MODEL_FILTER
=
ENABLE_MODEL_FILTER
app
.
state
.
ENABLE_MODEL_FILTER
=
ENABLE_MODEL_FILTER
app
.
state
.
MODEL_FILTER_LIST
=
MODEL_FILTER_LIST
app
.
state
.
MODEL_FILTER_LIST
=
MODEL_FILTER_LIST
app
.
state
.
MODEL_CONFIG
=
MODEL_CONFIG
.
get
(
"ollama"
,
[])
app
.
state
.
OLLAMA_BASE_URLS
=
OLLAMA_BASE_URLS
app
.
state
.
OLLAMA_BASE_URLS
=
OLLAMA_BASE_URLS
app
.
state
.
MODELS
=
{}
app
.
state
.
MODELS
=
{}
...
@@ -158,15 +160,26 @@ async def get_all_models():
...
@@ -158,15 +160,26 @@ async def get_all_models():
models
=
{
models
=
{
"models"
:
merge_models_lists
(
"models"
:
merge_models_lists
(
map
(
lambda
response
:
response
[
"models"
]
if
response
else
None
,
responses
)
map
(
lambda
response
:
(
response
[
"models"
]
if
response
else
None
),
responses
,
)
)
)
}
}
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
[
"name"
]
==
model
[
"model"
]),
{}
)
@
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 @
e76a444e
...
@@ -26,6 +26,7 @@ from config import (
...
@@ -26,6 +26,7 @@ from config import (
CACHE_DIR
,
CACHE_DIR
,
ENABLE_MODEL_FILTER
,
ENABLE_MODEL_FILTER
,
MODEL_FILTER_LIST
,
MODEL_FILTER_LIST
,
MODEL_CONFIG
,
)
)
from
typing
import
List
,
Optional
from
typing
import
List
,
Optional
...
@@ -47,6 +48,7 @@ app.add_middleware(
...
@@ -47,6 +48,7 @@ app.add_middleware(
app
.
state
.
ENABLE_MODEL_FILTER
=
ENABLE_MODEL_FILTER
app
.
state
.
ENABLE_MODEL_FILTER
=
ENABLE_MODEL_FILTER
app
.
state
.
MODEL_FILTER_LIST
=
MODEL_FILTER_LIST
app
.
state
.
MODEL_FILTER_LIST
=
MODEL_FILTER_LIST
app
.
state
.
MODEL_CONFIG
=
MODEL_CONFIG
.
get
(
"openai"
,
[])
app
.
state
.
OPENAI_API_BASE_URLS
=
OPENAI_API_BASE_URLS
app
.
state
.
OPENAI_API_BASE_URLS
=
OPENAI_API_BASE_URLS
app
.
state
.
OPENAI_API_KEYS
=
OPENAI_API_KEYS
app
.
state
.
OPENAI_API_KEYS
=
OPENAI_API_KEYS
...
@@ -217,10 +219,19 @@ async def get_all_models():
...
@@ -217,10 +219,19 @@ 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
[
"name"
]
==
model
[
"id"
]),
{}
)
@
app
.
get
(
"/models"
)
@
app
.
get
(
"/models"
)
...
...
backend/apps/web/routers/configs.py
View file @
e76a444e
...
@@ -35,6 +35,19 @@ class SetDefaultSuggestionsForm(BaseModel):
...
@@ -35,6 +35,19 @@ class SetDefaultSuggestionsForm(BaseModel):
suggestions
:
List
[
PromptSuggestion
]
suggestions
:
List
[
PromptSuggestion
]
class
ModelConfig
(
BaseModel
):
id
:
str
name
:
str
description
:
str
vision_capable
:
bool
class
SetModelConfigForm
(
BaseModel
):
ollama
:
List
[
ModelConfig
]
litellm
:
List
[
ModelConfig
]
openai
:
List
[
ModelConfig
]
############################
############################
# SetDefaultModels
# SetDefaultModels
############################
############################
...
@@ -57,3 +70,14 @@ async def set_global_default_suggestions(
...
@@ -57,3 +70,14 @@ async def set_global_default_suggestions(
data
=
form_data
.
model_dump
()
data
=
form_data
.
model_dump
()
request
.
app
.
state
.
DEFAULT_PROMPT_SUGGESTIONS
=
data
[
"suggestions"
]
request
.
app
.
state
.
DEFAULT_PROMPT_SUGGESTIONS
=
data
[
"suggestions"
]
return
request
.
app
.
state
.
DEFAULT_PROMPT_SUGGESTIONS
return
request
.
app
.
state
.
DEFAULT_PROMPT_SUGGESTIONS
@
router
.
post
(
"/models"
,
response_model
=
SetModelConfigForm
)
async
def
set_global_default_suggestions
(
request
:
Request
,
form_data
:
SetModelConfigForm
,
user
=
Depends
(
get_admin_user
),
):
data
=
form_data
.
model_dump
()
request
.
app
.
state
.
MODEL_CONFIG
=
data
return
request
.
app
.
state
.
MODEL_CONFIG
backend/config.py
View file @
e76a444e
...
@@ -424,6 +424,8 @@ WEBHOOK_URL = os.environ.get("WEBHOOK_URL", "")
...
@@ -424,6 +424,8 @@ WEBHOOK_URL = os.environ.get("WEBHOOK_URL", "")
ENABLE_ADMIN_EXPORT
=
os
.
environ
.
get
(
"ENABLE_ADMIN_EXPORT"
,
"True"
).
lower
()
==
"true"
ENABLE_ADMIN_EXPORT
=
os
.
environ
.
get
(
"ENABLE_ADMIN_EXPORT"
,
"True"
).
lower
()
==
"true"
MODEL_CONFIG
=
CONFIG_DATA
.
get
(
"models"
,
{
"ollama"
:
[],
"litellm"
:
[],
"openai"
:
[]})
####################################
####################################
# WEBUI_SECRET_KEY
# WEBUI_SECRET_KEY
####################################
####################################
...
...
backend/main.py
View file @
e76a444e
...
@@ -58,6 +58,7 @@ from config import (
...
@@ -58,6 +58,7 @@ from config import (
SRC_LOG_LEVELS
,
SRC_LOG_LEVELS
,
WEBHOOK_URL
,
WEBHOOK_URL
,
ENABLE_ADMIN_EXPORT
,
ENABLE_ADMIN_EXPORT
,
MODEL_CONFIG
,
)
)
from
constants
import
ERROR_MESSAGES
from
constants
import
ERROR_MESSAGES
...
...
src/lib/apis/litellm/index.ts
View file @
e76a444e
...
@@ -33,7 +33,8 @@ export const getLiteLLMModels = async (token: string = '') => {
...
@@ -33,7 +33,8 @@ export const getLiteLLMModels = async (token: string = '') => {
id
:
model
.
id
,
id
:
model
.
id
,
name
:
model
.
name
??
model
.
id
,
name
:
model
.
name
??
model
.
id
,
external
:
true
,
external
:
true
,
source
:
'
LiteLLM
'
source
:
'
LiteLLM
'
,
custom_info
:
model
.
custom_info
??
{}
}))
}))
.
sort
((
a
,
b
)
=>
{
.
sort
((
a
,
b
)
=>
{
return
a
.
name
.
localeCompare
(
b
.
name
);
return
a
.
name
.
localeCompare
(
b
.
name
);
...
...
src/lib/apis/openai/index.ts
View file @
e76a444e
...
@@ -163,7 +163,12 @@ export const getOpenAIModels = async (token: string = '') => {
...
@@ -163,7 +163,12 @@ export const getOpenAIModels = async (token: string = '') => {
return
models
return
models
?
models
?
models
.
map
((
model
)
=>
({
id
:
model
.
id
,
name
:
model
.
name
??
model
.
id
,
external
:
true
}))
.
map
((
model
)
=>
({
id
:
model
.
id
,
name
:
model
.
name
??
model
.
id
,
external
:
true
,
custom_info
:
model
.
custom_info
??
{}
}))
.
sort
((
a
,
b
)
=>
{
.
sort
((
a
,
b
)
=>
{
return
a
.
name
.
localeCompare
(
b
.
name
);
return
a
.
name
.
localeCompare
(
b
.
name
);
})
})
...
...
src/lib/components/admin/Settings/Users.svelte
View file @
e76a444e
...
@@ -125,7 +125,7 @@
...
@@ -125,7 +125,7 @@
<option value="" disabled selected>{$i18n.t('Select a model')}</option>
<option value="" disabled selected>{$i18n.t('Select a model')}</option>
{#each $models.filter((model) => model.id) as model}
{#each $models.filter((model) => model.id) as model}
<option value={model.id} class="bg-gray-100 dark:bg-gray-700"
<option value={model.id} class="bg-gray-100 dark:bg-gray-700"
>{model.name}</option
>{
model.custom_info?.displayName ??
model.name}</option
>
>
{/each}
{/each}
</select>
</select>
...
...
src/lib/components/chat/MessageInput.svelte
View file @
e76a444e
<script lang="ts">
<script lang="ts">
import { toast } from 'svelte-sonner';
import { toast } from 'svelte-sonner';
import { onMount, tick, getContext } from 'svelte';
import { onMount, tick, getContext } from 'svelte';
import { modelfiles, settings, showSidebar } from '$lib/stores';
import {
type Model,
modelfiles, settings, showSidebar } from '$lib/stores';
import { blobToFile, calculateSHA256, findWordIndices } from '$lib/utils';
import { blobToFile, calculateSHA256, findWordIndices } from '$lib/utils';
import {
import {
...
@@ -27,7 +27,7 @@
...
@@ -27,7 +27,7 @@
export let stopResponse: Function;
export let stopResponse: Function;
export let autoScroll = true;
export let autoScroll = true;
export let selectedModel
= ''
;
export let selectedModel
: Model | undefined
;
let chatTextAreaElement: HTMLTextAreaElement;
let chatTextAreaElement: HTMLTextAreaElement;
let filesInputElement;
let filesInputElement;
...
@@ -359,6 +359,12 @@
...
@@ -359,6 +359,12 @@
inputFiles.forEach((file) => {
inputFiles.forEach((file) => {
console.log(file, file.name.split('.').at(-1));
console.log(file, file.name.split('.').at(-1));
if (['image/gif', 'image/jpeg', 'image/png'].includes(file['type'])) {
if (['image/gif', 'image/jpeg', 'image/png'].includes(file['type'])) {
if (selectedModel !== undefined) {
if (!(selectedModel.custom_info?.vision_capable ?? true)) {
toast.error($i18n.t('Selected model does not support image inputs.'));
return;
}
}
let reader = new FileReader();
let reader = new FileReader();
reader.onload = (event) => {
reader.onload = (event) => {
files = [
files = [
...
@@ -500,7 +506,7 @@
...
@@ -500,7 +506,7 @@
}}
}}
/>
/>
{#if selectedModel !==
''
}
{#if selectedModel !==
undefined
}
<div
<div
class="px-3 py-2.5 text-left w-full flex justify-between items-center absolute bottom-0 left-0 right-0 bg-gradient-to-t from-50% from-white dark:from-gray-900"
class="px-3 py-2.5 text-left w-full flex justify-between items-center absolute bottom-0 left-0 right-0 bg-gradient-to-t from-50% from-white dark:from-gray-900"
>
>
...
@@ -515,14 +521,16 @@
...
@@ -515,14 +521,16 @@
: `${WEBUI_BASE_URL}/static/favicon.png`)}
: `${WEBUI_BASE_URL}/static/favicon.png`)}
/>
/>
<div>
<div>
Talking to <span class=" font-medium">{selectedModel.name} </span>
Talking to <span class=" font-medium"
>{selectedModel.custom_info?.displayName ?? selectedModel.name}
</span>
</div>
</div>
</div>
</div>
<div>
<div>
<button
<button
class="flex items-center"
class="flex items-center"
on:click={() => {
on:click={() => {
selectedModel =
''
;
selectedModel =
undefined
;
}}
}}
>
>
<XMark />
<XMark />
...
@@ -548,6 +556,12 @@
...
@@ -548,6 +556,12 @@
const _inputFiles = Array.from(inputFiles);
const _inputFiles = Array.from(inputFiles);
_inputFiles.forEach((file) => {
_inputFiles.forEach((file) => {
if (['image/gif', 'image/jpeg', 'image/png'].includes(file['type'])) {
if (['image/gif', 'image/jpeg', 'image/png'].includes(file['type'])) {
if (selectedModel !== undefined) {
if (!(selectedModel.custom_info?.vision_capable ?? true)) {
toast.error($i18n.t('Selected model does not support image inputs.'));
return;
}
}
let reader = new FileReader();
let reader = new FileReader();
reader.onload = (event) => {
reader.onload = (event) => {
files = [
files = [
...
@@ -880,7 +894,7 @@
...
@@ -880,7 +894,7 @@
if (e.key === 'Escape') {
if (e.key === 'Escape') {
console.log('Escape');
console.log('Escape');
selectedModel =
''
;
selectedModel =
undefined
;
}
}
}}
}}
rows="1"
rows="1"
...
...
src/lib/components/chat/MessageInput/Models.svelte
View file @
e76a444e
...
@@ -21,8 +21,12 @@
...
@@ -21,8 +21,12 @@
let filteredModels = [];
let filteredModels = [];
$: filteredModels = $models
$: filteredModels = $models
.filter((p) => p.name.includes(prompt.split(' ')?.at(0)?.substring(1) ?? ''))
.filter((p) =>
.sort((a, b) => a.name.localeCompare(b.name));
(p.custom_info?.displayName ?? p.name).includes(prompt.split(' ')?.at(0)?.substring(1) ?? '')
)
.sort((a, b) =>
(a.custom_info?.displayName ?? a.name).localeCompare(b.custom_info?.displayName ?? b.name)
);
$: if (prompt) {
$: if (prompt) {
selectedIdx = 0;
selectedIdx = 0;
...
@@ -156,7 +160,7 @@
...
@@ -156,7 +160,7 @@
on:focus={() => {}}
on:focus={() => {}}
>
>
<div class=" font-medium text-black line-clamp-1">
<div class=" font-medium text-black line-clamp-1">
{model.name}
{
model.custom_info?.displayName ??
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/chat/Messages/ResponseMessage.svelte
View file @
e76a444e
...
@@ -343,7 +343,7 @@
...
@@ -343,7 +343,7 @@
{#if message.model in modelfiles}
{#if message.model in modelfiles}
{modelfiles[message.model]?.title}
{modelfiles[message.model]?.title}
{:else}
{:else}
{message.model ? ` ${message.model}` : ''}
{
message.modelName ? ` ${message.modelName}` :
message.model ? ` ${message.model}` : ''}
{/if}
{/if}
{#if message.timestamp}
{#if message.timestamp}
...
...
src/lib/components/chat/ModelSelector.svelte
View file @
e76a444e
...
@@ -49,7 +49,7 @@
...
@@ -49,7 +49,7 @@
.filter((model) => model.name !== 'hr')
.filter((model) => model.name !== 'hr')
.map((model) => ({
.map((model) => ({
value: model.id,
value: model.id,
label: model.name,
label:
model.custom_info?.displayName ??
model.name,
info: model
info: model
}))}
}))}
bind:value={selectedModel}
bind:value={selectedModel}
...
...
src/lib/components/chat/ModelSelector/Selector.svelte
View file @
e76a444e
...
@@ -247,7 +247,11 @@
...
@@ -247,7 +247,11 @@
<!-- {JSON.stringify(item.info)} -->
<!-- {JSON.stringify(item.info)} -->
{#if item.info.external}
{#if item.info.external}
<Tooltip content={item.info?.source ?? 'External'}>
<Tooltip
content={`${item.info?.source ?? 'External'}${
item.info.custom_info?.description ? '<br>' : ''
}${item.info.custom_info?.description?.replaceAll('\n', '<br>') ?? ''}`}
>
<div class=" mr-2">
<div class=" mr-2">
<svg
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
...
@@ -274,7 +278,9 @@
...
@@ -274,7 +278,9 @@
item.info?.details?.quantization_level
item.info?.details?.quantization_level
? item.info?.details?.quantization_level + ' '
? item.info?.details?.quantization_level + ' '
: ''
: ''
}${item.info.size ? `(${(item.info.size / 1024 ** 3).toFixed(1)}GB)` : ''}`}
}${item.info.size ? `(${(item.info.size / 1024 ** 3).toFixed(1)}GB)` : ''}${
item.info.custom_info?.description ? '<br>' : ''
}${item.info.custom_info?.description?.replaceAll('\n', '<br>') ?? ''}`}
>
>
<div class=" mr-2">
<div class=" mr-2">
<svg
<svg
...
...
src/lib/components/chat/Settings/Interface.svelte
View file @
e76a444e
...
@@ -244,7 +244,10 @@
...
@@ -244,7 +244,10 @@
{#each $models as model}
{#each $models as model}
{#if model.size != null}
{#if model.size != null}
<option value={model.name} class="bg-gray-100 dark:bg-gray-700">
<option value={model.name} class="bg-gray-100 dark:bg-gray-700">
{model.name + ' (' + (model.size / 1024 ** 3).toFixed(1) + ' GB)'}
{(model.custom_info?.displayName ?? model.name) +
' (' +
(model.size / 1024 ** 3).toFixed(1) +
' GB)'}
</option>
</option>
{/if}
{/if}
{/each}
{/each}
...
@@ -262,7 +265,7 @@
...
@@ -262,7 +265,7 @@
{#each $models as model}
{#each $models as model}
{#if model.name !== 'hr'}
{#if model.name !== 'hr'}
<option value={model.name} class="bg-gray-100 dark:bg-gray-700">
<option value={model.name} class="bg-gray-100 dark:bg-gray-700">
{model.name}
{
model.custom_info?.displayName ??
model.name}
</option>
</option>
{/if}
{/if}
{/each}
{/each}
...
...
src/lib/components/chat/Settings/Models.svelte
View file @
e76a444e
...
@@ -13,7 +13,7 @@
...
@@ -13,7 +13,7 @@
uploadModel
uploadModel
} from '$lib/apis/ollama';
} from '$lib/apis/ollama';
import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants';
import { WEBUI_NAME, models, MODEL_DOWNLOAD_POOL, user } from '$lib/stores';
import { WEBUI_NAME, models, MODEL_DOWNLOAD_POOL, user
, config
} from '$lib/stores';
import { splitStream } from '$lib/utils';
import { splitStream } from '$lib/utils';
import { onMount, getContext } from 'svelte';
import { onMount, getContext } from 'svelte';
import { addLiteLLMModel, deleteLiteLLMModel, getLiteLLMModelInfo } from '$lib/apis/litellm';
import { addLiteLLMModel, deleteLiteLLMModel, getLiteLLMModelInfo } from '$lib/apis/litellm';
...
@@ -67,6 +67,8 @@
...
@@ -67,6 +67,8 @@
let deleteModelTag = '';
let deleteModelTag = '';
let showModelInfo = false;
const updateModelsHandler = async () => {
const updateModelsHandler = async () => {
for (const model of $models.filter(
for (const model of $models.filter(
(m) =>
(m) =>
...
@@ -587,24 +589,28 @@
...
@@ -587,24 +589,28 @@
viewBox="0 0 24 24"
viewBox="0 0 24 24"
fill="currentColor"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
><style>
>
<style>
.spinner_ajPY {
.spinner_ajPY {
transform-origin: center;
transform-origin: center;
animation: spinner_AtaB 0.75s infinite linear;
animation: spinner_AtaB 0.75s infinite linear;
}
}
@keyframes spinner_AtaB {
@keyframes spinner_AtaB {
100% {
100% {
transform: rotate(360deg);
transform: rotate(360deg);
}
}
}
}
</style><path
</style>
<path
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
opacity=".25"
opacity=".25"
/><path
/>
<path
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
class="spinner_ajPY"
class="spinner_ajPY"
/>
</svg
/>
>
</svg
>
</div>
</div>
{:else}
{:else}
<svg
<svg
...
@@ -705,7 +711,10 @@
...
@@ -705,7 +711,10 @@
{/if}
{/if}
{#each $models.filter((m) => m.size != null && (selectedOllamaUrlIdx === null ? true : (m?.urls ?? []).includes(selectedOllamaUrlIdx))) as model}
{#each $models.filter((m) => m.size != null && (selectedOllamaUrlIdx === null ? true : (m?.urls ?? []).includes(selectedOllamaUrlIdx))) as model}
<option value={model.name} class="bg-gray-100 dark:bg-gray-700"
<option value={model.name} class="bg-gray-100 dark:bg-gray-700"
>{model.name + ' (' + (model.size / 1024 ** 3).toFixed(1) + ' GB)'}</option
>{(model.custom_info?.displayName ?? model.name) +
' (' +
(model.size / 1024 ** 3).toFixed(1) +
' GB)'}</option
>
>
{/each}
{/each}
</select>
</select>
...
@@ -833,24 +842,28 @@
...
@@ -833,24 +842,28 @@
viewBox="0 0 24 24"
viewBox="0 0 24 24"
fill="currentColor"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
><style>
>
<style>
.spinner_ajPY {
.spinner_ajPY {
transform-origin: center;
transform-origin: center;
animation: spinner_AtaB 0.75s infinite linear;
animation: spinner_AtaB 0.75s infinite linear;
}
}
@keyframes spinner_AtaB {
@keyframes spinner_AtaB {
100% {
100% {
transform: rotate(360deg);
transform: rotate(360deg);
}
}
}
}
</style><path
</style>
<path
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
opacity=".25"
opacity=".25"
/><path
/>
<path
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
class="spinner_ajPY"
class="spinner_ajPY"
/>
</svg
/>
>
</svg
>
</div>
</div>
{:else}
{:else}
<svg
<svg
...
@@ -932,6 +945,7 @@
...
@@ -932,6 +945,7 @@
<hr class=" dark:border-gray-700 my-2" />
<hr class=" dark:border-gray-700 my-2" />
{/if}
{/if}
<!--TODO: Hide LiteLLM options when ENABLE_LITELLM=false-->
<div class=" space-y-3">
<div class=" space-y-3">
<div class="mt-2 space-y-3 pr-1.5">
<div class="mt-2 space-y-3 pr-1.5">
<div>
<div>
...
@@ -1126,6 +1140,79 @@
...
@@ -1126,6 +1140,79 @@
{/if}
{/if}
</div>
</div>
</div>
</div>
<hr class=" dark:border-gray-700 my-2" />
</div>
</div>
<!-- <div class=" space-y-3">-->
<!-- <div class="mt-2 space-y-3 pr-1.5">-->
<!-- <div>-->
<!-- <div class="mb-2">-->
<!-- <div class="flex justify-between items-center text-xs">-->
<!-- <div class=" text-sm font-medium">{$i18n.t('Manage Model Information')}</div>-->
<!-- <button-->
<!-- class=" text-xs font-medium text-gray-500"-->
<!-- type="button"-->
<!-- on:click={() => {-->
<!-- showModelInfo = !showModelInfo;-->
<!-- }}>{showModelInfo ? $i18n.t('Hide') : $i18n.t('Show')}</button-->
<!-- >-->
<!-- </div>-->
<!-- </div>-->
<!-- {#if showModelInfo}-->
<!-- <div>-->
<!-- <div class="flex justify-between items-center text-xs">-->
<!-- <div class=" text-sm font-medium">{$i18n.t('Current Models')}</div>-->
<!-- </div>-->
<!-- <div class="flex gap-2">-->
<!-- <div class="flex-1 pb-1">-->
<!-- <select-->
<!-- class="w-full rounded-lg py-2 px-4 text-sm dark:text-gray-300 dark:bg-gray-850 outline-none"-->
<!-- bind:value={selectedOllamaUrlIdx}-->
<!-- placeholder={$i18n.t('Select an existing model')}-->
<!-- >-->
<!-- {#each $config. as url, idx}-->
<!-- <option value={idx} class="bg-gray-100 dark:bg-gray-700">{url}</option>-->
<!-- {/each}-->
<!-- </select>-->
<!-- </div>-->
<!-- <div>-->
<!-- <div class="flex w-full justify-end">-->
<!-- <Tooltip content="Update All Models" placement="top">-->
<!-- <button-->
<!-- class="p-2.5 flex gap-2 items-center bg-gray-100 hover:bg-gray-200 text-gray-800 dark:bg-gray-850 dark:hover:bg-gray-800 dark:text-gray-100 rounded-lg transition"-->
<!-- on:click={() => {-->
<!-- updateModelsHandler();-->
<!-- }}-->
<!-- >-->
<!-- <svg-->
<!-- xmlns="http://www.w3.org/2000/svg"-->
<!-- viewBox="0 0 16 16"-->
<!-- fill="currentColor"-->
<!-- class="w-4 h-4"-->
<!-- >-->
<!-- <path-->
<!-- d="M7 1a.75.75 0 0 1 .75.75V6h-1.5V1.75A.75.75 0 0 1 7 1ZM6.25 6v2.94L5.03 7.72a.75.75 0 0 0-1.06 1.06l2.5 2.5a.75.75 0 0 0 1.06 0l2.5-2.5a.75.75 0 1 0-1.06-1.06L7.75 8.94V6H10a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2.25Z"-->
<!-- />-->
<!-- <path-->
<!-- d="M4.268 14A2 2 0 0 0 6 15h6a2 2 0 0 0 2-2v-3a2 2 0 0 0-1-1.732V11a3 3 0 0 1-3 3H4.268Z"-->
<!-- />-->
<!-- </svg>-->
<!-- </button>-->
<!-- </Tooltip>-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
<!-- {#if updateModelId}-->
<!-- Updating "{updateModelId}" {updateProgress ? `(${updateProgress}%)` : ''}-->
<!-- {/if}-->
<!-- </div>-->
<!-- {/if}-->
<!-- </div>-->
<!-- </div>-->
<!-- </div>-->
</div>
</div>
</div>
</div>
src/lib/components/documents/Settings/General.svelte
View file @
e76a444e
...
@@ -321,7 +321,10 @@
...
@@ -321,7 +321,10 @@
{/if}
{/if}
{#each $models.filter((m) => m.id && !m.external) as model}
{#each $models.filter((m) => m.id && !m.external) as model}
<option value={model.name} class="bg-gray-100 dark:bg-gray-700"
<option value={model.name} class="bg-gray-100 dark:bg-gray-700"
>{model.name + ' (' + (model.size / 1024 ** 3).toFixed(1) + ' GB)'}</option
>{(model.custom_info?.displayName ?? model.name) +
' (' +
(model.size / 1024 ** 3).toFixed(1) +
' GB)'}</option
>
>
{/each}
{/each}
</select>
</select>
...
...
src/lib/stores/index.ts
View file @
e76a444e
...
@@ -39,27 +39,34 @@ export const showSidebar = writable(false);
...
@@ -39,27 +39,34 @@ export const showSidebar = writable(false);
export
const
showSettings
=
writable
(
false
);
export
const
showSettings
=
writable
(
false
);
export
const
showChangelog
=
writable
(
false
);
export
const
showChangelog
=
writable
(
false
);
type
Model
=
OpenAIModel
|
OllamaModel
;
export
type
Model
=
OpenAIModel
|
OllamaModel
;
type
OpenAIModel
=
{
type
ModelCustomInfo
=
{
id
:
string
;
name
?
:
string
;
n
ame
:
string
;
displayN
ame
?
:
string
;
external
:
boolean
;
description
?:
string
;
source
?:
string
;
vision_capable
?:
boolean
;
};
};
type
Ollama
Model
=
{
type
Base
Model
=
{
id
:
string
;
id
:
string
;
name
:
string
;
name
:
string
;
custom_info
?:
ModelCustomInfo
;
};
// Ollama specific fields
interface
OpenAIModel
extends
BaseModel
{
external
:
boolean
;
source
?:
string
;
}
interface
OllamaModel
extends
BaseModel
{
details
:
OllamaModelDetails
;
details
:
OllamaModelDetails
;
size
:
number
;
size
:
number
;
description
:
string
;
description
:
string
;
model
:
string
;
model
:
string
;
modified_at
:
string
;
modified_at
:
string
;
digest
:
string
;
digest
:
string
;
}
;
}
type
OllamaModelDetails
=
{
type
OllamaModelDetails
=
{
parent_model
:
string
;
parent_model
:
string
;
...
@@ -129,6 +136,20 @@ type Config = {
...
@@ -129,6 +136,20 @@ type Config = {
default_models
?:
string
[];
default_models
?:
string
[];
default_prompt_suggestions
?:
PromptSuggestion
[];
default_prompt_suggestions
?:
PromptSuggestion
[];
trusted_header_auth
?:
boolean
;
trusted_header_auth
?:
boolean
;
model_config
?:
GlobalModelConfig
;
};
type
GlobalModelConfig
=
{
ollama
?:
ModelConfig
[];
litellm
?:
ModelConfig
[];
openai
?:
ModelConfig
[];
};
type
ModelConfig
=
{
id
?:
string
;
name
?:
string
;
description
?:
string
;
vision_capable
?:
boolean
;
};
};
type
PromptSuggestion
=
{
type
PromptSuggestion
=
{
...
...
src/routes/(app)/+page.svelte
View file @
e76a444e
...
@@ -16,7 +16,8 @@
...
@@ -16,7 +16,8 @@
config
,
config
,
WEBUI_NAME
,
WEBUI_NAME
,
tags
as
_tags
,
tags
as
_tags
,
showSidebar
showSidebar
,
type
Model
}
from
'$lib/stores'
;
}
from
'$lib/stores'
;
import
{
copyToClipboard
,
splitStream
}
from
'$lib/utils'
;
import
{
copyToClipboard
,
splitStream
}
from
'$lib/utils'
;
...
@@ -53,7 +54,7 @@
...
@@ -53,7 +54,7 @@
let
showModelSelector
=
true
;
let
showModelSelector
=
true
;
let
selectedModels
=
[
''
];
let
selectedModels
=
[
''
];
let
atSelectedModel
=
''
;
let
atSelectedModel
:
Model
|
undefined
;
let
selectedModelfile
=
null
;
let
selectedModelfile
=
null
;
$:
selectedModelfile
=
$:
selectedModelfile
=
...
@@ -254,50 +255,66 @@
...
@@ -254,50 +255,66 @@
const
_chatId
=
JSON
.
parse
(
JSON
.
stringify
($
chatId
));
const
_chatId
=
JSON
.
parse
(
JSON
.
stringify
($
chatId
));
await
Promise
.
all
(
await
Promise
.
all
(
(
atSelectedModel
!== '' ? [atSelectedModel.id] : selectedModels).map(async (modelId) => {
(
atSelectedModel
!== undefined ? [atSelectedModel.id] : selectedModels).map(
console
.
log
(
'modelId'
,
modelId
);
async
(
modelId
)
=>
{
const
model
=
$
models
.
filter
((
m
)
=>
m
.
id
===
modelId
).
at
(
0
);
console
.
log
(
'modelId'
,
modelId
);
const
model
=
$
models
.
filter
((
m
)
=>
m
.
id
===
modelId
).
at
(
0
);
if
(
model
)
{
//
Create
response
message
if
(
model
)
{
let
responseMessageId
=
uuidv4
();
//
If
there
are
image
files
,
check
if
model
is
vision
capable
let
responseMessage
=
{
const
hasImages
=
messages
.
some
((
message
)
=>
parentId
:
parentId
,
message
.
files
?.
some
((
file
)
=>
file
.
type
===
'image'
)
id
:
responseMessageId
,
);
childrenIds
:
[],
if
(
hasImages
&&
!(model.custom_info?.vision_capable ?? true)) {
role
:
'assistant'
,
toast
.
error
(
content
:
''
,
$
i18n
.
t
(
'Model {{modelName}} is not vision capable'
,
{
model
:
model
.
id
,
modelName
:
model
.
custom_info
?.
displayName
??
model
.
name
??
model
.
id
timestamp
:
Math
.
floor
(
Date
.
now
()
/
1000
)
//
Unix
epoch
})
};
);
}
//
Add
message
to
history
and
Set
currentId
to
messageId
history
.
messages
[
responseMessageId
]
=
responseMessage
;
//
Create
response
message
history
.
currentId
=
responseMessageId
;
let
responseMessageId
=
uuidv4
();
let
responseMessage
=
{
//
Append
messageId
to
childrenIds
of
parent
message
parentId
:
parentId
,
if
(
parentId
!== null) {
id
:
responseMessageId
,
history
.
messages
[
parentId
].
childrenIds
=
[
childrenIds
:
[],
...
history
.
messages
[
parentId
].
childrenIds
,
role
:
'assistant'
,
responseMessageId
content
:
''
,
];
model
:
model
.
id
,
}
modelName
:
model
.
custom_info
?.
displayName
??
model
.
name
??
model
.
id
,
timestamp
:
Math
.
floor
(
Date
.
now
()
/
1000
)
//
Unix
epoch
};
//
Add
message
to
history
and
Set
currentId
to
messageId
history
.
messages
[
responseMessageId
]
=
responseMessage
;
history
.
currentId
=
responseMessageId
;
//
Append
messageId
to
childrenIds
of
parent
message
if
(
parentId
!== null) {
history
.
messages
[
parentId
].
childrenIds
=
[
...
history
.
messages
[
parentId
].
childrenIds
,
responseMessageId
];
}
if
(
model
?.
external
)
{
if
(
model
?.
external
)
{
await
sendPromptOpenAI
(
model
,
prompt
,
responseMessageId
,
_chatId
);
await
sendPromptOpenAI
(
model
,
prompt
,
responseMessageId
,
_chatId
);
}
else
if
(
model
)
{
}
else
if
(
model
)
{
await
sendPromptOllama
(
model
,
prompt
,
responseMessageId
,
_chatId
);
await
sendPromptOllama
(
model
,
prompt
,
responseMessageId
,
_chatId
);
}
}
else
{
toast
.
error
($
i18n
.
t
(`
Model
{{
modelId
}}
not
found
`,
{
modelId
}));
}
}
}
else
{
toast
.
error
($
i18n
.
t
(`
Model
{{
modelId
}}
not
found
`,
{
modelId
}));
}
}
}
)
)
);
);
await
chats
.
set
(
await
getChatList
(
localStorage
.
token
));
await
chats
.
set
(
await
getChatList
(
localStorage
.
token
));
};
};
const
sendPromptOllama
=
async
(
model
,
userPrompt
,
responseMessageId
,
_chatId
)
=>
{
const
sendPromptOllama
=
async
(
model
,
userPrompt
,
responseMessageId
,
_chatId
)
=>
{
const
modelName
=
model
.
custom_info
?.
displayName
??
model
.
name
??
model
.
id
;
model
=
model
.
id
;
model
=
model
.
id
;
const
responseMessage
=
history
.
messages
[
responseMessageId
];
const
responseMessage
=
history
.
messages
[
responseMessageId
];
...
@@ -702,17 +719,17 @@
...
@@ -702,17 +719,17 @@
} else {
} else {
toast.error(
toast.error(
$i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
$i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: model.name ?? model.id
provider:
model.custom_info?.displayName ??
model.name ?? model.id
})
})
);
);
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: model.name ?? model.id
provider:
model.custom_info?.displayName ??
model.name ?? model.id
});
});
}
}
responseMessage.error = true;
responseMessage.error = true;
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: model.name ?? model.id
provider:
model.custom_info?.displayName ??
model.name ?? model.id
});
});
responseMessage.done = true;
responseMessage.done = true;
messages = messages;
messages = messages;
...
...
src/routes/(app)/c/[id]/+page.svelte
View file @
e76a444e
...
@@ -15,7 +15,8 @@
...
@@ -15,7 +15,8 @@
config
,
config
,
WEBUI_NAME
,
WEBUI_NAME
,
tags
as
_tags
,
tags
as
_tags
,
showSidebar
showSidebar
,
type
Model
}
from
'$lib/stores'
;
}
from
'$lib/stores'
;
import
{
copyToClipboard
,
splitStream
,
convertMessagesToHistory
}
from
'$lib/utils'
;
import
{
copyToClipboard
,
splitStream
,
convertMessagesToHistory
}
from
'$lib/utils'
;
...
@@ -57,7 +58,7 @@
...
@@ -57,7 +58,7 @@
//
let
chatId
=
$
page
.
params
.
id
;
//
let
chatId
=
$
page
.
params
.
id
;
let
showModelSelector
=
true
;
let
showModelSelector
=
true
;
let
selectedModels
=
[
''
];
let
selectedModels
=
[
''
];
let
atSelectedModel
=
''
;
let
atSelectedModel
:
Model
|
undefined
;
let
selectedModelfile
=
null
;
let
selectedModelfile
=
null
;
...
@@ -259,43 +260,58 @@
...
@@ -259,43 +260,58 @@
const
_chatId
=
JSON
.
parse
(
JSON
.
stringify
($
chatId
));
const
_chatId
=
JSON
.
parse
(
JSON
.
stringify
($
chatId
));
await
Promise
.
all
(
await
Promise
.
all
(
(
atSelectedModel
!== '' ? [atSelectedModel.id] : selectedModels).map(async (modelId) => {
(
atSelectedModel
!== undefined ? [atSelectedModel.id] : selectedModels).map(
const
model
=
$
models
.
filter
((
m
)
=>
m
.
id
===
modelId
).
at
(
0
);
async
(
modelId
)
=>
{
const
model
=
$
models
.
filter
((
m
)
=>
m
.
id
===
modelId
).
at
(
0
);
if
(
model
)
{
//
Create
response
message
if
(
model
)
{
let
responseMessageId
=
uuidv4
();
//
If
there
are
image
files
,
check
if
model
is
vision
capable
let
responseMessage
=
{
const
hasImages
=
messages
.
some
((
message
)
=>
parentId
:
parentId
,
message
.
files
?.
some
((
file
)
=>
file
.
type
===
'image'
)
id
:
responseMessageId
,
);
childrenIds
:
[],
if
(
hasImages
&&
!(model.custom_info?.vision_capable ?? true)) {
role
:
'assistant'
,
toast
.
error
(
content
:
''
,
$
i18n
.
t
(
'Model {{modelName}} is not vision capable'
,
{
model
:
model
.
id
,
modelName
:
model
.
custom_info
?.
displayName
??
model
.
name
??
model
.
id
timestamp
:
Math
.
floor
(
Date
.
now
()
/
1000
)
//
Unix
epoch
})
};
);
}
//
Add
message
to
history
and
Set
currentId
to
messageId
history
.
messages
[
responseMessageId
]
=
responseMessage
;
//
Create
response
message
history
.
currentId
=
responseMessageId
;
let
responseMessageId
=
uuidv4
();
let
responseMessage
=
{
//
Append
messageId
to
childrenIds
of
parent
message
parentId
:
parentId
,
if
(
parentId
!== null) {
id
:
responseMessageId
,
history
.
messages
[
parentId
].
childrenIds
=
[
childrenIds
:
[],
...
history
.
messages
[
parentId
].
childrenIds
,
role
:
'assistant'
,
responseMessageId
content
:
''
,
];
model
:
model
.
id
,
}
modelName
:
model
.
custom_info
?.
displayName
??
model
.
name
??
model
.
id
,
timestamp
:
Math
.
floor
(
Date
.
now
()
/
1000
)
//
Unix
epoch
};
//
Add
message
to
history
and
Set
currentId
to
messageId
history
.
messages
[
responseMessageId
]
=
responseMessage
;
history
.
currentId
=
responseMessageId
;
//
Append
messageId
to
childrenIds
of
parent
message
if
(
parentId
!== null) {
history
.
messages
[
parentId
].
childrenIds
=
[
...
history
.
messages
[
parentId
].
childrenIds
,
responseMessageId
];
}
if
(
model
?.
external
)
{
if
(
model
?.
external
)
{
await
sendPromptOpenAI
(
model
,
prompt
,
responseMessageId
,
_chatId
);
await
sendPromptOpenAI
(
model
,
prompt
,
responseMessageId
,
_chatId
);
}
else
if
(
model
)
{
}
else
if
(
model
)
{
await
sendPromptOllama
(
model
,
prompt
,
responseMessageId
,
_chatId
);
await
sendPromptOllama
(
model
,
prompt
,
responseMessageId
,
_chatId
);
}
}
else
{
toast
.
error
($
i18n
.
t
(`
Model
{{
modelId
}}
not
found
`,
{
modelId
}));
}
}
}
else
{
toast
.
error
($
i18n
.
t
(`
Model
{{
modelId
}}
not
found
`,
{
modelId
}));
}
}
}
)
)
);
);
await
chats
.
set
(
await
getChatList
(
localStorage
.
token
));
await
chats
.
set
(
await
getChatList
(
localStorage
.
token
));
...
@@ -706,17 +722,17 @@
...
@@ -706,17 +722,17 @@
} else {
} else {
toast.error(
toast.error(
$i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
$i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: model.name ?? model.id
provider:
model.custom_info?.displayName ??
model.name ?? model.id
})
})
);
);
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: model.name ?? model.id
provider:
model.custom_info?.displayName ??
model.name ?? model.id
});
});
}
}
responseMessage.error = true;
responseMessage.error = true;
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
responseMessage.content = $i18n.t(`Uh-oh! There was an issue connecting to {{provider}}.`, {
provider: model.name ?? model.id
provider:
model.custom_info?.displayName ??
model.name ?? model.id
});
});
responseMessage.done = true;
responseMessage.done = true;
messages = messages;
messages = messages;
...
...
Prev
1
2
Next
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