BotFramework-Composer icon indicating copy to clipboard operation
BotFramework-Composer copied to clipboard

Wrap the text in the button of QnAmaker hero card

Open Levis0045 opened this issue 2 years ago • 7 comments

Is your feature request related to a problem? Please describe.

When active learning is triggered, the QnAmaker hero card can not wrap the text in the buttons with (...). This behavior don't allow us to completely see the question returned.

Describe the solution you'd like

We would like to able wrap the text in the button. We also want some options to control the behavior of this hero card. Actually all is done automatically.

Describe alternatives you've considered

Something which could be better is to have manual control of this bahavior.

Additional context

  • ActiveLearning functionality
  • QnAmaker hero card

MicrosoftTeams-image (3)

MicrosoftTeams-image (4)

Capture du 2022-03-07 15-20-17

Levis0045 avatar Mar 07 '22 14:03 Levis0045

Hi, is there a way to override the card sent by the QnA maker component? I don't think Hero cards supprot "text wrap" on buttons which mean that the workaround is to use an Adaptive Card instead - Here is an example to do that:

{ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.3", "body": [ { "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": "Please select an option" } ] }, { "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": "Option 1 - Click on this text to submit your action - This text will be wrapped to the next line automatically ", "selectAction": { "type": "Action.Submit", "data": { "response": 1 } } } ] }, { "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": "Option 2 - Click on this text to submit your action - This text will be wrapped to the next line automatically ", "selectAction": { "type": "Action.Submit", "data": { "response": 2 } } } ] } ] }

timoleo23 avatar Mar 10 '22 10:03 timoleo23

Hi @timoleo23 , thanks for your answer. But in composer, we have to use the type "imback" to continue de qna dialog (otherwise we have to change too much codes in module package), do you know how to add "imback" in adaptive card ? Because we have this error with your example + imback: image We would like to have another example of adaptive card with "imback", thanks for your help! PS: With idea of this issue: https://github.com/microsoft/BotFramework-WebChat/issues/616 , we use actually a carousel for those suggestion cards(because imback is automatically in hero card): image it's better than before but the UI is not friendly to the users, so we still want to find a solution with adaptive card.

tingting0118 avatar Mar 11 '22 15:03 tingting0118

Hi @tingting0118 , you can use this specific format that only works with Adaptive Cards for Microsoft Teams. Here, you can control the message back displayed to the user and the value returned to the bot. Documentation is here - https://docs.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/cards/cards-actions?tabs=json#adaptive-cards-with-messageback-action

{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.4",
    "body": [
        {
            "type": "RichTextBlock",
            "inlines": [
                {
                    "type": "TextRun",
                    "text": "Please select an option"
                }
            ]
        },
        {
            "type": "RichTextBlock",
            "inlines": [
                {
                    "type": "TextRun",
                    "text": "Option 1 - Click on this text to submit your action - This text will be wrapped to the next line automatically ",
                    "selectAction": {
                        "type": "Action.Submit",
                        "data": {
                            "response": 1
                        }
                    }
                }
            ]
        },
        {
            "type": "RichTextBlock",
            "inlines": [
                {
                    "type": "TextRun",
                    "text": "Option 2 - Click on this text to submit your action - This text will be wrapped to the next line automatically ",
                    "selectAction": {
                        "type": "Action.Submit",
                        "title": "Click me for messageBack",
                        "data": {
                            "msteams": {
                                "type": "messageBack",
                                "displayText": "I clicked this button",
                                "text": "text to bots",
                                "value": { "response" : 2 }
                            }
                        }
                    }
                }
            ]
        }
    ]
}

timoleo23 avatar Mar 14 '22 09:03 timoleo23

Hi @timoleo23, thanks for this response.

But the problem there is Bot Composer Interface. Your suggestion requiert for us to update the internal code of Microsoft libraries (npm packages). We have implemented your suggestion, but this type messageBack requiert a value or imBack type doesn't requiert a value. imBack type respond to this problem, the question is how can we use it with wrap text ? How can we update the library to implement it ?

MicrosoftTeams-image (7)

Do you have a zip example of your projet that we can test with ? Please consider the fact that we work with Bot Framework Composer sofware (Ubuntu version) not with Bot services (with native typescript code).

Levis0045 avatar Mar 15 '22 10:03 Levis0045

Here is the Adaptive Card format with imBack However, I don't know if we can supercharge the built-in QnA maker component in Bot Composer and I'd differ this question to the Microsoft support team.

{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.4",
    "body": [
        {
            "type": "RichTextBlock",
            "inlines": [
                {
                    "type": "TextRun",
                    "text": "Please select an option"
                }
            ]
        },
        {
            "type": "RichTextBlock",
            "inlines": [
                {
                    "type": "TextRun",
                    "text": "Option 1 - Click on this text to submit your action - This text will be wrapped to the next line automatically ",
                    "selectAction": {
                        "type": "Action.Submit",
                        "data": {
                            "response": 1
                        }
                    }
                }
            ]
        },
        {
            "type": "RichTextBlock",
            "inlines": [
                {
                    "type": "TextRun",
                    "text": "Option 2 - Click on this text to submit your action - This text will be wrapped to the next line automatically ",
                    "selectAction": {
                        "type": "Action.Submit",
                        "title": "Click me for messageBack",
                        "data": {
                            "msteams": {
                                "type": "imBack",
                                "title": "More",
                                "value": "Show me more"
                            }
                        }
                    }
                }
            ]
        }
    ]
}

timoleo23 avatar Mar 15 '22 14:03 timoleo23

@timoleo23, thanks for your idea, that helps a lot! Here is the codes for the developper who has the same question in Bot Composer :

  1. open the script in path YourProject/node_modules/botbuilder-ai/lib/qnaCardBuilder.js"

  2. Just modify the function getSuggestionsCard(suggestionsList, cardTitle, cardNoMatchText) -> option 1.1 - Adaptive Card for Teams /!\ That will not work in Composer when you test, but it will work with Teams

  3. Here is the code to change: static getSuggestionsCard(suggestionsList, cardTitle, cardNoMatchText) { if (!Array.isArray(suggestionsList)) { throw new Error('Missing suggestionsList'); } if (!cardTitle) { throw new Error('Missing cardTitle'); } if (!cardNoMatchText) { throw new Error('Missing cardNoMatchText'); } const cardls=[ { "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": cardTitle, "weight": "Bolder" } ] }]; suggestionsList.forEach((suggestion) => { cardls.push({ "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": "👉 " + suggestion, "selectAction": { "type": "Action.Submit", "title": suggestion, "data": { "msteams": { "type": "imBack", "title": suggestion, "value": suggestion } } } }] }); }); cardls.push({ "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": "❗ " + cardNoMatchText, "selectAction": { "type": "Action.Submit", "title": cardNoMatchText, "data": { "msteams": { "type": "imBack", "title": cardNoMatchText, "value": cardNoMatchText } } } } ] }); const card=botbuilder_core_1.CardFactory.adaptiveCard({ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.2", "body": cardls}); const message = botbuilder_core_1.MessageFactory.attachment(card); return message; } -> option 1.2 - Adaptive Card for WebChat

  4. Here is the code to change: static getSuggestionsCard(suggestionsList, cardTitle, cardNoMatchText) { if (!Array.isArray(suggestionsList)) { throw new Error('Missing suggestionsList'); } if (!cardTitle) { throw new Error('Missing cardTitle'); } if (!cardNoMatchText) { throw new Error('Missing cardNoMatchText'); } const cardls=[ { "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": cardTitle, "weight": "Bolder" } ] }]; suggestionsList.forEach((suggestion) => { cardls.push({ "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": "👉 " + suggestion, "selectAction": { "type": "Action.Submit", "title": suggestion, "data": suggestion } } ] }); }); cardls.push({ "type": "RichTextBlock", "inlines": [ { "type": "TextRun", "text": "❗ " + cardNoMatchText, "selectAction": { "type": "Action.Submit", "title": cardNoMatchText, "data": cardNoMatchText } } ] }); const card=botbuilder_core_1.CardFactory.adaptiveCard({ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "type": "AdaptiveCard", "version": "1.2", "body": cardls}); const message = botbuilder_core_1.MessageFactory.attachment(card); return message; } -> option 2 - Carousel

  5. codes to modify: const cardlist=[]; suggestionsList.forEach((suggestion) => { cardlist.push(botbuilder_core_1.CardFactory.heroCard(undefined, suggestion,undefined, [{ value: suggestion, type: 'imBack', title: "Ask it", }])); }); cardlist.push(botbuilder_core_1.CardFactory.heroCard(undefined,undefined,[{ value: cardNoMatchText, type: 'imBack', title: cardNoMatchText, }])); const message = botbuilder_core_1.MessageFactory.carousel(cardlist,cardTitle)

  6. Save the script and restart the bot in composer.

tingting0118 avatar Mar 16 '22 10:03 tingting0118

To display wrapped QnA prompts text in .Net Composer Project, can consider updating Language Generation (bot response) to display proper adaptive card for WebChat & Teams, and then modify the response action in QnA Maker dialog canvas.

I can make it work with below are detailed steps:

  1. In Bot Composer, click Bot Responses
  2. Click Common
  3. Click the main dialog (suppose your QnA is in the dialog)
  4. Click Show Code
  5. Paste below three sections LG code into the Editor one by one
# getResponseWithPrompts(answer, prompts)
-```
{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "version": "1.2",
    "type": "AdaptiveCard",
    "body": [
        {
            "type": "TextBlock",
            "text": "${answer}",
            "wrap": true
        }
    ,   
       ${getButtonList(prompts)}
    ]
}```

# getButtonList(prompts)
- ${join(foreach(prompts, u, if(turn.Activity.channelId == 'msteams' ,getButtonWrapTextItemTeams(u.displayText, u.id) ,getButtonWrapTextItemWeb(u.displayText, u.id))), ',')}
# getButtonWrapTextItemWeb(value, id)
-```
{
            "type": "RichTextBlock",
            "inlines": [
                {
                    "type": "TextRun",
                    "text": "${value}",
                    "selectAction": {
                        "id": "${id}",
                        "type": "Action.Submit",
                        "data": "${value}"
                    }
                }
            ]
}```
# getButtonWrapTextItemTeams(value, id)
-```
{
            "type": "RichTextBlock",
            "inlines": [
                {
                    "type": "TextRun",
                    "text": "${value}",
                    "selectAction": {
                        "type": "Action.Submit",
                        "title": "Click me for messageBack",
                        "data": {
                            "msteams": {
                                "type": "imBack",
                                "title": "More",
                                "value": "${value}"
                            }
                        }
                    }
                }
            ]
        }```

A UI sample in my composer when I update the common LG (bot responses): image

  1. Click Create in the left navigation panel

  2. Click QnA Intent Recognized trigger

  3. In the Dialog canvas, select the **Prompt for Text" action (currently it uses SuggestedAction)

  4. In the Properties pane, in the Bot Response part, click Show code

  5. Replace the code with below content

[Activity

    Attachments = ${json(getResponseWithPrompts(@answer, turn.recognized.answers[0].context.prompts))}

]

The UI sample in my composer:

image

With above steps, you will see Composer and Teams can proper wrapped text with imback type

In Composer Web Chat

In Teams image

When I work on this method, also referred one previous discussion https://github.com/microsoft/botbuilder-dotnet/issues/5149, after some modification, its main part can work well in current composer version QnA.

freistli avatar Apr 21 '22 03:04 freistli