Files
usda-vision/camera-management-api/usda_vision_system/video/presentation/schemas.py

149 lines
5.9 KiB
Python

"""
Video API Request/Response Schemas.
Pydantic models for API serialization and validation.
"""
from typing import List, Optional, Tuple
from datetime import datetime
from pydantic import BaseModel, Field
class VideoMetadataResponse(BaseModel):
"""Video metadata response model"""
duration_seconds: float = Field(..., description="Video duration in seconds")
width: int = Field(..., description="Video width in pixels")
height: int = Field(..., description="Video height in pixels")
fps: float = Field(..., description="Video frame rate")
codec: str = Field(..., description="Video codec")
bitrate: Optional[int] = Field(None, description="Video bitrate in bps")
aspect_ratio: float = Field(..., description="Video aspect ratio")
class Config:
schema_extra = {
"example": {
"duration_seconds": 120.5,
"width": 1920,
"height": 1080,
"fps": 30.0,
"codec": "XVID",
"bitrate": 5000000,
"aspect_ratio": 1.777
}
}
class VideoInfoResponse(BaseModel):
"""Video file information response"""
file_id: str = Field(..., description="Unique file identifier")
camera_name: str = Field(..., description="Camera that recorded the video")
filename: str = Field(..., description="Original filename")
file_size_bytes: int = Field(..., description="File size in bytes")
format: str = Field(..., description="Video format (avi, mp4, webm)")
status: str = Field(..., description="Video status")
created_at: datetime = Field(..., description="Creation timestamp")
start_time: Optional[datetime] = Field(None, description="Recording start time")
end_time: Optional[datetime] = Field(None, description="Recording end time")
machine_trigger: Optional[str] = Field(None, description="Machine that triggered recording")
metadata: Optional[VideoMetadataResponse] = Field(None, description="Video metadata")
is_streamable: bool = Field(..., description="Whether video can be streamed")
needs_conversion: bool = Field(..., description="Whether video needs format conversion")
class Config:
schema_extra = {
"example": {
"file_id": "camera1_recording_20250804_143022.avi",
"camera_name": "camera1",
"filename": "camera1_recording_20250804_143022.avi",
"file_size_bytes": 52428800,
"format": "avi",
"status": "completed",
"created_at": "2025-08-04T14:30:22",
"start_time": "2025-08-04T14:30:22",
"end_time": "2025-08-04T14:32:22",
"machine_trigger": "vibratory_conveyor",
"is_streamable": True,
"needs_conversion": True
}
}
class VideoListResponse(BaseModel):
"""Video list response"""
videos: List[VideoInfoResponse] = Field(..., description="List of videos")
total_count: int = Field(..., description="Total number of matching videos (ignores pagination)")
page: Optional[int] = Field(None, description="Current page number (if using page/limit)")
total_pages: Optional[int] = Field(None, description="Total pages (if using page/limit)")
has_next: Optional[bool] = Field(None, description="Is there a next page?")
has_previous: Optional[bool] = Field(None, description="Is there a previous page?")
class Config:
schema_extra = {
"example": {
"videos": [],
"total_count": 0,
"page": 1,
"total_pages": 1,
"has_next": False,
"has_previous": False
}
}
class StreamingInfoResponse(BaseModel):
"""Streaming information response"""
file_id: str = Field(..., description="Video file ID")
file_size_bytes: int = Field(..., description="Total file size")
content_type: str = Field(..., description="MIME content type")
supports_range_requests: bool = Field(..., description="Whether range requests are supported")
chunk_size_bytes: int = Field(..., description="Recommended chunk size for streaming")
class Config:
schema_extra = {
"example": {
"file_id": "camera1_recording_20250804_143022.avi",
"file_size_bytes": 52428800,
"content_type": "video/x-msvideo",
"supports_range_requests": True,
"chunk_size_bytes": 262144
}
}
class VideoListRequest(BaseModel):
"""Video list request parameters"""
camera_name: Optional[str] = Field(None, description="Filter by camera name")
start_date: Optional[datetime] = Field(None, description="Filter by start date")
end_date: Optional[datetime] = Field(None, description="Filter by end date")
limit: Optional[int] = Field(50, description="Maximum number of results")
offset: Optional[int] = Field(0, description="Number of items to skip (for pagination)")
include_metadata: bool = Field(False, description="Include video metadata for returned items only")
class Config:
schema_extra = {
"example": {
"camera_name": "camera1",
"start_date": "2025-08-04T00:00:00",
"end_date": "2025-08-04T23:59:59",
"limit": 50,
"offset": 0,
"include_metadata": True
}
}
class ThumbnailRequest(BaseModel):
"""Thumbnail generation request"""
timestamp_seconds: float = Field(1.0, description="Timestamp to extract thumbnail from")
width: int = Field(320, description="Thumbnail width")
height: int = Field(240, description="Thumbnail height")
class Config:
schema_extra = {
"example": {
"timestamp_seconds": 5.0,
"width": 320,
"height": 240
}
}