raspibot/bot.js
2021-06-13 13:51:44 +02:00

173 lines
5.4 KiB
JavaScript

'use strict'
/* Pakete die wir brauchen */
const querystring = require('querystring');
const fetch = require('node-fetch');
var WebSocketClient = require('websocket').client;
/** Wissensbasis importieren und als Dictionary abspeichern */
var wissensbasis = require('./wissensbasis.json');
var answerDict = {};
wissensbasis.intents.forEach(e => {
answerDict[e.intent] = e.answers;
});
var repeat1Dict = {};
wissensbasis.intents.forEach(e => {
repeat1Dict[e.intent] = e.repeat1;
});
var repeat2Dict = {};
wissensbasis.intents.forEach(e => {
repeat2Dict[e.intent] = e.repeat2;
});
var fallbacks = [];
wissensbasis.fallbacks.forEach(e => {
fallbacks.push(e);
});
/* Die Intents der letzten 2 Anfragen werden hier gespeichert */
var savedIntents = {};
/** bot ist ein einfacher Websocket Chat Client */
class bot {
/**
* Konstruktor baut den client auf. Er erstellt einen Websocket und verbindet sich zum Server
* Bitte beachten Sie, dass die Server IP hardcodiert ist. Sie müssen sie umsetzten
*/
constructor () {
/** Die Websocketverbindung */
this.client = new WebSocketClient()
/** Der Name des Bots */
this.botname = "Raspi-Bot"
/** Wenn der Websocket verbunden ist, dann setzten wir ihn auf true */
this.connected = false
/** LUIS Endpoint-Parameter */
this.endpointKey = "9c4cdfefdcde4156a0735c0d2100ef3e";
this.endpoint = "raspberry-pi-4-chatbot.cognitiveservices.azure.com/";
this.appId = "87bb26ac-91ee-4006-a144-6cc7db61b0fb";
/** Wenn die Verbindung nicht zustande kommt, dann läuft der Aufruf hier hinein */
this.client.on('connectFailed', function (error) {
console.log('[BOT] Connect Error: ' + error.toString())
})
/** Wenn der Client sich mit dem Server verbindet sind wir hier */
this.client.on('connect', function (connection) {
this.con = connection
console.log('[BOT] WebSocket Client Connected')
connection.on('error', function (error) {
console.log('[BOT] Connection Error: ' + error.toString())
})
/**
* Es kann immer sein, dass sich der Client disconnected
* (typischer Weise, wenn der Server nicht mehr da ist)
*/
connection.on('close', function () {
console.log('[BOT] echo-protocol Connection Closed')
})
/**
* Hier ist der Kern, wenn immmer eine Nachricht empfangen wird, kommt hier die
* Nachricht an.
*/
connection.on('message', function (message) {
if (message.type === 'utf8') {
var data = JSON.parse(message.utf8Data)
console.log('[BOT] Received: ' + data.msg + ' ' + data.name)
}
})
/**
* Hier senden wir unsere Kennung damit der Server uns erkennt.
* Wir formatieren die Kennung als JSON
*/
function joinGesp () {
if (connection.connected) {
connection.sendUTF('{"type": "join", "name":"Raspi-Bot"}')
}
}
joinGesp()
})
}
/**
* Methode um sich mit dem Server zu verbinden.
*/
connect () {
this.client.connect('ws://localhost:8181/', 'chat')
this.connected = true
}
/**
* Hier muss ihre Verarbeitungslogik integriert werden.
* Diese Funktion wird automatisch im Server aufgerufen, wenn etwas ankommt, das wir
* nicht geschrieben haben
* @param nachricht auf die der bot reagieren soll
* @param nachricht name des Absenders
*/
async post (nachricht, uname) {
// Initialisiert den Intent-Speicher falls dies noch nicht geschehen ist
if(savedIntents[uname] == undefined){
savedIntents[uname] = [];
}
// Sendet die Nachricht an LUIS und erhält extrahiert den Top-Intent und dessen Score aus der Antwort
var luisResponse = await this.sendLUISrequest(nachricht);
var intent = luisResponse.prediction.topIntent;
var intentScore = luisResponse.prediction.intents[intent].score;
// Antwort anhand des erhaltenen Intents und den vorherigen Intents ermitteln
var answer;
if(intentScore > 0.5){
if(intent != savedIntents[uname][0]){
var answerArray = answerDict[intent]
answer = answerArray[Math.floor(Math.random() * answerArray.length)];
}else{
if(intent == savedIntents[uname][1]){
var repeat2Array = repeat2Dict[intent]
answer = repeat2Array[Math.floor(Math.random() * repeat2Array.length)];
}else{
var repeat1Array = repeat1Dict[intent]
answer = repeat1Array[Math.floor(Math.random() * repeat1Array.length)];
}
}
// Speichert den neuen Intent ab
savedIntents[uname][1] = savedIntents[uname][0];
savedIntents[uname][0] = intent;
}else{
answer = fallbacks[Math.floor(Math.random() * fallbacks.length)];
}
// Antwort zusammensetzen und absenden
var msg = '{"type": "msg", "name": "Raspi-Bot", "msg":"' + answer + '"}'
this.client.con.sendUTF(msg)
}
/**
* Sendet die Nachricht zum LUIS Endpoint
*
* @param message die Nachricht
* @returns die Antwort
*/
async sendLUISrequest(message){
var queryParams = {
"show-all-intents": true,
"verbose": true,
"query": message,
"subscription-key": this.endpointKey
}
var URI =`https://${this.endpoint}/luis/prediction/v3.0/apps/${this.appId}/slots/production/predict?${querystring.stringify(queryParams)}`;
var result
await fetch(URI).then(d=>d.json()).then(e=>{
result = e
});
return result;
}
}
module.exports = bot