public async Task <ConfirmResult> Recognize(ITurnContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Activity); if (context.Activity.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } IMessageActivity message = context.Activity.AsMessageActivity(); var confirmResult = new ConfirmResult(); var results = model.Parse(message.Text); if (results.Any()) { var result = results.First(); if (bool.TryParse(result.Resolution["value"].ToString(), out bool value)) { confirmResult.Status = PromptStatus.Recognized; confirmResult.Confirmation = value; confirmResult.Text = result.Text; if (Validator != null) { await Validator(context, confirmResult); } } } return(confirmResult); }
/// <summary> /// Process the request from WeChat. /// </summary> /// <param name="wechatRequest">Request message entity from wechat.</param> /// <param name="callback"> Bot callback handler.</param> /// <param name="cancellationToken">Cancellation Token of this Task.</param> /// <returns>Response message entity.</returns> private async Task <object> ProcessWeChatRequest(IRequestMessageBase wechatRequest, BotCallbackHandler callback, CancellationToken cancellationToken) { var activity = await _wechatMessageMapper.ToConnectorMessage(wechatRequest).ConfigureAwait(false); BotAssert.ActivityNotNull(activity); return(await ProcessActivityAsync(activity, callback, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Used to validate the incoming text, expected on context.Activity, is /// valid according to the rules defined in the validation steps. /// </summary> public override async Task <NumberWithUnit> Recognize(ITurnContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Activity); if (context.Activity.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } IMessageActivity message = context.Activity.AsMessageActivity(); NumberWithUnit value = new NumberWithUnit(); var results = _model.Parse(message.Text); if (results.Any()) { var result = results.First(); value.Unit = (string)result.Resolution["unit"]; if (float.TryParse(result.Resolution["value"]?.ToString() ?? String.Empty, out float val)) { value.Status = PromptStatus.Recognized; value.Text = result.Text; value.Value = val; await Validate(context, value); } } return(value); }
/// <summary> /// Used to validate the incoming text, expected on context.Request, is /// valid according to the rules defined in the validation steps. /// </summary> public override async Task <ValueResult> Recognize(IBotContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Request); if (context.Request.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } IMessageActivity message = context.Request.AsMessageActivity(); var results = _model.Parse(message.Text); if (results.Any()) { var result = results.First(); ValueResult value = new ValueResult() { Text = result.Text, Value = (string)result.Resolution["value"] }; if (await Validate(context, value)) { return(value); } } return(null); }
/// <summary> /// Prompt the User to signin if not already signed in for the given connection name. /// </summary> /// <param name="context"></param> /// <param name="activity"></param> /// <returns></returns> public async Task Prompt(ITurnContext context, IMessageActivity activity) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(activity); var adapter = context.Adapter as BotFrameworkAdapter; if (adapter == null) { throw new InvalidOperationException("OAuthPrompt.Prompt(): not supported by the current adapter"); } if (activity.Attachments == null || activity.Attachments.Count == 0) { throw new InvalidOperationException("OAuthPrompt.Prompt(): length of attachments cannot be null"); } var cards = activity.Attachments.Where(a => a.Content is OAuthCard); if (cards.Count() == 0) { throw new InvalidOperationException("OAuthPrompt.Prompt(): at least one of the cards should be an oauth card"); } var replyActivity = MessageFactory.Attachment(cards.First());//todo:send an oauth or signin card based on channel id await context.SendActivity(replyActivity).ConfigureAwait(false); }
//protected ConfirmPrompt(IModel model, PromptValidator<ConfirmResult> validator = null) // : base(validator) //{ // this._model = model; //} public override async Task <ConfirmResult> Recognize(ITurnContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Activity); if (context.Activity.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } IMessageActivity message = context.Activity.AsMessageActivity(); var confirmResult = new ConfirmResult(); Match yesMatch = yes.Match(message.Text); Match noMatch = no.Match(message.Text); if (yesMatch.Success) { confirmResult.Status = PromptStatus.Recognized; confirmResult.Confirmation = true; confirmResult.Text = yesMatch.Value; await Validate(context, confirmResult); } else if (noMatch.Success) { confirmResult.Status = PromptStatus.Recognized; confirmResult.Confirmation = false; confirmResult.Text = noMatch.Value; await Validate(context, confirmResult); } return(confirmResult); }
/// <summary> /// Used to validate the incoming text, expected on context.Request, is /// valid according to the rules defined in the validation steps. /// </summary> /// <param name="context">Context for the current turn of the conversation with the user.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public override async Task <DateTimeResult> RecognizeAsync(ITurnContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Activity); if (context.Activity.Type == ActivityTypes.Message) { var message = context.Activity.AsMessageActivity(); var results = _model.Parse(message.Text); if (results.Any()) { var values = (List <Dictionary <string, string> >)results[0].Resolution["values"]; var dateTimeResult = new DateTimeResult { Status = PromptStatus.Recognized, Text = message.Text, }; foreach (var value in values) { dateTimeResult.Resolution.Add(ReadResolution(value)); } await ValidateAsync(context, dateTimeResult).ConfigureAwait(false); return(dateTimeResult); } } return(new DateTimeResult()); }
#pragma warning restore CA2227 // Collection properties should be read only /// <summary> /// Primary adapter method for processing activities sent from streaming channel. /// Creates a turn context and runs the middleware pipeline for an incoming activity. /// Throws <see cref="ArgumentNullException"/> on null arguments. /// </summary> /// <param name="activity">The <see cref="Activity"/> to process.</param> /// <param name="callbackHandler">The <see cref="BotCallbackHandler"/> that will handle the activity.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A task that represents the work queued to execute. If the activity type /// was 'Invoke' and the corresponding key (channelId + activityId) was found /// then an InvokeResponse is returned, otherwise null is returned.</returns> /// <remarks>Call this method to reactively send a message to a conversation. /// If the task completes successfully, then if the activity's <see cref="Activity.Type"/> /// is <see cref="ActivityTypes.Invoke"/> and the corresponding key /// (<see cref="Activity.ChannelId"/> + <see cref="Activity.Id"/>) is found /// then an <see cref="InvokeResponse"/> is returned, otherwise null is returned. /// <para>This method registers the following services for the turn.<list type="bullet"/></para> /// </remarks> public async Task <InvokeResponse> ProcessStreamingActivityAsync(Activity activity, BotCallbackHandler callbackHandler, CancellationToken cancellationToken = default) { BotAssert.ActivityNotNull(activity); Logger.LogInformation($"Received an incoming streaming activity. ActivityId: {activity.Id}"); // If a StreamingRequestHandler.Audience is a null value, then no callerId should have been generated // and GetAudienceFromCallerId returns null. // Thus we fallback to relying on the "original key", essentially $"{ServiceUrl}{Conversation.Id}", // as opposed to $"{ServiceUrl}{Audience}{Conversation.Id}" and the StreamingRequestHandler implicitly does not support skills. var audience = GetAudienceFromCallerId(activity); // If a conversation has moved from one connection to another for the same Channel or Skill and // hasn't been forgotten by the previous StreamingRequestHandler. The last requestHandler // the conversation has been associated with should always be the active connection. var requestHandler = RequestHandlers.Where( h => h.ServiceUrl == activity.ServiceUrl && h.Audience == audience && h.HasConversation(activity.Conversation.Id)) .LastOrDefault(); using (var context = new TurnContext(this, activity)) { context.TurnState.Add <string>(OAuthScopeKey, audience); // Pipes are unauthenticated. Pending to check that we are in pipes right now. Do not merge to master without that. if (ClaimsIdentity != null) { context.TurnState.Add <IIdentity>(BotIdentityKey, ClaimsIdentity); } using (var connectorClient = CreateStreamingConnectorClient(activity, requestHandler)) { // Add connector client to be used throughout the turn context.TurnState.Add(connectorClient); await RunPipelineAsync(context, callbackHandler, cancellationToken).ConfigureAwait(false); // Cleanup connector client context.TurnState.Set <IConnectorClient>(null); } if (activity.Type == ActivityTypes.Invoke) { var activityInvokeResponse = context.TurnState.Get <Activity>(InvokeResponseKey); if (activityInvokeResponse == null) { return(new InvokeResponse { Status = (int)HttpStatusCode.NotImplemented }); } else { return((InvokeResponse)activityInvokeResponse.Value); } } return(null); } }
/// <summary> /// Used to validate the incoming text, expected on context.Request, is /// valid according to the rules defined in the validation steps. /// </summary> public override async Task <NumberResult <float> > Recognize(IBotContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Request); if (context.Request.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } IMessageActivity message = context.Request.AsMessageActivity(); var results = _model.Parse(message.Text); if (results.Any()) { var result = results.First(); if (float.TryParse(result.Resolution["value"].ToString().TrimEnd('%'), out float value)) { NumberResult <float> numberResult = new NumberResult <float>() { Value = value, Text = result.Text }; if (await Validate(context, numberResult)) { return(numberResult); } } } return(null); }
public async Task ProcessActivty(string authHeader, Activity activity, Func <IBotContext, Task> callback) { BotAssert.ActivityNotNull(activity); await JwtTokenValidation.AssertValidActivity(activity, authHeader, _credentialProvider, _httpClient); await base.ProcessActivityInternal(activity, callback).ConfigureAwait(false); }
/// <summary> /// Primary adapter method for processing activities sent from channel. /// Creates a turn context and runs the middleware pipeline for an incoming activity. /// Throws <see cref="ArgumentNullException"/> on null arguments. /// </summary> /// <param name="activity">The <see cref="Activity"/> to process.</param> /// <param name="callback">The code to run at the end of the adapter's middleware pipeline.</param> /// <param name="cancellationToken">A cancellation token that can be used by other objects /// or threads to receive notice of cancellation.</param> /// <returns>A task that represents the work queued to execute. If the activity type /// was 'Invoke' and the corresponding key (channelId + activityId) was found /// then an InvokeResponse is returned, otherwise null is returned.</returns> /// <remarks>Call this method to reactively send a message to a conversation. /// If the task completes successfully, then if the activity's <see cref="Activity.Type"/> /// is <see cref="ActivityTypes.Invoke"/> and the corresponding key /// (<see cref="Activity.ChannelId"/> + <see cref="Activity.Id"/>) is found /// then an <see cref="InvokeResponse"/> is returned, otherwise null is returned. /// <para>This method registers the following services for the turn.<list type="bullet"/></para> /// </remarks> public async Task <InvokeResponse> ProcessActivityAsync(Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken = default(CancellationToken)) { BotAssert.ActivityNotNull(activity); if (callback == null) { throw new ArgumentNullException(nameof(callback)); } _logger.LogInformation($"Received an incoming activity. ActivityId: {activity.Id}"); using (var context = new TurnContext(this, activity)) { await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false); if (activity.Type == ActivityTypes.Invoke) { var activityInvokeResponse = context.TurnState.Get <Activity>(InvokeReponseKey); if (activityInvokeResponse == null) { return(new InvokeResponse { Status = (int)HttpStatusCode.NotImplemented }); } else { return((InvokeResponse)activityInvokeResponse.Value); } } return(null); } }
public async Task <InvokeResponse> ProcessActivityAsync(Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken) { BotAssert.ActivityNotNull(activity); _logger.LogInformation($"Received an incoming activity. ActivityId: {activity.Id}"); using (var context = new TurnContext(this, activity)) { await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false); // Handle Invoke scenarios, which deviate from the request/response model in that // the Bot will return a specific body and return code. if (activity.Type == ActivityTypes.Invoke) { var activityInvokeResponse = context.TurnState.Get <Activity>(InvokeReponseKey); if (activityInvokeResponse == null) { return(new InvokeResponse { Status = (int)HttpStatusCode.NotImplemented }); } else { return((InvokeResponse)activityInvokeResponse.Value); } } // For all non-invoke scenarios, the HTTP layers above don't have to mess // withthe Body and return codes. return(null); } }
public override async Task <InvokeResponse> ProcessActivityAsync(ClaimsIdentity claimsIdentity, Schema.Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken) { BotAssert.ActivityNotNull(activity); using (var context = new TurnContext(this, activity)) { context.TurnState.Add <IIdentity>(BotIdentityKey, claimsIdentity); context.TurnState.Add(this.config); context.TurnState.Add(callback); await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false); // Handle ExpectedReplies scenarios where the all the activities have been buffered and sent back at once // in an invoke response. if (context.Activity.DeliveryMode == DeliveryModes.ExpectReplies) { return(new InvokeResponse { Status = (int)HttpStatusCode.OK, Body = new ExpectedReplies(context.BufferedReplyActivities) }); } // Handle Invoke scenarios, which deviate from the request/request model in that // the Bot will return a specific body and return code. if (activity.Type == ActivityTypes.Invoke) { return(new InvokeResponse { Status = (int)HttpStatusCode.NotImplemented }); } // For all non-invoke scenarios, the HTTP layers above don't have to mess // with the Body and return codes. return(null); } }
/// <summary> /// Used to validate the incoming text, expected on context.Request, is /// valid according to the rules defined in the validation steps. /// </summary> public override async Task <DateTimeResult> Recognize(ITurnContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Activity); if (context.Activity.Type == ActivityTypes.Message) { var message = context.Activity.AsMessageActivity(); var results = _model.Parse(message.Text); if (results.Any()) { var result = results.First(); if (result.Resolution.Any()) { var dateTimeResult = new DateTimeResult { Status = PromptStatus.Recognized, Text = result.Text }; foreach (var resolution in result.Resolution) { var values = (List <Dictionary <string, string> >)resolution.Value; if (values.Any()) { dateTimeResult.Resolution.Add(ReadResolution(values.First())); await Validate(context, dateTimeResult); return(dateTimeResult); } } } } } return(new DateTimeResult()); }
public override async Task <RangeResult> Recognize(ITurnContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Activity); if (context.Activity.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } RangeResult rangeResult = new RangeResult(); IMessageActivity message = context.Activity.AsMessageActivity(); var results = _model.Parse(message.Text); if (results.Any()) { var result = results.First(); if (result.TypeName == "numberrange") { string[] values = result.Resolution["value"].ToString().Trim('(', ')').Split(','); if (float.TryParse(values[0], out float startValue) && float.TryParse(values[1], out float endValue)) { rangeResult.Status = PromptStatus.Recognized; rangeResult.Text = result.Text; rangeResult.Start = startValue; rangeResult.End = endValue; await Validate(context, rangeResult); } } } return(rangeResult); }
public async Task <InvokeResponse> ProcessActivity(ClaimsIdentity identity, Activity activity, Func <ITurnContext, Task> callback) { BotAssert.ActivityNotNull(activity); using (var context = new TurnContext(this, activity)) { context.Services.Add <IIdentity>("BotIdentity", identity); var connectorClient = await this.CreateConnectorClientAsync(activity.ServiceUrl, identity).ConfigureAwait(false); context.Services.Add <IConnectorClient>(connectorClient); await base.RunPipeline(context, callback).ConfigureAwait(false); // Handle Invoke scenarios, which deviate from the request/response model in that // the Bot will return a specific body and return code. if (activity.Type == ActivityTypes.Invoke) { Activity invokeResponse = context.Services.Get <Activity>(InvokeReponseKey); if (invokeResponse == null) { // ToDo: Trace Here throw new InvalidOperationException("Bot failed to return a valid 'invokeResponse' activity."); } else { return((InvokeResponse)invokeResponse.Value); } } // For all non-invoke scenarios, the HTTP layers above don't have to mess // withthe Body and return codes. return(null); } }
public void TrackCustomEvent(IActivity activity, string eventName = EventTypes.CustomEvent, IDictionary <string, string> properties = null) { BotAssert.ActivityNotNull(activity); var activityAdapter = new ActivityAdapter(activity); activityAdapter.TrackCustomEvent(this.telemetryClient, this.settings, eventName, properties); }
public async Task TrackMessageSentiment(IMessageActivity activity) { BotAssert.ActivityNotNull(activity); var activityAdapter = new ActivityAdapter(activity); await activityAdapter.TrackMessageSentiment(this.telemetryClient, this.settings, this.sentimentClient).ConfigureAwait(false); }
/// <summary> /// Creates a turn context and runs the middleware pipeline for an incoming activity. /// </summary> /// <param name="authHeader">The HTTP authentication header of the request.</param> /// <param name="activity">The incoming activity.</param> /// <param name="callback">The code to run at the end of the adapter's middleware /// pipeline.</param> /// <returns>A task that represents the work queued to execute. If the activity type /// was 'Invoke' and the corresponding key (channelId + activityId) was found /// then an InvokeResponse is returned, otherwise null is returned.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="activity"/> is <c>null</c>.</exception> /// <exception cref="UnauthorizedAccessException"> /// authentication failed.</exception> /// <remarks>Call this method to reactively send a message to a conversation. /// <para>This method registers the following services for the turn.<list type="bullet"> /// <item><see cref="IIdentity"/> (key = "BotIdentity"), a claims identity for the bot.</item> /// <item><see cref="IConnectorClient"/>, the channel connector client to use this turn.</item> /// </list></para> /// </remarks> /// <seealso cref="ContinueConversation(string, ConversationReference, Func{ITurnContext, Task})"/> /// <seealso cref="BotAdapter.RunPipeline(ITurnContext, Func{ITurnContext, Task}, System.Threading.CancellationTokenSource)"/> public async Task <InvokeResponse> ProcessActivity(string authHeader, Activity activity, Func <ITurnContext, Task> callback) { BotAssert.ActivityNotNull(activity); var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _httpClient).ConfigureAwait(false); return(await ProcessActivity(claimsIdentity, activity, callback).ConfigureAwait(false)); }
/// <summary> /// Log an activity to the transcript. /// </summary> /// <param name="activity">Activity being logged.</param> /// <returns>A <see cref="Task"/>A task that represents the work queued to execute.</returns> public async Task LogActivityAsync(IActivity activity) { BotAssert.ActivityNotNull(activity); switch (activity.Type) { case ActivityTypes.MessageUpdate: { var activityAndBlob = await InnerReadBlobAsync(activity).ConfigureAwait(false); if (activityAndBlob.Item1 != null) { var updatedActivity = JsonConvert.DeserializeObject <Activity>(JsonConvert.SerializeObject(activity)); updatedActivity.Type = ActivityTypes.Message; // fixup original type (should be Message) updatedActivity.LocalTimestamp = activityAndBlob.Item1.LocalTimestamp; updatedActivity.Timestamp = activityAndBlob.Item1.Timestamp; await LogActivityToBlobClientAsync(updatedActivity, activityAndBlob.Item2, true).ConfigureAwait(false); } return; } case ActivityTypes.MessageDelete: { var activityAndBlob = await InnerReadBlobAsync(activity).ConfigureAwait(false); if (activityAndBlob.Item1 != null) { // tombstone the original message var tombstonedActivity = new Activity() { Type = ActivityTypes.MessageDelete, Id = activityAndBlob.Item1.Id, From = new ChannelAccount(id: "deleted", role: activityAndBlob.Item1.From.Role), Recipient = new ChannelAccount(id: "deleted", role: activityAndBlob.Item1.Recipient.Role), Locale = activityAndBlob.Item1.Locale, LocalTimestamp = activityAndBlob.Item1.Timestamp, Timestamp = activityAndBlob.Item1.Timestamp, ChannelId = activityAndBlob.Item1.ChannelId, Conversation = activityAndBlob.Item1.Conversation, ServiceUrl = activityAndBlob.Item1.ServiceUrl, ReplyToId = activityAndBlob.Item1.ReplyToId, }; await LogActivityToBlobClientAsync(tombstonedActivity, activityAndBlob.Item2, true).ConfigureAwait(false); } return; } default: var blobName = GetBlobName(activity); var blobClient = _containerClient.Value.GetBlobClient(blobName); await LogActivityToBlobClientAsync(activity, blobClient).ConfigureAwait(false); return; } }
/// <summary> /// Log an activity to the transcript. /// </summary> /// <param name="activity">Activity being logged.</param> /// <returns>A <see cref="Task"/>A task that represents the work queued to execute.</returns> public async Task LogActivityAsync(IActivity activity) { BotAssert.ActivityNotNull(activity); switch (activity.Type) { case ActivityTypes.MessageUpdate: { var blob = await FindActivityBlobAsync(activity).ConfigureAwait(false); if (blob != null) { var originalActivity = JsonConvert.DeserializeObject<Activity>(await blob.DownloadTextAsync().ConfigureAwait(false)); var updatedActivity = JsonConvert.DeserializeObject<Activity>(JsonConvert.SerializeObject(activity)); updatedActivity.Type = ActivityTypes.Message; // fixup original type (should be Message) updatedActivity.LocalTimestamp = originalActivity.LocalTimestamp; updatedActivity.Timestamp = originalActivity.Timestamp; await LogActivityAsync(updatedActivity, blob).ConfigureAwait(false); } return; } case ActivityTypes.MessageDelete: { var blob = await FindActivityBlobAsync(activity).ConfigureAwait(false); if (blob != null) { var originalActivity = JsonConvert.DeserializeObject<Activity>(await blob.DownloadTextAsync().ConfigureAwait(false)); // tombstone the original message var tombstonedActivity = new Activity() { Type = ActivityTypes.MessageDelete, Id = originalActivity.Id, From = new ChannelAccount(id: "deleted", role: originalActivity.From.Role), Recipient = new ChannelAccount(id: "deleted", role: originalActivity.Recipient.Role), Locale = originalActivity.Locale, LocalTimestamp = originalActivity.Timestamp, Timestamp = originalActivity.Timestamp, ChannelId = originalActivity.ChannelId, Conversation = originalActivity.Conversation, ServiceUrl = originalActivity.ServiceUrl, ReplyToId = originalActivity.ReplyToId, }; await LogActivityAsync(tombstonedActivity, blob).ConfigureAwait(false); } return; } default: var blobName = GetBlobName(activity); var blobReference = this.Container.Value.GetBlockBlobReference(blobName); await LogActivityAsync(activity, blobReference).ConfigureAwait(false); return; } }
public async Task Receive(string authHeader, Activity activity) { BotAssert.ActivityNotNull(activity); await JwtTokenValidation.AssertValidActivity(activity, authHeader, _credentialProvider, _httpClient); if (this.OnReceive != null) { await OnReceive(activity).ConfigureAwait(false); } }
public async Task ProcessActivity(string authHeader, Activity activity, Func <IBotContext, Task> callback) { BotAssert.ActivityNotNull(activity); ClaimsIdentity claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _httpClient); // For requests from channel App Id is in Audience claim of JWT token. For emulator it is in AppId claim. For // unauthenticated requests we have anonymouse identity provided auth is disabled. string botAppId = GetBotId(claimsIdentity); var context = new BotFrameworkBotContext(botAppId, this, activity); await base.RunPipeline(context, callback).ConfigureAwait(false); }
public async Task <AlexaResponseBody> ProcessActivity(AlexaRequestBody alexaRequest, AlexaOptions alexaOptions, BotCallbackHandler callback) { TurnContext context = null; try { Options = alexaOptions; var activity = RequestToActivity(alexaRequest); BotAssert.ActivityNotNull(activity); context = new TurnContext(this, activity); if (alexaRequest.Session.Attributes != null && alexaRequest.Session.Attributes.Any()) { context.TurnState.Add("AlexaSessionAttributes", alexaRequest.Session.Attributes); } else { context.TurnState.Add("AlexaSessionAttributes", new Dictionary <string, string>()); } context.TurnState.Add("AlexaResponseDirectives", new List <IAlexaDirective>()); Responses = new Dictionary <string, List <Activity> >(); await base.RunPipelineAsync(context, callback, default(CancellationToken)).ConfigureAwait(false); var key = $"{activity.Conversation.Id}:{activity.Id}"; try { AlexaResponseBody response = null; var activities = Responses.ContainsKey(key) ? Responses[key] : new List <Activity>(); response = CreateResponseFromLastActivity(activities, context); response.SessionAttributes = context.AlexaSessionAttributes(); return(response); } finally { if (Responses.ContainsKey(key)) { Responses.Remove(key); } } } catch (Exception ex) { await alexaOptions.OnTurnError(context, ex); throw; } }
/// <summary> /// Applies all relevant Conversation related identifies to an activity. This effectivly /// couples a blank Activity to a conversation. /// </summary> /// <param name="activity">The activity to update. Existing values in the Activity will be overwritten.</param> /// <param name="reference">The ConversationReference from which to pull the relevant conversation information</param> /// <remarks> /// This method applies the following values from ConversationReference: /// ChannelId /// ServiceUrl /// Conversation /// Bot (assigned to the .From property on the Activity) /// User (assigned to the .Recipient on the Activity) /// ActivityId (assigned as the ReplyToId on the Activity) /// </remarks> public static void ApplyConversationReference(IActivity activity, ConversationReference reference) { BotAssert.ActivityNotNull(activity); BotAssert.ConversationReferenceNotNull(reference); activity.ChannelId = reference.ChannelId; activity.ServiceUrl = reference.ServiceUrl; activity.Conversation = reference.Conversation; activity.From = reference.Bot; activity.Recipient = reference.User; activity.ReplyToId = reference.ActivityId; }
public async Task ProcessActivity(string authHeader, Activity activity, Func <ITurnContext, Task> callback) { BotAssert.ActivityNotNull(activity); var claimsIdentity = await JwtTokenValidation.AuthenticateRequest(activity, authHeader, _credentialProvider, _httpClient); var context = new TurnContext(this, activity); context.Services.Add <IIdentity>("BotIdentity", claimsIdentity); var connectorClient = await this.CreateConnectorClientAsync(activity.ServiceUrl, claimsIdentity); context.Services.Add <IConnectorClient>(connectorClient); await base.RunPipeline(context, callback).ConfigureAwait(false); }
public void TrackCustomEvent( IActivity activity, string eventName = EventTypes.CustomEvent, IDictionary <string, string> properties = null) { BotAssert.ActivityNotNull(activity); var builder = new EventTelemetryBuilder(activity, this.settings, properties); var eventTelemetry = builder.Build(); eventTelemetry.Name = string.IsNullOrWhiteSpace(eventName) ? EventTypes.CustomEvent : eventName; this.telemetryClient.TrackEvent(eventTelemetry); }
public async Task ProcessActivityAsync(Activity activity, string msAppId, ConversationReference conversationRef, BotCallbackHandler callback, CancellationToken cancellationToken) { BotAssert.ActivityNotNull(activity); activity.ApplyConversationReference(conversationRef, true); await ContinueConversationAsync( msAppId, conversationRef, async (ITurnContext proactiveContext, CancellationToken ct) => { using (var contextWithActivity = new TurnContext(this, activity)) { contextWithActivity.TurnState.Add(proactiveContext.TurnState.Get <IConnectorClient>()); await base.RunPipelineAsync(contextWithActivity, callback, cancellationToken); if (contextWithActivity.Activity.Name == "handoff.status") { var conversationStateAccessors = _conversationState.CreateProperty <LoggingConversationData>(nameof(LoggingConversationData)); var conversationData = await conversationStateAccessors.GetAsync(contextWithActivity, () => new LoggingConversationData()); Activity replyActivity; var state = (contextWithActivity.Activity.Value as JObject)?.Value <string>("state"); if (state == "typing") { replyActivity = new Activity { Type = ActivityTypes.Typing, Text = "agent is typing", }; } else if (state == "accepted") { replyActivity = MessageFactory.Text("An agent has accepted the conversation and will respond shortly."); await _conversationState.SaveChangesAsync(contextWithActivity); } else if (state == "completed") { replyActivity = MessageFactory.Text("The agent has closed the conversation."); } else { replyActivity = MessageFactory.Text($"Conversation status changed to '{state}'"); } await contextWithActivity.SendActivityAsync(replyActivity); } } }, cancellationToken).ConfigureAwait(false); }
public void TrackIntent(IActivity activity, RecognizerResult result) { BotAssert.ActivityNotNull(activity); if (result == null) { throw new ArgumentNullException(nameof(result)); } var activityAdapter = new ActivityAdapter(activity); var recognizerResultAdapter = new RecognizerResultAdapter(result); activityAdapter.TrackIntent(recognizerResultAdapter.IntentResult, this.telemetryClient, this.settings); }
public async Task <object> ProcessActivity(Payload actionPayload, BotCallbackHandler callback, string uniqueRequestId = null) { TurnContext context = null; try { var activity = RequestToActivity(actionPayload, uniqueRequestId); BotAssert.ActivityNotNull(activity); context = new TurnContext(this, activity); context.TurnState.Add("GoogleUserId", activity.From.Id); Responses = new Dictionary <string, List <Activity> >(); await base.RunPipelineAsync(context, callback, default(CancellationToken)).ConfigureAwait(false); var key = $"{activity.Conversation.Id}:{activity.Id}"; try { object response = null; var activities = Responses.ContainsKey(key) ? Responses[key] : new List <Activity>(); if (WebhookType == GoogleWebhookType.DialogFlow) { response = CreateDialogFlowResponseFromLastActivity(activities, context); } else { response = CreateConversationResponseFromLastActivity(activities, context); } return(response); } finally { if (Responses.ContainsKey(key)) { Responses.Remove(key); } } } catch (Exception ex) { await OnTurnError(context, ex); throw; } }