diff --git a/samples/13.core-bot/pom.xml b/samples/13.core-bot/pom.xml index a75393538..a59ab13e3 100644 --- a/samples/13.core-bot/pom.xml +++ b/samples/13.core-bot/pom.xml @@ -89,11 +89,6 @@ bot-dialogs 4.6.0-preview9 - - com.microsoft.bot - bot-ai-qna - 4.6.0-preview9 - com.microsoft.bot bot-ai-luis-v3 diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/Application.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/Application.java index 3b73661df..8ae95d1f7 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/Application.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/Application.java @@ -5,9 +5,7 @@ import com.microsoft.bot.builder.Bot; import com.microsoft.bot.builder.ConversationState; -import com.microsoft.bot.builder.Storage; import com.microsoft.bot.builder.UserState; -import com.microsoft.bot.dialogs.Dialog; import com.microsoft.bot.integration.AdapterWithErrorHandler; import com.microsoft.bot.integration.BotFrameworkHttpAdapter; import com.microsoft.bot.integration.Configuration; @@ -36,8 +34,10 @@ * override methods in order to provide custom implementations. */ public class Application extends BotDependencyConfiguration { + /** * The start method. + * * @param args The args. */ public static void main(String[] args) { @@ -48,56 +48,21 @@ public static void main(String[] args) { * Returns the Bot for this application. * *

- * The @Component annotation could be used on the Bot class instead of this method - * with the @Bean annotation. + * The @Component annotation could be used on the Bot class instead of this method with the + * @Bean annotation. *

* * @return The Bot implementation for this application. */ @Bean public Bot getBot( + Configuration configuration, + UserState userState, + ConversationState conversationState ) { - Storage storage = this.getStorage(); - UserState userState = this.getUserState(storage); - ConversationState conversationState = this.getConversationState(storage); - Dialog rootDialog = this.getRootDialog(); - return new DialogAndWelcomeBot(conversationState, userState, rootDialog); - } - - /** - * Returns a FlightBookingRecognizer object. - * @return The FlightBookingRecognizer. - */ - @Bean - public FlightBookingRecognizer getFlightBookingRecognizer() { - Configuration configuration = this.getConfiguration(); - return new FlightBookingRecognizer(configuration); - } - - /** - * Returns a BookingDialog object. - * @return The BookingDialog. - */ - @Bean - public BookingDialog getBookingDialog() { - return new BookingDialog(); - } - - /** - * Returns the starting Dialog for this application. - * - *

- * The @Component annotation could be used on the Dialog class instead of this method - * with the @Bean annotation. - *

- * - * @return The Dialog implementation for this application. - */ - @Bean - public Dialog getRootDialog() { - FlightBookingRecognizer flightBookingRecognizer = this.getFlightBookingRecognizer(); - BookingDialog bookingDialog = this.getBookingDialog(); - return new MainDialog(flightBookingRecognizer, bookingDialog); + FlightBookingRecognizer recognizer = new FlightBookingRecognizer(configuration); + MainDialog dialog = new MainDialog(recognizer, new BookingDialog()); + return new DialogAndWelcomeBot<>(conversationState, userState, dialog); } /** diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/BookingDetails.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/BookingDetails.java index 4e95a5807..330740a57 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/BookingDetails.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/BookingDetails.java @@ -7,12 +7,14 @@ * The model class to retrieve the information of the booking. */ public class BookingDetails { + private String destination; private String origin; private String travelDate; /** * Gets the destination of the booking. + * * @return The destination. */ public String getDestination() { @@ -22,6 +24,7 @@ public String getDestination() { /** * Sets the destination of the booking. + * * @param withDestination The new destination. */ public void setDestination(String withDestination) { @@ -30,6 +33,7 @@ public void setDestination(String withDestination) { /** * Gets the origin of the booking. + * * @return The origin. */ public String getOrigin() { @@ -38,6 +42,7 @@ public String getOrigin() { /** * Sets the origin of the booking. + * * @param withOrigin The new origin. */ public void setOrigin(String withOrigin) { @@ -46,6 +51,7 @@ public void setOrigin(String withOrigin) { /** * Gets the travel date of the booking. + * * @return The travel date. */ public String getTravelDate() { @@ -54,6 +60,7 @@ public String getTravelDate() { /** * Sets the travel date of the booking. + * * @param withTravelDate The new travel date. */ public void setTravelDate(String withTravelDate) { diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/BookingDialog.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/BookingDialog.java index 5af80feb0..4a5e45721 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/BookingDialog.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/BookingDialog.java @@ -23,6 +23,7 @@ * The class containing the booking dialogs. */ public class BookingDialog extends CancelAndHelpDialog { + private final String destinationStepMsgText = "Where would you like to travel to?"; private final String originStepMsgText = "Where are you traveling from?"; @@ -54,7 +55,9 @@ private CompletableFuture destinationStep(WaterfallStepContext if (bookingDetails.getDestination().isEmpty()) { Activity promptMessage = - MessageFactory.text(destinationStepMsgText, destinationStepMsgText, InputHints.EXPECTING_INPUT); + MessageFactory.text(destinationStepMsgText, destinationStepMsgText, + InputHints.EXPECTING_INPUT + ); PromptOptions promptOptions = new PromptOptions(); promptOptions.setPrompt(promptMessage); return stepContext.prompt("TextPrompt", promptOptions); @@ -71,7 +74,8 @@ private CompletableFuture originStep(WaterfallStepContext step if (bookingDetails.getOrigin().isEmpty()) { Activity promptMessage = - MessageFactory.text(originStepMsgText, originStepMsgText, InputHints.EXPECTING_INPUT); + MessageFactory + .text(originStepMsgText, originStepMsgText, InputHints.EXPECTING_INPUT); PromptOptions promptOptions = new PromptOptions(); promptOptions.setPrompt(promptMessage); return stepContext.prompt("TextPrompt", promptOptions); @@ -100,9 +104,13 @@ private CompletableFuture confirmStep(WaterfallStepContext ste bookingDetails.setTravelDate(stepContext.getResult().toString()); String messageText = - String.format("Please confirm, I have you traveling to: %s from: %s on: %s. Is this correct?", - bookingDetails.getDestination(), bookingDetails.getOrigin(), bookingDetails.getTravelDate()); - Activity promptMessage = MessageFactory.text(messageText, messageText, InputHints.EXPECTING_INPUT); + String.format( + "Please confirm, I have you traveling to: %s from: %s on: %s. Is this correct?", + bookingDetails.getDestination(), bookingDetails.getOrigin(), + bookingDetails.getTravelDate() + ); + Activity promptMessage = MessageFactory + .text(messageText, messageText, InputHints.EXPECTING_INPUT); PromptOptions promptOptions = new PromptOptions(); promptOptions.setPrompt(promptMessage); @@ -114,7 +122,6 @@ private CompletableFuture confirmStep(WaterfallStepContext ste private CompletableFuture finalStep(WaterfallStepContext stepContext) { if ((Boolean) stepContext.getResult()) { BookingDetails bookingDetails = (BookingDetails) stepContext.getOptions(); - return stepContext.endDialog(bookingDetails); } diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/CancelAndHelpDialog.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/CancelAndHelpDialog.java index 393c04c5b..570fb3eaf 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/CancelAndHelpDialog.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/CancelAndHelpDialog.java @@ -18,11 +18,13 @@ * The class in charge of the dialog interruptions. */ public class CancelAndHelpDialog extends ComponentDialog { + private final String helpMsgText = "Show help here"; private final String cancelMsgText = "Cancelling..."; /** * The constructor of the CancelAndHelpDialog class. + * * @param id The dialog's Id. */ public CancelAndHelpDialog(String id) { @@ -30,13 +32,13 @@ public CancelAndHelpDialog(String id) { } /** - * Called when the dialog is _continued_, where it is the active dialog and the - * user replies with a new activity. + * Called when the dialog is _continued_, where it is the active dialog and the user replies + * with a new activity. + * * @param innerDc innerDc The inner {@link DialogContext} for the current turn of conversation. - * @return A {@link CompletableFuture} representing the asynchronous operation. - * If the task is successful, the result indicates whether the dialog is - * still active after the turn has been processed by the dialog. The - * result may also contain a return value. + * @return A {@link CompletableFuture} representing the asynchronous operation. If the task is + * successful, the result indicates whether the dialog is still active after the turn has been + * processed by the dialog. The result may also contain a return value. */ @Override protected CompletableFuture onContinueDialog(DialogContext innerDc) { @@ -55,16 +57,19 @@ private CompletableFuture interrupt(DialogContext innerDc) { switch (text) { case "help": case "?": - Activity helpMessage = MessageFactory.text(helpMsgText, helpMsgText, InputHints.EXPECTING_INPUT); + Activity helpMessage = MessageFactory + .text(helpMsgText, helpMsgText, InputHints.EXPECTING_INPUT); return innerDc.getContext().sendActivity(helpMessage) .thenCompose(sendResult -> - CompletableFuture.completedFuture(new DialogTurnResult(DialogTurnStatus.WAITING))); + CompletableFuture + .completedFuture(new DialogTurnResult(DialogTurnStatus.WAITING))); case "cancel": case "quit": Activity cancelMessage = MessageFactory .text(cancelMsgText, cancelMsgText, InputHints.IGNORING_INPUT); return innerDc.getContext() - .sendActivity(cancelMessage).thenCompose(sendResult -> innerDc.cancelAllDialogs()); + .sendActivity(cancelMessage) + .thenCompose(sendResult -> innerDc.cancelAllDialogs()); default: break; } diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DateResolverDialog.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DateResolverDialog.java index bbdbf8c0e..635ae92b3 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DateResolverDialog.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DateResolverDialog.java @@ -75,16 +75,12 @@ private CompletableFuture initialStep(WaterfallStepContext ste return stepContext.prompt("DateTimePrompt", promptOptions); } - DateTimeResolution dateTimeResolution = new DateTimeResolution() { - { - setTimex(timex); - } - }; - List dateTimeResolutions = new ArrayList() { - { - add(dateTimeResolution); - } - }; + DateTimeResolution dateTimeResolution = new DateTimeResolution() {{ + setTimex(timex); + }}; + List dateTimeResolutions = new ArrayList() {{ + add(dateTimeResolution); + }}; return stepContext.next(dateTimeResolutions); } @@ -93,8 +89,9 @@ private CompletableFuture finalStep(WaterfallStepContext stepC return stepContext.endDialog(timex); } - private static CompletableFuture dateTimePromptValidator(PromptValidatorContext> - promptContext) { + private static CompletableFuture dateTimePromptValidator( + PromptValidatorContext> promptContext + ) { if (promptContext.getRecognized().getSucceeded()) { // This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the // Time part. TIMEX is a format that represents DateTime expressions that include some ambiguity. diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DialogAndWelcomeBot.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DialogAndWelcomeBot.java index 5d15bf417..48228d02f 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DialogAndWelcomeBot.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DialogAndWelcomeBot.java @@ -24,30 +24,38 @@ /** * The class containing the welcome dialog. + * * @param is a Dialog. */ public class DialogAndWelcomeBot extends DialogBot { + /** * Creates a DialogBot. + * * @param withConversationState ConversationState to use in the bot * @param withUserState UserState to use * @param withDialog Param inheriting from Dialog class */ - public DialogAndWelcomeBot(ConversationState withConversationState, UserState withUserState, T withDialog) { + public DialogAndWelcomeBot( + ConversationState withConversationState, UserState withUserState, T withDialog + ) { super(withConversationState, withUserState, withDialog); } /** - * When the {@link #onConversationUpdateActivity(TurnContext)} method receives a - * conversation update activity that indicates one or more users other than the - * bot are joining the conversation, it calls this method. - * @param membersAdded A list of all the members added to the conversation, - * as described by the conversation update activity - * @param turnContext The context object for this turn. + * When the {@link #onConversationUpdateActivity(TurnContext)} method receives a conversation + * update activity that indicates one or more users other than the bot are joining the + * conversation, it calls this method. + * + * @param membersAdded A list of all the members added to the conversation, as described by the + * conversation update activity + * @param turnContext The context object for this turn. * @return A task that represents the work queued to execute. */ @Override - protected CompletableFuture onMembersAdded(List membersAdded, TurnContext turnContext) { + protected CompletableFuture onMembersAdded( + List membersAdded, TurnContext turnContext + ) { return turnContext.getActivity().getMembersAdded().stream() .filter(member -> !StringUtils .equals(member.getId(), turnContext.getActivity().getRecipient().getId())) @@ -55,10 +63,13 @@ protected CompletableFuture onMembersAdded(List membersAdd // Greet anyone that was not the target (recipient) of this message. // To learn more about Adaptive Cards, see https://aka.ms/msbot-adaptivecards for more details. Attachment welcomeCard = createAdaptiveCardAttachment(); - Activity response = MessageFactory.attachment(welcomeCard, null, "Welcome to Bot Framework!", null); + Activity response = MessageFactory + .attachment(welcomeCard, null, "Welcome to Bot Framework!", null); return turnContext.sendActivity(response).thenApply(sendResult -> { - return Dialog.run(getDialog(), turnContext, getConversationState().createProperty("DialogState")); + return Dialog.run(getDialog(), turnContext, + getConversationState().createProperty("DialogState") + ); }); }) .collect(CompletableFutures.toFutureList()) @@ -67,14 +78,17 @@ protected CompletableFuture onMembersAdded(List membersAdd // Load attachment from embedded resource. private Attachment createAdaptiveCardAttachment() { - try (InputStream inputStream = Thread.currentThread(). - getContextClassLoader().getResourceAsStream("cards/welcomeCard.json")) { - String adaptiveCardJson = IOUtils.toString(inputStream, StandardCharsets.UTF_8.toString()); + try ( + InputStream inputStream = Thread.currentThread(). + getContextClassLoader().getResourceAsStream("cards/welcomeCard.json") + ) { + String adaptiveCardJson = IOUtils + .toString(inputStream, StandardCharsets.UTF_8.toString()); - return new Attachment() {{ - setContentType("application/vnd.microsoft.card.adaptive"); - setContent(Serialization.jsonToTree(adaptiveCardJson)); - }}; + return new Attachment() {{ + setContentType("application/vnd.microsoft.card.adaptive"); + setContent(Serialization.jsonToTree(adaptiveCardJson)); + }}; } catch (IOException e) { e.printStackTrace(); diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DialogBot.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DialogBot.java index 3826b7f54..18df7b20f 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DialogBot.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/DialogBot.java @@ -14,15 +14,17 @@ import java.util.concurrent.CompletableFuture; /** - * This Bot implementation can run any type of Dialog. The use of type parameterization is to allow multiple - * different bots to be run at different endpoints within the same project. This can be achieved by defining - * distinct Controller types each with dependency on distinct Bot types. The ConversationState is used by - * the Dialog system. The UserState isn't, however, it might have been used in a Dialog implementation, - * and the requirement is that all BotState objects are saved at the end of a turn. + * This Bot implementation can run any type of Dialog. The use of type parameterization is to allow + * multiple different bots to be run at different endpoints within the same project. This can be + * achieved by defining distinct Controller types each with dependency on distinct Bot types. The + * ConversationState is used by the Dialog system. The UserState isn't, however, it might have been + * used in a Dialog implementation, and the requirement is that all BotState objects are saved at + * the end of a turn. * * @param parameter of a type inheriting from Dialog */ public class DialogBot extends ActivityHandler { + private Dialog dialog; private BotState conversationState; private BotState userState; @@ -83,11 +85,14 @@ protected void setUserState(BotState withUserState) { /** * Creates a DialogBot. + * * @param withConversationState ConversationState to use in the bot - * @param withUserState UserState to use - * @param withDialog Param inheriting from Dialog class + * @param withUserState UserState to use + * @param withDialog Param inheriting from Dialog class */ - public DialogBot(ConversationState withConversationState, UserState withUserState, T withDialog) { + public DialogBot( + ConversationState withConversationState, UserState withUserState, T withDialog + ) { this.conversationState = withConversationState; this.userState = withUserState; this.dialog = withDialog; @@ -95,6 +100,7 @@ public DialogBot(ConversationState withConversationState, UserState withUserStat /** * Saves the BotState objects at the end of each turn. + * * @param turnContext * @return */ @@ -107,6 +113,7 @@ public CompletableFuture onTurn(TurnContext turnContext) { /** * This method is executed when the turnContext receives a message activity. + * * @param turnContext * @return */ diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/FlightBookingRecognizer.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/FlightBookingRecognizer.java index da2533aac..9693b8cf0 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/FlightBookingRecognizer.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/FlightBookingRecognizer.java @@ -21,10 +21,12 @@ * The class in charge of recognizing the booking information. */ public class FlightBookingRecognizer implements Recognizer { + private LuisRecognizer recognizer; /** * The constructor of the FlightBookingRecognizer class. + * * @param configuration The Configuration object to use. */ public FlightBookingRecognizer(Configuration configuration) { @@ -35,11 +37,13 @@ public FlightBookingRecognizer(Configuration configuration) { LuisApplication luisApplication = new LuisApplication( configuration.getProperty("LuisAppId"), configuration.getProperty("LuisAPIKey"), - String.format("https://%s", configuration.getProperty("LuisAPIHostName"))); + String.format("https://%s", configuration.getProperty("LuisAPIHostName")) + ); // Set the recognizer options depending on which endpoint version you want to use. // More details can be found in // https://docs.microsoft.com/en-gb/azure/cognitive-services/luis/luis-migration-api-v3 - LuisRecognizerOptionsV3 recognizerOptions = new LuisRecognizerOptionsV3(luisApplication) { + LuisRecognizerOptionsV3 recognizerOptions = new LuisRecognizerOptionsV3( + luisApplication) { { setIncludeInstanceData(true); } @@ -51,6 +55,7 @@ public FlightBookingRecognizer(Configuration configuration) { /** * Verify if the recognizer is configured. + * * @return True if it's configured, False if it's not. */ public Boolean isConfigured() { @@ -59,6 +64,7 @@ public Boolean isConfigured() { /** * Return an object with preformatted LUIS results for the bot's dialogs to consume. + * * @param context A {link TurnContext} * @return A {link RecognizerResult} */ @@ -69,16 +75,20 @@ public CompletableFuture executeLuisQuery(TurnContext context) /** * Gets the From data from the entities which is part of the result. + * * @param result The recognizer result. * @return The object node representing the From data. */ public ObjectNode getFromEntities(RecognizerResult result) { String fromValue = "", fromAirportValue = ""; if (result.getEntities().get("$instance").get("From") != null) { - fromValue = result.getEntities().get("$instance").get("From").get(0).get("text").asText(); + fromValue = result.getEntities().get("$instance").get("From").get(0).get("text") + .asText(); } - if (!fromValue.isEmpty() && result.getEntities().get("From").get(0).get("Airport") != null) { - fromAirportValue = result.getEntities().get("From").get(0).get("Airport").get(0).get(0).asText(); + if (!fromValue.isEmpty() + && result.getEntities().get("From").get(0).get("Airport") != null) { + fromAirportValue = result.getEntities().get("From").get(0).get("Airport").get(0).get(0) + .asText(); } ObjectMapper mapper = new ObjectMapper().findAndRegisterModules(); @@ -90,6 +100,7 @@ public ObjectNode getFromEntities(RecognizerResult result) { /** * Gets the To data from the entities which is part of the result. + * * @param result The recognizer result. * @return The object node representing the To data. */ @@ -99,7 +110,8 @@ public ObjectNode getToEntities(RecognizerResult result) { toValue = result.getEntities().get("$instance").get("To").get(0).get("text").asText(); } if (!toValue.isEmpty() && result.getEntities().get("To").get(0).get("Airport") != null) { - toAirportValue = result.getEntities().get("To").get(0).get("Airport").get(0).get(0).asText(); + toAirportValue = result.getEntities().get("To").get(0).get("Airport").get(0).get(0) + .asText(); } ObjectMapper mapper = new ObjectMapper().findAndRegisterModules(); @@ -110,8 +122,10 @@ public ObjectNode getToEntities(RecognizerResult result) { } /** - * This value will be a TIMEX. And we are only interested in a Date so grab the first result and drop the Time part. - * TIMEX is a format that represents DateTime expressions that include some ambiguity. e.g. missing a Year. + * This value will be a TIMEX. And we are only interested in a Date so grab the first result and + * drop the Time part. TIMEX is a format that represents DateTime expressions that include some + * ambiguity. e.g. missing a Year. + * * @param result A {link RecognizerResult} * @return The Timex value without the Time model */ @@ -132,6 +146,7 @@ public String getTravelDate(RecognizerResult result) { /** * Runs an utterance through a recognizer and returns a generic recognizer result. + * * @param turnContext Turn context. * @return Analysis of utterance. */ diff --git a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/MainDialog.java b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/MainDialog.java index 51a3bbe56..6f913a559 100644 --- a/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/MainDialog.java +++ b/samples/13.core-bot/src/main/java/com/microsoft/bot/sample/core/MainDialog.java @@ -30,13 +30,15 @@ * The class containing the main dialog for the sample. */ public class MainDialog extends ComponentDialog { + private final FlightBookingRecognizer luisRecognizer; private final Integer plusDayValue = 7; /** * The constructor of the Main Dialog class. + * * @param withLuisRecognizer The FlightBookingRecognizer object. - * @param bookingDialog The BookingDialog object with booking dialogs. + * @param bookingDialog The BookingDialog object with booking dialogs. */ public MainDialog(FlightBookingRecognizer withLuisRecognizer, BookingDialog bookingDialog) { super("MainDialog"); @@ -57,9 +59,10 @@ public MainDialog(FlightBookingRecognizer withLuisRecognizer, BookingDialog book } /** - * First step in the waterfall dialog. Prompts the user for a command. - * Currently, this expects a booking request, like "book me a flight from Paris to Berlin on march 22" - * Note that the sample LUIS model will only recognize Paris, Berlin, New York and London as airport cities. + * First step in the waterfall dialog. Prompts the user for a command. Currently, this expects a + * booking request, like "book me a flight from Paris to Berlin on march 22" Note that the + * sample LUIS model will only recognize Paris, Berlin, New York and London as airport cities. + * * @param stepContext A {@link WaterfallStepContext} * @return A {@link DialogTurnResult} */ @@ -78,16 +81,19 @@ private CompletableFuture introStep(WaterfallStepContext stepC String messageText = stepContext.getOptions() != null ? stepContext.getOptions().toString() : String.format("What can I help you with today?\n" - + "Say something like \"Book a flight from Paris to Berlin on %s\"", weekLaterDate); - Activity promptMessage = MessageFactory.text(messageText, messageText, InputHints.EXPECTING_INPUT); + + "Say something like \"Book a flight from Paris to Berlin on %s\"", weekLaterDate); + Activity promptMessage = MessageFactory + .text(messageText, messageText, InputHints.EXPECTING_INPUT); PromptOptions promptOptions = new PromptOptions(); promptOptions.setPrompt(promptMessage); return stepContext.prompt("TextPrompt", promptOptions); } /** - * Second step in the waterfall. This will use LUIS to attempt to extract the origin, destination and travel dates. - * Then, it hands off to the bookingDialog child dialog to collect any remaining details. + * Second step in the waterfall. This will use LUIS to attempt to extract the origin, + * destination and travel dates. Then, it hands off to the bookingDialog child dialog to collect + * any remaining details. + * * @param stepContext A {@link WaterfallStepContext} * @return A {@link DialogTurnResult} */ @@ -106,53 +112,65 @@ private CompletableFuture actStep(WaterfallStepContext stepCon ObjectNode toEntities = luisRecognizer.getToEntities(luisResult); // Show a warning for Origin and Destination if we can't resolve them. - return showWarningForUnsupportedCities(stepContext.getContext(), fromEntities, toEntities) + return showWarningForUnsupportedCities( + stepContext.getContext(), fromEntities, toEntities) .thenCompose(showResult -> { - // Initialize BookingDetails with any entities we may have found in the response. - - BookingDetails bookingDetails = new BookingDetails(); - bookingDetails.setDestination(toEntities.get("airport").asText()); - bookingDetails.setOrigin(fromEntities.get("airport").asText()); - bookingDetails.setTravelDate(luisRecognizer.getTravelDate(luisResult)); - // Run the BookingDialog giving it whatever details we have from the LUIS call, - // it will fill out the remainder. - return stepContext.beginDialog("BookingDialog", bookingDetails); - } - ); + // Initialize BookingDetails with any entities we may have found in the response. + + BookingDetails bookingDetails = new BookingDetails(); + bookingDetails.setDestination(toEntities.get("airport").asText()); + bookingDetails.setOrigin(fromEntities.get("airport").asText()); + bookingDetails.setTravelDate(luisRecognizer.getTravelDate(luisResult)); + // Run the BookingDialog giving it whatever details we have from the LUIS call, + // it will fill out the remainder. + return stepContext.beginDialog("BookingDialog", bookingDetails); + } + ); case "GetWeather": // We haven't implemented the GetWeatherDialog so we just display a TODO message. String getWeatherMessageText = "TODO: get weather flow here"; Activity getWeatherMessage = MessageFactory - .text(getWeatherMessageText, getWeatherMessageText, InputHints.IGNORING_INPUT); - stepContext.getContext().sendActivity(getWeatherMessage); - break; + .text( + getWeatherMessageText, getWeatherMessageText, + InputHints.IGNORING_INPUT + ); + return stepContext.getContext().sendActivity(getWeatherMessage) + .thenCompose(resourceResponse -> stepContext.next(null)); + default: // Catch all for unhandled intents - String didntUnderstandMessageText = String.format("Sorry, I didn't get that. Please " - + " try asking in a different way (intent was %s)", luisResult.getTopScoringIntent().intent); + String didntUnderstandMessageText = String.format( + "Sorry, I didn't get that. Please " + + " try asking in a different way (intent was %s)", + luisResult.getTopScoringIntent().intent + ); Activity didntUnderstandMessage = MessageFactory - .text(didntUnderstandMessageText, didntUnderstandMessageText, InputHints.IGNORING_INPUT); - stepContext.getContext().sendActivity(didntUnderstandMessage); - break; + .text( + didntUnderstandMessageText, didntUnderstandMessageText, + InputHints.IGNORING_INPUT + ); + return stepContext.getContext().sendActivity(didntUnderstandMessage) + .thenCompose(resourceResponse -> stepContext.next(null)); } - return stepContext.next(null); }); } /** - * Shows a warning if the requested From or To cities are recognized as entities - * but they are not in the Airport entity list. - * In some cases LUIS will recognize the From and To composite entities as a valid cities - * but the From and To Airport values - * will be empty if those entity values can't be mapped to a canonical item in the Airport. - * @param turnContext A {@link WaterfallStepContext} + * Shows a warning if the requested From or To cities are recognized as entities but they are + * not in the Airport entity list. In some cases LUIS will recognize the From and To composite + * entities as a valid cities but the From and To Airport values will be empty if those entity + * values can't be mapped to a canonical item in the Airport. + * + * @param turnContext A {@link WaterfallStepContext} * @param fromEntities An ObjectNode with the entities of From object - * @param toEntities An ObjectNode with the entities of To object + * @param toEntities An ObjectNode with the entities of To object * @return A task */ - private static CompletableFuture showWarningForUnsupportedCities(TurnContext turnContext, - ObjectNode fromEntities, - ObjectNode toEntities) { + private static CompletableFuture showWarningForUnsupportedCities( + TurnContext turnContext, + ObjectNode fromEntities, + ObjectNode toEntities + ) { List unsupportedCities = new ArrayList(); if (StringUtils.isNotBlank(fromEntities.get("from").asText()) @@ -166,41 +184,49 @@ private static CompletableFuture showWarningForUnsupportedCities(TurnConte } if (!unsupportedCities.isEmpty()) { - String messageText = String.format("Sorry but the following airports are not supported: %s", - String.join(", ", unsupportedCities)); - Activity message = MessageFactory.text(messageText, messageText, InputHints.IGNORING_INPUT); - turnContext.sendActivity(message).thenApply(sendResult -> null); + String messageText = String.format( + "Sorry but the following airports are not supported: %s", + String.join(", ", unsupportedCities) + ); + Activity message = MessageFactory + .text(messageText, messageText, InputHints.IGNORING_INPUT); + return turnContext.sendActivity(message) + .thenApply(sendResult -> null); } return CompletableFuture.completedFuture(null); } /** - * This is the final step in the main waterfall dialog. - * It wraps up the sample "book a flight" interaction with a simple confirmation. + * This is the final step in the main waterfall dialog. It wraps up the sample "book a flight" + * interaction with a simple confirmation. + * * @param stepContext A {@link WaterfallStepContext} * @return A {@link DialogTurnResult} */ private CompletableFuture finalStep(WaterfallStepContext stepContext) { + CompletableFuture stepResult = CompletableFuture.completedFuture(null); + // If the child dialog ("BookingDialog") was cancelled, // the user failed to confirm or if the intent wasn't BookFlight // the Result here will be null. if (stepContext.getResult() instanceof BookingDetails) { // Now we have all the booking details call the booking service. - // If the call to the booking service was successful tell the user. - BookingDetails result = (BookingDetails) stepContext.getResult(); TimexProperty timeProperty = new TimexProperty(result.getTravelDate()); String travelDateMsg = timeProperty.toNaturalLanguage(LocalDateTime.now()); String messageText = String.format("I have you booked to %s from %s on %s", - result.getDestination(), result.getOrigin(), travelDateMsg); - Activity message = MessageFactory.text(messageText, messageText, InputHints.IGNORING_INPUT); - stepContext.getContext().sendActivity(message).thenApply(sendResult -> null); + result.getDestination(), result.getOrigin(), travelDateMsg + ); + Activity message = MessageFactory + .text(messageText, messageText, InputHints.IGNORING_INPUT); + stepResult = stepContext.getContext().sendActivity(message).thenApply(sendResult -> null); } // Restart the main dialog with a different message the second time around String promptMessage = "What else can I do for you?"; - return stepContext.replaceDialog(getInitialDialogId(), promptMessage); + return stepResult + .thenCompose(result -> stepContext.replaceDialog(getInitialDialogId(), promptMessage)); } }