feat(01-01): create package structure, Pydantic models, and device abstractions

- pyproject.toml with FastAPI, uvicorn, Pydantic v2, aiofiles, structlog deps
- DeviceConfig Pydantic model with StripType, UUID, validation constraints
- ShowModel with AudioRef, TrackModel, CueModel, AnalysisBlock, schema_version=1
- BaseDevice ABC with encode_frame, encode_animation_cmd, bytes_per_pixel
- SK6812Device (4 bytes/pixel) and WS2801Device (3 bytes/pixel) implementations
This commit is contained in:
Claude
2026-04-05 18:45:19 +00:00
parent 5721bef791
commit 061edfcf6a
10 changed files with 179 additions and 0 deletions

46
lightsync/models/show.py Normal file
View File

@@ -0,0 +1,46 @@
from uuid import UUID, uuid4
from datetime import datetime, timezone
from typing import Any, Literal
from pydantic import BaseModel, Field
from lightsync.models.device import DeviceConfig
class AudioRef(BaseModel):
source_type: Literal["file", "youtube"] = "file"
path: str | None = None
yt_url: str | None = None
duration_seconds: float | None = None
class CueModel(BaseModel):
id: UUID = Field(default_factory=uuid4)
timestamp: float
mode: Literal["animation", "frame_sequence"] = "animation"
animation: str | None = None
params: dict[str, Any] = Field(default_factory=dict)
class TrackModel(BaseModel):
device_id: UUID
cues: list[CueModel] = Field(default_factory=list)
class AnalysisBlock(BaseModel):
analysed_at: datetime | None = None
tempo_bpm: float | None = None
beat_times: list[float] = Field(default_factory=list)
onset_times: list[float] = Field(default_factory=list)
class ShowModel(BaseModel):
schema_version: int = 1
id: UUID = Field(default_factory=uuid4)
name: str
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
audio: AudioRef = Field(default_factory=AudioRef)
devices: list[DeviceConfig] = Field(default_factory=list)
analysis: AnalysisBlock = Field(default_factory=AnalysisBlock)
tracks: list[TrackModel] = Field(default_factory=list)
ai_sequences: list[Any] = Field(default_factory=list)