files.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import io
  2. import os
  3. import urllib.parse
  4. from typing import Optional, List
  5. from fastapi import APIRouter, Depends, UploadFile, Form, HTTPException, Query
  6. from starlette.responses import StreamingResponse
  7. from sqlalchemy.ext.asyncio import AsyncSession
  8. from app.api.deps import get_async_session
  9. from app.models import File
  10. from app.schemas.common import DeleteResponse
  11. from app.schemas.files import ListFilesResponse
  12. from app.services.file.file import FileService
  13. router = APIRouter()
  14. # 限制文件大小
  15. max_size = 512 * 1024 * 1024
  16. # 支持的文件类型
  17. file_ext = [".csv", ".docx", ".html", ".json", ".md", ".pdf", ".pptx", ".txt",
  18. ".xlsx", ".gif", ".png", ".jpg", ".jpeg", ".svg", ".mp3", ".mp4"]
  19. @router.get("", response_model=ListFilesResponse)
  20. async def list_files(
  21. *,
  22. purpose: Optional[str] = None,
  23. file_ids: Optional[List[str]] = Query(None, alias="ids[]"),
  24. session: AsyncSession = Depends(get_async_session),
  25. ) -> ListFilesResponse:
  26. """
  27. Returns a list of files that belong to the user's organization.
  28. """
  29. files = await FileService.get_file_list(session=session, purpose=purpose, file_ids=file_ids)
  30. return ListFilesResponse(data=files)
  31. @router.post("", response_model=File)
  32. async def create_file(
  33. *, session: AsyncSession = Depends(get_async_session), purpose: str = Form(default="assistants"), file: UploadFile
  34. ) -> File:
  35. """
  36. The size of individual files can be a maximum of 512 MB. See the [Assistants Tools guide]
  37. (/docs/assistants/tools) to learn more about the types of files supported.
  38. """
  39. # 判断后缀名
  40. _, file_extension = os.path.splitext(file.filename)
  41. if file_extension not in file_ext:
  42. raise HTTPException(status_code=400, detail=f"文件类型{file_extension}暂时不支持")
  43. # 判断文件大小
  44. if file.size == 0 or file.size > max_size:
  45. raise HTTPException(status_code=413, detail="File too large")
  46. print(FileService)
  47. return await FileService.create_file(session=session, purpose=purpose, file=file)
  48. @router.delete("/{file_id}", response_model=DeleteResponse)
  49. async def delete_file(*, session: AsyncSession = Depends(get_async_session), file_id: str) -> DeleteResponse:
  50. """
  51. Delete a file.
  52. """
  53. return await FileService.delete_file(session=session, file_id=file_id)
  54. @router.get("/{file_id}", response_model=File)
  55. async def retrieve_file(*, session: AsyncSession = Depends(get_async_session), file_id: str) -> File:
  56. """
  57. Returns information about a specific file.
  58. """
  59. return await FileService.get_file(session=session, file_id=file_id)
  60. @router.get("/{file_id}/content", response_class=StreamingResponse)
  61. async def download_file(*, file_id: str, session: AsyncSession = Depends(get_async_session)):
  62. """
  63. Returns the contents of the specified file.
  64. """
  65. file_data, filename = await FileService.get_file_content(session=session, file_id=file_id)
  66. response = StreamingResponse(io.BytesIO(file_data), media_type="application/octet-stream")
  67. response.headers["Content-Disposition"] = f"attachment; filename*=UTF-8''{urllib.parse.quote(filename)}"
  68. response.headers["Content-Type"] = "application/octet-stream"
  69. return response