open-webui/backend/apps/webui/routers/tools.py

382 lines
11 KiB
Python
Raw Normal View History

2024-06-11 05:38:48 +00:00
from fastapi import Depends, FastAPI, HTTPException, status, Request
2024-06-11 03:39:55 +00:00
from datetime import datetime, timedelta
from typing import List, Union, Optional
from fastapi import APIRouter
from pydantic import BaseModel
import json
2024-06-22 18:26:33 +00:00
from apps.webui.models.users import Users
2024-06-11 03:39:55 +00:00
from apps.webui.models.tools import Tools, ToolForm, ToolModel, ToolResponse
2024-06-11 06:40:27 +00:00
from apps.webui.utils import load_toolkit_module_by_id
2024-06-11 03:39:55 +00:00
2024-06-22 18:26:33 +00:00
from utils.utils import get_admin_user, get_verified_user
2024-06-11 03:39:55 +00:00
from utils.tools import get_tools_specs
from constants import ERROR_MESSAGES
from importlib import util
import os
2024-06-19 01:07:51 +00:00
from pathlib import Path
2024-06-11 03:39:55 +00:00
2024-06-19 01:07:51 +00:00
from config import DATA_DIR, CACHE_DIR
2024-06-11 03:39:55 +00:00
2024-06-11 06:40:27 +00:00
2024-06-11 03:39:55 +00:00
TOOLS_DIR = f"{DATA_DIR}/tools"
os.makedirs(TOOLS_DIR, exist_ok=True)
router = APIRouter()
############################
# GetToolkits
############################
@router.get("/", response_model=List[ToolResponse])
async def get_toolkits(user=Depends(get_verified_user)):
2024-06-11 04:33:46 +00:00
toolkits = [toolkit for toolkit in Tools.get_tools()]
return toolkits
############################
# ExportToolKits
############################
@router.get("/export", response_model=List[ToolModel])
async def get_toolkits(user=Depends(get_admin_user)):
toolkits = [toolkit for toolkit in Tools.get_tools()]
2024-06-11 03:39:55 +00:00
return toolkits
############################
# CreateNewToolKit
############################
@router.post("/create", response_model=Optional[ToolResponse])
2024-06-11 05:38:48 +00:00
async def create_new_toolkit(
request: Request,
form_data: ToolForm,
user=Depends(get_admin_user),
2024-06-11 05:38:48 +00:00
):
2024-06-11 04:59:06 +00:00
if not form_data.id.isidentifier():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Only alphanumeric characters and underscores are allowed in the id",
)
2024-06-11 05:10:53 +00:00
form_data.id = form_data.id.lower()
toolkit = Tools.get_tool_by_id(form_data.id)
2024-06-11 03:39:55 +00:00
if toolkit == None:
toolkit_path = os.path.join(TOOLS_DIR, f"{form_data.id}.py")
try:
with open(toolkit_path, "w") as tool_file:
tool_file.write(form_data.content)
2024-06-24 03:31:40 +00:00
toolkit_module, frontmatter = load_toolkit_module_by_id(form_data.id)
form_data.meta.manifest = frontmatter
2024-06-11 05:38:48 +00:00
TOOLS = request.app.state.TOOLS
2024-06-11 03:39:55 +00:00
TOOLS[form_data.id] = toolkit_module
specs = get_tools_specs(TOOLS[form_data.id])
toolkit = Tools.insert_new_tool(user.id, form_data, specs)
2024-06-11 03:39:55 +00:00
2024-06-19 01:07:51 +00:00
tool_cache_dir = Path(CACHE_DIR) / "tools" / form_data.id
tool_cache_dir.mkdir(parents=True, exist_ok=True)
2024-06-11 03:39:55 +00:00
if toolkit:
2024-06-11 04:33:46 +00:00
return toolkit
2024-06-11 03:39:55 +00:00
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
2024-06-11 21:30:18 +00:00
detail=ERROR_MESSAGES.DEFAULT("Error creating toolkit"),
2024-06-11 03:39:55 +00:00
)
except Exception as e:
2024-06-11 21:30:18 +00:00
print(e)
2024-06-11 03:39:55 +00:00
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
2024-06-11 04:33:46 +00:00
detail=ERROR_MESSAGES.ID_TAKEN,
2024-06-11 03:39:55 +00:00
)
############################
# GetToolkitById
############################
2024-06-11 04:53:51 +00:00
@router.get("/id/{id}", response_model=Optional[ToolModel])
async def get_toolkit_by_id(id: str, user=Depends(get_admin_user)):
toolkit = Tools.get_tool_by_id(id)
2024-06-11 03:39:55 +00:00
if toolkit:
2024-06-11 04:33:46 +00:00
return toolkit
2024-06-11 03:39:55 +00:00
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
2024-06-24 03:31:40 +00:00
############################
# 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),
2024-06-24 03:31:40 +00:00
):
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)
2024-06-24 03:31:40 +00:00
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)
2024-06-24 03:31:40 +00:00
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
2024-06-24 01:34:42 +00:00
############################
# GetToolValves
############################
@router.get("/id/{id}/valves", response_model=Optional[dict])
async def get_toolkit_valves_by_id(id: str, user=Depends(get_admin_user)):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
try:
2024-06-24 02:18:13 +00:00
valves = Tools.get_tool_valves_by_id(id)
return valves
2024-06-24 01:34:42 +00:00
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
2024-06-24 02:02:27 +00:00
############################
# GetToolValvesSpec
############################
@router.get("/id/{id}/valves/spec", response_model=Optional[dict])
async def get_toolkit_valves_spec_by_id(
request: Request, id: str, user=Depends(get_admin_user)
):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
if id in request.app.state.TOOLS:
toolkit_module = request.app.state.TOOLS[id]
else:
2024-06-24 03:31:40 +00:00
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
2024-06-24 02:02:27 +00:00
request.app.state.TOOLS[id] = toolkit_module
2024-06-24 02:10:52 +00:00
if hasattr(toolkit_module, "Valves"):
Valves = toolkit_module.Valves
return Valves.schema()
2024-06-24 02:02:27 +00:00
return None
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
2024-06-24 01:34:42 +00:00
############################
# UpdateToolValves
############################
@router.post("/id/{id}/valves/update", response_model=Optional[dict])
async def update_toolkit_valves_by_id(
2024-06-24 02:02:27 +00:00
request: Request, id: str, form_data: dict, user=Depends(get_admin_user)
2024-06-24 01:34:42 +00:00
):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
2024-06-24 02:02:27 +00:00
if id in request.app.state.TOOLS:
toolkit_module = request.app.state.TOOLS[id]
else:
2024-06-24 03:31:40 +00:00
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
2024-06-24 02:02:27 +00:00
request.app.state.TOOLS[id] = toolkit_module
if hasattr(toolkit_module, "Valves"):
Valves = toolkit_module.Valves
try:
2024-06-24 02:05:56 +00:00
form_data = {k: v for k, v in form_data.items() if v is not None}
2024-06-24 02:02:27 +00:00
valves = Valves(**form_data)
Tools.update_tool_valves_by_id(id, valves.model_dump())
return valves.model_dump()
except Exception as e:
print(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
2024-06-24 01:34:42 +00:00
raise HTTPException(
2024-06-24 02:02:27 +00:00
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
2024-06-24 01:34:42 +00:00
)
2024-06-24 02:02:27 +00:00
2024-06-24 01:34:42 +00:00
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
2024-06-22 18:26:33 +00:00
############################
# ToolUserValves
############################
@router.get("/id/{id}/valves/user", response_model=Optional[dict])
async def get_toolkit_user_valves_by_id(id: str, user=Depends(get_verified_user)):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
try:
user_valves = Tools.get_user_valves_by_id_and_user_id(id, user.id)
return user_valves
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
@router.get("/id/{id}/valves/user/spec", response_model=Optional[dict])
async def get_toolkit_user_valves_spec_by_id(
request: Request, id: str, user=Depends(get_verified_user)
):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
if id in request.app.state.TOOLS:
toolkit_module = request.app.state.TOOLS[id]
else:
2024-06-24 03:31:40 +00:00
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
2024-06-22 18:26:33 +00:00
request.app.state.TOOLS[id] = toolkit_module
if hasattr(toolkit_module, "UserValves"):
UserValves = toolkit_module.UserValves
return UserValves.schema()
return None
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
@router.post("/id/{id}/valves/user/update", response_model=Optional[dict])
async def update_toolkit_user_valves_by_id(
request: Request, id: str, form_data: dict, user=Depends(get_verified_user)
):
toolkit = Tools.get_tool_by_id(id)
if toolkit:
if id in request.app.state.TOOLS:
toolkit_module = request.app.state.TOOLS[id]
else:
2024-06-24 03:31:40 +00:00
toolkit_module, frontmatter = load_toolkit_module_by_id(id)
2024-06-22 18:26:33 +00:00
request.app.state.TOOLS[id] = toolkit_module
if hasattr(toolkit_module, "UserValves"):
UserValves = toolkit_module.UserValves
try:
2024-06-24 02:05:56 +00:00
form_data = {k: v for k, v in form_data.items() if v is not None}
2024-06-22 18:26:33 +00:00
user_valves = UserValves(**form_data)
Tools.update_user_valves_by_id_and_user_id(
id, user.id, user_valves.model_dump()
)
return user_valves.model_dump()
except Exception as e:
print(e)
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=ERROR_MESSAGES.DEFAULT(e),
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)
else:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=ERROR_MESSAGES.NOT_FOUND,
)