BotFramework-Composer
BotFramework-Composer copied to clipboard
Wrap the text in the button of QnAmaker hero card
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
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 } } } ] } ] }
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:
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):
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.
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 }
}
}
}
}
]
}
]
}
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 ?
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).
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, thanks for your idea, that helps a lot! Here is the codes for the developper who has the same question in Bot Composer :
-
open the script in path
YourProject/node_modules/botbuilder-ai/lib/qnaCardBuilder.js"
-
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 -
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 -
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 -
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)
-
Save the script and restart the bot in composer.
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:
- In Bot Composer, click Bot Responses
- Click Common
- Click the main dialog (suppose your QnA is in the dialog)
- Click Show Code
- 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):
-
Click Create in the left navigation panel
-
Click QnA Intent Recognized trigger
-
In the Dialog canvas, select the **Prompt for Text" action (currently it uses SuggestedAction)
-
In the Properties pane, in the Bot Response part, click Show code
-
Replace the code with below content
[Activity
Attachments = ${json(getResponseWithPrompts(@answer, turn.recognized.answers[0].context.prompts))}
]
The UI sample in my composer:
With above steps, you will see Composer and Teams can proper wrapped text with imback type
In Composer Web Chat

In Teams
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.