Search code examples
azureazure-language-understandingazure-cognitive-search

LUIS and Azure-search in a single bot


I am very new to bot builder. I need to use LUIs intents and then eventually call azure-search to search the intent.

However, below is my code. In the Aco-Saerch intent, I want to extract the intent from the user's message and then want to pass to the query in the azure-search.

In the dialog SearchDialog, waterfall functions are not proceeding after the first function. Can anyone help me out whats wrong here.

I am trying the use the azure search code and libraries from this git-hub shared code: Realstate azure search node js code

In future, I want to add QnA recognizer too. Aim is : search the query in qnA base, if found, return else, use the LUIS to find out the intent and then pass it the azure search.

var util = require('util');
var _ = require('lodash');
var builder = require('botbuilder');
var restify = require('restify');

/// <reference path="../SearchDialogLibrary/index.d.ts" />
var SearchLibrary = require('../SearchDialogLibrary');
var AzureSearch = require('../SearchProviders/azure-search');

// 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 bot and listen for messages
var connector = new builder.ChatConnector({
    appId: process.env.MICROSOFT_APP_ID,
    appPassword: process.env.MICROSOFT_APP_PASSWORD
});
server.post('/api/messages', connector.listen());

// Bot Storage: Here we register the state storage for your bot. 
// Default store: volatile in-memory store - Only for prototyping!
// We provide adapters for Azure Table, CosmosDb, SQL Azure, or you can implement your own!
// For samples and documentation, see: https://github.com/Microsoft/BotBuilder-Azure
var inMemoryStorage = new builder.MemoryBotStorage();

const LuisModelUrl = 'https://westeurope.api.cognitive.microsoft.com/luis/v2.0/apps/180a9aaa-9d67-4d40-b3d3-121917f4dbb8?subscription-key=39155bb750dc4b2abd84d410d80fce21&timezoneOffset=0&q=';
var recognizer = new builder.LuisRecognizer(LuisModelUrl);
// Bot with main dialog that triggers search and display its results
var bot = new builder.UniversalBot(connector, function (session, args) {
    session.send('You reached the default message handler. You said \'%s\'.', session.message.text);
}).set('storage', inMemoryStorage);

bot.recognizer(recognizer);

bot.dialog('GreetingDialog',
    (session) => {
        session.send('You reached the Greeting intent. You said \'%s\'.', session.message.text);
        session.endDialog();
    }
).triggerAction({
    matches: 'Greeting'
})

bot.dialog('HelpDialog',
    (session) => {
        session.send('You reached the Help intent. You said \'%s\'.', session.message.text);
        session.endDialog();
    }
).triggerAction({
    matches: 'Help'
})

bot.dialog('CancelDialog',
    (session) => {
        session.send('You reached the Cancel intent. You said \'%s\'.', session.message.text);
        session.endDialog();
    }
).triggerAction({
    matches: 'Cancel'
})

bot.dialog('SearchDialog', [
    function (session, args) {
        var intent = args.intent;
        var title = builder.EntityRecognizer.findEntity(intent.entities, 'businessterm');
        console.log(title.entity);
        session.send('You reached the Search.Aco intent. You enquire for the entitiy \'%s\'.', title.entity);
    },
    function (session, args, results) {
        // Trigger Search
        console.log("Inside the SearchLibrary.begin");
        SearchLibrary.begin(session);
        console.log("after  the SearchLibrary.begin");
    },
    function (session, args, results) {
        // Process selected search results
        session.send(
            'Done! For future reference, you selected these properties: %s',
            args.selection.map(function (i) { return i.key; }).join(', '));
    }
]).triggerAction({
    matches: 'Search.Aco'
});

var azureSearchClient = AzureSearch.create('aco-intel2', '4105C6676D0CDD9B2E7891952B9E9E00', 'azureblob-index');
var jobsResultsMapper = SearchLibrary.defaultResultsMapper(jobToSearchHit);

// Register Search Dialogs Library with bot
bot.library(SearchLibrary.create({
    multipleSelection: true,
    search: function (query) { return azureSearchClient.search(query).then(jobsResultsMapper); },
    refiners: ['people', 'content', 'location']
}));

// Maps the AzureSearch Job Document into a SearchHit that the Search Library can use
function jobToSearchHit(acosearch) {
    console.log("inside jobToSearchHit");
    console.log("inside acosearch.DocUrl" + acosearch.DocUrl + "-------" + acosearch.metadata_storage_name);
    return {
        key: acosearch.id,
        title: acosearch.metadata_storage_name,
        description: acosearch.content.substring(0, 100)+"...",
        documenturl:acosearch.DocUrl,
        imageUrl: acosearch.imageurl
    };
}

Solution

  • Your dialog isn't advancing as there is nothing for it to act on. Thus, it reaches the end of the first function with nowhere to move on to. You have a few options. You can:

    1. You can include a prompt or button (i.e. some sort of action) to move the dialog along. Ex:

      bot.dialog('SearchDialog', [
          function (session, args) {
              var intent = args.intent;
              var title = builder.EntityRecognizer.findEntity(intent.entities, 'businessterm');
              console.log(title.entity);
              session.send('You reached the Search.Aco intent. You enquire for the entitiy \'%s\'.', title.entity);
              builder.Prompts.choice(session, "Start search?", "Yes|No", { listStyle: builder.ListStyle["button"] });
          },
          function (session, args, results) {
              // Trigger Search
              console.log("Inside the SearchLibrary.begin");
              SearchLibrary.begin(session);
              console.log("after  the SearchLibrary.begin");
          }
      
    2. You can marry the first and second function. However, again, you will need something to move the dialog along from the search function to the search results function.

      bot.dialog('SearchDialog', [
          function (session, args) {
              var intent = args.intent;
              var title = builder.EntityRecognizer.findEntity(intent.entities, 'businessterm');
              console.log(title.entity);
              session.send('You reached the Search.Aco intent. You enquire for the entitiy \'%s\'.', title.entity);
      
              // Trigger Search
              console.log("Inside the SearchLibrary.begin");
              SearchLibrary.begin(session);
              console.log("after  the SearchLibrary.begin");
          },
          function (session, args, results) {
              // Process selected search results
              session.send(
                  'Done! For future reference, you selected these properties: %s',
                  args.selection.map(function (i) { return i.key; }).join(', '));
          }
      ]).triggerAction({
      matches: 'Search.Aco'
      });
      
    3. You can make the search function a separate dialog that is initiated at the end of the first dialog function and, once completes, returns and continues the original dialog.

      bot.dialog('SearchDialog', [
          function (session, args) {
              var intent = args.intent;
              var title = builder.EntityRecognizer.findEntity(intent.entities, 'businessterm');
              console.log(title.entity);
              session.send('You reached the Search.Aco intent. You enquire for the entitiy \'%s\'.', title.entity);
              session.beginDialog('/searchAzure');
          },
          function (session, args, results) {
              // Process selected search results
              session.send(
                  'Done! For future reference, you selected these properties: %s',
                  args.selection.map(function (i) { return i.key; }).join(', '));
          }
      ]).triggerAction({
      matches: 'Search.Aco'
      });
      
      bot.dialog('/searchAzure', [
          function (session) {
              // Trigger Search
              console.log("Inside the SearchLibrary.begin");
              SearchLibrary.begin(session);
              console.log("after  the SearchLibrary.begin");
              session.endDialog();
          }
      ]);