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
abf212c2
"magic_pdf/vscode:/vscode.git/clone" did not exist on "61e88cb2d4359039e5a08ab54d4277efc0c5ad9e"
Commit
abf212c2
authored
Jun 23, 2024
by
Timothy J. Baek
Browse files
enh: tools & functions frontmatter
parent
8b998701
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
212 additions
and
175 deletions
+212
-175
backend/apps/webui/main.py
backend/apps/webui/main.py
+3
-1
backend/apps/webui/models/functions.py
backend/apps/webui/models/functions.py
+1
-0
backend/apps/webui/models/tools.py
backend/apps/webui/models/tools.py
+1
-0
backend/apps/webui/routers/functions.py
backend/apps/webui/routers/functions.py
+99
-95
backend/apps/webui/routers/tools.py
backend/apps/webui/routers/tools.py
+73
-71
backend/apps/webui/utils.py
backend/apps/webui/utils.py
+26
-3
backend/main.py
backend/main.py
+9
-5
No files found.
backend/apps/webui/main.py
View file @
abf212c2
...
...
@@ -109,7 +109,9 @@ async def get_pipe_models():
for
pipe
in
pipes
:
# Check if function is already loaded
if
pipe
.
id
not
in
app
.
state
.
FUNCTIONS
:
function_module
,
function_type
=
load_function_module_by_id
(
pipe
.
id
)
function_module
,
function_type
,
frontmatter
=
load_function_module_by_id
(
pipe
.
id
)
app
.
state
.
FUNCTIONS
[
pipe
.
id
]
=
function_module
else
:
function_module
=
app
.
state
.
FUNCTIONS
[
pipe
.
id
]
...
...
backend/apps/webui/models/functions.py
View file @
abf212c2
...
...
@@ -39,6 +39,7 @@ class Function(Model):
class
FunctionMeta
(
BaseModel
):
description
:
Optional
[
str
]
=
None
manifest
:
Optional
[
dict
]
=
{}
class
FunctionModel
(
BaseModel
):
...
...
backend/apps/webui/models/tools.py
View file @
abf212c2
...
...
@@ -38,6 +38,7 @@ class Tool(Model):
class
ToolMeta
(
BaseModel
):
description
:
Optional
[
str
]
=
None
manifest
:
Optional
[
dict
]
=
{}
class
ToolModel
(
BaseModel
):
...
...
backend/apps/webui/routers/functions.py
View file @
abf212c2
...
...
@@ -69,7 +69,10 @@ async def create_new_function(
with
open
(
function_path
,
"w"
)
as
function_file
:
function_file
.
write
(
form_data
.
content
)
function_module
,
function_type
=
load_function_module_by_id
(
form_data
.
id
)
function_module
,
function_type
,
frontmatter
=
load_function_module_by_id
(
form_data
.
id
)
form_data
.
meta
.
manifest
=
frontmatter
FUNCTIONS
=
request
.
app
.
state
.
FUNCTIONS
FUNCTIONS
[
form_data
.
id
]
=
function_module
...
...
@@ -117,6 +120,97 @@ async def get_function_by_id(id: str, user=Depends(get_admin_user)):
)
############################
# ToggleFunctionById
############################
@
router
.
post
(
"/id/{id}/toggle"
,
response_model
=
Optional
[
FunctionModel
])
async
def
toggle_function_by_id
(
id
:
str
,
user
=
Depends
(
get_admin_user
)):
function
=
Functions
.
get_function_by_id
(
id
)
if
function
:
function
=
Functions
.
update_function_by_id
(
id
,
{
"is_active"
:
not
function
.
is_active
}
)
if
function
:
return
function
else
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
"Error updating function"
),
)
else
:
raise
HTTPException
(
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
detail
=
ERROR_MESSAGES
.
NOT_FOUND
,
)
############################
# UpdateFunctionById
############################
@
router
.
post
(
"/id/{id}/update"
,
response_model
=
Optional
[
FunctionModel
])
async
def
update_function_by_id
(
request
:
Request
,
id
:
str
,
form_data
:
FunctionForm
,
user
=
Depends
(
get_admin_user
)
):
function_path
=
os
.
path
.
join
(
FUNCTIONS_DIR
,
f
"
{
id
}
.py"
)
try
:
with
open
(
function_path
,
"w"
)
as
function_file
:
function_file
.
write
(
form_data
.
content
)
function_module
,
function_type
,
frontmatter
=
load_function_module_by_id
(
id
)
form_data
.
meta
.
manifest
=
frontmatter
FUNCTIONS
=
request
.
app
.
state
.
FUNCTIONS
FUNCTIONS
[
id
]
=
function_module
updated
=
{
**
form_data
.
model_dump
(
exclude
=
{
"id"
}),
"type"
:
function_type
}
print
(
updated
)
function
=
Functions
.
update_function_by_id
(
id
,
updated
)
if
function
:
return
function
else
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
"Error updating function"
),
)
except
Exception
as
e
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
e
),
)
############################
# DeleteFunctionById
############################
@
router
.
delete
(
"/id/{id}/delete"
,
response_model
=
bool
)
async
def
delete_function_by_id
(
request
:
Request
,
id
:
str
,
user
=
Depends
(
get_admin_user
)
):
result
=
Functions
.
delete_function_by_id
(
id
)
if
result
:
FUNCTIONS
=
request
.
app
.
state
.
FUNCTIONS
if
id
in
FUNCTIONS
:
del
FUNCTIONS
[
id
]
# delete the function file
function_path
=
os
.
path
.
join
(
FUNCTIONS_DIR
,
f
"
{
id
}
.py"
)
os
.
remove
(
function_path
)
return
result
############################
# GetFunctionValves
############################
...
...
@@ -155,7 +249,7 @@ async def get_function_valves_spec_by_id(
if
id
in
request
.
app
.
state
.
FUNCTIONS
:
function_module
=
request
.
app
.
state
.
FUNCTIONS
[
id
]
else
:
function_module
,
function_type
=
load_function_module_by_id
(
id
)
function_module
,
function_type
,
frontmatter
=
load_function_module_by_id
(
id
)
request
.
app
.
state
.
FUNCTIONS
[
id
]
=
function_module
if
hasattr
(
function_module
,
"Valves"
):
...
...
@@ -184,7 +278,7 @@ async def update_function_valves_by_id(
if
id
in
request
.
app
.
state
.
FUNCTIONS
:
function_module
=
request
.
app
.
state
.
FUNCTIONS
[
id
]
else
:
function_module
,
function_type
=
load_function_module_by_id
(
id
)
function_module
,
function_type
,
frontmatter
=
load_function_module_by_id
(
id
)
request
.
app
.
state
.
FUNCTIONS
[
id
]
=
function_module
if
hasattr
(
function_module
,
"Valves"
):
...
...
@@ -247,7 +341,7 @@ async def get_function_user_valves_spec_by_id(
if
id
in
request
.
app
.
state
.
FUNCTIONS
:
function_module
=
request
.
app
.
state
.
FUNCTIONS
[
id
]
else
:
function_module
,
function_type
=
load_function_module_by_id
(
id
)
function_module
,
function_type
,
frontmatter
=
load_function_module_by_id
(
id
)
request
.
app
.
state
.
FUNCTIONS
[
id
]
=
function_module
if
hasattr
(
function_module
,
"UserValves"
):
...
...
@@ -271,7 +365,7 @@ async def update_function_user_valves_by_id(
if
id
in
request
.
app
.
state
.
FUNCTIONS
:
function_module
=
request
.
app
.
state
.
FUNCTIONS
[
id
]
else
:
function_module
,
function_type
=
load_function_module_by_id
(
id
)
function_module
,
function_type
,
frontmatter
=
load_function_module_by_id
(
id
)
request
.
app
.
state
.
FUNCTIONS
[
id
]
=
function_module
if
hasattr
(
function_module
,
"UserValves"
):
...
...
@@ -300,93 +394,3 @@ async def update_function_user_valves_by_id(
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
detail
=
ERROR_MESSAGES
.
NOT_FOUND
,
)
############################
# ToggleFunctionById
############################
@
router
.
post
(
"/id/{id}/toggle"
,
response_model
=
Optional
[
FunctionModel
])
async
def
toggle_function_by_id
(
id
:
str
,
user
=
Depends
(
get_admin_user
)):
function
=
Functions
.
get_function_by_id
(
id
)
if
function
:
function
=
Functions
.
update_function_by_id
(
id
,
{
"is_active"
:
not
function
.
is_active
}
)
if
function
:
return
function
else
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
"Error updating function"
),
)
else
:
raise
HTTPException
(
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
detail
=
ERROR_MESSAGES
.
NOT_FOUND
,
)
############################
# UpdateFunctionById
############################
@
router
.
post
(
"/id/{id}/update"
,
response_model
=
Optional
[
FunctionModel
])
async
def
update_function_by_id
(
request
:
Request
,
id
:
str
,
form_data
:
FunctionForm
,
user
=
Depends
(
get_admin_user
)
):
function_path
=
os
.
path
.
join
(
FUNCTIONS_DIR
,
f
"
{
id
}
.py"
)
try
:
with
open
(
function_path
,
"w"
)
as
function_file
:
function_file
.
write
(
form_data
.
content
)
function_module
,
function_type
=
load_function_module_by_id
(
id
)
FUNCTIONS
=
request
.
app
.
state
.
FUNCTIONS
FUNCTIONS
[
id
]
=
function_module
updated
=
{
**
form_data
.
model_dump
(
exclude
=
{
"id"
}),
"type"
:
function_type
}
print
(
updated
)
function
=
Functions
.
update_function_by_id
(
id
,
updated
)
if
function
:
return
function
else
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
"Error updating function"
),
)
except
Exception
as
e
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
e
),
)
############################
# DeleteFunctionById
############################
@
router
.
delete
(
"/id/{id}/delete"
,
response_model
=
bool
)
async
def
delete_function_by_id
(
request
:
Request
,
id
:
str
,
user
=
Depends
(
get_admin_user
)
):
result
=
Functions
.
delete_function_by_id
(
id
)
if
result
:
FUNCTIONS
=
request
.
app
.
state
.
FUNCTIONS
if
id
in
FUNCTIONS
:
del
FUNCTIONS
[
id
]
# delete the function file
function_path
=
os
.
path
.
join
(
FUNCTIONS_DIR
,
f
"
{
id
}
.py"
)
os
.
remove
(
function_path
)
return
result
backend/apps/webui/routers/tools.py
View file @
abf212c2
...
...
@@ -74,7 +74,8 @@ async def create_new_toolkit(
with
open
(
toolkit_path
,
"w"
)
as
tool_file
:
tool_file
.
write
(
form_data
.
content
)
toolkit_module
=
load_toolkit_module_by_id
(
form_data
.
id
)
toolkit_module
,
frontmatter
=
load_toolkit_module_by_id
(
form_data
.
id
)
form_data
.
meta
.
manifest
=
frontmatter
TOOLS
=
request
.
app
.
state
.
TOOLS
TOOLS
[
form_data
.
id
]
=
toolkit_module
...
...
@@ -123,6 +124,73 @@ async def get_toolkit_by_id(id: str, user=Depends(get_admin_user)):
)
############################
# UpdateToolkitById
############################
@
router
.
post
(
"/id/{id}/update"
,
response_model
=
Optional
[
ToolModel
])
async
def
update_toolkit_by_id
(
request
:
Request
,
id
:
str
,
form_data
:
ToolForm
,
user
=
Depends
(
get_admin_user
)
):
toolkit_path
=
os
.
path
.
join
(
TOOLS_DIR
,
f
"
{
id
}
.py"
)
try
:
with
open
(
toolkit_path
,
"w"
)
as
tool_file
:
tool_file
.
write
(
form_data
.
content
)
toolkit_module
,
frontmatter
=
load_toolkit_module_by_id
(
id
)
form_data
.
meta
.
manifest
=
frontmatter
TOOLS
=
request
.
app
.
state
.
TOOLS
TOOLS
[
id
]
=
toolkit_module
specs
=
get_tools_specs
(
TOOLS
[
id
])
updated
=
{
**
form_data
.
model_dump
(
exclude
=
{
"id"
}),
"specs"
:
specs
,
}
print
(
updated
)
toolkit
=
Tools
.
update_tool_by_id
(
id
,
updated
)
if
toolkit
:
return
toolkit
else
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
"Error updating toolkit"
),
)
except
Exception
as
e
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
e
),
)
############################
# DeleteToolkitById
############################
@
router
.
delete
(
"/id/{id}/delete"
,
response_model
=
bool
)
async
def
delete_toolkit_by_id
(
request
:
Request
,
id
:
str
,
user
=
Depends
(
get_admin_user
)):
result
=
Tools
.
delete_tool_by_id
(
id
)
if
result
:
TOOLS
=
request
.
app
.
state
.
TOOLS
if
id
in
TOOLS
:
del
TOOLS
[
id
]
# delete the toolkit file
toolkit_path
=
os
.
path
.
join
(
TOOLS_DIR
,
f
"
{
id
}
.py"
)
os
.
remove
(
toolkit_path
)
return
result
############################
# GetToolValves
############################
...
...
@@ -161,7 +229,7 @@ async def get_toolkit_valves_spec_by_id(
if
id
in
request
.
app
.
state
.
TOOLS
:
toolkit_module
=
request
.
app
.
state
.
TOOLS
[
id
]
else
:
toolkit_module
=
load_toolkit_module_by_id
(
id
)
toolkit_module
,
frontmatter
=
load_toolkit_module_by_id
(
id
)
request
.
app
.
state
.
TOOLS
[
id
]
=
toolkit_module
if
hasattr
(
toolkit_module
,
"Valves"
):
...
...
@@ -189,7 +257,7 @@ async def update_toolkit_valves_by_id(
if
id
in
request
.
app
.
state
.
TOOLS
:
toolkit_module
=
request
.
app
.
state
.
TOOLS
[
id
]
else
:
toolkit_module
=
load_toolkit_module_by_id
(
id
)
toolkit_module
,
frontmatter
=
load_toolkit_module_by_id
(
id
)
request
.
app
.
state
.
TOOLS
[
id
]
=
toolkit_module
if
hasattr
(
toolkit_module
,
"Valves"
):
...
...
@@ -252,7 +320,7 @@ async def get_toolkit_user_valves_spec_by_id(
if
id
in
request
.
app
.
state
.
TOOLS
:
toolkit_module
=
request
.
app
.
state
.
TOOLS
[
id
]
else
:
toolkit_module
=
load_toolkit_module_by_id
(
id
)
toolkit_module
,
frontmatter
=
load_toolkit_module_by_id
(
id
)
request
.
app
.
state
.
TOOLS
[
id
]
=
toolkit_module
if
hasattr
(
toolkit_module
,
"UserValves"
):
...
...
@@ -276,7 +344,7 @@ async def update_toolkit_user_valves_by_id(
if
id
in
request
.
app
.
state
.
TOOLS
:
toolkit_module
=
request
.
app
.
state
.
TOOLS
[
id
]
else
:
toolkit_module
=
load_toolkit_module_by_id
(
id
)
toolkit_module
,
frontmatter
=
load_toolkit_module_by_id
(
id
)
request
.
app
.
state
.
TOOLS
[
id
]
=
toolkit_module
if
hasattr
(
toolkit_module
,
"UserValves"
):
...
...
@@ -305,69 +373,3 @@ async def update_toolkit_user_valves_by_id(
status_code
=
status
.
HTTP_401_UNAUTHORIZED
,
detail
=
ERROR_MESSAGES
.
NOT_FOUND
,
)
############################
# UpdateToolkitById
############################
@
router
.
post
(
"/id/{id}/update"
,
response_model
=
Optional
[
ToolModel
])
async
def
update_toolkit_by_id
(
request
:
Request
,
id
:
str
,
form_data
:
ToolForm
,
user
=
Depends
(
get_admin_user
)
):
toolkit_path
=
os
.
path
.
join
(
TOOLS_DIR
,
f
"
{
id
}
.py"
)
try
:
with
open
(
toolkit_path
,
"w"
)
as
tool_file
:
tool_file
.
write
(
form_data
.
content
)
toolkit_module
=
load_toolkit_module_by_id
(
id
)
TOOLS
=
request
.
app
.
state
.
TOOLS
TOOLS
[
id
]
=
toolkit_module
specs
=
get_tools_specs
(
TOOLS
[
id
])
updated
=
{
**
form_data
.
model_dump
(
exclude
=
{
"id"
}),
"specs"
:
specs
,
}
print
(
updated
)
toolkit
=
Tools
.
update_tool_by_id
(
id
,
updated
)
if
toolkit
:
return
toolkit
else
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
"Error updating toolkit"
),
)
except
Exception
as
e
:
raise
HTTPException
(
status_code
=
status
.
HTTP_400_BAD_REQUEST
,
detail
=
ERROR_MESSAGES
.
DEFAULT
(
e
),
)
############################
# DeleteToolkitById
############################
@
router
.
delete
(
"/id/{id}/delete"
,
response_model
=
bool
)
async
def
delete_toolkit_by_id
(
request
:
Request
,
id
:
str
,
user
=
Depends
(
get_admin_user
)):
result
=
Tools
.
delete_tool_by_id
(
id
)
if
result
:
TOOLS
=
request
.
app
.
state
.
TOOLS
if
id
in
TOOLS
:
del
TOOLS
[
id
]
# delete the toolkit file
toolkit_path
=
os
.
path
.
join
(
TOOLS_DIR
,
f
"
{
id
}
.py"
)
os
.
remove
(
toolkit_path
)
return
result
backend/apps/webui/utils.py
View file @
abf212c2
from
importlib
import
util
import
os
import
re
from
config
import
TOOLS_DIR
,
FUNCTIONS_DIR
def
extract_frontmatter
(
file_path
):
"""
Extract frontmatter as a dictionary from the specified file path.
"""
frontmatter
=
{}
frontmatter_pattern
=
re
.
compile
(
r
"^([a-z_]+):\s*(.*)\s*$"
,
re
.
IGNORECASE
)
with
open
(
file_path
,
"r"
,
encoding
=
"utf-8"
)
as
file
:
for
line
in
file
:
if
line
.
strip
()
==
'"""'
:
# End of frontmatter section
break
match
=
frontmatter_pattern
.
match
(
line
)
if
match
:
key
,
value
=
match
.
groups
()
frontmatter
[
key
]
=
value
return
frontmatter
def
load_toolkit_module_by_id
(
toolkit_id
):
toolkit_path
=
os
.
path
.
join
(
TOOLS_DIR
,
f
"
{
toolkit_id
}
.py"
)
spec
=
util
.
spec_from_file_location
(
toolkit_id
,
toolkit_path
)
module
=
util
.
module_from_spec
(
spec
)
frontmatter
=
extract_frontmatter
(
toolkit_path
)
try
:
spec
.
loader
.
exec_module
(
module
)
print
(
f
"Loaded module:
{
module
.
__name__
}
"
)
if
hasattr
(
module
,
"Tools"
):
return
module
.
Tools
()
return
module
.
Tools
()
,
frontmatter
else
:
raise
Exception
(
"No Tools class found"
)
except
Exception
as
e
:
...
...
@@ -28,14 +50,15 @@ def load_function_module_by_id(function_id):
spec
=
util
.
spec_from_file_location
(
function_id
,
function_path
)
module
=
util
.
module_from_spec
(
spec
)
frontmatter
=
extract_frontmatter
(
function_path
)
try
:
spec
.
loader
.
exec_module
(
module
)
print
(
f
"Loaded module:
{
module
.
__name__
}
"
)
if
hasattr
(
module
,
"Pipe"
):
return
module
.
Pipe
(),
"pipe"
return
module
.
Pipe
(),
"pipe"
,
frontmatter
elif
hasattr
(
module
,
"Filter"
):
return
module
.
Filter
(),
"filter"
return
module
.
Filter
(),
"filter"
,
frontmatter
else
:
raise
Exception
(
"No Function class found"
)
except
Exception
as
e
:
...
...
backend/main.py
View file @
abf212c2
...
...
@@ -258,7 +258,7 @@ async def get_function_call_response(
if
tool_id
in
webui_app
.
state
.
TOOLS
:
toolkit_module
=
webui_app
.
state
.
TOOLS
[
tool_id
]
else
:
toolkit_module
=
load_toolkit_module_by_id
(
tool_id
)
toolkit_module
,
frontmatter
=
load_toolkit_module_by_id
(
tool_id
)
webui_app
.
state
.
TOOLS
[
tool_id
]
=
toolkit_module
file_handler
=
False
...
...
@@ -415,8 +415,8 @@ class ChatCompletionMiddleware(BaseHTTPMiddleware):
if
filter_id
in
webui_app
.
state
.
FUNCTIONS
:
function_module
=
webui_app
.
state
.
FUNCTIONS
[
filter_id
]
else
:
function_module
,
function_type
=
load_function_module_by_id
(
filter_id
function_module
,
function_type
,
frontmatter
=
(
load_function_module_by_id
(
filter_id
)
)
webui_app
.
state
.
FUNCTIONS
[
filter_id
]
=
function_module
...
...
@@ -909,7 +909,9 @@ async def generate_chat_completions(form_data: dict, user=Depends(get_verified_u
# Check if function is already loaded
if
pipe_id
not
in
webui_app
.
state
.
FUNCTIONS
:
function_module
,
function_type
=
load_function_module_by_id
(
pipe_id
)
function_module
,
function_type
,
frontmatter
=
(
load_function_module_by_id
(
pipe_id
)
)
webui_app
.
state
.
FUNCTIONS
[
pipe_id
]
=
function_module
else
:
function_module
=
webui_app
.
state
.
FUNCTIONS
[
pipe_id
]
...
...
@@ -1155,7 +1157,9 @@ async def chat_completed(form_data: dict, user=Depends(get_verified_user)):
if
filter_id
in
webui_app
.
state
.
FUNCTIONS
:
function_module
=
webui_app
.
state
.
FUNCTIONS
[
filter_id
]
else
:
function_module
,
function_type
=
load_function_module_by_id
(
filter_id
)
function_module
,
function_type
,
frontmatter
=
(
load_function_module_by_id
(
filter_id
)
)
webui_app
.
state
.
FUNCTIONS
[
filter_id
]
=
function_module
if
hasattr
(
function_module
,
"valves"
)
and
hasattr
(
...
...
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