| 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 |
| tenant_id: str |
| type: FileType |
| transfer_method: FileTransferMethod |
| remote_url: Optional[str] = None |
| 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(), |
| } |
|
|
| @property |
| 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 |
| ) |
|
|
| @model_validator(mode="after") |
| 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") |
|
|
| |
| 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: |
| |
| if not self._extra_config.image_config: |
| return self |
| |
| 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 |
|
|