.
This commit is contained in:
@@ -0,0 +1,591 @@
|
||||
"""Kazakh first names for biasing the STT during the initial name-capture turn.
|
||||
|
||||
Sized for ElevenLabs Scribe v2 *batch* keyterms cap (1000 entries, 50 chars
|
||||
each). The Realtime path is intentionally skipped during the first turn —
|
||||
see CallSession._start_live_stt_stream — so we use the larger batch ceiling
|
||||
to maximize coverage for Kazakh-origin names. Russian-origin names are
|
||||
excluded; they are already recognized correctly without biasing.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
TOP_KAZAKH_NAMES: tuple[str, ...] = (
|
||||
# ---- Male ----
|
||||
"Абай",
|
||||
"Абдрахман",
|
||||
"Абдулла",
|
||||
"Абдулмажид",
|
||||
"Абдулжалил",
|
||||
"Абжан",
|
||||
"Абильхан",
|
||||
"Абубакир",
|
||||
"Абыз",
|
||||
"Абылай",
|
||||
"Абылайхан",
|
||||
"Адал",
|
||||
"Адахан",
|
||||
"Адельжан",
|
||||
"Адиль",
|
||||
"Адильбек",
|
||||
"Адильхан",
|
||||
"Азамат",
|
||||
"Азат",
|
||||
"Азиз",
|
||||
"Азизбек",
|
||||
"Айбар",
|
||||
"Айбат",
|
||||
"Айбек",
|
||||
"Айбол",
|
||||
"Айболат",
|
||||
"Айдан",
|
||||
"Айдар",
|
||||
"Айдарбек",
|
||||
"Айдархан",
|
||||
"Айдос",
|
||||
"Айкын",
|
||||
"Айнабек",
|
||||
"Айнур",
|
||||
"Айсен",
|
||||
"Айсултан",
|
||||
"Айткали",
|
||||
"Айткеш",
|
||||
"Айтуар",
|
||||
"Акан",
|
||||
"Акбар",
|
||||
"Акжан",
|
||||
"Акжол",
|
||||
"Аким",
|
||||
"Аксултан",
|
||||
"Алау",
|
||||
"Алдар",
|
||||
"Алдияр",
|
||||
"Алибек",
|
||||
"Алим",
|
||||
"Алимхан",
|
||||
"Алишер",
|
||||
"Алмагамбет",
|
||||
"Алмаз",
|
||||
"Алмас",
|
||||
"Алпамыс",
|
||||
"Алтай",
|
||||
"Алтынбек",
|
||||
"Аман",
|
||||
"Аманбай",
|
||||
"Аманжол",
|
||||
"Аманкос",
|
||||
"Аманкельды",
|
||||
"Амангельды",
|
||||
"Амир",
|
||||
"Амиржан",
|
||||
"Амирхан",
|
||||
"Амре",
|
||||
"Анар",
|
||||
"Анарбай",
|
||||
"Анарбек",
|
||||
"Анвар",
|
||||
"Аркат",
|
||||
"Ардак",
|
||||
"Арман",
|
||||
"Арнур",
|
||||
"Арсен",
|
||||
"Арслан",
|
||||
"Арыстан",
|
||||
"Асан",
|
||||
"Асет",
|
||||
"Асим",
|
||||
"Аскар",
|
||||
"Аскат",
|
||||
"Аскер",
|
||||
"Аслан",
|
||||
"Атабек",
|
||||
"Аубакир",
|
||||
"Ауез",
|
||||
"Аян",
|
||||
"Аяс",
|
||||
"Бакдаулет",
|
||||
"Бакир",
|
||||
"Бактияр",
|
||||
"Бактыбай",
|
||||
"Бакыт",
|
||||
"Бакытбек",
|
||||
"Бакытжан",
|
||||
"Балапан",
|
||||
"Балгабай",
|
||||
"Барлыбай",
|
||||
"Бауыржан",
|
||||
"Баян",
|
||||
"Бекарыс",
|
||||
"Бекасыл",
|
||||
"Бекболат",
|
||||
"Бекжан",
|
||||
"Бекзат",
|
||||
"Бексултан",
|
||||
"Берген",
|
||||
"Берик",
|
||||
"Биржан",
|
||||
"Болат",
|
||||
"Болатбек",
|
||||
"Болатхан",
|
||||
"Бостандык",
|
||||
"Бухар",
|
||||
"Габидолла",
|
||||
"Габит",
|
||||
"Гали",
|
||||
"Галым",
|
||||
"Галымжан",
|
||||
"Гани",
|
||||
"Гумар",
|
||||
"Гумарбек",
|
||||
"Дамир",
|
||||
"Данияр",
|
||||
"Дархан",
|
||||
"Дастан",
|
||||
"Даулет",
|
||||
"Дауренбек",
|
||||
"Даурен",
|
||||
"Дидар",
|
||||
"Динмухамед",
|
||||
"Динислам",
|
||||
"Дияз",
|
||||
"Досмухамед",
|
||||
"Досжан",
|
||||
"Досымбек",
|
||||
"Дулат",
|
||||
"Едил",
|
||||
"Едыге",
|
||||
"Ельжан",
|
||||
"Еламан",
|
||||
"Ерасыл",
|
||||
"Ерболат",
|
||||
"Ерзат",
|
||||
"Ержан",
|
||||
"Ерик",
|
||||
"Еркебулан",
|
||||
"Еркетай",
|
||||
"Еркин",
|
||||
"Ерлан",
|
||||
"Ерлик",
|
||||
"Ермагамбет",
|
||||
"Ермек",
|
||||
"Ермухан",
|
||||
"Ернар",
|
||||
"Ернур",
|
||||
"Есенгали",
|
||||
"Есим",
|
||||
"Ескендир",
|
||||
"Есламбек",
|
||||
"Жайдар",
|
||||
"Жакау",
|
||||
"Жалгас",
|
||||
"Жамал",
|
||||
"Жамшидбек",
|
||||
"Жанабат",
|
||||
"Жанат",
|
||||
"Жанболат",
|
||||
"Жангильды",
|
||||
"Жангир",
|
||||
"Жанибек",
|
||||
"Жасулан",
|
||||
"Жаугашты",
|
||||
"Жиен",
|
||||
"Жолан",
|
||||
"Жомарт",
|
||||
"Жубан",
|
||||
"Жумабай",
|
||||
"Жумабек",
|
||||
"Жумагали",
|
||||
"Жумаш",
|
||||
"Зейнолла",
|
||||
"Зекен",
|
||||
"Зейнулла",
|
||||
"Зердебай",
|
||||
"Идрис",
|
||||
"Илиас",
|
||||
"Ильяс",
|
||||
"Иман",
|
||||
"Имран",
|
||||
"Иса",
|
||||
"Искандер",
|
||||
"Кабылбек",
|
||||
"Кадыр",
|
||||
"Кадыржан",
|
||||
"Кайдар",
|
||||
"Кайрат",
|
||||
"Кайыргали",
|
||||
"Кайсар",
|
||||
"Канат",
|
||||
"Канатбек",
|
||||
"Канжар",
|
||||
"Канипа",
|
||||
"Карим",
|
||||
"Касен",
|
||||
"Касым",
|
||||
"Кенес",
|
||||
"Кенесары",
|
||||
"Кенжебай",
|
||||
"Куандык",
|
||||
"Куаныш",
|
||||
"Куат",
|
||||
"Курманбай",
|
||||
"Кылыш",
|
||||
"Лукман",
|
||||
"Магжан",
|
||||
"Мадияр",
|
||||
"Майлы",
|
||||
"Майлыбай",
|
||||
"Максат",
|
||||
"Максут",
|
||||
"Манар",
|
||||
"Манас",
|
||||
"Манатай",
|
||||
"Маралбек",
|
||||
"Марат",
|
||||
"Мардан",
|
||||
"Маулен",
|
||||
"Мерген",
|
||||
"Мирас",
|
||||
"Мукагали",
|
||||
"Мукаш",
|
||||
"Муратбек",
|
||||
"Мурат",
|
||||
"Мухамед",
|
||||
"Мухамеджан",
|
||||
"Мухтар",
|
||||
"Мырзабек",
|
||||
"Мырзахан",
|
||||
"Мырзахмет",
|
||||
"Назар",
|
||||
"Наурыз",
|
||||
"Несип",
|
||||
"Нияз",
|
||||
"Нурадил",
|
||||
"Нурбек",
|
||||
"Нурбол",
|
||||
"Нурдаулет",
|
||||
"Нуржан",
|
||||
"Нурлан",
|
||||
"Нурлыбек",
|
||||
"Нурмагамбет",
|
||||
"Нурмурат",
|
||||
"Нурсадык",
|
||||
"Нурсат",
|
||||
"Нурсултан",
|
||||
"Нуртас",
|
||||
"Нурым",
|
||||
"Олжас",
|
||||
"Омар",
|
||||
"Ораз",
|
||||
"Оразбай",
|
||||
"Оразалы",
|
||||
"Орак",
|
||||
"Оралбек",
|
||||
"Оралхан",
|
||||
"Орынбай",
|
||||
"Райымбек",
|
||||
"Райыс",
|
||||
"Рамазан",
|
||||
"Расул",
|
||||
"Рауан",
|
||||
"Рахман",
|
||||
"Рахмет",
|
||||
"Раушан",
|
||||
"Ринат",
|
||||
"Рустам",
|
||||
"Рустем",
|
||||
"Сабит",
|
||||
"Сабыр",
|
||||
"Сагиман",
|
||||
"Сагынтай",
|
||||
"Сагынбай",
|
||||
"Саду",
|
||||
"Саин",
|
||||
"Сайрам",
|
||||
"Сакен",
|
||||
"Самат",
|
||||
"Самет",
|
||||
"Санжар",
|
||||
"Сапар",
|
||||
"Саркен",
|
||||
"Сасан",
|
||||
"Сейтжан",
|
||||
"Серик",
|
||||
"Серикбай",
|
||||
"Серикбек",
|
||||
"Серикжан",
|
||||
"Султан",
|
||||
"Султанбек",
|
||||
"Султанмурат",
|
||||
"Сұңғат",
|
||||
"Сұңқар",
|
||||
"Талгат",
|
||||
"Талгатбек",
|
||||
"Тамерлан",
|
||||
"Танат",
|
||||
"Темирбек",
|
||||
"Темирболат",
|
||||
"Темирлан",
|
||||
"Темиржан",
|
||||
"Тилеген",
|
||||
"Тимур",
|
||||
"Толкын",
|
||||
"Толеген",
|
||||
"Тулеген",
|
||||
"Турар",
|
||||
"Турсын",
|
||||
"Турсунбай",
|
||||
"Узакбай",
|
||||
"Улан",
|
||||
"Уразалы",
|
||||
"Усербай",
|
||||
"Утеген",
|
||||
"Файзулла",
|
||||
"Фарит",
|
||||
"Фархад",
|
||||
"Хабиб",
|
||||
"Хайрат",
|
||||
"Хамза",
|
||||
"Чингиз",
|
||||
"Шалабай",
|
||||
"Шамиль",
|
||||
"Шерхан",
|
||||
"Шернияз",
|
||||
"Шынгысхан",
|
||||
"Эльдар",
|
||||
"Эрнар",
|
||||
"Юсуф",
|
||||
"Якуб",
|
||||
# ---- Female ----
|
||||
"Аделя",
|
||||
"Адина",
|
||||
"Адия",
|
||||
"Азиля",
|
||||
"Айгерим",
|
||||
"Айгуль",
|
||||
"Айдай",
|
||||
"Айдана",
|
||||
"Айзада",
|
||||
"Айжамал",
|
||||
"Айжан",
|
||||
"Айзере",
|
||||
"Айман",
|
||||
"Айна",
|
||||
"Айнагуль",
|
||||
"Айнура",
|
||||
"Айсара",
|
||||
"Айсауле",
|
||||
"Айсулу",
|
||||
"Айша",
|
||||
"Айя",
|
||||
"Айяна",
|
||||
"Акбота",
|
||||
"Акерке",
|
||||
"Аксана",
|
||||
"Акмарал",
|
||||
"Акниет",
|
||||
"Акшолпан",
|
||||
"Алина",
|
||||
"Алия",
|
||||
"Алмагуль",
|
||||
"Алтын",
|
||||
"Алтынай",
|
||||
"Алуа",
|
||||
"Альбина",
|
||||
"Альмира",
|
||||
"Альфия",
|
||||
"Анел",
|
||||
"Анелия",
|
||||
"Аннур",
|
||||
"Аружан",
|
||||
"Аруна",
|
||||
"Асем",
|
||||
"Асемгуль",
|
||||
"Асель",
|
||||
"Асима",
|
||||
"Асия",
|
||||
"Асылзада",
|
||||
"Асылзат",
|
||||
"Асылым",
|
||||
"Аяжан",
|
||||
"Аяна",
|
||||
"Аяулым",
|
||||
"Багдат",
|
||||
"Багила",
|
||||
"Бадигуль",
|
||||
"Балауса",
|
||||
"Балгуль",
|
||||
"Балжан",
|
||||
"Балнур",
|
||||
"Балым",
|
||||
"Бахытгуль",
|
||||
"Бахытжан",
|
||||
"Бибигуль",
|
||||
"Бибинур",
|
||||
"Бикеш",
|
||||
"Венера",
|
||||
"Газиза",
|
||||
"Гайша",
|
||||
"Галия",
|
||||
"Гаухар",
|
||||
"Гаухарбану",
|
||||
"Гулим",
|
||||
"Гулбану",
|
||||
"Гулбаршын",
|
||||
"Гулдана",
|
||||
"Гулден",
|
||||
"Гулжан",
|
||||
"Гулзада",
|
||||
"Гулзара",
|
||||
"Гулмира",
|
||||
"Гулназ",
|
||||
"Гулнар",
|
||||
"Гулсая",
|
||||
"Гулсара",
|
||||
"Гулсина",
|
||||
"Гулсум",
|
||||
"Гулшат",
|
||||
"Гульдана",
|
||||
"Гульден",
|
||||
"Гульжан",
|
||||
"Гульзада",
|
||||
"Гульзара",
|
||||
"Гульмира",
|
||||
"Гульназ",
|
||||
"Гульнар",
|
||||
"Гульсая",
|
||||
"Гульсина",
|
||||
"Гульсум",
|
||||
"Гульшат",
|
||||
"Гульбану",
|
||||
"Гульбаршын",
|
||||
"Гулнара",
|
||||
"Гультас",
|
||||
"Дамира",
|
||||
"Дана",
|
||||
"Данара",
|
||||
"Данель",
|
||||
"Дария",
|
||||
"Дарига",
|
||||
"Дарика",
|
||||
"Дилда",
|
||||
"Дильдар",
|
||||
"Дильнара",
|
||||
"Дильназ",
|
||||
"Дина",
|
||||
"Динара",
|
||||
"Динель",
|
||||
"Жадыра",
|
||||
"Жайна",
|
||||
"Жанаргуль",
|
||||
"Жанар",
|
||||
"Жанбал",
|
||||
"Жанна",
|
||||
"Жания",
|
||||
"Жасмин",
|
||||
"Жибек",
|
||||
"Жулдыз",
|
||||
"Зайнаб",
|
||||
"Замзагуль",
|
||||
"Замира",
|
||||
"Зара",
|
||||
"Зарема",
|
||||
"Зарина",
|
||||
"Зарифа",
|
||||
"Захира",
|
||||
"Зейнеп",
|
||||
"Зира",
|
||||
"Зулайхан",
|
||||
"Зухра",
|
||||
"Иасмин",
|
||||
"Инара",
|
||||
"Индира",
|
||||
"Камажай",
|
||||
"Камила",
|
||||
"Камилла",
|
||||
"Карлыга",
|
||||
"Карлыгаш",
|
||||
"Касиет",
|
||||
"Кулжайнар",
|
||||
"Кулзада",
|
||||
"Куляш",
|
||||
"Куралай",
|
||||
"Кымбат",
|
||||
"Лаура",
|
||||
"Лейла",
|
||||
"Леяла",
|
||||
"Лиана",
|
||||
"Луиза",
|
||||
"Мадина",
|
||||
"Майра",
|
||||
"Майя",
|
||||
"Мақпал",
|
||||
"Малика",
|
||||
"Манара",
|
||||
"Манагуль",
|
||||
"Маржан",
|
||||
"Маржанкуль",
|
||||
"Мариямкуль",
|
||||
"Мариям",
|
||||
"Мариам",
|
||||
"Меруерт",
|
||||
"Мира",
|
||||
"Молдир",
|
||||
"Мунира",
|
||||
"Назым",
|
||||
"Назгуль",
|
||||
"Назифа",
|
||||
"Наргиз",
|
||||
"Нурай",
|
||||
"Нурбала",
|
||||
"Нургуль",
|
||||
"Нуржамал",
|
||||
"Нурзада",
|
||||
"Нуриля",
|
||||
"Нурлыгуль",
|
||||
"Перизат",
|
||||
"Райхан",
|
||||
"Рузия",
|
||||
"Сабина",
|
||||
"Сагила",
|
||||
"Сайраш",
|
||||
"Салима",
|
||||
"Салтанат",
|
||||
"Самал",
|
||||
"Самира",
|
||||
"Сандугаш",
|
||||
"Сапура",
|
||||
"Сара",
|
||||
"Саулет",
|
||||
"Сауле",
|
||||
"Сахида",
|
||||
"Симбат",
|
||||
"Сулу",
|
||||
"Сулушаш",
|
||||
"Тазагуль",
|
||||
"Тогжан",
|
||||
"Толгана",
|
||||
"Толганай",
|
||||
"Томирис",
|
||||
"Турсынай",
|
||||
"Тұрсынгүл",
|
||||
"Улжан",
|
||||
"Улпан",
|
||||
"Умит",
|
||||
"Умитжан",
|
||||
"Фариза",
|
||||
"Фарзана",
|
||||
"Фатима",
|
||||
"Хадиша",
|
||||
"Хайша",
|
||||
"Шамшия",
|
||||
"Шарбану",
|
||||
"Шарифа",
|
||||
"Шолпан",
|
||||
"Шынар",
|
||||
"Эльмира",
|
||||
"Энлик",
|
||||
"Юлдыз",
|
||||
)
|
||||
|
||||
|
||||
__all__ = ("TOP_KAZAKH_NAMES",)
|
||||
+106
-9
@@ -15,6 +15,7 @@ from collections.abc import Iterable
|
||||
from enum import Enum
|
||||
|
||||
from realtime_voice_service.core.filler_audio import FillerAudioLibrary
|
||||
from realtime_voice_service.core.kazakh_names import TOP_KAZAKH_NAMES
|
||||
from realtime_voice_service.core.vad import BaseVAD, SileroVADDetector
|
||||
from realtime_voice_service.providers.base import BaseLLM, BaseSTT, BaseSTTStream, BaseTTS, MockLLM, MockSTT, MockTTS
|
||||
from realtime_voice_service.transports.base import BaseMediaTransport
|
||||
@@ -53,7 +54,7 @@ FILLER_AUDIO_DELAY_MS = _filler_delay_ms()
|
||||
TTS_CHUNK_SOFT_MIN_CHARS = _tts_chunk_soft_min_chars()
|
||||
TTS_CHUNK_SOFT_MIN_WORDS = _tts_chunk_soft_min_words()
|
||||
|
||||
_FAREWELL_MARKERS: frozenset[str] = frozenset({
|
||||
_COURTESY_OR_FAREWELL_MARKERS: frozenset[str] = frozenset({
|
||||
"спасибо",
|
||||
"благодарю",
|
||||
"до свидания",
|
||||
@@ -77,6 +78,48 @@ _FAREWELL_MARKERS: frozenset[str] = frozenset({
|
||||
"bye",
|
||||
})
|
||||
|
||||
_TERMINAL_DIRECT_FAREWELL_MARKERS: frozenset[str] = frozenset({
|
||||
"до свидания",
|
||||
"всего доброго",
|
||||
"пока",
|
||||
"до встречи",
|
||||
"хорошего дня",
|
||||
"goodbye",
|
||||
"bye",
|
||||
})
|
||||
|
||||
_TERMINAL_CLOSE_REQUEST_MARKERS: frozenset[str] = frozenset({
|
||||
"можно завершить",
|
||||
"можем завершить",
|
||||
"можете завершать",
|
||||
"давайте завершим",
|
||||
"давайте закончим",
|
||||
"завершить разговор",
|
||||
"закончить разговор",
|
||||
"заканчиваем разговор",
|
||||
"завершайте разговор",
|
||||
"кладу трубку",
|
||||
"положу трубку",
|
||||
})
|
||||
|
||||
_TERMINAL_NO_MORE_HELP_MARKERS: frozenset[str] = frozenset({
|
||||
"ничего не нужно",
|
||||
"ничего не надо",
|
||||
"мне ничего не нужно",
|
||||
"мне ничего не надо",
|
||||
"больше ничего",
|
||||
"больше ничего не нужно",
|
||||
"больше ничего не надо",
|
||||
"ничего больше не нужно",
|
||||
"ничего больше не надо",
|
||||
"это все",
|
||||
"это всё",
|
||||
"на этом все",
|
||||
"на этом всё",
|
||||
"вопросов нет",
|
||||
"больше вопросов нет",
|
||||
})
|
||||
|
||||
_FAREWELL_QUERY_MARKERS: frozenset[str] = frozenset({
|
||||
"вопрос",
|
||||
"подскаж",
|
||||
@@ -90,7 +133,6 @@ _FAREWELL_QUERY_MARKERS: frozenset[str] = frozenset({
|
||||
"нужно ли",
|
||||
"нужно еще",
|
||||
"нужно ещё",
|
||||
"хочу",
|
||||
"еще",
|
||||
"ещё",
|
||||
"теперь",
|
||||
@@ -107,22 +149,63 @@ _FAREWELL_QUERY_MARKERS: frozenset[str] = frozenset({
|
||||
"нужна",
|
||||
"нужны",
|
||||
})
|
||||
|
||||
_FAREWELL_HARD_QUERY_MARKERS: frozenset[str] = frozenset(
|
||||
marker for marker in _FAREWELL_QUERY_MARKERS if marker not in {"вопрос", "можно"}
|
||||
)
|
||||
FAREWELL_RESPONSE_TEXT = "Спасибо за обращение в DigiOps. Всего доброго, до свидания!"
|
||||
|
||||
|
||||
def _contains_voice_phrase(normalized_text: str, phrase: str) -> bool:
|
||||
phrase_parts = [re.escape(part) for part in phrase.split()]
|
||||
if not phrase_parts:
|
||||
return False
|
||||
phrase_pattern = r"\s+".join(phrase_parts)
|
||||
return re.search(
|
||||
rf"(?<![^\W\d_]){phrase_pattern}(?![^\W\d_])",
|
||||
normalized_text,
|
||||
flags=re.UNICODE,
|
||||
) is not None
|
||||
|
||||
|
||||
def _ends_with_voice_phrase(normalized_text: str, phrase: str) -> bool:
|
||||
phrase_parts = [re.escape(part) for part in phrase.split()]
|
||||
if not phrase_parts:
|
||||
return False
|
||||
phrase_pattern = r"\s+".join(phrase_parts)
|
||||
return re.search(
|
||||
rf"(?<![^\W\d_]){phrase_pattern}(?:\s+(?:спасибо|благодарю))?$",
|
||||
normalized_text,
|
||||
flags=re.UNICODE,
|
||||
) is not None
|
||||
|
||||
|
||||
def _is_farewell_transcript(text: str) -> bool:
|
||||
normalized = _voice_text_key(text)
|
||||
return any(marker in normalized for marker in _FAREWELL_MARKERS)
|
||||
return any(_contains_voice_phrase(normalized, marker) for marker in _COURTESY_OR_FAREWELL_MARKERS)
|
||||
|
||||
|
||||
def _is_terminal_farewell(text: str) -> bool:
|
||||
normalized = _voice_text_key(text)
|
||||
if not any(marker in normalized for marker in _FAREWELL_MARKERS):
|
||||
has_direct_farewell = any(
|
||||
_contains_voice_phrase(normalized, marker)
|
||||
for marker in _TERMINAL_DIRECT_FAREWELL_MARKERS
|
||||
)
|
||||
has_close_request = any(
|
||||
_contains_voice_phrase(normalized, marker)
|
||||
for marker in _TERMINAL_CLOSE_REQUEST_MARKERS
|
||||
)
|
||||
has_no_more_help = any(
|
||||
_ends_with_voice_phrase(normalized, marker)
|
||||
for marker in _TERMINAL_NO_MORE_HELP_MARKERS
|
||||
)
|
||||
if not (has_direct_farewell or has_close_request or has_no_more_help):
|
||||
return False
|
||||
if any(marker in normalized for marker in _FAREWELL_QUERY_MARKERS):
|
||||
query_markers = _FAREWELL_QUERY_MARKERS if has_direct_farewell else _FAREWELL_HARD_QUERY_MARKERS
|
||||
if any(marker in normalized for marker in query_markers):
|
||||
return False
|
||||
word_count = len(re.findall(r"[^\W\d_]+(?:[-'][^\W\d_]+)*", normalized, flags=re.UNICODE))
|
||||
return word_count <= 10
|
||||
return word_count <= 16
|
||||
|
||||
|
||||
SEMANTIC_CONTINUATION_TOKENS = {
|
||||
@@ -1405,7 +1488,12 @@ class CallSession:
|
||||
len(audio_bytes),
|
||||
_audio_duration_ms(audio_bytes, sample_rate_hz=self.transport.sample_rate_hz),
|
||||
)
|
||||
pending_transcript = (await self._stt.transcribe(audio_bytes)).strip()
|
||||
pending_transcript = (
|
||||
await self._stt.transcribe(
|
||||
audio_bytes,
|
||||
keyterms=self._name_capture_keyterms() if self._awaiting_customer_name else None,
|
||||
)
|
||||
).strip()
|
||||
except Exception:
|
||||
LOGGER.exception("realtime session %s failed to transcribe pending unanswered audio", self.session_id)
|
||||
continue
|
||||
@@ -1421,6 +1509,9 @@ class CallSession:
|
||||
)
|
||||
return pending_texts
|
||||
|
||||
def _name_capture_keyterms(self) -> tuple[str, ...]:
|
||||
return TOP_KAZAKH_NAMES
|
||||
|
||||
def _build_name_collection_response(self, transcript: str) -> str | None:
|
||||
if not self._awaiting_customer_name:
|
||||
return None
|
||||
@@ -1880,7 +1971,10 @@ class CallSession:
|
||||
self._reset_semantic_endpointing()
|
||||
try:
|
||||
LOGGER.info("realtime session %s live STT stream start requested", self.session_id)
|
||||
live_stt_stream = await self._stt.start_stream(partial_callback=self._handle_partial_transcript)
|
||||
live_stt_stream = await self._stt.start_stream(
|
||||
partial_callback=self._handle_partial_transcript,
|
||||
keyterms=self._name_capture_keyterms() if self._awaiting_customer_name else None,
|
||||
)
|
||||
except Exception:
|
||||
LOGGER.exception("realtime session %s failed to start live STT stream", self.session_id)
|
||||
return
|
||||
@@ -1953,7 +2047,10 @@ class CallSession:
|
||||
len(utterance_audio),
|
||||
_audio_duration_ms(utterance_audio, sample_rate_hz=self.transport.sample_rate_hz),
|
||||
)
|
||||
return await self._stt.transcribe(utterance_audio)
|
||||
return await self._stt.transcribe(
|
||||
utterance_audio,
|
||||
keyterms=self._name_capture_keyterms() if self._awaiting_customer_name else None,
|
||||
)
|
||||
|
||||
def _maybe_dump_audio(self, audio_bytes: bytes) -> None:
|
||||
if str(os.getenv("ENABLE_AUDIO_DUMP", "")).strip().lower() not in {"1", "true", "yes", "on"}:
|
||||
|
||||
Reference in New Issue
Block a user