Botframework V4 上的网络聊天价值交换问题

Webchat Value Exchanging Issue on Botframework V4

我在 Botframework V4 上的机器人 运行 上使用 Direct Line、MS 语音服务和 Webchat.js。
我使用 webchat.js 从网页启动机器人,将值传递给后端应用程序 https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/04.api/d.post-activity-event
用于在网络频道上实例化机器人的代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>FTD Bit_Bot</title>
</head>
<body style="background-color: #fff; background-image: url('img/FTDBackground.jpg');">
    <div id="chatbot" role="main"
         data-cb-width="320px"
         data-cb-height="400px"
         data-cb-border="1px solid #ededed"
         data-cb-border-radius="0px"
         data-cb-background-color="white"
         data-cb-position="fixed"
         data-cb-right="40px"
         data-cb-bottom="100px"
         data-cb-zIndex="1"
         data-cb-bubble-background="rgba(217, 217, 217, 0.15)"
         data-cb-bubble-from-user-background="#e22e2c"
         data-cb-bubble-from-user-text-color="white"
         data-cb-bubble-max-width="600"
         data-cb-bot-avatar-image="http://demo.radical-thinking.net/bella/microsoft/chat-assets/img/Chat-in-day-Workshop-Icon.png"
         data-cb-hide-send-box="false"
         data-cb-hide-upload-button="true"
         data-cb-send-box-button-color="#e22e2c"
         data-cb-send-box-button-color-on-disabled="#CCC"
         data-cb-send-box-button-color-on-focus="#333"
         data-cb-send-box-button-color-on-hover="#333"
         data-cb-send-box-height="30"
         data-cb-suggested-action-text-color="black"
         data-cb-suggested-action-border="solid 2px #e22e2c"
         data-cb-suggested-action-height="30">
    </div>
    <!-- Include ajax library for speech service token request call -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
    <!-- Include webchat client functionality (https://github.com/Microsoft/BotFramework-WebChat) -->
    <!-- Change to the latest directory to stop the 'No renderer for this activity' error. However the avatar won't show -->
    <script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js" charset="utf-8"></script>
    <script>
        var chatbot = document.getElementById('chatbot');

        // Style modifications
        const styleOptions = {

            // Colors
            bubbleBackground: chatbot.dataset.cbBubbleBackground,
            bubbleFromUserBackground: chatbot.dataset.cbBubbleFromUserBackground,
            bubbleFromUserTextColor: chatbot.dataset.cbBubbleFromUserTextColor,
            bubbleMaxWidth: parseInt(chatbot.dataset.cbBubbleMaxWidth), // maximum width of text message

            // Avatar
            botAvatarImage: chatbot.dataset.cbBotAvatarImage,
            userAvatarInitials: '',

            // Send box
            hideSendBox: JSON.parse(chatbot.dataset.cbHideSendBox),
            hideUploadButton: JSON.parse(chatbot.dataset.cbHideUploadButton),
            sendBoxButtonColor: chatbot.dataset.cbSendBoxButtonColor,
            sendBoxButtonColorOnDisabled: chatbot.dataset.cbSendBoxButtonColorOnDisabled,
            sendBoxButtonColorOnFocus: chatbot.dataset.cbSendBoxButtonColorOnFocus,
            sendBoxButtonColorOnHover: chatbot.dataset.cbSendBoxButtonColorOnHover,
            sendBoxHeight: parseInt(chatbot.dataset.cbSendBoxHeight),

            // Suggested actions
            suggestedActionTextColor: chatbot.dataset.cbSuggestedActionTextColor,
            suggestedActionBorder: chatbot.dataset.cbSuggestedActionBorder,
            suggestedActionHeight: parseInt(chatbot.dataset.cbSuggestedActionHeight),

        }
    </script>
    <script>
        var chatbot = document.getElementById("chatbot");

        //style tag start
        var script = {
            id: 'chatbotStyle',
            type: 'text/css',
            style: document.createElement('style'),
            content: '@import url("https://fonts.googleapis.com/css?family=Roboto:300,400,600"); ::-webkit-scrollbar{width:10px}::-webkit-scrollbar-track{background:#f1f1f1}::-webkit-scrollbar-thumb{background:#888}::-webkit-scrollbar-thumb:hover{background:#555} #chatbot{ font-family: Roboto, sans-serif; font-weight: 400; position: fixed; right: 10px; bottom: 20px; text-align: center; } #chatbot img{ margin: auto; } #chatbot small{ display: block; font-size: 9px; } .initLaunchPad{ cursor: pointer; text-align: center; transition: .4s all; } .botHeader{min-height:40px;background:#ededed;border-radius:6px 6px 0 0;display:flex;justify-content:space-between;align-items:center;padding:4px} .botHeader img{float:left;width:32px;height:32px; border-radius:50%;background-color:#f9f9f9}.botHeader h5{float:left;padding:0!important;margin:4px 0 3px 6px} .botHeader h5 small{font-size: 12px;} .botHeader > div{width:40%;display:flex;align-items:center;text-align:left;height:32px} #botClose{cursor:pointer;font-size:12px;font-weight:600;padding:6px 8px;border-radius:4px;background-color:#e22e2c;color:#fff; } #botContainer{ display: none; border-radius: 8px; border:1px solid #cbcbcb; transition:.4s all; width: 310px; height: 420px; max-width:420px; max-height: 420px; margin-bottom: 4px; } #botBody{ height: 366px; } ',
            append: function () {
                this.style.type = this.type;
                this.style.appendChild(document.createTextNode(this.content));
                document.head.appendChild(this.style);
            }
        }; script.append();
        //style tag end

        //initLaunchPad started
        var initLaunchPad = document.createElement('div');
        initLaunchPad.classList.add('initLaunchPad');
        var initBotIcon = document.createElement('img');
        initBotIcon.src = "https://farm5.staticflickr.com/4876/39891228293_13c532f352_o.gif";
        initBotIcon.width = 86;
        initLaunchPad.appendChild(initBotIcon);
        chatbot.appendChild(initLaunchPad);

        $(function getSpeechAuthToken() {
            var params = {
                // Request parameters
            };

            $.ajax({
                url: "https://brazilsouth.api.cognitive.microsoft.com/sts/v1.0/issuetoken" + $.param(params),
                beforeSend: function (xhrObj) {
                    // Request headers
                    xhrObj.setRequestHeader("Ocp-Apim-Subscription-Key", "XXXXXX");
                },
                type: "POST",
                // Request body
                data: "{body}",
            })
                .done(function (data) {
                    speechAuthToken = data;
                })
                .fail(function () {
                    alert("error");
                });
        });
        initBotIcon.addEventListener('click', function (e) {
            e.preventDefault();
            initLaunchPad.style.display = "none";
            botContainer.style.display = "block";

            /*Call bot API*/
            (async function () {

                const searchParams = new URLSearchParams(window.location.search);

                //Speech Service Token Generation
                const subscriptionKey = 'XXXXXX';
                const region = 'brazilsouth';
                let webSpeechPonyfillFactory;

                //Speech Service Setting
                webSpeechPonyfillFactory = await window.WebChat.createCognitiveServicesSpeechServicesPonyfillFactory({
                    credentials: {
                        authorizationToken: speechAuthToken,
                        region: region
                    }
                });

                //Direct-Line BotToken Generation
                const res = await fetch('https://directline.botframework.com/v3/directline/tokens/generate', { method: 'POST', headers: { Authorization: 'Bearer ' + 'XXXXXX' } });
                const { token } = await res.json();

                window.WebChat.renderWebChat({
                    directLine: window.WebChat.createDirectLine({ token }),
                    store,
                    userID: "User",
                    styleOptions,
                    locale: 'pt-BR',
                    selectVoice: (voices, activity) =>
                        activity.locale === 'pt-BR'
                            ? voices.find(({ name }) => /Daniel/iu.test(name))
                            : voices.find(({ name }) => /Daniel/iu.test(name)) ||
                            voices.find(({ name }) => /Daniel/iu.test(name)),
                    webSpeechPonyfillFactory
                }, document.getElementById('botBody'));
                document.querySelector('#botBody > *').focus();

                var mainTag = chatbot.getElementsByClassName('main')[0];
                mainTag.style.borderTop = chatbot.dataset.cbBorder;
            })().catch(err => console.error(err));

            //Bot Message Exchange Setting 
            const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
                if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
                    dispatch({
                        type: 'WEB_CHAT/SEND_EVENT',
                        payload: {
                            name: 'userName',
                            value: Paul
                        }
                    });
                    dispatch({
                        type: 'WEB_CHAT/SEND_EVENT',
                        payload: {
                            name: 'userGenre',
                            value: male
                        }
                    });
                    dispatch({
                        type: 'WEB_CHAT/SEND_EVENT',
                        payload: {
                            name: 'activityName',
                            value: chatBotMission
                        }
                    });
                }
                return next(action);
            });

        //initLaunchPad ended

        var botContainer = document.createElement('div');
        botContainer.id = "botContainer";

        var botHeader = document.createElement('div');
        botHeader.classList.add('botHeader');

        var botClose = document.createElement('a');
        botClose.id = "botClose";
        botClose.innerText = "X";
        botClose.title = "Close";
        botHeader.innerHTML = "<div><img src='" + chatbot.dataset.cbBotAvatarImage + "'/> <h5>Bit_Bot <small>FTD Educação</small> </div></h5>";
        botHeader.appendChild(botClose);

        botClose.addEventListener('click', function (e) {
            e.preventDefault();
            initLaunchPad.style.display = "";
            botContainer.style.display = "none";
            return false;
        });

        botContainer.appendChild(botHeader);

        var botBody = document.createElement('div');
        botBody.id = "botBody";
        botContainer.appendChild(botBody);

        var poweredBy = document.createElement('div');
        poweredBy.innerHTML = "<small>Powered by <img src='http://ainetw.com/img/icon.png' width=12 /> AI Networks</small>";

        chatbot.appendChild(botContainer);
        chatbot.appendChild(poweredBy);
    </script>

</body>
</html>

我的机器人中机器人发送数据收集的代码片段:

 public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
        {
            var studentProfile = await _studentProfileAccessor.GetAsync(turnContext, () => new StudentProfile(), cancellationToken);
            DialogContext dc = await _dialogs.CreateContextAsync(turnContext, cancellationToken);

            //Bot Channel Message Exchange Collection 
            if (turnContext.Activity.Name == "userName")
            {   
                studentProfile.Name = turnContext.Activity.Value.ToString();                   
                studentName = turnContext.Activity.Value.ToString();
            }
            if (turnContext.Activity.Name == "userGenre")
            {
                studentProfile.Gender = turnContext.Activity.Value.ToString();
                conversationSessionID = turnContext.Activity.From.Id;
                if (conversationSessionID.ToLower() == "user")
                {
                    var myConversationSessionID = turnContext.Activity.Id;
                    if (myConversationSessionID.IndexOf("|") != -1)
                    {
                        conversationSessionID = myConversationSessionID.Substring(0, myConversationSessionID.IndexOf("|"));
                    }
                }
                studentGender = turnContext.Activity.Value.ToString();
        //Variables persistance on DB
                SessionVariable SessionVariable = new SessionVariable();
                SessionVariable.AddSessionVariable(BellaMain.GlobalVariable.SystemID, BellaMain.GlobalVariable.CustomerID, conversationSessionID, "StudentName", studentName, "StudentGender", studentGender, "", "", "", "", "", "", "", "", "", "", "", 0);
            }
            if (turnContext.Activity.Name == "activityName")
            {
                if (turnContext.Activity.Value.ToString().ToLower() =="atividade2")
                {
                    var message = $"**Olá {studentName}, bem vindo ao Quant Bot!**";
                    await turnContext.SendActivityAsync(message);
                    await dc.BeginDialogAsync(Activity2MainDialog, "activity2MainDialog", cancellationToken);
                }
                else
                {
                    var message = $"**Olá {studentName}, bem vindo ao Quant Bot!**";
                    await turnContext.SendActivityAsync(message);                    
                }
            }

该应用程序工作正常,但是当有多个用户连接到它时,交换的数据会多次不匹配,例如
Webclient 1 发送用户名:Paul 和性别:男 ==> app 收到 Paul 和 male
Webclient 2 发送用户名:Mary 和性别:女性 ==> 应用有时会收到 Paul 和男性!?它应该改为接收 Mary 和 female
我有一种感觉,发送的数据在 Azure 或其他地方进行了缓冲,每次启动新的 Web 应用程序机器人实例时都需要 cleared/refreshed。
是否有意义?如何修复?谢谢

在您的示例中,您将 'User' 分配给 userID,这是一个静态字符串。

Assigning userID as a static value is not recommended since this will cause all users to share state. Please see the API userID entry for more information. (source)

从您的代码段中删除用户 ID 部分或将 "User" 更改为动态内容。否则状态将被共享,这意味着用户数据在访问机器人的所有用户之间共享。

userID: "User"

首先,如果您真的这样做了,请不要在您的客户端中通过您的直线授权。这是一个主要的安全问题,您很容易被破坏。

关于您的问题,请考虑生成唯一的 userID 并将其传递到 createDirectLine() 令牌调用中。这样,userID 将被烘焙到令牌中,不会具体成为页面的功能。由于令牌 应该 对每个用户都是唯一的,这应该有助于(如果不能解决)您的用户交叉问题。

如果没有,我建议从您的网络聊天代码中删除直线直接 API 呼叫。在我的例子中,我有自己的令牌生成服务器,我从网络聊天中调用它。当 Web Chat 调用我的服务器的 API 时,令牌服务器会调用 Direct Line。我还在令牌服务器中生成 userID,因此它被烘焙到令牌中,然后返回到 Web Chat 以供使用。

如果这些选项都不能解决您的问题,那么我会仔细查看您在别处提到的外部数据收集。

希望得到帮助!

感谢大家对此的支持。 分享我们如何找到案例的解决方案。 首先,我们删除了 userID: "User" 条目。 所以每个机器人会话都会有自己的随机 ID。 然后我们只创建了一个 'website-to-bot' 数据交换变量。 这将确保所有数据仅在一个浏览器周期内发送。 这似乎是导致我们的应用程序出现问题的原因。 代码片段如下:
var enviromentContextData = 'studentName=&' + 用户名 + '&studentGender=|' + 用户类型 + '|'; //机器人消息交换设置 const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => { 如果(action.type === 'DIRECT_LINE/CONNECT_FULFILLED'){ 派遣({ 类型:'WEB_CHAT/SEND_EVENT', 有效载荷:{ 姓名:'enviromentContextDataPass', 值:环境上下文数据 } });<br> } return 下一个(动作); });