Files
agentik-desktop/MIC-ASR-SEARCH.md
T

175 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Микрофон и распознавание: результаты поиска
**Задача была:** найти готовые библиотеки для работы с микрофоном и распознавания,
прежде чем брать код из `ai/assistent`. **Код не пишем** — только поиск.
**Ответ короткий:** и то, и другое **уже есть у нас, готовое и опубликованное**.
Из `ai/assistent` брать код микрофона **не нужно вообще**.
---
## 1. Микрофон: библиотека есть — `mic-kmp`
**Репозиторий:** https://git.binom.pw/subochev/mic-kmp
**Каталог:** https://git.binom.pw/subochev/libraries (раздел «📦 Микрофон»)
KMP-библиотека: поток микрофона как `Flow<ByteArray>` (s16le mono PCM).
Три файла, вот и вся библиотека:
| Файл | Что делает |
|---|---|
| `mic-api/src/commonMain/.../MicAudio.kt` | интерфейс `MicDevice` + объект `MicAudio.record(...)` |
| `mic-api/src/jvmMain/.../MicJvm.kt` | JVM — `javax.sound.sampled` (`TargetDataLine`) |
| `mic-api/src/androidMain/.../MicAndroid.kt` | Android — `AudioRecord` |
**Таргеты: `jvm` и `android`.** JVM-таргет — ровно то, что нужно десктопу.
JVM-код собран на `JvmTarget.JVM_17`.
**Опубликована в Nexus `caffeine`, версия `1.0.0`:**
- `pw.binom.mic:mic-api:1.0.0` (KMP metadata)
- `pw.binom.mic:mic-api-jvm:1.0.0` (JVM — **наше**)
- `pw.binom.mic:mic-api-android:1.0.0`
Проверено: `maven-metadata.xml` отдаёт `HTTP 200`, latest = `1.0.0`.
**Использование — одна строка:**
```kotlin
MicAudio.record(sampleRate = 16000, channels = 1, chunkMillis = 100)
.onEach { chunk: ByteArray -> /* s16le mono PCM, ~100 мс */ }
```
**Чем лучше кода из assistent:** отмена **структурная**. Остановил корутину-коллектор —
микрофон освободился сам, в `finally`. Не надо помнить про `close()`. В assistent
(`MicrophoneRecorder`, 83 строки) — ручное управление через `start()`/`stop()`,
и связка «канал + флаг recording + внешний TargetDataLine». Наш вариант чище.
**Вывод: копировать `MicrophoneRecorder` из assistent НЕ надо — подключить `mic-kmp`.**
---
## 2. Распознавание: библиотека есть — `asr-kmp`
**Репозиторий:** https://git.binom.pw/subochev/asr-kmp
**Каталог:** https://git.binom.pw/subochev/libraries (раздел «🎙 ASR»)
KMP, таргеты **jvm** и **android** (плюс native: linux, macos, mingw).
Потоковый интерфейс — приём аудио кусками и **промежуточный текст по ходу**:
```kotlin
interface Stt : AutoCloseable {
fun feed(samples: FloatArray) // порция 16 кГц моно PCM, [-1, 1]
fun partialText(): String? // промежуточный текст (растёт по ходу)
fun endOfInput() // конец ввода
fun finalText(): String // итог
override fun close()
}
```
**Есть `partialText` — текст появляется по мере речи**, а не после конца записи.
Для нашей кнопки микрофона это именно то поведение, которое нужно.
### Движки (все опубликованы в `caffeine`)
| Движок | Координаты (группа `pw.binom.asr`) | Версии в Nexus |
|---|---|---|
| `asr-api` — интерфейс | `asr-api` / `-jvm` / `-android` | до `4` |
| `asr-vosk` — Vosk | `asr-vosk` / `-jvm` / `-android` | есть |
| `asr-qwen3` — Qwen3-ASR | `asr-qwen3` / `-jvm` | есть |
| `asr-whisper` — Whisper | `asr-whisper` / `-jvm` / `-android` | есть |
| `asr-openai` — удалённое (OpenAI-совместимое) | `asr-openai` | есть |
Под капотом нейронок — `sherpa-onnx` (`com.github.k2-fsa.sherpa-onnx`, `v1.13.6`),
для JVM отдельно тянется нативная библиотека `sherpa-onnx-native-lib-linux-x64`.
### Про модели (важно)
- **Qwen3-ASR** — модель уже на нашем статик-сервере, качать из-за бугра не надо:
`http://static.binom.pw/models/qwen3_06/` (~940 МБ: encoder 175M, decoder 721M, frontend 43M).
- **Whisper small int8** — модели на статике НЕТ, качать самостоятельно.
- **Vosk** (`vosk-model-small-ru-0.22`) — **входит в комплект**, распаковывается сам.
Самый простой путь для первого запуска: ничего качать не надо.
---
## 3. Рядом есть ещё три полезные библиотеки
Из того же каталога `subochev/libraries`:
### VAD — детектор речи, `vad-kmp`
https://git.binom.pw/subochev/vad-kmp — «VAD — Silero», KMP jvm+android,
**модель внутри артефакта** (2.3 МБ, ничего качать не надо).
```kotlin
VadInstance(16000).use { vad ->
val prob = vad.processingWindow(windowPcmFloats) // FloatArray → [0..1]
}
```
Координаты: `pw.binom.voice.vad:vad-jvm`, версия `2`.
**Зачем:** определять, говорит человек или молчит — не гнать тишину в распознавание.
### Есть и второй VAD
`pw.binom.ai.voice:vad` — «детектор речи (VAD) — `vad` / `vad-jvm`». Два разных VAD,
при выборе разобраться, какой свежее.
### OpenAI-клиент
`pw.binom.openai:api` / `api-jvm` + `ktor-impl` (HTTP-движок). Нужен для `asr-openai`
(распознавание на удалённом сервере, а не локальной нейронкой).
### Speaker-эмбеддинги и text-embedding
- `subochev/embedding-kmp` — voice embedding (кто говорит).
- `subochev/text-embedding-kmp` — text embedding (SigLIP2).
Нам сейчас не нужно, но пусть будет известно.
---
## 4. Как это собрано вместе — пример `view-mate`
**Репо:** `/root/WORK/view-mate` (очки RayNeo X2), модули `app-glasses`, `app-phone`, `app-host`, `lib-core`.
**Важно:** view-mate **не подключает** `mic-kmp`/`asr-kmp` как библиотеки — у него
своя реализация `SttMicStream` на `android.media.AudioRecord`
(`app-glasses/.../stt/SttMicStream.kt`). То есть `mic-kmp` — это **вынесенная
и обобщённая** версия того же подхода.
Из полезного в `SttMicStream.kt` — комментарий на строке 229:
`AudioRecord.read(byte[], int, inFrameCount)` возвращает **число кадров**, а не байт.
Классические грабли Android-записи.
---
## 5. Чем пользуется сам `ai/assistent`
Важно для понимания разницы подходов:
`chat-server/.../stt/SttClientImpl.kt` — это **не** локальное распознавание.
Это HTTP-клиент к OpenAI-совместимому API:
```kotlin
client.post("$base/audio/transcriptions") { ... } // multipart, как у OpenAI
```
Настройки через переменные окружения:
- `STT_API_KEY` — без него голосовой адаптер выключен;
- `STT_URL` — по умолчанию `https://api.openai.com/v1`;
- `STT_MODEL` — по умолчанию `whisper-1`.
**Вывод:** у assistent распознавание — **отправка файла на сервер**. У нас
`asr-kmp` умеет и локальные нейронки (Qwen3, Whisper, Vosk), и удалённое (`asr-openai`).
Наш вариант шире, а `mic-kmp` (поток) + `asr-kmp` (поток) + `vad-kmp` (детектор речи)
складываются в готовую цепочку: **микрофон → детектор речи → распознавание → текст**.
---
## 6. Итог: что делать
| Вопрос | Ответ |
|---|---|
| Та отдельная библиотечка для микрофона, которую мы делали — существует? | **Да.** `mic-kmp`, опубликована в `caffeine` версии `1.0.0`, jvm-таргет есть. |
| Библиотечки распознавания с нейронками где? | **`asr-kmp`** — Qwen3, Whisper, Vosk, удалённое. Всё в `caffeine`. Плюс каталог: `subochev/libraries`. |
| Есть ли где-то микрофон в каталоге библиотек? | **Да**, первым разделом — «📦 Микрофон». |
| Брать ли код микрофона из `ai/assistent`? | **Нет.** Подключаем `mic-kmp` — чище, с автоосвобождением, без внешних библиотек. |
| Нужны ли сторонние зависимости для звука? | **Нет.** Всё на стандартной Java (`javax.sound.sampled`) и sherpa-onnx для нейронок. |
**Код не писан** — только поиск, как и просили.