From c79619e425793b70c4f9bea797898976ce6a79ff Mon Sep 17 00:00:00 2001 From: Paul Aschmann Date: Sun, 15 Sep 2019 10:36:09 -0400 Subject: [PATCH] Add support for Chat/Conversations --- server/routes/index.js | 2 +- server/routes/rasa_router.js | 93 +++++++++++++++------------ web/src/app/components/chat/chat.html | 72 +++++++++++++++------ web/src/app/components/chat/chat.js | 28 +++++++- web/src/app/directives.js | 13 +++- web/src/assets/css/style.css | 9 ++- 6 files changed, 152 insertions(+), 65 deletions(-) diff --git a/server/routes/index.js b/server/routes/index.js index 524ce52..9e6956a 100755 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -136,7 +136,7 @@ router.post('/rasa/model/parse', rasa_router.modelParseRequest); router.post('/rasa/conversations/messages', rasa_router.conversationParseRequest); router.post('/rasa/restart', rasa_router.restartRasaCoreConversation); router.get('/rasa/story', rasa_router.getConversationStory); - +router.post('/rasa/conversations/execute', rasa_router.runActionInConversation); //authentication js diff --git a/server/routes/rasa_router.js b/server/routes/rasa_router.js index 3ced3f2..241b0a0 100755 --- a/server/routes/rasa_router.js +++ b/server/routes/rasa_router.js @@ -17,7 +17,8 @@ module.exports = { loadRasaModel: loadRasaModel, conversationParseRequest: conversationParseRequest, restartRasaCoreConversation: restartRasaCoreConversation, - getConversationStory: getConversationStory + getConversationStory: getConversationStory, + runActionInConversation: runActionInConversation }; /* -------------------------------- Util Functions ----------------------------------------------------------------------------------------------------- */ @@ -207,8 +208,7 @@ function modelParseRequest(req, res, next) { function getConversationStory(req, res, next) { try { logger.winston.info("Routing to Model Rasa Story Request -> " + global.rasa_endpoint + "/conversations/" + req.query.conversation_id + "/story"); - request({ method: 'GET', uri: global.rasa_endpoint + "/conversations/" + req.query.conversation_id + "/story" }, - function (err, response, body) { + request({ method: 'GET', uri: global.rasa_endpoint + "/conversations/" + req.query.conversation_id + "/story" }, function (err, response, body) { try { logger.winston.verbose('Rasa Response: ' + body.substring(1, 200) + ' ... '); logs.logRequest(req, 'parse', @@ -216,16 +216,8 @@ function getConversationStory(req, res, next) { server_response: body, query: req.body.q }); - //Update conversation table with updated conversation response from rasa ... - //TODO: Add story? - db.run('update conversations set story = ? where conversation_id = ?', [body, req.query.conversation_id], function(err) { - if (err) { - logger.winston.info("Error updating the record"); - } else { - //http_code, res, body, headers, type - sendOutput(200, res, body, { 'Content-Type': 'plain/text' }, ''); - } - }); + updateStory(req.query.conversation_id, body); + sendOutput(200, res, body, { 'Content-Type': 'plain/text' }, ''); } catch (err) { logger.winston.error(err); sendOutput(500, res, '{"error" : ' + err + "}"); @@ -236,8 +228,27 @@ function getConversationStory(req, res, next) { } } +function updateStory(conversation_id, story) { + db.run('update conversations set story = ? where conversation_id = ?', [story, conversation_id], function (err) { + if (err) { + logger.winston.info("Error updating the record"); + } else { + logger.winston.info("Updated story"); + } + }); +} +function updateConversation(conversation_id, conversation) { + //Update the DB with the latest results + db.run('update conversations set conversation = ? where conversation_id = ?', [conversation, conversation_id], function (err) { + if (err) { + logger.winston.error("Error updating the record"); + } else { + logger.winston.info("Updated conversation"); + } + }); +} function conversationParseRequest(req, res, next) { try { @@ -251,20 +262,11 @@ function conversationParseRequest(req, res, next) { server_response: body, query: req.body.q }); - //Maybe we should run this before the DB update and save both to the DB at the same time and then return both responses to the client - request({ method: 'POST', uri: global.rasa_endpoint + "/conversations/" + req.body.conversation_id + "/predict", body: JSON.stringify(req.body) }, - function (err, response, predict_body) { - //console.log(body); - //Update conversation table with updated conversation response from rasa ... - db.run('update conversations set conversation = ? where conversation_id = ?', [predict_body, req.body.conversation_id], function(err) { - if (err) { - logger.winston.error("Error updating the record"); - } else { - - sendOutput(200, res, predict_body); - } - }); - }); + + request({ method: 'POST', uri: global.rasa_endpoint + "/conversations/" + req.body.conversation_id + "/predict", body: JSON.stringify(req.body) }, function (err, response, predict_body) { + updateConversation(req.body.conversation_id, predict_body); + sendOutput(200, res, predict_body); + }); } catch (err) { logger.winston.error(err); sendOutput(500, res, '{"error" : ' + err + "}"); @@ -275,31 +277,40 @@ function conversationParseRequest(req, res, next) { } } +function runActionInConversation(req, res, next) { + logger.winston.info("Rasa Core Run Action Request -> " + global.rasa_endpoint + "/conversations/" + req.body.conversation_id + "/execute"); + try { + request({ method: "POST", uri: global.rasa_endpoint + "/conversations/" + req.body.conversation_id + "/execute", body: JSON.stringify(req.body.action) }, function (err, response, execute_body) { + if (err) { + logger.winston.error(err); + sendOutput(500, res, '{"error" : "Exception caught !!"}'); + return; + } + logger.winston.verbose("Run Action Response" + JSON.stringify(execute_body)); + updateConversation(req.body.conversation_id, execute_body); + sendOutput(200, res, execute_body); + }); + } catch (err) { + logger.winston.error(err); + sendOutput(500, res, '{"error" : "Exception caught !!"}'); + return; + } +} + function restartRasaCoreConversation(req, res, next) { logger.winston.info("Rasa Core Restart Request -> " + global.rasa_endpoint + "/conversations/" + req.body.conversation_id + "/tracker/events"); try { var body = JSON.stringify({ "event": "restart" }); - request({ - method: "POST", - uri: global.rasa_endpoint + "/conversations/" + req.body.conversation_id + "/tracker/events", - body: body - }, function (err, response, body) { + request({ method: "POST", uri: global.rasa_endpoint + "/conversations/" + req.body.conversation_id + "/tracker/events", body: body }, function (err, response, body) { if (err) { logger.winston.error(err); sendOutput(500, res, '{"error" : "Exception caught !!"}'); return; } logger.winston.verbose("Restart Response" + JSON.stringify(body)); - //Update conversation table with updated conversation response from rasa ... - db.run('update conversations set conversation = ?, story = ? where conversation_id = ?', [body, '', req.body.conversation_id], function(err) { - if (err) { - logger.winston.error("Error updating the record"); - } else { - //Predict the next action? - sendOutput(200, res, body); - } - }); + updateConversation(req.body.conversation_id, body); + sendOutput(200, res, body); }); } catch (err) { logger.winston.error(err); diff --git a/web/src/app/components/chat/chat.html b/web/src/app/components/chat/chat.html index 6ba5439..5084069 100755 --- a/web/src/app/components/chat/chat.html +++ b/web/src/app/components/chat/chat.html @@ -71,18 +71,45 @@
-
-
-
-
+
+ + +
+
+

{{ transaction.text }}

-
- - {{ transaction.timestamp * 1000 | date: 'MM/dd/yyyy h:mm:ss a' }} +
+ {{ transaction.parse_data.intent.name }} +
+
+ {{ transaction.timestamp * 1000 | chatDate }} +
+
+
+ + +
+
+
+

{{ transaction.text }}

+
+
+ + {{ transaction.timestamp * 1000 | chatDate }} +
+
+
+ + +
+
+
+

{{ transaction.name }}

+
@@ -95,7 +122,7 @@
- +
@@ -111,25 +138,32 @@
- - - - - - - +
+
+
+
  +
+
+
+
+
+ +
+
- - + +
+ +
diff --git a/web/src/app/components/chat/chat.js b/web/src/app/components/chat/chat.js index 33713b5..d45eac3 100755 --- a/web/src/app/components/chat/chat.js +++ b/web/src/app/components/chat/chat.js @@ -30,6 +30,11 @@ function ChatController($scope, $rootScope, $interval, $http, Rasa_Version, Sett }); } + $scope.resendMessage = function() { + $scope.test_text = $scope.selected_message.text; + $scope.executeCoreRequest(); + } + $scope.addBotConversation = function () { this.formData.bot_id = $scope.selectedBot.bot_id; Conversations.save(this.formData).$promise.then(function () { @@ -50,7 +55,7 @@ function ChatController($scope, $rootScope, $interval, $http, Rasa_Version, Sett $scope.selected_conversation = selected_conversation; if (selected_conversation.conversation) { var conversation = JSON.parse(selected_conversation.conversation); - if (conversation && conversation.tracker.events) { + if (conversation && conversation.tracker && conversation.tracker.events) { $scope.transactions = conversation.tracker.events; } $scope.loadConversationStory(selected_conversation.conversation_id); @@ -86,8 +91,9 @@ function ChatController($scope, $rootScope, $interval, $http, Rasa_Version, Sett $('.write_msg').focus(); $http.post(appConfig.api_endpoint_v2 + '/rasa/conversations/messages', JSON.stringify(reqMessage)).then(function (response) { if (response.data && response.data.tracker) { - $scope.selected_conversation.conversation = JSON.stringify(response.data); + $scope.selected_conversation.conversation = response.data; $scope.transactions = response.data.tracker.events; + checkForActions(response.data); $scope.loadConversationStory($scope.selected_conversation.conversation_id); scrollToMessage(); } @@ -99,6 +105,24 @@ function ChatController($scope, $rootScope, $interval, $http, Rasa_Version, Sett } }; + function checkForActions(messages_response) { + if (messages_response.confidence && messages_response.confidence >= 1) { + var body = {'conversation_id': $scope.selected_conversation.conversation_id, action : {'name': messages_response.scores[0].action }}; + $http.post(appConfig.api_endpoint_v2 + '/rasa/conversations/execute', JSON.stringify(body)).then(function (response) { + if (response.data && response.data.tracker) { + $scope.selected_conversation.conversation = response.data; + $scope.transactions = response.data.tracker.events; + $scope.loadConversationStory($scope.selected_conversation.conversation_id); + scrollToMessage(); + } + }, + function (errorResponse) { + // + } + ); + } + } + function clearScreen() { $scope.transactions = []; $scope.selected_conversation = {}; diff --git a/web/src/app/directives.js b/web/src/app/directives.js index 97ccad9..93d2672 100755 --- a/web/src/app/directives.js +++ b/web/src/app/directives.js @@ -38,7 +38,18 @@ angular.module('app') return $sce.trustAsHtml(ss) }; } - ); + ).filter('chatDate', function($filter) { + var angularDateFilter = $filter('date'); + return function(theDate) { + const today = new Date(); + const filterDate = new Date(theDate); + if (filterDate.setHours(0,0,0,0) == today.setHours(0,0,0,0)) { + return angularDateFilter(theDate, 'HH:mm:ss'); + } else { + return angularDateFilter(theDate, 'MM/dd/yyyy h:mm:ss a'); + } + } + });; function confirmClickDirective() { let i = 0; diff --git a/web/src/assets/css/style.css b/web/src/assets/css/style.css index b5e07d7..c816fda 100755 --- a/web/src/assets/css/style.css +++ b/web/src/assets/css/style.css @@ -1,6 +1,7 @@ .list-group-item.active { - background-color: #CCC; + background-color: #EEE; border-color: #20a8d8; + color: #151b1e } .app-header.navbar .navbar-brand { @@ -157,6 +158,7 @@ tags-input .tags .tag-item .remove-button { } .time_date { + text-align: left; color: #747474; display: block; font-size: 12px; @@ -247,4 +249,9 @@ tags-input .tags .tag-item .remove-button { .wrapper { max-height: 800px; overflow-y: scroll; +} + +.action_msg { + text-align: center; + color: lightgray; } \ No newline at end of file