Перейти к содержанию

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

Основная сущность процесса транскрибации.

Атрибуты:

  • fileId
  • ownerUserId
  • inputS3Key
  • transcriptS3Key
  • status
  • providerTranscriptId
  • createdAt
  • updatedAt
  • errorReason
  • speakerMode
  • fileSize
  • durationEstimate

Системные инварианты

  • 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 представлены лишь частично в демонстрационных целях