umbot
Version:
Мультиплатформенный фреймворк для создания голосовых навыков и чат-ботов с единой бизнес-логикой. Встроенная поддержка ВКонтакте, Telegram, Viber, MAX, Яндекс Алисы, Маруси и Сбера SmartApp. Архитектура на адаптерах позволяет подключать любые другие платф
177 lines (176 loc) • 8.74 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.YandexSoundRequest = void 0;
const YandexRequest_1 = require("./YandexRequest");
const index_1 = require("../../../index");
const path_1 = __importDefault(require("path"));
const ALLOWED_AUDIO_EXT = ['.mp3', '.ogg', '.opus', '.wav', '.m4a', '.aac'];
/**
* Адрес, на который будет отправляться запрос
*/
const STANDARD_URL = 'https://dialogs.yandex.net/api/v1/';
/**
* Класс, отвечающий за загрузку аудиофайлов в навык Алисы
* @see https://yandex.ru/dev/dialogs/alice/doc/resource-sounds-upload-docpage/ Документация API Яндекс.Диалогов
*
* @class YandexSoundRequest
*/
class YandexSoundRequest extends YandexRequest_1.YandexRequest {
/**
* Идентификатор навыка, необходимый для корректного сохранения аудиофайлов
* @see YandexRequest Базовый класс для работы с API Яндекса
*/
skillId;
/**
* Создает экземпляр класса для работы с аудиофайлами в навыке Алисы
* @param oauth Авторизационный токен для загрузки аудиофайлов
* @param skillId Идентификатор навыка
* @param appContext Контекст приложения
* @see https://tech.yandex.ru/dialogs/alice/doc/resource-upload-docpage/ Документация по загрузке ресурсов
* @see https://oauth.yandex.ru/verification_code Получение OAuth-токена
*/
constructor(oauth = null, skillId = null, appContext) {
super(oauth, appContext);
this.skillId = skillId || null;
this._request.url = STANDARD_URL;
}
/**
* Получение адреса для загрузки аудиофайлов.
*
* @return string
*/
#getSoundsUrl() {
return `${STANDARD_URL}skills/${this.skillId}/sounds`;
}
/**
* Проверка занятого места в хранилище аудиофайлов
* @returns {Promise<IYandexCheckOutPlace | null>} Информация о занятом месте:
* - total: общий доступный объем хранилища
* - used: использованный объем хранилища
* @remarks Для каждого аккаунта действует лимит в 1 ГБ. Учитывается размер сжатых файлов в формате OPUS
*/
async checkOutPlace() {
this._request.url = STANDARD_URL + 'status';
const query = await this.call();
if (query?.sounds?.quota !== undefined) {
return query.sounds.quota;
}
this._log('checkOutPlace() Не удалось проверить занятое место под аудиофайлы.');
return null;
}
/**
* Загрузка аудиофайла с сервера
* @param soundDir Путь к аудиофайлу на сервере
* @returns {Promise<IYandexRequestDownloadSound | null>} Информация о загруженном аудиофайле:
* - id: уникальный идентификатор файла
* - skillId: идентификатор навыка
* - size: размер файла в байтах
* - originalName: оригинальное имя файла
* - createdAt: дата и время загрузки
* - isProcessed: статус обработки файла
* - error: сообщение об ошибке (если есть)
*/
async downloadSoundFile(soundDir) {
if (this.skillId) {
const ext = path_1.default.extname(soundDir).toLowerCase();
if (!ALLOWED_AUDIO_EXT.includes(ext)) {
this._log(`downloadSoundFile() Недопустимый тип файла: ${ext}. Ожидаются аудиофайлы.`);
return null;
}
this._request.url = this.#getSoundsUrl();
this._request.header = index_1.Request.HEADER_FORM_DATA;
this._request.attach = soundDir;
const query = await this.call();
if (query?.sound?.id === undefined) {
this._log(`downloadSoundFile() Не удалось загрузить аудио по пути "${soundDir}".`);
}
else {
return query.sound;
}
}
else {
this._log('downloadSoundFile() Не указан навык, в который необходимо загрузить аудио.');
}
return null;
}
/**
* Получение списка всех загруженных аудиофайлов
* @returns {Promise<IYandexRequestDownloadSound[] | null>} Массив с информацией о загруженных аудиофайлах
*/
async getLoadedSounds() {
if (this.skillId) {
this._request.url = this.#getSoundsUrl();
const query = await this.call();
return query?.sounds || null;
}
else {
this._log('getLoadedSounds() Не указан навык, у которого необходимо получить все загруженные аудиофайлы.');
}
return null;
}
/**
* Удаление конкретного аудиофайла по его идентификатору
* @param soundId Идентификатор аудиофайла для удаления
* @returns {Promise<string | null>} 'ok' при успешном удалении, null при ошибке
*/
async deleteSound(soundId) {
if (this.skillId) {
if (soundId) {
this._request.url = `${this.#getSoundsUrl()}/${soundId}`;
this._request.customRequest = 'DELETE';
const query = await this.call();
this._request.customRequest = null;
if (query?.result === undefined) {
this._log('deleteSound() Не удалось удалить аудиофайл.');
}
else {
return query.result;
}
}
else {
this._log('deleteSound() Не выбрано аудио для удаления.');
}
}
else {
this._log('deleteSound() Не указан навык, в котором необходимо удалить аудио.');
}
return null;
}
/**
* Удаление всех загруженных аудиофайлов
* @returns {Promise<boolean>} true если все файлы успешно удалены, false при ошибке
* @remarks Если при удалении произойдет ошибка, некоторые файлы могут остаться в хранилище
*/
async deleteSounds() {
if (this.skillId) {
const sounds = await this.getLoadedSounds();
if (sounds) {
const results = await Promise.allSettled(sounds.map(async (image) => {
try {
await this.deleteSound(image.id);
// Добавить задержку между запросами
await new Promise((resolve) => setTimeout(resolve, 200).unref());
return true;
}
catch (e) {
this._log(`deleteSounds() Ошибка при удалении аудио "${image.id}": ${e}`);
return false;
}
}));
// Если хотя бы один аудиофайл не удалено — вернуть false
return results.every((r) => r.status === 'fulfilled' && r.value);
}
else {
this._log('deleteSounds() Не удалось получить загруженные аудиофайлы!');
}
}
else {
this._log('deleteSounds() Не указан навык, в котором необходимо удалить аудиофайлы.');
}
return false;
}
}
exports.YandexSoundRequest = YandexSoundRequest;