Skip to content

Commit

Permalink
Adaptive Card update for VA (microsoft#1022)
Browse files Browse the repository at this point in the history
* Added MainDialogResponses for new intro card text, GreetingCardModel for card properties, image assets for card.

* Added MainDialogResponses for new intro card text, GreetingCardModel for card properties, image assets for card.

* Removed intro json
Added user greeting cards mapping to model.
Updated onboarding dialog to only ask for name for quick personalisation & to remember returning user.

* added translated strings for main dialgo responses

* Updated image assets and passing wwwroot references to cards.
Updated VA tests

* Removed bad merge

* revert _accessors name

* Removed incorrect spaces in zh-cn responses

* Updated to aka.ms links
  • Loading branch information
ryanisgrig authored and darrenj committed Mar 27, 2019
1 parent ad124bb commit b3d70c5
Show file tree
Hide file tree
Showing 44 changed files with 671 additions and 553 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Luis;
using Microsoft.AspNetCore.Http;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Solutions.Dialogs;
using Microsoft.Bot.Builder.Solutions.Proactive;
using Microsoft.Bot.Builder.Solutions.Responses;
using Microsoft.Bot.Builder.Solutions.Skills;
using Microsoft.Bot.Builder.Solutions.TaskExtensions;
using Microsoft.Bot.Builder.Solutions.Telemetry;
Expand All @@ -21,6 +24,7 @@
using VirtualAssistant.Dialogs.Escalate;
using VirtualAssistant.Dialogs.Main.Resources;
using VirtualAssistant.Dialogs.Onboarding;
using VirtualAssistant.Models;

namespace VirtualAssistant.Dialogs.Main
{
Expand All @@ -33,15 +37,21 @@ public class MainDialog : RouterDialog
private ProactiveState _proactiveState;
private EndpointService _endpointService;
private IBackgroundTaskQueue _backgroundTaskQueue;
private IHttpContextAccessor _httpContext;
private IStatePropertyAccessor<OnboardingState> _onboardingState;
private IStatePropertyAccessor<Dictionary<string, object>> _parametersAccessor;
private IStatePropertyAccessor<VirtualAssistantState> _virtualAssistantState;
private ResponseManager _responseManager;
private string _imageAssetLocation;
private MainResponses _responder = new MainResponses();
private SkillRouter _skillRouter;

private string headerImagePath = "header_greeting.png";
private string backgroundImagePath = "background_light.png";
private string columnBackgroundImagePath = "background_dark.png";
private bool _conversationStarted = false;

public MainDialog(BotServices services, ConversationState conversationState, UserState userState, ProactiveState proactiveState, EndpointService endpointService, IBotTelemetryClient telemetryClient, IBackgroundTaskQueue backgroundTaskQueue)
public MainDialog(BotServices services, ConversationState conversationState, UserState userState, ProactiveState proactiveState, EndpointService endpointService, IBotTelemetryClient telemetryClient, IBackgroundTaskQueue backgroundTaskQueue, ResponseManager responseManager, string imageAssetLocation, IHttpContextAccessor httpContext = null)
: base(nameof(MainDialog), telemetryClient)
{
_services = services ?? throw new ArgumentNullException(nameof(services));
Expand All @@ -51,6 +61,9 @@ public MainDialog(BotServices services, ConversationState conversationState, Use
_endpointService = endpointService;
TelemetryClient = telemetryClient;
_backgroundTaskQueue = backgroundTaskQueue;
_httpContext = httpContext;
_imageAssetLocation = imageAssetLocation;
_responseManager = responseManager;
_onboardingState = _userState.CreateProperty<OnboardingState>(nameof(OnboardingState));
_parametersAccessor = _userState.CreateProperty<Dictionary<string, object>>("userInfo");
_virtualAssistantState = _conversationState.CreateProperty<VirtualAssistantState>(nameof(VirtualAssistantState));
Expand Down Expand Up @@ -251,8 +264,6 @@ protected override async Task<InterruptionAction> OnInterruptDialogAsync(DialogC

protected override async Task CompleteAsync(DialogContext dc, DialogTurnResult result = null, CancellationToken cancellationToken = default(CancellationToken))
{
await _responder.ReplyWith(dc.Context, MainResponses.ResponseIds.Completed);

// End active dialog
await dc.EndDialogAsync(result);
}
Expand Down Expand Up @@ -423,10 +434,62 @@ protected override async Task<InterruptionAction> OnInterruptDialogAsync(DialogC
}
}

/// <summary>
/// Displays a greeting card to new and returning users.
/// </summary>
/// <param name="dc">Dialog context.</param>
/// <param name="cancellationToken">Cancellation token.</param>
/// <returns>Task.</returns>
private async Task StartConversation(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
{
var view = new MainResponses();
await view.ReplyWith(dc.Context, MainResponses.ResponseIds.Intro);
var onboardingState = await _onboardingState.GetAsync(dc.Context, () => new OnboardingState());

if (string.IsNullOrEmpty(onboardingState.Name))
{
var titleResponse = _responseManager.GetResponse(MainDialogResponses.NewUserGreetingTitle);
var bodyResponse = _responseManager.GetResponse(MainDialogResponses.NewUserGreetingBody);

var greetingCardData = new GreetingCardModel()
{
HeaderImageUrl = GetCardImageUri(headerImagePath),
BackgroundImageUrl = GetCardImageUri(backgroundImagePath),
ColumnBackgroundImageUrl = GetCardImageUri(columnBackgroundImagePath),
Title = titleResponse.Text,
Body = bodyResponse.Text,
Speak = string.Format("{0} {1}", titleResponse.Speak, bodyResponse.Speak)
};

var card = new Card("NewUserGreeting", greetingCardData);
var greetingCardMessage = _responseManager.GetCardResponse(card);

await dc.Context.SendActivityAsync(greetingCardMessage);

// This is the first time the user is interacting with the bot, so gather onboarding information.
await dc.BeginDialogAsync(nameof(OnboardingDialog));
}
else
{
var titleResponse = _responseManager.GetResponse(MainDialogResponses.ReturningUserGreetingTitle, new StringDictionary() { { "Name", onboardingState.Name } });
var bodyResponse = _responseManager.GetResponse(MainDialogResponses.ReturningUserGreetingBody);

var greetingCardData = new GreetingCardModel()
{
HeaderImageUrl = GetCardImageUri(headerImagePath),
BackgroundImageUrl = GetCardImageUri(backgroundImagePath),
ColumnBackgroundImageUrl = GetCardImageUri(columnBackgroundImagePath),
Title = titleResponse.Text,
Body = bodyResponse.Text,
Speak = string.Format("{0} {1}", titleResponse.Speak, bodyResponse.Speak)
};

var card = new Card("ReturningUserGreeting", greetingCardData);
var greetingCardMessage = _responseManager.GetCardResponse(card);

await dc.Context.SendActivityAsync(greetingCardMessage);

var greetingMessage = _responseManager.GetResponse(MainDialogResponses.Greeting);
await dc.Context.SendActivityAsync(greetingMessage);
}
}

private async Task RouteToSkillAsync(DialogContext dc, SkillDialogOptions options)
Expand Down Expand Up @@ -488,6 +551,28 @@ private void RegisterSkills(List<SkillDefinition> skillDefinitions)
_skillRouter = new SkillRouter(_services.SkillDefinitions);
}

private string GetCardImageUri(string imagePath)
{
// If we are in local mode we leverage the HttpContext to get the current path to the image assets
if (_httpContext != null)
{
string serverUrl = _httpContext.HttpContext.Request.Scheme + "://" + _httpContext.HttpContext.Request.Host.Value;
return $"{serverUrl}/images/{imagePath}";
}
else
{
// Otherwise use a configured image asset location
if (string.IsNullOrWhiteSpace(_imageAssetLocation))
{
throw new Exception("imageAssetLocation not configured on the skill.");
}
else
{
return $"{_imageAssetLocation}/{imagePath}";
}
}
}

private class Events
{
public const string TokenResponseEvent = "tokens/response";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,6 @@ public class MainResponses : TemplateManager
ResponseIds.Help,
(context, data) => BuildHelpCard(context, data)
},
{
ResponseIds.Intro,
(context, data) => BuildIntroCard(context, data)
},
{
ResponseIds.Qna,
(context, data) => BuildQnACard(context, data)
Expand All @@ -66,16 +62,6 @@ public MainResponses()
Register(new DictionaryRenderer(_responseTemplates));
}

public static IMessageActivity BuildIntroCard(ITurnContext turnContext, dynamic data)
{
var introPath = string.Join(Path.DirectorySeparatorChar, MainStrings.INTRO_PATH.Split('\\'));
var introCard = File.ReadAllText(introPath);
var card = AdaptiveCard.FromJson(introCard).Card;
var attachment = new Attachment(AdaptiveCard.ContentType, content: card);

return MessageFactory.Attachment(attachment, ssml: card.Speak, inputHint: InputHints.AcceptingInput);
}

public static IMessageActivity BuildHelpCard(ITurnContext turnContext, dynamic data)
{
var attachment = new HeroCard()
Expand Down Expand Up @@ -137,7 +123,6 @@ public class ResponseIds
public const string Confused = "confused";
public const string Greeting = "greeting";
public const string Help = "help";
public const string Intro = "intro";
public const string Error = "error";
public const string NoActiveDialog = "noActiveDialog";
public const string Qna = "qna";
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit b3d70c5

Please sign in to comment.