from datetime import datetime from pydantic import BaseModel, Field, root_validator, validator from app.config import settings class HTMLGenerateRequest(BaseModel): html_content: str = Field( ..., description="Required HTML content or HTML fragment.", ) title: str | None = Field( default=None, max_length=120, description="Optional page title shown in the generated HTML document.", ) source: str | None = Field( default=None, max_length=80, description="Optional source identifier such as a Tencent agent name.", ) request_id: str | None = Field( default=None, max_length=120, description="Optional trace id used for debugging and log correlation.", ) ttl_days: int | None = Field( default=None, ge=1, description="Optional retention days for the file.", ) @root_validator(pre=True) def normalize_aliases(cls, values: dict) -> dict: if isinstance(values.get("body"), dict): merged_values = dict(values["body"]) for key, value in values.items(): if key != "body" and key not in merged_values: merged_values[key] = value values = merged_values alias_map = { "html": "html_content", "content": "html_content", "expire_days": "ttl_days", } for alias, target in alias_map.items(): if target not in values and alias in values: values[target] = values[alias] return values @validator("html_content") def validate_html_content(cls, value: str) -> str: content = value.strip() if not content: raise ValueError("html_content cannot be empty") if len(content.encode("utf-8")) > settings.max_html_length: raise ValueError( f"html_content exceeds the limit of {settings.max_html_length} bytes" ) return content @validator("title", "source", "request_id") def normalize_optional_text(cls, value: str | None) -> str | None: if value is None: return None normalized = value.strip() return normalized or None @validator("ttl_days") def validate_ttl_days(cls, value: int | None) -> int | None: if value is None: return None if value > settings.max_retention_days: raise ValueError( f"ttl_days cannot be greater than {settings.max_retention_days}" ) return value class Config: extra = "ignore" class HTMLGenerateResponse(BaseModel): message: str unique_id: str url: str = Field(description="Direct URL that serves the generated HTML content.") query_url: str = Field(description="Metadata URL for querying the generated record.") title: str | None = None source: str | None = None request_id: str | None = None size_bytes: int created_at: datetime expires_at: datetime