您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. from collections.abc import Mapping, Sequence
  2. from typing import Any, Optional
  3. from pydantic import BaseModel, Field, model_validator
  4. from core.model_runtime.entities.message_entities import ImagePromptMessageContent
  5. from core.tools.signature import sign_tool_file
  6. from . import helpers
  7. from .constants import FILE_MODEL_IDENTITY
  8. from .enums import FileTransferMethod, FileType
  9. class ImageConfig(BaseModel):
  10. """
  11. NOTE: This part of validation is deprecated, but still used in app features "Image Upload".
  12. """
  13. number_limits: int = 0
  14. transfer_methods: Sequence[FileTransferMethod] = Field(default_factory=list)
  15. detail: ImagePromptMessageContent.DETAIL | None = None
  16. class FileUploadConfig(BaseModel):
  17. """
  18. File Upload Entity.
  19. """
  20. image_config: Optional[ImageConfig] = None
  21. allowed_file_types: Sequence[FileType] = Field(default_factory=list)
  22. allowed_file_extensions: Sequence[str] = Field(default_factory=list)
  23. allowed_file_upload_methods: Sequence[FileTransferMethod] = Field(default_factory=list)
  24. number_limits: int = 0
  25. class File(BaseModel):
  26. # NOTE: dify_model_identity is a special identifier used to distinguish between
  27. # new and old data formats during serialization and deserialization.
  28. dify_model_identity: str = FILE_MODEL_IDENTITY
  29. id: Optional[str] = None # message file id
  30. tenant_id: str
  31. type: FileType
  32. transfer_method: FileTransferMethod
  33. # If `transfer_method` is `FileTransferMethod.remote_url`, the
  34. # `remote_url` attribute must not be `None`.
  35. remote_url: Optional[str] = None # remote url
  36. # If `transfer_method` is `FileTransferMethod.local_file` or
  37. # `FileTransferMethod.tool_file`, the `related_id` attribute must not be `None`.
  38. #
  39. # It should be set to `ToolFile.id` when `transfer_method` is `tool_file`.
  40. related_id: Optional[str] = None
  41. filename: Optional[str] = None
  42. extension: Optional[str] = Field(default=None, description="File extension, should contain dot")
  43. mime_type: Optional[str] = None
  44. size: int = -1
  45. # Those properties are private, should not be exposed to the outside.
  46. _storage_key: str
  47. def __init__(
  48. self,
  49. *,
  50. id: Optional[str] = None,
  51. tenant_id: str,
  52. type: FileType,
  53. transfer_method: FileTransferMethod,
  54. remote_url: Optional[str] = None,
  55. related_id: Optional[str] = None,
  56. filename: Optional[str] = None,
  57. extension: Optional[str] = None,
  58. mime_type: Optional[str] = None,
  59. size: int = -1,
  60. storage_key: Optional[str] = None,
  61. dify_model_identity: Optional[str] = FILE_MODEL_IDENTITY,
  62. url: Optional[str] = None,
  63. ):
  64. super().__init__(
  65. id=id,
  66. tenant_id=tenant_id,
  67. type=type,
  68. transfer_method=transfer_method,
  69. remote_url=remote_url,
  70. related_id=related_id,
  71. filename=filename,
  72. extension=extension,
  73. mime_type=mime_type,
  74. size=size,
  75. dify_model_identity=dify_model_identity,
  76. url=url,
  77. )
  78. self._storage_key = str(storage_key)
  79. def to_dict(self) -> Mapping[str, str | int | None]:
  80. data = self.model_dump(mode="json")
  81. return {
  82. **data,
  83. "url": self.generate_url(),
  84. }
  85. @property
  86. def markdown(self) -> str:
  87. url = self.generate_url()
  88. if self.type == FileType.IMAGE:
  89. text = f"![{self.filename or ''}]({url})"
  90. else:
  91. text = f"[{self.filename or url}]({url})"
  92. return text
  93. def generate_url(self) -> Optional[str]:
  94. if self.transfer_method == FileTransferMethod.REMOTE_URL:
  95. return self.remote_url
  96. elif self.transfer_method == FileTransferMethod.LOCAL_FILE:
  97. if self.related_id is None:
  98. raise ValueError("Missing file related_id")
  99. return helpers.get_signed_file_url(upload_file_id=self.related_id)
  100. elif self.transfer_method == FileTransferMethod.TOOL_FILE:
  101. assert self.related_id is not None
  102. assert self.extension is not None
  103. return sign_tool_file(tool_file_id=self.related_id, extension=self.extension)
  104. def to_plugin_parameter(self) -> dict[str, Any]:
  105. return {
  106. "dify_model_identity": FILE_MODEL_IDENTITY,
  107. "mime_type": self.mime_type,
  108. "filename": self.filename,
  109. "extension": self.extension,
  110. "size": self.size,
  111. "type": self.type,
  112. "url": self.generate_url(),
  113. }
  114. @model_validator(mode="after")
  115. def validate_after(self):
  116. match self.transfer_method:
  117. case FileTransferMethod.REMOTE_URL:
  118. if not self.remote_url:
  119. raise ValueError("Missing file url")
  120. if not isinstance(self.remote_url, str) or not self.remote_url.startswith("http"):
  121. raise ValueError("Invalid file url")
  122. case FileTransferMethod.LOCAL_FILE:
  123. if not self.related_id:
  124. raise ValueError("Missing file related_id")
  125. case FileTransferMethod.TOOL_FILE:
  126. if not self.related_id:
  127. raise ValueError("Missing file related_id")
  128. return self