Что можно сказать, решает слот-автомат, а не модель: в промпт попадают только раскрытые факты. Иначе LLM услужливо назовёт адрес, которого не спрашивали. Промпты лежат файлами — их правит тот, кто ведёт занятия. Отказ провайдера не роняет занятие: звонящий откатывается на заготовки. Молчащий звонящий хуже шаблонной фразы. Офлайн — таблица, а не локальная модель. Ветвление уже делает слот-автомат, поэтому таблица индексируется парой «событие × настроение» и выходит небольшой: для пожарного сценария 62 реплики, около 36 секунд генерации. Формулировки в ней от облачной модели, а задержка на занятии нулевая — локальная 3–4B дала бы формулировки хуже и за 2.5 секунды. Найдено на бесплатной модели OpenRouter: рассуждающие модели тратят сотни токенов на размышление и при малом бюджете возвращают пустой content с finish_reason=length. Пустой ответ теперь честный отказ, бюджет токенов поднят, рассуждение из ответа исключается. Живые запросы к LLM вынесены из общего прогона: они требуют сети, а рассуждающая модель отвечает десятками секунд.
62 lines
2.1 KiB
TOML
62 lines
2.1 KiB
TOML
[project]
|
||
name = "lct-backend"
|
||
version = "0.1.0"
|
||
description = "Учебный симулятор занятия для системы 112 — бэкенд"
|
||
requires-python = ">=3.11,<3.12"
|
||
dependencies = [
|
||
"fastapi>=0.115",
|
||
"uvicorn[standard]>=0.30",
|
||
"pydantic>=2.7",
|
||
"pydantic-settings>=2.3",
|
||
"sqlalchemy[asyncio]>=2.0",
|
||
"alembic>=1.13",
|
||
"asyncpg>=0.29",
|
||
"httpx>=0.27",
|
||
"pyyaml>=6.0",
|
||
"structlog>=24.1",
|
||
# Эмбеддинги для слот-автомата: матчинг вопроса к чек-листу. Нужны ядру,
|
||
# а не только голосу, поэтому не в группе voice.
|
||
"onnxruntime>=1.18",
|
||
"tokenizers>=0.19",
|
||
"numpy>=1.26",
|
||
# Числа словами перед синтезом: Silero молча выбрасывает цифры, и звонящий
|
||
# произносит «улица Ленина, дом… квартира…» без номеров.
|
||
"num2words>=0.5.13",
|
||
]
|
||
|
||
[project.optional-dependencies]
|
||
# Тяжёлый слой моделей — ставится отдельно: uv sync --extra voice
|
||
voice = [
|
||
"onnx-asr>=0.6",
|
||
"torch>=2.2",
|
||
# Нужен пакету Silero TTS: импорт зашит внутри v5_ru.pt.
|
||
"scipy>=1.11",
|
||
]
|
||
dev = [
|
||
"pytest>=8.2",
|
||
"pytest-asyncio>=0.23",
|
||
]
|
||
|
||
# torch — только CPU-сборка. Из обычного PyPI он тянет CUDA-библиотеки
|
||
# на несколько гигабайт, а GPU на стенде нет (docs/arch/STACK.md).
|
||
[tool.uv.sources]
|
||
torch = { index = "pytorch-cpu" }
|
||
|
||
[[tool.uv.index]]
|
||
name = "pytorch-cpu"
|
||
url = "https://download.pytorch.org/whl/cpu"
|
||
explicit = true
|
||
|
||
[build-system]
|
||
requires = ["hatchling"]
|
||
build-backend = "hatchling.build"
|
||
|
||
[tool.hatch.build.targets.wheel]
|
||
packages = ["app"]
|
||
|
||
[tool.pytest.ini_options]
|
||
asyncio_mode = "auto"
|
||
# Живые запросы к LLM идут отдельно (`make test-llm`): они требуют сети,
|
||
# а рассуждающая модель отвечает десятками секунд.
|
||
markers = ["llm: живой запрос к провайдеру LLM"]
|
||
addopts = "-m 'not llm'"
|