digraph detection_pipeline { rankdir=TB bgcolor="#0a0e17" fontname="Helvetica" node [fontname="Helvetica" fontsize=11 style=filled color="#1e2a4a" fontcolor="#e8eaf0" shape=box] edge [fontname="Helvetica" fontsize=9 fontcolor="#8892a8" color="#4a5568"] label="Detection Pipeline (core/detect/graph/nodes.py)" labelloc=t fontsize=16 fontcolor="#0066ff" extract_frames [label="extract_frames\n(ffmpeg, fps from profile)" fillcolor="#121829"] filter_scenes [label="filter_scenes\n(scene-change filter)" fillcolor="#121829"] field_seg [label="field_segmentation\n(HSV mask · GPU/WASM)" fillcolor="#0d1a33" fontcolor="#0066ff"] detect_edges [label="detect_edges\n(Canny + Hough · GPU/WASM)" fillcolor="#0d1a33" fontcolor="#0066ff"] detect_objects [label="detect_objects\n(YOLO · GPU)" fillcolor="#1a3a1a" fontcolor="#00c853"] preprocess [label="preprocess\n(crop · contrast · deskew)" fillcolor="#121829"] run_ocr [label="run_ocr\n(OCR · GPU)" fillcolor="#1a3a1a" fontcolor="#00c853"] match_brands [label="match_brands\n(rapidfuzz vs session)" fillcolor="#121829"] escalate_vlm [label="escalate_vlm\n(local VLM · GPU)" fillcolor="#1a3a1a" fontcolor="#00c853"] escalate_cloud [label="escalate_cloud\n(Anthropic · Gemini\nOpenAI · Groq)" fillcolor="#243056" shape=octagon] compile_report [label="compile_report\n(timeline + brand stats)" fillcolor="#0d1a33" fontcolor="#0066ff"] extract_frames -> filter_scenes filter_scenes -> field_seg filter_scenes -> detect_objects field_seg -> detect_edges [label="masks"] detect_edges -> detect_objects [style=dashed label="region hints"] detect_objects -> preprocess [label="boxes"] preprocess -> run_ocr run_ocr -> match_brands [label="text candidates"] match_brands -> escalate_vlm [label="unresolved"] escalate_vlm -> escalate_cloud [label="still unresolved"] match_brands -> compile_report escalate_vlm -> compile_report escalate_cloud -> compile_report }