AWS Serverless транскрибатор аудио — SRS-сборка¶
Эта страница собирает разделы для спецификации требований к ПО: от контекста и проблемы до безопасности, качества и эксплуатации.
Содержание¶
- Краткое описание
- Контекст и проблема
- Цели, требования и ограничения
- Роль и обязанности
- Модель системы
- Архитектура и интеграции
- Безопасность, качество и эксплуатация
Краткое описание¶
Статус¶
В эксплуатации
Роль¶
Системный проектировщик
Стек¶
Python, AWS Lambda, API Gateway, DynamoDB, AWS S3, Terraform, LLM API integration
Ценность проекта¶
Для пользователя:
- быстрая транскрибация длинных аудиозаписей без загрузки в тяжёлые SaaS-сервисы;
- контролируемый доступ к результатам через Cognito и предподписанные ссылки;
- минимальные постоянные расходы за счёт serverless-модели.
Для профессионального профиля:
- практическое проектирование AWS serverless workflow;
- работа с асинхронной обработкой, webhook, polling UI и жизненным циклом задачи;
- применение Infrastructure-as-Code через Terraform;
- выбор решений исходя из эпизодической нагрузки и ограничений стоимости (cost-driven architecture).
Контекст и проблема¶
Контекст и предпосылки¶
Контекст и проблема¶
Есть периодическая потребность транскрибировать длинные аудиозаписи: интервью, рабочие обсуждения, созвоны, заметки и исследовательские материалы. Типовой файл может занимать 1.5+ часа и весить сотни мегабайт.
Готовые SaaS-сервисы закрывают задачу, но для личного/ограниченного сценария дают избыточный функционал, непрозрачную стоимость и лишний операционный контур: пользователь вручную загружает файл, ждёт обработку, скачивает результат и хранит его отдельно.
Проблема¶
Ключевая архитектурная проблема: транскрибация является долгой асинхронной операцией, а аудиофайлы слишком велики для прямой передачи через API Gateway/Lambda. Поэтому система должна разделить upload, запуск обработки, получение webhook, хранение результата и скачивание transcript.
Часть записей может содержать приватные сведения, поэтому важно ограничить доступ к интерфейсу, файлам и результатам. При этом передача аудио внешнему transcription provider остаётся осознанным компромиссом, принятым ради стоимости, качества и из-за отсутствия собственной GPU-инфраструктуры.
Цели, требования и ограничения¶
Цели и нецели¶
Основные цели проекта¶
- Реализовать оптимальную по стоимости транскрибацию аудиозаписей для личного использования
Что не входит в проект¶
- Не является общедоступной открытой системой
- Не является платной системой или монетизируемой платформой
Бизнес-требования¶
- BR-001. Сервис доступен через интернет.
- BR-002. Доступ ограничен авторизованными пользователями.
- BR-003. Система поддерживает транскрибацию длинных аудио.
- BR-004. Система поддерживает диаризацию.
- BR-005. Пользователь может скачать готовый транскрипт.
Функциональные требования¶
- FR-001. Пользователь получает presigned upload URL.
- FR-002. Система создаёт задачу транскрибации, актуальный статус которой пользователь может проверять без обновления страницы.
- FR-003. Система обновляет статус задачи по мере обработки.
- FR-004. UI отображает список job и текущий статус.
- FR-005. Пользователь получает предподписанную URL для готового транскрипта.
- FR-006. Обработчик Webhook принимает обратный вызов от провайдера транскрибации.
Constraints¶
- CON-001. Файлы до 300 MB.
- CON-002. Длительность записи до 6 часов.
- CON-003. До 5 файлов транскрибируются одновременно.
- CON-004. 1–3 пользователя.
- CON-005. Модель на собственных мощностях не рассматривается.
- CON-006. Постоянные инфраструктурные расходы должны быть минимальны.
Non-functional requirements¶
- NFR-001. Access control.
- NFR-002. Cost efficiency.
- NFR-003. Portability.
- NFR-004. Operability.
- NFR-005. Resilience of async workflow.
Требования (ФТ)¶
- BR-001. Доступность системы через интернет Система должна быть доступна с любого устройства, подключенного к сети интернет.
- BR-002. Доступ к системе должен быть ограничен Система должна обеспечивать авторизацию и аутентификацию пользователя. Регистрация новых пользователей не предполагается, но управление ими должно быть.
- BR-003. Поддержка диаризации Система должна поддерживать разделение стенограммы по говорящим.
- BR-004. форматы файлов. Система должна поддерживать наиболее распространенные форматы записей с диктофона - MP3, AAC.
Правила и Ограничения (НФТ)¶
-
CON-001. Регион размещения: для пользователей из Европы, Кавказа и Турции. AWS-регион с принципиальной доступностью. Низкая latency не является критичным требованием, так как основной сценарий асинхронный.
-
CON-002. Размер файла записи - до 300мб.
-
CON-003. Продолжительность одной записи - до 6 часов. Система должна стабильно работать на продолжитьельных записях.
-
CON-004. Итоговая стоимость транскрибации Стоимость минуты записи при 40 часах в месяц должна быть не более $0.3/минута с учетом расходов на инфраструктуру (расценка https://speech2text.ru/my/rate ).
-
CON-005. Обязательное ограничение доступа Можно ограничиться 1-2 учетными записями для личных целей.
-
CON-006. Запуск opensource модели транскрибации не предполагается Ввиду отсутствия доступного железа необходимого уровня, а также экономической нецелесообразности аренды такого обрудования.
-
CON-007. Переносимость решения Решение должно быть таким, чтобы его можно было легко поднять и при необходимости свернуть, если потребность в нём временно исчезла.
-
CON-008. Минимальные расходы на поддержание Решение должно требовать минимальные ресурсы для поддержки (установку обновлений безопасности и т.п.).
Роль и обязанности¶
Моя роль¶
Я выступал как системный проектировщик и технический владелец решения.
Моя работа включала:
- перевод личной потребности в требования, ограничения и архитектурную модель;
- выбор serverless-архитектуры с учётом эпизодической нагрузки и стоимости;
- проектирование асинронного процесса: upload -> запрос транскрибации -> webhook -> сохранение результата -> скачивание;
- проектирование модели состояний задачи транскрибации;
- выбор AWS-сервисов и границ ответственности между Lambda, S3, DynamoDB, API Gateway, Cognito и внешним провайдером транскрибации;
- описание sequence-диаграм и ADR;
- использование ИИ-инструментов поддержки разработки как ускорителя реализации при ручном контроле архитектуры, границ безопасности и deployment-решений.
Применение ИИ¶
Проект разрабатывался с использованием AI.
LLM применялись для ускорения реализации, генерации шаблонного кода и быстрых итераций. Ключевые решения оставались под ручным контролем:
- интерпретация требований;
- доменное моделирование;
- архитектурные решения;
- границы данных;
- модель доступа;
- код ревью;
- дебаг;
- решения по развертыванию;
- техническая документация.
Модель системы¶
Модель данных¶
TranscriptionJob¶
Основная сущность процесса транскрибации.
Атрибуты:
fileIdownerUserIdinputS3KeytranscriptS3KeystatusproviderTranscriptIdcreatedAtupdatedAterrorReasonspeakerModefileSizedurationEstimate
Системные инварианты¶
- job принадлежит одному пользователю;
- download URL выдаётся только владельцу job;
- transcript можно скачать только в статусе
READY; - webhook должен быть idempotent;
- повторный callback от provider не должен создавать новый transcript;
- failed job не должен блокировать список остальных job;
- presigned URLs имеют ограниченное время жизни.
DynamoDB - статусы джобов¶
Каждая задача транскрибации хранится как запись БД с жизненным циклом:
| State Machine | Значение |
|---|---|
UPLOADING | Выдана предподписанная ссылка; идёт загрузка клиентом |
TRANSMITTING | Аудио загружено в S3; отправка в сервис |
PROCESSING | сервис транскрибирует (transcript_id сохранён) |
READY | Транскрипт сохранён в S3; доступен для скачивания |
ERROR | Ошибка AssemblyAI или пайплайна (причина в логе) |
Amazon S3¶
- Bucket файлов: загрузки аудио и сгенерированные транскрипты (
Transcript.txt). - Bucket статического сайта: SPA, раздаётся через CloudFront.
API-контракты¶
API Gateway (аутентификация)¶
| Метод | Путь | Назначение |
|---|---|---|
GET | /upload-url | Создать запись; вернуть Presigned POST URL и fileId |
GET | /jobs | Список джобов пользователя (polling UI) |
GET | /download-url?fileId=... | Проверка доступа; Presigned GET URL транскрипта |
POST | /webhook | Callback AssemblyAI (transcript_id) |
Все маршруты API Gateway требуют JWT (Amazon Cognito), кроме /webhook (callback провайдера транскрибации).
Amazon Cognito (Hosted UI / PKCE)¶
| Метод | Путь | Назначение |
|---|---|---|
POST | /oauth2/token | Обмен authorization code на Access & ID tokens |
внешний API провайдера транскрибации¶
| Метод | Путь | Назначение |
|---|---|---|
POST | /v2/transcript | Отправка URL аудио + webhook URL; возвращает transcript_id |
GET | /v2/transcript/{id} | Получение готового текста транскрипции |
Amazon S3 (прямой доступ клиента)¶
| Метод | Цель | Назначение |
|---|---|---|
POST | Presigned POST URL | Прямая загрузка аудио (обход лимитов API Gateway) |
GET | Presigned GET URL | Прямое скачивание транскрипта |
Архитектура и интеграции¶
Архитектура¶
Архитектурная концепция¶
Система построена на событийной модели.
Статический frontend раздаётся через S3/CloudFront. Пользователь проходит аутентификацию через Cognito Hosted UI и вызывает API Gateway, используя полученный JWT. API Gateway маршрутизирует запросы в Lambda-функции.
Большие аудиофайлы не проходят через API Gateway и Lambda. Backend выдаёт предподписанную POST URL, после чего браузер загружает файл напрямую в S3. Событие S3 ObjectCreated запускает обработчик, который создаёт временный URL для провайдера транскрибации и отправляет запрос на новую транскрибацию. Внешний провайдер выполняет долгую транскрибацию асинхронно и возвращает результат через webhook. Итоговый текстовый транскрипт сохраняется в S3, а статус задачи изменяется и хранится в DynamoDB.
architecture-beta
service dynamo(aws:dynamodb)[AWS DynamoDB]
service lambda(aws:lambda)[AWS Lambda]
service api(aws:api-gateway)[AWS API Gateway]
service static(aws:simple-storage-service)[Static website at Amazon S3]
service storage(aws:simple-storage-service)[File storage at Amazon S3]
service browser(logos:chrome)[Browser]
service cognito(aws:cognito)[AWS Cognito]
service ai(logos:webhooks)[Transcriber API]
service front(aws:cloudfront)[AWS CloudFront]
front:T --> B:static
browser:T --> B:api
browser:L --> R:front
browser:B --> T:cognito
api:R --> L:lambda
api:T <-- B:ai
lambda:T --> R:ai
lambda:R --> L:dynamo
lambda:B --> T:storage
storage:L <-- R:browser Потоки интеграции¶
Диаграммы последовательности¶
Отправка файла аудио¶
sequenceDiagram
autonumber
actor U as Браузер (SPA)
participant API as API Gateway
participant L as AWS Lambda
participant S3 as Amazon S3
participant DB as DynamoDB
U->>API: GET /upload-url (+JWT в Header)
activate API
API->>L: Вызов get_upload_url
deactivate API
activate L
L->>DB: Создание записи (Status: UPLOADING)
L->>S3: Генерация Presigned POST URL
activate S3
S3-->>L: Ссылка для загрузки
deactivate S3
L-->>U: JSON: { uploadUrl, fileId }
deactivate L
Прямая загрузка и Асинхронный Триггер (Event-Driven)¶
sequenceDiagram
autonumber
actor U as Браузер (SPA)
participant L as AWS Lambda
participant S3 as Amazon S3
participant DB as DynamoDB
participant AI as TranscribeProvider
U->>S3: POST Загрузка аудио-файла (Обход API Gateway)
activate S3
S3-->>U: 204 No Content (Успех)
deactivate S3
S3-)L: Event: ObjectCreated (Асинхронный вызов s3_trigger)
activate L
L->>DB: Обновление статуса (TRANSMITTING)
L->>S3: Генерация временной GET Presigned URL для AI
L->>AI: POST /v2/transcript (Аудио URL + Webhook URL)
activate AI
alt TranscribeProvider принимает запрос
AI-->>L: 201 Created (transcript_id)
L->>DB: Status = PROCESSING (сохранение ID)
else Ошибка API (например, HTTP 400/500)
AI-->>L: 4xx / 5xx Error
deactivate AI
L->>DB: Status = ERROR (Запись причины в лог)
end
deactivate L
Обработка ИИ и Webhook (до нескольких минут)¶
sequenceDiagram
autonumber
actor U as Браузер (SPA)
participant API as API Gateway
participant L as AWS Lambda
participant S3 as Amazon S3
participant DB as DynamoDB
participant AI as TranscribeProvider
loop Каждые 15 секунд (Polling)
U->>API: GET /jobs
activate API
API->>L: Вызов get_jobs
deactivate API
activate L
L->>DB: Запрос списка файлов пользователя
activate DB
DB-->>L: Данные (Status: PROCESSING)
deactivate DB
L-->>U: Обновление UI
deactivate L
end
Note over AI, DB: TranscribeProvider завершает работу
AI->>API: POST /webhook (передача transcript_id)
activate API
API->>L: Вызов webhook_TranscribeProvider
deactivate API
activate L
L->>AI: GET /v2/transcript/{id}
activate AI
AI-->>L: Готовый текст транскрипции
deactivate AI
L->>S3: PUT Сохранение текста (Transcript.txt)
L->>DB: Обновление статуса (READY)
deactivate L
Получение результата (Скачивание)¶
sequenceDiagram
autonumber
actor U as Браузер (SPA)
participant API as API Gateway
participant L as AWS Lambda
participant S3 as Amazon S3
participant DB as DynamoDB
U->>API: GET /jobs (Очередной опрос)
activate API
API-->>U: Status: READY (Кнопка скачивания активна)
deactivate API
U->>API: GET /download-url?fileId=...
activate API
API->>L: Вызов get_download_url
deactivate API
activate L
L->>DB: Проверка прав доступа пользователя к файлу
L->>S3: Генерация Presigned GET URL (с Content-Disposition)
L-->>U: JSON: { downloadUrl }
deactivate L
U->>S3: Прямое скачивание текста.txt
activate S3
S3-->>U: Файл транскрипции
deactivate S3 Безопасность, качество и эксплуатация¶
Модель безопасности и доступа¶
| Зона | Риск | Контроль |
|---|---|---|
| Authentication | доступ постороннего пользователя | Cognito Hosted UI, JWT validation |
| Authorization | скачивание чужого transcript | owner check в DynamoDB перед выдачей presigned GET URL |
| Upload | загрузка слишком большого/неподдерживаемого файла | client-side и backend-side validation, content-type/size constraints |
| S3 access | прямой публичный доступ к файлам | private buckets, presigned URLs only |
| Webhook | поддельный callback | shared secret / provider verification |
| Secrets | утечка provider API key | Secrets Manager / encrypted env, no secrets in code |
| Logs | попадание приватных данных в logs | не логировать transcript/audio content, только status/error metadata |
| Cost abuse | массовый запуск дорогих job | ограничение пользователей, quotas, AWS budget alerts |
Требования к доступу¶
- Необходимо обеспечить ограничение доступа к сервису.
- Необходимо обеспечить разделение пользовательских данных.
Аутентификация - AWS Cognito¶
- Разделение пользовательских данных: AWS Cognito - встроенный менеджмент учётных записей, регистрация, 2FA, защита от брутфорса и т.п. Сервис бесшовно встроен в экосистему AWS.
- Проверка прав пользователя на файл при скачивании (
get_download_urlпроверяет доступ в DynamoDB перед выдачей Presigned URL).
Аутентификация¶
sequenceDiagram
autonumber
actor U as Браузер (SPA)
participant API as API Gateway
participant C as Amazon Cognito
U->>API: Запрос к API (без JWT / протухший JWT)
activate API
API-->>U: 401 Unauthorized
deactivate API
U->>U: SPA очищает локальные данные
U->>C: Редирект на Hosted UI форму логина
activate C
C->>U: Форма логина
deactivate C
U->>C: Ввод данных и попытка аутентификации
activate C
alt Некорректные реквизиты
C-->>U: Возврат ошибки (Invalid credentials)
else Корректные реквизиты
C-->>U: Возврат Auth Code (через redirect_uri)
deactivate C
U->>C: POST /oauth2/token (Обмен Code на JWT)
activate C
C-->>U: Access & ID Tokens
deactivate C
end Режимы отказа¶
| Режим отказа | Последствие | Обнаружение | Митигация / восстановление |
|---|---|---|---|
| Lambda timeout при синхронной транскрибации | job не завершается | логи Lambda | async workflow + webhook |
| Ошибка provider API 4xx/5xx | job переходит в ERROR | логи провайдера | сохранить reason, показать статус пользователю |
| Webhook не пришёл | задача зависает в PROCESSING | UI | попытка перезапуска через новую задачу |
| Повторный webhook | возможная перезапись результата | двойной коллбэк | идемпотентная запись через transcriptId |
| Пользователь пытается скачать чужой transcript | утечка данных | проверка прав не пройдена | проверка владельца перед выдачей предподписанной URL |
| Presigned URL истёк | пользователь не может загрузить/скачать файл | ошибка на клиенте | сгенерировать новую предподписанную URL |
| S3 upload не завершился | задача остаётся в UPLOADING | зависший UPLOADING статус | TTL очистка / повторная попытка загрузки |
| Утечка API key | несанкционированные расходы | AWS уведомления о превышении квот | ротация ключей, сброс квот, ограничение бюджета на счету провайдера транскрибации + выключение овердрафта |
| Рост стоимости из-за массовых задач | неожиданный счет | AWS Budgets / CloudWatch | квоты, лимит на одновременность, ограничение бюджета на счету провайдера транскрибации + выключение овердрафта |
| Транскрипт сохранён, но статус не обновлён | UI не показывает готовый результат | UI не показывает готовый результат | проверка целостности / дебаг логики задач |
Оценка масштаба и стоимости¶
Предполагаемая нагрузка¶
| Параметр | Значение |
|---|---|
| Пользователи | 1–3 |
| Аудио в месяц | до 40 часов |
| Средняя длина файла | 1.5+ часа |
| Максимальная длина файла | 6 часов |
| Максимальный размер файла | 300 MB |
| Параллельные job | до 5 |
Драйверы стоимости¶
| Компонент | Что влияет на стоимость |
|---|---|
| Transcription provider | минуты/часы аудио |
| S3 | объём аудио и transcript files |
| DynamoDB | количество job/status reads |
| Lambda | количество invocation и длительность handlers |
| API Gateway | количество API-запросов |
| CloudFront/S3 static hosting | frontend traffic |
| Secrets Manager | хранение provider API key |
| CloudWatch | logs retention |
Логика расчета стоимости¶
Основная стоимость находится не в AWS compute, а во внешнем transcription provider. AWS Lambda, API Gateway, DynamoDB и S3 при заданном профиле нагрузки остаются вторичными cost drivers. Поэтому архитектура оптимизирована не под высокую нагрузку, а под минимальные постоянные расходы и отсутствие простаивающей инфраструктуры.