This commit is contained in:
2026-03-23 15:18:23 -03:00
parent 5ed876d694
commit b57da622cb
17 changed files with 554 additions and 103 deletions

View File

@@ -10,12 +10,16 @@ Opens: http://mpr.local.ar/detection/?job=<JOB_ID>
import argparse
import json
import logging
import random
import time
from datetime import datetime, timezone
import redis
logging.basicConfig(level=logging.INFO, format="%(levelname)-7s %(name)s%(message)s")
logger = logging.getLogger(__name__)
STAGES = ["FrameExtractor", "SceneFilter", "YOLODetector", "OCRStage", "BrandResolver", "VLMLocal", "Aggregator"]
LEVELS = ["INFO", "INFO", "INFO", "INFO", "WARNING", "DEBUG", "ERROR"] # weighted toward INFO
MESSAGES = {
@@ -70,9 +74,9 @@ def main():
r = redis.Redis(port=args.port, decode_responses=True)
key = f"detect_events:{args.job}"
print(f"Pushing {args.count} log events to {key} (redis port {args.port})")
print(f"Open: http://mpr.local.ar/detection/?job={args.job}")
print()
logger.info("Pushing %d log events to %s (redis port %d)", args.count, key, args.port)
logger.info("Open: http://mpr.local.ar/detection/?job=%s", args.job)
input("\nPress Enter to start...")
for i in range(args.count):
stage = random.choice(STAGES)
@@ -88,10 +92,10 @@ def main():
}
r.rpush(key, json.dumps(event))
print(f" {level:7s} {stage:16s} {msg[:60]}")
logger.log(getattr(logging, level, logging.INFO), "[%s] %s", stage, msg)
time.sleep(args.delay)
print(f"\nDone. {args.count} events pushed.")
logger.info("Done. %d events pushed.", args.count)
if __name__ == "__main__":

View File

@@ -10,11 +10,15 @@ Opens: http://mpr.local.ar/detection/?job=<JOB_ID>
import argparse
import json
import logging
import time
from datetime import datetime, timezone
import redis
logging.basicConfig(level=logging.INFO, format="%(levelname)-7s %(name)s%(message)s")
logger = logging.getLogger(__name__)
def ts():
return datetime.now(timezone.utc).isoformat()
@@ -25,7 +29,7 @@ def push(r, key, event):
r.rpush(key, json.dumps(event))
etype = event["event"]
detail = event.get("msg", event.get("stage", ""))
print(f" [{etype:14s}] {detail}")
logger.info("[%s] %s", etype, detail)
return event
@@ -39,12 +43,11 @@ def main():
r = redis.Redis(port=args.port, decode_responses=True)
key = f"detect_events:{args.job}"
# Clear previous events for this job
r.delete(key)
print(f"Simulating pipeline run → {key}")
print(f"Open: http://mpr.local.ar/detection/?job={args.job}")
print()
logger.info("Simulating pipeline run → %s", key)
logger.info("Open: http://mpr.local.ar/detection/?job=%s", args.job)
input("\nPress Enter to start...")
delay = args.delay
@@ -171,7 +174,7 @@ def main():
},
}})
print(f"\nPipeline simulation complete.")
logger.info("Pipeline simulation complete.")
if __name__ == "__main__":

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env python3
"""
Run FrameExtractor → SceneFilter on a real video and push events to Redis.
Usage:
python tests/detect/manual/run_extract_filter.py [--job JOB_ID] [--port PORT]
Opens: http://mpr.local.ar/detection/?job=<JOB_ID>
"""
import argparse
import logging
import os
import sys
# Parse args early so we can set REDIS_URL before imports
parser = argparse.ArgumentParser()
parser.add_argument("--job", default="extract-filter-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.profiles.soccer import SoccerBroadcastProfile
from detect.stages.frame_extractor import extract_frames
from detect.stages.scene_filter import scene_filter
logger = logging.getLogger(__name__)
VIDEO = "media/out/chunks/95043d50-4df6-4ac8-bbd5-2ba873117c6e/chunk_0000.mp4"
def main():
profile = SoccerBroadcastProfile()
logger.info("Job: %s", args.job)
logger.info("Open: http://mpr.local.ar/detection/?job=%s", args.job)
input("\nPress Enter to start...")
# Stage 1: Extract frames
extract_config = profile.frame_extraction_config()
extract_config.max_frames = 30
logger.info("Extracting frames (fps=%s, max=%d)...", extract_config.fps, extract_config.max_frames)
frames = extract_frames(VIDEO, extract_config, job_id=args.job)
logger.info("%d frames extracted", len(frames))
# Stage 2: Scene filter
filter_config = profile.scene_filter_config()
logger.info("Filtering scenes (hamming_threshold=%d)...", filter_config.hamming_threshold)
kept = scene_filter(frames, filter_config, job_id=args.job)
logger.info("%d frames kept (%d dropped)", len(kept), len(frames) - len(kept))
logger.info("Done.")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""
End-to-end test: run FrameExtractor and verify SSE events are emitted.
Usage:
python tests/detect/manual/test_frame_extractor_e2e.py
Requires Redis running. Events appear at: http://mpr.local.ar/detection/?job=e2e-test
"""
import logging
import sys
sys.path.insert(0, ".")
from detect.profiles.soccer import SoccerBroadcastProfile
from detect.stages.frame_extractor import extract_frames
logger = logging.getLogger(__name__)
VIDEO = "media/out/chunks/95043d50-4df6-4ac8-bbd5-2ba873117c6e/chunk_0000.mp4"
JOB_ID = "e2e-test"
profile = SoccerBroadcastProfile()
config = profile.frame_extraction_config()
config.max_frames = 20
logger.info("Extracting frames from %s (fps=%s, max=%d)", VIDEO, config.fps, config.max_frames)
logger.info("Open: http://mpr.local.ar/detection/?job=%s", JOB_ID)
input("\nPress Enter to start...")
frames = extract_frames(VIDEO, config, job_id=JOB_ID)
logger.info("Done: %d frames extracted", len(frames))
logger.info("Open http://mpr.local.ar/detection/?job=%s to see the events", JOB_ID)