tools.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. from fastapi import Depends, FastAPI, HTTPException, status, Request
  2. from datetime import datetime, timedelta
  3. from typing import List, Union, Optional
  4. from fastapi import APIRouter
  5. from pydantic import BaseModel
  6. import json
  7. from apps.webui.models.tools import Tools, ToolForm, ToolModel, ToolResponse
  8. from apps.webui.utils import load_toolkit_module_by_id
  9. from utils.utils import get_current_user, get_admin_user
  10. from utils.tools import get_tools_specs
  11. from constants import ERROR_MESSAGES
  12. from importlib import util
  13. import os
  14. from pathlib import Path
  15. from config import DATA_DIR, CACHE_DIR
  16. TOOLS_DIR = f"{DATA_DIR}/tools"
  17. os.makedirs(TOOLS_DIR, exist_ok=True)
  18. router = APIRouter()
  19. ############################
  20. # GetToolkits
  21. ############################
  22. @router.get("/", response_model=List[ToolResponse])
  23. async def get_toolkits(user=Depends(get_current_user)):
  24. toolkits = [toolkit for toolkit in Tools.get_tools()]
  25. return toolkits
  26. ############################
  27. # ExportToolKits
  28. ############################
  29. @router.get("/export", response_model=List[ToolModel])
  30. async def get_toolkits(user=Depends(get_admin_user)):
  31. toolkits = [toolkit for toolkit in Tools.get_tools()]
  32. return toolkits
  33. ############################
  34. # CreateNewToolKit
  35. ############################
  36. @router.post("/create", response_model=Optional[ToolResponse])
  37. async def create_new_toolkit(
  38. request: Request, form_data: ToolForm, user=Depends(get_admin_user)
  39. ):
  40. if not form_data.id.isidentifier():
  41. raise HTTPException(
  42. status_code=status.HTTP_400_BAD_REQUEST,
  43. detail="Only alphanumeric characters and underscores are allowed in the id",
  44. )
  45. form_data.id = form_data.id.lower()
  46. toolkit = Tools.get_tool_by_id(form_data.id)
  47. if toolkit == None:
  48. toolkit_path = os.path.join(TOOLS_DIR, f"{form_data.id}.py")
  49. try:
  50. with open(toolkit_path, "w") as tool_file:
  51. tool_file.write(form_data.content)
  52. toolkit_module = load_toolkit_module_by_id(form_data.id)
  53. TOOLS = request.app.state.TOOLS
  54. TOOLS[form_data.id] = toolkit_module
  55. specs = get_tools_specs(TOOLS[form_data.id])
  56. toolkit = Tools.insert_new_tool(user.id, form_data, specs)
  57. tool_cache_dir = Path(CACHE_DIR) / "tools" / form_data.id
  58. tool_cache_dir.mkdir(parents=True, exist_ok=True)
  59. if toolkit:
  60. return toolkit
  61. else:
  62. raise HTTPException(
  63. status_code=status.HTTP_400_BAD_REQUEST,
  64. detail=ERROR_MESSAGES.DEFAULT("Error creating toolkit"),
  65. )
  66. except Exception as e:
  67. print(e)
  68. raise HTTPException(
  69. status_code=status.HTTP_400_BAD_REQUEST,
  70. detail=ERROR_MESSAGES.DEFAULT(e),
  71. )
  72. else:
  73. raise HTTPException(
  74. status_code=status.HTTP_400_BAD_REQUEST,
  75. detail=ERROR_MESSAGES.ID_TAKEN,
  76. )
  77. ############################
  78. # GetToolkitById
  79. ############################
  80. @router.get("/id/{id}", response_model=Optional[ToolModel])
  81. async def get_toolkit_by_id(id: str, user=Depends(get_admin_user)):
  82. toolkit = Tools.get_tool_by_id(id)
  83. if toolkit:
  84. return toolkit
  85. else:
  86. raise HTTPException(
  87. status_code=status.HTTP_401_UNAUTHORIZED,
  88. detail=ERROR_MESSAGES.NOT_FOUND,
  89. )
  90. ############################
  91. # UpdateToolkitById
  92. ############################
  93. @router.post("/id/{id}/update", response_model=Optional[ToolModel])
  94. async def update_toolkit_by_id(
  95. request: Request, id: str, form_data: ToolForm, user=Depends(get_admin_user)
  96. ):
  97. toolkit_path = os.path.join(TOOLS_DIR, f"{id}.py")
  98. try:
  99. with open(toolkit_path, "w") as tool_file:
  100. tool_file.write(form_data.content)
  101. toolkit_module = load_toolkit_module_by_id(id)
  102. TOOLS = request.app.state.TOOLS
  103. TOOLS[id] = toolkit_module
  104. specs = get_tools_specs(TOOLS[id])
  105. updated = {
  106. **form_data.model_dump(exclude={"id"}),
  107. "specs": specs,
  108. }
  109. print(updated)
  110. toolkit = Tools.update_tool_by_id(id, updated)
  111. if toolkit:
  112. return toolkit
  113. else:
  114. raise HTTPException(
  115. status_code=status.HTTP_400_BAD_REQUEST,
  116. detail=ERROR_MESSAGES.DEFAULT("Error updating toolkit"),
  117. )
  118. except Exception as e:
  119. raise HTTPException(
  120. status_code=status.HTTP_400_BAD_REQUEST,
  121. detail=ERROR_MESSAGES.DEFAULT(e),
  122. )
  123. ############################
  124. # DeleteToolkitById
  125. ############################
  126. @router.delete("/id/{id}/delete", response_model=bool)
  127. async def delete_toolkit_by_id(request: Request, id: str, user=Depends(get_admin_user)):
  128. result = Tools.delete_tool_by_id(id)
  129. if result:
  130. TOOLS = request.app.state.TOOLS
  131. if id in TOOLS:
  132. del TOOLS[id]
  133. # delete the toolkit file
  134. toolkit_path = os.path.join(TOOLS_DIR, f"{id}.py")
  135. os.remove(toolkit_path)
  136. return result