AWS Serverless транскрибатор аудио — архитектурное ревью¶
Эта страница собирает разделы для архитектурного ревью: цели, требования и ограничения; модель системы; архитектура и интеграции; безопасность, качество и эксплуатация; решения, компромиссы и риски.
Содержание¶
- Краткое описание
- Цели, требования и ограничения
- Модель системы
- Архитектура и интеграции
- Безопасность, качество и эксплуатация
- Решения, компромиссы и риски
Краткое описание¶
Статус¶
В эксплуатации
Роль¶
Системный проектировщик
Стек¶
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).
Цели, требования и ограничения¶
Цели и нецели¶
Основные цели проекта¶
- Реализовать оптимальную по стоимости транскрибацию аудиозаписей для личного использования
Что не входит в проект¶
- Не является общедоступной открытой системой
- Не является платной системой или монетизируемой платформой
Бизнес-требования¶
- 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. Минимальные расходы на поддержание Решение должно требовать минимальные ресурсы для поддержки (установку обновлений безопасности и т.п.).
Модель системы¶
Модель данных¶
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. Поэтому архитектура оптимизирована не под высокую нагрузку, а под минимальные постоянные расходы и отсутствие простаивающей инфраструктуры.
Решения, компромиссы и риски¶
Ключевые решения¶
Полноценная событийная модель¶
Необходимо учесть, что процесс транскрибаци продолжителен во времени, которое может превысить время работы Lambda-функции. * Решение: Внедрить событийную модель. Развязать по времени отправку аудио-файла и получение текстового результата. Необходимо найти такого провайдера транскрибации, который предоставит функциональность уведомления по webhook.
Работа с 300мб файлами¶
Необходимо учесть, что объем файлов может превосходить ограничения API Gateway и будут увеличивать время работы Lambda-функций. * Решение: Использовать функциональность предподписанных ссылок (Presigned URL), которую предлагает Amazon S3 из коробки. Это позволит обращаться клиенту напрямую к S3 в обход API Gateway и Lambda.
Архитектурные компромиссы (ADR)¶
1. Оптимальный архитектурный стиль¶
Контекст¶
Необходимо учесть эпизодический характер использования инструмента, небольшое количество сценариев использования, широкую зону доступности и при этом жесткие требования к себестоимости инфраструктуры и поддержки.
Принятое Решение¶
Использовать Serverless подход и инфраструктуру AWS Lambda.
Отклонённая альтернатива¶
VPS, Telegram bot
Обоснование¶
-
Lambda-функции оплачиваются за время запуска, при эпизодическом запуске вполне могут уместиться в Free-tier (1 млн.запросов или 400Тб-с в месяц), т.е. бизнес-логика при заданных условиях бесплатна. Также в AWS Lambda безопасность инфраструктуры обеспечивается на стороне Amazon, что исключает расходы на поддержку.
-
VPS требуют периодической оплаты мощностей (даже когда сервис не используется это может быть $3-7 в месяц), а также требуют ресурсы на поддержание требуемого уровня безопасности (установка обновлений безопасности ОС, свежих пакетов и т.п.).
-
Telegram bot ка кканал достаточно удобен, но не подойдет по причине ограничений на размер аудио-файла (50Мб) + не отменяет необходимости где-то размещать логику бота (VPS со всеми вытекающими).
Компромиссы¶
- Serverless-подход требует более тщательного проектирования, максимального выноса тяжелых операций за пределы функций (presigned URL в S3). Требование к стабильности функций должно быть повышено. Необходимо обеспечить установку квот на запуск и уведомлений по размеру расходов.
- Serverless сложнее дебажить.
2. Оптимальная инфраструктура транскрибации¶
Контекст¶
Необходимо учесть, что бюджет для запуска opensource модели на своих мощностях не предполагается.
Принятое Решение¶
Использовать сторонний API-сервис транскрибации.
Отклонённая альтернатива¶
Локально запущенная opensource модель, арендованное оборудование под запуск opensource-модели.
Обоснование¶
-
Сторонний API-сервис транскрибации работает быстро, не требует обслуживания. Оптимальным по соотношению качество/цена был выбран AssemblyAI - $0.15 в час. Стоимость минуты составит $0.0025 при условии использования облака Amazon и serverless-подхода, что в 120 раз меньше требуемого. Ограничение на 5 одновременных процессов транскрибации также выполняется.
-
Для локального запуска модели нет доступного железа (минимальные требования - 16Гб RAM и 8Гб видео памяти на внешней GPU). Приобретение дополнительного железа не входит в парадигму digital nomad.
-
Аренда совместимого оборудования будет стоить $5-10 в месяц при почасовой оплате, потребует отдельных ресурсов на развертывание решения, запуск, обеспечение безопасности (установка обновлений безопасности). Постоянная работа такого обордования обойдется в $40-60 в месяц. Решение неоптимально.
Компромиссы¶
-
запись отдается стороннему сервису, запрос на приватность решения не выполняется. Согласовано с заказчиком.
-
сторонний сервис может поменять расценки, может закрыться.
-
нужно безопасно хранить секреты (API-key). Хранить в коде небезопасно и плохой тон. Услуга хранения секрета в AWS Secret Manager стоит $0.40 в месяц + $0.05 за каждые 10000 запросов - это необходимо заложить в итоговую себестоимость минуты транскрибации.
3. Разделение пользовательских данных¶
Контекст¶
Необходимо учесть требование к ограничению доступа и разделению данных, а также чтобы сервисом могли пользоваться несколько пользователей, но вместе с тем без открытой регистрации.
Принятое Решение¶
AWS Cognito
Отклонённая альтернатива¶
Парольная защита статической страницы HTML
Обоснование¶
-
AWS Cognito - в него встроен менеджмент учетных записей, возможность регистрации, 2FA, защита от брутфорса и т.п. Сервис бесшовно встроен в экосистему AWS. Потребности проекта вписываются в Free-tier (<10 000 MAU).
-
Парольная защита HTML - слабо адаптирована к брутфорсу, смена пароля через изменение кода - что не является лучшей практикой. Нет возможности разделить доступ между несколькими пользователями.
-
Своя система менеджмента доступа - оверинжениринг поверх одного бизнес-процесса.
Компромиссы¶
- Условия Free-tier могут измениться и функциональность менеджмента пользователей может стать платной. Необходимо будет пересмотреть стоимость решения.
... Ключевые ADR представлены лишь частично в демонстрационных целях