- адреса приложения переехали в своё пространство `/app/`, опрос готовности убран целиком: рубеж и причину остановки владелец узнаёт карточкой записи, текст — отдельным адресом названного вида - заведена единая точка отображения доменной ошибки и слой, приводящий к той же форме отказы библиотеки: тело несёт машиночитаемый код рядом с сообщением - у записи появились имя файла отправителя, длительность и размер своими колонками, а у ленты владельца — свой индекс: без него страница сканировала весь архив сервиса
11 KiB
Паспорт проекта
Зачем это и для кого. architecture.md отвечает «как устроено», tasks/BACKLOG.md — «в каком порядке», паспорт — «зачем и для кого».
Цель
Превращать записанную речь в текст, который можно читать и искать, и хранить этот текст вместе с записью.
Сервис — архив, и это решено 2026-08-11. Прежде граница читалась «отдаём текст и на этом заканчиваем»; теперь расшифровки и исходные записи лежат бессрочно, а список отбирается по темам. Причина в основном сценарии: семейный архив загружают один раз, а возвращаются к нему годами.
Потребители — список закрытый: он определяет, что считать нужным, а что интересным.
| Кто | Что ему нужно от нас |
|---|---|
| Владелец сервиса | Загрузить диктофонную запись или видео из семейного архива с телефона и получить текст. Видеть, кто сколько загрузил и во что это обошлось |
| Приглашённый пользователь | Войти в приложение через свою учётную запись, загрузить запись, забрать текст, вернуться к ней через месяц. Приложение ставится на телефон; каждый видит только свои записи |
| Внешняя программа | Отдать файл по HTTP, представившись своим токеном, и опросить готовность. Сегодня почти не работает: приём и опрос закрыты сессией OIDC, а своего токена у программы нет — годится только чужая сессия, снятая из браузера и предъявленная кукой либо заголовком Authorization. Токен приносит api-tokens |
Вход у сервиса один — HTTP API, и приложение строится поверх него. До 2026-08-11 основным входом был Telegram-бот. 2026-08-11 основным объявили приложение: диктофонная запись на несколько часов через Telegram не проходит вовсе. 2026-08-14 бот убран целиком — временно, до задачи, которая свяжет чат с учётной записью. Вместе с ним из потребителей ушёл пользователь Telegram.
Цель достигнута, когда:
- запись любого распространённого формата принимается без предварительной подготовки, включая дорожку из видео;
- запись расчётного потолка — шести часов — доходит до текста, а не прерывается
ошибкой при достижении предела (норма —
openspec/specs/storage); - сервисом пользуются несколько человек, и записи одного не видны другому;
- текст доступен там же, где загружали. Человек узнаёт о его готовности, не держа приложение открытым;
- расшифровка не теряется: к записи возвращаются через месяц и находят её по заголовку и темам;
- владелец видит расход по каждому пользователю и понимает, во что обходится приглашение ещё одного человека.
Что целью не является
Граница домена. По ней в теме architecture судят, не перенесено ли понятие
через границу.
- Правка текста руками. Машинную вычитку расшифровки отдаём — литературный текст стоит рядом с сырым, — а редактором не становимся: текст руками не правим, не размечаем и не экспортируем в форматы документов. Граница сдвинута 2026-08-11: до того запрет читался «расшифровку отдаём как есть».
- Разговор о записи. Ответы на вопросы по содержанию и поиск по смыслу — за границей. Заголовок, пересказ и темы внутри границы: она сдвинута 2026-08-10, и до того запись читалась «мы отдаём текст, а не выводы из него». Считать уровни текста берётся задача llm-insights-adapter.
- Собственные модели. Не обучаем и не держим у себя ни модель распознавания, ни языковую модель: и речь, и выводы из текста считает внешний сервис.
- Управление учётными записями. Пользователей заводит и проверяет внешний провайдер, свою регистрацию и свои пароли не делаем. Одно исключение появилось 2026-08-11 вместе с решением про PocketBase: в панель администратора владелец входит своим паролем, потому что подпустить к ней внешнего провайдера PocketBase не даёт.
- Живая расшифровка. Работаем с готовой записью, поток в реальном времени не обрабатываем.
- Диктофон. Запись звука делает телефон, а приложение принимает готовый файл. Своей записи и работы без сети не делаем.
- Файловое хранилище общего назначения. Храним аудио и видео, отданные ради
речи в них. Складом произвольных файлов и папками сервис не становится. Общего
доступа к чужим записям целью нет, и с 2026-08-14 его нет и на деле: у записи
есть владелец, и чужую по её идентификатору не отдают
(security.md, «Периметр»). Закрыла это задача
record-ownership. - Учёт денег. Считаем объём, минуты и токены по каждому пользователю и показываем их владельцу. Цен, счетов и отказов по исчерпании квоты не делаем: пользователя, потратившего слишком много, останавливает разговор или отзыв доступа в Authelia.
Типовые сценарии
Первые два — основные, и сегодня не работает ни один: приложения нет.
- Семейный архив. Человек открывает приложение на телефоне, выбирает до десяти записей разом — диктофонные дорожки и видео, — и закрывает его. Загрузка показывает ход. Файл, который уже загружали, не грузится второй раз. Когда текст готов, приходит уведомление; в списке запись видна заголовком и темами.
- Возвращение к записи. Через месяц человек открывает список, находит запись по заголовку или теме и читает вычитанный текст, а при нужде — сырую расшифровку.
- Загрузка по HTTP. Программа шлёт
POST /app/audiorecordsсо своим токеном, получает идентификатор записи и читает её карточкуGET /app/audiorecords/{id}, пока не увидитdone; текст забирает отдельным адресомGET /app/audiorecords/{id}/text. Сегодня доступно только предъявившему сессию OIDC: анонимный запрос всеми адресами отклоняется. Своего входа у программы нет — его заводитapi-tokens. Записи при этом разграничены: программа с чужой сессией видит только записи того, чью сессию предъявила. - Отказ на середине. Конвертация или распознавание не удались — запись
получает признак остановки с причиной, и карточка записи отдаёт признак и
причину тому, кто её загрузил. Сообщения о неудаче сервис никому не шлёт:
доставка ушла вместе с ботом, а уведомления заводит задача
ntfy-delivery.
Референсы
Где смотреть prior art, когда упёрлись.
- Yandex SpeechKit, отложенное распознавание — модель
deferred-general, которой пользуемся: она и задаёт потолок по длине записи и формату. - Whisper и его серверные обёртки — запасной путь, если внешний сервис
перестанет устраивать по цене или по качеству русской речи.
PocketBase из референсов ушла: она больше не кандидат — в стек её перевела
задача
pocketbase-storage2026-08-12 (adr); там она держит хранилище, файлы и панель владельца. Схема и раскладка — database.md. Учётные записи она хранит и получает от Authelia своим провайдером OIDC, но источником их не становится: заводит и проверяет людей по-прежнему Authelia.