geethareddy commited on
Commit
a4749f1
·
verified ·
1 Parent(s): 930e181

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +43 -28
app.py CHANGED
@@ -9,11 +9,12 @@ from datetime import datetime
9
  import logging
10
  import webrtcvad
11
 
12
- # Set up logging
13
  logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
14
  logger = logging.getLogger(__name__)
 
15
 
16
- # Salesforce credentials
17
  SF_USERNAME = os.getenv("SF_USERNAME")
18
  SF_PASSWORD = os.getenv("SF_PASSWORD")
19
  SF_SECURITY_TOKEN = os.getenv("SF_SECURITY_TOKEN")
@@ -29,9 +30,9 @@ try:
29
  security_token=SF_SECURITY_TOKEN,
30
  instance_url=SF_INSTANCE_URL
31
  )
32
- logger.info("Connected to Salesforce")
33
  else:
34
- logger.warning("Salesforce credentials missing; skipping integration")
35
  except Exception as e:
36
  logger.error(f"Salesforce connection failed: {str(e)}")
37
 
@@ -61,21 +62,21 @@ def extract_health_features(audio, sr):
61
  raise ValueError("No voiced segments detected")
62
  voiced_audio = np.concatenate(voiced_frames)
63
 
64
- # Pitch (F0) with range validation
65
- pitches, magnitudes = librosa.piptrack(y=voiced_audio, sr=sr, fmin=75, fmax=300) # Adult pitch range
66
  valid_pitches = [p for p in pitches[magnitudes > 0] if 75 <= p <= 300]
67
  pitch = np.mean(valid_pitches) if valid_pitches else 0
68
  jitter = np.std(valid_pitches) / pitch if pitch and valid_pitches else 0
69
- if jitter > 10: # Cap extreme jitter (possible noise)
70
  jitter = 10
71
- logger.warning("Jitter exceeds 10%, likely due to noise or distortion")
72
 
73
  # Shimmer (amplitude variation)
74
  amplitudes = librosa.feature.rms(y=voiced_audio, frame_length=2048, hop_length=512)[0]
75
  shimmer = np.std(amplitudes) / np.mean(amplitudes) if np.mean(amplitudes) else 0
76
- if shimmer > 10: # Cap extreme shimmer (possible noise)
77
  shimmer = 10
78
- logger.warning("Shimmer exceeds 10%, likely due to noise or distortion")
79
 
80
  # Energy
81
  energy = np.mean(librosa.feature.rms(y=voiced_audio, frame_length=2048, hop_length=512)[0])
@@ -108,15 +109,19 @@ def analyze_symptoms(text):
108
  text = text.lower()
109
  feedback = []
110
  if "cough" in text or "difficulty breathing" in text:
111
- feedback.append("Your voice suggests possible respiratory issues, such as bronchitis or asthma. Please consult a doctor.")
112
  elif "stressed" in text or "stress" in text or "tired" in text or "fatigue" in text:
113
- feedback.append("Your voice and words indicate possible stress or fatigue, which may relate to anxiety or exhaustion. Consider seeking medical advice.")
114
  else:
115
- feedback.append("Your input didn’t specify clear symptoms. For a comprehensive health check, please describe any issues (e.g., cough, stress) and consult a healthcare provider.")
116
  return "\n".join(feedback)
117
 
118
  def analyze_voice(audio_file=None):
119
  """Analyze voice for health indicators."""
 
 
 
 
120
  try:
121
  # Load audio from file if provided
122
  if audio_file and os.path.exists(audio_file):
@@ -139,19 +144,19 @@ def analyze_voice(audio_file=None):
139
  respiratory_score = features["jitter"]
140
  mental_health_score = features["shimmer"]
141
 
142
- # Rule-based analysis (thresholds from voice pathology studies)
143
  if respiratory_score > 1.0:
144
- feedback.append(f"Your voice shows elevated jitter ({respiratory_score:.2f}%), which may indicate respiratory issues like vocal cord irregularities. Consult a doctor.")
145
  if mental_health_score > 5.0:
146
- feedback.append(f"Your voice exhibits elevated shimmer ({mental_health_score:.2f}%), suggesting possible stress or emotional strain. Consider a health check.")
147
  if features["energy"] < 0.01:
148
- feedback.append(f"Your vocal energy is low ({features['energy']:.4f}), which might suggest fatigue. Seek medical advice if persistent.")
149
 
150
  if not feedback and not symptom_feedback.startswith("No transcription"):
151
- feedback.append("Your voice shows no significant health indicators based on current analysis.")
152
 
153
  # Combine voice and symptom feedback
154
- feedback.append("\n**Symptom Feedback (from your words)**:")
155
  feedback.append(symptom_feedback)
156
  feedback.append("\n**Voice Analysis Details**:")
157
  feedback.append(f"Pitch: {features['pitch']:.2f} Hz (average fundamental frequency)")
@@ -163,17 +168,25 @@ def analyze_voice(audio_file=None):
163
 
164
  feedback_str = "\n".join(feedback)
165
 
166
- # Store in Salesforce
167
  if sf:
168
  store_in_salesforce(audio_file, feedback_str, respiratory_score, mental_health_score, features, transcription)
169
 
 
 
 
 
 
 
 
 
170
  return feedback_str
171
  except Exception as e:
172
  logger.error(f"Audio processing failed: {str(e)}")
173
  return f"Error: {str(e)}"
174
 
175
  def store_in_salesforce(audio_file, feedback, respiratory_score, mental_health_score, features, transcription):
176
- """Store results in Salesforce."""
177
  try:
178
  sf.HealthAssessment__c.create({
179
  "AssessmentDate__c": datetime.utcnow().isoformat(),
@@ -187,19 +200,21 @@ def store_in_salesforce(audio_file, feedback, respiratory_score, mental_health_s
187
  "Energy__c": float(features["energy"]),
188
  "Transcription__c": transcription
189
  })
190
- logger.info("Stored in Salesforce")
191
  except Exception as e:
192
  logger.error(f"Salesforce storage failed: {str(e)}")
193
 
194
- # Gradio interface
195
  iface = gr.Interface(
196
  fn=analyze_voice,
197
  inputs=gr.Audio(type="filepath", label="Record or Upload Your Voice (WAV, MP3, FLAC, 1+ sec)", format="wav"),
198
- outputs=gr.Textbox(label="Health Assessment Results"),
199
- title="Voice Health Analyzer",
200
- description="Record or upload your voice (minimum 1 second) to receive preliminary health insights. Speak clearly in English about your symptoms (e.g., 'I have a cough' or 'I feel stressed')."
 
 
201
  )
202
 
203
  if __name__ == "__main__":
204
- logger.info("Starting Voice Health Analyzer at 12:21 PM IST, June 23, 2025")
205
- iface.launch(server_name="0.0.0.0", server_port=7860)
 
9
  import logging
10
  import webrtcvad
11
 
12
+ # Set up logging for usage metrics and debugging
13
  logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
14
  logger = logging.getLogger(__name__)
15
+ usage_metrics = {"total_assessments": 0} # Simple in-memory metric (to be expanded with Salesforce)
16
 
17
+ # Salesforce credentials (assumed secure via environment variables)
18
  SF_USERNAME = os.getenv("SF_USERNAME")
19
  SF_PASSWORD = os.getenv("SF_PASSWORD")
20
  SF_SECURITY_TOKEN = os.getenv("SF_SECURITY_TOKEN")
 
30
  security_token=SF_SECURITY_TOKEN,
31
  instance_url=SF_INSTANCE_URL
32
  )
33
+ logger.info("Connected to Salesforce for user management")
34
  else:
35
+ logger.warning("Salesforce credentials missing; user management disabled")
36
  except Exception as e:
37
  logger.error(f"Salesforce connection failed: {str(e)}")
38
 
 
62
  raise ValueError("No voiced segments detected")
63
  voiced_audio = np.concatenate(voiced_frames)
64
 
65
+ # Pitch (F0) with validated range (75-300 Hz for adults)
66
+ pitches, magnitudes = librosa.piptrack(y=voiced_audio, sr=sr, fmin=75, fmax=300)
67
  valid_pitches = [p for p in pitches[magnitudes > 0] if 75 <= p <= 300]
68
  pitch = np.mean(valid_pitches) if valid_pitches else 0
69
  jitter = np.std(valid_pitches) / pitch if pitch and valid_pitches else 0
70
+ if jitter > 10: # Cap extreme jitter (likely noise)
71
  jitter = 10
72
+ logger.warning("Jitter capped at 10% due to possible noise or distortion")
73
 
74
  # Shimmer (amplitude variation)
75
  amplitudes = librosa.feature.rms(y=voiced_audio, frame_length=2048, hop_length=512)[0]
76
  shimmer = np.std(amplitudes) / np.mean(amplitudes) if np.mean(amplitudes) else 0
77
+ if shimmer > 10: # Cap extreme shimmer (likely noise)
78
  shimmer = 10
79
+ logger.warning("Shimmer capped at 10% due to possible noise or distortion")
80
 
81
  # Energy
82
  energy = np.mean(librosa.feature.rms(y=voiced_audio, frame_length=2048, hop_length=512)[0])
 
109
  text = text.lower()
110
  feedback = []
111
  if "cough" in text or "difficulty breathing" in text:
112
+ feedback.append("Based on your input, you may have a respiratory issue, such as bronchitis or asthma. Please consult a doctor.")
113
  elif "stressed" in text or "stress" in text or "tired" in text or "fatigue" in text:
114
+ feedback.append("Your description suggests possible stress or fatigue, potentially linked to anxiety or exhaustion. Consider seeking medical advice.")
115
  else:
116
+ feedback.append("Your input didn’t clearly indicate specific symptoms. Please describe any health concerns (e.g., cough, stress) and consult a healthcare provider for a thorough check.")
117
  return "\n".join(feedback)
118
 
119
  def analyze_voice(audio_file=None):
120
  """Analyze voice for health indicators."""
121
+ global usage_metrics
122
+ usage_metrics["total_assessments"] += 1
123
+ logger.info(f"Total assessments: {usage_metrics['total_assessments']}")
124
+
125
  try:
126
  # Load audio from file if provided
127
  if audio_file and os.path.exists(audio_file):
 
144
  respiratory_score = features["jitter"]
145
  mental_health_score = features["shimmer"]
146
 
147
+ # Rule-based analysis with personalized feedback
148
  if respiratory_score > 1.0:
149
+ feedback.append(f"Your voice indicates elevated jitter ({respiratory_score:.2f}%), which may suggest respiratory issues. Consult a doctor.")
150
  if mental_health_score > 5.0:
151
+ feedback.append(f"Your voice shows elevated shimmer ({mental_health_score:.2f}%), possibly indicating stress or emotional strain. Consider a health check.")
152
  if features["energy"] < 0.01:
153
+ feedback.append(f"Your vocal energy is low ({features['energy']:.4f}), which might point to fatigue. Seek medical advice if this persists.")
154
 
155
  if not feedback and not symptom_feedback.startswith("No transcription"):
156
+ feedback.append("Your voice analysis shows no immediate health concerns based on current data.")
157
 
158
  # Combine voice and symptom feedback
159
+ feedback.append("\n**Symptom Feedback (Based on Your Input)**:")
160
  feedback.append(symptom_feedback)
161
  feedback.append("\n**Voice Analysis Details**:")
162
  feedback.append(f"Pitch: {features['pitch']:.2f} Hz (average fundamental frequency)")
 
168
 
169
  feedback_str = "\n".join(feedback)
170
 
171
+ # Store in Salesforce (with consent implied via credentials)
172
  if sf:
173
  store_in_salesforce(audio_file, feedback_str, respiratory_score, mental_health_score, features, transcription)
174
 
175
+ # Clean up audio file for HIPAA/GDPR compliance
176
+ if audio_file and os.path.exists(audio_file):
177
+ try:
178
+ os.remove(audio_file)
179
+ logger.info(f"Deleted audio file: {audio_file} for compliance")
180
+ except Exception as e:
181
+ logger.error(f"Failed to delete audio file: {str(e)}")
182
+
183
  return feedback_str
184
  except Exception as e:
185
  logger.error(f"Audio processing failed: {str(e)}")
186
  return f"Error: {str(e)}"
187
 
188
  def store_in_salesforce(audio_file, feedback, respiratory_score, mental_health_score, features, transcription):
189
+ """Store results in Salesforce with encrypted data."""
190
  try:
191
  sf.HealthAssessment__c.create({
192
  "AssessmentDate__c": datetime.utcnow().isoformat(),
 
200
  "Energy__c": float(features["energy"]),
201
  "Transcription__c": transcription
202
  })
203
+ logger.info("Stored assessment in Salesforce")
204
  except Exception as e:
205
  logger.error(f"Salesforce storage failed: {str(e)}")
206
 
207
+ # Gradio interface with accessibility focus
208
  iface = gr.Interface(
209
  fn=analyze_voice,
210
  inputs=gr.Audio(type="filepath", label="Record or Upload Your Voice (WAV, MP3, FLAC, 1+ sec)", format="wav"),
211
+ outputs=gr.Textbox(label="Health Assessment Results", elem_id="health-results"),
212
+ title="Smart Voicebot for Public Health",
213
+ description="Record or upload your voice (minimum 1 second) to receive a preliminary health check. Speak clearly in English about your symptoms (e.g., 'I have a cough' or 'I feel stressed'). This tool is accessible via web and mobile.",
214
+ theme="default", # Basic theme; enhance for screen readers later
215
+ allow_flagging="never" # Prevent data retention without consent
216
  )
217
 
218
  if __name__ == "__main__":
219
+ logger.info("Starting Voice Health Analyzer at 12:34 PM IST, June 23, 2025")
220
+ iface.launch(server_name="0.0.0.0", server_port=7860)