.
This commit is contained in:
@@ -557,6 +557,13 @@ def _sanitize_voice_text(text: str) -> str:
|
||||
|
||||
DEFAULT_NAME_RETRY_TEXT = "Подскажите, пожалуйста, как я могу к вам обращаться?"
|
||||
DEFAULT_PERSONALIZED_GREETING_TEMPLATE = '{name}, я работаю на основе искусственного интеллекта и постараюсь максимально внимательно разобраться с вашим вопросом. Чем я могу помочь?'
|
||||
_NAME_CAPTURE_CONFUSION_ALIASES = {
|
||||
"парень": "Арнур",
|
||||
"арнер": "Арнур",
|
||||
"ар нур": "Арнур",
|
||||
"шомарт": "Жомарт",
|
||||
"шумарт": "Жомарт",
|
||||
}
|
||||
|
||||
|
||||
def _voice_text_key(text: str | None) -> str:
|
||||
@@ -564,6 +571,9 @@ def _voice_text_key(text: str | None) -> str:
|
||||
return re.sub(r"\s+", " ", compact).strip()
|
||||
|
||||
|
||||
_KAZAKH_NAME_BY_KEY = {_voice_text_key(name): name for name in TOP_KAZAKH_NAMES}
|
||||
|
||||
|
||||
def _voice_letters_key(text: str | None) -> str:
|
||||
return "".join(re.findall(r"[^\W\d_]+", str(text or "").lower(), flags=re.UNICODE))
|
||||
|
||||
@@ -582,6 +592,39 @@ def _looks_like_supported_name_text(text: str) -> bool:
|
||||
)
|
||||
|
||||
|
||||
def _correct_name_capture_candidate(name: str | None) -> str | None:
|
||||
candidate = _canonical_name(str(name or "").strip())
|
||||
if not candidate:
|
||||
return None
|
||||
key = _voice_text_key(candidate)
|
||||
exact_match = _KAZAKH_NAME_BY_KEY.get(key)
|
||||
if exact_match:
|
||||
return exact_match
|
||||
alias_match = _NAME_CAPTURE_CONFUSION_ALIASES.get(key)
|
||||
if alias_match:
|
||||
return alias_match
|
||||
|
||||
best_name = None
|
||||
best_ratio = 0.0
|
||||
for gazetteer_key, gazetteer_name in _KAZAKH_NAME_BY_KEY.items():
|
||||
ratio = difflib.SequenceMatcher(None, key, gazetteer_key).ratio()
|
||||
if ratio > best_ratio:
|
||||
best_ratio = ratio
|
||||
best_name = gazetteer_name
|
||||
if best_name is None:
|
||||
return candidate
|
||||
threshold = 0.82 if len(key) >= 5 else 0.9
|
||||
if best_ratio >= threshold:
|
||||
LOGGER.info(
|
||||
"name capture candidate corrected via Kazakh names: candidate=%r corrected=%r ratio=%.3f",
|
||||
candidate,
|
||||
best_name,
|
||||
best_ratio,
|
||||
)
|
||||
return best_name
|
||||
return candidate
|
||||
|
||||
|
||||
def _normalize_name_candidate(text: str | None) -> str | None:
|
||||
raw = str(text or "").strip(" \t\r\n,.;:!?\"'()[]{}")
|
||||
if not raw or any(ch.isdigit() for ch in raw):
|
||||
@@ -798,6 +841,16 @@ def _voice_start_name_outcome(text: str | None) -> tuple[str, str | None]:
|
||||
if not raw:
|
||||
return "name_not_obtained", None
|
||||
candidate, needs_followup = _extract_name_candidate(raw)
|
||||
if candidate:
|
||||
corrected_candidate = _correct_name_capture_candidate(candidate) or candidate
|
||||
if corrected_candidate != candidate:
|
||||
LOGGER.info(
|
||||
"name capture candidate normalized: candidate=%r corrected=%r transcript=%r",
|
||||
candidate,
|
||||
corrected_candidate,
|
||||
_preview_text(raw),
|
||||
)
|
||||
candidate = corrected_candidate
|
||||
if candidate and not needs_followup:
|
||||
return "name_obtained", candidate
|
||||
if candidate:
|
||||
@@ -1493,6 +1546,8 @@ class CallSession:
|
||||
await self._stt.transcribe(
|
||||
audio_bytes,
|
||||
keyterms=self._name_capture_keyterms() if self._awaiting_customer_name else None,
|
||||
language_code=self._name_capture_language_code() if self._awaiting_customer_name else None,
|
||||
force_batch=self._awaiting_customer_name,
|
||||
)
|
||||
).strip()
|
||||
except Exception:
|
||||
@@ -1513,6 +1568,14 @@ class CallSession:
|
||||
def _name_capture_keyterms(self) -> tuple[str, ...]:
|
||||
return TOP_KAZAKH_NAMES
|
||||
|
||||
def _name_capture_language_code(self) -> str | None:
|
||||
raw = (
|
||||
os.getenv("STT_NAME_CAPTURE_LANGUAGE_CODE", "").strip()
|
||||
or os.getenv("STT_NAME_CAPTURE_LANGUAGE", "").strip()
|
||||
or "kz"
|
||||
)
|
||||
return raw or None
|
||||
|
||||
def _build_name_collection_response(self, transcript: str) -> str | None:
|
||||
if not self._awaiting_customer_name:
|
||||
return None
|
||||
@@ -2074,6 +2137,8 @@ class CallSession:
|
||||
return await self._stt.transcribe(
|
||||
utterance_audio,
|
||||
keyterms=self._name_capture_keyterms() if self._awaiting_customer_name else None,
|
||||
language_code=self._name_capture_language_code() if self._awaiting_customer_name else None,
|
||||
force_batch=self._awaiting_customer_name,
|
||||
)
|
||||
|
||||
def _maybe_dump_audio(self, audio_bytes: bytes) -> None:
|
||||
|
||||
Reference in New Issue
Block a user