160 lines
6.3 KiB
Python
160 lines
6.3 KiB
Python
# Copyright (c) 2025 Patrick Motsch
|
|
# All rights reserved.
|
|
"""File-related datamodels: FileItem, FilePreview, FileData."""
|
|
|
|
from typing import Dict, Any, List, Optional, Union
|
|
from pydantic import BaseModel, Field
|
|
from modules.datamodels.datamodelBase import PowerOnModel
|
|
from modules.shared.i18nRegistry import i18nModel
|
|
import uuid
|
|
import base64
|
|
|
|
|
|
@i18nModel("Datei")
|
|
class FileItem(PowerOnModel):
|
|
"""Metadaten einer gespeicherten Datei."""
|
|
id: str = Field(
|
|
default_factory=lambda: str(uuid.uuid4()),
|
|
description="Primary key",
|
|
json_schema_extra={"label": "ID", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False},
|
|
)
|
|
fileName: str = Field(
|
|
description="Name of the file",
|
|
json_schema_extra={"label": "Dateiname", "frontend_type": "text", "frontend_readonly": False, "frontend_required": True},
|
|
)
|
|
mandateId: Optional[str] = Field(
|
|
default="",
|
|
description="ID of the mandate this file belongs to",
|
|
json_schema_extra={
|
|
"label": "Mandant",
|
|
"frontend_type": "text",
|
|
"frontend_readonly": True,
|
|
"frontend_required": False,
|
|
"frontend_fk_source": "/api/mandates/",
|
|
"frontend_fk_display_field": "label",
|
|
"fk_model": "Mandate",
|
|
"fk_target": {"db": "poweron_app", "table": "Mandate"},
|
|
},
|
|
)
|
|
featureInstanceId: Optional[str] = Field(
|
|
default="",
|
|
description="ID of the feature instance this file belongs to",
|
|
json_schema_extra={
|
|
"label": "Feature-Instanz",
|
|
"frontend_type": "text",
|
|
"frontend_readonly": True,
|
|
"frontend_required": False,
|
|
"frontend_fk_source": "/api/features/instances",
|
|
"frontend_fk_display_field": "label",
|
|
"fk_model": "FeatureInstance",
|
|
"fk_target": {"db": "poweron_app", "table": "FeatureInstance"},
|
|
},
|
|
)
|
|
mimeType: str = Field(
|
|
description="MIME type of the file",
|
|
json_schema_extra={"label": "MIME-Typ", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False},
|
|
)
|
|
fileHash: str = Field(
|
|
description="Hash of the file",
|
|
json_schema_extra={"label": "Datei-Hash", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False},
|
|
)
|
|
fileSize: int = Field(
|
|
description="Size of the file in bytes",
|
|
json_schema_extra={"label": "Dateigroesse", "frontend_type": "integer", "frontend_readonly": True, "frontend_required": False},
|
|
)
|
|
tags: Optional[List[str]] = Field(
|
|
default=None,
|
|
description="Tags for categorization and search",
|
|
json_schema_extra={"label": "Tags", "frontend_type": "tags", "frontend_readonly": False, "frontend_required": False},
|
|
)
|
|
folderId: Optional[str] = Field(
|
|
default=None,
|
|
description="ID of the parent folder",
|
|
json_schema_extra={
|
|
"label": "Ordner-ID",
|
|
"frontend_type": "text",
|
|
"frontend_readonly": False,
|
|
"frontend_required": False,
|
|
"fk_target": {"db": "poweron_management", "table": "FileFolder"},
|
|
},
|
|
)
|
|
description: Optional[str] = Field(
|
|
default=None,
|
|
description="User-provided description of the file",
|
|
json_schema_extra={"label": "Beschreibung", "frontend_type": "textarea", "frontend_readonly": False, "frontend_required": False},
|
|
)
|
|
status: Optional[str] = Field(
|
|
default=None,
|
|
description="Processing status: pending, extracted, embedding, indexed, failed",
|
|
json_schema_extra={"label": "Status", "frontend_type": "text", "frontend_readonly": True, "frontend_required": False},
|
|
)
|
|
scope: str = Field(
|
|
default="personal",
|
|
description="Data visibility scope: personal, featureInstance, mandate, global",
|
|
json_schema_extra={"label": "Sichtbarkeit", "frontend_type": "select", "frontend_readonly": False, "frontend_required": False, "frontend_options": [
|
|
{"value": "personal", "label": "Persönlich"},
|
|
{"value": "featureInstance", "label": "Feature-Instanz"},
|
|
{"value": "mandate", "label": "Mandant"},
|
|
{"value": "global", "label": "Global"},
|
|
]},
|
|
)
|
|
neutralize: bool = Field(
|
|
default=False,
|
|
description="Whether this file should be neutralized before AI processing",
|
|
json_schema_extra={"label": "Neutralisieren", "frontend_type": "checkbox", "frontend_readonly": False, "frontend_required": False},
|
|
)
|
|
|
|
|
|
@i18nModel("Datei-Vorschau")
|
|
class FilePreview(BaseModel):
|
|
"""Vorschau-Inhalt einer Datei fuer die Anzeige."""
|
|
content: Union[str, bytes] = Field(
|
|
description="File content (text or binary)",
|
|
json_schema_extra={"label": "Inhalt"},
|
|
)
|
|
mimeType: str = Field(
|
|
description="MIME type of the file",
|
|
json_schema_extra={"label": "MIME-Typ"},
|
|
)
|
|
fileName: str = Field(
|
|
description="Original fileName",
|
|
json_schema_extra={"label": "Dateiname"},
|
|
)
|
|
isText: bool = Field(
|
|
description="Whether the content is text (True) or binary (False)",
|
|
json_schema_extra={"label": "Ist Text"},
|
|
)
|
|
encoding: Optional[str] = Field(
|
|
None,
|
|
description="Text encoding if content is text",
|
|
json_schema_extra={"label": "Kodierung"},
|
|
)
|
|
size: int = Field(
|
|
description="Size of the content in bytes",
|
|
json_schema_extra={"label": "Groesse"},
|
|
)
|
|
|
|
def toDictWithBase64Encoding(self) -> Dict[str, Any]:
|
|
"""Convert to dictionary with base64 encoding for binary content."""
|
|
data = self.model_dump()
|
|
if isinstance(data.get("content"), bytes):
|
|
data["content"] = base64.b64encode(data["content"]).decode("utf-8")
|
|
return data
|
|
|
|
|
|
@i18nModel("Dateidaten")
|
|
class FileData(PowerOnModel):
|
|
"""Rohdaten einer Datei (z.B. Base64)."""
|
|
id: str = Field(
|
|
default_factory=lambda: str(uuid.uuid4()),
|
|
description="Primary key",
|
|
json_schema_extra={"label": "ID"},
|
|
)
|
|
data: str = Field(
|
|
description="File data content",
|
|
json_schema_extra={"label": "Daten"},
|
|
)
|
|
base64Encoded: bool = Field(
|
|
description="Whether the data is base64 encoded",
|
|
json_schema_extra={"label": "Base64-kodiert"},
|
|
)
|