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
).
Как это работает? Как проверить?
- Импортировать файл
4fresh Laravel API.postman_collection.json
в Postman - Загрузить статью на обработку через Postman: точка входа "Добавить статью"
- Если статья успешно загружена, то она добавляется в очередь на отправку для преобразования в звуковой файл.
- Как только очередь дошла до данной статьи, то она отправляется в Yandex SpeechKit API и мы ждем ответа от сервера.
- Если сервер возвращает файл, то мы его сохраняем в 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 StorageSTATUS_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