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
562e40a7
Commit
562e40a7
authored
Mar 31, 2024
by
Jun Siang Cheah
Browse files
Merge branch 'dev' into feat/trusted-email-header
parents
0e3b7a11
587a8c59
Changes
58
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
217 additions
and
127 deletions
+217
-127
.github/workflows/format-backend.yaml
.github/workflows/format-backend.yaml
+23
-11
.github/workflows/format-build-frontend.yaml
.github/workflows/format-build-frontend.yaml
+28
-14
CHANGELOG.md
CHANGELOG.md
+18
-0
backend/apps/audio/main.py
backend/apps/audio/main.py
+7
-1
backend/apps/images/main.py
backend/apps/images/main.py
+3
-3
backend/apps/images/utils/comfyui.py
backend/apps/images/utils/comfyui.py
+13
-7
backend/apps/ollama/main.py
backend/apps/ollama/main.py
+14
-4
backend/apps/rag/main.py
backend/apps/rag/main.py
+3
-3
backend/apps/web/models/auths.py
backend/apps/web/models/auths.py
+1
-0
backend/apps/web/models/documents.py
backend/apps/web/models/documents.py
+1
-0
backend/apps/web/models/modelfiles.py
backend/apps/web/models/modelfiles.py
+12
-12
backend/apps/web/models/prompts.py
backend/apps/web/models/prompts.py
+9
-6
backend/apps/web/models/tags.py
backend/apps/web/models/tags.py
+1
-0
backend/apps/web/routers/chats.py
backend/apps/web/routers/chats.py
+1
-0
backend/apps/web/routers/configs.py
backend/apps/web/routers/configs.py
+6
-2
backend/apps/web/routers/modelfiles.py
backend/apps/web/routers/modelfiles.py
+24
-21
backend/apps/web/routers/users.py
backend/apps/web/routers/users.py
+1
-0
backend/config.py
backend/config.py
+18
-4
backend/data/config.json
backend/data/config.json
+23
-34
backend/main.py
backend/main.py
+11
-5
No files found.
.github/workflows/format-backend.yaml
View file @
562e40a7
name
:
Python CI
name
:
Python CI
on
:
on
:
push
:
push
:
branches
:
[
'
main'
]
branches
:
-
main
-
dev
pull_request
:
pull_request
:
branches
:
-
main
-
dev
jobs
:
jobs
:
build
:
build
:
name
:
'
Format
Backend'
name
:
'
Format
Backend'
env
:
PUBLIC_API_BASE_URL
:
'
'
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
strategy
:
strategy
:
matrix
:
matrix
:
node
-version
:
python
-version
:
[
3.11
]
-
latest
steps
:
steps
:
-
uses
:
actions/checkout@v4
-
uses
:
actions/checkout@v4
-
name
:
Use Python
uses
:
actions/setup-python@v4
-
name
:
Set up Python
-
name
:
Use Bun
uses
:
actions/setup-python@v2
uses
:
oven-sh/setup-bun@v1
with
:
python-version
:
${{ matrix.python-version }}
-
name
:
Install dependencies
-
name
:
Install dependencies
run
:
|
run
:
|
python -m pip install --upgrade pip
python -m pip install --upgrade pip
pip install yapf
pip install black
-
name
:
Format backend
-
name
:
Format backend
run
:
bun run format:backend
run
:
black . --exclude "/venv/"
-
name
:
Check for changes after format
run
:
git diff --exit-code
.github/workflows/format-build-frontend.yaml
View file @
562e40a7
name
:
Bun CI
name
:
Frontend Build
on
:
on
:
push
:
push
:
branches
:
[
'
main'
]
branches
:
-
main
-
dev
pull_request
:
pull_request
:
branches
:
-
main
-
dev
jobs
:
jobs
:
build
:
build
:
name
:
'
Format
&
Build
Frontend'
name
:
'
Format
&
Build
Frontend'
env
:
PUBLIC_API_BASE_URL
:
'
'
runs-on
:
ubuntu-latest
runs-on
:
ubuntu-latest
steps
:
steps
:
-
uses
:
actions/checkout@v4
-
name
:
Checkout Repository
-
name
:
Use Bun
uses
:
actions/checkout@v4
uses
:
oven-sh/setup-bun@v1
-
run
:
bun --version
-
name
:
Setup Node.js
-
name
:
Install frontend dependencies
uses
:
actions/setup-node@v3
run
:
bun install
with
:
-
name
:
Format frontend
node-version
:
'
20'
# Or specify any other version you want to use
run
:
bun run format
-
name
:
Build frontend
-
name
:
Install Dependencies
run
:
bun run build
run
:
npm install
-
name
:
Format Frontend
run
:
npm run format
-
name
:
Check for Changes After Format
run
:
git diff --exit-code
-
name
:
Build Frontend
run
:
npm run build
CHANGELOG.md
View file @
562e40a7
...
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
...
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
The format is based on
[
Keep a Changelog
](
https://keepachangelog.com/en/1.1.0/
)
,
The format is based on
[
Keep a Changelog
](
https://keepachangelog.com/en/1.1.0/
)
,
and this project adheres to
[
Semantic Versioning
](
https://semver.org/spec/v2.0.0.html
)
.
and this project adheres to
[
Semantic Versioning
](
https://semver.org/spec/v2.0.0.html
)
.
## [0.1.116] - 2024-03-31
### Added
-
**🔄 Enhanced UI**
: Model selector now conveniently located in the navbar, enabling seamless switching between multiple models during conversations.
-
**🔍 Improved Model Selector**
: Directly pull a model from the selector/Models now display detailed information for better understanding.
-
**💬 Webhook Support**
: Now compatible with Google Chat and Microsoft Teams.
-
**🌐 Localization**
: Korean translation (I18n) now available.
-
**🌑 Dark Theme**
: OLED dark theme introduced for reduced strain during prolonged usage.
-
**🏷️ Tag Autocomplete**
: Dropdown feature added for effortless chat tagging.
### Fixed
-
**🔽 Auto-Scrolling**
: Addressed OpenAI auto-scrolling issue.
-
**🏷️ Tag Validation**
: Implemented tag validation to prevent empty string tags.
-
**🚫 Model Whitelisting**
: Resolved LiteLLM model whitelisting issue.
-
**✅ Spelling**
: Corrected various spelling issues for improved readability.
## [0.1.115] - 2024-03-24
## [0.1.115] - 2024-03-24
### Added
### Added
...
...
backend/apps/audio/main.py
View file @
562e40a7
...
@@ -22,7 +22,13 @@ from utils.utils import (
...
@@ -22,7 +22,13 @@ from utils.utils import (
)
)
from
utils.misc
import
calculate_sha256
from
utils.misc
import
calculate_sha256
from
config
import
SRC_LOG_LEVELS
,
CACHE_DIR
,
UPLOAD_DIR
,
WHISPER_MODEL
,
WHISPER_MODEL_DIR
from
config
import
(
SRC_LOG_LEVELS
,
CACHE_DIR
,
UPLOAD_DIR
,
WHISPER_MODEL
,
WHISPER_MODEL_DIR
,
)
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
log
.
setLevel
(
SRC_LOG_LEVELS
[
"AUDIO"
])
log
.
setLevel
(
SRC_LOG_LEVELS
[
"AUDIO"
])
...
...
backend/apps/images/main.py
View file @
562e40a7
...
@@ -325,7 +325,7 @@ def save_url_image(url):
...
@@ -325,7 +325,7 @@ def save_url_image(url):
return
image_id
return
image_id
except
Exception
as
e
:
except
Exception
as
e
:
print
(
f
"Error saving image:
{
e
}
"
)
log
.
exception
(
f
"Error saving image:
{
e
}
"
)
return
None
return
None
...
@@ -397,7 +397,7 @@ def generate_image(
...
@@ -397,7 +397,7 @@ def generate_image(
user
.
id
,
user
.
id
,
app
.
state
.
COMFYUI_BASE_URL
,
app
.
state
.
COMFYUI_BASE_URL
,
)
)
print
(
res
)
log
.
debug
(
f
"res:
{
res
}
"
)
images
=
[]
images
=
[]
...
@@ -409,7 +409,7 @@ def generate_image(
...
@@ -409,7 +409,7 @@ def generate_image(
with
open
(
file_body_path
,
"w"
)
as
f
:
with
open
(
file_body_path
,
"w"
)
as
f
:
json
.
dump
(
data
.
model_dump
(
exclude_none
=
True
),
f
)
json
.
dump
(
data
.
model_dump
(
exclude_none
=
True
),
f
)
print
(
images
)
log
.
debug
(
f
"images:
{
images
}
"
)
return
images
return
images
else
:
else
:
if
form_data
.
model
:
if
form_data
.
model
:
...
...
backend/apps/images/utils/comfyui.py
View file @
562e40a7
...
@@ -4,6 +4,12 @@ import json
...
@@ -4,6 +4,12 @@ import json
import
urllib.request
import
urllib.request
import
urllib.parse
import
urllib.parse
import
random
import
random
import
logging
from
config
import
SRC_LOG_LEVELS
log
=
logging
.
getLogger
(
__name__
)
log
.
setLevel
(
SRC_LOG_LEVELS
[
"COMFYUI"
])
from
pydantic
import
BaseModel
from
pydantic
import
BaseModel
...
@@ -121,7 +127,7 @@ COMFYUI_DEFAULT_PROMPT = """
...
@@ -121,7 +127,7 @@ COMFYUI_DEFAULT_PROMPT = """
def
queue_prompt
(
prompt
,
client_id
,
base_url
):
def
queue_prompt
(
prompt
,
client_id
,
base_url
):
print
(
"queue_prompt"
)
log
.
info
(
"queue_prompt"
)
p
=
{
"prompt"
:
prompt
,
"client_id"
:
client_id
}
p
=
{
"prompt"
:
prompt
,
"client_id"
:
client_id
}
data
=
json
.
dumps
(
p
).
encode
(
"utf-8"
)
data
=
json
.
dumps
(
p
).
encode
(
"utf-8"
)
req
=
urllib
.
request
.
Request
(
f
"
{
base_url
}
/prompt"
,
data
=
data
)
req
=
urllib
.
request
.
Request
(
f
"
{
base_url
}
/prompt"
,
data
=
data
)
...
@@ -129,7 +135,7 @@ def queue_prompt(prompt, client_id, base_url):
...
@@ -129,7 +135,7 @@ def queue_prompt(prompt, client_id, base_url):
def
get_image
(
filename
,
subfolder
,
folder_type
,
base_url
):
def
get_image
(
filename
,
subfolder
,
folder_type
,
base_url
):
print
(
"get_image"
)
log
.
info
(
"get_image"
)
data
=
{
"filename"
:
filename
,
"subfolder"
:
subfolder
,
"type"
:
folder_type
}
data
=
{
"filename"
:
filename
,
"subfolder"
:
subfolder
,
"type"
:
folder_type
}
url_values
=
urllib
.
parse
.
urlencode
(
data
)
url_values
=
urllib
.
parse
.
urlencode
(
data
)
with
urllib
.
request
.
urlopen
(
f
"
{
base_url
}
/view?
{
url_values
}
"
)
as
response
:
with
urllib
.
request
.
urlopen
(
f
"
{
base_url
}
/view?
{
url_values
}
"
)
as
response
:
...
@@ -137,14 +143,14 @@ def get_image(filename, subfolder, folder_type, base_url):
...
@@ -137,14 +143,14 @@ def get_image(filename, subfolder, folder_type, base_url):
def
get_image_url
(
filename
,
subfolder
,
folder_type
,
base_url
):
def
get_image_url
(
filename
,
subfolder
,
folder_type
,
base_url
):
print
(
"get_image"
)
log
.
info
(
"get_image"
)
data
=
{
"filename"
:
filename
,
"subfolder"
:
subfolder
,
"type"
:
folder_type
}
data
=
{
"filename"
:
filename
,
"subfolder"
:
subfolder
,
"type"
:
folder_type
}
url_values
=
urllib
.
parse
.
urlencode
(
data
)
url_values
=
urllib
.
parse
.
urlencode
(
data
)
return
f
"
{
base_url
}
/view?
{
url_values
}
"
return
f
"
{
base_url
}
/view?
{
url_values
}
"
def
get_history
(
prompt_id
,
base_url
):
def
get_history
(
prompt_id
,
base_url
):
print
(
"get_history"
)
log
.
info
(
"get_history"
)
with
urllib
.
request
.
urlopen
(
f
"
{
base_url
}
/history/
{
prompt_id
}
"
)
as
response
:
with
urllib
.
request
.
urlopen
(
f
"
{
base_url
}
/history/
{
prompt_id
}
"
)
as
response
:
return
json
.
loads
(
response
.
read
())
return
json
.
loads
(
response
.
read
())
...
@@ -212,15 +218,15 @@ def comfyui_generate_image(
...
@@ -212,15 +218,15 @@ def comfyui_generate_image(
try
:
try
:
ws
=
websocket
.
WebSocket
()
ws
=
websocket
.
WebSocket
()
ws
.
connect
(
f
"ws://
{
host
}
/ws?clientId=
{
client_id
}
"
)
ws
.
connect
(
f
"ws://
{
host
}
/ws?clientId=
{
client_id
}
"
)
print
(
"WebSocket connection established."
)
log
.
info
(
"WebSocket connection established."
)
except
Exception
as
e
:
except
Exception
as
e
:
print
(
f
"Failed to connect to WebSocket server:
{
e
}
"
)
log
.
exception
(
f
"Failed to connect to WebSocket server:
{
e
}
"
)
return
None
return
None
try
:
try
:
images
=
get_images
(
ws
,
comfyui_prompt
,
client_id
,
base_url
)
images
=
get_images
(
ws
,
comfyui_prompt
,
client_id
,
base_url
)
except
Exception
as
e
:
except
Exception
as
e
:
print
(
f
"Error while receiving images:
{
e
}
"
)
log
.
exception
(
f
"Error while receiving images:
{
e
}
"
)
images
=
None
images
=
None
ws
.
close
()
ws
.
close
()
...
...
backend/apps/ollama/main.py
View file @
562e40a7
...
@@ -33,7 +33,13 @@ from constants import ERROR_MESSAGES
...
@@ -33,7 +33,13 @@ from constants import ERROR_MESSAGES
from
utils.utils
import
decode_token
,
get_current_user
,
get_admin_user
from
utils.utils
import
decode_token
,
get_current_user
,
get_admin_user
from
config
import
SRC_LOG_LEVELS
,
OLLAMA_BASE_URLS
,
MODEL_FILTER_ENABLED
,
MODEL_FILTER_LIST
,
UPLOAD_DIR
from
config
import
(
SRC_LOG_LEVELS
,
OLLAMA_BASE_URLS
,
MODEL_FILTER_ENABLED
,
MODEL_FILTER_LIST
,
UPLOAD_DIR
,
)
from
utils.misc
import
calculate_sha256
from
utils.misc
import
calculate_sha256
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
...
@@ -266,7 +272,7 @@ async def pull_model(
...
@@ -266,7 +272,7 @@ async def pull_model(
if
request_id
in
REQUEST_POOL
:
if
request_id
in
REQUEST_POOL
:
yield
chunk
yield
chunk
else
:
else
:
pr
in
t
(
"User: canceled request"
)
log
.
warn
in
g
(
"User: canceled request"
)
break
break
finally
:
finally
:
if
hasattr
(
r
,
"close"
):
if
hasattr
(
r
,
"close"
):
...
@@ -664,7 +670,7 @@ async def generate_completion(
...
@@ -664,7 +670,7 @@ async def generate_completion(
else
:
else
:
raise
HTTPException
(
raise
HTTPException
(
status_code
=
400
,
status_code
=
400
,
detail
=
"err
or_d
e
ta
il"
,
detail
=
ERROR_MESSAGES
.
MODEL_NOT_FOUND
(
f
or
m
_d
a
ta
.
model
)
,
)
)
url
=
app
.
state
.
OLLAMA_BASE_URLS
[
url_idx
]
url
=
app
.
state
.
OLLAMA_BASE_URLS
[
url_idx
]
...
@@ -770,7 +776,11 @@ async def generate_chat_completion(
...
@@ -770,7 +776,11 @@ async def generate_chat_completion(
r
=
None
r
=
None
log
.
debug
(
"form_data.model_dump_json(exclude_none=True).encode(): {0} "
.
format
(
form_data
.
model_dump_json
(
exclude_none
=
True
).
encode
()))
log
.
debug
(
"form_data.model_dump_json(exclude_none=True).encode(): {0} "
.
format
(
form_data
.
model_dump_json
(
exclude_none
=
True
).
encode
()
)
)
def
get_request
():
def
get_request
():
nonlocal
form_data
nonlocal
form_data
...
...
backend/apps/rag/main.py
View file @
562e40a7
...
@@ -333,7 +333,7 @@ def store_docs_in_vector_db(docs, collection_name, overwrite: bool = False) -> b
...
@@ -333,7 +333,7 @@ def store_docs_in_vector_db(docs, collection_name, overwrite: bool = False) -> b
if
overwrite
:
if
overwrite
:
for
collection
in
CHROMA_CLIENT
.
list_collections
():
for
collection
in
CHROMA_CLIENT
.
list_collections
():
if
collection_name
==
collection
.
name
:
if
collection_name
==
collection
.
name
:
print
(
f
"deleting existing collection
{
collection_name
}
"
)
log
.
info
(
f
"deleting existing collection
{
collection_name
}
"
)
CHROMA_CLIENT
.
delete_collection
(
name
=
collection_name
)
CHROMA_CLIENT
.
delete_collection
(
name
=
collection_name
)
collection
=
CHROMA_CLIENT
.
create_collection
(
collection
=
CHROMA_CLIENT
.
create_collection
(
...
@@ -346,7 +346,7 @@ def store_docs_in_vector_db(docs, collection_name, overwrite: bool = False) -> b
...
@@ -346,7 +346,7 @@ def store_docs_in_vector_db(docs, collection_name, overwrite: bool = False) -> b
)
)
return
True
return
True
except
Exception
as
e
:
except
Exception
as
e
:
print
(
e
)
log
.
exception
(
e
)
if
e
.
__class__
.
__name__
==
"UniqueConstraintError"
:
if
e
.
__class__
.
__name__
==
"UniqueConstraintError"
:
return
True
return
True
...
@@ -575,7 +575,7 @@ def scan_docs_dir(user=Depends(get_admin_user)):
...
@@ -575,7 +575,7 @@ def scan_docs_dir(user=Depends(get_admin_user)):
),
),
)
)
except
Exception
as
e
:
except
Exception
as
e
:
print
(
e
)
log
.
exception
(
e
)
pass
pass
except
Exception
as
e
:
except
Exception
as
e
:
...
...
backend/apps/web/models/auths.py
View file @
562e40a7
...
@@ -11,6 +11,7 @@ from utils.utils import verify_password
...
@@ -11,6 +11,7 @@ from utils.utils import verify_password
from
apps.web.internal.db
import
DB
from
apps.web.internal.db
import
DB
from
config
import
SRC_LOG_LEVELS
from
config
import
SRC_LOG_LEVELS
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
...
...
backend/apps/web/models/documents.py
View file @
562e40a7
...
@@ -13,6 +13,7 @@ from apps.web.internal.db import DB
...
@@ -13,6 +13,7 @@ from apps.web.internal.db import DB
import
json
import
json
from
config
import
SRC_LOG_LEVELS
from
config
import
SRC_LOG_LEVELS
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
...
...
backend/apps/web/models/modelfiles.py
View file @
562e40a7
...
@@ -64,8 +64,8 @@ class ModelfilesTable:
...
@@ -64,8 +64,8 @@ class ModelfilesTable:
self
.
db
.
create_tables
([
Modelfile
])
self
.
db
.
create_tables
([
Modelfile
])
def
insert_new_modelfile
(
def
insert_new_modelfile
(
self
,
user_id
:
str
,
self
,
user_id
:
str
,
form_data
:
ModelfileForm
form_data
:
ModelfileForm
)
->
Optional
[
ModelfileModel
]:
)
->
Optional
[
ModelfileModel
]:
if
"tagName"
in
form_data
.
modelfile
:
if
"tagName"
in
form_data
.
modelfile
:
modelfile
=
ModelfileModel
(
modelfile
=
ModelfileModel
(
**
{
**
{
...
@@ -73,7 +73,8 @@ class ModelfilesTable:
...
@@ -73,7 +73,8 @@ class ModelfilesTable:
"tag_name"
:
form_data
.
modelfile
[
"tagName"
],
"tag_name"
:
form_data
.
modelfile
[
"tagName"
],
"modelfile"
:
json
.
dumps
(
form_data
.
modelfile
),
"modelfile"
:
json
.
dumps
(
form_data
.
modelfile
),
"timestamp"
:
int
(
time
.
time
()),
"timestamp"
:
int
(
time
.
time
()),
})
}
)
try
:
try
:
result
=
Modelfile
.
create
(
**
modelfile
.
model_dump
())
result
=
Modelfile
.
create
(
**
modelfile
.
model_dump
())
...
@@ -87,29 +88,28 @@ class ModelfilesTable:
...
@@ -87,29 +88,28 @@ class ModelfilesTable:
else
:
else
:
return
None
return
None
def
get_modelfile_by_tag_name
(
self
,
def
get_modelfile_by_tag_name
(
self
,
tag_name
:
str
)
->
Optional
[
ModelfileModel
]:
tag_name
:
str
)
->
Optional
[
ModelfileModel
]:
try
:
try
:
modelfile
=
Modelfile
.
get
(
Modelfile
.
tag_name
==
tag_name
)
modelfile
=
Modelfile
.
get
(
Modelfile
.
tag_name
==
tag_name
)
return
ModelfileModel
(
**
model_to_dict
(
modelfile
))
return
ModelfileModel
(
**
model_to_dict
(
modelfile
))
except
:
except
:
return
None
return
None
def
get_modelfiles
(
self
,
def
get_modelfiles
(
self
,
skip
:
int
=
0
,
limit
:
int
=
50
)
->
List
[
ModelfileResponse
]:
skip
:
int
=
0
,
limit
:
int
=
50
)
->
List
[
ModelfileResponse
]:
return
[
return
[
ModelfileResponse
(
ModelfileResponse
(
**
{
**
{
**
model_to_dict
(
modelfile
),
**
model_to_dict
(
modelfile
),
"modelfile"
:
"modelfile"
:
json
.
loads
(
modelfile
.
modelfile
),
json
.
loads
(
modelfile
.
modelfile
),
}
})
for
modelfile
in
Modelfile
.
select
()
)
for
modelfile
in
Modelfile
.
select
()
# .limit(limit).offset(skip)
# .limit(limit).offset(skip)
]
]
def
update_modelfile_by_tag_name
(
def
update_modelfile_by_tag_name
(
self
,
tag_name
:
str
,
modelfile
:
dict
)
->
Optional
[
ModelfileModel
]:
self
,
tag_name
:
str
,
modelfile
:
dict
)
->
Optional
[
ModelfileModel
]:
try
:
try
:
query
=
Modelfile
.
update
(
query
=
Modelfile
.
update
(
modelfile
=
json
.
dumps
(
modelfile
),
modelfile
=
json
.
dumps
(
modelfile
),
...
...
backend/apps/web/models/prompts.py
View file @
562e40a7
...
@@ -52,8 +52,9 @@ class PromptsTable:
...
@@ -52,8 +52,9 @@ class PromptsTable:
self
.
db
=
db
self
.
db
=
db
self
.
db
.
create_tables
([
Prompt
])
self
.
db
.
create_tables
([
Prompt
])
def
insert_new_prompt
(
self
,
user_id
:
str
,
def
insert_new_prompt
(
form_data
:
PromptForm
)
->
Optional
[
PromptModel
]:
self
,
user_id
:
str
,
form_data
:
PromptForm
)
->
Optional
[
PromptModel
]:
prompt
=
PromptModel
(
prompt
=
PromptModel
(
**
{
**
{
"user_id"
:
user_id
,
"user_id"
:
user_id
,
...
@@ -61,7 +62,8 @@ class PromptsTable:
...
@@ -61,7 +62,8 @@ class PromptsTable:
"title"
:
form_data
.
title
,
"title"
:
form_data
.
title
,
"content"
:
form_data
.
content
,
"content"
:
form_data
.
content
,
"timestamp"
:
int
(
time
.
time
()),
"timestamp"
:
int
(
time
.
time
()),
})
}
)
try
:
try
:
result
=
Prompt
.
create
(
**
prompt
.
model_dump
())
result
=
Prompt
.
create
(
**
prompt
.
model_dump
())
...
@@ -81,13 +83,14 @@ class PromptsTable:
...
@@ -81,13 +83,14 @@ class PromptsTable:
def
get_prompts
(
self
)
->
List
[
PromptModel
]:
def
get_prompts
(
self
)
->
List
[
PromptModel
]:
return
[
return
[
PromptModel
(
**
model_to_dict
(
prompt
))
for
prompt
in
Prompt
.
select
()
PromptModel
(
**
model_to_dict
(
prompt
))
for
prompt
in
Prompt
.
select
()
# .limit(limit).offset(skip)
# .limit(limit).offset(skip)
]
]
def
update_prompt_by_command
(
def
update_prompt_by_command
(
self
,
command
:
str
,
self
,
command
:
str
,
form_data
:
PromptForm
form_data
:
PromptForm
)
->
Optional
[
PromptModel
]:
)
->
Optional
[
PromptModel
]:
try
:
try
:
query
=
Prompt
.
update
(
query
=
Prompt
.
update
(
title
=
form_data
.
title
,
title
=
form_data
.
title
,
...
...
backend/apps/web/models/tags.py
View file @
562e40a7
...
@@ -11,6 +11,7 @@ import logging
...
@@ -11,6 +11,7 @@ import logging
from
apps.web.internal.db
import
DB
from
apps.web.internal.db
import
DB
from
config
import
SRC_LOG_LEVELS
from
config
import
SRC_LOG_LEVELS
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
...
...
backend/apps/web/routers/chats.py
View file @
562e40a7
...
@@ -29,6 +29,7 @@ from apps.web.models.tags import (
...
@@ -29,6 +29,7 @@ from apps.web.models.tags import (
from
constants
import
ERROR_MESSAGES
from
constants
import
ERROR_MESSAGES
from
config
import
SRC_LOG_LEVELS
from
config
import
SRC_LOG_LEVELS
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
...
...
backend/apps/web/routers/configs.py
View file @
562e40a7
...
@@ -10,7 +10,12 @@ import uuid
...
@@ -10,7 +10,12 @@ import uuid
from
apps.web.models.users
import
Users
from
apps.web.models.users
import
Users
from
utils.utils
import
get_password_hash
,
get_current_user
,
get_admin_user
,
create_token
from
utils.utils
import
(
get_password_hash
,
get_current_user
,
get_admin_user
,
create_token
,
)
from
utils.misc
import
get_gravatar_url
,
validate_email_format
from
utils.misc
import
get_gravatar_url
,
validate_email_format
from
constants
import
ERROR_MESSAGES
from
constants
import
ERROR_MESSAGES
...
@@ -43,7 +48,6 @@ async def set_global_default_models(
...
@@ -43,7 +48,6 @@ async def set_global_default_models(
return
request
.
app
.
state
.
DEFAULT_MODELS
return
request
.
app
.
state
.
DEFAULT_MODELS
@
router
.
post
(
"/default/suggestions"
,
response_model
=
List
[
PromptSuggestion
])
@
router
.
post
(
"/default/suggestions"
,
response_model
=
List
[
PromptSuggestion
])
async
def
set_global_default_suggestions
(
async
def
set_global_default_suggestions
(
request
:
Request
,
request
:
Request
,
...
...
backend/apps/web/routers/modelfiles.py
View file @
562e40a7
...
@@ -24,9 +24,9 @@ router = APIRouter()
...
@@ -24,9 +24,9 @@ router = APIRouter()
@
router
.
get
(
"/"
,
response_model
=
List
[
ModelfileResponse
])
@
router
.
get
(
"/"
,
response_model
=
List
[
ModelfileResponse
])
async
def
get_modelfiles
(
skip
:
int
=
0
,
async
def
get_modelfiles
(
limit
:
int
=
50
,
skip
:
int
=
0
,
limit
:
int
=
50
,
user
=
Depends
(
get_current_user
)
user
=
Depends
(
get_current_user
)
):
):
return
Modelfiles
.
get_modelfiles
(
skip
,
limit
)
return
Modelfiles
.
get_modelfiles
(
skip
,
limit
)
...
@@ -36,17 +36,16 @@ async def get_modelfiles(skip: int = 0,
...
@@ -36,17 +36,16 @@ async def get_modelfiles(skip: int = 0,
@
router
.
post
(
"/create"
,
response_model
=
Optional
[
ModelfileResponse
])
@
router
.
post
(
"/create"
,
response_model
=
Optional
[
ModelfileResponse
])
async
def
create_new_modelfile
(
form_data
:
ModelfileForm
,
async
def
create_new_modelfile
(
form_data
:
ModelfileForm
,
user
=
Depends
(
get_admin_user
)):
user
=
Depends
(
get_admin_user
)):
modelfile
=
Modelfiles
.
insert_new_modelfile
(
user
.
id
,
form_data
)
modelfile
=
Modelfiles
.
insert_new_modelfile
(
user
.
id
,
form_data
)
if
modelfile
:
if
modelfile
:
return
ModelfileResponse
(
return
ModelfileResponse
(
**
{
**
{
**
modelfile
.
model_dump
(),
**
modelfile
.
model_dump
(),
"modelfile"
:
"modelfile"
:
json
.
loads
(
modelfile
.
modelfile
),
json
.
loads
(
modelfile
.
modelfile
),
}
}
)
)
else
:
else
:
raise
HTTPException
(
raise
HTTPException
(
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
...
@@ -60,17 +59,18 @@ async def create_new_modelfile(form_data: ModelfileForm,
...
@@ -60,17 +59,18 @@ async def create_new_modelfile(form_data: ModelfileForm,
@
router
.
post
(
"/"
,
response_model
=
Optional
[
ModelfileResponse
])
@
router
.
post
(
"/"
,
response_model
=
Optional
[
ModelfileResponse
])
async
def
get_modelfile_by_tag_name
(
form_data
:
ModelfileTagNameForm
,
async
def
get_modelfile_by_tag_name
(
user
=
Depends
(
get_current_user
)):
form_data
:
ModelfileTagNameForm
,
user
=
Depends
(
get_current_user
)
):
modelfile
=
Modelfiles
.
get_modelfile_by_tag_name
(
form_data
.
tag_name
)
modelfile
=
Modelfiles
.
get_modelfile_by_tag_name
(
form_data
.
tag_name
)
if
modelfile
:
if
modelfile
:
return
ModelfileResponse
(
return
ModelfileResponse
(
**
{
**
{
**
modelfile
.
model_dump
(),
**
modelfile
.
model_dump
(),
"modelfile"
:
"modelfile"
:
json
.
loads
(
modelfile
.
modelfile
),
json
.
loads
(
modelfile
.
modelfile
),
}
}
)
)
else
:
else
:
raise
HTTPException
(
raise
HTTPException
(
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
...
@@ -84,8 +84,9 @@ async def get_modelfile_by_tag_name(form_data: ModelfileTagNameForm,
...
@@ -84,8 +84,9 @@ async def get_modelfile_by_tag_name(form_data: ModelfileTagNameForm,
@
router
.
post
(
"/update"
,
response_model
=
Optional
[
ModelfileResponse
])
@
router
.
post
(
"/update"
,
response_model
=
Optional
[
ModelfileResponse
])
async
def
update_modelfile_by_tag_name
(
form_data
:
ModelfileUpdateForm
,
async
def
update_modelfile_by_tag_name
(
user
=
Depends
(
get_admin_user
)):
form_data
:
ModelfileUpdateForm
,
user
=
Depends
(
get_admin_user
)
):
modelfile
=
Modelfiles
.
get_modelfile_by_tag_name
(
form_data
.
tag_name
)
modelfile
=
Modelfiles
.
get_modelfile_by_tag_name
(
form_data
.
tag_name
)
if
modelfile
:
if
modelfile
:
updated_modelfile
=
{
updated_modelfile
=
{
...
@@ -94,14 +95,15 @@ async def update_modelfile_by_tag_name(form_data: ModelfileUpdateForm,
...
@@ -94,14 +95,15 @@ async def update_modelfile_by_tag_name(form_data: ModelfileUpdateForm,
}
}
modelfile
=
Modelfiles
.
update_modelfile_by_tag_name
(
modelfile
=
Modelfiles
.
update_modelfile_by_tag_name
(
form_data
.
tag_name
,
updated_modelfile
)
form_data
.
tag_name
,
updated_modelfile
)
return
ModelfileResponse
(
return
ModelfileResponse
(
**
{
**
{
**
modelfile
.
model_dump
(),
**
modelfile
.
model_dump
(),
"modelfile"
:
"modelfile"
:
json
.
loads
(
modelfile
.
modelfile
),
json
.
loads
(
modelfile
.
modelfile
),
}
}
)
)
else
:
else
:
raise
HTTPException
(
raise
HTTPException
(
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
...
@@ -115,7 +117,8 @@ async def update_modelfile_by_tag_name(form_data: ModelfileUpdateForm,
...
@@ -115,7 +117,8 @@ async def update_modelfile_by_tag_name(form_data: ModelfileUpdateForm,
@
router
.
delete
(
"/delete"
,
response_model
=
bool
)
@
router
.
delete
(
"/delete"
,
response_model
=
bool
)
async
def
delete_modelfile_by_tag_name
(
form_data
:
ModelfileTagNameForm
,
async
def
delete_modelfile_by_tag_name
(
user
=
Depends
(
get_admin_user
)):
form_data
:
ModelfileTagNameForm
,
user
=
Depends
(
get_admin_user
)
):
result
=
Modelfiles
.
delete_modelfile_by_tag_name
(
form_data
.
tag_name
)
result
=
Modelfiles
.
delete_modelfile_by_tag_name
(
form_data
.
tag_name
)
return
result
return
result
backend/apps/web/routers/users.py
View file @
562e40a7
...
@@ -16,6 +16,7 @@ from utils.utils import get_current_user, get_password_hash, get_admin_user
...
@@ -16,6 +16,7 @@ from utils.utils import get_current_user, get_password_hash, get_admin_user
from
constants
import
ERROR_MESSAGES
from
constants
import
ERROR_MESSAGES
from
config
import
SRC_LOG_LEVELS
from
config
import
SRC_LOG_LEVELS
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MODELS"
])
...
...
backend/config.py
View file @
562e40a7
...
@@ -117,7 +117,20 @@ else:
...
@@ -117,7 +117,20 @@ else:
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
log
.
info
(
f
"GLOBAL_LOG_LEVEL:
{
GLOBAL_LOG_LEVEL
}
"
)
log
.
info
(
f
"GLOBAL_LOG_LEVEL:
{
GLOBAL_LOG_LEVEL
}
"
)
log_sources
=
[
"AUDIO"
,
"CONFIG"
,
"DB"
,
"IMAGES"
,
"LITELLM"
,
"MAIN"
,
"MODELS"
,
"OLLAMA"
,
"OPENAI"
,
"RAG"
]
log_sources
=
[
"AUDIO"
,
"COMFYUI"
,
"CONFIG"
,
"DB"
,
"IMAGES"
,
"LITELLM"
,
"MAIN"
,
"MODELS"
,
"OLLAMA"
,
"OPENAI"
,
"RAG"
,
"WEBHOOK"
,
]
SRC_LOG_LEVELS
=
{}
SRC_LOG_LEVELS
=
{}
...
@@ -239,7 +252,7 @@ OLLAMA_API_BASE_URL = os.environ.get(
...
@@ -239,7 +252,7 @@ OLLAMA_API_BASE_URL = os.environ.get(
)
)
OLLAMA_BASE_URL
=
os
.
environ
.
get
(
"OLLAMA_BASE_URL"
,
""
)
OLLAMA_BASE_URL
=
os
.
environ
.
get
(
"OLLAMA_BASE_URL"
,
""
)
K
UBERNETES_SERVICE_HOST
=
os
.
environ
.
get
(
"KUBERNETES_SERVICE_HOST
"
,
""
)
K
8S_FLAG
=
os
.
environ
.
get
(
"K8S_FLAG
"
,
""
)
if
OLLAMA_BASE_URL
==
""
and
OLLAMA_API_BASE_URL
!=
""
:
if
OLLAMA_BASE_URL
==
""
and
OLLAMA_API_BASE_URL
!=
""
:
OLLAMA_BASE_URL
=
(
OLLAMA_BASE_URL
=
(
...
@@ -249,9 +262,10 @@ if OLLAMA_BASE_URL == "" and OLLAMA_API_BASE_URL != "":
...
@@ -249,9 +262,10 @@ if OLLAMA_BASE_URL == "" and OLLAMA_API_BASE_URL != "":
)
)
if
ENV
==
"prod"
:
if
ENV
==
"prod"
:
if
OLLAMA_BASE_URL
==
"/ollama"
and
KUBERNETES_SERVICE_HOST
==
""
:
if
OLLAMA_BASE_URL
==
"/ollama"
:
OLLAMA_BASE_URL
=
"http://host.docker.internal:11434"
OLLAMA_BASE_URL
=
"http://host.docker.internal:11434"
else
:
elif
K8S_FLAG
:
OLLAMA_BASE_URL
=
"http://ollama-service.open-webui.svc.cluster.local:11434"
OLLAMA_BASE_URL
=
"http://ollama-service.open-webui.svc.cluster.local:11434"
...
...
backend/data/config.json
View file @
562e40a7
{
{
"version"
:
0
,
"version"
:
0
,
"ui"
:
{
"ui"
:
{
"prompt_suggestions"
:
[
"default_locale"
:
"en-US"
,
{
"prompt_suggestions"
:
[
"title"
:
[
{
"Help me study"
,
"title"
:
[
"Help me study"
,
"vocabulary for a college entrance exam"
],
"vocabulary for a college entrance exam"
"content"
:
"Help me study vocabulary: write a sentence for me to fill in the blank, and I'll try to pick the correct option."
],
},
"content"
:
"Help me study vocabulary: write a sentence for me to fill in the blank, and I'll try to pick the correct option."
{
},
"title"
:
[
"Give me ideas"
,
"for what to do with my kids' art"
],
{
"content"
:
"What are 5 creative things I could do with my kids' art? I don't want to throw them away, but it's also so much clutter."
"title"
:
[
},
"Give me ideas"
,
{
"for what to do with my kids' art"
"title"
:
[
"Tell me a fun fact"
,
"about the Roman Empire"
],
],
"content"
:
"Tell me a random fun fact about the Roman Empire"
"content"
:
"What are 5 creative things I could do with my kids' art? I don't want to throw them away, but it's also so much clutter."
},
},
{
{
"title"
:
[
"Show me a code snippet"
,
"of a website's sticky header"
],
"title"
:
[
"content"
:
"Show me a code snippet of a website's sticky header in CSS and JavaScript."
"Tell me a fun fact"
,
}
"about the Roman Empire"
]
],
}
"content"
:
"Tell me a random fun fact about the Roman Empire"
}
},
{
"title"
:
[
"Show me a code snippet"
,
"of a website's sticky header"
],
"content"
:
"Show me a code snippet of a website's sticky header in CSS and JavaScript."
}
]
}
}
\ No newline at end of file
backend/main.py
View file @
562e40a7
...
@@ -32,6 +32,7 @@ from utils.utils import get_admin_user
...
@@ -32,6 +32,7 @@ from utils.utils import get_admin_user
from
apps.rag.utils
import
rag_messages
from
apps.rag.utils
import
rag_messages
from
config
import
(
from
config
import
(
CONFIG_DATA
,
WEBUI_NAME
,
WEBUI_NAME
,
ENV
,
ENV
,
VERSION
,
VERSION
,
...
@@ -49,6 +50,7 @@ logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
...
@@ -49,6 +50,7 @@ logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL)
log
=
logging
.
getLogger
(
__name__
)
log
=
logging
.
getLogger
(
__name__
)
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MAIN"
])
log
.
setLevel
(
SRC_LOG_LEVELS
[
"MAIN"
])
class
SPAStaticFiles
(
StaticFiles
):
class
SPAStaticFiles
(
StaticFiles
):
async
def
get_response
(
self
,
path
:
str
,
scope
):
async
def
get_response
(
self
,
path
:
str
,
scope
):
try
:
try
:
...
@@ -88,7 +90,6 @@ class RAGMiddleware(BaseHTTPMiddleware):
...
@@ -88,7 +90,6 @@ class RAGMiddleware(BaseHTTPMiddleware):
# Example: Add a new key-value pair or modify existing ones
# Example: Add a new key-value pair or modify existing ones
# data["modified"] = True # Example modification
# data["modified"] = True # Example modification
if
"docs"
in
data
:
if
"docs"
in
data
:
data
=
{
**
data
}
data
=
{
**
data
}
data
[
"messages"
]
=
rag_messages
(
data
[
"messages"
]
=
rag_messages
(
data
[
"docs"
],
data
[
"docs"
],
...
@@ -163,11 +164,15 @@ app.mount("/rag/api/v1", rag_app)
...
@@ -163,11 +164,15 @@ app.mount("/rag/api/v1", rag_app)
@
app
.
get
(
"/api/config"
)
@
app
.
get
(
"/api/config"
)
async
def
get_app_config
():
async
def
get_app_config
():
return
{
return
{
"status"
:
True
,
"status"
:
True
,
"name"
:
WEBUI_NAME
,
"name"
:
WEBUI_NAME
,
"version"
:
VERSION
,
"version"
:
VERSION
,
"default_locale"
:
(
CONFIG_DATA
[
"ui"
][
"default_locale"
]
if
"ui"
in
CONFIG_DATA
and
"default_locale"
in
CONFIG_DATA
[
"ui"
]
else
"en-US"
),
"images"
:
images_app
.
state
.
ENABLED
,
"images"
:
images_app
.
state
.
ENABLED
,
"default_models"
:
webui_app
.
state
.
DEFAULT_MODELS
,
"default_models"
:
webui_app
.
state
.
DEFAULT_MODELS
,
"default_prompt_suggestions"
:
webui_app
.
state
.
DEFAULT_PROMPT_SUGGESTIONS
,
"default_prompt_suggestions"
:
webui_app
.
state
.
DEFAULT_PROMPT_SUGGESTIONS
,
...
@@ -192,7 +197,6 @@ class ModelFilterConfigForm(BaseModel):
...
@@ -192,7 +197,6 @@ class ModelFilterConfigForm(BaseModel):
async
def
update_model_filter_config
(
async
def
update_model_filter_config
(
form_data
:
ModelFilterConfigForm
,
user
=
Depends
(
get_admin_user
)
form_data
:
ModelFilterConfigForm
,
user
=
Depends
(
get_admin_user
)
):
):
app
.
state
.
MODEL_FILTER_ENABLED
=
form_data
.
enabled
app
.
state
.
MODEL_FILTER_ENABLED
=
form_data
.
enabled
app
.
state
.
MODEL_FILTER_LIST
=
form_data
.
models
app
.
state
.
MODEL_FILTER_LIST
=
form_data
.
models
...
@@ -202,6 +206,9 @@ async def update_model_filter_config(
...
@@ -202,6 +206,9 @@ async def update_model_filter_config(
openai_app
.
state
.
MODEL_FILTER_ENABLED
=
app
.
state
.
MODEL_FILTER_ENABLED
openai_app
.
state
.
MODEL_FILTER_ENABLED
=
app
.
state
.
MODEL_FILTER_ENABLED
openai_app
.
state
.
MODEL_FILTER_LIST
=
app
.
state
.
MODEL_FILTER_LIST
openai_app
.
state
.
MODEL_FILTER_LIST
=
app
.
state
.
MODEL_FILTER_LIST
litellm_app
.
state
.
MODEL_FILTER_ENABLED
=
app
.
state
.
MODEL_FILTER_ENABLED
litellm_app
.
state
.
MODEL_FILTER_LIST
=
app
.
state
.
MODEL_FILTER_LIST
return
{
return
{
"enabled"
:
app
.
state
.
MODEL_FILTER_ENABLED
,
"enabled"
:
app
.
state
.
MODEL_FILTER_ENABLED
,
"models"
:
app
.
state
.
MODEL_FILTER_LIST
,
"models"
:
app
.
state
.
MODEL_FILTER_LIST
,
...
@@ -232,7 +239,6 @@ async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)):
...
@@ -232,7 +239,6 @@ async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)):
@
app
.
get
(
"/api/version"
)
@
app
.
get
(
"/api/version"
)
async
def
get_app_config
():
async
def
get_app_config
():
return
{
return
{
"version"
:
VERSION
,
"version"
:
VERSION
,
}
}
...
@@ -240,7 +246,7 @@ async def get_app_config():
...
@@ -240,7 +246,7 @@ async def get_app_config():
@
app
.
get
(
"/api/changelog"
)
@
app
.
get
(
"/api/changelog"
)
async
def
get_app_changelog
():
async
def
get_app_changelog
():
return
CHANGELOG
return
{
key
:
CHANGELOG
[
key
]
for
idx
,
key
in
enumerate
(
CHANGELOG
)
if
idx
<
5
}
@
app
.
get
(
"/api/version/updates"
)
@
app
.
get
(
"/api/version/updates"
)
...
...
Prev
1
2
3
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