lct-07 (без LLM): слот-автомат, персона, звонящий на заготовках, make repl
Звонящий не выдаёт данные сам: автомат держит раскрытые факты явно и
отдаёт звонящему только их. Тест прогоняет длинную серию реплик и
проверяет, что ни один нераскрытый факт не прозвучал.
Главная находка — матчинг по порогу близости не работает. На
multilingual-e5-small настоящие вопросы дают 0.79–0.95, а «Оставайтесь
на линии» — до 0.89: диапазоны перекрываются, и любой порог либо выдаёт
адрес на «успокойтесь», либо не слышит «где вы находитесь?».
Решение — сравнение с ближайшим соседом: у пункта чек-листа несколько
формулировок (examples), рядом общий список не-вопросов
(checklists/common.yaml), и реплика засчитывается пункту, только если она
ближе к нему, чем к любому не-вопросу. На отложенных фразах: 19 из 20
вопросов, 0 из 8 ложных срабатываний.
Реплика режется только по границам предложений, со знаком: «?» для e5 —
сильный признак вопроса, без него «Куда ехать» уходит к не-вопросам.
Подсказка берёт неотработанный пункт из автомата. В живой сессии автомат
начнёт слышать оператора, когда голосовой контур передаст ему stt.final.
Ждёт ключа LLM: условие approach у скрытых фактов, звонящий своими
словами, dialog/llm.py с кэшем.
2026-09-17 13:57:43 +03:00
|
|
|
|
"""make models: веса моделей в backend/models/.
|
|
|
|
|
|
|
lct-02: замер задержки голосового контура, make latency
Замер на машине разработки (Ryzen 7 8845HS, WSL2), не на демо-машине —
там make latency надо прогнать трижды, разброс между прогонами до 20%.
Распознавание — GigaAM v3 RNNT int8: фраза на 2 с за ~285 мс, WER 0%
на 99 словах живой речи Golos. CTC не быстрее ни в одном из двух прогонов
и ошибается чаще: время съедает общий энкодер, поэтому ступень деградации
«RNNT не успевает → CTC» по скорости ничего не даёт.
Синтез — Silero v5: в 10 раз быстрее реального времени, а не в 40, как
заложено в STACK.md; первая фраза 100–250 мс в зависимости от длины.
Частота синтеза на скорость не влияет, без профилирующего компилятора —
на 13% быстрее.
Сквозной бюджет: 600 мс endpointing + ~285 STT + ~150 TTS = ~1 с без LLM.
Цель ≤ 1.5 с держится, только если LLM отдаёт первое предложение быстрее
~465 мс. Вопрос, считается ли филлер «алло?..» первым звуком, записан
в LATENCY.md для людей.
make models качает GigaAM и Silero VAD с Hugging Face. Silero TTS лежит
на российском хосте, недоступном из-под VPN: скрипт не лезет на зеркала
(.pt грузится через pickle — это чужой код) и честно говорит, откуда
скачать вручную.
2026-09-17 14:44:02 +03:00
|
|
|
|
Эмбеддинги, распознавание (GigaAM v3, int8) и VAD качаются с Hugging Face.
|
|
|
|
|
|
Синтез (Silero TTS v5) лежит на models.silero.ai — российском хосте, который
|
|
|
|
|
|
не отвечает из-под VPN: его скрипт не качает, а проверяет и говорит, что делать.
|
lct-07 (без LLM): слот-автомат, персона, звонящий на заготовках, make repl
Звонящий не выдаёт данные сам: автомат держит раскрытые факты явно и
отдаёт звонящему только их. Тест прогоняет длинную серию реплик и
проверяет, что ни один нераскрытый факт не прозвучал.
Главная находка — матчинг по порогу близости не работает. На
multilingual-e5-small настоящие вопросы дают 0.79–0.95, а «Оставайтесь
на линии» — до 0.89: диапазоны перекрываются, и любой порог либо выдаёт
адрес на «успокойтесь», либо не слышит «где вы находитесь?».
Решение — сравнение с ближайшим соседом: у пункта чек-листа несколько
формулировок (examples), рядом общий список не-вопросов
(checklists/common.yaml), и реплика засчитывается пункту, только если она
ближе к нему, чем к любому не-вопросу. На отложенных фразах: 19 из 20
вопросов, 0 из 8 ложных срабатываний.
Реплика режется только по границам предложений, со знаком: «?» для e5 —
сильный признак вопроса, без него «Куда ехать» уходит к не-вопросам.
Подсказка берёт неотработанный пункт из автомата. В живой сессии автомат
начнёт слышать оператора, когда голосовой контур передаст ему stt.final.
Ждёт ключа LLM: условие approach у скрытых фактов, звонящий своими
словами, dialog/llm.py с кэшем.
2026-09-17 13:57:43 +03:00
|
|
|
|
Докачка продолжается с места обрыва: сеть на стенде бывает медленной.
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
|
import urllib.request
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
MODELS = ROOT / "models"
|
|
|
|
|
|
|
|
|
|
|
|
E5 = "https://huggingface.co/Xenova/multilingual-e5-small/resolve/main/"
|
lct-02: замер задержки голосового контура, make latency
Замер на машине разработки (Ryzen 7 8845HS, WSL2), не на демо-машине —
там make latency надо прогнать трижды, разброс между прогонами до 20%.
Распознавание — GigaAM v3 RNNT int8: фраза на 2 с за ~285 мс, WER 0%
на 99 словах живой речи Golos. CTC не быстрее ни в одном из двух прогонов
и ошибается чаще: время съедает общий энкодер, поэтому ступень деградации
«RNNT не успевает → CTC» по скорости ничего не даёт.
Синтез — Silero v5: в 10 раз быстрее реального времени, а не в 40, как
заложено в STACK.md; первая фраза 100–250 мс в зависимости от длины.
Частота синтеза на скорость не влияет, без профилирующего компилятора —
на 13% быстрее.
Сквозной бюджет: 600 мс endpointing + ~285 STT + ~150 TTS = ~1 с без LLM.
Цель ≤ 1.5 с держится, только если LLM отдаёт первое предложение быстрее
~465 мс. Вопрос, считается ли филлер «алло?..» первым звуком, записан
в LATENCY.md для людей.
make models качает GigaAM и Silero VAD с Hugging Face. Silero TTS лежит
на российском хосте, недоступном из-под VPN: скрипт не лезет на зеркала
(.pt грузится через pickle — это чужой код) и честно говорит, откуда
скачать вручную.
2026-09-17 14:44:02 +03:00
|
|
|
|
GIGAAM = "https://huggingface.co/istupakov/gigaam-v3-onnx/resolve/main/"
|
|
|
|
|
|
VAD = "https://huggingface.co/istupakov/silero-vad-onnx/resolve/main/"
|
lct-07 (без LLM): слот-автомат, персона, звонящий на заготовках, make repl
Звонящий не выдаёт данные сам: автомат держит раскрытые факты явно и
отдаёт звонящему только их. Тест прогоняет длинную серию реплик и
проверяет, что ни один нераскрытый факт не прозвучал.
Главная находка — матчинг по порогу близости не работает. На
multilingual-e5-small настоящие вопросы дают 0.79–0.95, а «Оставайтесь
на линии» — до 0.89: диапазоны перекрываются, и любой порог либо выдаёт
адрес на «успокойтесь», либо не слышит «где вы находитесь?».
Решение — сравнение с ближайшим соседом: у пункта чек-листа несколько
формулировок (examples), рядом общий список не-вопросов
(checklists/common.yaml), и реплика засчитывается пункту, только если она
ближе к нему, чем к любому не-вопросу. На отложенных фразах: 19 из 20
вопросов, 0 из 8 ложных срабатываний.
Реплика режется только по границам предложений, со знаком: «?» для e5 —
сильный признак вопроса, без него «Куда ехать» уходит к не-вопросам.
Подсказка берёт неотработанный пункт из автомата. В живой сессии автомат
начнёт слышать оператора, когда голосовой контур передаст ему stt.final.
Ждёт ключа LLM: условие approach у скрытых фактов, звонящий своими
словами, dialog/llm.py с кэшем.
2026-09-17 13:57:43 +03:00
|
|
|
|
FILES = {
|
|
|
|
|
|
"e5-small/config.json": E5 + "config.json",
|
|
|
|
|
|
"e5-small/tokenizer.json": E5 + "tokenizer.json",
|
|
|
|
|
|
"e5-small/model_quantized.onnx": E5 + "onnx/model_quantized.onnx",
|
lct-02: замер задержки голосового контура, make latency
Замер на машине разработки (Ryzen 7 8845HS, WSL2), не на демо-машине —
там make latency надо прогнать трижды, разброс между прогонами до 20%.
Распознавание — GigaAM v3 RNNT int8: фраза на 2 с за ~285 мс, WER 0%
на 99 словах живой речи Golos. CTC не быстрее ни в одном из двух прогонов
и ошибается чаще: время съедает общий энкодер, поэтому ступень деградации
«RNNT не успевает → CTC» по скорости ничего не даёт.
Синтез — Silero v5: в 10 раз быстрее реального времени, а не в 40, как
заложено в STACK.md; первая фраза 100–250 мс в зависимости от длины.
Частота синтеза на скорость не влияет, без профилирующего компилятора —
на 13% быстрее.
Сквозной бюджет: 600 мс endpointing + ~285 STT + ~150 TTS = ~1 с без LLM.
Цель ≤ 1.5 с держится, только если LLM отдаёт первое предложение быстрее
~465 мс. Вопрос, считается ли филлер «алло?..» первым звуком, записан
в LATENCY.md для людей.
make models качает GigaAM и Silero VAD с Hugging Face. Silero TTS лежит
на российском хосте, недоступном из-под VPN: скрипт не лезет на зеркала
(.pt грузится через pickle — это чужой код) и честно говорит, откуда
скачать вручную.
2026-09-17 14:44:02 +03:00
|
|
|
|
# RNNT — основная модель, CTC — запасная на случай, если RNNT не загрузится
|
|
|
|
|
|
# (по скорости CTC не выигрывает — docs/LATENCY.md).
|
|
|
|
|
|
"gigaam-v3-onnx/config.json": GIGAAM + "config.json",
|
|
|
|
|
|
"gigaam-v3-onnx/v3_vocab.txt": GIGAAM + "v3_vocab.txt",
|
|
|
|
|
|
"gigaam-v3-onnx/v3_rnnt_encoder.int8.onnx": GIGAAM + "v3_rnnt_encoder.int8.onnx",
|
|
|
|
|
|
"gigaam-v3-onnx/v3_rnnt_decoder.int8.onnx": GIGAAM + "v3_rnnt_decoder.int8.onnx",
|
|
|
|
|
|
"gigaam-v3-onnx/v3_rnnt_joint.int8.onnx": GIGAAM + "v3_rnnt_joint.int8.onnx",
|
|
|
|
|
|
"gigaam-v3-onnx/v3_ctc.int8.onnx": GIGAAM + "v3_ctc.int8.onnx",
|
|
|
|
|
|
"silero-vad/config.json": VAD + "config.json",
|
|
|
|
|
|
"silero-vad/silero_vad.onnx": VAD + "silero_vad.onnx",
|
lct-07 (без LLM): слот-автомат, персона, звонящий на заготовках, make repl
Звонящий не выдаёт данные сам: автомат держит раскрытые факты явно и
отдаёт звонящему только их. Тест прогоняет длинную серию реплик и
проверяет, что ни один нераскрытый факт не прозвучал.
Главная находка — матчинг по порогу близости не работает. На
multilingual-e5-small настоящие вопросы дают 0.79–0.95, а «Оставайтесь
на линии» — до 0.89: диапазоны перекрываются, и любой порог либо выдаёт
адрес на «успокойтесь», либо не слышит «где вы находитесь?».
Решение — сравнение с ближайшим соседом: у пункта чек-листа несколько
формулировок (examples), рядом общий список не-вопросов
(checklists/common.yaml), и реплика засчитывается пункту, только если она
ближе к нему, чем к любому не-вопросу. На отложенных фразах: 19 из 20
вопросов, 0 из 8 ложных срабатываний.
Реплика режется только по границам предложений, со знаком: «?» для e5 —
сильный признак вопроса, без него «Куда ехать» уходит к не-вопросам.
Подсказка берёт неотработанный пункт из автомата. В живой сессии автомат
начнёт слышать оператора, когда голосовой контур передаст ему stt.final.
Ждёт ключа LLM: условие approach у скрытых фактов, звонящий своими
словами, dialog/llm.py с кэшем.
2026-09-17 13:57:43 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
lct-02: замер задержки голосового контура, make latency
Замер на машине разработки (Ryzen 7 8845HS, WSL2), не на демо-машине —
там make latency надо прогнать трижды, разброс между прогонами до 20%.
Распознавание — GigaAM v3 RNNT int8: фраза на 2 с за ~285 мс, WER 0%
на 99 словах живой речи Golos. CTC не быстрее ни в одном из двух прогонов
и ошибается чаще: время съедает общий энкодер, поэтому ступень деградации
«RNNT не успевает → CTC» по скорости ничего не даёт.
Синтез — Silero v5: в 10 раз быстрее реального времени, а не в 40, как
заложено в STACK.md; первая фраза 100–250 мс в зависимости от длины.
Частота синтеза на скорость не влияет, без профилирующего компилятора —
на 13% быстрее.
Сквозной бюджет: 600 мс endpointing + ~285 STT + ~150 TTS = ~1 с без LLM.
Цель ≤ 1.5 с держится, только если LLM отдаёт первое предложение быстрее
~465 мс. Вопрос, считается ли филлер «алло?..» первым звуком, записан
в LATENCY.md для людей.
make models качает GigaAM и Silero VAD с Hugging Face. Silero TTS лежит
на российском хосте, недоступном из-под VPN: скрипт не лезет на зеркала
(.pt грузится через pickle — это чужой код) и честно говорит, откуда
скачать вручную.
2026-09-17 14:44:02 +03:00
|
|
|
|
SILERO_TTS = "silero-tts/v5_ru.pt"
|
|
|
|
|
|
SILERO_TTS_URL = "https://models.silero.ai/models/tts/ru/v5_ru.pt"
|
|
|
|
|
|
|
lct-07 (без LLM): слот-автомат, персона, звонящий на заготовках, make repl
Звонящий не выдаёт данные сам: автомат держит раскрытые факты явно и
отдаёт звонящему только их. Тест прогоняет длинную серию реплик и
проверяет, что ни один нераскрытый факт не прозвучал.
Главная находка — матчинг по порогу близости не работает. На
multilingual-e5-small настоящие вопросы дают 0.79–0.95, а «Оставайтесь
на линии» — до 0.89: диапазоны перекрываются, и любой порог либо выдаёт
адрес на «успокойтесь», либо не слышит «где вы находитесь?».
Решение — сравнение с ближайшим соседом: у пункта чек-листа несколько
формулировок (examples), рядом общий список не-вопросов
(checklists/common.yaml), и реплика засчитывается пункту, только если она
ближе к нему, чем к любому не-вопросу. На отложенных фразах: 19 из 20
вопросов, 0 из 8 ложных срабатываний.
Реплика режется только по границам предложений, со знаком: «?» для e5 —
сильный признак вопроса, без него «Куда ехать» уходит к не-вопросам.
Подсказка берёт неотработанный пункт из автомата. В живой сессии автомат
начнёт слышать оператора, когда голосовой контур передаст ему stt.final.
Ждёт ключа LLM: условие approach у скрытых фактов, звонящий своими
словами, dialog/llm.py с кэшем.
2026-09-17 13:57:43 +03:00
|
|
|
|
|
|
|
|
|
|
def fetch(url: str, target: Path) -> None:
|
|
|
|
|
|
partial = target.with_suffix(target.suffix + ".part")
|
|
|
|
|
|
offset = partial.stat().st_size if partial.exists() else 0
|
|
|
|
|
|
request = urllib.request.Request(url, headers={"Range": f"bytes={offset}-"} if offset else {})
|
|
|
|
|
|
with urllib.request.urlopen(request, timeout=60) as response, partial.open("ab") as out:
|
|
|
|
|
|
total = offset + int(response.headers.get("Content-Length", 0))
|
|
|
|
|
|
while chunk := response.read(1 << 20):
|
|
|
|
|
|
out.write(chunk)
|
|
|
|
|
|
done = out.tell()
|
|
|
|
|
|
if total:
|
|
|
|
|
|
print(f"\r {target.name}: {done // (1 << 20)} из {total // (1 << 20)} МБ", end="", flush=True)
|
|
|
|
|
|
partial.rename(target)
|
|
|
|
|
|
print()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> None:
|
|
|
|
|
|
for relative, url in FILES.items():
|
|
|
|
|
|
target = MODELS / relative
|
|
|
|
|
|
if target.exists():
|
|
|
|
|
|
print(f" {relative}: уже есть")
|
|
|
|
|
|
continue
|
|
|
|
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
|
|
fetch(url, target)
|
lct-02: замер задержки голосового контура, make latency
Замер на машине разработки (Ryzen 7 8845HS, WSL2), не на демо-машине —
там make latency надо прогнать трижды, разброс между прогонами до 20%.
Распознавание — GigaAM v3 RNNT int8: фраза на 2 с за ~285 мс, WER 0%
на 99 словах живой речи Golos. CTC не быстрее ни в одном из двух прогонов
и ошибается чаще: время съедает общий энкодер, поэтому ступень деградации
«RNNT не успевает → CTC» по скорости ничего не даёт.
Синтез — Silero v5: в 10 раз быстрее реального времени, а не в 40, как
заложено в STACK.md; первая фраза 100–250 мс в зависимости от длины.
Частота синтеза на скорость не влияет, без профилирующего компилятора —
на 13% быстрее.
Сквозной бюджет: 600 мс endpointing + ~285 STT + ~150 TTS = ~1 с без LLM.
Цель ≤ 1.5 с держится, только если LLM отдаёт первое предложение быстрее
~465 мс. Вопрос, считается ли филлер «алло?..» первым звуком, записан
в LATENCY.md для людей.
make models качает GigaAM и Silero VAD с Hugging Face. Silero TTS лежит
на российском хосте, недоступном из-под VPN: скрипт не лезет на зеркала
(.pt грузится через pickle — это чужой код) и честно говорит, откуда
скачать вручную.
2026-09-17 14:44:02 +03:00
|
|
|
|
tts = MODELS / SILERO_TTS
|
|
|
|
|
|
if tts.exists():
|
|
|
|
|
|
print(f" {SILERO_TTS}: уже есть")
|
|
|
|
|
|
print("все модели на месте")
|
|
|
|
|
|
return 0
|
|
|
|
|
|
# Не качаем с зеркал: .pt грузится через pickle, файл из непроверенного
|
|
|
|
|
|
# источника — это чужой код на стенде.
|
|
|
|
|
|
print(f"""
|
|
|
|
|
|
{SILERO_TTS}: НЕТ. Хост models.silero.ai не отвечает из-под VPN — скачайте вручную:
|
|
|
|
|
|
{SILERO_TTS_URL}
|
|
|
|
|
|
и положите в backend/models/{SILERO_TTS}""")
|
|
|
|
|
|
return 1
|
lct-07 (без LLM): слот-автомат, персона, звонящий на заготовках, make repl
Звонящий не выдаёт данные сам: автомат держит раскрытые факты явно и
отдаёт звонящему только их. Тест прогоняет длинную серию реплик и
проверяет, что ни один нераскрытый факт не прозвучал.
Главная находка — матчинг по порогу близости не работает. На
multilingual-e5-small настоящие вопросы дают 0.79–0.95, а «Оставайтесь
на линии» — до 0.89: диапазоны перекрываются, и любой порог либо выдаёт
адрес на «успокойтесь», либо не слышит «где вы находитесь?».
Решение — сравнение с ближайшим соседом: у пункта чек-листа несколько
формулировок (examples), рядом общий список не-вопросов
(checklists/common.yaml), и реплика засчитывается пункту, только если она
ближе к нему, чем к любому не-вопросу. На отложенных фразах: 19 из 20
вопросов, 0 из 8 ложных срабатываний.
Реплика режется только по границам предложений, со знаком: «?» для e5 —
сильный признак вопроса, без него «Куда ехать» уходит к не-вопросам.
Подсказка берёт неотработанный пункт из автомата. В живой сессии автомат
начнёт слышать оператора, когда голосовой контур передаст ему stt.final.
Ждёт ключа LLM: условие approach у скрытых фактов, звонящий своими
словами, dialog/llm.py с кэшем.
2026-09-17 13:57:43 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
|
sys.exit(main())
|