# Peito Denoise

[English](README.md) · **Русский**

Реалтайм ИИ-шумодав для браузера, Electron и Capacitor-WebView. Нейросетевое подавление шума прямо на клиенте, сквозная латентность ~60 мс, поставляется как npm-библиотека `peito-denoise`.

Демо: https://peito.ru

## Что это

Библиотека берёт любой аудиоисточник в Web Audio (микрофон, `MediaStreamTrack`, файл) и отдаёт очищенный звук в реальном времени — без сервера инференса, вся модель работает в браузере через `onnxruntime-web`. Ядро — порт DSP-конвейера DeepFilterNet3 на TypeScript плюс стриминговый нейросетевой инференс. Вокруг ядра — коммерческая обвязка: лендинг, личный кабинет, админка, офлайн-лицензии с ECDSA-подписью, онлайн-активация и оплата через ЮKassa.

Отдельный акцент проекта — наблюдаемость. Шумодав легко «съедает» речь или добавляет музыкальные артефакты, и на слух это ловится плохо. Поэтому в поставке есть спектрограммы вход/выход бок о бок, живые метрики, детекторы искажений и выгрузка raw/processed в WAV для офлайн-репро.

## Возможности

- **Реалтайм-инференс в браузере.** DeepFilterNet3 через `onnxruntime-web` (wasm), стриминговый прогон кадр за кадром с переносом состояния GRU между кадрами. Инференс p50 ~4 мс/кадр — быстрее реалтайма.
- **Несколько бэкендов из коробки.** `dfn3` (нейросеть), `spectral` (чистый TS: STFT + Wiener-gain, ~24 дБ на стационарном шуме, без ассетов) и `passthrough`. Переключение в рантайме без пересоздания аудиографа.
- **Плагинные бэкенды.** Свою модель (RNNoise / DTLN / GTCRN / произвольный ONNX) подключаешь через `registerBackend`, не трогая конвейер — интерфейс покадровой обработки с внутренним состоянием.
- **Наблюдаемость.** Батч метрик ~15 Гц: in/out RMS и peak в дБ, фактический `reductionDb`, шумовой пол, `inferMs` p50/p95/p99, `deadlineMisses`, заполнение кольца, under/overruns, измеренная латентность, VAD. Спектрограммы вход/выход и дамп в WAV.
- **Детекторы искажений.** `clip`, `click`/разрыв, `musical`, `oversuppress` (модель ест речь при активном VAD), `nan`/`inf` (guard с мьютом кадра), `dead` — как события с кольцевым журналом истории.
- **Fail-open watchdog.** Если воркер замолчал дольше `watchdogMs`, шумодав автоматически пропускает сырой звук (а не тишину) и восстанавливается, когда воркер оживает. Все границы wasm/worker обёрнуты, ошибки идут в событие, не молча.
- **AutoGain.** Дотягивание тихой речи до целевого уровня: VAD-гейт, посэмпловое сглаживание, lookahead-лимитер — без щелчков и клиппинга, с ограничением буста.
- **Лицензирование.** Офлайн-проверка по подписи ECDSA P-256 (WebCrypto): домены с wildcard, срок, фичи. Основной путь — онлайн-активация с выдачей зашифрованных моделей и мгновенным отзывом.
- **Кросс-платформенность.** Браузер, Electron, Capacitor-WebView; адаптер `TrackProcessor` для LiveKit.

## Технологии

**Ядро / DSP-ML**
TypeScript, Web Audio API (AudioWorklet), Web Workers, SharedArrayBuffer + Atomics, `onnxruntime-web`, DeepFilterNet3 (ONNX, streaming-сплит), собственный DSP (STFT/ISTFT, ERB-фильтрбанк, FFT по Блюштейну, биквады, VAD, AutoGain).

**Бэкенд витрины**
Node.js + TypeScript (tsx), собственный HTTP-слой, JSON-хранилище с атомарной записью, ECDSA-подпись ключей (WebCrypto), ЮKassa (checkout + вебхук с проверкой статуса через API), nodemailer (подтверждение email, сброс пароля), Redis / in-memory rate-limit и сессии.

**Инфраструктура**
Vite (сборка библиотеки и сайта), Docker Compose, Caddy (статик + авто-TLS Let's Encrypt + прокси), Redis, S3 Selectel (раздача зашифрованных моделей по presigned-URL), Prometheus + Grafana, шифрованные бэкапы БД (AES-256-GCM).

## Архитектура

Горячий путь аудио вынесен из основного потока и построен так, чтобы никогда не блокироваться. **AudioWorklet** держит realtime-контракт: в его `process()` нет ни инференса, ни аллокаций — только чтение и запись кольцевых буферов, а при underrun он делает fail-open на сырой звук. Весь тяжёлый расчёт живёт в **Web Worker**: инференс модели, метрики, детекторы искажений, кольцевая запись для дампа.

Обмен между worklet и worker идёт через **lock-free SPSC ring buffer на `SharedArrayBuffer`** плюс отдельный блок атомиков под контрол и счётчики. `postMessage` используется только для редких контрол-сообщений и троттлёного батча метрик — на горячем пути его нет вообще. Против джиттера и щелчков выходное кольцо праймится тишиной (запас на GC и пачечное потребление аудиоустройством), а лишний входной бэклог сливается редкими крупными кусками, а не частыми мелкими дропами.

DSP-ядро DeepFilterNet3 портировано с upstream libDF на TypeScript: STFT 960/480 с Vorbis-окном, ERB-фильтрбанк на 32 полосы, нормализации и ISTFT. Корректность порта проверена round-trip-реконструкцией — ошибка **2.4e-7**. FFT размера 960 (не степень двойки) считается через алгоритм Блюштейна. Инференс повторяет upstream 1:1: `enc_conv → enc_gru(h) → erb_dec(h) + df_dec(h)`, применение ERB-маски и deep filter (5 тапов × 96 бинов) со стейтами GRU между кадрами.

Для `SharedArrayBuffer` нужна cross-origin isolation, поэтому вся раздача работает под заголовками COOP `same-origin` / COEP `require-corp`, а модели с S3 отдаются с `Cross-Origin-Resource-Policy: cross-origin`. На реальном домене это требует HTTPS (secure context) — в деплое TLS выпускает и продлевает Caddy.

```
mic / track / файл → MediaStreamSource → AudioWorklet (realtime ring IO)
                                              |
                     SharedArrayBuffer: lock-free SPSC ring + атомики
                                              |
                          Web Worker (инференс модели + метрики + детекторы)
                                              |
                     AudioWorklet out → destination / MediaStreamDestination
```

## Цифры

| Показатель | Значение |
|---|---|
| Сквозная латентность | ~60 мс (~30 мс алгоритмических: lookahead 2 кадра + хоп; 20–40 мс антиджиттер-буфер) |
| Инференс DFN3 | p50 ~4 мс/кадр (wasm), быстрее realtime |
| Ошибка round-trip DSP-ядра | 2.4e-7 |
| Спектральный шумодав | ~24 дБ на стационарном шуме, без ассетов |
| Размер ONNX-моделей | ≈8.5 МБ (streaming-сплит, 4 модели) |
| Частота / кадр (spectral) | 48 кГц, hop 256, FFT 512, 50% overlap, sqrt-Hann |
| Пропускная способность API активаций | ~3300 актив./с (бенч на одной ноде) |

## Что входит в продукт помимо ядра

- **npm-библиотека** `peito-denoise` с типами, worklet и отдельной точкой входа `peito-denoise/panel` (дебаг-панель с метриками, лампами детекторов и журналом — не в прод-бандле).
- **Витрина**: лендинг с тарифами, документация по интеграции, демо-стенд шумодава.
- **Личный кабинет**: регистрация и вход с подтверждением email и восстановлением пароля, список лицензий, покупка (бесплатный план сразу, платный — через ЮKassa), смена доменов с перевыпуском ключа, отзыв.
- **Админка**: онлайн-сессии, платежи, лицензии, выручка, аптайм; автообновление.
- **Деплой одной командой**: Docker Compose со стеком Caddy + API + Redis + шифрованные бэкапы + Prometheus/Grafana, раздача моделей с S3.

Надёжность вынесена в приоритет: атомарная запись БД (temp + `rename` + `.prev`) с автовосстановлением из `.prev`, graceful degradation при падении Redis (fail-open на in-memory, активации не падают), graceful shutdown по SIGTERM, health-check и авто-рестарт контейнеров, retry активаций на клиенте с экспоненциальным backoff, шифрованные бэкапы каждые 15 минут.

## Статус

Коммерческий продукт. Исходный код закрыт, доступ для технического ревью — по запросу. Живое демо — по ссылке выше.
