This commit is contained in:
2026-03-28 10:05:59 -03:00
parent e46bbc419c
commit d0707333fd
12 changed files with 381 additions and 120 deletions

View File

@@ -1,17 +1,20 @@
"""
ContentTypeProfile protocol and config dataclasses.
The pipeline graph is fixed — what varies per content type is configuration
and hooks. Each profile provides stage configs, a brand dictionary,
VLM prompt templates, and an aggregation strategy.
Each profile defines the pipeline topology (as a JSONB blob), stage configs,
brand dictionary, VLM prompt templates, and aggregation strategy.
When profiles are persisted, the pipeline field is a JSONB column.
For now, profiles are code-only and pipeline_config() returns a hardcoded value.
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Protocol
from typing import Any, Dict, Protocol
from detect.models import BrandDetection, DetectionReport
from core.schema.models.pipeline_config import PipelineConfig, StageRef, Edge
@dataclass
@@ -64,9 +67,24 @@ class CropContext:
position_hint: str = ""
def pipeline_config_from_dict(data: Dict[str, Any]) -> PipelineConfig:
"""Deserialize a PipelineConfig from a JSONB dict."""
stages = [StageRef(**s) for s in data.get("stages", [])]
edges = [Edge(**e) for e in data.get("edges", [])]
return PipelineConfig(
name=data.get("name", ""),
profile_name=data.get("profile_name", ""),
stages=stages,
edges=edges,
routing_rules=data.get("routing_rules", {}),
)
class ContentTypeProfile(Protocol):
name: str
pipeline: Dict[str, Any] # JSONB blob — PipelineConfig shape
def pipeline_config(self) -> PipelineConfig: ...
def frame_extraction_config(self) -> FrameExtractionConfig: ...
def scene_filter_config(self) -> SceneFilterConfig: ...
def region_analysis_config(self) -> RegionAnalysisConfig: ...

View File

@@ -2,6 +2,7 @@
from __future__ import annotations
from core.schema.models.pipeline_config import PipelineConfig
from detect.models import BrandDetection, BrandStats, DetectionReport, PipelineStats
from .base import (
@@ -12,12 +13,46 @@ from .base import (
RegionAnalysisConfig,
ResolverConfig,
SceneFilterConfig,
pipeline_config_from_dict,
)
class SoccerBroadcastProfile:
name = "soccer_broadcast"
# Pipeline topology as JSONB — will be a DB field when profiles are persisted
pipeline = {
"name": "soccer_broadcast",
"profile_name": "soccer_broadcast",
"stages": [
{"name": "extract_frames", "branch": "trunk"},
{"name": "filter_scenes", "branch": "trunk"},
{"name": "detect_edges", "branch": "hoarding"},
{"name": "detect_objects", "branch": "objects"},
{"name": "preprocess"},
{"name": "run_ocr"},
{"name": "match_brands"},
{"name": "escalate_vlm"},
{"name": "escalate_cloud"},
{"name": "compile_report"},
],
"edges": [
{"source": "extract_frames", "target": "filter_scenes"},
{"source": "filter_scenes", "target": "detect_edges"},
{"source": "filter_scenes", "target": "detect_objects"},
{"source": "detect_edges", "target": "preprocess"},
{"source": "detect_objects", "target": "preprocess"},
{"source": "preprocess", "target": "run_ocr"},
{"source": "run_ocr", "target": "match_brands"},
{"source": "match_brands", "target": "escalate_vlm"},
{"source": "escalate_vlm", "target": "escalate_cloud"},
{"source": "escalate_cloud", "target": "compile_report"},
],
}
def pipeline_config(self) -> PipelineConfig:
return pipeline_config_from_dict(self.pipeline)
def frame_extraction_config(self) -> FrameExtractionConfig:
return FrameExtractionConfig(fps=2.0, max_frames=500)