# Copyright (c) 2025 Patrick Motsch # All rights reserved. """Utility datamodels: Prompt, TextMultilingual.""" from typing import Dict, Optional from pydantic import BaseModel, ConfigDict, Field, field_validator from modules.shared.attributeUtils import registerModelLabels import uuid class Prompt(BaseModel): model_config = ConfigDict(extra='allow') # Preserve system fields (_createdBy, _createdAt, etc.) id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False}) mandateId: str = Field(default="", description="ID of the mandate this prompt belongs to", json_schema_extra={"frontend_type": "text", "frontend_readonly": True, "frontend_required": False}) isSystem: bool = Field(default=False, description="System prompt visible to all users (read-only for non-SysAdmin)", json_schema_extra={"frontend_type": "boolean", "frontend_readonly": True, "frontend_required": False}) content: str = Field(description="Content of the prompt", json_schema_extra={"frontend_type": "textarea", "frontend_readonly": False, "frontend_required": True}) name: str = Field(description="Name of the prompt", json_schema_extra={"frontend_type": "text", "frontend_readonly": False, "frontend_required": True}) @field_validator('isSystem', mode='before') @classmethod def _coerceIsSystem(cls, v): """Existing records may have isSystem=None (field didn't exist). Treat None as False.""" if v is None: return False return v registerModelLabels( "Prompt", {"en": "Prompt", "fr": "Invite"}, { "id": {"en": "ID", "fr": "ID"}, "mandateId": {"en": "Mandate ID", "fr": "ID du mandat"}, "isSystem": {"en": "System", "fr": "Système"}, "content": {"en": "Content", "fr": "Contenu"}, "name": {"en": "Name", "fr": "Nom"}, }, ) class TextMultilingual(BaseModel): """ Multilingual text field supporting multiple languages. Default languages: en (English), ge (German), fr (French), it (Italian) English (en) is the default/required language. """ en: str = Field(description="English text (default language, required)") ge: Optional[str] = Field(None, description="German text") fr: Optional[str] = Field(None, description="French text") it: Optional[str] = Field(None, description="Italian text") @field_validator('en') @classmethod def validate_en_required(cls, v): """Ensure English text is not empty""" if not v or not v.strip(): raise ValueError("English text (en) is required and cannot be empty") return v def model_dump(self, **kwargs) -> Dict[str, str]: """Return as dictionary, filtering out None values""" result = {} for lang in ['en', 'ge', 'fr', 'it']: value = getattr(self, lang, None) if value is not None: result[lang] = value return result @classmethod def from_dict(cls, data: Dict[str, str]) -> 'TextMultilingual': """Create TextMultilingual from dictionary""" return cls( en=data.get('en', ''), ge=data.get('ge'), fr=data.get('fr'), it=data.get('it') ) def get_text(self, lang: str = 'en') -> str: """Get text for a specific language, fallback to English if not available""" value = getattr(self, lang, None) if value: return value return self.en # Fallback to English