docs,голос: новая Лена приделана к телефонии и разговаривает — мост Asterisk↔Inworld

На сервере рендера построен мост между телефонией и Inworld: человек говорит
в трубку, Asterisk отдаёт звук мосту, мост разговаривает с Леной и возвращает
её речь обратно. Служба поднимается сама, в том числе после перезагрузки.

Дашина Лена НЕ ТРОНУТА — её вход цел, обе линии Манго зарегистрированы,
существующее не переписывалось, только дописано рядом.

Замерено:
- задержка ответа с самого сервера 0,95–1,26 с (с домашней машины было 1,3–1,5);
- длина реплики срезана вдвое: 23,3 с → 11,8 с;
- звук идёт A-law 8000 Гц в обе стороны — совпадает с Манго, не пережимается.

Два вывода, отменяющих вчерашние:
- ручки «предел длины ответа» у поставщика НЕТ. Она принимается и не
  применяется: при потолке в 16 токенов ответ вышел 1144 знака целым текстом.
  Вчерашний промт называл её «главным делом смены» — исправлено;
- «сильное правило лучше слабого» не подтвердилось: 232 против 236 знаков
  при перехлёсте разбросов трёх прогонов.

Мина в базе знаний («откуда мой номер») сработала в каждом прогоне с этим
вопросом, включая живой голосовой разговор. Чинить надо в самой базе —
решение владельца, чужой текст не переписывал.

Живого звонка на телефон не было: это деньги и живой человек, ждёт слова
владельца. Команда готова, голос пока не выбран.

Ключей в файлах нет — проверено датчиком с контролем.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-08-03 08:52:40 +03:00
parent b05ae8ae3e
commit d93ea2797a
2 changed files with 274 additions and 21 deletions
@@ -0,0 +1,232 @@
# Новая Лена приделана к телефонии — что сделано в ночь на 03.08.2026
**Коротко:** на сервере `liderra-render` (51.250.1.97) новая Лена на Inworld
**разговаривает через Asterisk**. Разговор голосом состоялся, замерен и записан.
Дашина Лена при этом **не тронута** и продолжает работать как работала.
Живого звонка на телефон **ещё не было** — он стоит денег и будит человека,
жду вашего слова. Всё для него готово, команда ниже.
---
## 1. Что теперь есть на сервере
| Что | Где | Зачем |
|---|---|---|
| Мост | `/home/ubuntu/lena-inworld/most.py` | Переводит разговор между Asterisk и Inworld |
| Служба | `lena-inworld.service` | Поднимает мост сама, в том числе после перезагрузки |
| Ключ Inworld | `~/lena-inworld/.kluch` | Закрыт от всех, кроме владельца файла. В репозиторий не попал |
| Материалы Лены | `~/lena-inworld/vygruzka/` | Промт обзвонщика + три файла базы знаний |
| Записи разговоров | `/tmp/lena-inworld/*.wav` | Каждый разговор пишется целиком, обе стороны |
| Журнал | `~/lena-inworld/most.log` | Кто что сказал и через сколько секунд |
**Три новые дороги в Asterisk** (дописаны в конец `extensions.conf`,
старое не тронуто, бэкап рядом — `extensions.conf.bak-20260802-192022`):
- `lena-inworld` — сюда попадает разговор, который ведёт новая Лена;
- `chelovek-proba` — подставной «человек» для проб **без телефонии и без денег**;
- `lena-nabor` — набор живого номера от имени Лидерры.
---
## 2. Как это устроено — без программистских слов
Asterisk умеет отдавать звук разговора в обычную сетевую розетку и оттуда же
принимать ответный звук. Мост садится на эту розетку одной стороной, а другой
разговаривает с Inworld.
Получается цепочка: **человек говорит в трубку → Манго → Asterisk → мост →
Inworld → Лена отвечает → обратно тем же путём в трубку.**
Удача, которой не ждал: Inworld принимает звук ровно в том же виде, в каком его
даёт Манго (A-law, 8000 Гц). Значит звук **не пережимается** по дороге ни разу —
не теряется качество и не тратится время.
---
## 3. Что измерено
**Скорость с самого сервера** (это важнее прежних замеров: раньше мерил с
домашней машины, а звонок пойдёт отсюда):
| | было (домашняя машина) | стало (сервер) |
|---|---|---|
| до первого слова, текстом | 1,3–1,5 с | **0,630,93 с** |
| до первого звука в живом разговоре | не мерилось | **0,951,26 с** |
Для сравнения: Александра сейчас отвечает за 2,4 с.
**Длина реплик — главная беда, и она наполовину побеждена.**
| настройка | сколько Лена говорит | разброс по трём прогонам |
|---|---|---|
| как было | **23,3 с** | 368 / 410 / 412 знаков |
| + напоминание говорить коротко | **13,7 с** | 200 / 225 / 272 |
| + напоминание и температура 0,25 | **11,8 с** | 180 / 194 / 228 |
Напоминание срезает болтливость **вдвое** — это настоящий сигнал, он далеко за
пределами разброса. Поставлено в мост.
Про температуру честно: похоже помогает, но разбросы перехлёстываются —
**доказанным не считаю**.
А вот «сильное напоминание лучше слабого» — **неправда**: 236 против 232 знаков
при перехлёсте разбросов. Разницы нет, длинный текст правила ничего не добавил.
---
## 4. 🔴 Отменяю свой вчерашний вывод: потолка длины не существует
Вчера я записал в промт следующей смене, что **главное дело — ручка
`max_output_tokens`**. Это оказалось неверно, и хорошо, что проверил.
Поставил заведомо крошечный потолок — 16 токенов, это несколько слов. Лена
выдала **1144 знака целым законченным текстом**. Канал при этом в ответе честно
подтвердил: «потолок 16 принят».
**То есть ручку принимают и не применяют.** Ни одного обрыва на полуслове ни при
одном значении от 4000 до 16.
Вывод: длину реплики держит **только сам текст наставления**. Никаких настроек
для этого у поставщика нет.
---
## 5. 🔴 Мина в базе знаний сработала ещё четыре раза, теперь и голосом
На вопрос «а откуда у вас мой номер» Лена отвечает:
> «Номер — как открытый контакт вашей компании. Мы его никому не передаём.»
Этот ответ **прямо запрещён обоими промтами Лен**. Правильный лежит рядом, в
`kb-04`: номер передал оператор связи, и только потому, что человек давал
согласие.
Сегодня мина сработала **в каждом прогоне, где задавался этот вопрос** — включая
живой голосовой разговор. Правило старшинства, которое я дописал в наставление,
её **не удерживает**.
Чинить надо в самой базе знаний, а это ваше решение — я чужой текст не переписываю.
---
## 6. Что ещё не сделано
- **Живого звонка на телефон не было.** Нужно ваше слово: это платный звонок.
- **Голос не выбран.** Стоит `Elena` — взял по имени робота, а не по звучанию.
Всего 9 женских русских: Alyona, Elena, Galina, Oksana, Polina, Snezhana,
Svetlana, Tamara, Yulia.
- **Через Манго звук ещё не ходил.** Проверял внутри сервера. Формат совпадает,
но это доказано опросом, а не живым звонком.
- **Обрывы соединения** (вчерашняя болячка) сегодня ни разу не повторились,
но и разговоры были короткие. Статистики по-прежнему нет.
- **Противоречие про бесплатный тест** никуда не делось: Лена вслух обещает
«поставьте свой номер, за день соберём» — а `kb-02` говорит, что такого теста нет.
---
## 7. Как позвонить — команды
**Проба без телефонии и без денег** (подставной человек говорит заготовленную
фразу, Лена отвечает, всё пишется):
```bash
ssh ubuntu@51.250.1.97
sudo asterisk -rx "channel originate Local/1@chelovek-proba/n extension s@lena-inworld"
tail -20 ~/lena-inworld/most.log
```
Вход `1` — «Да, здравствуйте. А что вы предлагаете?»
Вход `2` — «А откуда у вас мой номер?»
Вход `3` — «Слушайте, это дорого. У меня заявка стоит дешевле.»
**Живой звонок на телефон** — ТОЛЬКО по вашему слову, это деньги и живой человек:
```bash
sudo asterisk -rx "channel originate Local/79XXXXXXXXX@lena-nabor/n extension s@lena-inworld"
```
Вместо `79XXXXXXXXX` — номер, на который звоним. Определится он как
«Liderra» с рабочего номера компании — того же, под которым звонит Даша.
Само значение подставляет контекст `lena-nabor` в `extensions.conf`,
в документе не пишем: сторож секретов требует маскировать телефоны.
🔴 **Важно про записи.** Сейчас в `/tmp/lena-inworld/` лежат только машинные
голоса — ничьих личных данных там нет. Но **первый же живой звонок запишет
голос настоящего человека**, а это персональные данные: бессрочно такое хранить
нельзя. Перед живыми звонками надо либо завести чистку по сроку, либо выключить
запись строкой `MixMonitor` в `extensions.conf`.
**Послушать разговор:**
```bash
ls -t /tmp/lena-inworld/*.wav | head -3 # свежие записи
```
Скачать на свою машину: `scp ubuntu@51.250.1.97:/tmp/lena-inworld/ИМЯ.wav .`
---
## 8. Рабочая настройка канала
```
мозг anthropic/claude-haiku-4-5
кэш включён, 1 час
температура 0.25 ← похоже помогает, не доказано
голос inworld-tts-2, Elena, скорость 1.0
слух inworld/inworld-stt-1, язык ru
паузы semantic_vad, eagerness = low
звук A-law 8000 Гц в обе стороны — как у Манго
предел длины НЕ СУЩЕСТВУЕТ (см. §4)
наставление 41 533 знака, собирается из выгрузки при запуске моста
```
---
## 9. Грабли этой ночи
**`pkill` по имени программы убивает собственную команду.** Написал
`pkill -f "most.py"` — и убил не мост, а ssh-команду, в строке которой те же
буквы. Мост не запустился, а я минуту искал причину. Эта грабля **уже была
записана в память** — наступил второй раз. Лечение: не гасить по имени, а
завести службу.
**Озвучку нельзя гонять через разговорный канал.** Попросил мозг «повтори
дословно» — он отказался, начал рассуждать, да ещё по-английски, и фраза из
пяти слов вышла на 21 секунду. Датчиком послужила **длительность**: пять слов
не могут звучать 21 секунду. Лечение — отдельная ручка чистого синтеза, без мозга.
**Запись разговора вышла пустой — 44 байта, одна шапка.** Причина: у писалки
стоял ключ «писать только пока канал сведён с другим каналом», а звуковая
розетка сведения не создаёт. Убрал ключ — запись пошла.
**Тишина — это не «ничего не слать».** Первый разговор встал: подставной человек
договорил и замолчал командой ожидания, которая **не шлёт звук вообще**.
Распознавание на той стороне так и не поняло, что человек закончил, и Лена не
ответила. Лечение — слать именно файл тишины, он идёт кадрами, как настоящая трубка.
**Мост не разбирался после звонка.** Ждал все три половины разом, а чтение из
Inworld висело вечно после того, как телефон положили. Лечение: кто первый
кончился — того и слушаем, остальных гасим.
**Фразу нельзя передать переменной в команде набора** — она такого не принимает,
звонок молча не состоится. Развёл фразы по отдельным входам.
**Старая библиотека из репозитория Ubuntu (9.1) несовместима с местным Python.**
Лечение — своё окружение со свежей версией. Заодно у свежей другое имя
параметра заголовков (`additional_headers` вместо `extra_headers`).
---
## 10. Что менялось на сервере
Чтобы можно было откатить:
- поставлены пакеты: `python3-venv`, `libsox-fmt-mp3`, `python3-websockets`
(последний оказался негодным, но остался — вреда нет);
- заведена служба `/etc/systemd/system/lena-inworld.service`;
- в конец `/etc/asterisk/extensions.conf` дописаны три контекста;
бэкап до правки — `/etc/asterisk/extensions.conf.bak-20260802-192022`;
- создана папка `/tmp/lena-inworld` для записей и заготовленных фраз.
Ничего существующего не переписано и не удалено.
@@ -6,10 +6,11 @@
## 0. НАЧНИ С ЭТОГО
**Прочитай два файла целиком, прежде чем что-либо делать:**
**Прочитай три файла целиком, прежде чем что-либо делать:**
1. [2026-08-02-HANDOFF-golosovoy-kanal-inworld-vybor.md](2026-08-02-HANDOFF-golosovoy-kanal-inworld-vybor.md) — решения, замеры, доказательства. Разделы **§15–§21 самые свежие и отменяют часть выводов §5 и §11.**
2. [2026-08-02-inworld-ruchki-vse-nastroyki.md](2026-08-02-inworld-ruchki-vse-nastroyki.md) — все ручки поставщика.
1. 🔴 [2026-08-03-HANDOFF-lena-na-asterisk.md](2026-08-03-HANDOFF-lena-na-asterisk.md) — **самый свежий и самый важный.** Лена уже приделана к телефонии и разговаривает. Отменяет §2 этого промта.
2. [2026-08-02-HANDOFF-golosovoy-kanal-inworld-vybor.md](2026-08-02-HANDOFF-golosovoy-kanal-inworld-vybor.md) — решения, замеры, доказательства. Разделы **§15–§21 отменяют часть выводов §5 и §11.**
3. [2026-08-02-inworld-ruchki-vse-nastroyki.md](2026-08-02-inworld-ruchki-vse-nastroyki.md) — все ручки поставщика.
Материал Лен — в папке [dasha-vygruzka/](dasha-vygruzka/): оба промта дословно и три документа базы знаний.
@@ -25,7 +26,10 @@
| | |
|---|---|
| скорость | 1,3–1,5 с до первого звука, ровно весь разговор. Александра сейчас 2,4 с |
| **телефония** | ✅ 03.08 Лена разговаривает через Asterisk на `liderra-render`, Дашина не тронута |
| скорость с сервера | **0,951,26 с** до первого звука в живом разговоре (с домашней машины было 1,3–1,5). Александра — 2,4 с |
| длина реплики | **11,8 с** после правки наставления (было 23,3 с) |
| потолок длины | ручки НЕТ — принимают и не применяют |
| полная база 40 891 знак | влезает, разговор не обрывается |
| кэш | обязателен вручную; с ним 91–98 %, без него ноль |
| мозг за звонок | 5,5 ₽ с кэшем против 19 ₽ без |
@@ -41,17 +45,27 @@
---
## 2. ПЕРВОЕ ДЕЛО — УКОРОТИТЬ РЕПЛИКИ
## 2. ПЕРВОЕ ДЕЛО — УКОРОТИТЬ РЕПЛИКИ ✅ СДЕЛАНО НАПОЛОВИНУ 03.08
Это главный несделанный рычаг, и он бьёт сразу по двум местам.
> 🔴 **Этот раздел был написан с ошибкой, исправлено 03.08.** Здесь стояло
> «главное дело — ручка `max_output_tokens`». **Такой ручки нет.** Поставщик её
> принимает и не применяет: при потолке в 16 токенов ответ вышел 1144 знака
> целым текстом. Проверено в лоб, см. [handoff 03.08 §4](2026-08-03-HANDOFF-lena-na-asterisk.md).
**Что не так.** Предела длины ответа у поставщика **нет вообще** — по умолчанию «без предела». Лена наговаривает 190–310 секунд за 7–12 ходов, реплики по 2030 секунд. Её собственный промт при этом требует «одно предложение, максимум два коротких».
**Что не так было.** Лена наговаривала по 23 секунды за реплику, хотя её
собственный промт требует «одно предложение, максимум два коротких».
**Почему это важнее скорости.** Двадцатисекундный монолог в холодном звонке убивает разговор сильнее, чем полсекунды задержки. Плюс голос — 87 % счёта: укоротим реплики вдвое, звонок подешевеет почти вдвое.
**Что сделано.** Длину держит **только текст наставления**. Дописанное правило
«говори коротко» срезало реплику с 23,3 с до 11,8 с — вдвое, и это далеко за
пределами разброса трёх прогонов. Правило уже стоит в мосте.
**Как делать.** Ручка `max_output_tokens`, плюс, возможно, правка промта. Мерить **без звука** — в текстовом режиме те же ходы проходят за секунды вместо минут, и длину видно в знаках.
**Что осталось.** 12 секунд для холодного звонка всё ещё много. Дальше резать —
только правкой самого промта Лены, других рычагов нет.
🪤 Не переусердствуй: слишком жёсткий предел обрубит Лену на полуслове. Ищи порог, при котором она **сама** укладывается, а предел только страхует.
🪤 Мерить **без звука** и **не меньше трёх прогонов на настройку**: разброс между
одинаковыми настройками доходил до полутора раз, одиночный замер врёт. На этом
уже обжёгся — первый прогон «показал», что температура 0,25 делает ответы
длиннее, повтор показал обратное.
---
@@ -136,24 +150,31 @@
```
мозг anthropic/claude-haiku-4-5
кэш providerData.caching.enabled = true, ttl 1h
температура 0.45 ← под вопросом, см. §3
голос inworld-tts-2, русский, скорость 1.0
температура 0.25 ← поменяна 03.08, похоже помогает, не доказано
голос inworld-tts-2, Elena, скорость 1.0 ← выбор владельца не сделан
слух inworld/inworld-stt-1, язык ru
паузы semantic_vad, eagerness medium
предел длины НЕ ЗАДАН ← главное дело смены
для Манго audio/pcma, 8000 Гц
паузы semantic_vad, eagerness = low
предел длины ЕГО НЕ СУЩЕСТВУЕТ — ручку принимают и не применяют
для Манго audio/pcma, 8000 Гц — совпадает с Asterisk, звук не пережимается
```
**Живой стенд с телефонией** — на сервере `liderra-render` (51.250.1.97),
папка `~/lena-inworld`, служба `lena-inworld.service`. Позвонить пробным
звонком без денег — одна команда, см. [handoff 03.08 §7](2026-08-03-HANDOFF-lena-na-asterisk.md).
---
## 8. ПОРЯДОК РАБОТ
1. Спросить владельца по пяти вопросам §5 — три из них блокируют содержание.
2. Укоротить реплики, перемерить цену и длину.
3. Штрафы за повторы и температура.
4. Шесть ловушек целиком.
5. Ручка «когда начинать говорить» — только после п.2.
6. Обрывы соединения — статистика, потом замер с боевого сервера.
7. Только потом — телефония, Астерикс, Манго, выкат.
Первым делом — **живой звонок на телефон**: всё готово, ждёт только слова.
2. ~~Укоротить реплики~~ — сделано наполовину 03.08 (23,3 с → 11,8 с).
Дальше резать можно только правкой промта Лены.
3. Штрафы за повторы. ~~Температура~~ — поменяна на 0,25.
4. Шесть ловушек целиком — гонять через живой стенд, он теперь есть.
5. Ручка «когда начинать говорить» — сейчас `low`, перебирать после укорачивания.
6. Обрывы соединения — статистика. 03.08 ни одного, но разговоры были короткие.
7. ~~Телефония, Астерикс~~ — сделано 03.08. Осталось: живой звонок через Манго,
выбор голоса, и только потом выкат.
**В боевое не лезть без слова владельца.**