Skip to content

Commit

Permalink
Add support for Chat/Conversations
Browse files Browse the repository at this point in the history
  • Loading branch information
paschmann committed Sep 15, 2019
1 parent d260b9f commit c79619e
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 65 deletions.
2 changes: 1 addition & 1 deletion server/routes/index.js
Expand Up @@ -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
Expand Down
93 changes: 52 additions & 41 deletions server/routes/rasa_router.js
Expand Up @@ -17,7 +17,8 @@ module.exports = {
loadRasaModel: loadRasaModel,
conversationParseRequest: conversationParseRequest,
restartRasaCoreConversation: restartRasaCoreConversation,
getConversationStory: getConversationStory
getConversationStory: getConversationStory,
runActionInConversation: runActionInConversation
};

/* -------------------------------- Util Functions ----------------------------------------------------------------------------------------------------- */
Expand Down Expand Up @@ -207,25 +208,16 @@ 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',
{
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 + "}");
Expand All @@ -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 {
Expand All @@ -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 + "}");
Expand All @@ -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);
Expand Down
72 changes: 53 additions & 19 deletions web/src/app/components/chat/chat.html
Expand Up @@ -71,18 +71,45 @@
<div class="col-sm-12 wrapper" id="container">
<div id="chat">
<div class="msg_history" id="message_history">
<div ng-repeat="transaction in transactions" ng-if="transaction.text" ng-click="loadConversationDetail(transaction)">
<div ng-class=" transaction.source == 'server' ? 'incoming_msg' : 'outgoing_msg' ">
<div ng-class=" transaction.source == 'server' ? 'received_msg' : 'sent_msg' ">
<div ng-class=" transaction.source == 'server' ? 'received_withd_msg' : '' ">
<div ng-repeat="transaction in transactions" ng-click="loadConversationDetail(transaction)">

<!-- Sent Message -->
<div ng-if="transaction.event == 'user'" class="outgoing_msg">
<div class="sent_msg">
<div class="">
<p>{{ transaction.text }}</p>
</div>
<div ng-class=" transaction.source == 'server' ? 'received_withd_msg' : '' ">
<span class="time_date" ng-class=" transaction.source != 'server' ? 'sent' : '' ">
{{ transaction.timestamp * 1000 | date: 'MM/dd/yyyy h:mm:ss a' }}</span>
<div class="">
<span class="time_date sent">{{ transaction.parse_data.intent.name }}</span>
</div>
<div class="">
<span class="time_date sent">{{ transaction.timestamp * 1000 | chatDate }}</span>
</div>
</div>
</div>

<!-- Received Message -->
<div ng-if="transaction.event == 'bot'" class="incoming_msg">
<div class="received_msg">
<div class="received_withd_msg">
<p>{{ transaction.text }}</p>
</div>
<div class="received_withd_msg">
<span class="time_date">
{{ transaction.timestamp * 1000 | chatDate }}</span>
</div>
</div>
</div>

<!-- Action -->
<div class="action_msg">
<div>
<div>
<p>{{ transaction.name }}</p>
</div>
</div>
</div>

</div>
</div>
</div>
Expand All @@ -95,7 +122,7 @@
<div class="input-group">
<input class="form-control" ng-model="test_text" placeholder="Type a message">
<span class="input-group-append">
<button class="btn btn-primary" id="msg_send_btn" type="submit" ng-class=" selected_conversation.conversation_id ? '' : 'disabled' "><i class="icon-paper-plane" aria-hidden="true"></i></button>
<button class="btn btn-primary" id="msg_send_btn" type="submit" ng-disabled=" selected_message.event != 'user'"><i class="icon-paper-plane" aria-hidden="true"></i></button>
</span>
</div>
</div>
Expand All @@ -111,25 +138,32 @@
<div class="col-sm-3">
<tabset class="tab-container" id="tabs">
<ul class="nav nav-tabs">
<li class="nav-item active"><a class="nav-link active" data-target="#story" data-toggle="tab"> Story</a>
</li>
<li class="nav-item active"><a class="nav-link active" data-target="#story" data-toggle="tab"> Story</a></li>
<li class="nav-item"><a class="nav-link" data-target="#message" data-toggle="tab">Message</a></li>
<li class="nav-item"><a class="nav-link" data-target="#conversation" data-toggle="tab">Conversation</a></li>
</ul>
<div class="tab-content">
<tab class="tab-pane active" id="story">
<textarea class="datainput form-control" ng-model="selected_conversation.story">{{ selected_conversation.story }}</textarea>
</tab>
<tab class="tab-pane" id="message">
<json-formatter json="selected_message" open="3"></json-formatter>
</tab>
<tab class="tab-pane" id="nlu_data">
<textarea class="datainput" ng-model="raw_data.nlu" ng-change="stringifyData()">{{ raw_data.nlu }}</textarea>
</tab>
<tab class="tab-pane" id="stories">
<textarea class="datainput" ng-model="raw_data.stories" ng-change="stringifyData()">{{ raw_data.stories }}</textarea>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<button type="button" class="btn btn-info active float-right" ng-disabled=" selected_message.event != 'user'" ng-click="resendMessage()"><i class="icon-plus"></i>&nbsp;Resend</button><br />&nbsp;
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<json-formatter json="selected_message" open="3"></json-formatter>
</div>
</div>
</tab>
<tab class="tab-pane" id="domain">
<textarea class="datainput" ng-model="raw_data.domain" ng-change="stringifyData()">{{ raw_data.domain }}</textarea>
<tab class="tab-pane" id="conversation">
<div class="col-sm-12">
<json-formatter json="selected_conversation" open="3"></json-formatter>
</div>
</tab>
</div>
</tabset>
Expand Down
28 changes: 26 additions & 2 deletions web/src/app/components/chat/chat.js
Expand Up @@ -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 () {
Expand All @@ -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);
Expand Down Expand Up @@ -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();
}
Expand All @@ -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 = {};
Expand Down
13 changes: 12 additions & 1 deletion web/src/app/directives.js
Expand Up @@ -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;
Expand Down
9 changes: 8 additions & 1 deletion 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 {
Expand Down Expand Up @@ -157,6 +158,7 @@ tags-input .tags .tag-item .remove-button {
}

.time_date {
text-align: left;
color: #747474;
display: block;
font-size: 12px;
Expand Down Expand Up @@ -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;
}

0 comments on commit c79619e

Please sign in to comment.