# 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 ```