UNPKG

ask-cli

Version:

Alexa Skills Kit (ASK) Command Line Interfaces

182 lines (169 loc) 7.38 kB
const chalk = require('chalk'); const fs = require('fs-extra'); const R = require('ramda'); const path = require('path'); const stringUtils = require('@src/utils/string-utils'); const Messenger = require('@src/view/messenger'); const responseParser = require('@src/controllers/dialog-controller/simulation-response-parser'); const SkillSimulationController = require('@src/controllers/skill-simulation-controller'); const RECORD_FORMAT = 'Please use the format: ".record <fileName>" or ".record <fileName> --append-quit"'; module.exports = class DialogController extends SkillSimulationController { /** * Constructor for DialogModeController. * @param {Object} configuration | config object includes information such as skillId, locale, profile, stage. */ constructor(configuration) { super(configuration); this.newSession = configuration.newSession === false ? configuration.newSession : true; this.utteranceCache = []; } /** * Evaluate individual utterance input by the User/replay_file. * @param {String} input Utterance by the user sent to Alexa. * @param {Object} replView Dialog command's repl view. * @param {Function} replCallback */ evaluateUtterance(input, replView, replCallback) { replView.startProgressSpinner('Sending simulation request to Alexa...'); this.startSkillSimulation(input.trim(), (startErr, startResponse) => { if (startErr) { replView.terminateProgressSpinner(); Messenger.getInstance().error(startErr); replCallback(); } else if (startResponse.statusCode >= 300) { replView.terminateProgressSpinner(); Messenger.getInstance().error(R.view(R.lensPath(['body', 'error', 'message']), startResponse)); replCallback(); } else { replView.updateProgressSpinner('Waiting for the simulation response...'); const simulationId = R.view(R.lensPath(['body', 'id']), startResponse); this.getSkillSimulationResult(simulationId, (getErr, getResponse) => { replView.terminateProgressSpinner(); if (getErr) { Messenger.getInstance().error(getErr); } else { if (responseParser.shouldEndSession(getResponse.body)) { Messenger.getInstance().info('Session ended'); this.clearSession(); } const captions = responseParser.getCaption(getResponse.body); captions.forEach((caption) => { Messenger.getInstance().info(chalk.yellow.bold('Alexa > ') + caption); }); } replCallback(); }); } }); } /** * Registers special commands with the REPL server. * @param {Object} dialogReplView dialog command's repl view. * @param {Function} callback */ setupSpecialCommands(dialogReplView, callback) { dialogReplView.registerRecordCommand((recordArgs) => { const recordArgsList = recordArgs.trim().split(' '); if (!stringUtils.isNonBlankString(recordArgs) || recordArgsList.length > 2) { return Messenger.getInstance().warn(`Incorrect format. ${RECORD_FORMAT}`); } const { filePath, shouldAppendQuit } = this._validateRecordCommandInput(recordArgsList, RECORD_FORMAT); const utteranceCacheCopy = [...this.utteranceCache]; if (shouldAppendQuit) { utteranceCacheCopy.push('.quit'); } if (filePath) { try { this.createReplayFile(filePath, utteranceCacheCopy); Messenger.getInstance().info(`Created replay file at ${filePath}` + `${shouldAppendQuit ? ' (appended ".quit" to list of utterances).' : ''}`); } catch (replayFileCreationError) { return callback(replayFileCreationError); } } }); dialogReplView.registerQuitCommand(() => {}); } /** * Validate record command arguments. * @param {Array} recordArgsList * @param {String} recordCommandFormat */ _validateRecordCommandInput(recordArgsList) { const filePath = recordArgsList[0]; const appendQuitArgument = recordArgsList[1]; let shouldAppendQuit = false; const JSON_FILE_EXTENSION = '.json'; if (path.extname(filePath).toLowerCase() !== JSON_FILE_EXTENSION) { Messenger.getInstance().warn(`File should be of type '${JSON_FILE_EXTENSION}'`); return {}; } if (stringUtils.isNonBlankString(appendQuitArgument)) { if (appendQuitArgument !== '--append-quit') { Messenger.getInstance().warn(`Unable to validate arguments: "${appendQuitArgument}". ${RECORD_FORMAT}`); return {}; } shouldAppendQuit = true; } return { filePath, shouldAppendQuit }; } /** * Start skill simulation by calling SMAPI POST skill simulation endpoint. * @param {String} utterance text utterance to simulate against. * @param {Function} onSuccess callback to execute upon a successful request. * @param {Function} onError callback to execute upon a failed request. */ startSkillSimulation(utterance, callback) { super.startSkillSimulation( utterance, this.newSession, (err, response) => { if (response) { this.utteranceCache.push(utterance); } return callback(err, response); } ); } /** * Poll for skill simulation results. * @param {String} simulationId simulation ID associated to the current simulation. * @param {Function} onSuccess callback to execute upon a successful request. * @param {Function} onError callback to execute upon a failed request. */ getSkillSimulationResult(simulationId, callback) { super.getSkillSimulationResult(simulationId, (err, response) => { if (err) { return callback(err); } const errorMsg = responseParser.getErrorMessage(response.body); if (errorMsg) { return callback(errorMsg); } this.newSession = false; return callback(null, response); }); } /** * Clears dialog session by resetting to a new session and clearing caches. */ clearSession() { this.newSession = true; this.utteranceCache = []; } /** * Function to create replay file. * @param {String} filename name of file to save replay JSON. */ createReplayFile(filename, utterances) { if (stringUtils.isNonBlankString(filename)) { const content = { skillId: this.skillId, locale: this.locale, type: 'text', userInput: utterances }; fs.outputJSONSync(filename, content); } } };