173 lines
5.4 KiB
JavaScript
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 |