/laravel-api

Laravel API to synthesize text with Yandex SpeechKit API

Primary LanguagePHP

Laravel API для озвучки текста через Yandex SpeechKit API

Было сделано:

  • Создано API приложение на фреймворке Laravel (v7.13.0) со следующими точками входа:
    • GET /article: Получение списка статей
    • GET /article/{ID}: Получение статьи по {ID}
    • POST /article: Отправка статьи для преобразования текста в звук
    • PUT /article/{ID}: Обновление информации о статье по {ID}
    • DELETE /article/{ID}: Удаление статьи с {ID} и звука к ней
  • В корне репозитория добавлен файл [4fresh Laravel API.postman_collection.json](4fresh Laravel API.postman_collection.json) для импорта в Postman и проверки точек входа API.
  • Реализован механизм очередей при помощи базы данных https://laravel.com/docs/7.x/queues . После того как статья добавлена, она помещается в очередь на преобразование в звук.
  • Синтезирование звуковых файлов производится с помощью Yandex SpeechKit API
  • Полученные звуковые файлы хранятся в Yandex Object Storage: https://cloud.yandex.ru/docs/storage/quickstart
  • API приложение хостится на Heroku: https://immense-refuge-94796.herokuapp.com/ Сюда же настроен автоматический деплой при коммите в master ветку данного репозитория.
  • Написаны тесты (директория tests):
    • Unit тест, который тестирует, что статья успешно сохраняется в базу данных
    • функциональные тесты, которые тестируют точки входа POST /article и GET /article, GET /article/{ID}
  • При получении информации о статье с успешно синтезированным звуком через API в атрибуте speechUrl передается ссылка, по которой можно прослушать звук (например, http://synthesizetext.storage.yandexcloud.net/synthesize/7.ogg)
  • Логируются этапы обработки созданных статей от момента записи в базу данных до получение звука или ошибки. Для этой цели были созданы следющие статусы (записываются в таблицу articles.status).

Как это работает? Как проверить?

  1. Импортировать файл 4fresh Laravel API.postman_collection.json в Postman
  2. Загрузить статью на обработку через Postman: точка входа "Добавить статью"
  3. Если статья успешно загружена, то она добавляется в очередь на отправку для преобразования в звуковой файл.
  4. Как только очередь дошла до данной статьи, то она отправляется в Yandex SpeechKit API и мы ждем ответа от сервера.
  5. Если сервер возвращает файл, то мы его сохраняем в Yandex Object Storage. Статье ставится статус = 4. Теперь API для данной статьи будет возвращать в том числе и ссылку на прослушивание данного звука.

Специфические настройки и статусы (при самостоятельно развертывании)

Env Variables

Помимо основных переменных, которые используются в Laravel, необходимо также добавить в .env следующие переменные:

YANDEX_OAUTH_TOKEN=
YANDEX_CLOUD_FOLDER_ID=

YANDEX_CLOUD_ACCESS_KEY_ID=
YANDEX_CLOUD_SECRET_ACCESS_KEY=
YANDEX_CLOUD_DEFAULT_REGION=us-east-1
YANDEX_CLOUD_BUCKET=

LOGGING_HEROKU_SINGLE=errorlog

Получить YANDEX_OAUTH_TOKEN можно по следующей ссылке: https://cloud.yandex.ru/docs/iam/operations/iam-token/create Введите идентификатор каталога YANDEX_CLOUD_FOLDER_ID, в котором будут синтезироваться звуковые файлы на странице: https://console.cloud.yandex.ru/

Для хранения синтезированных звуковых файлов выбрано хранилище Yandex Object Storage: https://cloud.yandex.ru/docs/storage/quickstart Необходимо создать бакет для хранения файлов и внести данные этого бакета в переменные:

YANDEX_CLOUD_ACCESS_KEY_ID=
YANDEX_CLOUD_SECRET_ACCESS_KEY=
YANDEX_CLOUD_DEFAULT_REGION=us-east-1
YANDEX_CLOUD_BUCKET=

Следующая переменная используется только на хостинге Heroku для просмотра лога через консоль:

LOGGING_HEROKU_SINGLE=errorlog

Env Testing

Для проведения теста используется друга база данных. Ее надо создать и прописать в файле .env.testing переменные для данной БД. Например:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_api_testing
DB_USERNAME=root
DB_PASSWORD=

Остальные значения переменных можно взять из .env файла

Article Statuses

  • STATUS_CREATED = 1; => статья сохранена в БД
  • STATUS_QUEUED = 2; => статья добавлена в очередь на отправку преобразования текста
  • STATUS_SYNTHESIZE_STARTED = 3; => текст статьи отправлен на обработку преобразования текста
  • STATUS_SUCCESS_SYNTHESIZED = 4; => текст успешно преобразован в звук и сохранен в Yandex Object Storage
  • STATUS_FAILED_SYNTHESIZED = 5; => произолша ошибка при преобразовании текста в звук

To Do

Как сделать так, чтобы озвучить больше 5000 знаков?

  • Снимаем ограничение по сохранению статьи, где body больше 5000 символов.
  • При обработке текста статьи разбиваем текст на порции, не превышающие 5000 символов с помощью подобной функции:
$parts = str_split($this->article->body, 5000);

$parts - массив порций длинного текста. Каждый элемент данного массива не превышает длину в 5000 символов.

  • После этого в цикле foreach "пробегаем" по массиву $parts и для каждого элемента массива синтезируем звуковой файл со следующим именем: "{$this->article->id}_{$key}.wav". Например, если мы работаем со статьей с ID=4 и длиной body = 18000 символов, то в результате синтезирования частей текста мы получим следующие файлы в Yandex Storage: 4_0.wav, 4_1.wav, 4_2.wav, 4_3.wav. Сохранение в формат WAV делаем по следующей инструкции: https://cloud.yandex.ru/docs/speechkit/tts/request#wav с помощью утилиты SoX
  • далее предлагаю 2 варианта:

Объединить полученные файлы в один (смержить)

После того, как все файлы для каждой из частей текста созданы, нам необходимо объединить все полученные файлы в один (смержить). Для этого мы можем запустить следующую консольную команду с помощью той же утилиты SoX, как описано в следующем комментарии: https://superuser.com/a/64260. Для нашего случая это будет выглядеть примерно так:

sox 4_0.wav 4_1.wav 4_2.wav 4_3.wav 4.ogg

Альтернативный вариант

Если с объединением файлов в один будут какие-то проблемы, то также можно предложить вариант проигрывателя озвученного текста статьи в виде плеера с плейлистом. Элементы данного плейлиста - файлы 4_0.wav, 4_1.wav, 4_2.wav, 4_3.wav