tools.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. from fastapi import Depends, FastAPI, HTTPException, status
  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 utils.utils import get_current_user, get_admin_user
  9. from utils.tools import get_tools_specs
  10. from constants import ERROR_MESSAGES
  11. from importlib import util
  12. import os
  13. from config import DATA_DIR
  14. TOOLS_DIR = f"{DATA_DIR}/tools"
  15. os.makedirs(TOOLS_DIR, exist_ok=True)
  16. TOOLS = {}
  17. router = APIRouter()
  18. def load_toolkit_module_from_path(tools_id, tools_path):
  19. spec = util.spec_from_file_location(tools_id, tools_path)
  20. module = util.module_from_spec(spec)
  21. try:
  22. spec.loader.exec_module(module)
  23. print(f"Loaded module: {module.__name__}")
  24. if hasattr(module, "Tools"):
  25. return module.Tools()
  26. else:
  27. raise Exception("No Tools class found")
  28. except Exception as e:
  29. print(f"Error loading module: {tools_id}")
  30. # Move the file to the error folder
  31. os.rename(tools_path, f"{tools_path}.error")
  32. raise e
  33. ############################
  34. # GetToolkits
  35. ############################
  36. @router.get("/", response_model=List[ToolResponse])
  37. async def get_toolkits(user=Depends(get_current_user)):
  38. toolkits = [ToolResponse(**toolkit) for toolkit in Tools.get_tools()]
  39. return toolkits
  40. ############################
  41. # CreateNewToolKit
  42. ############################
  43. @router.post("/create", response_model=Optional[ToolResponse])
  44. async def create_new_toolkit(form_data: ToolForm, user=Depends(get_admin_user)):
  45. toolkit = Tools.get_tool_by_id(form_data.id)
  46. if toolkit == None:
  47. toolkit_path = os.path.join(TOOLS_DIR, f"{form_data.id}.py")
  48. try:
  49. with open(toolkit_path, "w") as tool_file:
  50. tool_file.write(form_data.content)
  51. toolkit_module = load_toolkit_module_from_path(form_data.id, toolkit_path)
  52. TOOLS[form_data.id] = toolkit_module
  53. specs = get_tools_specs(TOOLS[form_data.id])
  54. toolkit = Tools.insert_new_tool(user.id, form_data, specs)
  55. if toolkit:
  56. return ToolResponse(**toolkit)
  57. else:
  58. raise HTTPException(
  59. status_code=status.HTTP_400_BAD_REQUEST,
  60. detail=ERROR_MESSAGES.FILE_EXISTS,
  61. )
  62. except Exception as e:
  63. raise HTTPException(
  64. status_code=status.HTTP_400_BAD_REQUEST,
  65. detail=ERROR_MESSAGES.DEFAULT(e),
  66. )
  67. else:
  68. raise HTTPException(
  69. status_code=status.HTTP_400_BAD_REQUEST,
  70. detail=ERROR_MESSAGES.NAME_TAG_TAKEN,
  71. )
  72. ############################
  73. # GetToolkitById
  74. ############################
  75. @router.get("/id/{id}", response_model=Optional[ToolResponse])
  76. async def get_toolkit_by_id(id: str, user=Depends(get_admin_user)):
  77. toolkit = Tools.get_tool_by_id(id)
  78. if toolkit:
  79. return ToolResponse(**toolkit)
  80. else:
  81. raise HTTPException(
  82. status_code=status.HTTP_401_UNAUTHORIZED,
  83. detail=ERROR_MESSAGES.NOT_FOUND,
  84. )
  85. ############################
  86. # UpdateToolkitById
  87. ############################
  88. @router.post("/id/{id}/update", response_model=Optional[ToolResponse])
  89. async def update_toolkit_by_id(
  90. id: str, form_data: ToolForm, user=Depends(get_admin_user)
  91. ):
  92. toolkit_path = os.path.join(TOOLS_DIR, f"{id}.py")
  93. try:
  94. with open(toolkit_path, "w") as tool_file:
  95. tool_file.write(form_data.content)
  96. toolkit_module = load_toolkit_module_from_path(id, toolkit_path)
  97. TOOLS[id] = toolkit_module
  98. specs = get_tools_specs(TOOLS[id])
  99. toolkit = Tools.update_tool_by_id(
  100. id, {**form_data.model_dump(), "specs": specs}
  101. )
  102. if toolkit:
  103. return ToolResponse(**toolkit)
  104. else:
  105. raise HTTPException(
  106. status_code=status.HTTP_400_BAD_REQUEST,
  107. detail=ERROR_MESSAGES.DEFAULT("Error updating toolkit"),
  108. )
  109. except Exception as e:
  110. raise HTTPException(
  111. status_code=status.HTTP_400_BAD_REQUEST,
  112. detail=ERROR_MESSAGES.DEFAULT(e),
  113. )
  114. ############################
  115. # DeleteToolkitById
  116. ############################
  117. @router.delete("/id/{id}/delete", response_model=bool)
  118. async def delete_toolkit_by_id(id: str, user=Depends(get_admin_user)):
  119. result = Tools.delete_tool_by_id(id)
  120. return result