files.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import logging
  2. import os
  3. import shutil
  4. import uuid
  5. from pathlib import Path
  6. from typing import Optional
  7. from open_webui.apps.webui.models.files import FileForm, FileModel, Files
  8. from open_webui.apps.retrieval.main import process_file, ProcessFileForm
  9. from open_webui.config import UPLOAD_DIR
  10. from open_webui.constants import ERROR_MESSAGES
  11. from open_webui.env import SRC_LOG_LEVELS
  12. from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status
  13. from fastapi.responses import FileResponse, StreamingResponse
  14. from open_webui.utils.utils import get_admin_user, get_verified_user
  15. log = logging.getLogger(__name__)
  16. log.setLevel(SRC_LOG_LEVELS["MODELS"])
  17. router = APIRouter()
  18. ############################
  19. # Upload File
  20. ############################
  21. @router.post("/")
  22. def upload_file(file: UploadFile = File(...), user=Depends(get_verified_user)):
  23. log.info(f"file.content_type: {file.content_type}")
  24. try:
  25. unsanitized_filename = file.filename
  26. filename = os.path.basename(unsanitized_filename)
  27. # replace filename with uuid
  28. id = str(uuid.uuid4())
  29. name = filename
  30. filename = f"{id}_{filename}"
  31. file_path = f"{UPLOAD_DIR}/{filename}"
  32. contents = file.file.read()
  33. with open(file_path, "wb") as f:
  34. f.write(contents)
  35. f.close()
  36. file = Files.insert_new_file(
  37. user.id,
  38. FileForm(
  39. **{
  40. "id": id,
  41. "filename": filename,
  42. "meta": {
  43. "name": name,
  44. "content_type": file.content_type,
  45. "size": len(contents),
  46. "path": file_path,
  47. },
  48. }
  49. ),
  50. )
  51. try:
  52. process_file(ProcessFileForm(file_id=id))
  53. file = Files.get_file_by_id(id=id)
  54. except Exception as e:
  55. log.exception(e)
  56. log.error(f"Error processing file: {file.id}")
  57. if file:
  58. return file
  59. else:
  60. raise HTTPException(
  61. status_code=status.HTTP_400_BAD_REQUEST,
  62. detail=ERROR_MESSAGES.DEFAULT("Error uploading file"),
  63. )
  64. except Exception as e:
  65. log.exception(e)
  66. raise HTTPException(
  67. status_code=status.HTTP_400_BAD_REQUEST,
  68. detail=ERROR_MESSAGES.DEFAULT(e),
  69. )
  70. ############################
  71. # List Files
  72. ############################
  73. @router.get("/", response_model=list[FileModel])
  74. async def list_files(user=Depends(get_verified_user)):
  75. if user.role == "admin":
  76. files = Files.get_files()
  77. else:
  78. files = Files.get_files_by_user_id(user.id)
  79. return files
  80. ############################
  81. # Delete All Files
  82. ############################
  83. @router.delete("/all")
  84. async def delete_all_files(user=Depends(get_admin_user)):
  85. result = Files.delete_all_files()
  86. if result:
  87. folder = f"{UPLOAD_DIR}"
  88. try:
  89. # Check if the directory exists
  90. if os.path.exists(folder):
  91. # Iterate over all the files and directories in the specified directory
  92. for filename in os.listdir(folder):
  93. file_path = os.path.join(folder, filename)
  94. try:
  95. if os.path.isfile(file_path) or os.path.islink(file_path):
  96. os.unlink(file_path) # Remove the file or link
  97. elif os.path.isdir(file_path):
  98. shutil.rmtree(file_path) # Remove the directory
  99. except Exception as e:
  100. print(f"Failed to delete {file_path}. Reason: {e}")
  101. else:
  102. print(f"The directory {folder} does not exist")
  103. except Exception as e:
  104. print(f"Failed to process the directory {folder}. Reason: {e}")
  105. return {"message": "All files deleted successfully"}
  106. else:
  107. raise HTTPException(
  108. status_code=status.HTTP_400_BAD_REQUEST,
  109. detail=ERROR_MESSAGES.DEFAULT("Error deleting files"),
  110. )
  111. ############################
  112. # Get File By Id
  113. ############################
  114. @router.get("/{id}", response_model=Optional[FileModel])
  115. async def get_file_by_id(id: str, user=Depends(get_verified_user)):
  116. file = Files.get_file_by_id(id)
  117. if file and (file.user_id == user.id or user.role == "admin"):
  118. return file
  119. else:
  120. raise HTTPException(
  121. status_code=status.HTTP_404_NOT_FOUND,
  122. detail=ERROR_MESSAGES.NOT_FOUND,
  123. )
  124. ############################
  125. # Get File Content By Id
  126. ############################
  127. @router.get("/{id}/content", response_model=Optional[FileModel])
  128. async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
  129. file = Files.get_file_by_id(id)
  130. if file and (file.user_id == user.id or user.role == "admin"):
  131. file_path = Path(file.meta["path"])
  132. # Check if the file already exists in the cache
  133. if file_path.is_file():
  134. print(f"file_path: {file_path}")
  135. return FileResponse(file_path)
  136. else:
  137. raise HTTPException(
  138. status_code=status.HTTP_404_NOT_FOUND,
  139. detail=ERROR_MESSAGES.NOT_FOUND,
  140. )
  141. else:
  142. raise HTTPException(
  143. status_code=status.HTTP_404_NOT_FOUND,
  144. detail=ERROR_MESSAGES.NOT_FOUND,
  145. )
  146. @router.get("/{id}/content/text")
  147. async def get_file_text_content_by_id(id: str, user=Depends(get_verified_user)):
  148. file = Files.get_file_by_id(id)
  149. if file and (file.user_id == user.id or user.role == "admin"):
  150. return {"text": file.data.get("content")}
  151. else:
  152. raise HTTPException(
  153. status_code=status.HTTP_404_NOT_FOUND,
  154. detail=ERROR_MESSAGES.NOT_FOUND,
  155. )
  156. @router.get("/{id}/content/{file_name}", response_model=Optional[FileModel])
  157. async def get_file_content_by_id(id: str, user=Depends(get_verified_user)):
  158. file = Files.get_file_by_id(id)
  159. if file and (file.user_id == user.id or user.role == "admin"):
  160. file_path = file.meta.get("path")
  161. if file_path:
  162. file_path = Path(file_path)
  163. # Check if the file already exists in the cache
  164. if file_path.is_file():
  165. print(f"file_path: {file_path}")
  166. return FileResponse(file_path)
  167. else:
  168. raise HTTPException(
  169. status_code=status.HTTP_404_NOT_FOUND,
  170. detail=ERROR_MESSAGES.NOT_FOUND,
  171. )
  172. else:
  173. # File path doesn’t exist, return the content as .txt if possible
  174. file_content = file.content.get("content", "")
  175. file_name = file.filename
  176. # Create a generator that encodes the file content
  177. def generator():
  178. yield file_content.encode("utf-8")
  179. return StreamingResponse(
  180. generator(),
  181. media_type="text/plain",
  182. headers={"Content-Disposition": f"attachment; filename={file_name}"},
  183. )
  184. else:
  185. raise HTTPException(
  186. status_code=status.HTTP_404_NOT_FOUND,
  187. detail=ERROR_MESSAGES.NOT_FOUND,
  188. )
  189. ############################
  190. # Delete File By Id
  191. ############################
  192. @router.delete("/{id}")
  193. async def delete_file_by_id(id: str, user=Depends(get_verified_user)):
  194. file = Files.get_file_by_id(id)
  195. if file and (file.user_id == user.id or user.role == "admin"):
  196. result = Files.delete_file_by_id(id)
  197. if result:
  198. return {"message": "File deleted successfully"}
  199. else:
  200. raise HTTPException(
  201. status_code=status.HTTP_400_BAD_REQUEST,
  202. detail=ERROR_MESSAGES.DEFAULT("Error deleting file"),
  203. )
  204. else:
  205. raise HTTPException(
  206. status_code=status.HTTP_404_NOT_FOUND,
  207. detail=ERROR_MESSAGES.NOT_FOUND,
  208. )