Compare commits
1
Commits
dev
...
dev_spectility
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ce51f3b1f |
@@ -60,26 +60,59 @@ class AIOrchestrator:
|
|||||||
stage = session.stage
|
stage = session.stage
|
||||||
code = specialty.get("code", "general")
|
code = specialty.get("code", "general")
|
||||||
lang = (session.language or "ta-IN").lower()
|
lang = (session.language or "ta-IN").lower()
|
||||||
msg_lower = user_message.lower().strip()
|
msg_lower = (user_message or "").lower().strip()
|
||||||
is_negative = msg_lower in ["no", "no more", "nothing", "nothing else", "know nothing", "none", "illness none", "இல்லை", "ஒன்றுமில்லை", "नहीं"]
|
# Broad negative word matching across Indian languages & dialects
|
||||||
|
negative_keywords = [
|
||||||
|
"no", "no more", "nothing", "nothing else", "none", "no illness", "no problem",
|
||||||
|
"இல்லை", "இல்லைங்க", "இல்ல", "ஒன்றுமில்லை", "ஒன்னுமில்ல", "ஏதுமில்லை",
|
||||||
|
"नहीं", "कुछ नहीं", "कोई नहीं", "नाही",
|
||||||
|
"లేదు", "ఏమీ లేదు", "లేదండి",
|
||||||
|
"ಇಲ್ಲ", "ಇಲ್ಲವೇ ಇಲ್ಲ", "ಏನೂ ಇಲ್ಲ",
|
||||||
|
"ഇല്ല", "ഒന്നുമില്ല", "ഇല്ല കട്ടായം",
|
||||||
|
"না", "কিছু না", "নাই",
|
||||||
|
"नाही", "काही नाही",
|
||||||
|
"નથી", "કાંઈ નથી",
|
||||||
|
"ਨਹੀਂ", "ਕੁਝ ਨਹੀਂ"
|
||||||
|
]
|
||||||
|
is_negative = any(k in msg_lower for k in negative_keywords)
|
||||||
|
|
||||||
# Localized clinical phrases (Spoken & Caring Tone)
|
# Localized clinical phrases (Spoken & Caring Tone)
|
||||||
if lang.startswith("ta"):
|
if lang.startswith("ta"):
|
||||||
conclusion_text = "மிக்க நன்றி. உங்கள் உடல்நல விவரங்கள் சிறப்பாக பதிவு செய்யப்பட்டுள்ளன. மருத்துவர் விரைவில் உங்களைப் பரிசீலிப்பார்."
|
conclusion_text = "மிக்க நன்றி. உங்கள் உடல்நல விவரங்கள் சிறப்பாக பதிவு செய்யப்பட்டுள்ளன. மருத்துவர் விரைவில் உங்களைப் பரிசீலிப்பார்."
|
||||||
symptom_q = "இந்த அறிகுறிகள் எத்தனை நாளா இருக்கு? இதுக்காக ஏதாச்சும் மாத்திரை சாப்பிட்டீங்களா?"
|
symptom_q = "சரிங்க, உங்களோட அறிகுறிகள் பற்றி சொன்னீங்க. இந்த பிரச்சனை எத்தனை நாளா இருக்கு? இதுக்காக ஏதாச்சும் மாத்திரை சாப்பிட்டீங்களா?"
|
||||||
med_q = "சரிங்க. உங்களுக்கு வேற ஏதேனும் உடம்பு பிரச்சனைகள் அல்லது மாத்திரை ஒவ்வாமை (Allergy) இருக்கா?"
|
med_q = "சரிங்க. உங்களுக்கு வேற ஏதேனும் உடம்பு பிரச்சனைகள் அல்லது மாத்திரை ஒவ்வாமை (Allergy) இருக்கா?"
|
||||||
elif lang.startswith("hi"):
|
elif lang.startswith("hi"):
|
||||||
conclusion_text = "धन्यवाद। आपकी स्वास्थ्य जानकारी दर्ज कर ली गई है। डॉक्टर जल्द ही समीक्षा करेंगे।"
|
conclusion_text = "धन्यवाद। आपकी स्वास्थ्य जानकारी सफलतापूर्वक दर्ज कर ली गई है। डॉक्टर जल्द ही आपकी समीक्षा करेंगे।"
|
||||||
symptom_q = "आपको यह समस्या कितने दिनों से है और क्या आपने कोई दवाई ली है?"
|
symptom_q = "जी समझ गया। आपको यह समस्या कितने दिनों से है और क्या इसके लिए आपने कोई दवाई ली है?"
|
||||||
med_q = "धन्यवाद। क्या आपको किसी दवाई से एलर्जी या कोई अन्य बीमारी है?"
|
med_q = "ठीक है। क्या आपको किसी दवाई से एलर्जी या कोई अन्य बीमारी है?"
|
||||||
elif lang.startswith("te"):
|
elif lang.startswith("te"):
|
||||||
conclusion_text = "ధన్యవాదాలు. మీ ఆరోగ్య వివరాలు నమోదు చేయబడ్డాయి."
|
conclusion_text = "చాలా ధన్యవాదాలు. మీ ఆరోగ్య వివరాలు నమోదు చేయబడ్డాయి. వైద్యులు త్వరలోనే పరిశీలిస్తారు."
|
||||||
symptom_q = "ఈ సమస్య మీకు ఎన్ని రోజుల నుండి ఉంది మరియు ఏవైనా మందులు వాడారా?"
|
symptom_q = "సరేనండి, ఈ సమస్య మీకు ఎన్ని రోజుల నుండి ఉంది? దీని కోసం ఏవైనా మందులు వాడారా?"
|
||||||
med_q = "ధన్యవాదాలు. మీకు ఏవైనా మందుల పడనితనం (Allergy) ఉందా?"
|
med_q = "ధన్యవాదాలు. మీకు ఏవైనా మందుల పడనితనం (Allergy) లేదా ఇతర ఆరోగ్య సమస్యలు ఉన్నాయా?"
|
||||||
elif lang.startswith("kn"):
|
elif lang.startswith("kn"):
|
||||||
conclusion_text = "ಧನ್ಯವಾದಗಳು. ನಿಮ್ಮ ಆರೋಗ್ಯದ ಮಾಹಿತಿ ದಾಖಲಾಗಿದೆ."
|
conclusion_text = "ತುಂಬಾ ಧನ್ಯವಾದಗಳು. ನಿಮ್ಮ ಆರೋಗ್ಯದ ಮಾಹಿತಿ ದಾಖಲಾಗಿದೆ. ವೈದ್ಯರು ಶೀಘ್ರದಲ್ಲೇ ಪರಿಶೀಲಿಸಲಿದ್ದಾರೆ."
|
||||||
symptom_q = "ಈ ಸಮಸ್ಯೆ ನಿಮಗೆ ಎಷ್ಟು ದಿನಗಳಿಂದ ಇದೆ ಮತ್ತು ಯಾವುದೇ ಮಾತ್ರೆಗಳನ್ನು ತೆಗೆದುಕೊಂಡಿದ್ದೀರಾ?"
|
symptom_q = "ಸರಿ, ಈ ತೊಂದರೆ ನಿಮಗೆ ಎಷ್ಟು ದಿನಗಳಿಂದ ಇದೆ? ಯಾವುದಾದರೂ ಮಾತ್ರೆ ತೆಗೆದುಕೊಂಡಿದ್ದೀರಾ?"
|
||||||
med_q = "ಧನ್ಯವಾದಗಳು. ನಿಮಗೆ ಯಾವುದೇ ಔಷಧಿ ಅಲರ್ಜಿ ಇದೆಯೇ?"
|
med_q = "ಧನ್ಯವಾದಗಳು. ನಿಮಗೆ ಯಾವುದಾದರೂ ಔಷಧಿ ಅಲರ್ಜಿ (Allergy) ಅಥವಾ ಇತರ ಆರೋಗ್ಯ ಸಮಸ್ಯೆ ಇದೆಯೇ?"
|
||||||
|
elif lang.startswith("ml"):
|
||||||
|
conclusion_text = "വളരെ നന്ദി. താങ്കളുടെ വിവരങ്ങൾ രേഖപ്പെടുത്തിയിട്ടുണ്ട്. ഡോക്ടർ ഉടൻ പരിശോധിക്കുന്നതാണ്."
|
||||||
|
symptom_q = "ശരി, ഈ ലക്ഷണങ്ങൾ എത്ര ദിവസമായിട്ടുണ്ട്? ഇതിനായി എന്തെങ്കിലും മരുന്ന് കഴിച്ചിട്ടുണ്ടോ?"
|
||||||
|
med_q = "നന്ദി. താങ്കൾക്ക് എന്തെങ്കിലും മരുന്ന് അലർജിയോ മറ്റ് ആരോഗ്യ പ്രശ്നങ്ങളോ ഉണ്ടോ?"
|
||||||
|
elif lang.startswith("bn"):
|
||||||
|
conclusion_text = "অনেক ধন্যবাদ। আপনার স্বাস্থ্য সম্পর্কিত তথ্য জমা নেওয়া হয়েছে। চিকিৎসক শীঘ্রই পর্যালোচনা করবেন।"
|
||||||
|
symptom_q = "ঠিক আছে, এই সমস্যা আপনার কত দিন ধরে হচ্ছে? এর জন্য কোনো ওষুধ খেয়েছেন কি?"
|
||||||
|
med_q = "ধন্যবাদ। আপনার কি কোনো ওষুধে অ্যালার্জি বা অন্য কোনো রোগ আছে?"
|
||||||
|
elif lang.startswith("mr"):
|
||||||
|
conclusion_text = "खूप खूप धन्यवाद. आपली आरोग्य माहिती नोंदवली गेली आहे. डॉक्टर लवकरच तपासणी करतील."
|
||||||
|
symptom_q = "होय, हा त्रास तुम्हाला किती दिवसांपासून होत आहे आणि काही औषध घेतले आहे का?"
|
||||||
|
med_q = "धन्यवाद. आपल्याला काही औषधांची ॲलर्जी किंवा इतर कोणताही आजार आहे का?"
|
||||||
|
elif lang.startswith("gu"):
|
||||||
|
conclusion_text = "ખૂબ ખૂબ આભાર. આપની આરોગ્ય વિગતો નોંધાઈ ગઈ છે. ડોક્ટર જલ્દી તપાસ કરશે."
|
||||||
|
symptom_q = "બરાબર, આ તકલીફ તમને કેટલા દિવસથી છે અને કોઈ દવા લીધી છે?"
|
||||||
|
med_q = "આભાર. તમને કોઈ દવાની એલર્જી કે અન્ય કોઈ બીમારી છે?"
|
||||||
|
elif lang.startswith("pa"):
|
||||||
|
conclusion_text = "ਬਹੁਤ ਧੰਨਵਾਦ। ਤੁਹਾਡੀ ਜਾਣਕਾਰੀ ਦਰਜ ਕਰ ਲਈ ਗਈ ਹੈ। ਡਾਕਟਰ ਜਲਦੀ ਹੀ ਜਾਂਚ ਕਰਨਗੇ।"
|
||||||
|
symptom_q = "ਜੀ ਠੀਕ ਹੈ, ਇਹ ਸਮੱਸਿਆ ਤੁਹਾਨੂੰ ਕਿੰਨੇ ਦਿਨਾਂ ਤੋਂ ਹੈ ਅਤੇ ਕੀ ਕੋਈ ਦਵਾਈ ਲਈ ਹੈ?"
|
||||||
|
med_q = "ਧੰਨਵਾਦ। ਕੀ ਤੁਹਾਨੂੰ ਕਿਸੇ ਦਵਾਈ ਤੋਂ ਐਲਰਜੀ ਜਾਂ ਕੋਈ ਹੋਰ ਬੀਮਾਰੀ ਹੈ?"
|
||||||
else:
|
else:
|
||||||
conclusion_text = "Thank you. I have recorded your intake details for the doctor to review."
|
conclusion_text = "Thank you. I have recorded your intake details for the doctor to review."
|
||||||
symptom_q = "How long have you had these symptoms, and have you taken any medicines?"
|
symptom_q = "How long have you had these symptoms, and have you taken any medicines?"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import base64
|
||||||
import json
|
import json
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -75,10 +76,11 @@ async def start_voice_onboarding(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Synthesize audio greeting
|
# Synthesize audio greeting
|
||||||
audio_id, _ = await voice_service.text_to_speech(
|
audio_id, greeting_bytes = await voice_service.text_to_speech(
|
||||||
greeting_text,
|
greeting_text,
|
||||||
request.language,
|
request.language,
|
||||||
)
|
)
|
||||||
|
greeting_b64 = f"data:audio/wav;base64,{base64.b64encode(greeting_bytes).decode('utf-8')}" if greeting_bytes else None
|
||||||
|
|
||||||
# Save initial assistant message
|
# Save initial assistant message
|
||||||
onboarding_service.save_message(
|
onboarding_service.save_message(
|
||||||
@@ -99,6 +101,7 @@ async def start_voice_onboarding(
|
|||||||
stage=session.stage,
|
stage=session.stage,
|
||||||
greeting_text=greeting_text,
|
greeting_text=greeting_text,
|
||||||
audio_url=f"/v1/voice-onboarding/audio/{audio_id}",
|
audio_url=f"/v1/voice-onboarding/audio/{audio_id}",
|
||||||
|
audio_base64=greeting_b64,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -252,11 +255,13 @@ async def voice_turn(
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 9. Synthesize AI Speech Audio (TTS)
|
# 9. Synthesize AI Speech Audio (TTS)
|
||||||
audio_id, _ = await voice_service.text_to_speech(
|
audio_id, audio_bytes = await voice_service.text_to_speech(
|
||||||
text=ai_reply_text,
|
text=ai_reply_text,
|
||||||
language_code=session.language,
|
language_code=session.language,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
audio_b64 = f"data:audio/wav;base64,{base64.b64encode(audio_bytes).decode('utf-8')}" if audio_bytes else None
|
||||||
|
|
||||||
return VoiceTurnResponse(
|
return VoiceTurnResponse(
|
||||||
success=True,
|
success=True,
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
@@ -265,6 +270,7 @@ async def voice_turn(
|
|||||||
stage=session.stage,
|
stage=session.stage,
|
||||||
completed=is_completed,
|
completed=is_completed,
|
||||||
audio_url=f"/v1/voice-onboarding/audio/{audio_id}",
|
audio_url=f"/v1/voice-onboarding/audio/{audio_id}",
|
||||||
|
audio_base64=audio_b64,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class StartVoiceOnboardingResponse(BaseModel):
|
|||||||
stage: str
|
stage: str
|
||||||
greeting_text: str
|
greeting_text: str
|
||||||
audio_url: str
|
audio_url: str
|
||||||
|
audio_base64: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class VoiceTurnResponse(BaseModel):
|
class VoiceTurnResponse(BaseModel):
|
||||||
@@ -29,3 +30,4 @@ class VoiceTurnResponse(BaseModel):
|
|||||||
stage: str
|
stage: str
|
||||||
completed: bool = False
|
completed: bool = False
|
||||||
audio_url: str
|
audio_url: str
|
||||||
|
audio_base64: Optional[str] = None
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import io
|
|||||||
import os
|
import os
|
||||||
import wave
|
import wave
|
||||||
import struct
|
import struct
|
||||||
|
import hashlib
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
import httpx2
|
import httpx2
|
||||||
@@ -13,6 +14,8 @@ from app.services.medical_speech_normalizer import normalize_medical_speech
|
|||||||
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||||
AUDIO_DIR = BASE_DIR / "data" / "audio"
|
AUDIO_DIR = BASE_DIR / "data" / "audio"
|
||||||
|
CACHE_DIR = AUDIO_DIR / "cache"
|
||||||
|
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
AUDIO_DIR.mkdir(parents=True, exist_ok=True)
|
AUDIO_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
||||||
@@ -33,9 +36,19 @@ class VoiceService:
|
|||||||
elif lang_lower.startswith("hi"):
|
elif lang_lower.startswith("hi"):
|
||||||
return f"नमस्ते {name} जी, CureSelect अस्पताल में आपका स्वागत है। आज आपको क्या तकलीफ या लक्षण महसूस हो रहे हैं, कृपया बताएंगे?"
|
return f"नमस्ते {name} जी, CureSelect अस्पताल में आपका स्वागत है। आज आपको क्या तकलीफ या लक्षण महसूस हो रहे हैं, कृपया बताएंगे?"
|
||||||
elif lang_lower.startswith("te"):
|
elif lang_lower.startswith("te"):
|
||||||
return f"నమస్కారం {name} గారు, CureSelect హాస్పిటల్కు స్వాగతం. ఈరోజు మీకున్న ఆరోగ్య సమస్య గురించి చెప్పగలరా?"
|
return f"నమస్కారం {name} గారు, CureSelect హాస్పిటల్కు స్వాగతం. ఈరోజు మీకున్న ఆరోగ్య సమస్యలు లేదా లక్షణాల గురించి చెప్పగలరా?"
|
||||||
elif lang_lower.startswith("kn"):
|
elif lang_lower.startswith("kn"):
|
||||||
return f"ನಮಸ್ಕಾರ {name} ಅವರೇ, CureSelect ಆಸ್ಪತ್ರೆಗೆ ಸುಸ್ವಾಗತ. ಇಂದು ನಿಮ್ಮ ಆರೋಗ್ಯದ ತೊಂದರೆ ಬಗ್ಗೆ ತಿಳಿಸಬಹುದೇ?"
|
return f"ನಮಸ್ಕಾರ {name} ಅವರೇ, CureSelect ಆಸ್ಪತ್ರೆಗೆ ಸುಸ್ವಾಗತ. ಇಂದು ನಿಮ್ಮ ಆರೋಗ್ಯದಲ್ಲಿ ಏನು ತೊಂದರೆ ಇದೆ ಎಂದು ತಿಳಿಸಬಹುದೇ?"
|
||||||
|
elif lang_lower.startswith("ml"):
|
||||||
|
return f"നമസ്കാരം {name}, CureSelect ആശുപത്രിയിലേക്ക് സ്വാഗതം. ഇന്ന് താങ്കൾക്ക് എന്തെല്ലാം ആരോഗ്യ ബുദ്ധിമുട്ടുകളാണ് ഉള്ളത് എന്ന് പറയാമോ?"
|
||||||
|
elif lang_lower.startswith("bn"):
|
||||||
|
return f"নমস্কার {name}, CureSelect হাসপাতালে আপনাকে স্বাগতম। আজ আপনার কি ধরনের শারীরিক অসুবিধা হচ্ছে বলবেন কি?"
|
||||||
|
elif lang_lower.startswith("mr"):
|
||||||
|
return f"नमस्कार {name} जी, CureSelect रुग्णालयात आपले स्वागत आहे। आज आपल्याला काय त्रास होत आहे, ते सांगू शकाल का?"
|
||||||
|
elif lang_lower.startswith("gu"):
|
||||||
|
return f"નમસ્તે {name} જી, CureSelect હોસ્પિટલમાં આપનું સ્વાગત છે। આજે આપને શું તકલીફ કે લક્ષણો છે, જરા જણાવશો?"
|
||||||
|
elif lang_lower.startswith("pa"):
|
||||||
|
return f"ਸਤਿ ਸ਼੍ਰੀ ਅਕਾਲ {name} ਜੀ, CureSelect ਹਸਪਤਾਲ ਵਿੱਚ ਤੁਹਾਡਾ ਸਵਾਗਤ ਹੈ। ਅੱਜ ਤੁਹਾਨੂੰ ਕੀ ਤਕਲੀਫ਼ ਹੈ, ਕਿਰਪਾ ਕਰਕੇ ਦੱਸੋਗੇ?"
|
||||||
else:
|
else:
|
||||||
return f"Hello {name}, welcome to CureSelect Healthcare. Could you please share what health symptoms you are experiencing today?"
|
return f"Hello {name}, welcome to CureSelect Healthcare. Could you please share what health symptoms you are experiencing today?"
|
||||||
|
|
||||||
@@ -113,7 +126,16 @@ class VoiceService:
|
|||||||
.strip()
|
.strip()
|
||||||
)
|
)
|
||||||
|
|
||||||
# 1. Use Sarvam AI TTS for Indian Languages (Native Indian Accent)
|
# Instant Disk Cache Lookup (< 0.001s response)
|
||||||
|
cache_key = hashlib.md5(f"{language_code}:{cleaned_text}".encode("utf-8")).hexdigest()
|
||||||
|
cache_path = CACHE_DIR / f"{cache_key}.wav"
|
||||||
|
if cache_path.exists():
|
||||||
|
cached_data = cache_path.read_bytes()
|
||||||
|
# Also save to current session audio_id for endpoint streaming
|
||||||
|
(AUDIO_DIR / f"{audio_id}.wav").write_bytes(cached_data)
|
||||||
|
return audio_id, cached_data
|
||||||
|
|
||||||
|
# 1. Use Sarvam AI TTS for Indian Languages (Native Indian Accent with 1.15x Human Pace)
|
||||||
if (
|
if (
|
||||||
self.sarvam_key
|
self.sarvam_key
|
||||||
and self.sarvam_key.strip()
|
and self.sarvam_key.strip()
|
||||||
@@ -132,6 +154,7 @@ class VoiceService:
|
|||||||
"target_language_code": language_code,
|
"target_language_code": language_code,
|
||||||
"speaker": speaker,
|
"speaker": speaker,
|
||||||
"model": "bulbul:v3",
|
"model": "bulbul:v3",
|
||||||
|
"pace": 1.15,
|
||||||
}
|
}
|
||||||
res = await client.post(
|
res = await client.post(
|
||||||
"https://api.sarvam.ai/text-to-speech",
|
"https://api.sarvam.ai/text-to-speech",
|
||||||
@@ -145,6 +168,7 @@ class VoiceService:
|
|||||||
audio_data = base64.b64decode(audios[0])
|
audio_data = base64.b64decode(audios[0])
|
||||||
file_path = AUDIO_DIR / f"{audio_id}.wav"
|
file_path = AUDIO_DIR / f"{audio_id}.wav"
|
||||||
file_path.write_bytes(audio_data)
|
file_path.write_bytes(audio_data)
|
||||||
|
cache_path.write_bytes(audio_data)
|
||||||
return audio_id, audio_data
|
return audio_id, audio_data
|
||||||
else:
|
else:
|
||||||
print(f"[Sarvam TTS HTTP Error]: {res.status_code} - {res.text}")
|
print(f"[Sarvam TTS HTTP Error]: {res.status_code} - {res.text}")
|
||||||
|
|||||||
Reference in New Issue
Block a user