- паспорт: сервис объявлен архивом с бессрочным хранением записей и текстов, машинная вычитка расшифровки внутри границ, приложение — основной вход; добавлены две границы: не файловое хранилище общего назначения и не биллинг; - заведены цели upload-reliability, user-settings, usage-stats и тринадцать задач; очередь пересобрана — сперва починки, затем разведки о хранилище, затем доступ и владелец, и только потом экраны; - архитектура: четыре новых открытых вопроса — приём большого файла, учёт расхода, срок хранения, потолок шести часов.
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
Установка и запуск
- Клонируйте репозиторий
- Установите зависимости:
go mod tidy - Скопируйте образец конфига и заполните его:
cp config.dist.toml config.toml - Запустите приложение:
go run . -c config.toml
Сервер запустится на порту из [server] port, по умолчанию 8080. Нужен
установленный ffmpeg.
Белый список Telegram
Бот отвечает только тем, кто перечислен в [server] users_while_list. В
config.dist.toml этого ключа нет — добавьте его сами:
[server]
users_while_list = ["@username"]
Значения сверяются со строкой автора сообщения из Telegram (@username либо имя
с фамилией), а не с числовым id.
Деплой
Деплой запускается из pet-project-server:
inv pl -- transcriber
Плейбук сам зовёт task image (контракт роли app_image): образ собирается
локально и едет на сервер через docker save/load, реестр не участвует.
Локально образ можно собрать и руками — task image даст transcriber:dev.
API Endpoints
POST /api/audio
Загружает аудиофайл и создает задачу на расшифровку. Отвечает 201 Created.
Параметры:
audio(form-data) - аудиофайл для расшифровки
Пример запроса:
curl -X POST \
http://localhost:8080/api/audio \
-F "audio=@/path/to/your/audio.mp3"
Ответ:
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "created"
}
GET /api/status/:id
Получает статус задачи расшифровки по ID. Поле transcription_text появляется,
когда задача перешла в done.
Пример запроса:
curl http://localhost:8080/api/status/550e8400-e29b-41d4-a716-446655440000
Ответ:
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "done",
"created_at": "2024-01-01T12:00:00Z",
"transcription_text": "расшифрованный текст"
}
GET /metrics
Метрики Prometheus с префиксом transcriber_.
GET /health
Проверка работоспособности сервиса.
Ответ:
{
"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илиs3file_name(TEXT) - имя файла в хранилищеsize(INTEGER) - размер файла в байтахcreated_at(DATETIME) - время создания
Таблица transcribe_jobs
id(TEXT) - UUID задачиstate(TEXT) - состояние задачиsource(TEXT) - откуда пришла задача:api,telegramилиunknownfile_id(TEXT) - ссылка на текущий файл задачиdelay_time(DATETIME) - не брать задачу раньше этого времениacquisition_id,acquire_time- захват задачи воркеромrecognition_op_id(TEXT) - ID операции распознавания в Yandex Cloudtranscription_text(TEXT) - результат распознаванияis_error(BOOLEAN),error_text(TEXT) - признак и текст ошибкиtg_chat_id,tg_reply_message_id- куда отправить результат в Telegramcreated_at,updated_at(DATETIME) - времена создания и обновления
Разработка
Миграции накатываются автоматически при старте сервиса — они вшиты в бинарник
через //go:embed. Достаточно положить новый файл в migrations/.
Создать файл миграции и накатить или откатить её вручную:
# Создание новой миграции
goose -dir migrations create migration_name sql
# Применение миграций
goose -dir migrations sqlite3 data/transcriber.db up
# Откат миграций
goose -dir migrations sqlite3 data/transcriber.db down
Проверки перед коммитом:
go build ./...
go vet ./...
gofmt -l .
go test ./...
golangci-lint run