CLAUDE.md описывает конвейер задач, подвохи конфига и правило про четыре списка колонок в репозитории sqlite. .golangci.yml включает стандартный набор плюс errorlint; осознанные непроверенные вызовы вынесены в исключения. README приведён к коду: эндпоинты /api/audio и /api/status/:id, состояния задач, структура internal/, фактические колонки таблиц.
216 lines
8.0 KiB
Markdown
216 lines
8.0 KiB
Markdown
# Transcriber Service
|
||
|
||
Сервис расшифровки аудиозаписей. Два входа — Telegram-бот и HTTP API.
|
||
|
||
## Возможности
|
||
|
||
- Приём аудио из Telegram: голосовые сообщения, аудиофайлы и документы с аудио
|
||
- Приём аудиофайлов через HTTP API
|
||
- Конвертация в ogg через ffmpeg
|
||
- Распознавание речи через Yandex SpeechKit
|
||
- Отслеживание статуса задач расшифровки
|
||
- SQLite для хранения метаданных, метрики Prometheus
|
||
|
||
## Технологии
|
||
|
||
- **Веб-фреймворк**: gin-gonic/gin
|
||
- **Telegram**: go-telegram-bot-api
|
||
- **Распознавание**: Yandex SpeechKit + Yandex Object Storage (S3)
|
||
- **Конвертация**: ffmpeg
|
||
- **SQL Builder**: doug-martin/goqu
|
||
- **Миграции БД**: pressly/goose
|
||
- **База данных**: SQLite
|
||
- **Метрики**: prometheus/client_golang
|
||
|
||
## Установка и запуск
|
||
|
||
1. Клонируйте репозиторий
|
||
2. Установите зависимости:
|
||
```bash
|
||
go mod tidy
|
||
```
|
||
3. Скопируйте образец конфига и заполните его:
|
||
```bash
|
||
cp config.dist.toml config.toml
|
||
```
|
||
4. Запустите приложение:
|
||
```bash
|
||
go run . -c config.toml
|
||
```
|
||
|
||
Сервер запустится на порту из `[server] port`, по умолчанию 8080. Нужен
|
||
установленный `ffmpeg`.
|
||
|
||
### Белый список Telegram
|
||
|
||
Бот отвечает только тем, кто перечислен в `[server] users_while_list`. В
|
||
`config.dist.toml` этого ключа нет — добавьте его сами:
|
||
|
||
```toml
|
||
[server]
|
||
users_while_list = ["@username"]
|
||
```
|
||
|
||
Значения сверяются со строкой автора сообщения из Telegram (`@username` либо имя
|
||
с фамилией), а не с числовым id.
|
||
|
||
## Деплой
|
||
|
||
Деплой запускается из `pet-project-server`:
|
||
|
||
```bash
|
||
inv pl -- transcriber
|
||
```
|
||
|
||
Плейбук сам зовёт `task image` (контракт роли `app_image`): образ собирается
|
||
локально и едет на сервер через `docker save`/`load`, реестр не участвует.
|
||
Локально образ можно собрать и руками — `task image` даст `transcriber:dev`.
|
||
|
||
## API Endpoints
|
||
|
||
### POST /api/audio
|
||
|
||
Загружает аудиофайл и создает задачу на расшифровку. Отвечает `201 Created`.
|
||
|
||
**Параметры:**
|
||
- `audio` (form-data) - аудиофайл для расшифровки
|
||
|
||
**Пример запроса:**
|
||
```bash
|
||
curl -X POST \
|
||
http://localhost:8080/api/audio \
|
||
-F "audio=@/path/to/your/audio.mp3"
|
||
```
|
||
|
||
**Ответ:**
|
||
```json
|
||
{
|
||
"job_id": "550e8400-e29b-41d4-a716-446655440000",
|
||
"status": "created"
|
||
}
|
||
```
|
||
|
||
### GET /api/status/:id
|
||
|
||
Получает статус задачи расшифровки по ID. Поле `transcription_text` появляется,
|
||
когда задача перешла в `done`.
|
||
|
||
**Пример запроса:**
|
||
```bash
|
||
curl http://localhost:8080/api/status/550e8400-e29b-41d4-a716-446655440000
|
||
```
|
||
|
||
**Ответ:**
|
||
```json
|
||
{
|
||
"job_id": "550e8400-e29b-41d4-a716-446655440000",
|
||
"status": "done",
|
||
"created_at": "2024-01-01T12:00:00Z",
|
||
"transcription_text": "расшифрованный текст"
|
||
}
|
||
```
|
||
|
||
### GET /metrics
|
||
|
||
Метрики Prometheus с префиксом `transcriber_`.
|
||
|
||
### GET /health
|
||
|
||
Проверка работоспособности сервиса.
|
||
|
||
**Ответ:**
|
||
```json
|
||
{
|
||
"status": "ok",
|
||
"message": "Transcriber service is running"
|
||
}
|
||
```
|
||
|
||
## Состояния задач
|
||
|
||
- `created` - задача создана, файл сохранён, ждёт конвертации
|
||
- `converted` - файл сконвертирован в ogg, ждёт отправки на распознавание
|
||
- `transcribe` - распознавание запущено в Yandex SpeechKit, ждём результата
|
||
- `done` - задача завершена успешно
|
||
- `failed` - задача завершена с ошибкой
|
||
|
||
Задачи двигают три фоновых воркера: `conversion_worker`, `transcribe_worker` и
|
||
`check_worker`. Каждый опрашивает базу раз в секунду и делает один шаг.
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
transcriber/
|
||
├── main.go # Точка входа: конфиг, миграции, сборка зависимостей, запуск
|
||
├── internal/
|
||
│ ├── entity/ # Модели: задача, файл, результат распознавания
|
||
│ ├── contract/ # Интерфейсы адаптеров и репозиториев, типы ошибок
|
||
│ ├── config/ # Разбор config.toml
|
||
│ ├── metrics/ # Метрики Prometheus
|
||
│ ├── service/ # Конвейер расшифровки
|
||
│ ├── controller/
|
||
│ │ ├── http/ # HTTP-обработчики
|
||
│ │ ├── tg/ # Telegram-бот
|
||
│ │ └── worker/ # Фоновые воркеры
|
||
│ └── adapter/
|
||
│ ├── converter/ffmpeg/ # Конвертация аудио
|
||
│ ├── metaviewer/ffmpeg/ # Длительность аудио
|
||
│ ├── recognizer/yandex/ # SpeechKit + Object Storage
|
||
│ ├── telegram/ # Отправка сообщений
|
||
│ └── repo/sqlite/ # Репозитории
|
||
├── migrations/ # Миграции goose, вшиты в бинарник через go:embed
|
||
└── data/
|
||
├── files/ # Директория для сохранения файлов
|
||
└── transcriber.db # SQLite база данных (создается автоматически)
|
||
```
|
||
|
||
## База данных
|
||
|
||
### Таблица `files`
|
||
- `id` (TEXT) - UUID файла
|
||
- `storage` (TEXT) - где лежит файл: `local` или `s3`
|
||
- `file_name` (TEXT) - имя файла в хранилище
|
||
- `size` (INTEGER) - размер файла в байтах
|
||
- `created_at` (DATETIME) - время создания
|
||
|
||
### Таблица `transcribe_jobs`
|
||
- `id` (TEXT) - UUID задачи
|
||
- `state` (TEXT) - состояние задачи
|
||
- `source` (TEXT) - откуда пришла задача: `api`, `telegram` или `unknown`
|
||
- `file_id` (TEXT) - ссылка на текущий файл задачи
|
||
- `delay_time` (DATETIME) - не брать задачу раньше этого времени
|
||
- `acquisition_id`, `acquire_time` - захват задачи воркером
|
||
- `recognition_op_id` (TEXT) - ID операции распознавания в Yandex Cloud
|
||
- `transcription_text` (TEXT) - результат распознавания
|
||
- `is_error` (BOOLEAN), `error_text` (TEXT) - признак и текст ошибки
|
||
- `tg_chat_id`, `tg_reply_message_id` - куда отправить результат в Telegram
|
||
- `created_at`, `updated_at` (DATETIME) - времена создания и обновления
|
||
|
||
## Разработка
|
||
|
||
Миграции накатываются автоматически при старте сервиса — они вшиты в бинарник
|
||
через `//go:embed`. Достаточно положить новый файл в `migrations/`.
|
||
|
||
Создать файл миграции и накатить или откатить её вручную:
|
||
|
||
```bash
|
||
# Создание новой миграции
|
||
goose -dir migrations create migration_name sql
|
||
|
||
# Применение миграций
|
||
goose -dir migrations sqlite3 data/transcriber.db up
|
||
|
||
# Откат миграций
|
||
goose -dir migrations sqlite3 data/transcriber.db down
|
||
```
|
||
|
||
Проверки перед коммитом:
|
||
|
||
```bash
|
||
go build ./...
|
||
go vet ./...
|
||
gofmt -l .
|
||
go test ./...
|
||
golangci-lint run
|
||
```
|