UNPKG

umbot

Version:

Мультиплатформенный фреймворк для создания голосовых навыков и чат-ботов с единой бизнес-логикой. Встроенная поддержка ВКонтакте, Telegram, Viber, MAX, Яндекс Алисы, Маруси и Сбера SmartApp. Архитектура на адаптерах позволяет подключать любые другие платф

236 lines (235 loc) 9.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getImageToken = getImageToken; exports.getSoundToken = getSoundToken; exports.getPause = getPause; exports.replaceSound = replaceSound; exports.removeSound = removeSound; exports.defaultSoundProcessing = defaultSoundProcessing; exports.initUserCommand = initUserCommand; exports.getCorrectButtons = getCorrectButtons; exports.tryParse = tryParse; const models_1 = require("../../../models"); const utils_1 = require("../../../utils"); /** * Возвращает токен для изображения. * В случае, если найти токен в базе не удалось, отрабатывает обработчик, который отправляет запрос на получение токена. * @param path Путь до изображения * @param platform Платформа для которой нужно получить токен * @param controller Контроллер приложения * @param cb Обработчик, который вернет токен. */ async function getImageToken(path, platform, controller, cb) { if (path) { const model = new models_1.ImageTokens(controller.appContext); model.platform = platform; model.path = path; const query = await model.whereOne({ platform, path, }); if (query && model.imageToken) { return model.imageToken; } return cb(model); } return null; } /** * Возвращает токен для аудио. * В случае, если найти токен в базе не удалось, отрабатывает обработчик, который отправляет запрос на получение токена. * @param path Путь до аудиофайла * @param platform Платформа для которой нужно получить токен * @param controller Контроллер приложения * @param cb Обработчик, который вернет токен. */ async function getSoundToken(path, platform, controller, cb) { if (path) { const model = new models_1.SoundTokens(controller.appContext); model.platform = platform; model.path = path; const query = await model.whereOne({ platform, path, }); if (query && model.soundToken) { return model.soundToken; } return cb(model); } return null; } const PAUSE_REG = /#pause_<\[(\d+)]>#/g; /** * Ищет в запросе команду для паузы, и заменяет ее на корректный вид(sil). * * @param {string} text - Текст, который будет озвучен пользователю * @returns {string} - Строка с паузой в формате sil <[ms]> */ function getPause(text) { return text.replace(PAUSE_REG, (_, ms) => `sil <[${ms}]>`); } /** * Заменяет звуковой токен в тексте на соответствующий звук * * @param {string} key - Ключ звука для замены * @param {string | string[]} value - Значение или массив значений для замены * @param {string} text - Исходный текст * @returns {string} - Текст с замененными звуками * * @example * ```ts * // Замена одиночного звука * const text = replaceSound( * '#game_win#', * '<speaker audio="alice-sounds-game-win-1.opus">', * 'Поздравляем #game_win# с победой!' * ); * * // Замена на массив звуков * const text = replaceSound( * '#nature_rain#', * [ * '<speaker audio="alice-sounds-nature-rain-1.opus">', * '<speaker audio="alice-sounds-nature-rain-2.opus">' * ], * 'На улице #nature_rain# идет дождь' * ); * ``` */ function replaceSound(key, value, text) { if (text.includes(key)) { return utils_1.Text.textReplace(key, value, text); } return text; } /** * Удаляет все звуковые токены из текста * * @param {string} text - Исходный текст * @returns {string} - Текст без звуковых токенов * * @example * ```ts * // Удаление звуковых токенов * const text = removeSound('Текст #game_win# без #nature_rain# звуков'); * // Результат: 'Текст без звуков' * ``` */ function removeSound(text) { if (text.includes('speaker') || text.includes('sil')) { return text.replace(/<speaker[^>]*>|sil\s*<\[\d+]>/gi, ''); } return text; } /** * Базовый метод для обработки tts. * Основная задача метода - найти все ключи в запросе, и заменить их на корректные звуки/эффекты. * По умолчанию используется в Алисе и Марусе. * @param soundInfo - Информация необходимая для обработки аудио * @param defaultSounds - Стандартные звуки * @param defaultEffects - Стандартные эффекты */ /** * Базовый метод для обработки tts. * Основная задача метода - найти все ключи в запросе, и заменить их на корректные звуки/эффекты. * По умолчанию используется в Алисе и Марусе. * @param soundInfo - Информация необходимая для обработки аудио * @param defaultSounds - Стандартные звуки * @param defaultEffects - Стандартные эффекты */ function defaultSoundProcessing(soundInfo, defaultSounds, defaultEffects) { let updSounds = []; if (soundInfo.sounds.length) { updSounds = [...soundInfo.sounds, ...(soundInfo.usedStandardSound ? defaultSounds : [])]; } else if (soundInfo.usedStandardSound) { updSounds = defaultSounds; } // Если в тексте нет "#", и никто не задал свои звуки, // то считаем что звук никто не вставляет, поэтому доп обработка не требуется. // По-хорошему, всегда стоит смотреть на наличие #, и при ее отсутствии не выполнять ничего, но могут быть места, где ключ может сильно отличаться. const usedSoundEffect = soundInfo.text.includes('#'); if (usedSoundEffect) { if (defaultEffects) { defaultEffects.forEach((item) => { soundInfo.text = soundInfo.text.replace(new RegExp(item.key, 'g'), item.effect); }); } soundInfo.text = getPause(soundInfo.text); } else if (!soundInfo.sounds.length) { return soundInfo.text; } let res = soundInfo.text; if (updSounds.length) { for (let i = 0; i < updSounds.length; i++) { const sound = updSounds[i]; if (typeof sound === 'object' && sound.sounds !== undefined && sound.key !== undefined) { const sText = utils_1.Text.getText(sound.sounds); if (sText) { res = replaceSound(sound.key, sText, res); } } } } return res; } /** * Базовая функция, которая инициализирует команду пользователя. * Обрабатывает различные типы запросов и сохраняет команду в контроллере * @param request Объект запроса от пользователя * @param controller Контроллер приложения */ function initUserCommand(request, controller) { if (request.type === 'SimpleUtterance') { controller.userCommand = request.command?.trim() || ''; controller.originalUserCommand = request.original_utterance.trim() || ''; } else { if (typeof request.payload === 'string') { controller.userCommand = request.payload; controller.originalUserCommand = request.payload; } else { controller.userCommand = request.command?.trim() || ''; controller.originalUserCommand = request.original_utterance?.trim() || ''; } controller.payload = request.payload; } if (!controller.userCommand) { controller.userCommand = controller.originalUserCommand; } } /** * Возвращает корректный массив кнопок с учетом лимита * @param buttons * @param limit */ function getCorrectButtons(buttons, limit = 10) { if (buttons && buttons.length > limit) { return buttons.slice(0, limit); } return buttons; } /** * Утилита для безопасного преобразования строки в объект * @param data */ function tryParse(data) { const rawPayload = data; if (typeof rawPayload === 'string') { const trimmedPayload = rawPayload.trim(); if (trimmedPayload[0] === '{' || trimmedPayload[0] === '[') { try { return JSON.parse(rawPayload); } catch { return rawPayload; } } } return rawPayload; }