phase 4
This commit is contained in:
@@ -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__":
|
||||
|
||||
@@ -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__":
|
||||
|
||||
60
tests/detect/manual/run_extract_filter.py
Normal file
60
tests/detect/manual/run_extract_filter.py
Normal 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()
|
||||
34
tests/detect/manual/test_frame_extractor_e2e.py
Normal file
34
tests/detect/manual/test_frame_extractor_e2e.py
Normal 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)
|
||||
Reference in New Issue
Block a user