简体   繁体   English

将Bing Web Search API与QnA聊天机器人集成

[英]Intergrating Bing Web Search API with QnA chat bot

I am making a chat bot using the QnA template (Microsoft Azure). 我正在使用QnA模板(Microsoft Azure)制作聊天机器人。 Basically, a user asks a question and the bot will try and find the answer in an FAQ document. 基本上,用户问一个问题,机器人将尝试在FAQ文档中找到答案。 If it fails, I want it to run a Bing search with the user's query and replies with the most accurate answer. 如果失败,我希望它对用户的查询运行Bing搜索,并以最准确的答案进行回复。 I found this example that uses Bing Web Search API: https://docs.microsoft.com/en-us/azure/cognitive-services/bing-web-search/quickstarts/nodejs . 我找到了使用Bing Web搜索API的示例: https : //docs.microsoft.com/zh-cn/azure/cognitive-services/bing-web-search/quickstarts/nodejs For now, I just want the bot to reply with the first link of the search for example. 现在,我只想让该机器人以搜索的第一个链接作为答复。 However, I don't know how to merge the code in the link, with the generated code for the QnA Bot (in Node.js): 但是,我不知道如何将链接中的代码与QnA Bot的生成代码(在Node.js中)合并:

var restify = require('restify');
var builder = require('botbuilder');
var botbuilder_azure = require("botbuilder-azure");
var builder_cognitiveservices = require("botbuilder-cognitiveservices");
var request = require('request');

// Setup Restify Server
var server = restify.createServer();
server.listen(process.env.port || process.env.PORT || 3978, function () {
    console.log('%s listening to %s', server.name, server.url); 
});

// Create chat connector for communicating with the Bot Framework Service
var connector = new builder.ChatConnector({
    appId: process.env.MicrosoftAppId,
    appPassword: process.env.MicrosoftAppPassword,
    openIdMetadata: process.env.BotOpenIdMetadata 
});

// Listen for messages from users 
server.post('/api/messages', connector.listen());

var tableName = 'botdata';
var azureTableClient = new botbuilder_azure.AzureTableClient(tableName, process.env['AzureWebJobsStorage']);
var tableStorage = new botbuilder_azure.AzureBotStorage({ gzipData: false }, azureTableClient);

// Create your bot with a function to receive messages from the user
var bot = new builder.UniversalBot(connector);
bot.set('storage', tableStorage);

// Recognizer and and Dialog for GA QnAMaker service
var recognizer = new builder_cognitiveservices.QnAMakerRecognizer({
    knowledgeBaseId: process.env.QnAKnowledgebaseId,
    authKey: process.env.QnAAuthKey || process.env.QnASubscriptionKey, // Backward compatibility with QnAMaker (Preview)
    endpointHostName: process.env.QnAEndpointHostName
});

var basicQnAMakerDialog = new builder_cognitiveservices.QnAMakerDialog({
    recognizers: [recognizer],
    defaultMessage: 'Sorry, I cannot find anything on that topic',
    qnaThreshold: 0.3
});

// Override the invokeAnswer function from QnAMakerDialog 
builder_cognitiveservices.QnAMakerDialog.prototype.invokeAnswer = function (session, recognizeResult, threshold, noMatchMessage) {
    var qnaMakerResult = recognizeResult;
    session.privateConversationData.qnaFeedbackUserQuestion = session.message.text;
    if (qnaMakerResult.score >= threshold && qnaMakerResult.answers.length > 0) {
        if (this.isConfidentAnswer(qnaMakerResult) || this.qnaMakerTools == null) {
            this.respondFromQnAMakerResult(session, qnaMakerResult);
            this.defaultWaitNextMessage(session, qnaMakerResult);
        }
        else {
            this.qnaFeedbackStep(session, qnaMakerResult);
        }
    }
    else {
        this.noMatch(session, noMatchMessage, qnaMakerResult);
    }
};

// API call to Bing
basicQnAMakerDialog.noMatch = function (session, noMatchMessage, qnaMakerResult) {
    var term = session.message.text;
    var key = 'i hid it';

    var options = {
            url: "https://api.cognitive.microsoft.com/bing/v7.0/search?q=" + term,
            method: 'GET',
            headers : {
        'Ocp-Apim-Subscription-Key' : key
    }
    }; 

    request(options, function(err,res, body){
        if(err){
            console.error(err);
            session.send(noMatchMessage);
        }
        body = JSON.parse(body);
        session.send("I found a thing: " + body["webPages"]["value"][0]["name"]);
    });
};

bot.dialog('basicQnAMakerDialog', basicQnAMakerDialog);

bot.dialog('/', //basicQnAMakerDialog);
        [ 
         function (session, results) {
             session.replaceDialog('basicQnAMakerDialog');
         },

         ]);

In the function inside the bot.dialog, I think I should add a condition such as: if the bot returns the default message, open a web page and let the "term" to search be the user's last message. 在bot.dialog内部的函数中,我认为我应该添加一个条件,例如:如果bot返回默认消息,请打开一个网页,并让“条件”搜索成为用户的最后一条消息。 However, I don't know how to code this exactly, and where to do so. 但是,我不知道该如何精确地编写代码以及在哪里进行编写。 Also, I don't know how to exit from the replaceDialog function in order to reply with something other than the default message or the answers in the FAQ. 另外,我不知道如何从replaceDialog函数退出以用默认消息或FAQ中的答案以外的其他方式答复。

PS: I don't have much experience with javascript or web development in general. PS:总体而言,我对JavaScript或Web开发没有太多经验。 Any help will be appreciated :) 任何帮助将不胜感激 :)

What you are implementing involves two steps, extracting out the "noMatch" case to a method so you can make a full response message, and then the API call itself. 您要实现的过程涉及两个步骤,将方法的“ noMatch”用例提取出来,以便发出完整的响应消息,然后API调用自身。

The "noMatch" method. “ noMatch”方法。

First, you will want to override the invokeAnswer function from QnAMakerDialog (This override changes nothing but adding a call to a separate method for the noMatch case.) 首先,您将要覆盖QnAMakerDialog的invokeAnswer函数(此覆盖仅改变了什么,只为noMatch情况添加了对单独方法的调用。)

builder_cognitiveservices.QnAMakerDialog.prototype.invokeAnswer = function (session, recognizeResult, threshold, noMatchMessage) {
        var qnaMakerResult = recognizeResult;
        session.privateConversationData.qnaFeedbackUserQuestion = session.message.text;
        if (qnaMakerResult.score >= threshold && qnaMakerResult.answers.length > 0) {
            if (this.isConfidentAnswer(qnaMakerResult) || this.qnaMakerTools == null) {
                this.respondFromQnAMakerResult(session, qnaMakerResult);
                this.defaultWaitNextMessage(session, qnaMakerResult);
            }
            else {
                this.qnaFeedbackStep(session, qnaMakerResult);
            }
        }
        else {
                this.noMatch(session, noMatchMessage, qnaMakerResult);
        }
    };

After this you will define your basicQnAMakerDialog as usual, but consider making the default message field something for an error case or "no results found". 此后,您将像往常一样定义basicQnAMakerDialog,但考虑将默认消息字段用于错误情况或“未找到结果”。 (This doesn't really matter, as you can arbitrarily decide what you send back within the noMatch method, but it's nice to have the default there) (这并不重要,因为您可以在noMatch方法中任意决定要发回的内容,但是最好在其中使用默认值)

var basicQnAMakerDialog = new builder_cognitiveservices.QnAMakerDialog({
    recognizers: [recognizer],
    defaultMessage: 'Sorry, I can't find anything on that topic'
    qnaThreshold: 0.3
});

After this you can define the noMatch method seperately. 之后,您可以分别定义noMatch方法。

basicQnAMakerDialog.noMatch = function (session, noMatchMessage, qnaMakerResult) {
            session.send(noMatchMessage); //Contains the default message
            this.defaultWaitNextMessage(session, qnaMakerResult);
}

Within this method we can call the API or do basically whatever we want. 在此方法中,我们可以调用API或基本执行我们想要的任何操作。

Credit to gliddell on this override 归功于gliddell

The API call. API调用。

Within the noMatch method, we will make an API call to Bing 在noMatch方法中,我们将对Bing进行API调用

basicQnAMakerDialog.noMatch = function (session, noMatchMessage, qnaMakerResult) {
    var term = session.message.text;
    var key = <Environment Var containing the Bing key>;

    var options = {
        url: "https://api.cognitive.microsoft.com/bing/v7.0/search?q=" + term,
        method: 'GET',
        headers : {
            'Ocp-Apim-Subscription-Key' : key
        }
    }; 
    request(options, function(err,res, body){
        if(err){
            console.error(err);
            session.send(noMatchMessage);
        }
        body = JSON.parse(body);
        session.send("I found a thing: " + body["webPages"]["value"][0]["name"]);
    });
};

You can customize the message you are sending back as much as you like after you get the results from the search. 从搜索结果中获取消息后,您可以根据需要自定义发送回的消息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM