Spaces:
Paused
Paused
| from collections.abc import Mapping, Sequence | |
| from typing import Optional | |
| from pydantic import BaseModel, Field, model_validator | |
| from core.model_runtime.entities.message_entities import ImagePromptMessageContent | |
| from . import helpers | |
| from .constants import FILE_MODEL_IDENTITY | |
| from .enums import FileTransferMethod, FileType | |
| from .tool_file_parser import ToolFileParser | |
| class ImageConfig(BaseModel): | |
| """ | |
| NOTE: This part of validation is deprecated, but still used in app features "Image Upload". | |
| """ | |
| number_limits: int = 0 | |
| transfer_methods: Sequence[FileTransferMethod] = Field(default_factory=list) | |
| detail: ImagePromptMessageContent.DETAIL | None = None | |
| class FileExtraConfig(BaseModel): | |
| """ | |
| File Upload Entity. | |
| """ | |
| image_config: Optional[ImageConfig] = None | |
| allowed_file_types: Sequence[FileType] = Field(default_factory=list) | |
| allowed_extensions: Sequence[str] = Field(default_factory=list) | |
| allowed_upload_methods: Sequence[FileTransferMethod] = Field(default_factory=list) | |
| number_limits: int = 0 | |
| class File(BaseModel): | |
| dify_model_identity: str = FILE_MODEL_IDENTITY | |
| id: Optional[str] = None # message file id | |
| tenant_id: str | |
| type: FileType | |
| transfer_method: FileTransferMethod | |
| remote_url: Optional[str] = None # remote url | |
| related_id: Optional[str] = None | |
| filename: Optional[str] = None | |
| extension: Optional[str] = Field(default=None, description="File extension, should contains dot") | |
| mime_type: Optional[str] = None | |
| size: int = -1 | |
| _extra_config: FileExtraConfig | None = None | |
| def to_dict(self) -> Mapping[str, str | int | None]: | |
| data = self.model_dump(mode="json") | |
| return { | |
| **data, | |
| "url": self.generate_url(), | |
| } | |
| def markdown(self) -> str: | |
| url = self.generate_url() | |
| if self.type == FileType.IMAGE: | |
| text = f'' | |
| else: | |
| text = f"[{self.filename or url}]({url})" | |
| return text | |
| def generate_url(self) -> Optional[str]: | |
| if self.type == FileType.IMAGE: | |
| if self.transfer_method == FileTransferMethod.REMOTE_URL: | |
| return self.remote_url | |
| elif self.transfer_method == FileTransferMethod.LOCAL_FILE: | |
| if self.related_id is None: | |
| raise ValueError("Missing file related_id") | |
| return helpers.get_signed_file_url(upload_file_id=self.related_id) | |
| elif self.transfer_method == FileTransferMethod.TOOL_FILE: | |
| assert self.related_id is not None | |
| assert self.extension is not None | |
| return ToolFileParser.get_tool_file_manager().sign_file( | |
| tool_file_id=self.related_id, extension=self.extension | |
| ) | |
| else: | |
| if self.transfer_method == FileTransferMethod.REMOTE_URL: | |
| return self.remote_url | |
| elif self.transfer_method == FileTransferMethod.LOCAL_FILE: | |
| if self.related_id is None: | |
| raise ValueError("Missing file related_id") | |
| return helpers.get_signed_file_url(upload_file_id=self.related_id) | |
| elif self.transfer_method == FileTransferMethod.TOOL_FILE: | |
| assert self.related_id is not None | |
| assert self.extension is not None | |
| return ToolFileParser.get_tool_file_manager().sign_file( | |
| tool_file_id=self.related_id, extension=self.extension | |
| ) | |
| def validate_after(self): | |
| match self.transfer_method: | |
| case FileTransferMethod.REMOTE_URL: | |
| if not self.remote_url: | |
| raise ValueError("Missing file url") | |
| if not isinstance(self.remote_url, str) or not self.remote_url.startswith("http"): | |
| raise ValueError("Invalid file url") | |
| case FileTransferMethod.LOCAL_FILE: | |
| if not self.related_id: | |
| raise ValueError("Missing file related_id") | |
| case FileTransferMethod.TOOL_FILE: | |
| if not self.related_id: | |
| raise ValueError("Missing file related_id") | |
| # Validate the extra config. | |
| if not self._extra_config: | |
| return self | |
| if self._extra_config.allowed_file_types: | |
| if self.type not in self._extra_config.allowed_file_types and self.type != FileType.CUSTOM: | |
| raise ValueError(f"Invalid file type: {self.type}") | |
| if self._extra_config.allowed_extensions and self.extension not in self._extra_config.allowed_extensions: | |
| raise ValueError(f"Invalid file extension: {self.extension}") | |
| if ( | |
| self._extra_config.allowed_upload_methods | |
| and self.transfer_method not in self._extra_config.allowed_upload_methods | |
| ): | |
| raise ValueError(f"Invalid transfer method: {self.transfer_method}") | |
| match self.type: | |
| case FileType.IMAGE: | |
| # NOTE: This part of validation is deprecated, but still used in app features "Image Upload". | |
| if not self._extra_config.image_config: | |
| return self | |
| # TODO: skip check if transfer_methods is empty, because many test cases are not setting this field | |
| if ( | |
| self._extra_config.image_config.transfer_methods | |
| and self.transfer_method not in self._extra_config.image_config.transfer_methods | |
| ): | |
| raise ValueError(f"Invalid transfer method: {self.transfer_method}") | |
| return self | |