This commit is contained in:
2026-03-23 15:52:03 -03:00
parent b57da622cb
commit 4fdbdfc6d3
11 changed files with 599 additions and 5 deletions

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""
Run the full LangGraph detection pipeline on a test video.
Usage:
python tests/detect/manual/run_graph.py [--job JOB_ID] [--port PORT]
Opens: http://mpr.local.ar/detection/?job=<JOB_ID>
"""
import argparse
import logging
import os
import sys
parser = argparse.ArgumentParser()
parser.add_argument("--job", default="graph-test")
parser.add_argument("--port", type=int, default=6382)
args = parser.parse_args()
os.environ["REDIS_URL"] = f"redis://localhost:{args.port}/0"
logging.basicConfig(level=logging.INFO, format="%(levelname)-7s %(name)s%(message)s")
sys.path.insert(0, ".")
from detect.graph import get_pipeline
from detect.state import DetectState
logger = logging.getLogger(__name__)
VIDEO = "media/out/chunks/95043d50-4df6-4ac8-bbd5-2ba873117c6e/chunk_0000.mp4"
def main():
logger.info("Job: %s", args.job)
logger.info("Open: http://mpr.local.ar/detection/?job=%s", args.job)
input("\nPress Enter to start...")
pipeline = get_pipeline()
initial_state = DetectState(
video_path=VIDEO,
job_id=args.job,
profile_name="soccer_broadcast",
)
logger.info("Running pipeline...")
result = pipeline.invoke(initial_state)
frames = result.get("frames", [])
filtered = result.get("filtered_frames", [])
report = result.get("report")
logger.info("Frames extracted: %d", len(frames))
logger.info("Frames after filter: %d", len(filtered))
if report:
logger.info("Brands found: %d", len(report.brands))
logger.info("Done.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,79 @@
"""Tests for the LangGraph detection pipeline."""
import pytest
from detect.graph import NODES, build_graph, get_pipeline
from detect.models import PipelineStats
from detect.state import DetectState
VIDEO = "media/out/chunks/95043d50-4df6-4ac8-bbd5-2ba873117c6e/chunk_0000.mp4"
def test_graph_compiles():
pipeline = get_pipeline()
assert pipeline is not None
def test_graph_has_all_nodes():
graph = build_graph()
for node in NODES:
assert node in graph.nodes
def test_graph_runs_end_to_end(monkeypatch):
"""Run the full graph with mocked event emission."""
events = []
monkeypatch.setattr("detect.emit.push_detect_event",
lambda job_id, etype, data: events.append((etype, data)))
pipeline = get_pipeline()
initial_state = DetectState(
video_path=VIDEO,
job_id="test-graph",
profile_name="soccer_broadcast",
)
result = pipeline.invoke(initial_state)
# All nodes should have transitioned
graph_events = [e for e in events if e[0] == "graph_update"]
assert len(graph_events) > 0
# Should have frames
assert len(result["frames"]) > 0
assert len(result["filtered_frames"]) > 0
# Report should exist
assert result["report"] is not None
assert result["report"].content_type == "soccer_broadcast"
# job_complete should have been emitted
complete_events = [e for e in events if e[0] == "job_complete"]
assert len(complete_events) == 1
def test_graph_node_transitions(monkeypatch):
"""Verify each node emits running → done transitions."""
events = []
monkeypatch.setattr("detect.emit.push_detect_event",
lambda job_id, etype, data: events.append((etype, data)))
pipeline = get_pipeline()
initial_state = DetectState(
video_path=VIDEO,
job_id="test-transitions",
profile_name="soccer_broadcast",
)
pipeline.invoke(initial_state)
graph_events = [e[1] for e in events if e[0] == "graph_update"]
# Each node should appear as "running" then "done"
for node_name in NODES:
running = [e for e in graph_events
if any(n["id"] == node_name and n["status"] == "running" for n in e["nodes"])]
done = [e for e in graph_events
if any(n["id"] == node_name and n["status"] == "done" for n in e["nodes"])]
assert len(running) >= 1, f"{node_name} never entered 'running'"
assert len(done) >= 1, f"{node_name} never reached 'done'"