I use Microsoft Bot Framework. From: https://dev.botframework.com/
AND
Microsoft Bot Emulator (V4 Preview) version 4.0.15-alpha. From: https://github.com/microsoft/botframework-emulator
I created a new C# project with "Bot Application" template. I run this project. I launched two entities of the Emulator.
Now I receive the message from the first Emulator entity but I want to send the response to the second Emulator entity. How can I do this?
This is the function where I try to modify the destination (the code that is commented) but does not work.
/// <summary>
/// POST: api/Messages
/// Receive a message from a user and reply to it
/// </summary>
public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
//activity.Recipient.Id = "default-user";
//activity.ServiceUrl = "http://localhost:52234";
//activity.Conversation.Id = "e7bbb310-a93c-11e8-8dcc-7d6fd69e3901|livechat";
//activity.ReplyToId = "6cc291f0-a93d-11e8-9634-9f01a6c082d4";
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
I launched two entities of the Emulator. Now I receive the message from the first Emulator entity but I want to send the response to the second Emulator entity. How can I do this?
Before you write code to send message to another emulator, you need to get the value of ServiceUrl and conversationId etc. And then you could refer to the following code to send message to the specified conversation.
In dialog:
await context.PostAsync($"{this.count++}: You said {activity.Text}");
var userAccount = new ChannelAccount(name: "User", id: "default-user");
var botAccount = new ChannelAccount(name: "Bot", id: "default-bot");
var connector = new ConnectorClient(new Uri("{your_ServiceUrl_here}"));
IMessageActivity message = Activity.CreateMessageActivity();
message.From = botAccount;
message.Recipient = userAccount;
//specify conversationId
message.Conversation = new ConversationAccount(id: "{your_conversationId_here}");
message.Text = $"You said {activity.Text} from emulator1";
message.Locale = "en-Us";
await connector.Conversations.SendToConversationAsync((Activity)message);
context.Wait(MessageReceivedAsync);
Test result:
Related
I have a SMS / Twilio Channel that I'm using to send out a Proactive message to the user. To send the Proactive message I'm calling a API method passing in MySpecialId which is used later in the conversation.
I want to save this MySpecialId into the conversation but at the point I have the MySpecialId the conversation doesn't exist yet, and I don't have a turnContext, so I can't really save it yet.
Is there a way to pass this Id from my API method into the BotCallback? I created a quick example. (Here is the original example I'm using https://github.com/microsoft/BotBuilder-Samples/tree/master/samples/csharp_dotnetcore/16.proactive-messages)
Thanks
[HttpGet("{number}")]
public async Task<IActionResult> Get(string MySpecialId)
{
//For Twillio Channel
MicrosoftAppCredentials.TrustServiceUrl("https://sms.botframework.com/");
var NewConversation = new ConversationReference
{
User = new ChannelAccount { Id = $"+1{PHONENUMBERTOTEXTHERE}" },
Bot = new ChannelAccount { Id = "+1MYPHONENUMBERHERE" },
Conversation = new ConversationAccount { Id = $"+1{PHONENUMBERTOTEXTHERE}" },
ChannelId = "sms",
ServiceUrl = "https://sms.botframework.com/"
};
BotAdapter ba = (BotAdapter)_HttpAdapter;
await ((BotAdapter)_HttpAdapter).ContinueConversationAsync(_AppId, NewConversation, BotCallback, default(CancellationToken));
return new ContentResult()
{
Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
};
}
private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
{
try
{
var MyConversationState = _ConversationState.CreateProperty<MyConversationData>(nameof(MyConversationData));
var ConversationState = await MyConversationState.GetAsync(turnContext, () => new MyConversationData(), cancellationToken);
//********************************************************************************************************************
ConversationState.MySpecialId = //HOW DO I GET MySpecialId FROM THE GET METHOD ABOVE HERE?
//********************************************************************************************************************
await _ConversationState.SaveChangesAsync((turnContext, false, cancellationToken);
await turnContext.SendActivityAsync("Starting proactive message bot call back");
}
catch (Exception ex)
{
this._Logger.LogError(ex.Message);
}
}
I don't believe that you can. Normally, you would do something like this by passing values through Activity.ChannelData, but ChannelData doesn't exist on ConversationReference.
Per comments below, #Ryan pointed out that you can pass data on ConversationAccount.Properties. Note, however, this is currently only available in the C# SDK. I've opened an issue to bring this into the Node SDK, but ETA is unknown at this point.
Instead, I'd suggest using a something more native to C#, like:
Create a ConcurrentDictionary
private ConcurrentDictionary<string, string> _idMap;
Map MySpecialId to Conversation.Id (in your Get function)
_idMap.AddOrUpdate(conversationReference.Conversation.Id, MySpecialId, (key, newValue) => MySpecialId);
Access the MySpecialId from the Activity.Conversation.Id (in BotCallback)
var ConversationState = await MyConversationState.GetAsync(turnContext, () => new MyConversationData(), cancellationToken);
ConversationState.MySpecialId = _idMap.GetValueOrDefault(turnContext.Activity.Conversation.Id);
Save ConversationState
await ConversationState.SaveChangesAsync(turnContext, false, cancellationToken);
There's other ways you could do this and some validation checks you'll need to add, but this should get you started.
I'm just trying to use Twilio to send transaction SMS. I have tried exactly the same code which is provided in the Twilio Documentation
static void Main(string[] args)
{
try
{
// Find your Account Sid and Token at twilio.com/console
const string accountSid = "AC5270abb139629daeb8f3c205ec632155";
const string authToken = "XXXXXXXXXXXXXX";
TwilioClient.Init(accountSid, authToken);
var message = MessageResource.Create(
from: new Twilio.Types.PhoneNumber("+15017122661"),
body: "Body",
to: new Twilio.Types.PhoneNumber("MyNumber")
);
Console.WriteLine(message.Sid);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
in this authToken copy from Twilio console and the TO number is my number which is used to register on Twilio. I also have verified the number in Verified Caller IDs segment in Twilio Console.
From Number initially, I was using the number which is generated by in Twilio Console the Number Belongs to the US but it won't work. After Reading this
Article I used the Exact code provided by Twilio just make the Changes as authToken and TO Number. But still, it won't work.
I have No idea why it Does not Work. is that you Can't Send the message from one country to another country?
As I want to Verify Mobile number by sending code from SMS. so achieve this I'm using
Twilio Verify API here where the Code is generated by Twilio and verified by himself.
this Solve my problem.
TO Send SMS :-
var client = new HttpClient();
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string,string>("via", "sms"),
new KeyValuePair<string,string>("phone_number", "Moblienumber"),
new KeyValuePair<string,string>("country_code", "CountryCode"),
});
// https://api.authy.com/protected/$AUTHY_API_FORMAT/phones/verification/start?via=$VIA&country_code=$USER_COUNTRY&phone_number=$USER_PHONE
HttpResponseMessage response = await client.PostAsync(
"https://api.authy.com/protected/json/phones/verification/start?api_key=" + "Your Key",
requestContent);
// Get the response content.
HttpContent responseContent = response.Content;
// Get the stream of the content.
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// Write the output.
Console.WriteLine(await reader.ReadToEndAsync());
}
return Ok();
To Verify :-
// Create client
var client = new HttpClient();
// Add authentication header
client.DefaultRequestHeaders.Add("X-Authy-API-Key", "Your Key");
// https://api.authy.com/protected/$AUTHY_API_FORMAT/phones/verification/check?phone_number=$USER_PHONE&country_code=$USER_COUNTRY&verification_code=$VERIFY_CODE
HttpResponseMessage response = await client.GetAsync(
"https://api.authy.com/protected/json/phones/verification/check?phone_number=phone_number&country_code=country_code&verification_code=CodeReceivedbySMS ");
// Get the response content.
HttpContent responseContent = response.Content;
// Get the stream of the content.
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// Write the output.
Console.WriteLine(await reader.ReadToEndAsync());
}
return Ok();
I am creating a bot to proactively start a conversation with an account I have never had a previous conversation with. I have created another controller that I am posting to and doing the following steps:
public class OutboundController : ApiController {
public HttpResponseMessage Post([FromUri] int id, [FromBody] OutboundData outboundData) {
MicrosoftAppCredentials.TrustServiceUrl(outboundData.ServiceUrl);
//create conversation
var connector = new ConnectorClient(new Uri(outboundData.ServiceUrl));
var botAccount = new ChannelAccount { Id = outboundData.FromAccountId, Name = outboundData.FromAccountName };
var toAccount = new ChannelAccount { Id = outboundData.ToAccountId, Name = outboundData.ToAccountName };
if(!MicrosoftAppCredentials.IsTrustedServiceUrl(outboundData.ServiceUrl)) {
throw new Exception("service URL is not trusted!");
}
var conversationResponse = connector.Conversations.CreateDirectConversation(botAccount, toAccount);
var client = new BuslogicClient();
var confirmData = client.GetOutboundData(id);
var greetingMessage = CreateGreetingMessage(confirmData);
var convoMessage = Activity.CreateMessageActivity();
convoMessage.Text = greetingMessage;
convoMessage.From = botAccount;
convoMessage.Recipient = toAccount;
convoMessage.Conversation = new ConversationAccount(id: conversationResponse.Id);
convoMessage.Locale = "en-Us";
connector.Conversations.SendToConversationAsync((Activity)convoMessage);
string message = string.Format("I received correlationid:{0} and started conversationId:{1}", id, conversationResponse.Id);
var response = Request.CreateResponse(HttpStatusCode.OK, message);
return response;
}
When I call connector.Conversations.CreateDirectConversation I am getting the following exception: Additional information: Authorization for Microsoft App ID [ID] failed with status code Unauthorized and reason phrase 'Unauthorized'. If I do this with appId and password blank everything works fine in the channel emulator. I've tried providing the MicrosoftAppCredentials to the constructor of the ConnectorClient, but that has no affect. I've read on other threads that the service URL must be trusted so I used MicrosoftAppCredentials.TrustServiceUrl.
versions I am using:
BotBuilder 3.5.3
Channel Emulator 3.0.0.59
The use-case for my bot is to post to the outbound controller with some user info to create a proactive message to be sent out (specifically SMS). If the user responds to my message it will be intercepted by the messages controller and passed to my dialogs for further processing and conversation responses on that same channel.
I've also taken a look at: https://github.com/Microsoft/BotBuilder/issues/2155 but don't quite understand solution described in the comments or if it even pertains to the issue I'm trying to solve.
Any suggestions or help would be appreciated!
You need to pass credentials explicitly to connector:
var credentials = new MicrosoftAppCredentials("YoursMicrosoftAppId", "YoursMicrosoftAppPassword");
var connector = new ConnectorClient(serviceUrl, credentials);
How can I send a message to the user without the user sending me a message? Like for example CNN bot is sending messages every day in the morning by itself. How can I do that in the bot framework?
See this.
In fact, you do not strictly need to receive a message from the user first, but addressing manually can be error-prone (you have to know the user's and bot's channel account, the service URL, etc.)
And in turn (per #thegaram's message), that only works for some channels. For example, Skype requires that the user contact the bot before the bot can message the user.
Once contacted, you can store the user's channelAccount data once they contact you and use that to send them proactive messages. For example if the user has subscribed to hear sports scores for a particular team over time.
Any sort of unsolicited spam messages of course are prohibited by the policies of the Bot Framework (and most of the channels).
Yes you can do that. We called it Greeting from Bot. I have done it and sharing a sample code with you.
Write this code in your messageController or first dialog used in bot.
if (activity.Text == null)
{
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
Activity isActivityTyping = activity.CreateReply();
isActivityTyping.Type = ActivityTypes.Typing;
await connector.Conversations.ReplyToActivityAsync(isActivityTyping);
await Conversation.SendAsync(activity, () => new Dialogs.GreetDialog());
}
after this code you need to create a dialog GreetDialog. Below is the cs file code for your reference.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Connector;
namespace GPP.Bot.Dialogs
{
[Serializable]
internal class GreetDialog : IDialog<object>
{
public async Task StartAsync(IDialogContext context)
{
context.Wait(Greeting);
}
private async Task Greeting(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var message = await argument;
if (string.IsNullOrEmpty(message.Text))
{
// Hero Card
var cardMsg = context.MakeMessage();
var attachment = BotWelcomeCard("Hello, I am a bot. Right now I am on training and in a prototype state", "");
cardMsg.Attachments.Add(attachment);
await context.PostAsync(cardMsg);
context.Call<object>(new ActionDialog(), AfterGreetingDialogCompleted);
}
else
{
context.Call<object>(new ActionDialog(), AfterGreetingDialogCompleted);
}
}
private static Attachment BotWelcomeCard(string responseFromQNAMaker, string userQuery)
{
var heroCard = new HeroCard
{
Title = userQuery,
Subtitle = "",
Text = responseFromQNAMaker,
Images = new List<CardImage> { new CardImage("https://i2.wp.com/lawyerist.com/lawyerist/wp-content/uploads/2016/08/docubot.gif?fit=322%2C294&ssl=1") },
Buttons = new List<CardAction> { new CardAction(ActionTypes.ImBack, "Show Menu", value: "Show Bot Menu") }
};
return heroCard.ToAttachment();
}
private async Task AfterGreetingDialogCompleted(IDialogContext context, IAwaitable<object> result)
{
context.Done<object>(new object());
}
}
}
this is a working code. Do let me know in case you face ant issue.
~cheers :)
Updated
I am developing a Skype bot with 1:1 conversation with Bot Framework.
In that I have a WebHook method which will call from an external service and sends message to my bot, then my bot will send that message to a skype user.
The following code is for v1 in message controller along with api/messages post method
public async Task<Message> Post([FromBody]Message message){}
[Route("~/api/messages/hook")]
[HttpPost]
public async Task<IHttpActionResult> WebHook([FromBody]WebHookMessage message)
{
if (message.Type == "EmotionUpdate")
{
const string fromBotAddress = "<Skype Bot ID here>";
const string toBotAddress = "<Destination Skype name here>";
var text = resolveEmoji(message.Data);
using (var client = new ConnectorClient())
{
var outMessage = new Message
{
To = new ChannelAccount("skype", address: toBotAddress , isBot: false),
From = new ChannelAccount("skype", address: $"8:{fromBotAddress}", isBot: true),
Text = text,
Language = "en",
};
await client.Messages.SendMessageAsync(outMessage);
}
}
return Ok();
}
I will call above WebHook from another service, so that my bot will send messages to the respective skype user.
Can anyone please help me how can I achieve the same in V3 bot framework?
I tried the following but not working
const string fromBotAddress = "Microsoft App ID of my bot";
const string toBotAddress = "skype username";
WebHookMessage processedData = JsonConvert.DeserializeObject<WebHookMessage>(message);
var text = resolveEmoji(processedData.Data);
using (var client = new ConnectorClient(new Uri("https://botname.azurewebsites.net/")
, "Bot Microsoft App Id", "Bot Microsoft App secret",null))
{
var outMessage = new Activity
{
ReplyToId = toBotAddress,
From = new ChannelAccount("skype", $"8:{fromBotAddress}"),
Text = text
};
await client.Conversations.SendToConversationAsync(outMessage);
}
But it is not working, finally what I want to achieve is I want my bot send a message to a user any time how we will send message to a person in skype.
The following code works, but there are some things that are not that obvious that I figured out (tested on Skype channel)
When a user interacts with the bot the user is allocated an id that can only be used from a specific bot..for example: I have multiple bots each using a skype channel. When I send a message from my skype user to bot A the id is different than for bot B. In the previous version of the bot framework I could just send a message to my real skype user id, but not anymore. In a way it simplifies the whole process because you only need the recipient's id and the framework takes care of the rest, so you don't have to specify a sender or bot Id (I guessed all that is linked behind the scenes)
[Route("OutboundMessages/Skype")]
[HttpPost]
public async Task<HttpResponseMessage> SendSkypeMessage(SkypePayload payload)
{
using (var client = new ConnectorClient(new Uri("https://skype.botframework.com")))
{
var conversation = await client.Conversations.CreateDirectConversationAsync(new ChannelAccount(), new ChannelAccount(payload.ToSkypeId));
IMessageActivity message = Activity.CreateMessageActivity();
message.From = new ChannelAccount();
message.Recipient = new ChannelAccount(payload.ToSkypeId);
message.Conversation = new ConversationAccount { Id= conversation.Id };
message.Text = payload.MessageBody;
await client.Conversations.SendToConversationAsync((Activity)message);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
I'm not sure I understand what you're trying to do. If you'd like to answer a message (activity), try something like this:
ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var reply = activity.createReply(text, "en");
await connector.Conversations.ReplyToActivityAsync(reply);
Activity.createReply switches the From and Recipient fields from the incoming activity. You can also try setting these field manually.
UPDATE
You need to create a ConnectorClient to the Skype Connector Service, not to your bot! So try with the Uri http://skype.botframework.com it might work.
However, I don't think you can message a user on Skype without receiving a message from it in the first place (i.e. your bot needs to be added to the user's contacts). Once you have an incoming message from the user, you can use it the create replies, just as described above.
WebHookMessage processedData = JsonConvert.DeserializeObject<WebHookMessage>(message);
var text = resolveEmoji(processedData.Data);
var client = new ConnectorClient(new Uri(activity.serviceUrl));
var outMessage = activity.createReply(text);
await client.Conversations.SendToConversationAsync(outMessage);
activity is a message received from the given user earlier. In this case, activity.serviceUrl should be http://skype.botframework.com, but generally you should not rely on this.
You can try to create the activity (outMessage) manually; for that, I'd recommend inspecting the From and Recipient fields of a message coming from a Skype user and setting these fields accordingly. However, as mentioned before, your bot needs to be added to the user's contacts, so at this point it will have received a message from the user.