a
This commit is contained in:
@@ -28,6 +28,7 @@ from .grpc import (
|
||||
from .job import Job, JobStatus, RunType
|
||||
from .timeline import Timeline
|
||||
from .checkpoint import Checkpoint
|
||||
from .stage_output import StageOutput
|
||||
from .brand import BrandSource, Brand
|
||||
from .media import AssetStatus, MediaAsset
|
||||
from .profile import Profile
|
||||
@@ -41,7 +42,7 @@ from .source import ChunkInfo, SourceJob, SourceType
|
||||
|
||||
# Core domain models - generates SQLModel, TypeScript
|
||||
DATACLASSES = [MediaAsset, TranscodePreset,
|
||||
Job, Timeline, Checkpoint, Brand, Profile]
|
||||
Job, Timeline, Checkpoint, StageOutput, Brand, Profile]
|
||||
|
||||
# API request/response models
|
||||
API_MODELS = [
|
||||
|
||||
@@ -11,25 +11,24 @@ class Checkpoint:
|
||||
"""
|
||||
A snapshot of pipeline state on a timeline.
|
||||
|
||||
Stage outputs stored as JSONB — each stage serializes to JSON,
|
||||
the checkpoint stores it without knowing the shape.
|
||||
|
||||
parent_id forms a tree: multiple children from the same parent
|
||||
= different config tries from the same starting point.
|
||||
|
||||
Stage outputs are stored separately in StageOutput table,
|
||||
not carried in the checkpoint itself.
|
||||
"""
|
||||
|
||||
id: UUID
|
||||
timeline_id: UUID
|
||||
job_id: Optional[UUID] = None # which job created this checkpoint
|
||||
parent_id: Optional[UUID] = None # null = root checkpoint
|
||||
job_id: Optional[UUID] = None
|
||||
parent_id: Optional[UUID] = None
|
||||
|
||||
# Stage outputs — JSONB per stage, opaque to the checkpoint layer
|
||||
stage_outputs: Dict[str, Any] = field(default_factory=dict)
|
||||
stage_name: str = "" # which stage produced this checkpoint
|
||||
|
||||
# Config that produced this checkpoint
|
||||
config_overrides: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
# Pipeline state
|
||||
# Pipeline stats at this point
|
||||
stats: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
# Scenario bookmark
|
||||
|
||||
@@ -38,7 +38,7 @@ class Job:
|
||||
video_path: str
|
||||
profile_name: str = "soccer_broadcast"
|
||||
|
||||
# Timeline — set after frame extraction, or upfront for replay jobs
|
||||
# Timeline — set at job creation (timeline exists before any job)
|
||||
timeline_id: Optional[UUID] = None
|
||||
|
||||
# Lineage
|
||||
|
||||
27
core/schema/models/stage_output.py
Normal file
27
core/schema/models/stage_output.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""StageOutput schema — per-stage result storage."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional
|
||||
from uuid import UUID
|
||||
|
||||
|
||||
@dataclass
|
||||
class StageOutput:
|
||||
"""
|
||||
Output of a single stage within a job.
|
||||
|
||||
Flat table with composite unique (job_id, stage_name).
|
||||
Upserted on each stage completion. Independently queryable —
|
||||
"give me all edge detection outputs for this timeline."
|
||||
"""
|
||||
|
||||
id: UUID
|
||||
job_id: UUID
|
||||
timeline_id: UUID
|
||||
stage_name: str
|
||||
checkpoint_id: Optional[UUID] = None
|
||||
|
||||
output: Dict[str, Any] = field(default_factory=dict)
|
||||
|
||||
created_at: Optional[datetime] = None
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Timeline schema — source of truth for frame sequences."""
|
||||
"""Timeline schema — source of truth for source material sequences."""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
@@ -9,21 +9,27 @@ from uuid import UUID
|
||||
@dataclass
|
||||
class Timeline:
|
||||
"""
|
||||
The frame sequence from a source video.
|
||||
A user-created selection of source material.
|
||||
|
||||
Independent of stages — exists before any stage runs.
|
||||
Frames stored in MinIO as JPEGs, metadata here.
|
||||
One timeline per job.
|
||||
Exists before any job runs. Holds source references (chunk paths,
|
||||
asset IDs) and extraction config.
|
||||
|
||||
Frame cache: extracted frames live at media/timelines/{id}/frames/
|
||||
as JPEGs. Any job on this timeline reads from the cache. Cache is
|
||||
rebuildable from chunks (clear + re-extract). For ephemeral sources
|
||||
(streams), the cache is the only record.
|
||||
|
||||
Many jobs can work on the same timeline.
|
||||
"""
|
||||
|
||||
id: UUID
|
||||
name: str = ""
|
||||
source_asset_id: Optional[UUID] = None
|
||||
source_video: str = ""
|
||||
chunk_paths: List[str] = field(default_factory=list)
|
||||
profile_name: str = ""
|
||||
status: str = "created" # created | cached | ready
|
||||
fps: float = 2.0
|
||||
|
||||
frames_prefix: str = "" # s3: timeline/{id}/frames/
|
||||
frames_manifest: Dict[int, str] = field(default_factory=dict) # seq → s3 key
|
||||
frames_meta: List[Dict[str, Any]] = field(default_factory=list)
|
||||
frame_count: int = 0
|
||||
source_ephemeral: bool = False # True for streams — cache can't be rebuilt
|
||||
|
||||
created_at: Optional[datetime] = None
|
||||
|
||||
Reference in New Issue
Block a user