corrected language detection
Browse files- python-services/llm_server.py +25 -14
- python-services/utils.py +7 -0
python-services/llm_server.py
CHANGED
|
@@ -20,7 +20,8 @@ from pydantic import BaseModel
|
|
| 20 |
# Internal Domain Layer Imports
|
| 21 |
from client import groq, fireworks
|
| 22 |
from conversation_manager import ConversationManager, ConversationSession
|
| 23 |
-
from
|
|
|
|
| 24 |
from prompt_builder import build_system_prompt
|
| 25 |
from summary import generate_summary
|
| 26 |
from caller_info_extractor import extract_name_from_text, extract_phone_from_text
|
|
@@ -122,37 +123,47 @@ def _extract_sentences(buffer: str) -> tuple[list[str], str]:
|
|
| 122 |
return sentences, buffer[last_end:]
|
| 123 |
|
| 124 |
|
| 125 |
-
async def _fire_tts(sentence: str, language: str, gender: str) -> Optional[bytes]:
|
| 126 |
"""
|
| 127 |
Asynchronously POST a single sentence to the deployed TTS Space.
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
Returns raw audio bytes (audio/mpeg) on success, None on any failure.
|
| 131 |
"""
|
| 132 |
sentence = sentence.strip()
|
| 133 |
if not sentence:
|
| 134 |
-
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
try:
|
| 136 |
async with httpx.AsyncClient(timeout=TTS_SYNTHESISE_TIMEOUT) as client:
|
| 137 |
resp = await client.post(
|
| 138 |
f"{TTS_SPACE_URL}/synthesise",
|
| 139 |
-
json={"text": sentence, "language":
|
| 140 |
)
|
| 141 |
if resp.status_code == 200:
|
| 142 |
-
logger.info(f"TTS ✓ lang={
|
| 143 |
-
return resp.content
|
| 144 |
logger.warning(
|
| 145 |
f"TTS Space returned HTTP {resp.status_code}: {resp.text[:120]}"
|
| 146 |
)
|
| 147 |
-
return None
|
| 148 |
except httpx.TimeoutException:
|
| 149 |
logger.error(
|
| 150 |
f"TTS request timed out ({TTS_SYNTHESISE_TIMEOUT}s): {sentence[:60]!r}"
|
| 151 |
)
|
| 152 |
-
return None
|
| 153 |
except Exception as exc:
|
| 154 |
logger.error(f"TTS request error: {exc}")
|
| 155 |
-
return None
|
| 156 |
|
| 157 |
|
| 158 |
def _start_groq_stream_thread(
|
|
@@ -534,13 +545,13 @@ async def chat_stream(req: ChatRequest):
|
|
| 534 |
Fire TTS for one sentence.
|
| 535 |
Returns a ready-to-yield SSE audio event string, or None if TTS failed.
|
| 536 |
"""
|
| 537 |
-
audio_bytes = await _fire_tts(sentence, detected_language, tts_gender)
|
| 538 |
if audio_bytes:
|
| 539 |
return _sse({
|
| 540 |
"type": "audio",
|
| 541 |
"sentence": sentence,
|
| 542 |
"audio_b64": base64.b64encode(audio_bytes).decode("utf-8"),
|
| 543 |
-
"lang":
|
| 544 |
})
|
| 545 |
return None
|
| 546 |
|
|
|
|
| 20 |
# Internal Domain Layer Imports
|
| 21 |
from client import groq, fireworks
|
| 22 |
from conversation_manager import ConversationManager, ConversationSession
|
| 23 |
+
from utils import detect_language_from_content, SUPPORTED_LANGUAGES
|
| 24 |
+
from language_config import normalize_language
|
| 25 |
from prompt_builder import build_system_prompt
|
| 26 |
from summary import generate_summary
|
| 27 |
from caller_info_extractor import extract_name_from_text, extract_phone_from_text
|
|
|
|
| 123 |
return sentences, buffer[last_end:]
|
| 124 |
|
| 125 |
|
| 126 |
+
async def _fire_tts(sentence: str, language: str, gender: str) -> tuple[Optional[bytes], str]:
|
| 127 |
"""
|
| 128 |
Asynchronously POST a single sentence to the deployed TTS Space.
|
| 129 |
+
Language is resolved from sentence content so Urdu/English never collide.
|
| 130 |
+
Returns (audio_bytes, tts_language) on success, (None, tts_language) on failure.
|
|
|
|
| 131 |
"""
|
| 132 |
sentence = sentence.strip()
|
| 133 |
if not sentence:
|
| 134 |
+
return None, normalize_language(language)
|
| 135 |
+
|
| 136 |
+
tts_lang = normalize_language(detect_language_from_content(sentence))
|
| 137 |
+
session_lang = normalize_language(language)
|
| 138 |
+
if tts_lang != session_lang:
|
| 139 |
+
logger.info(
|
| 140 |
+
"TTS lang from content: session=%s → sentence=%s preview=%r",
|
| 141 |
+
session_lang,
|
| 142 |
+
tts_lang,
|
| 143 |
+
sentence[:60],
|
| 144 |
+
)
|
| 145 |
+
|
| 146 |
try:
|
| 147 |
async with httpx.AsyncClient(timeout=TTS_SYNTHESISE_TIMEOUT) as client:
|
| 148 |
resp = await client.post(
|
| 149 |
f"{TTS_SPACE_URL}/synthesise",
|
| 150 |
+
json={"text": sentence, "language": tts_lang, "gender": gender},
|
| 151 |
)
|
| 152 |
if resp.status_code == 200:
|
| 153 |
+
logger.info(f"TTS ✓ lang={tts_lang} chars={len(sentence)}")
|
| 154 |
+
return resp.content, tts_lang
|
| 155 |
logger.warning(
|
| 156 |
f"TTS Space returned HTTP {resp.status_code}: {resp.text[:120]}"
|
| 157 |
)
|
| 158 |
+
return None, tts_lang
|
| 159 |
except httpx.TimeoutException:
|
| 160 |
logger.error(
|
| 161 |
f"TTS request timed out ({TTS_SYNTHESISE_TIMEOUT}s): {sentence[:60]!r}"
|
| 162 |
)
|
| 163 |
+
return None, tts_lang
|
| 164 |
except Exception as exc:
|
| 165 |
logger.error(f"TTS request error: {exc}")
|
| 166 |
+
return None, tts_lang
|
| 167 |
|
| 168 |
|
| 169 |
def _start_groq_stream_thread(
|
|
|
|
| 545 |
Fire TTS for one sentence.
|
| 546 |
Returns a ready-to-yield SSE audio event string, or None if TTS failed.
|
| 547 |
"""
|
| 548 |
+
audio_bytes, tts_lang = await _fire_tts(sentence, detected_language, tts_gender)
|
| 549 |
if audio_bytes:
|
| 550 |
return _sse({
|
| 551 |
"type": "audio",
|
| 552 |
"sentence": sentence,
|
| 553 |
"audio_b64": base64.b64encode(audio_bytes).decode("utf-8"),
|
| 554 |
+
"lang": tts_lang,
|
| 555 |
})
|
| 556 |
return None
|
| 557 |
|
python-services/utils.py
CHANGED
|
@@ -12,6 +12,8 @@ from language_config import (
|
|
| 12 |
GURMUKHI,
|
| 13 |
has_arabic_script,
|
| 14 |
normalize_language,
|
|
|
|
|
|
|
| 15 |
)
|
| 16 |
|
| 17 |
|
|
@@ -45,6 +47,11 @@ def detect_language_from_content(text: str) -> str:
|
|
| 45 |
if detect_roman_urdu(text):
|
| 46 |
return "ur"
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
return "en"
|
| 49 |
|
| 50 |
|
|
|
|
| 12 |
GURMUKHI,
|
| 13 |
has_arabic_script,
|
| 14 |
normalize_language,
|
| 15 |
+
SUPPORTED_LANGUAGES,
|
| 16 |
+
URDU_SHARED_PHRASES,
|
| 17 |
)
|
| 18 |
|
| 19 |
|
|
|
|
| 47 |
if detect_roman_urdu(text):
|
| 48 |
return "ur"
|
| 49 |
|
| 50 |
+
text_lower = text.lower()
|
| 51 |
+
for phrase in URDU_SHARED_PHRASES:
|
| 52 |
+
if phrase.lower() in text_lower:
|
| 53 |
+
return "ur"
|
| 54 |
+
|
| 55 |
return "en"
|
| 56 |
|
| 57 |
|