version 1.0
This commit is contained in:
parent
72eb7d55ea
commit
cee856f59a
2 changed files with 765 additions and 41 deletions
205
app.py
205
app.py
|
@ -652,7 +652,8 @@ def get_or_init_session_pipeline_state(camera_id):
|
|||
"yolo_inference_enabled": True, # Controls whether to run YOLO inference
|
||||
"cached_detection_dict": None, # Cached detection dict for lightweight mode
|
||||
"stable_track_id": None, # The stable track ID we're monitoring
|
||||
"validated_detection": None # Stored detection result from validation phase for full_pipeline reuse
|
||||
"validated_detection": None, # Stored detection result from validation phase for full_pipeline reuse
|
||||
"progression_stage": None # Tracks current progression stage (welcome, car_wait_staff, car_fueling, car_waitpayment)
|
||||
}
|
||||
return session_pipeline_states[camera_id]
|
||||
|
||||
|
@ -829,11 +830,25 @@ async def detect(websocket: WebSocket):
|
|||
|
||||
# ═══ SESSION ID-BASED PROCESSING MODE ═══
|
||||
if not backend_session_id:
|
||||
# No session ID - keep current mode if it's validation_detecting or send_detections
|
||||
if current_mode not in ["validation_detecting", "send_detections", "waiting_for_session_id"]:
|
||||
# No session ID - handle different modes appropriately
|
||||
if current_mode == "lightweight":
|
||||
# Check if we're in car_waitpayment stage - if so, don't reset immediately
|
||||
current_progression = pipeline_state.get("progression_stage")
|
||||
if current_progression == "car_waitpayment":
|
||||
# Stay in lightweight mode - let absence counter + sessionId null logic handle reset
|
||||
logger.debug(f"🔍 Camera {camera_id}: No session ID but in car_waitpayment - staying in lightweight mode for dual reset condition")
|
||||
else:
|
||||
# Not in car_waitpayment - reset immediately (situation 1)
|
||||
update_session_pipeline_mode(camera_id, "validation_detecting")
|
||||
current_mode = "validation_detecting"
|
||||
logger.debug(f"🔍 Camera {camera_id}: No session ID - reset to validation_detecting (not in car_waitpayment)")
|
||||
elif current_mode not in ["validation_detecting", "send_detections", "waiting_for_session_id"]:
|
||||
# Other modes - reset to validation_detecting
|
||||
update_session_pipeline_mode(camera_id, "validation_detecting")
|
||||
current_mode = "validation_detecting"
|
||||
logger.debug(f"🔍 Camera {camera_id}: No session ID - in {current_mode} mode")
|
||||
logger.debug(f"🔍 Camera {camera_id}: No session ID - reset to validation_detecting from {current_mode}")
|
||||
else:
|
||||
logger.debug(f"🔍 Camera {camera_id}: No session ID - staying in {current_mode} mode")
|
||||
else:
|
||||
# Session ID available - switch to full pipeline mode
|
||||
if current_mode in ["send_detections", "waiting_for_session_id"]:
|
||||
|
@ -1041,16 +1056,21 @@ async def detect(websocket: WebSocket):
|
|||
logger.debug(f"🪶 Camera {camera_id}: LIGHTWEIGHT MODE - stable_track_id={stable_track_id}")
|
||||
|
||||
if not pipeline_state.get("yolo_inference_enabled", True):
|
||||
# YOLO inference disabled - waiting for reset
|
||||
logger.debug(f"🛑 Camera {camera_id}: YOLO inference disabled - waiting for reset")
|
||||
detection_result = None # Don't send anything
|
||||
# YOLO inference disabled during car_fueling - continue sending cached detection dict
|
||||
logger.debug(f"🛑 Camera {camera_id}: YOLO inference disabled during car_fueling - continue sending cached detection dict")
|
||||
if cached_detection_dict:
|
||||
detection_result = cached_detection_dict # Continue sending cached data
|
||||
logger.info(f"⛽ Camera {camera_id}: YOLO disabled during car_fueling but sending cached detection dict")
|
||||
else:
|
||||
logger.warning(f"⚠️ Camera {camera_id}: YOLO disabled but no cached detection dict available")
|
||||
detection_result = None
|
||||
else:
|
||||
# Run YOLO inference to check car presence for reset logic
|
||||
from siwatsystem.pympta import run_detection_with_tracking
|
||||
all_detections, regions_dict, track_validation_result = run_detection_with_tracking(cropped_frame, model_tree, pipeline_context)
|
||||
# Run lightweight YOLO inference to check car presence for reset logic (no tracking validation needed)
|
||||
from siwatsystem.pympta import run_lightweight_detection
|
||||
basic_detection = run_lightweight_detection(cropped_frame, model_tree)
|
||||
|
||||
any_car_detected = len(all_detections) > 0
|
||||
current_tracks = track_validation_result.get("current_tracks", [])
|
||||
any_car_detected = basic_detection and basic_detection.get("car_detected", False)
|
||||
logger.debug(f"🔍 Camera {camera_id}: LIGHTWEIGHT - simple car presence check: {any_car_detected}")
|
||||
|
||||
if any_car_detected:
|
||||
# Car detected - reset absence counter, continue sending cached detection dict
|
||||
|
@ -1070,33 +1090,77 @@ async def detect(websocket: WebSocket):
|
|||
|
||||
logger.info(f"👻 Camera {camera_id}: LIGHTWEIGHT - no car detected (absence {absence_count}/{max_absence})")
|
||||
|
||||
# Check if we should reset: Need BOTH 3 consecutive absence frames AND sessionId: null
|
||||
current_progression = pipeline_state.get("progression_stage")
|
||||
should_check_session_null = current_progression == "car_waitpayment"
|
||||
|
||||
if absence_count >= max_absence:
|
||||
# SIMPLE RESET CONDITION: 2 consecutive empty frames
|
||||
logger.info(f"🔄 Camera {camera_id}: RESET CONDITION MET - {max_absence} consecutive empty frames")
|
||||
|
||||
# Clear all state and prepare for next car
|
||||
cached_full_pipeline_results.pop(camera_id, None)
|
||||
pipeline_state["cached_detection_dict"] = None
|
||||
pipeline_state["stable_track_id"] = None
|
||||
pipeline_state["validated_detection"] = None
|
||||
old_absence_counter = pipeline_state["absence_counter"]
|
||||
old_validation_counter = pipeline_state.get("validation_counter", 0)
|
||||
pipeline_state["absence_counter"] = 0
|
||||
pipeline_state["validation_counter"] = 0 # Clear validation counter
|
||||
pipeline_state["yolo_inference_enabled"] = True
|
||||
|
||||
logger.info(f"🧹 Camera {camera_id}: CLEARING ALL COUNTERS - absence_counter: {old_absence_counter}→0, validation_counter: {old_validation_counter}→0")
|
||||
|
||||
# Clear stability tracking data for this camera
|
||||
from siwatsystem.pympta import reset_camera_stability_tracking
|
||||
reset_camera_stability_tracking(camera_id, model_tree.get("modelId", "unknown"))
|
||||
|
||||
# Switch back to validation phase
|
||||
update_session_pipeline_mode(camera_id, "validation_detecting")
|
||||
logger.info(f"✅ Camera {camera_id}: RESET TO VALIDATION COMPLETE - ready for new car")
|
||||
|
||||
# Now in validation mode - send what YOLO detection finds (will be null since no car)
|
||||
detection_result = {"class": "none", "confidence": 1.0, "bbox": [0, 0, 0, 0]}
|
||||
if should_check_session_null:
|
||||
# In car_waitpayment stage - require BOTH conditions
|
||||
if backend_session_id is None:
|
||||
# Both conditions met: 3 absence frames + sessionId: null
|
||||
logger.info(f"🔄 Camera {camera_id}: DUAL RESET CONDITIONS MET - {max_absence} consecutive absence frames + sessionId: null")
|
||||
|
||||
# Clear all state and prepare for next car
|
||||
cached_full_pipeline_results.pop(camera_id, None)
|
||||
pipeline_state["cached_detection_dict"] = None
|
||||
pipeline_state["stable_track_id"] = None
|
||||
pipeline_state["validated_detection"] = None
|
||||
pipeline_state["progression_stage"] = None
|
||||
old_absence_counter = pipeline_state["absence_counter"]
|
||||
old_validation_counter = pipeline_state.get("validation_counter", 0)
|
||||
pipeline_state["absence_counter"] = 0
|
||||
pipeline_state["validation_counter"] = 0
|
||||
pipeline_state["yolo_inference_enabled"] = True
|
||||
|
||||
logger.info(f"🧹 Camera {camera_id}: DUAL RESET - absence_counter: {old_absence_counter}→0, validation_counter: {old_validation_counter}→0, progression_stage: {current_progression}→None")
|
||||
|
||||
# Clear stability tracking data for this camera
|
||||
from siwatsystem.pympta import reset_camera_stability_tracking
|
||||
reset_camera_stability_tracking(camera_id, model_tree.get("modelId", "unknown"))
|
||||
|
||||
# Switch back to validation phase
|
||||
update_session_pipeline_mode(camera_id, "validation_detecting")
|
||||
logger.info(f"✅ Camera {camera_id}: DUAL RESET TO VALIDATION COMPLETE - ready for new car")
|
||||
|
||||
# Now in validation mode - send what YOLO detection finds (will be null since no car)
|
||||
detection_result = {"class": "none", "confidence": 1.0, "bbox": [0, 0, 0, 0]}
|
||||
else:
|
||||
# Only absence frames met, but sessionId is not null - continue sending cached detection
|
||||
logger.info(f"⏳ Camera {camera_id}: {max_absence} absence frames reached but sessionId={backend_session_id} (not null) - continuing with cached detection")
|
||||
if cached_detection_dict:
|
||||
detection_result = cached_detection_dict
|
||||
else:
|
||||
logger.warning(f"⚠️ Camera {camera_id}: No cached detection dict available")
|
||||
detection_result = None
|
||||
else:
|
||||
# Not in car_waitpayment - use original simple reset condition (situation 1)
|
||||
logger.info(f"🔄 Camera {camera_id}: SIMPLE RESET CONDITION MET - {max_absence} consecutive empty frames (not in car_waitpayment)")
|
||||
|
||||
# Clear all state and prepare for next car
|
||||
cached_full_pipeline_results.pop(camera_id, None)
|
||||
pipeline_state["cached_detection_dict"] = None
|
||||
pipeline_state["stable_track_id"] = None
|
||||
pipeline_state["validated_detection"] = None
|
||||
pipeline_state["progression_stage"] = None
|
||||
old_absence_counter = pipeline_state["absence_counter"]
|
||||
old_validation_counter = pipeline_state.get("validation_counter", 0)
|
||||
pipeline_state["absence_counter"] = 0
|
||||
pipeline_state["validation_counter"] = 0
|
||||
pipeline_state["yolo_inference_enabled"] = True
|
||||
|
||||
logger.info(f"🧹 Camera {camera_id}: SIMPLE RESET - absence_counter: {old_absence_counter}→0, validation_counter: {old_validation_counter}→0")
|
||||
|
||||
# Clear stability tracking data for this camera
|
||||
from siwatsystem.pympta import reset_camera_stability_tracking
|
||||
reset_camera_stability_tracking(camera_id, model_tree.get("modelId", "unknown"))
|
||||
|
||||
# Switch back to validation phase
|
||||
update_session_pipeline_mode(camera_id, "validation_detecting")
|
||||
logger.info(f"✅ Camera {camera_id}: SIMPLE RESET TO VALIDATION COMPLETE - ready for new car")
|
||||
|
||||
# Now in validation mode - send what YOLO detection finds (will be null since no car)
|
||||
detection_result = {"class": "none", "confidence": 1.0, "bbox": [0, 0, 0, 0]}
|
||||
else:
|
||||
# Still within absence threshold - continue sending cached detection dict
|
||||
if cached_detection_dict:
|
||||
|
@ -1181,9 +1245,16 @@ async def detect(websocket: WebSocket):
|
|||
detection_dict = None # Send detection: null
|
||||
logger.info(f"🚫 LIGHTWEIGHT - no car detected, sending detection=null")
|
||||
elif isinstance(detection_result, dict) and ("carBrand" in detection_result or "carModel" in detection_result):
|
||||
# This is a cached detection dict - send it
|
||||
detection_dict = detection_result
|
||||
logger.info(f"💾 LIGHTWEIGHT - sending cached detection dict")
|
||||
# Check if we're waiting for dual reset condition
|
||||
current_progression = pipeline_state.get("progression_stage")
|
||||
if current_progression == "car_waitpayment" and backend_session_id is None:
|
||||
# In car_waitpayment + sessionId: null - STOP sending cached detection to prevent new session creation
|
||||
detection_dict = None
|
||||
logger.info(f"🛑 LIGHTWEIGHT - in car_waitpayment with sessionId: null, NOT sending cached detection (waiting for dual reset)")
|
||||
else:
|
||||
# Normal lightweight mode - send cached detection dict
|
||||
detection_dict = detection_result
|
||||
logger.info(f"💾 LIGHTWEIGHT - sending cached detection dict")
|
||||
else:
|
||||
logger.warning(f"⚠️ LIGHTWEIGHT - unexpected detection_result type: {type(detection_result)}")
|
||||
detection_dict = None
|
||||
|
@ -2311,6 +2382,58 @@ async def detect(websocket: WebSocket):
|
|||
await websocket.send_json(response)
|
||||
logger.info(f"Acknowledged patch for session {session_id}")
|
||||
|
||||
elif msg_type == "setProgressionStage":
|
||||
payload = data.get("payload", {})
|
||||
display_identifier = payload.get("displayIdentifier")
|
||||
progression_stage = payload.get("progressionStage")
|
||||
|
||||
logger.info(f"🏁 PROGRESSION STAGE RECEIVED: displayId={display_identifier}, stage={progression_stage}")
|
||||
|
||||
if display_identifier:
|
||||
# Find all cameras associated with this display
|
||||
with streams_lock:
|
||||
affected_cameras = []
|
||||
for camera_id, stream in streams.items():
|
||||
if stream["subscriptionIdentifier"].startswith(display_identifier + ";"):
|
||||
affected_cameras.append(camera_id)
|
||||
|
||||
logger.debug(f"🎯 Found {len(affected_cameras)} cameras for display {display_identifier}: {affected_cameras}")
|
||||
|
||||
# Handle different progression stages
|
||||
for camera_id in affected_cameras:
|
||||
pipeline_state = get_or_init_session_pipeline_state(camera_id)
|
||||
current_mode = pipeline_state.get("mode", "validation_detecting")
|
||||
|
||||
if progression_stage == "car_fueling":
|
||||
# Situation 2: Stop YOLO inference, continue sending cached detection dict
|
||||
if current_mode == "lightweight":
|
||||
pipeline_state["yolo_inference_enabled"] = False
|
||||
pipeline_state["progression_stage"] = "car_fueling"
|
||||
logger.info(f"⏸️ Camera {camera_id}: YOLO inference DISABLED for car_fueling stage (still sending cached detection dict)")
|
||||
else:
|
||||
logger.debug(f"📊 Camera {camera_id}: car_fueling received but not in lightweight mode (mode: {current_mode})")
|
||||
|
||||
elif progression_stage == "car_waitpayment":
|
||||
# Resume YOLO inference for absence counter
|
||||
pipeline_state["yolo_inference_enabled"] = True
|
||||
pipeline_state["progression_stage"] = "car_waitpayment"
|
||||
logger.info(f"▶️ Camera {camera_id}: YOLO inference RE-ENABLED for car_waitpayment stage")
|
||||
|
||||
elif progression_stage == "welcome":
|
||||
# Ignore welcome messages during car_waitpayment as per requirement
|
||||
current_progression = pipeline_state.get("progression_stage")
|
||||
if current_progression == "car_waitpayment":
|
||||
logger.info(f"🚫 Camera {camera_id}: IGNORING welcome stage (currently in car_waitpayment)")
|
||||
else:
|
||||
pipeline_state["progression_stage"] = "welcome"
|
||||
logger.info(f"🎉 Camera {camera_id}: Progression stage set to welcome")
|
||||
|
||||
elif progression_stage in ["car_wait_staff"]:
|
||||
pipeline_state["progression_stage"] = progression_stage
|
||||
logger.info(f"📋 Camera {camera_id}: Progression stage set to {progression_stage}")
|
||||
else:
|
||||
logger.warning(f"🚨 Invalid setProgressionStage message: missing displayIdentifier in payload")
|
||||
|
||||
else:
|
||||
logger.error(f"Unknown message type: {msg_type}")
|
||||
except json.JSONDecodeError:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue