| """ |
| Pydantic models for request/response validation and OpenAPI schema generation |
| """ |
|
|
| from typing import Optional, Dict |
| from pydantic import BaseModel, Field |
| from datetime import datetime |
|
|
|
|
| class RenderRequest(BaseModel): |
| """Request model for rendering Manim animations""" |
|
|
| code: str = Field( |
| ..., |
| description="Python code containing Manim Scene class definition", |
| json_schema_extra={ |
| "example": ( |
| "from manim import *\n\n" |
| "class SquareToCircle(Scene):\n" |
| " def construct(self):\n" |
| " square = Square()\n" |
| " circle = Circle()\n" |
| " self.play(Transform(square, circle))\n" |
| " self.wait()" |
| ) |
| } |
| ) |
|
|
| quality: str = Field( |
| default="720p", |
| description="Quality preset for rendering", |
| json_schema_extra={ |
| "enum": ["4k", "2k", "1080p", "720p", "480p"] |
| } |
| ) |
|
|
| fps: Optional[int] = Field( |
| None, |
| description="Custom frames per second (overrides quality preset default)", |
| ge=1, |
| le=120, |
| json_schema_extra={ |
| "example": 30 |
| } |
| ) |
|
|
| output_format: str = Field( |
| default="mp4", |
| description="Output video format(s). Use 'all' for MP4, GIF, and WebM", |
| json_schema_extra={ |
| "enum": ["mp4", "gif", "webm", "all"] |
| } |
| ) |
|
|
| scene_name: Optional[str] = Field( |
| None, |
| description="Specific Scene class name to render (required if code contains multiple scenes)", |
| json_schema_extra={ |
| "example": "SquareToCircle" |
| } |
| ) |
|
|
| class Config: |
| json_schema_extra = { |
| "example": { |
| "code": "from manim import *\n\nclass MyScene(Scene):\n def construct(self):\n text = Text('Hello, Manim!')\n self.play(Write(text))\n self.wait()", |
| "quality": "720p", |
| "fps": 30, |
| "output_format": "mp4", |
| "scene_name": "MyScene" |
| } |
| } |
|
|
|
|
| class RenderResponse(BaseModel): |
| """Response model for render requests""" |
|
|
| request_id: str = Field( |
| ..., |
| description="Unique identifier for this render request" |
| ) |
|
|
| status: str = Field( |
| ..., |
| description="Status of the render: 'success', 'error', or 'processing'", |
| json_schema_extra={ |
| "enum": ["success", "error", "processing"] |
| } |
| ) |
|
|
| message: str = Field( |
| ..., |
| description="Human-readable status message" |
| ) |
|
|
| urls: Optional[Dict[str, str]] = Field( |
| None, |
| description="URLs to download rendered video files (available when status is 'success')", |
| json_schema_extra={ |
| "example": { |
| "mp4": "https://your-space.hf.space/media/abc123-def456/output.mp4", |
| "gif": "https://your-space.hf.space/media/abc123-def456/output.gif", |
| "webm": "https://your-space.hf.space/media/abc123-def456/output.webm" |
| } |
| } |
| ) |
|
|
| expires_at: Optional[str] = Field( |
| None, |
| description="ISO 8601 timestamp when files will be automatically deleted (1 hour from creation)", |
| json_schema_extra={ |
| "example": "2025-12-19T15:30:00Z" |
| } |
| ) |
|
|
| error_details: Optional[str] = Field( |
| None, |
| description="Detailed error message and traceback (available when status is 'error')" |
| ) |
|
|
| class Config: |
| json_schema_extra = { |
| "example": { |
| "request_id": "abc123-def456-789", |
| "status": "success", |
| "message": "Animation rendered successfully", |
| "urls": { |
| "mp4": "https://your-space.hf.space/media/abc123-def456-789/output.mp4" |
| }, |
| "expires_at": "2025-12-19T15:30:00Z", |
| "error_details": None |
| } |
| } |
|
|
|
|
| class HealthResponse(BaseModel): |
| """Response model for health check endpoint""" |
|
|
| status: str = Field( |
| ..., |
| description="Overall system health status", |
| json_schema_extra={ |
| "enum": ["healthy", "degraded", "unhealthy"] |
| } |
| ) |
|
|
| manim_version: str = Field( |
| ..., |
| description="Installed Manim version" |
| ) |
|
|
| ffmpeg_available: bool = Field( |
| ..., |
| description="Whether FFmpeg is available for video conversion" |
| ) |
|
|
| disk_space_mb: Optional[float] = Field( |
| None, |
| description="Available disk space in megabytes" |
| ) |
|
|
| active_renders: Optional[int] = Field( |
| None, |
| description="Number of currently active render processes" |
| ) |
|
|
| class Config: |
| json_schema_extra = { |
| "example": { |
| "status": "healthy", |
| "manim_version": "0.18.1", |
| "ffmpeg_available": True, |
| "disk_space_mb": 5120.5, |
| "active_renders": 0 |
| } |
| } |
|
|
|
|
| class StatusResponse(BaseModel): |
| """Response model for checking render status""" |
|
|
| request_id: str = Field( |
| ..., |
| description="Request ID being queried" |
| ) |
|
|
| status: str = Field( |
| ..., |
| description="Current status: 'ready', 'processing', 'not_found', or 'expired'", |
| json_schema_extra={ |
| "enum": ["ready", "processing", "not_found", "expired"] |
| } |
| ) |
|
|
| files_available: Optional[list[str]] = Field( |
| None, |
| description="List of available file formats (e.g., ['mp4', 'gif'])" |
| ) |
|
|
| urls: Optional[Dict[str, str]] = Field( |
| None, |
| description="Download URLs for available files" |
| ) |
|
|
| expires_at: Optional[str] = Field( |
| None, |
| description="ISO 8601 timestamp when files will be deleted" |
| ) |
|
|
| log_tail: Optional[str] = Field( |
| None, |
| description="Recent log output for in-progress renders" |
| ) |
|
|