How the bot's cards containg qnaid and context behave like QnA test? - botframework

In the test in QnA portal like the below screenshot, those buttons are created by the follow-up prompts from QnA, and when click those buttons, the next Http request contains all the prompts information like text and qnaid. Those the next response will be the answer of the specific qnaid.
But in the Bot -qnamaker-prompting Sampleenter link description here, when click the button, the Http request just contain the text as questions, thus the QnA will not get the answer bind with the qnaid. The answer may will not bind with qnaid and just context.
enter image description here
So anyone have ideas on how to create a bot like QnA test?

Generally, this is how you can get the same returned results generated from the getAnswers() API call as you get from QnA.
First, pass the current context into getAnswers() (which contains the user's message: "help", "Where did trees come from", "Why is the sky blue?", etc.) and then map the result to a variable:
const stepResults = turnContext.context;
let qnaResults = await this.qnaMaker.getAnswers(stepResults);
After validating a response is returned, you can pass the result text into an activity:
await innerDc.prompt('ConfirmPrompt', qnaResults[0].context.prompts[0].displayText);
Logging the above qnaResults[0].context.prompts shows the returned prompt values align with request payload seen in devtools:
With regards to the sample you linked, the prompt value is the returned QnAPrompts[] results (i.e. the follow-up prompt). If a prompt is present in the overall QnA results, it is parsed and displayed as a button. The displayText is coming from that prompt.
public static Activity GetHeroCard(string cardTitle, QnAPrompts[] prompts)
{
var chatActivity = Activity.CreateMessageActivity();
var buttons = new List<CardAction>();
var sortedPrompts = prompts.OrderBy(r => r.DisplayOrder);
foreach (var prompt in sortedPrompts)
{
buttons.Add(
new CardAction()
{
Value = prompt.DisplayText,
Type = ActionTypes.ImBack,
Title = prompt.DisplayText,
});
}
var plCard = new HeroCard()
{
Title = cardTitle,
Subtitle = string.Empty,
Buttons = buttons
};
var attachment = plCard.ToAttachment();
chatActivity.Attachments.Add(attachment);
return (Activity)chatActivity;
}
Hope of help!

Related

Text not wrapping in hero card

Im using a template from MS that allows me to use multi turn in QnA maker. the problem is the text on the hero cards wont wrap. From what i can see of the code the card title and subtitle are dynamically generated dependant on the existence of a prompt in Qna maker.
So far i've looked up on SO and can see the \n\n example but that wont apply in this case. or if it does could anyone help me with the correct syntax. there doesn't seem to be any further advice.
public static Activity GetHeroCard(string cardTitle, QnAPrompts[]
prompts)
{
var chatActivity = Activity.CreateMessageActivity();
var buttons = new List<CardAction>();
var sortedPrompts = prompts.OrderBy(r => r.DisplayOrder);
foreach (var prompt in sortedPrompts)
{
buttons.Add(
new CardAction()
{
Value = prompt.DisplayText,
Type = ActionTypes.ImBack,
Title = prompt.DisplayText,
});
}
var plCard = new HeroCard()
{
Title = cardTitle,
Subtitle = string.Empty,
Buttons = buttons
};
var attachment = plCard.ToAttachment();
chatActivity.Attachments.Add(attachment);
return (Activity)chatActivity;
}
}
so the code creates the card and attaches it to the return message to the user. Can Anyone advise how to wrap the text on the card.
First, you should assign your returned QnA result to the 'text' field, not the 'title' field. If you do so, you should find that there is no character limit. I say 'should' because the number of lines of text a hero card can display is channel specific. At the time of this writing, I know for certain that web chat, Teams, and Facebook do not have a character limit (you will need to test others that interest you).
As I don't know the channel you are trying to display your hero card over, your mileage may vary.
Here is an example of a hero card with the text field taken from the docs. You can read more about hero cards here. You can also reference this official sample from the Botbuilder-Samples repo.
public static HeroCard GetHeroCard()
{
var heroCard = new HeroCard
{
Title = "BotFramework Hero Card",
Subtitle = "Microsoft Bot Framework",
Text = "Build and connect intelligent bots to interact with your users naturally wherever they are," +
" from text/sms to Skype, Slack, Office 365 mail and other popular services.",
Images = new List<CardImage> { new CardImage("https://sec.ch9.ms/ch9/7ff5/e07cfef0-aa3b-40bb-9baa-7c9ef8ff7ff5/buildreactionbotframework_960.jpg") },
Buttons = new List<CardAction> { new CardAction(ActionTypes.OpenUrl, "Get Started", value: "https://learn.microsoft.com/bot-framework") },
};
return heroCard;
}
Hope of help!
First of all hero cards will only let you display two lines of text, so if you want more number of lines to be shown, then I advise you to use adaptive cards. Currently formatting is not supported for hero cards.
public static AdaptiveCard AdaptiveCard(string subtitle)
{
AdaptiveCard card = new AdaptiveCard();
card.Body.Add(new AdaptiveTextBlock()
{
Text = string.IsNullOrEmpty(subtitle) ? string.Empty : subtitle,
Speak =text ,
Wrap = true,
});
return card;
}

Speech services in web chat - text to speech - how to ignore some text in responses

In my web chat, I have my intent handling code responding with some text with embedded hyper-links so the user can click on these from the chat window. This works fine until I enabled speech and now those hyperlinks are being spoken. Is there a markup I can use in my text responses so that the speech services ignore certain text like the hyper-links?
Thanks
Larry
Is there a markup I can use in my text responses so that the speech services ignore certain text like the hyper-links?
You can detect hyperlink from text by using regular expression, and then explicitly specify text to be displayed and text to be spoken like below:
var mes = "For details, please check https://learn.microsoft.com/en-us/azure/cognitive-services/qnamaker/faqs";
var res = "";
if (Regex.Match(mes, #"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?").Success)
{
res = Regex.Replace(mes, #"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", "the link");
}
await context.SayAsync(text: $"{mes}", speak: $"{res}");
Test result:
I would make an IMessagActivityMapper that does checks like that for you. This way it will check every response you send back in one place rather than having to do it everywhere you send a url back.
public sealed class TextToSpeakActivityMapper : IMessageActivityMapper
{
public IMessageActivity Map(IMessageActivity message)
{
// only set the speak if it is not set by the developer.
var channelCapability = new ChannelCapability(Address.FromActivity(message));
if (channelCapability.SupportsSpeak() && string.IsNullOrEmpty(message.Speak))
{
message.Speak = Regex.Replace(message.Text, #"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", "the link");
}
return message;
}
}
Then register it in your Global.asax.cs file:
builder.RegisterType<TextToSpeakActivityMapper>()
.AsImplementedInterfaces()
.SingleInstance();

Mentioning a user in the System.History

I'm trying to add a new comment to a work item which mentions a user, but using the traditional "#adamh" as you would do on the website does not seem to work via the API.
The data updates fine, however the "#adamh" is just plain text, I need to be able to somehow chuck an identity into here. Can anyone point me in the right direction?
Thanks!
A snippet is here
const vsts = require('vso-node-api');
const item = require('vso-node-api/WorkItemTrackingApi')
const ti = require('vso-node-api/interfaces/WorkItemTrackingInterfaces');
// your collection url
const collectionUrl = "https://myArea.visualstudio.com/defaultcollection";
// ideally from config
const token = "helloWorld";
async function run() {
let authHandler = vsts.getPersonalAccessTokenHandler(token);
let connection = new vsts.WebApi(collectionUrl, authHandler);
let itemTracking = await connection.getWorkItemTrackingApi();
//Add all task data to new array
let taskData = await itemTracking.getWorkItems([15795,15796])
let newData = taskData[0]
let wijson = [
{
"op": "add",
"path": "/fields/System.History",
"value": "#adamh"
}
];
const updateItem = itemTracking.updateWorkItem(null, wijson, 15795).catch(err => {
console.log(err)
}).then(() => console.log("updated"))
return newData
}
const express = require('express')
const app = express()
app.get('/', async (req, res) => {
let data = await run()
res.send(data)
})
app.listen(3000, () => console.log('Example app listening on port 3000!'))
You can use the format shown here as part of the text value for your new comment:
...
This will create a mention link to that user. The link text can be the person's name or any other text you choose to put there. An email alert will be sent to the mentioned user if your system is configured to do so (same as in the UI).
To get your users' userid strings, you can follow the method shown here.
You can use the # to notify another team member about the discussion. Simply type # and their name.
It's using the #mention control , the person you #mention will receive an email alert with your comment and a link to the work item, commit, changeset, or shelveset.
There is not any public API shows how this work in VSTS, you could try to use F12 in google browser to track the process. Another workaround is directly using API to send a notification to the user you want to mention at.

Is it possible to launch native apps using Microsoft bot framework?

I am creating a Cortana skill on the Cortana canvas, I have a button.
I wanted to know if it possible to have an 'imback' type of button to open a webpage.
Ye, for example
var message = context.MakeMessage() as IMessageActivity;
message.ChannelData = JObject.FromObject(new
{
action = new { type = "LaunchUri", uri = "skype:echo123?call" }
});
await context.PostAsync(message);
this code will start a call with echo123 user on skype
Reference: https://learn.microsoft.com/en-us/cortana/tutorials/bot-skills/bot-entity-channel-data
You can supply an openUrl to a card action, or even use ChannelData to send a LaunchUri command, deep linking to an application. (I haven't tried this, but I assume 'http://websitename.com' will launch in the Cortana host platform's default browser.)
activity.ChannelData = new {
action = new { type = "LaunchUri", uri = "http://websitename.com"}
};

Is it possible to detect when a user opens the chat window on Facebook?

I'm trying to create a chatbot where in order to avoid the user opening the chat window and not knowing the available options, I want to give some basic instructions when the user opens the chat window.
Is there any trigger available when the user opens a chat window? Maybe then I can check, and if there's not an ongoing conversation I could provide basic instructions.
I did some googling and found nothing about this. Is it possible to do something like this, and if not, is there a way to mitigate this problem, and provide the user with information regarding the chatbot capabilities and supported instructions?
Facebook does not allow bots to initiate a conversation, unlike Skype or other platforms.
There are still some tricks you can do :
Go on the Settings of your Facebook page, then Messaging and check "Show a Messenger Greeting" as below, and write your greeting sentence.
The result will look like this :
You can also set a "Get Started" button to trigger an event.
Here's the doc :
"https://developers.facebook.com/docs/messenger-platform/thread-settings/get-started-button"
You can monitor for two event types: ConversationUpdate and ContactRelationUpdate.
The first one (ConversationUpdate) is called when a user is added or removed from the conversation. So, there's a place where you can introduce available options. It will be each type the new conversation has started. So, it may become annoying, you may add a check - do not show it if the user has been using the bot for some time.
The second (ContactRelationUpdate) is called when a user adds or removes the bot to/from the contacts. In general, it is only called once per user action.
Here's the extract from the Bot-Frameworks examples:
For Node.Js
bot.on('conversationUpdate', function (message) {
// Check for group conversations
if (message.address.conversation.isGroup) {
// Send a hello message when bot is added
if (message.membersAdded) {
message.membersAdded.forEach(function (identity) {
if (identity.id === message.address.bot.id) {
var reply = new builder.Message()
.address(message.address)
.text("Hello everyone!");
bot.send(reply);
}
});
}
// Send a goodbye message when bot is removed
if (message.membersRemoved) {
message.membersRemoved.forEach(function (identity) {
if (identity.id === message.address.bot.id) {
var reply = new builder.Message()
.address(message.address)
.text("Goodbye");
bot.send(reply);
}
});
}
}
});
bot.on('contactRelationUpdate', function (message) {
if (message.action === 'add') {
var name = message.user ? message.user.name : null;
var reply = new builder.Message()
.address(message.address)
.text("Hello %s... Thanks for adding me. Say 'hello' to see some great demos.", name || 'there');
bot.send(reply);
} else {
// delete their data
}
});
For C#
private void HandleMessage(Activity message)
{
if (message.Type == ActivityTypes.ConversationUpdate)
{
if (activity.MembersAdded.Any(m => m.Id == activity.Recipient.Id))
{
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var response = activity.CreateReply();
response.Text = "Hi! I am Bot. Here's what you can do...";
await connector.Conversations.ReplyToActivityAsync(response);
}
}
else if (message.Type == ActivityTypes.ContactRelationUpdate)
{
if (Activity.AsContactRelationUpdateActivity().Action == ContactRelationUpdateActionTypes.Add)
{
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var response = activity.CreateReply();
response.Text = "Hi! I am Bot. Thanks for adding me. Here's what you can do...";
}
}
return null;
}
I think the acid answer is not.
But you can intercept the IConversationUpdateActivity type message to know if the user has added the bot to a conversation. In the C# project template you can find a code block that ask for this message type but do nothing.

Resources