fix: bring aimaq host-override files (voice.py, persona env) back into git
Both services/ai_orchestrator_service/voice.py and the aimaq persona/DOMAIN
SCOPE prompt were bind-mounted straight from the host on the aimaq stack,
bypassing git and CI entirely since they were first hand-edited in prod.
voice.py: merged the host's live business logic (gas/aimaq domain keyword
list, off-domain Kazakh/Russian replies, disabled re-correction of an already
obtained name) with the timeout_seconds fix from 09bcf74 that never reached
aimaq because the bind mount blocked it.
aimaq.env.production: replaced the AI_OPERATOR_* env values (which were never
interpolated -- {agent_name}/{company_name} would have been read literally)
with the final resolved Zhanna/Kazakgaz Aimaq text including the DOMAIN SCOPE
clause, matching what was actually live on the host.
This commit is contained in:
@@ -604,16 +604,6 @@ def _voice_has_name_correction(text: str | None) -> bool:
|
||||
|
||||
|
||||
def _voice_reply_already_names_customer(reply_text: str, normalized_short: str) -> bool:
|
||||
"""Whether `reply_text` already addresses the customer by name.
|
||||
|
||||
Russian and Kazakh names decline grammatically (e.g. "Данияр" -> "Данияре",
|
||||
"Данияру", "Данияра"), so the model's own reply often names the customer in
|
||||
an inflected form that never exact-matches `normalized_short`. An exact
|
||||
token match alone misses that and this function then goes on to prepend
|
||||
the name a second time, producing a literal "Данияр, Здравствуйте, Данияре!"
|
||||
duplicate. Matching on a stem prefix instead of the full token catches any
|
||||
declined form of the same name.
|
||||
"""
|
||||
tokens = _voice_text_key(reply_text).split(" ")
|
||||
if normalized_short in tokens:
|
||||
return True
|
||||
@@ -635,14 +625,6 @@ def _voice_reply_with_name(
|
||||
*,
|
||||
greet: bool = False,
|
||||
) -> str:
|
||||
"""Prefix `reply_text` with the customer's name.
|
||||
|
||||
The prefix is always one of exactly two deterministic forms — "{name}, ..."
|
||||
or "Здравствуйте, {name}, ..." (`greet=True`, used the turn their name is
|
||||
first learned) — never left to the model's own free-form phrasing. That is
|
||||
what keeps this from colliding with a self-introduced name inside
|
||||
`reply_text` in the first place (see `_voice_reply_already_names_customer`).
|
||||
"""
|
||||
short_name = _voice_short_name(name)
|
||||
if not short_name:
|
||||
return reply_text
|
||||
@@ -786,13 +768,7 @@ def _voice_downstream_name_update(
|
||||
action = "provide" if not name_value else "confirm"
|
||||
candidate = candidate or name_value
|
||||
elif status == "name_obtained":
|
||||
if (
|
||||
candidate
|
||||
and candidate_key
|
||||
and candidate_key != current_key
|
||||
and _voice_has_name_correction(transcript_text)
|
||||
):
|
||||
action = "correct"
|
||||
pass
|
||||
else:
|
||||
if explicit_candidate:
|
||||
action = "provide"
|
||||
@@ -1079,7 +1055,6 @@ def _voice_has_service_topic(text: str | None) -> bool:
|
||||
"ошибк",
|
||||
"проблем",
|
||||
"сбой",
|
||||
"интернет",
|
||||
"связь",
|
||||
"оператор",
|
||||
"менеджер",
|
||||
@@ -1087,6 +1062,40 @@ def _voice_has_service_topic(text: str | None) -> bool:
|
||||
"компан",
|
||||
"подключ",
|
||||
"доставк",
|
||||
"газ",
|
||||
"счётчик",
|
||||
"счетчик",
|
||||
"ваучер",
|
||||
"отключ",
|
||||
"квитанц",
|
||||
"показан",
|
||||
"приложен",
|
||||
"безопасн",
|
||||
"техническ",
|
||||
"плит",
|
||||
"котл",
|
||||
"труб",
|
||||
"утечк",
|
||||
"запах",
|
||||
"абонент",
|
||||
"договор",
|
||||
"поверк",
|
||||
"монтаж",
|
||||
"счёт",
|
||||
"счет",
|
||||
"долг",
|
||||
"задолжен",
|
||||
"перерасчёт",
|
||||
"перерасчет",
|
||||
"регион",
|
||||
"аимак",
|
||||
"aimaq",
|
||||
"qazaqgaz",
|
||||
"казахгаз",
|
||||
"есептегіш",
|
||||
"төлеу",
|
||||
"өтінім",
|
||||
"шарт",
|
||||
)
|
||||
return any(marker in normalized for marker in service_markers)
|
||||
|
||||
@@ -1120,6 +1129,37 @@ def _voice_is_off_domain_request(text: str | None) -> bool:
|
||||
"java",
|
||||
"javascript",
|
||||
"погод",
|
||||
"плов",
|
||||
"приготов",
|
||||
"кулинар",
|
||||
"блюдо",
|
||||
"фильм",
|
||||
"кино",
|
||||
"спорт",
|
||||
"футбол",
|
||||
"хоккей",
|
||||
"теннис",
|
||||
"баскетбол",
|
||||
"президент",
|
||||
"политик",
|
||||
"выборы",
|
||||
"правительств",
|
||||
"курс валют",
|
||||
"криптовалют",
|
||||
"биткоин",
|
||||
"песн",
|
||||
"музык",
|
||||
"танц",
|
||||
"шутк",
|
||||
"загадк",
|
||||
"сериал",
|
||||
"книга",
|
||||
"стихотвор",
|
||||
"чемпионат",
|
||||
"ауа райы",
|
||||
"аспаздық",
|
||||
"кітап",
|
||||
"ән айт",
|
||||
)
|
||||
if any(marker in normalized for marker in broad_markers):
|
||||
return True
|
||||
@@ -1129,7 +1169,14 @@ def _voice_is_off_domain_request(text: str | None) -> bool:
|
||||
"что такое",
|
||||
"объясни",
|
||||
"расскажи про",
|
||||
"почему",
|
||||
"посоветуй",
|
||||
"как приготовить",
|
||||
"какая погода",
|
||||
"кто президент",
|
||||
"кто выиграл",
|
||||
"какая команда",
|
||||
"ауа райы қалай",
|
||||
"әнді айт",
|
||||
)
|
||||
return any(normalized.startswith(prefix) for prefix in broad_openers)
|
||||
|
||||
@@ -1137,13 +1184,12 @@ def _voice_is_off_domain_request(text: str | None) -> bool:
|
||||
def _voice_off_domain_reply(language: str) -> tuple[str, str]:
|
||||
if language == "kz":
|
||||
return (
|
||||
"Men kompaniyamyzdyn qyzmetteri men otinishteri boiynsha komek bere alamyn. "
|
||||
"Eger suraq bizdin qyzmetke qatysty bolsa, qysqasha naqtylaңыз. Qalasaңыз, operatorga qosamyn.",
|
||||
"AI qongyraudyn taqyrybyn kompaniya qyzmetteri sheginde naqtylaudy usyndy.",
|
||||
"Кешіріңіз, мен тек газ қызметтері бойынша көмектесемін: төлеу, есептегіш, ваучер. Қалай көмектесе аламын?",
|
||||
"AI off-topic сұрауды газ қызметтері тақырыбына шектеді.",
|
||||
)
|
||||
return (
|
||||
"Я помогу по вопросам наших услуг и обращений. Если вопрос связан с нашей компанией, скажите коротко, что именно нужно. Если хотите, сразу соединю с оператором.",
|
||||
"AI мягко вернул разговор к вопросам компании и предложил перевод на оператора.",
|
||||
"Извините, я помогаю только по вопросам газа: оплата, счётчики, ваучеры. Чем могу помочь?",
|
||||
"AI отклонил off-topic вопрос и ограничил тему газоснабжением.",
|
||||
)
|
||||
|
||||
|
||||
@@ -1856,7 +1902,7 @@ def _voice_decision(
|
||||
"latency_ms": 1,
|
||||
}
|
||||
|
||||
if not kb_results and _voice_is_off_domain_request(normalized):
|
||||
if _voice_is_off_domain_request(normalized):
|
||||
reply_text, summary_text = _voice_off_domain_reply(language)
|
||||
decision = {
|
||||
"language": language,
|
||||
|
||||
Reference in New Issue
Block a user