Add Picture Streams architecture with postprocessing templates and stream test UI
Introduce Picture Stream abstraction that separates the capture pipeline into composable layers: raw streams (display + capture engine + FPS) and processed streams (source stream + postprocessing template). Devices reference a picture stream instead of managing individual capture settings. - Add PictureStream and PostprocessingTemplate data models and stores - Add CRUD API endpoints for picture streams and postprocessing templates - Add stream chain resolution in ProcessorManager for start_processing - Add picture stream test endpoint with postprocessing preview support - Add Stream Settings modal with border_width and interpolation_mode controls - Add stream test modal with capture preview and performance metrics - Add full frontend: Picture Streams tab, Processing Templates tab, stream selector on device cards, test buttons on stream cards - Add localization keys for all new features (en, ru) - Migrate existing devices to picture streams on startup Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
"""Postprocessing template data model."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
|
||||
@dataclass
|
||||
class PostprocessingTemplate:
|
||||
"""Postprocessing settings template for color correction and smoothing."""
|
||||
|
||||
id: str
|
||||
name: str
|
||||
gamma: float
|
||||
saturation: float
|
||||
brightness: float
|
||||
smoothing: float
|
||||
created_at: datetime
|
||||
updated_at: datetime
|
||||
description: Optional[str] = None
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert template to dictionary."""
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"gamma": self.gamma,
|
||||
"saturation": self.saturation,
|
||||
"brightness": self.brightness,
|
||||
"smoothing": self.smoothing,
|
||||
"created_at": self.created_at.isoformat(),
|
||||
"updated_at": self.updated_at.isoformat(),
|
||||
"description": self.description,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict) -> "PostprocessingTemplate":
|
||||
"""Create template from dictionary."""
|
||||
return cls(
|
||||
id=data["id"],
|
||||
name=data["name"],
|
||||
gamma=data.get("gamma", 2.2),
|
||||
saturation=data.get("saturation", 1.0),
|
||||
brightness=data.get("brightness", 1.0),
|
||||
smoothing=data.get("smoothing", 0.3),
|
||||
created_at=datetime.fromisoformat(data["created_at"])
|
||||
if isinstance(data.get("created_at"), str)
|
||||
else data.get("created_at", datetime.utcnow()),
|
||||
updated_at=datetime.fromisoformat(data["updated_at"])
|
||||
if isinstance(data.get("updated_at"), str)
|
||||
else data.get("updated_at", datetime.utcnow()),
|
||||
description=data.get("description"),
|
||||
)
|
||||
Reference in New Issue
Block a user