- база своя: два пула, захват одним UPDATE ... RETURNING, шаги схемы на goose под файловым замком, одна миграция начальной схемы вместо семи прежних - транспорт переписан на net/http: свои слои, свой ограничитель частоты, отдача файла с проверкой владельца; панель /_/ и пространство /api/ исчезли - по находкам ревью: журнал не пишет путь под корнем приложения, ключ бюджета читается справа налево, узнавание известного идёт читающим пулом
154 lines
8.5 KiB
Markdown
154 lines
8.5 KiB
Markdown
# Transcriber Service
|
||
|
||
Сервис расшифровки аудиозаписей. Вход один — HTTP API.
|
||
|
||
## Возможности
|
||
|
||
- Приём аудиофайлов через HTTP API
|
||
- Конвертация в ogg через ffmpeg
|
||
- Распознавание речи через Yandex SpeechKit
|
||
- Отслеживание статуса задач расшифровки
|
||
- Своё хранилище: SQLite для метаданных и каталог файлов записей рядом с ним; метрики Prometheus
|
||
|
||
## Технологии
|
||
|
||
- **Язык**: Go 1.26, CGO не нужен
|
||
- **HTTP**: стандартная библиотека, `net/http`
|
||
- **Распознавание**: Yandex SpeechKit + Yandex Object Storage (S3)
|
||
- **Конвертация**: ffmpeg
|
||
- **База данных**: SQLite через modernc.org/sqlite, CGO не нужен
|
||
- **Шаги схемы**: pressly/goose/v3, библиотекой — накат при старте
|
||
- **Файлы записей**: свой каталог, подкаталог на запись
|
||
- **Метрики**: prometheus/client_golang
|
||
|
||
## Установка и запуск
|
||
|
||
1. Клонируйте репозиторий
|
||
2. Установите зависимости:
|
||
```bash
|
||
go mod tidy
|
||
```
|
||
3. Скопируйте образец конфига и заполните его:
|
||
```bash
|
||
cp config.example.toml config.toml
|
||
```
|
||
4. Запустите приложение:
|
||
```bash
|
||
go run ./cmd/transcriber -c config.toml
|
||
```
|
||
|
||
Сервер запустится на порту из `[server] port`, по умолчанию 8080. Нужен
|
||
установленный `ffmpeg`.
|
||
|
||
### Кого пускают
|
||
|
||
Кто пришёл, сервис узнаёт из заголовка `Remote-User`, который ставит обратный
|
||
прокси, сходив к Authelia; своего входа у сервиса нет. Кому верить, задаёт
|
||
перечень доверенных адресов в секции `[auth]`. Подробности —
|
||
[docs/security.md](docs/security.md), «Что разграничивает доступ»; известные
|
||
прорехи образца конфига — [docs/conventions/config.md](docs/conventions/config.md).
|
||
|
||
Локально прокси нет, а браузер заголовков не ставит — на место контура встаёт
|
||
подставной прокси из оснастки:
|
||
|
||
```bash
|
||
go run ./cmd/devtools proxy
|
||
```
|
||
|
||
Приложение после этого открывают **по адресу прокси** — `http://localhost:9000`.
|
||
В перечне доверенных адресов при этом должен стоять петлевой; строки под это
|
||
стоят в `config.example.toml`.
|
||
|
||
## Деплой
|
||
|
||
Деплой запускается из `pet-project-server`:
|
||
|
||
```bash
|
||
inv pl -- transcriber
|
||
```
|
||
|
||
Плейбук сам зовёт `task image` (контракт роли `app_image`): образ собирается
|
||
локально и едет на сервер через `docker save`/`load`, реестр не участвует.
|
||
Локально образ можно собрать и руками — `task image` даст `transcriber:dev`.
|
||
|
||
## HTTP API
|
||
|
||
Адреса приложения живут под корнем `/app`: `POST /app/audiorecords` — приём
|
||
записи, `GET /app/audiorecords` — страница своих записей,
|
||
`GET /app/audiorecords/{id}` — карточка, `GET /app/audiorecords/{id}/text` —
|
||
текст названного вида, `GET /app/audiorecords/{id}/file` — файл записи названной
|
||
копии, `GET /app/me` — кто пришёл, `GET /app/config` — пределы, которые сервис
|
||
объявляет приложению. Отдельными адресами стоят `GET /metrics` — метрики
|
||
Prometheus с префиксом `transcriber_` — и `GET /health` — проверка живости.
|
||
Своего входа у сервиса нет: кто пришёл, называет заголовок обратного прокси
|
||
([access](openspec/specs/access/spec.md)). Больше на этом порту не отвечает
|
||
ничего: всякий прочий путь получает разметку приложения.
|
||
|
||
Контракт приёма и опроса нормативен и живёт в
|
||
[openspec/specs/intake/spec.md](openspec/specs/intake/spec.md): поля запроса и
|
||
ответа, коды и условия. Менять его — необратимое действие
|
||
([CLAUDE.md](CLAUDE.md), «Работа»), и второго описания у него быть не должно.
|
||
|
||
## Состояния задач
|
||
|
||
Перечень состояний, переходы между ними и число воркеров —
|
||
[docs/database.md](docs/database.md), разделы «Таблицы» и «Представление
|
||
данных»; как сложен конвейер целиком — [docs/architecture.md](docs/architecture.md).
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
transcriber/
|
||
├── cmd/
|
||
│ ├── transcriber/ # Точка входа сервиса: конфиг, миграции, сборка зависимостей, запуск
|
||
│ └── devtools/ # Оснастка разработчика: подставной прокси и возврат записи в работу
|
||
├── internal/
|
||
│ ├── entity/ # Модели: запись, файл, результат распознавания
|
||
│ ├── ident/ # Выдача и разбор идентификаторов строк (ULID)
|
||
│ ├── contract/ # Интерфейсы адаптеров и репозиториев, типы ошибок
|
||
│ ├── config/ # Разбор config.toml
|
||
│ ├── metrics/ # Метрики Prometheus
|
||
│ ├── service/ # Конвейер расшифровки
|
||
│ ├── controller/
|
||
│ │ ├── http/ # HTTP-обработчики
|
||
│ │ └── worker/ # Фоновые воркеры
|
||
│ └── adapter/
|
||
│ ├── converter/ffmpeg/ # Конвертация аудио
|
||
│ ├── metaviewer/ffmpeg/ # Длительность аудио
|
||
│ ├── recognizer/yandex/ # SpeechKit + Object Storage
|
||
│ └── repo/sqlite/ # Репозитории, подключение к базе, шаги схемы, каталог файлов
|
||
└── data/ # Каталог данных: база и файлы записей вместе
|
||
├── transcriber.db # База (создаётся автоматически)
|
||
├── migrate.lock # Замок наката схемы
|
||
└── records/ # Файлы записей: подкаталог на запись
|
||
```
|
||
|
||
## Хранилище
|
||
|
||
Таблицы базы — аудиозапись и её приложения. Поля, ключи, правило времени и
|
||
идентификаторов, раскладка файлов записи и механика захвата задачи воркером —
|
||
[docs/database.md](docs/database.md). Панели владельца у сервиса нет: единственное
|
||
его действие вне экранов — возврат остановленной записи в работу подкомандой
|
||
оснастки.
|
||
|
||
```bash
|
||
go run ./cmd/devtools resume -c config.toml <идентификатор записи>
|
||
```
|
||
|
||
## Разработка
|
||
|
||
Схему двигают шаги `pressly/goose/v3` —
|
||
`internal/adapter/repo/sqlite/migrations`, файл на шаг, версия шага — число в
|
||
начале имени файла. Непринятые шаги накатываются при старте, прежде чем поднимутся
|
||
входы и стартуют воркеры; отказ шага роняет старт. Применённый шаг не
|
||
переписывается: изменение — только новым файлом шага.
|
||
|
||
Проверки перед коммитом — одной командой:
|
||
|
||
```bash
|
||
task gate
|
||
```
|
||
|
||
Что она гоняет, чем краснеет и какой отказ считается объявленным долгом —
|
||
[CLAUDE.md](CLAUDE.md), раздел «Гейт».
|