trixy194t commited on
Commit
3bdf2cf
·
verified ·
1 Parent(s): 96926be

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -11
app.py CHANGED
@@ -719,7 +719,7 @@ def count_precise_apneas(y, sr, segment_results, min_apnea=1, max_apnea=60):
719
  # Check B: ML model score (gap must score < 0.40)
720
  # BOTH must pass. This fixes the padding problem and reduces false positives.
721
  print(" Stage 3: DUAL validation (RMS energy + ML score)...")
722
- print(" Rules: gap RMS ratio < 0.5 AND ML score < 0.40")
723
 
724
  validated_apneas = []
725
 
@@ -752,7 +752,7 @@ def count_precise_apneas(y, sr, segment_results, min_apnea=1, max_apnea=60):
752
  # Avoid division by zero
753
  rms_ratio = gap_rms / (avg_snore_rms + 1e-10)
754
 
755
- rms_ok = rms_ratio < 0.5 # Gap must be at least 2x quieter than snoring
756
 
757
  except Exception as e:
758
  print(f" ⚠️ RMS check error for candidate {idx+1}: {e}")
@@ -834,7 +834,7 @@ def count_precise_apneas(y, sr, segment_results, min_apnea=1, max_apnea=60):
834
  else:
835
  reasons = []
836
  if not rms_ok:
837
- reasons.append(f"gap not quiet enough (RMS ratio {rms_ratio:.3f} >= 0.5)")
838
  if not ml_ok:
839
  reasons.append(f"ML says snoring in gap (score {ml_score:.3f} >= 0.40)")
840
  print(f" → REJECTED: {', '.join(reasons)}")
@@ -847,7 +847,7 @@ def count_precise_apneas(y, sr, segment_results, min_apnea=1, max_apnea=60):
847
  # VALIDATION
848
  # ========================================
849
  def validate_sleep_recording(y, sr):
850
- """Validate that this is a sleep recording"""
851
  duration = len(y) / sr
852
 
853
  if duration < 20:
@@ -855,12 +855,11 @@ def validate_sleep_recording(y, sr):
855
 
856
  rms_energy = np.sqrt(np.mean(y**2))
857
 
858
- if rms_energy < 0.001:
859
- return False, 0.0, "Audio is blank/silent"
860
-
861
- if rms_energy > 0.6:
862
- return False, 0.0, "Audio too loud (not a sleep recording)"
863
 
 
864
  stft = np.abs(librosa.stft(y))
865
  freq_bins = librosa.fft_frequencies(sr=sr)
866
 
@@ -871,11 +870,27 @@ def validate_sleep_recording(y, sr):
871
  low_freq_ratio = low_freq_energy / total_energy
872
  high_freq_ratio = high_freq_energy / total_energy
873
 
 
 
 
 
 
 
 
 
 
 
 
 
 
874
  if low_freq_ratio < 0.4:
875
- return False, 0.0, "Frequency distribution doesn't match sleep audio"
876
 
877
  if high_freq_ratio > 0.3:
878
- return False, 0.0, "Too much high-frequency content (speech/TV detected)"
 
 
 
879
 
880
  return True, 1.0, "Valid sleep recording detected"
881
 
 
719
  # Check B: ML model score (gap must score < 0.40)
720
  # BOTH must pass. This fixes the padding problem and reduces false positives.
721
  print(" Stage 3: DUAL validation (RMS energy + ML score)...")
722
+ print(" Rules: gap RMS ratio < 0.55 AND ML score < 0.40")
723
 
724
  validated_apneas = []
725
 
 
752
  # Avoid division by zero
753
  rms_ratio = gap_rms / (avg_snore_rms + 1e-10)
754
 
755
+ rms_ok = rms_ratio < 0.55 # Relaxed from 0.5 to 0.55 to account for noise reduction
756
 
757
  except Exception as e:
758
  print(f" ⚠️ RMS check error for candidate {idx+1}: {e}")
 
834
  else:
835
  reasons = []
836
  if not rms_ok:
837
+ reasons.append(f"gap not quiet enough (RMS ratio {rms_ratio:.3f} >= 0.55)")
838
  if not ml_ok:
839
  reasons.append(f"ML says snoring in gap (score {ml_score:.3f} >= 0.40)")
840
  print(f" → REJECTED: {', '.join(reasons)}")
 
847
  # VALIDATION
848
  # ========================================
849
  def validate_sleep_recording(y, sr):
850
+ """Validate that this is a sleep recording with detailed diagnostics"""
851
  duration = len(y) / sr
852
 
853
  if duration < 20:
 
855
 
856
  rms_energy = np.sqrt(np.mean(y**2))
857
 
858
+ # Calculate zero-crossing rate
859
+ zcr = librosa.feature.zero_crossing_rate(y)[0]
860
+ zcr_mean = np.mean(zcr)
 
 
861
 
862
+ # Calculate spectral characteristics
863
  stft = np.abs(librosa.stft(y))
864
  freq_bins = librosa.fft_frequencies(sr=sr)
865
 
 
870
  low_freq_ratio = low_freq_energy / total_energy
871
  high_freq_ratio = high_freq_energy / total_energy
872
 
873
+ # DIAGNOSTIC LOGGING
874
+ print(f" 📊 AUDIO QUALITY DIAGNOSTICS:")
875
+ print(f" RMS Energy: {rms_energy:.4f} (normal: 0.001-0.6)")
876
+ print(f" Zero-Crossing Rate: {zcr_mean:.4f} (speech-like if > 0.2)")
877
+ print(f" Low Freq (<2kHz): {low_freq_ratio:.3f} (should be > 0.4)")
878
+ print(f" High Freq (>4kHz): {high_freq_ratio:.3f} (should be < 0.3)")
879
+
880
+ if rms_energy < 0.001:
881
+ return False, 0.0, "Audio is blank/silent"
882
+
883
+ if rms_energy > 0.6:
884
+ return False, 0.0, "Audio too loud (not a sleep recording)"
885
+
886
  if low_freq_ratio < 0.4:
887
+ return False, 0.0, f"Frequency distribution doesn't match sleep audio (low_freq={low_freq_ratio:.3f}, needs >0.4) - FRONTEND AUDIO QUALITY ISSUE"
888
 
889
  if high_freq_ratio > 0.3:
890
+ return False, 0.0, f"Too much high-frequency content (high_freq={high_freq_ratio:.3f}, needs <0.3) - FRONTEND RECORDING HAS NOISE/ARTIFACTS"
891
+
892
+ if zcr_mean > 0.2:
893
+ return False, 0.0, f"Zero-crossing rate too high ({zcr_mean:.3f}) - Audio sounds like speech/noise, not snoring - FRONTEND RECORDING ISSUE"
894
 
895
  return True, 1.0, "Valid sleep recording detected"
896