""" ContentTypeProfile protocol and config dataclasses. 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 Any, Dict, Protocol from detect.models import BrandDetection, DetectionReport from core.schema.models.pipeline_config import PipelineConfig, StageRef, Edge @dataclass class FrameExtractionConfig: fps: float = 2.0 max_frames: int = 500 @dataclass class SceneFilterConfig: hamming_threshold: int = 8 enabled: bool = True @dataclass class DetectionConfig: model_name: str = "yolov8n.pt" confidence_threshold: float = 0.3 target_classes: list[str] = field(default_factory=lambda: ["logo", "text"]) @dataclass class OCRConfig: languages: list[str] = field(default_factory=lambda: ["en"]) min_confidence: float = 0.5 @dataclass class ResolverConfig: fuzzy_threshold: int = 75 @dataclass class RegionAnalysisConfig: enabled: bool = True # Edge detection (Canny + HoughLinesP) edge_canny_low: int = 50 edge_canny_high: int = 150 edge_hough_threshold: int = 80 edge_hough_min_length: int = 100 edge_hough_max_gap: int = 10 edge_pair_max_distance: int = 200 edge_pair_min_distance: int = 15 @dataclass class CropContext: image: bytes surrounding_text: str = "" 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: ... def detection_config(self) -> DetectionConfig: ... def ocr_config(self) -> OCRConfig: ... def resolver_config(self) -> ResolverConfig: ... def vlm_prompt(self, crop_context: CropContext) -> str: ... def aggregate(self, detections: list[BrandDetection]) -> DetectionReport: ... def auxiliary_detections(self, source: str) -> list[BrandDetection]: ...