Update app.py
Browse files
app.py
CHANGED
@@ -254,8 +254,17 @@ def analyze_symptoms(text):
|
|
254 |
elif not all("label" in item and "score" in item for item in flattened):
|
255 |
logger.warning(f"Missing label or score in flattened result: {flattened}")
|
256 |
else:
|
257 |
-
|
258 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
259 |
elif isinstance(result, dict):
|
260 |
logger.debug("Model returned single dictionary")
|
261 |
if "label" in result and "score" in result:
|
@@ -394,4 +403,95 @@ async def analyze_voice(audio_file, language="en", user_id="anonymous", consent_
|
|
394 |
if prediction == "No health condition detected"
|
395 |
else f"Possible {prediction.lower()} detected based on symptoms like '{transcription.lower()}', consult a doctor. This is not a medical diagnosis."
|
396 |
)
|
397 |
-
logger.info(f"Feedback: {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
elif not all("label" in item and "score" in item for item in flattened):
|
255 |
logger.warning(f"Missing label or score in flattened result: {flattened}")
|
256 |
else:
|
257 |
+
# Sort by score (descending) and take the highest
|
258 |
+
valid_items = [
|
259 |
+
item for item in flattened
|
260 |
+
if isinstance(item, dict) and "label" in item and "score" in item
|
261 |
+
and isinstance(item["label"], str)
|
262 |
+
and isinstance(item["score"], (int, float)) and 0 <= item["score"] <= 1
|
263 |
+
]
|
264 |
+
if valid_items:
|
265 |
+
sorted_items = sorted(valid_items, key=lambda x: x["score"], reverse=True)
|
266 |
+
prediction = sorted_items[0]["label"]
|
267 |
+
score = sorted_items[0]["score"]
|
268 |
elif isinstance(result, dict):
|
269 |
logger.debug("Model returned single dictionary")
|
270 |
if "label" in result and "score" in result:
|
|
|
403 |
if prediction == "No health condition detected"
|
404 |
else f"Possible {prediction.lower()} detected based on symptoms like '{transcription.lower()}', consult a doctor. This is not a medical diagnosis."
|
405 |
)
|
406 |
+
logger.info(f"Feedback: {feedback}, Transcription: {transcription}, Prediction: {prediction}, Score: {score:.4f}")
|
407 |
+
|
408 |
+
# Save to Salesforce
|
409 |
+
save_to_salesforce(user_id, transcription, prediction, score, feedback, consent_granted)
|
410 |
+
|
411 |
+
try:
|
412 |
+
os.remove(audio_file)
|
413 |
+
logger.debug(f"Deleted audio file: {audio_file}")
|
414 |
+
except Exception as e:
|
415 |
+
logger.error(f"Failed to delete audio file: {str(e)}")
|
416 |
+
|
417 |
+
# Speak response
|
418 |
+
await speak_response(feedback)
|
419 |
+
|
420 |
+
return feedback
|
421 |
+
except Exception as e:
|
422 |
+
logger.error(f"Voice analysis failed: {str(e)}")
|
423 |
+
return f"Error: {str(e)}"
|
424 |
+
|
425 |
+
async def test_with_sample_audio(language="en", user_id="anonymous", consent_granted=True):
|
426 |
+
"""Test with synthetic audio."""
|
427 |
+
temp_dir = os.path.join(tempfile.gettempdir(), "audio_samples")
|
428 |
+
if not ensure_writable_dir(temp_dir):
|
429 |
+
fallback_dir = os.path.join(os.getcwd(), "temp_audio_samples")
|
430 |
+
if not ensure_writable_dir(fallback_dir):
|
431 |
+
logger.error(f"Temp directories {temp_dir} and {fallback_dir} not writable")
|
432 |
+
return f"Error: Temp directories not writable"
|
433 |
+
temp_dir = fallback_dir
|
434 |
+
|
435 |
+
sample_audio_path = os.path.join(temp_dir, "dummy_test.wav")
|
436 |
+
logger.info(f"Generating synthetic audio at: {sample_audio_path}")
|
437 |
+
sr = 16000
|
438 |
+
t = np.linspace(0, 2, 2 * sr)
|
439 |
+
freq_mod = 440 + 10 * np.sin(2 * np.pi * 0.5 * t)
|
440 |
+
amplitude_mod = 0.5 + 0.1 * np.sin(2 * np.pi * 0.3 * t)
|
441 |
+
noise = 0.01 * np.random.normal(0, 1, len(t))
|
442 |
+
dummy_audio = amplitude_mod * np.sin(2 * np.pi * freq_mod * t) + noise
|
443 |
+
try:
|
444 |
+
soundfile.write(dummy_audio, sr, sample_audio_path)
|
445 |
+
logger.info(f"Generated synthetic audio: {sample_audio_path}")
|
446 |
+
except Exception as e:
|
447 |
+
logger.error(f"Failed to write synthetic audio: {str(e)}")
|
448 |
+
return f"Error: Failed to generate synthetic audio: {str(e)}"
|
449 |
+
|
450 |
+
if not os.path.exists(sample_audio_path):
|
451 |
+
logger.error(f"Synthetic audio not created: {sample_audio_path}")
|
452 |
+
return f"Error: Synthetic audio not created: {sample_audio_path}"
|
453 |
+
|
454 |
+
mock_transcription = "I have a cough and sore throat"
|
455 |
+
logger.info(f"Mock transcription: {mock_transcription}")
|
456 |
+
prediction, score = analyze_symptoms(mock_transcription)
|
457 |
+
feedback = (
|
458 |
+
"No health condition detected, consult a doctor if symptoms persist. This is not a medical diagnosis."
|
459 |
+
if prediction == "No health condition detected"
|
460 |
+
else f"Possible {prediction.lower()} detected based on symptoms like '{mock_transcription.lower()}', consult a doctor. This is not a medical diagnosis."
|
461 |
+
)
|
462 |
+
logger.info(f"Test feedback: {feedback}, Prediction: {prediction}, Score: {score:.4f}")
|
463 |
+
|
464 |
+
# Save to Salesforce
|
465 |
+
save_to_salesforce(user_id, mock_transcription, prediction, score, feedback, consent_granted)
|
466 |
+
|
467 |
+
try:
|
468 |
+
os.remove(sample_audio_path)
|
469 |
+
logger.debug(f"Deleted test audio: {sample_audio_path}")
|
470 |
+
except Exception:
|
471 |
+
pass
|
472 |
+
return feedback
|
473 |
+
|
474 |
+
async def voicebot_interface(audio_file, language="en", user_id="anonymous", consent_granted=True):
|
475 |
+
"""Gradio interface wrapper."""
|
476 |
+
return await analyze_voice(audio_file, language, user_id, consent_granted)
|
477 |
+
|
478 |
+
# Gradio interface
|
479 |
+
iface = gr.Interface(
|
480 |
+
fn=voicebot_interface,
|
481 |
+
inputs=[
|
482 |
+
gr.Audio(type="filepath", label="Record or Upload Voice (WAV, MP3, FLAC, 1+ sec)"),
|
483 |
+
gr.Dropdown(["en", "es", "hi", "zh"], label="Language", value="en"),
|
484 |
+
gr.Textbox(label="User ID (optional)", value="anonymous"),
|
485 |
+
gr.Checkbox(label="Consent to store data", value=True)
|
486 |
+
],
|
487 |
+
outputs=gr.Textbox(label="Health Assessment Feedback"),
|
488 |
+
title="Smart Voicebot for Public Health",
|
489 |
+
description="Record or upload a voice sample describing symptoms (e.g., 'I have a cough') for preliminary health assessment. Supports English, Spanish, Hindi, Mandarin. Not a diagnostic tool. Data is encrypted and stored with consent. Complies with HIPAA/GDPR."
|
490 |
+
)
|
491 |
+
|
492 |
+
if __name__ == "__main__":
|
493 |
+
logger.info("Starting Voice Health Analyzer")
|
494 |
+
# Test with synthetic audio
|
495 |
+
loop = asyncio.get_event_loop()
|
496 |
+
print(loop.run_until_complete(test_with_sample_audio()))
|
497 |
+
iface.launch(server_name="0.0.0.0", server_port=7860)
|