Стенограф — Microsoft Internet Explorer
« НазадАдрес:/projects/stenograf/

Стенографрасшифровка по ролям

Для себя · iPhone и веб-версия · октябрь 2026 AI-Created

Разговор — по ролям

Записывает разговор на телефон, разделяет его по голосам и выдаёт расшифровку по ролям — чтобы потом разобрать разговор, в том числе с помощью ИИ.

Звук и текст обрабатываются на устройстве, записи никуда не загружаются.

когда
20–21 октября 2026, 24 коммита
статус
версия 1.0.0; установлено на iPhone, проверка на устройстве идёт
роль
идея и постановка задачи, продуктовые решения, выбор дизайна и названия, тестирование и приёмка
97 %

речи в шумном кафе отнесено к правильному человеку

61 %

речи покрывает расшифровка в том же шуме — узкое место в распознавании

79 с

на 1 мин 34 с аудио в браузере, один поток

26 тестов

автотестов: 19 на Swift, 7 на JavaScript

цепочка

  1. 01запись
  2. 02голоса
  3. 03распознавание
  4. 04роли
  5. 05экспорт

что умеет

iPhone

  • запись одной кнопкой, из Быстрых команд и с кнопки действия; пауза
  • запись при заблокированном экране; после звонка продолжается сама, если iOS разрешает
  • таймер, уровень звука и сколько мегабайт уже на телефоне
  • запись возвращается после сбоя или закрытия приложения посреди записи
  • расшифровка на телефоне: число собеседников «авто» или от 2 до 8
  • голоса — переименовать, объединить, перенести реплику другому
  • плеер: перемотка по волне, ±15 с, 1× / 1,5× / 2×; нажал на реплику — слушаешь с неё
  • экспорт в Markdown, JSON или текст; аудио — в Telegram, AirDrop, почту или «Файлы»

Веб-версия

  • запись с микрофона или загрузка файла перетаскиванием
  • расшифровка в браузере, без сервера
  • разговор как многодорожечная запись: у каждого голоса своя дорожка
  • правка голосов и реплик — как в приложении
  • скачать расшифровку в Markdown, JSON или TXT и исходное аудио; скопировать для ИИ-чата
  • темы корпуса «Графит» и «Серебро»
  • два встроенных примера: четыре разных голоса и диалог в шумном кафе

как устроено

iPhone
Всё на телефоне, сервера нет. Запись — WAV 24 кГц моно, после остановки сжатие в AAC. Голоса — pyannote, WeSpeaker и кластеризация VBx через FluidAudio на Core ML / Neural Engine, речь — Parakeet. Интернет нужен один раз — скачать модели, около 1 ГБ.
общая логика
Отдельный модуль без зависимостей от iOS сопоставляет слова голосам, правит роли и делает экспорт. В веб-версию он перенесён построчно, поэтому реплики режутся одинаково.
веб
Одна страница. Модели в фоновом потоке на WebAssembly: pyannote-segmentation-3.0, WeSpeaker ResNet34, Whisper base с временем слов. Отпечатки голосов — иерархическая кластеризация, записи и кэш моделей — в IndexedDB.
сборка без Mac
GitHub Actions на macOS: тесты, сборка для симулятора, скриншоты в демо-режиме, автопроверка записи, сборка для iPhone. На Linux — тесты веб-версии.

что пришлось решать

  1. 01

    Нет Mac, а приложение для iPhone.

    Сборка и проверка целиком в GitHub Actions на macOS: скрипт сам выбирает свежий Xcode, симулятор снимает скриншоты, отдельный прогон проверяет запись. Готовая сборка складывается в отдельную ветку.

  2. 02

    Сжатый m4a становится нечитаемым, если приложение закрыли посреди записи.

    Звук пишется в WAV с первой секунды, на диске отмечено, что запись идёт. При следующем запуске заголовок чинится, запись появляется как «восстановленная»; сжатие — только после нормальной остановки.

  3. 03

    В веб-версии распознаватель выбрасывал речь после смены говорящего.

    Whisper получает звук кусками по репликам одного голоса, а не сплошным потоком.

  4. 04

    Модели около 120 МБ во встраиваемой версии страницы, где строгие правила: только свои файлы, ограниченные типы и размеры.

    Модели нарезаны на части до 14 МБ и подставляются в библиотеку через свой кэш.

  5. 05

    Открытой записи русского разговора в шумном кафе с разметкой не нашлось.

    Смесь собрана скриптом из открытых данных: актёрский диалог, шум столовой и приглушённый чужой разговор. Эталон, кто когда говорил, известен — качество считается, а не оценивается на глаз.

как проверялось

автотесты
19 на XCTest для общего модуля логики — на macOS; 7 на Node.js test runner для той же логики в вебе — на Linux. Всё в GitHub Actions.
каждая сборка
На симуляторе iPhone: скриншоты 5 экранов в демо-режиме, запись 6 секунд с проверкой сжатого файла, «убийство» приложения посреди записи и проверка, что запись восстановлена.
смоук-тест
Весь конвейер на тестовом диалоге двух голосов на Mac: тест падает при пустой расшифровке или неверном числе говорящих.
сценарии
Playwright и headless Chromium: правка ролей и сохранение после перезагрузки, режим встраиваемой страницы, запись с тестового микрофона, запуск из локального файла, вёрстка на 6 ширинах — от 1440 до 290 px.
вручную
Просмотр скриншотов после каждой сборки, веб-версия на ПК, установка на iPhone.

найденные баги

баг 01исправлено

Веб-версия на ПК записывала, но не расшифровывала

Ранние тесты проходили: браузер запускали с флагом доступа к файлам. Повторили тест без флага — на локальном файле фоновый обработчик не стартовал.

Обработчик переделан в «классический» Web Worker, проверено в том же режиме без флага.

баг 02исправлено

Записи на iPhone не сжимались

На скриншоте разговора — WAV вместо M4A, а список файлов из облачной проверки показал, что сжатый файл не создаётся: кодер AAC отказывался от 64 кбит/с на этой частоте.

Битрейт перебирается по списку, в конце кодер выбирает его сам; результат короче исходника отбрасывается. Проверено: 6,4 с → M4A, 33 КБ.

баг 03исправлено

Табло сужалось при скорости 1,5×

Ручная проверка веб-версии: на узком экране цифры счётчика становились мелкими.

Фиксированная ширина кнопки скорости, на телефоне табло на своей строке, цифры масштабируются по ширине. Проверено на 6 ширинах.

экраны

главный экран
главный экран
идёт запись
идёт запись
разговор по голосам
разговор по голосам
расшифровка по ролям
расшифровка по ролям
запись восстановлена после сбоя
запись восстановлена после сбоя
веб версия тёмная тема
веб версия тёмная тема
веб версия светлая тема
веб версия светлая тема
веб версия запись с микрофона
веб версия запись с микрофона

стек

iOS

  • Swift, SwiftUI, Observation, AVFoundation, Accelerate, App Intents
  • iOS 17+, Liquid Glass на iOS 26; XcodeGen, Xcode 26
  • FluidAudio (Core ML): pyannote, WeSpeaker, VBx, Parakeet

Веб

  • JavaScript, HTML, CSS
  • transformers.js, ONNX Runtime Web (WebAssembly)
  • Web Workers, IndexedDB, Web Audio, MediaRecorder, Canvas, SVG

Сборка и проверка

  • GitHub Actions: macOS и Linux
  • XCTest, Node.js test runner, Playwright
  • Python: сборка веб-версии, сведение тестового звука на numpy

Исходный код не выдаётся.