Testys commited on
Commit
0bcaa4e
·
verified ·
1 Parent(s): 7c9f785

Update pages/1_Live_Detection.py

Browse files
Files changed (1) hide show
  1. pages/1_Live_Detection.py +64 -94
pages/1_Live_Detection.py CHANGED
@@ -6,45 +6,31 @@ import av
6
  import os
7
  from dotenv import load_dotenv
8
  import base64
9
- import requests
10
  import queue
11
  import time
12
- from typing import List, Dict, Union
13
 
14
- # Correctly import from the drive_paddy package structure
15
  from src.detection.factory import get_detector
16
  from src.alerting.alert_system import get_alerter
17
 
18
- # --- Initialize Session State at the TOP of the script ---
19
- # This is the single source of truth for our queues and must run on every page load.
20
- if "status_queue" not in st.session_state:
21
- st.session_state.status_queue = queue.Queue()
22
- if "audio_queue" not in st.session_state:
23
- st.session_state.audio_queue = queue.Queue()
24
- if "last_status" not in st.session_state:
25
- st.session_state.last_status = {"drowsiness_level": "Awake", "lighting": "Good"}
26
-
27
-
28
  # --- Load Configuration and Environment Variables ---
29
  @st.cache_resource
30
  def load_app_config():
31
  """Loads config from yaml and .env files."""
32
  load_dotenv()
 
33
  # Navigate up to the root to find the config file
34
- config_path = "./config.yaml"
35
  with open(config_path, 'r') as f:
36
  config = yaml.safe_load(f)
37
- # Load secrets from environment
38
- secrets = {
39
- "gemini_api_key": os.getenv("GEMINI_API_KEY"),
40
- "turn_username": os.getenv("TURN_USERNAME"),
41
- "turn_credential": os.getenv("TURN_CREDENTIAL"),
42
- "metered_domain": os.getenv("METERED_DOMAIN"),
43
- "metered_api_key": os.getenv("METERED_KEY")
44
- }
45
- return config, secrets
46
-
47
- config, secrets = load_app_config()
48
 
49
  # --- Client-Side Audio Playback Function ---
50
  def autoplay_audio(audio_bytes: bytes):
@@ -59,83 +45,62 @@ def autoplay_audio(audio_bytes: bytes):
59
 
60
  # --- WebRTC Video Processor ---
61
  class VideoProcessor(VideoProcessorBase):
62
- # The __init__ method now accepts the queues as arguments
63
  def __init__(self):
64
- # It uses the queues passed in from session_state, not new ones.
65
- self.status_queue = queue.Queue
66
- self.audio_queue = queue.Queue
67
  self._detector = get_detector(config)
68
- self._alerter = get_alerter(config, secrets["gemini_api_key"])
69
 
70
  def recv(self, frame: av.VideoFrame) -> av.VideoFrame:
71
  img = frame.to_ndarray(format="bgr24")
72
 
73
  strategy = config.get('detection_strategy')
74
-
75
- # The return signature of process_frame varies by strategy.
76
- processed_frame, indicators, _ = self._detector.process_frame(img)
77
- drowsiness_level = indicators.get("drowsiness_level", "Awake")
78
-
79
- # This now correctly puts data into the shared session_state queue.
80
- self.status_queue.put(indicators)
81
-
82
- if drowsiness_level != "Awake":
83
- audio_data = self._alerter.trigger_alert(level=drowsiness_level)
84
  if audio_data:
85
- # This now correctly puts audio data into the shared queue.
86
- self.audio_queue.put(audio_data)
87
  else:
88
  self._alerter.reset_alert()
89
 
90
  return av.VideoFrame.from_ndarray(processed_frame, format="bgr24")
91
 
92
  # --- Page UI ---
 
 
93
  st.title("📹 Live Drowsiness Detection")
94
  st.info("Press 'START' to activate your camera and begin monitoring.")
95
 
 
 
96
  RTC_CONFIGURATION = RTCConfiguration({
97
- "iceServers": [
98
- {
99
- "urls": ["stun:stun.relay.metered.ca:80"],
100
- },
101
- {
102
- "urls": ["turn:global.relay.metered.ca:80"],
103
- "username": "086986a440b20fe48229738b",
104
- "credential": "mOC7fVSg00zjlsTD",
105
- },
106
- {
107
- "urls": ["turn:global.relay.metered.ca:80?transport=tcp"],
108
- "username": "086986a440b20fe48229738b",
109
- "credential": "mOC7fVSg00zjlsTD",
110
- },
111
- {
112
- "urls": ["turn:global.relay.metered.ca:443"],
113
- "username": "086986a440b20fe48229738b",
114
- "credential": "mOC7fVSg00zjlsTD",
115
- },
116
- {
117
- "urls": ["turns:global.relay.metered.ca:443?transport=tcp"],
118
- "username": "086986a440b20fe48229738b",
119
- "credential": "mOC7fVSg00zjlsTD",
120
- },
121
- ]
122
  })
123
 
 
124
  col1, col2 = st.columns([3, 1])
125
 
126
  with col1:
127
  webrtc_ctx = webrtc_streamer(
128
  key="drowsiness-detection",
129
- # The factory now correctly passes the queues from session_state
130
  video_processor_factory=VideoProcessor,
131
- # rtc_configuration=RTC_CONFIGURATION,
132
- # media_stream_constraints={"video": True, "audio": False},
133
- # async_processing=True,
134
  )
135
 
136
  with col2:
137
  st.header("System Status")
138
- audio_placeholder = st.empty()
139
  if not webrtc_ctx.state.playing:
140
  st.warning("System Inactive.")
141
  else:
@@ -143,41 +108,46 @@ with col2:
143
 
144
  st.subheader("Live Status:")
145
  status_placeholder = st.empty()
 
146
 
147
  if webrtc_ctx.state.playing:
 
148
  try:
149
- # This now reads from the correct queue that the processor is writing to.
150
  status_result = st.session_state.status_queue.get(timeout=0.1)
151
- st.session_state.last_status = status_result
152
  except queue.Empty:
153
- pass
154
 
 
 
 
 
 
 
155
  with status_placeholder.container():
156
- last_status = st.session_state.last_status
157
- drowsiness_level = last_status.get("drowsiness_level", "Awake")
158
- lighting = last_status.get("lighting", "Good")
159
- score = last_status.get("details", {}).get("Score", 0)
160
-
161
- st.metric(label="Lighting Condition", value=lighting)
162
- if lighting == "Low":
163
- st.warning("Detection paused due to low light.")
164
 
165
- if drowsiness_level == "Awake":
166
- st.info(f"✔️ Awake (Score: {score:.2f})")
167
- elif drowsiness_level == "Slightly Drowsy":
168
- st.warning(f"⚠️ Slightly Drowsy (Score: {score:.2f})")
169
- elif drowsiness_level == "Very Drowsy":
170
- st.error(f"🚨 Very Drowsy! (Score: {score:.2f})")
 
 
 
 
 
171
 
172
- try:
173
- audio_data = st.session_state.audio_queue.get(timeout=0.1)
174
  with audio_placeholder.container():
175
  autoplay_audio(audio_data)
176
- except queue.Empty:
177
- pass
178
-
179
  time.sleep(0.1)
180
  st.rerun()
 
181
  else:
182
  with status_placeholder.container():
183
  st.info("✔️ Driver is Awake")
 
6
  import os
7
  from dotenv import load_dotenv
8
  import base64
 
9
  import queue
10
  import time
 
11
 
 
12
  from src.detection.factory import get_detector
13
  from src.alerting.alert_system import get_alerter
14
 
 
 
 
 
 
 
 
 
 
 
15
  # --- Load Configuration and Environment Variables ---
16
  @st.cache_resource
17
  def load_app_config():
18
  """Loads config from yaml and .env files."""
19
  load_dotenv()
20
+ gemini_api_key = os.getenv("GEMINI_API_KEY")
21
  # Navigate up to the root to find the config file
22
+ config_path = "/config.yaml" if os.path.exists("/config.yaml") else "config.yaml"
23
  with open(config_path, 'r') as f:
24
  config = yaml.safe_load(f)
25
+ return config, gemini_api_key
26
+
27
+ config, gemini_api_key = load_app_config()
28
+
29
+ # --- Initialize Session State (if not already done in main.py) ---
30
+ if "play_audio" not in st.session_state:
31
+ st.session_state.play_audio = None
32
+ if "active_alerts" not in st.session_state:
33
+ st.session_state.active_alerts = {"status": "Awake"}
 
 
34
 
35
  # --- Client-Side Audio Playback Function ---
36
  def autoplay_audio(audio_bytes: bytes):
 
45
 
46
  # --- WebRTC Video Processor ---
47
  class VideoProcessor(VideoProcessorBase):
 
48
  def __init__(self):
 
 
 
49
  self._detector = get_detector(config)
50
+ self._alerter = get_alerter(config, gemini_api_key)
51
 
52
  def recv(self, frame: av.VideoFrame) -> av.VideoFrame:
53
  img = frame.to_ndarray(format="bgr24")
54
 
55
  strategy = config.get('detection_strategy')
56
+ if strategy == 'hybrid':
57
+ processed_frame, alert_triggered, active_alerts = self._detector.process_frame(img)
58
+ st.session_state.active_alerts = active_alerts if alert_triggered else {"status": "Awake"}
59
+ else: # Fallback for simpler strategies
60
+ processed_frame, indicators = self._detector.process_frame(img)
61
+ alert_triggered = any(indicators.values())
62
+ st.session_state.active_alerts = indicators if alert_triggered else {"status": "Awake"}
63
+
64
+ if alert_triggered:
65
+ audio_data = self._alerter.trigger_alert()
66
  if audio_data:
67
+ st.session_state.play_audio = audio_data
 
68
  else:
69
  self._alerter.reset_alert()
70
 
71
  return av.VideoFrame.from_ndarray(processed_frame, format="bgr24")
72
 
73
  # --- Page UI ---
74
+ # The st.set_page_config() call has been removed from this file.
75
+ # The configuration from main.py will apply to this page.
76
  st.title("📹 Live Drowsiness Detection")
77
  st.info("Press 'START' to activate your camera and begin monitoring.")
78
 
79
+ # --- Robust RTC Configuration ---
80
+ # Provide a list of STUN servers for better reliability.
81
  RTC_CONFIGURATION = RTCConfiguration({
82
+ "iceServers": [
83
+ {"urls": ["stun:stun.l.google.com:19302"]},
84
+ {"urls": ["stun:stun1.l.google.com:19302"]},
85
+ {"urls": ["stun:stun2.l.google.com:19302"]},
86
+ {"urls": ["stun:stun.services.mozilla.com:3478"]},
87
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  })
89
 
90
+
91
  col1, col2 = st.columns([3, 1])
92
 
93
  with col1:
94
  webrtc_ctx = webrtc_streamer(
95
  key="drowsiness-detection",
 
96
  video_processor_factory=VideoProcessor,
97
+ rtc_configuration=RTC_CONFIGURATION, # Use the new robust configuration
98
+ media_stream_constraints={"video": True, "audio": False},
99
+ async_processing=True,
100
  )
101
 
102
  with col2:
103
  st.header("System Status")
 
104
  if not webrtc_ctx.state.playing:
105
  st.warning("System Inactive.")
106
  else:
 
108
 
109
  st.subheader("Live Status:")
110
  status_placeholder = st.empty()
111
+ audio_placeholder = st.empty()
112
 
113
  if webrtc_ctx.state.playing:
114
+ # --- Polling Loop ---
115
  try:
 
116
  status_result = st.session_state.status_queue.get(timeout=0.1)
 
117
  except queue.Empty:
118
+ status_result = None
119
 
120
+ # Check for new audio alerts
121
+ try:
122
+ audio_data = st.session_state.audio_queue.get(timeout=0.1)
123
+ except queue.Empty:
124
+ audio_data = None
125
+
126
  with status_placeholder.container():
127
+ # Persist the last known status if there's no new one
128
+ if status_result:
129
+ st.session_state.last_status = status_result
 
 
 
 
 
130
 
131
+ last_status = getattr(st.session_state, 'last_status', {"status": "Awake"})
132
+
133
+ if last_status.get("Low Light"):
134
+ st.warning("⚠️ Low Light Detected! Accuracy may be affected.")
135
+ elif last_status.get("status") == "Awake":
136
+ st.info("✔️ Driver is Awake")
137
+ else:
138
+ st.error("🚨 DROWSINESS DETECTED!")
139
+ for key, value in last_status.items():
140
+ if key != "Low Light":
141
+ st.warning(f"-> {key}: {value:.2f}" if isinstance(value, float) else f"-> {key}")
142
 
143
+ if audio_data:
 
144
  with audio_placeholder.container():
145
  autoplay_audio(audio_data)
146
+
147
+ # Force a rerun to keep the polling active
 
148
  time.sleep(0.1)
149
  st.rerun()
150
+
151
  else:
152
  with status_placeholder.container():
153
  st.info("✔️ Driver is Awake")