public async Task <DialogResult> Continue(TurnContext context, object state) { BotAssert.ContextNotNull(context); if (state == null) { throw new ArgumentNullException(nameof(state)); } // Create empty dialog set and ourselves to it var dialogs = new DialogSet(); dialogs.Add("control", (IDialog)this); // Start the control var cdc = dialogs.CreateContext(context, state); await cdc.Continue(); return(cdc.DialogResult); }
internal override async Task <RecognizerResult> RecognizeInternalAsync(ITurnContext turnContext, HttpClient httpClient, CancellationToken cancellationToken) { BotAssert.ContextNotNull(turnContext); if (turnContext.Activity == null || turnContext.Activity.Type != ActivityTypes.Message) { return(null); } var utterance = turnContext.Activity.AsMessageActivity()?.Text; RecognizerResult recognizerResult; LuisResult luisResult = null; if (string.IsNullOrWhiteSpace(utterance)) { recognizerResult = new RecognizerResult { Text = utterance }; } else { luisResult = await GetLuisResultAsync(utterance, httpClient, cancellationToken).ConfigureAwait(false); recognizerResult = BuildRecognizerResultFromLuisResult(luisResult, utterance); } var traceInfo = JObject.FromObject( new { recognizerResult, luisModel = new { ModelID = Application.ApplicationId, }, luisOptions = PredictionOptions, luisResult, }); await turnContext.TraceActivityAsync("LuisRecognizer", traceInfo, LuisTraceType, LuisTraceLabel, cancellationToken).ConfigureAwait(false); return(recognizerResult); }
/// <summary> /// identifies intent /// </summary> /// <param name="innerDc"></param> /// <returns></returns> private async Task <DialogTurnResult> StartAsync(DialogContext innerDc) { BotAssert.ContextNotNull(innerDc.Context); string response = string.Empty; var message = innerDc.Context.Activity; string intent = await Utilities.PredictSalutationIntent(lstIntentUtterance, message.Text); if (!string.IsNullOrEmpty(intent)) { switch (intent) { case Constants.Greetings: GreetingHandler(out response, message); break; case Constants.IntentWelcome: case Constants.IntentClosurePositive: case Constants.IntentClosureNegative: GetWelcomeClosureResponse(out response, intent); break; } await innerDc.Context.SendActivityAsync(response.Replace("<FirstName>", innerDc.Context.Activity.From.Name)); // sql logging //TaskResult taskResult = new TaskResult() //{ // Category = CategoryType.Salutation, // ModelName = "SalutationQnA.csv", // Intent = intent, // Entity = string.Empty, // Response = response, // ResponseType = BotResponseType.ValidResponse, // Score = 1, // Source = string.IsNullOrEmpty(response) ? CategoryType.Salutation : CategoryType.BotResponse //}; //await _loggerRepository.InsertBotLogAsync(innerDc.Context.Activity, taskResult); return(await innerDc.EndDialogAsync(result : true)); } return(await innerDc.EndDialogAsync(result : false)); }
/// <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 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(x => x.ServiceUrl == activity.ServiceUrl).Where(y => y.HasConversation(activity.Conversation.Id)).LastOrDefault(); using (var context = new TurnContext(this, activity)) { // 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); } var connectorClient = CreateStreamingConnectorClient(activity, requestHandler); context.TurnState.Add(connectorClient); await RunPipelineAsync(context, callbackHandler, cancellationToken).ConfigureAwait(false); 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); } }
public async Task ReceiveActivity(IBotContext context, MiddlewareSet.NextDelegate next) { BotAssert.ContextNotNull(context); var intents = await this.Recognize(context); var result = new IntentRecognition(); if (intents.Count != 0) { result.Intents = intents; var topIntent = FindTopIntent(intents); if (topIntent.Score > 0.0) { result.TopIntent = topIntent; } } context.Set((IRecognizedIntents)result); await next().ConfigureAwait(false); }
/// <summary> /// Log an activity to the transcript. /// </summary> /// <param name="activity">Activity being logged.</param> /// <returns></returns> public async Task LogActivity(IActivity activity) { BotAssert.ActivityNotNull(activity); var blobName = GetBlobName(activity); var blobReference = this.Container.Value.GetBlockBlobReference(blobName); blobReference.Properties.ContentType = "application/json"; blobReference.Metadata["FromId"] = activity.From.Id; blobReference.Metadata["RecipientId"] = activity.Recipient.Id; blobReference.Metadata["Timestamp"] = activity.Timestamp.Value.ToString("O"); using (var blobStream = await blobReference.OpenWriteAsync()) { using (var jsonWriter = new JsonTextWriter(new StreamWriter(blobStream))) { jsonSerializer.Serialize(jsonWriter, activity); } } await blobReference.SetMetadataAsync(); }
public async override Task Send(IList <IActivity> activities) { BotAssert.ActivityListNotNull(activities); foreach (Activity activity in activities) { if (activity.Type == "delay") { // The Activity Schema doesn't have a delay type build in, so it's simulated // here in the Bot. This matches the behavior in the Node connector. int delayMs = (int)activity.Value; await Task.Delay(delayMs).ConfigureAwait(false); } else { var connectorClient = new ConnectorClient(new Uri(activity.ServiceUrl), _credentials); await connectorClient.Conversations.SendToConversationAsync(activity).ConfigureAwait(false); } } }
private async Task ContextCreatedInternal(IBotContext context, IContextCreated[] middleware) { BotAssert.MiddlewareNotNull(middleware); if (middleware.Length == 0) // No middleware to run. { return; } async Task next() { // Remove the first item from the list of middleware to call, // so that the next call just has the remaining items to worry about. IContextCreated[] remainingMiddleware = middleware.Skip(1).ToArray(); await ContextCreatedInternal(context, remainingMiddleware).ConfigureAwait(false); } // Grab the current middleware, which is the 1st element in the array, and execute it await middleware[0].ContextCreated(context, next).ConfigureAwait(false); }
public async Task OnProcessRequest(ITurnContext context, MiddlewareSet.NextDelegate next) { BotAssert.ContextNotNull(context); var intents = await this.Recognize(context); var result = new IntentRecognition(); if (intents.Count != 0) { result.Intents = intents; var topIntent = FindTopIntent(intents); if (topIntent.Score > 0.0) { result.TopIntent = topIntent; } } context.Services.Add((IRecognizedIntents)result); await next().ConfigureAwait(false); }
public void TrackIntent(IActivity activity, RecognizerResult result) { BotAssert.ActivityNotNull(activity); if (result == null) { throw new ArgumentNullException(nameof(result)); } var topScoringIntent = result.GetTopScoringIntent(); var properties = new Dictionary <string, string> { { IntentConstants.Intent, topScoringIntent.intent }, { IntentConstants.Score, topScoringIntent.score.ToString(CultureInfo.InvariantCulture) }, { IntentConstants.Entities, result.Entities.ToString(Formatting.None) } }; this.TrackIntent(activity, properties); }
/// <summary> /// Recognizes and validates the user input. /// </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 <AttachmentResult> RecognizeAsync(ITurnContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Activity); var attachmentResult = new AttachmentResult(); if (context.Activity.Type == ActivityTypes.Message) { var message = context.Activity.AsMessageActivity(); if (message.Attachments != null) { attachmentResult.Status = PromptStatus.Recognized; attachmentResult.Attachments.AddRange(message.Attachments); await ValidateAsync(context, attachmentResult); } } return(attachmentResult); }
public async Task OnTurn(ITurnContext context, MiddlewareSet.NextDelegate next) { BotAssert.ContextNotNull(context); var logCategoryStates = new List <LogCategoryState>(); logCategoryStates.Add(new LogCategoryState { Name = "Working out" }); logCategoryStates.Add(new LogCategoryState { Name = "Biking" }); logCategoryStates.Add(new LogCategoryState { Name = "Reading" }); context.Services.Add <IList <LogCategoryState> >(logCategoryStates); await next().ConfigureAwait(false); }
public async Task ProcessActivity(DirectMessageEvent obj, BotCallbackHandler callback) { TurnContext context = null; try { var activity = RequestToActivity(obj); BotAssert.ActivityNotNull(activity); context = new TurnContext(this, activity); await RunPipelineAsync(context, callback, default).ConfigureAwait(false); } catch (Exception ex) { await OnTurnError(context, ex); throw; } }
public async Task OnTurnAsync(ITurnContext context, NextDelegate nextTurn, CancellationToken cancellationToken) { BotAssert.ContextNotNull(context); var intents = await this.Recognize(context); var result = new IntentRecognition(); if (intents.Count != 0) { result.Intents = intents; var topIntent = FindTopIntent(intents); if (topIntent.Score > 0.0) { result.TopIntent = topIntent; } } context.TurnState.Add((IRecognizedIntents)result); await nextTurn(cancellationToken).ConfigureAwait(false); }
public async Task <ChoiceResult> RecognizeAsync(ITurnContext context, List <Choice> choices) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Activity); if (context.Activity.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } if (choices == null) { throw new ArgumentNullException(nameof(choices)); } var request = context.Activity; var utterance = request.Text; var options = RecognizerOptions ?? new FindChoicesOptions(); options.Locale = request.Locale ?? options.Locale ?? Culture ?? Recognizers.Text.Culture.English; var results = ChoiceRecognizers.RecognizeChoices(utterance, choices, options); if (results != null && results.Count > 0) { var value = results[0].Resolution; var result = new ChoiceResult { Status = PromptStatus.Recognized, Value = value }; if (Validator != null) { await Validator(context, result).ConfigureAwait(false); } return(result); } else { return(new ChoiceResult { Status = PromptStatus.NotRecognized }); } }
public async Task <GoogleResponseBody> ProcessActivity(Payload actionPayload, GoogleOptions googleOptions, BotCallbackHandler callback) { TurnContext context = null; try { Options = googleOptions; var activity = RequestToActivity(actionPayload, googleOptions); BotAssert.ActivityNotNull(activity); context = new TurnContext(this, activity); Responses = new Dictionary <string, List <Activity> >(); await base.RunPipelineAsync(context, callback, default(CancellationToken)).ConfigureAwait(false); var key = $"{activity.Conversation.Id}:{activity.Id}"; try { GoogleResponseBody response = null; var activities = Responses.ContainsKey(key) ? Responses[key] : new List <Activity>(); response = CreateResponseFromLastActivity(activities, context); return(response); } finally { if (Responses.ContainsKey(key)) { Responses.Remove(key); } } } catch (Exception ex) { await googleOptions.OnTurnError(context, ex); throw; } }
/// <summary> /// Processess an incoming activity. /// </summary> /// <param name="context">The context object for this turn.</param> /// <param name="next">The delegate to call to continue the bot middleware pipeline.</param> /// /// <param name="cancellationToken">Cancellation token.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</placeholder></returns> public async Task OnTurnAsync(ITurnContext context, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken)) { BotAssert.ContextNotNull(context); if (context.Activity.Type == ActivityTypes.Message) { var utterance = context.Activity.AsMessageActivity().Text; if (!string.IsNullOrWhiteSpace(utterance)) { var result = await _luisRecognizer.RecognizeAsync(context, CancellationToken.None).ConfigureAwait(false); context.TurnState.Add(LuisRecognizerResultKey, result); var traceActivity = Activity.CreateTraceActivity("LuisRecognizerMiddleware", LuisTraceType); await context.SendActivityAsync(traceActivity).ConfigureAwait(false); } } await next(cancellationToken).ConfigureAwait(false); }
/// <summary> /// Primary adapter method for processing activities sent from calling bot. /// </summary> /// <param name="activity">The activity to process.</param> /// <param name="callback">The BotCallBackHandler to call on completion.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>The response to the activity.</returns> public async Task <InvokeResponse> ProcessActivityAsync(Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken) { BotAssert.ActivityNotNull(activity); _botTelemetryClient.TrackTrace($"Received an incoming activity. ActivityId: {activity.Id}", Severity.Information, null); using (var context = new TurnContext(this, activity)) { await RunPipelineAsync(context, callback, cancellationToken).ConfigureAwait(false); // We do not support Invoke in websocket transport if (activity.Type == ActivityTypes.Invoke) { return(new InvokeResponse { Status = (int)HttpStatusCode.NotImplemented }); } return(null); } }
/// <summary> /// Recognizes and validates the user input. /// </summary> /// <param name="context">The context for the current turn.</param> /// <returns>A task that represents the work queued to execute.</returns> /// <remarks>Call this when you expect that the incoming activity for this /// turn contains the user input to recognize. /// If recognition succeeds, the <see cref="TextResult.Value"/> property of the /// result contains the value recognized. /// <para>If recognition fails, returns a <see cref="TextResult"/> with /// its <see cref="PromptStatus"/> set to <see cref="PromptStatus.NotRecognized"/> and /// its <see cref="TextResult.Value"/> set to <c>null</c>.</para> /// </remarks> public override async Task <TextResult> 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(); TextResult textResult = new TextResult(); if (message.Text != null) { textResult.Status = PromptStatus.Recognized; textResult.Value = message.Text; textResult.Text = message.Text; await Validate(context, textResult); } return(textResult); }
/// <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 <T> > Recognize(IBotContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Request); if (context.Request.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } NumberResult <T> numberResult = new NumberResult <T>(); IMessageActivity message = context.Request.AsMessageActivity(); var results = _model.Parse(message.Text); if (results.Any()) { var result = results.First(); if (typeof(T) == typeof(float)) { if (float.TryParse(result.Resolution["value"].ToString(), out float value)) { numberResult.Status = RecognitionStatus.Recognized; numberResult.Value = (T)(object)value; numberResult.Text = result.Text; await Validate(context, numberResult); } } else if (typeof(T) == typeof(int)) { if (int.TryParse(result.Resolution["value"].ToString(), out int value)) { numberResult.Status = RecognitionStatus.Recognized; numberResult.Value = (T)(object)value; numberResult.Text = result.Text; await Validate(context, numberResult); } } } return(numberResult); }
public async Task OnTurnAsync( ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken)) { BotAssert.ContextNotNull(turnContext); #pragma warning disable CA1062 // Validate arguments of public methods if (turnContext.Activity != null) #pragma warning restore CA1062 // Validate arguments of public methods { var et = this.BuildEventTelemetry(turnContext.Activity); this.telemetryClient.TrackEvent(et); } // hook up onSend pipeline turnContext.OnSendActivities(async(ctx, activities, nextSend) => { activities.ForEach(a => this.telemetryClient.TrackEvent(this.BuildEventTelemetry(a))); return(await nextSend() .ConfigureAwait(false)); }); // hook up update activity pipeline turnContext.OnUpdateActivity(async(ctx, activity, nextUpdate) => { var et = this.BuildEventTelemetry(activity); this.telemetryClient.TrackEvent(et); return(await nextUpdate() .ConfigureAwait(false)); }); if (next != null) { await next(cancellationToken) .ConfigureAwait(false); } }
/// <summary> /// Processess an incoming activity and if it is for MsTeams attaches <see cref="ITeamsContext"/> instances along with the context. /// </summary> /// <param name="context">The context object for this turn.</param> /// <param name="nextDelegate">The delegate to call to continue the bot middleware pipeline.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns> /// Task tracking operation. /// </returns> /// <remarks> /// Middleware calls the <paramref name="nextDelegate" /> delegate to pass control to /// the next middleware in the pipeline. If middleware doesn’t call the next delegate, /// the adapter does not call any of the subsequent middleware’s request handlers or the /// bot’s receive handler, and the pipeline short circuits. /// <para>The <paramref name="context" /> provides information about the /// incoming activity, and other data needed to process the activity.</para> /// </remarks> /// <seealso cref="ITurnContext" /> /// <seealso cref="Schema.IActivity" /> public async Task OnTurnAsync(ITurnContext context, NextDelegate nextDelegate, CancellationToken cancellationToken = default(CancellationToken)) { BotAssert.ContextNotNull(context); if (context.Activity.ChannelId.Equals(Channels.Msteams, StringComparison.OrdinalIgnoreCase)) { // BotFrameworkAdapter when processing activity, post Auth adds BotIdentity into the context. ClaimsIdentity claimsIdentity = context.TurnState.Get <ClaimsIdentity>("BotIdentity"); // If we failed to find ClaimsIdentity, create a new AnonymousIdentity. This tells us that Auth is off. if (claimsIdentity == null) { claimsIdentity = new ClaimsIdentity(new List <Claim>(), "anonymous"); } ITeamsConnectorClient teamsConnectorClient = await this.CreateTeamsConnectorClientAsync(context.Activity.ServiceUrl, claimsIdentity).ConfigureAwait(false); context.TurnState.Add((ITeamsContext) new TeamsContext(context, teamsConnectorClient)); } await nextDelegate(cancellationToken).ConfigureAwait(false); }
public void TrackEvent(IMessageActivity activity, QueryResult queryResult) { BotAssert.ActivityNotNull(activity); if (queryResult == null) { throw new ArgumentNullException(nameof(queryResult)); } var properties = new Dictionary <string, string> { { QnAConstants.UserQuery, activity.Text }, { QnAConstants.KnowledgeBaseQuestion, string.Join(QuestionsSeparator, queryResult.Questions) }, { QnAConstants.KnowledgeBaseAnswer, queryResult.Answer }, { QnAConstants.Score, queryResult.Score.ToString(CultureInfo.InvariantCulture) } }; var builder = new EventTelemetryBuilder(activity, this.settings, properties); var eventTelemetry = builder.Build(); eventTelemetry.Name = EventTypes.QnaEvent; this.telemetryClient.TrackEvent(eventTelemetry); }
public async Task Prompt(ITurnContext context, List <Choice> choices, string prompt = null, string speak = null) { BotAssert.ContextNotNull(context); if (choices == null) { throw new ArgumentNullException(nameof(choices)); } IMessageActivity msg; switch (Style) { case ListStyle.Inline: msg = ChoiceFactory.Inline(choices, prompt, speak, ChoiceOptions); break; case ListStyle.List: msg = ChoiceFactory.List(choices, prompt, speak, ChoiceOptions); break; case ListStyle.SuggestedAction: msg = ChoiceFactory.SuggestedAction(choices, prompt, speak); break; case ListStyle.None: msg = Activity.CreateMessageActivity(); msg.Text = prompt; msg.Speak = speak; break; case ListStyle.Auto: default: msg = ChoiceFactory.ForChannel(context, choices, prompt, speak, ChoiceOptions); break; } msg.InputHint = InputHints.ExpectingInput; await context.SendActivity(msg); }
/// <summary> /// Passes a users reply to the dialog for further processing.The bot should keep calling /// 'continue()' for future turns until the dialog returns a completion object with /// 'isCompleted == true'. To cancel or interrupt the prompt simply delete the `state` object /// being persisted. /// </summary> /// <param name="context">Context for the current turn of the conversation with the user.</param> /// <param name="state">A state object that was previously initialized by a call to [begin()](#begin).</param> /// <returns>DialogCompletion result</returns> public async Task <DialogCompletion> Continue(ITurnContext context, IDictionary <string, object> state) { BotAssert.ContextNotNull(context); if (state == null) { throw new ArgumentNullException(nameof(state)); } // Create empty dialog set and ourselves to it var dialogs = new DialogSet(); dialogs.Add("dialog", (IDialog)this); // Continue the dialog IDictionary <string, object> result = null; var dc = new DialogContext(dialogs, context, state, (r) => { result = r; }); if (dc.ActiveDialog != null) { await dc.Continue(); return(dc.ActiveDialog != null ? new DialogCompletion { IsActive = true, IsCompleted = false } : new DialogCompletion { IsActive = false, IsCompleted = true, Result = result }); } else { return(new DialogCompletion { IsActive = false, IsCompleted = false }); } }
public override async Task <TimexResult> 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 timexResult = new TimexResult { Status = PromptStatus.Recognized }; var distinctTimex = new HashSet <string>(); foreach (var resolution in result.Resolution) { var values = (List <Dictionary <string, string> >)resolution.Value; foreach (var timex in values.Select(r => r["timex"])) { distinctTimex.Add(timex); } } timexResult.Resolutions = distinctTimex.ToArray(); await Validate(context, timexResult); return(timexResult); } } } return(new TimexResult()); }
public async Task OnTurn(ITurnContext context, MiddlewareSet.NextDelegate next) { BotAssert.ContextNotNull(context); if (context.Activity.Type == ActivityTypes.Message) { var utterance = context.Activity.AsMessageActivity().Text; var result = await _luisRecognizer.CallAndRecognize(utterance, CancellationToken.None).ConfigureAwait(false); context.Services.Add(LuisRecognizerResultKey, result.recognizerResult); var traceInfo = new LuisTraceInfo { RecognizerResult = result.recognizerResult, LuisModel = RemoveSensitiveData(_luisModel), LuisOptions = _luisOptions, LuisResult = result.luisResult }; var traceActivity = Activity.CreateTraceActivity("LuisRecognizerMiddleware", LuisTraceType, traceInfo, LuisTraceLabel); await context.SendActivity(traceActivity).ConfigureAwait(false); } await next().ConfigureAwait(false); }
/// <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 <TextResult> Recognize(IBotContext context) { BotAssert.ContextNotNull(context); BotAssert.ActivityNotNull(context.Request); if (context.Request.Type != ActivityTypes.Message) { throw new InvalidOperationException("No Message to Recognize"); } TextResult textResult = new TextResult(); IMessageActivity message = context.Request.AsMessageActivity(); var results = _model.Parse(message.Text); if (results.Any()) { var result = results.First(); textResult.Status = RecognitionStatus.Recognized; textResult.Text = result.Text; textResult.Value = (string)result.Resolution["value"]; await Validate(context, textResult); } return(textResult); }
// TODO: Incorporate value preservation into other updates made to Adaptive Cards public async Task PreserveValuesAsync(ITurnContext turnContext, CancellationToken cancellationToken = default) { BotAssert.ContextNotNull(turnContext); if (turnContext.GetIncomingActionData() is JObject data) { var matchResult = await GetDataMatchAsync(turnContext, cancellationToken).ConfigureAwait(false); if (matchResult.SavedActivity != null && matchResult.SavedAttachment?.ContentType.EqualsCI(ContentTypes.AdaptiveCard) == true) { var changed = false; // The content must be non-null or else the attachment couldn't have been a match matchResult.SavedAttachment.Content = matchResult.SavedAttachment.Content.ToJObjectAndBack( card => { // Iterate through all inputs in the card foreach (var input in AdaptiveCardUtil.GetAdaptiveInputs(card)) { var id = AdaptiveCardUtil.GetAdaptiveInputId(input); var inputValue = data.GetValue(id); input.SetValue(AdaptiveProperties.Value, inputValue); changed = true; } }); if (changed) { // The changes to the attachment will already be reflected in the activity await UpdateActivityAsync(turnContext, matchResult.SavedActivity, cancellationToken).ConfigureAwait(false); } } } }
/// <summary> /// Primary adapter method for processing activities sent from calling bot. /// </summary> /// <param name="activity">The activity to process.</param> /// <param name="callback">The BotCallBackHandler to call on completion.</param> /// <param name="cancellationToken">Cancellation token.</param> /// <returns>The response to the activity.</returns> public async Task <InvokeResponse> ProcessActivityAsync(Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken) { // Ensure the Activity has been retrieved from the HTTP POST BotAssert.ActivityNotNull(activity); _botTelemetryClient.TrackTrace($"SkillHttpBotAdapter: Received an incoming activity. Activity id: {activity.Id}", Severity.Information, null); // Process the Activity through the Middleware and the Bot, this will generate Activities which we need to send back. using (var context = new TurnContext(this, activity)) { await RunPipelineAsync(context, callback, default(CancellationToken)); } _botTelemetryClient.TrackTrace($"SkillHttpBotAdapter: Batching activities in the response. ReplyToId: {activity.ReplyToId}", Severity.Information, null); // Any Activity responses are now available (via SendActivitiesAsync) so we need to pass back for the response var response = new InvokeResponse { Status = (int)HttpStatusCode.OK, Body = GetReplies(), }; return(response); }