file_manager.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import base64
  2. from configs import dify_config
  3. from core.helper import ssrf_proxy
  4. from core.model_runtime.entities import (
  5. AudioPromptMessageContent,
  6. DocumentPromptMessageContent,
  7. ImagePromptMessageContent,
  8. MultiModalPromptMessageContent,
  9. VideoPromptMessageContent,
  10. )
  11. from extensions.ext_storage import storage
  12. from . import helpers
  13. from .enums import FileAttribute
  14. from .models import File, FileTransferMethod, FileType
  15. from .tool_file_parser import ToolFileParser
  16. def get_attr(*, file: File, attr: FileAttribute):
  17. match attr:
  18. case FileAttribute.TYPE:
  19. return file.type.value
  20. case FileAttribute.SIZE:
  21. return file.size
  22. case FileAttribute.NAME:
  23. return file.filename
  24. case FileAttribute.MIME_TYPE:
  25. return file.mime_type
  26. case FileAttribute.TRANSFER_METHOD:
  27. return file.transfer_method.value
  28. case FileAttribute.URL:
  29. return file.remote_url
  30. case FileAttribute.EXTENSION:
  31. return file.extension
  32. def to_prompt_message_content(
  33. f: File,
  34. /,
  35. *,
  36. image_detail_config: ImagePromptMessageContent.DETAIL | None = None,
  37. ) -> MultiModalPromptMessageContent:
  38. if f.extension is None:
  39. raise ValueError("Missing file extension")
  40. if f.mime_type is None:
  41. raise ValueError("Missing file mime_type")
  42. params = {
  43. "base64_data": _get_encoded_string(f) if dify_config.MULTIMODAL_SEND_FORMAT == "base64" else "",
  44. "url": _to_url(f) if dify_config.MULTIMODAL_SEND_FORMAT == "url" else "",
  45. "format": f.extension.removeprefix("."),
  46. "mime_type": f.mime_type,
  47. }
  48. if f.type == FileType.IMAGE:
  49. params["detail"] = image_detail_config or ImagePromptMessageContent.DETAIL.LOW
  50. prompt_class_map = {
  51. FileType.IMAGE: ImagePromptMessageContent,
  52. FileType.AUDIO: AudioPromptMessageContent,
  53. FileType.VIDEO: VideoPromptMessageContent,
  54. FileType.DOCUMENT: DocumentPromptMessageContent,
  55. }
  56. try:
  57. return prompt_class_map[f.type](**params)
  58. except KeyError:
  59. raise ValueError(f"file type {f.type} is not supported")
  60. def download(f: File, /):
  61. if f.transfer_method in (FileTransferMethod.TOOL_FILE, FileTransferMethod.LOCAL_FILE):
  62. return _download_file_content(f._storage_key)
  63. elif f.transfer_method == FileTransferMethod.REMOTE_URL:
  64. response = ssrf_proxy.get(f.remote_url, follow_redirects=True)
  65. response.raise_for_status()
  66. return response.content
  67. raise ValueError(f"unsupported transfer method: {f.transfer_method}")
  68. def _download_file_content(path: str, /):
  69. """
  70. Download and return the contents of a file as bytes.
  71. This function loads the file from storage and ensures it's in bytes format.
  72. Args:
  73. path (str): The path to the file in storage.
  74. Returns:
  75. bytes: The contents of the file as a bytes object.
  76. Raises:
  77. ValueError: If the loaded file is not a bytes object.
  78. """
  79. data = storage.load(path, stream=False)
  80. if not isinstance(data, bytes):
  81. raise ValueError(f"file {path} is not a bytes object")
  82. return data
  83. def _get_encoded_string(f: File, /):
  84. match f.transfer_method:
  85. case FileTransferMethod.REMOTE_URL:
  86. response = ssrf_proxy.get(f.remote_url, follow_redirects=True)
  87. response.raise_for_status()
  88. data = response.content
  89. case FileTransferMethod.LOCAL_FILE:
  90. data = _download_file_content(f._storage_key)
  91. case FileTransferMethod.TOOL_FILE:
  92. data = _download_file_content(f._storage_key)
  93. encoded_string = base64.b64encode(data).decode("utf-8")
  94. return encoded_string
  95. def _to_url(f: File, /):
  96. if f.transfer_method == FileTransferMethod.REMOTE_URL:
  97. if f.remote_url is None:
  98. raise ValueError("Missing file remote_url")
  99. return f.remote_url
  100. elif f.transfer_method == FileTransferMethod.LOCAL_FILE:
  101. if f.related_id is None:
  102. raise ValueError("Missing file related_id")
  103. return f.remote_url or helpers.get_signed_file_url(upload_file_id=f.related_id)
  104. elif f.transfer_method == FileTransferMethod.TOOL_FILE:
  105. # add sign url
  106. if f.related_id is None or f.extension is None:
  107. raise ValueError("Missing file related_id or extension")
  108. return ToolFileParser.get_tool_file_manager().sign_file(tool_file_id=f.related_id, extension=f.extension)
  109. else:
  110. raise ValueError(f"Unsupported transfer method: {f.transfer_method}")