UNPKG

prisme-flow

Version:

prisme platform flow engine

122 lines (109 loc) 4.05 kB
/** * Created by prisme.io on 09/06/2017. */ var _ = require('underscore') var apiai = require('apiai') var moment = require('moment') var utils = require('./lib/helpers/utils') module.exports = function (RED) { function BotApiAi (config) { RED.nodes.createNode(this, config) var node = this node.rules = config.rules node.apiAiNodeId = config.apiai this.processMessage = function (msg) { msg = RED.util.cloneMessage(msg) var originalMessage = msg.originalMessage var chatId = msg.payload.chatId || (originalMessage && originalMessage.chat.id) var chatContext = msg.chat() var rules = node.rules var outputsNumber = (_.isArray(rules) ? rules.length : 0) + 1 var output = null var apiAiNode = RED.nodes.getNode(node.apiAiNodeId) var apiAi = apiAiNode.apiAi // check for string var message = null if (_.isString(msg.payload)) { message = msg.payload } else if (msg.payload != null && _.isString(msg.payload.content)) { message = msg.payload.content } else { node.error('A payload of string or chat text message is required as input') return } var outboundContexts = chatContext.get('topic') if (!_.isEmpty(outboundContexts)) { outboundContexts = _.isArray(outboundContexts) ? outboundContexts : [outboundContexts] } // prepare request apiAi.textRequest(message, { sessionId: chatId, contexts: outboundContexts // todo put timezone // todo put language }).on('response', function (response) { var result = response.result // parse result if (result.actionIncomplete || result.action === 'input.unknown') { // if action incomplete, start over from here next message, do nothing with context // the same if the action is unknow, just spit out the message and start from here chatContext.set('currentConversationNode', node.id) chatContext.set('currentConversationNode_at', moment()) // exit only from the first output msg.payload = response.result.fulfillment.speech output = new Array(outputsNumber) output[0] = msg } else { // get the output contexts, support multi context but try to reduce as a string if possible and // put the context back in the variables namespace var contexts = _(response.result.contexts).pluck('name') var inboundContexts = contexts if (_.isEmpty(contexts)) { inboundContexts = null } else if (contexts.length === 1) { inboundContexts = contexts[0] } chatContext.set('topic', inboundContexts) // set the parameters back to the chat context chatContext.set(result.parameters) // prepare output, only if it matches the context msg.payload = response.result.fulfillment.speech output = new Array() output.push(null) rules.forEach(function (rule) { output.push(utils.matchContext(inboundContexts, rule.topic) ? msg : null) }) } // finally send node.send(output) }).on('error', function (error) { node.error(error) }).end() } // relay message var handler = function (msg) { node.processMessage(msg) } RED.events.on('node:' + config.id, handler) // cleanup on close this.on('close', function () { RED.events.removeListener('node:' + config.id, handler) }) this.on('input', this.processMessage) } RED.nodes.registerType('bot-apiai', BotApiAi) function ApiAiToken (n) { RED.nodes.createNode(this, n) var self = this if (self.credentials != null && !_.isEmpty(self.credentials.token)) { self.apiAi = apiai(self.credentials.token) } } RED.nodes.registerType('bot-apiai-token', ApiAiToken, { credentials: { token: { type: 'text' } } }) }