Search code examples
javascriptjquerybotframeworkazure-qna-maker

how to send a message to direct line chat bot from the UI using JavaScript


I'm developing a chat bot (v4 using MS Azure bot framework & QnAmaker),

I've added a feature in that, i.e. while the users starts typing the questions, the bot will get prompt and show the relevant questions form the QnAmaker , and the user can select one of them , then that particular question will sent to the bot.

Following is the full code which I'm using,

<html>
<body>
    <div id="webchat" role="main"></div>
    <script>
        (async function () {

            const styleOptions = {
                hideUploadButton: true,
                bubbleBackground: '#D8F4FF',
                bubbleFromUserBackground: '#E8E8E8',
                botAvatarImage: '../botavatar.PNG',
                botAvatarInitials: 'bot',
                userAvatarInitials: initial,
                userAvatarImage: userimg,
                rootHeight: '100%',
                rootWidth: '50%'

            };

            const styleSet = window.WebChat.createStyleSet({
                bubbleBackground: 'rgba(0, 0, 255, .1)',
                bubbleFromUserBackground: 'rgba(0, 255, 0, .1)'
            });

            styleSet.textContent = {
                fontFamily: "'Comic Sans MS', 'Arial', sans-serif",
                fontWeight: 'bold'
            };
            const secret = secret;
            const res = await fetch('https://directline.botframework.com/v3/directline/tokens/generate',
                {
                    headers: {
                        Authorization: `Bearer ${secret}`,
                    },
                    method: 'POST'
                });
            const { token } = await res.json();

            const store = window.WebChat.createStore(
                {},
                ({ dispatch }) => next => action => {
                    if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
                        dispatch({
                            type: 'WEB_CHAT/SEND_EVENT',
                            payload: {
                                name: 'webchat/join',
                            }
                        });
                    }
                    return next(action);
                }
            );

            window.WebChat.renderWebChat({
                directLine: window.WebChat.createDirectLine({ token }),
                store,
                styleOptions,
                userID: emailid,
                username: fullname,
                locale: 'en-US',
                userAvatarInitials: initial
            }, document.getElementById('webchat'));
            document.querySelector('#webchat > *').focus();
            document.querySelectorAll('[aria-label="Sendbox"]')[0].placeholder = "Type your question and press enter";

            $("[aria-label='Sendbox']").keypress(function () {

                if ($("[aria-label='Sendbox']")[0].defaultValue.length > 4) {

                    getquestion(this.value);
                } else {
                    $('#ques').remove();
                }

            });
            $('div.probing').click(function () { alert(this.innerText); });

            $('div.probing').click(function () {
                document.querySelectorAll('[aria-label="Sendbox"]')[0].value = (this.innerText);
                document.querySelectorAll('[aria-label="Sendbox"]')[0].defaultValue = (this.innerText);
                $('.css-115fwte').trigger('click');
                $('#ques').remove();
            });

        })().catch(err => console.error(err));


        function getquestion(value) {
            var token = secret;
            var questionquery =
            {
                question: value,
                top: 2,
                scoreThreshold: 50,
                "strictFilters": [
                    {
                        "name": "message",
                        "value": "text"
                    }],
            }
            $.ajax({
                type: "POST",
                url: "https://endpoint/qnamaker/knowledgebases/KBID/generateAnswer",

                data: JSON.stringify(questionquery),
                beforeSend: function (xhr) {
                    xhr.setRequestHeader('Authorization', secret);
                },
                dataType: "json",
                contentType: "application/json",
                success: function (data) {    
                    var questions = "";
                    $('#ques').remove();

                    for (var i = 0; i < 4; i++) {
                        if (data.answers[0].questions[i] != null && data.answers[0].questions[i] != 'undefined')
                            questions = questions + "<div class='probing'>" + data.answers[0].questions[i] + "</div>";
                    }
                    $('.content').last().append("<div id='ques'>" + questions + "</div>");
                    $('div.probing').click(function () {
                        document.querySelectorAll('[aria-label="Sendbox"]')[0].value = (this.innerText);
                        document.querySelectorAll('[aria-label="Sendbox"]')[0].defaultValue = (this.innerText);
                        $('.css-115fwte').trigger('click');
                        $('#ques').remove();
                    });
                },
                error: function (data) {
                    alert(data.responseText);
                }
            });
        }

    </script>
</body>
</html>

Please check the below image of my bot with the prompted questions, it will look like this, these questions are get appended to the last reply given by the bot, after selecting the question, this div will get removed. On the next question this cycle will continue again.

enter image description here

Problem I'm facing is here, with the following code the value is getting entered in the input box, however the bot does not received any question, and hence it failed to answer.

$('div.probing').click(function () {
                        document.querySelectorAll('[aria-label="Sendbox"]')[0].value = (this.innerText);
                        document.querySelectorAll('[aria-label="Sendbox"]')[0].defaultValue = (this.innerText);
                        $('.css-115fwte').trigger('click');
                        $('#ques').remove();
                    });

With this code the value is getting entered in the input box, however the bot does not received any question, and hence it failed to answer.

this is how it will in console after adding the question by script. enter image description here Note that I've used all the required reference JS and CSS Files in my code. So please help me with the correct approach to achieve my requirement, Thanks in Advance.


Solution

  • Here's a working demo that should get you started, using a similar method from the sample:

    <!DOCTYPE html>
    <html lang="en-US">
    
    <head>
        <title>Web Chat: Programmatic access to post activity</title>
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
        <!--
          This CDN points to the latest official release of Web Chat. If you need to test against Web Chat's latest bits, please refer to pointing to Web Chat's MyGet feed:
          https://github.com/microsoft/BotFramework-WebChat#how-to-test-with-web-chats-latest-bits
        -->
        <script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
        <style>
            html,
            body {
                height: 100%;
            }
    
            body {
                margin: 0;
            }
    
            #webchat {
                height: 100%;
                width: 100%;
            }
        </style>
    </head>
    
    <body>
        <div id="webchat" role="main"></div>
        <script>
            (async function () {
                // In this demo, we are using Direct Line token from MockBot.
                // Your client code must provide either a secret or a token to talk to your bot.
                // Tokens are more secure. To learn about the differences between secrets and tokens
                // and to understand the risks associated with using secrets, visit https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication?view=azure-bot-service-4.0
    
                // We are creating the Web Chat store here so we can dispatch WEB_CHAT/SEND_MESSAGE action later.
                const store = window.WebChat.createStore();
    
                window.WebChat.renderWebChat(
                    {
                        directLine: window.WebChat.createDirectLine({ token: '<your token>' }),
                        // We are passing our own version of Web Chat store.
                        store
                    },
                    document.getElementById('webchat')
                );
    
                document.querySelector('#webchat > *').focus();
    
    // THIS IS THE IMPORTANT STUFF
    
                const sendbox = document.querySelector("[aria-label='Sendbox']");
    
                function removeQuestions() {
                    const questionDivs = document.querySelectorAll('.questions');
                        questionDivs.forEach((div) => {
                            div.remove();
                        })
                }
    
                // This ensures that we create unique listeners for each question
                let totalQuestions = 0;
    
                // Track the keypress events in the Send Box
                sendbox.addEventListener('keypress', () => {
                    if (sendbox.defaultValue.length > 4) {
                        getQuestion();
                    } else {
                        removeQuestions();
                    }
                });
    
                // Send a message containing the innerText of the target element
                function send(event) {
                    store.dispatch({
                        type: 'WEB_CHAT/SEND_MESSAGE',
                        payload: { text: event.currentTarget.innerText }
                    });
                    event.currentTarget.remove();
                }
    
                // This generates some test questions
                function getQuestion() {
                    // Create questions div
                    const questions = document.createElement('DIV');
                    questions.setAttribute('class', 'questions');
                    document.querySelector('.content').appendChild(questions);
    
                    // Generate test questions
                    for (var i = 0; i < 4; i++) {
                        // Create question div
                        const question = document.createElement('DIV');
                        question.setAttribute('id', `question${totalQuestions}`);
                        question.setAttribute('class', 'probing');
                        question.innerText = `this is a test ${totalQuestions}`;
                        questions.appendChild(question);
    
                        // Create listener for question
                        const element = document.querySelector(`#question${totalQuestions}`);
                        element.addEventListener('click', send, false);
                        totalQuestions++;
                    }
                }
            })().catch(err => console.error(err));
        </script>
    </body>
    
    </html>
    

    There are likely more elegant ways to do this, but I wanted to get an answer out to you ASAP.

    Note: I used vanilla javascript over jQuery to cut down on page load times and because I'm more familiar with it.