diff --git a/doc/tasks.md b/doc/tasks.md index 88b910d5..c5673ba1 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -259,10 +259,20 @@ существование файла, а `wf()` создаёт его до записи. Читатель иногда получает пустую ссылку и ошибку префикса `utun://`. Публиковать готовый файл атомарно. -[ ] **Linux ONNX Runtime: повторная регистрация схем при запуске теста** — 03.10.2026: - test_silero_vad при загрузке модели печатает серии `Schema error: ... already registered`. - Инференс, речь, тишина и reset проходят; отдельно проверить состав и загрузку Linux-библиотек ONNX. - Диагностика: `/tmp/vad-compressor-silero-tests.log`; Android-сборка таких сообщений не содержит. +[+] **Linux ONNX Runtime: повторная регистрация схем при запуске теста** — проверено 21.10.2026: + Причина в системной сборке `1.23.2+dfsg-6ubuntu1`: Runtime вручную регистрирует схемы, + затем динамическая `libonnx.so.1` повторяет регистрацию в `OpSchemaRegistry::map()`. + Подтверждено GDB (`/tmp/silero-schema-gdb.log`) и исходниками обеих библиотек. + Текущая Linux x64 CMake-сборка переключена на [официальный Runtime 1.23.2](https://github.com/microsoft/onnxruntime/releases/tag/v1.23.2). + Архив `onnxruntime-linux-x64-1.23.2.tgz` распакован в `.cache/onnxruntime/`; + SHA-256: `1fa4dcaef22f6f7d5cd81b28c2800414350c10116f5fdd46a2160082551c5f9b`. + Для существующего include `onnxruntime/onnxruntime_c_api.h` создана ссылка + `.cache/onnxruntime/include/onnxruntime` → `../onnxruntime-linux-x64-1.23.2/include`. + В CMake явно заданы абсолютные пути: `ONNXRUNTIME_INCLUDE_DIR=/.cache/onnxruntime/include`, + `ONNXRUNTIME_LIB=/.cache/onnxruntime/onnxruntime-linux-x64-1.23.2/lib/libonnxruntime.so`. + Выбор сохраняется в `tools/chatgui/build/CMakeCache.txt`; после удаления cache его нужно повторить. + `ldd` подтверждает официальный Runtime без отдельной `libonnx`; весь `test_silero_vad` проходит без `Schema error`. + Лог проверки: `/tmp/silero-runtime-test.log`, полный вывод — `tools/chatgui/build/Testing/Temporary/LastTest.log`. [ ] **debug_parse_config: формат и индексы категорий** — parser ожидает `:`, документация описывает `=`; преобразование битовой маски осталось после перехода enum на индексы. diff --git a/lib/silero_vad.c b/lib/silero_vad.c index b7c1e180..01ba359b 100644 --- a/lib/silero_vad.c +++ b/lib/silero_vad.c @@ -82,7 +82,8 @@ static int vad_read_file(const char* path, uint8_t** out, size_t* out_len) { } /* Общая инициализация детектора из байтов модели (файл или вшитая модель). - * data может указывать на внешний буфер (вшитая модель) — тогда не освобождается. */ + * owned_buf передаётся детектору только при успехе; при ошибке остаётся у вызывающего. + * Для вшитой модели owned_buf == NULL, её байты не освобождаются. */ static silero_vad_t* silero_vad_create_from_bytes(const uint8_t* data, size_t len, const uint8_t* owned_buf, const char* label) { silero_vad_t* vad = NULL; @@ -107,7 +108,6 @@ static silero_vad_t* silero_vad_create_from_bytes(const uint8_t* data, size_t le return NULL; } vad->ort = ort; - vad->model_data = (uint8_t*)owned_buf; vad->model_len = len; status = ort->CreateEnv(ORT_LOGGING_LEVEL_WARNING, "utun_silero_vad", &vad->env); @@ -127,6 +127,7 @@ static silero_vad_t* silero_vad_create_from_bytes(const uint8_t* data, size_t le if (status) { vad_report_ort_error(ort, status, "CreateCpuMemoryInfo"); goto fail; } ort->ReleaseSessionOptions(opts); + vad->model_data = (uint8_t*)owned_buf; DEBUG_INFO(DEBUG_CATEGORY_VAD, "silero_vad_create(%s): ok bytes=%zu window=%d context=%d input=%d", label, len, SILERO_VAD_WINDOW_SAMPLES, SILERO_VAD_CONTEXT_SAMPLES, SILERO_VAD_INPUT_SAMPLES); diff --git a/tests/test_silero_vad.c b/tests/test_silero_vad.c index be646569..87f3a03c 100644 --- a/tests/test_silero_vad.c +++ b/tests/test_silero_vad.c @@ -2,7 +2,7 @@ * * Проверяет: * - загрузку модели и жизненный цикл (create/destroy/reset); - * - обработку ошибок (пустой/несуществующий путь, NULL-аргументы); + * - обработку ошибок (пустой/несуществующий путь, неверная модель, NULL-аргументы); * - что на тишине вероятность речи близка к нулю (реальный инференс, не мусор); * - что путь pcm16 даёт тот же результат, что и float (конвертация /32768); * - что вероятность всегда лежит в [0;1]. @@ -17,6 +17,7 @@ #include "../lib/silero_vad.h" #include "../lib/audio_compressor.h" #include "../lib/debug_config.h" +#include "../lib/mem.h" #include "../src/radio/radio_auto.h" #define PI 3.14159265358979323846 @@ -60,6 +61,14 @@ static int test_lifecycle_and_errors(const char* model_path) { vad = silero_vad_create("/nonexistent/silero_vad.onnx"); CHECK(vad == NULL, "create(bad path) should fail"); + /* Непустая PCM-фикстура читается успешно, но ONNX должен отклонить её без double-free и утечки. */ + size_t allocated = u_get_allocated_count(); + vad = silero_vad_create(TEST_SILERO_SPEECH_PATH); + CHECK(vad == NULL, "create(invalid model) should fail"); + silero_vad_destroy(vad); + CHECK(u_get_allocated_count() == allocated, "create(invalid model) leaked allocations"); + DEBUG_INFO(DEBUG_CATEGORY_VAD, "invalid model cleanup: allocations before=%zu after=%zu", allocated, u_get_allocated_count()); + vad = silero_vad_create(model_path); CHECK(vad != NULL, "create(%s) should succeed", model_path); if (!vad) return 1; diff --git a/tools/chatgui/readme.md b/tools/chatgui/readme.md index cdbb632f..64c3cf7c 100644 --- a/tools/chatgui/readme.md +++ b/tools/chatgui/readme.md @@ -1,6 +1,11 @@ Vibechat -Децентрализованный чат, с поддержкой групп. По дизайну отправляет сообщения преимущественно напрямую адресату, а если прямое подключение невозможно то только через других участников этой группы. +Это децентрализованный мессенджер с упором на конфиденциальность и прямой обмен данными между узлами. Работает без каких либо серверов, напрямую между участниками. Поэтому для стабильной работы группы желательно иметь хотябы одного участника который имеет постоянный ip адрес и постоянно доступен. +После установки вы получаете мессенджер который не привязан ни к каким серерам, а использует для коммуникации только помощь других как вы участников групп которые вы добавили. +В начале вам надо либо создать свою группу и приглашать по ссылке других участников, либо присоединиться к чьей-то группе - попросите ссылку-приглашение и присоединитесь к группе. + + +Поддерживает групповые чаты, видеозвонки, рацию, голосовые сообщения, видеотрансляции, файлообмен. По дизайну отправляет сообщения преимущественно напрямую адресату, а если прямое подключение невозможно то только через других участников этой группы. Участника группы можно сделать суперузлом и медиаузлом. Суперузел должен иметь прямой ip адрес. Такие узлы будут помогать маршрутизации между узлами, а медиаузлы - хранению контента группы. Также есть личные сообщения - которые могут проходить через промежуточные узлы, но только в зашифрованном виде, включая аттачи. Если адресат недоступен, отправитель просит медиаузел сохранить собощение и передать узлу когда он станет доступен. Контент группы хранится на узлах которые его загрузили в незашифрованном виде.