Skip to content
This repository was archived by the owner on Dec 4, 2023. It is now read-only.

Commit 28fe834

Browse files
authored
Sample 43.complex-dialog (#959)
* Sample 43.complex-dialog * Refactored to use @bean instead of @component to be consistent with other samples.
1 parent 1537ece commit 28fe834

File tree

21 files changed

+1869
-38
lines changed

21 files changed

+1869
-38
lines changed

libraries/bot-dialogs/src/main/java/com/microsoft/bot/dialogs/DialogState.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*/
1414
public class DialogState {
1515
@JsonProperty(value = "dialogStack")
16-
private List<DialogInstance> dialogStack = new ArrayList<DialogInstance>();
16+
private List<DialogInstance> dialogStack;
1717

1818
/**
1919
* Initializes a new instance of the class with an empty stack.

libraries/bot-dialogs/src/main/java/com/microsoft/bot/dialogs/WaterfallDialog.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@
2424
*/
2525
public class WaterfallDialog extends Dialog {
2626

27-
private final String persistedOptions = "options";
28-
private final String stepIndex = "stepIndex";
29-
private final String persistedValues = "values";
30-
private final String persistedInstanceId = "instanceId";
27+
private static final String PERSISTED_OPTIONS = "options";
28+
private static final String PERSISTED_VALUES = "values";
29+
private static final String PERSISTED_INSTANCEID = "instanceId";
30+
private static final String STEP_INDEX = "stepIndex";
3131

3232
private final List<WaterfallStep> steps;
3333

3434
/**
35-
* Initializes a new instance of the {@link waterfallDialog} class.
35+
* Initializes a new instance of the {@link WaterfallDialog} class.
3636
*
3737
* @param dialogId The dialog ID.
3838
* @param actions Optional actions to be defined by the caller.
@@ -90,9 +90,9 @@ public CompletableFuture<DialogTurnResult> beginDialog(DialogContext dc, Object
9090
// Initialize waterfall state
9191
Map<String, Object> state = dc.getActiveDialog().getState();
9292
String instanceId = UUID.randomUUID().toString();
93-
state.put(persistedOptions, options);
94-
state.put(persistedValues, new HashMap<String, Object>());
95-
state.put(persistedInstanceId, instanceId);
93+
state.put(PERSISTED_OPTIONS, options);
94+
state.put(PERSISTED_VALUES, new HashMap<String, Object>());
95+
state.put(PERSISTED_INSTANCEID, instanceId);
9696

9797
Map<String, String> properties = new HashMap<String, String>();
9898
properties.put("DialogId", getId());
@@ -156,8 +156,8 @@ public CompletableFuture<DialogTurnResult> resumeDialog(DialogContext dc, Dialog
156156
// Increment step index and run step
157157
Map<String, Object> state = dc.getActiveDialog().getState();
158158
int index = 0;
159-
if (state.containsKey(stepIndex)) {
160-
index = (int) state.get(stepIndex);
159+
if (state.containsKey(STEP_INDEX)) {
160+
index = (int) state.get(STEP_INDEX);
161161
}
162162

163163
return runStep(dc, index + 1, reason, result);
@@ -178,9 +178,9 @@ public CompletableFuture<Void> endDialog(TurnContext turnContext, DialogInstance
178178
HashMap<String, Object> state = new HashMap<String, Object>((Map<String, Object>) instance.getState());
179179

180180
// Create step context
181-
int index = (int) state.get(stepIndex);
181+
int index = (int) state.get(STEP_INDEX);
182182
String stepName = waterfallStepName(index);
183-
String instanceId = (String) state.get(persistedInstanceId);
183+
String instanceId = (String) state.get(PERSISTED_INSTANCEID);
184184

185185
HashMap<String, String> properties = new HashMap<String, String>();
186186
properties.put("DialogId", getId());
@@ -190,7 +190,7 @@ public CompletableFuture<Void> endDialog(TurnContext turnContext, DialogInstance
190190
getTelemetryClient().trackEvent("WaterfallCancel", properties);
191191
} else if (reason == DialogReason.END_CALLED) {
192192
HashMap<String, Object> state = new HashMap<String, Object>((Map<String, Object>) instance.getState());
193-
String instanceId = (String) state.get(persistedInstanceId);
193+
String instanceId = (String) state.get(PERSISTED_INSTANCEID);
194194

195195
HashMap<String, String> properties = new HashMap<String, String>();
196196
properties.put("DialogId", getId());
@@ -210,7 +210,7 @@ public CompletableFuture<Void> endDialog(TurnContext turnContext, DialogInstance
210210
*/
211211
protected CompletableFuture<DialogTurnResult> onStep(WaterfallStepContext stepContext) {
212212
String stepName = waterfallStepName(stepContext.getIndex());
213-
String instanceId = (String) stepContext.getActiveDialog().getState().get(persistedInstanceId);
213+
String instanceId = (String) stepContext.getActiveDialog().getState().get(PERSISTED_INSTANCEID);
214214

215215
HashMap<String, String> properties = new HashMap<String, String>();
216216
properties.put("DialogId", getId());
@@ -245,11 +245,11 @@ protected CompletableFuture<DialogTurnResult> runStep(DialogContext dc, int inde
245245
// Update persisted step index
246246
Map<String, Object> state = (Map<String, Object>) dc.getActiveDialog().getState();
247247

248-
state.put(stepIndex, index);
248+
state.put(STEP_INDEX, index);
249249

250250
// Create step context
251-
Object options = state.get(persistedOptions);
252-
Map<String, Object> values = (Map<String, Object>) state.get(persistedValues);
251+
Object options = state.get(PERSISTED_OPTIONS);
252+
Map<String, Object> values = (Map<String, Object>) state.get(PERSISTED_VALUES);
253253
WaterfallStepContext stepContext =
254254
new WaterfallStepContext(this, dc, options, values, index, reason, result);
255255

libraries/bot-dialogs/src/main/java/com/microsoft/bot/dialogs/prompts/Prompt.java

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,23 @@
3232
* Defines the core behavior of prompt dialogs.
3333
*
3434
* When the prompt ends, it should return a Object that represents the value
35-
* that was prompted for. Use {@link DialogSet#add(Dialog)} or
36-
* {@link ComponentDialog#addDialog(Dialog)} to add a prompt to a dialog set or
37-
* component dialog, respectively. Use
35+
* that was prompted for. Use {@link com.microsoft.bot.dialogs.DialogSet#add(Dialog)} or
36+
* {@link com.microsoft.bot.dialogs.ComponentDialog#addDialog(Dialog)} to add a prompt to
37+
* a dialog set or component dialog, respectively. Use
3838
* {@link DialogContext#prompt(String, PromptOptions)} or
3939
* {@link DialogContext#beginDialog(String, Object)} to start the prompt. If you
40-
* start a prompt from a {@link WaterfallStep} in a {@link WaterfallDialog} ,
41-
* then the prompt result will be available in the next step of the waterfall.
40+
* start a prompt from a {@link com.microsoft.bot.dialogs.WaterfallStep} in a
41+
* {@link com.microsoft.bot.dialogs.WaterfallDialog}, then the prompt result will be
42+
* available in the next step of the waterfall.
4243
*
4344
* @param <T> Type the prompt is created for.
4445
*/
4546
public abstract class Prompt<T> extends Dialog {
4647

4748
public static final String ATTEMPTCOUNTKEY = "AttemptCount";
4849

49-
private final String persistedOptions = "options";
50-
private final String persistedState = "state";
50+
private static final String PERSISTED_OPTIONS = "options";
51+
private static final String PERSISTED_STATE = "state";
5152
private final PromptValidator<T> validator;
5253

5354
/**
@@ -58,8 +59,9 @@ public abstract class Prompt<T> extends Dialog {
5859
* @param validator Optional, a {@link PromptValidator{T}} that contains
5960
* additional, custom validation for this prompt.
6061
*
61-
* The value of {@link dialogId} must be unique within the
62-
* {@link DialogSet} or {@link ComponentDialog} to which the
62+
* The value of dialogId must be unique within the
63+
* {@link com.microsoft.bot.dialogs.DialogSet} or
64+
* {@link com.microsoft.bot.dialogs.ComponentDialog} to which the
6365
* prompt is added.
6466
*/
6567
public Prompt(String dialogId, PromptValidator<T> validator) {
@@ -114,16 +116,16 @@ public CompletableFuture<DialogTurnResult> beginDialog(DialogContext dc, Object
114116

115117
// Initialize prompt state
116118
Map<String, Object> state = dc.getActiveDialog().getState();
117-
state.put(persistedOptions, opt);
119+
state.put(PERSISTED_OPTIONS, opt);
118120

119121
HashMap<String, Object> pState = new HashMap<String, Object>();
120122
pState.put(ATTEMPTCOUNTKEY, 0);
121-
state.put(persistedState, pState);
123+
state.put(PERSISTED_STATE, pState);
122124

123125
// Send initial prompt
124126
onPrompt(dc.getContext(),
125-
(Map<String, Object>) state.get(persistedState),
126-
(PromptOptions) state.get(persistedOptions),
127+
(Map<String, Object>) state.get(PERSISTED_STATE),
128+
(PromptOptions) state.get(PERSISTED_OPTIONS),
127129
false);
128130
return CompletableFuture.completedFuture(Dialog.END_OF_TURN);
129131
}
@@ -157,8 +159,8 @@ public CompletableFuture<DialogTurnResult> continueDialog(DialogContext dc) {
157159

158160
// Perform base recognition
159161
DialogInstance instance = dc.getActiveDialog();
160-
Map<String, Object> state = (Map<String, Object>) instance.getState().get(persistedState);
161-
PromptOptions options = (PromptOptions) instance.getState().get(persistedOptions);
162+
Map<String, Object> state = (Map<String, Object>) instance.getState().get(PERSISTED_STATE);
163+
PromptOptions options = (PromptOptions) instance.getState().get(PERSISTED_OPTIONS);
162164
PromptRecognizerResult<T> recognized = onRecognize(dc.getContext(), state, options).join();
163165

164166
state.put(ATTEMPTCOUNTKEY, (int) state.get(ATTEMPTCOUNTKEY) + 1);
@@ -226,8 +228,8 @@ public CompletableFuture<DialogTurnResult> resumeDialog(DialogContext dc, Dialog
226228
*/
227229
@Override
228230
public CompletableFuture<Void> repromptDialog(TurnContext turnContext, DialogInstance instance) {
229-
Map<String, Object> state = (Map<String, Object>) instance.getState().get(persistedState);
230-
PromptOptions options = (PromptOptions) instance.getState().get(persistedOptions);
231+
Map<String, Object> state = (Map<String, Object>) instance.getState().get(PERSISTED_STATE);
232+
PromptOptions options = (PromptOptions) instance.getState().get(PERSISTED_OPTIONS);
231233
onPrompt(turnContext, state, options, false).join();
232234
return CompletableFuture.completedFuture(null);
233235
}
@@ -252,7 +254,7 @@ protected CompletableFuture<Boolean> onPreBubbleEvent(DialogContext dc, DialogEv
252254
// Perform base recognition
253255
Map<String, Object> state = dc.getActiveDialog().getState();
254256
PromptRecognizerResult<T> recognized = onRecognize(dc.getContext(),
255-
(Map<String, Object>) state.get(persistedState), (PromptOptions) state.get(persistedOptions)).join();
257+
(Map<String, Object>) state.get(PERSISTED_STATE), (PromptOptions) state.get(PERSISTED_OPTIONS)).join();
256258
return CompletableFuture.completedFuture(recognized.getSucceeded());
257259
}
258260

@@ -272,8 +274,8 @@ protected CompletableFuture<Boolean> onPreBubbleEvent(DialogContext dc, DialogEv
272274
* @param isRetry true if this is the first time this prompt dialog instance
273275
* is on the stack is prompting the user for input;
274276
* otherwise, false. Determines whether
275-
* {@link PromptOptions#prompt} or
276-
* {@link PromptOptions#retryPrompt} should be used.
277+
* {@link PromptOptions#getPrompt()} or
278+
* {@link PromptOptions#getRetryPrompt()} should be used.
277279
*
278280
* @return A {@link CompletableFuture} representing the asynchronous operation.
279281
*/

samples/43.complex-dialog/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Microsoft Corporation. All rights reserved.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Complex Dialog Sample
2+
3+
This sample creates a complex conversation with dialogs.
4+
5+
This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to use the prompts classes included in `botbuilder-dialogs`. This bot will ask for the user's name and age, then store the responses. It demonstrates a multi-turn dialog flow using a text prompt, a number prompt, and state accessors to store and retrieve values.
6+
7+
## Prerequisites
8+
9+
- Java 1.8+
10+
- Install [Maven](https://maven.apache.org/)
11+
- An account on [Azure](https://azure.microsoft.com) if you want to deploy to Azure.
12+
13+
## To try this sample locally
14+
- From the root of this project folder:
15+
- Build the sample using `mvn package`
16+
- Run it by using `java -jar .\target\bot-complexdialog-sample.jar`
17+
18+
- Test the bot using Bot Framework Emulator
19+
20+
[Bot Framework Emulator](https://github.com/microsoft/botframework-emulator) is a desktop application that allows bot developers to test and debug their bots on localhost or running remotely through a tunnel.
21+
22+
- Install the Bot Framework Emulator version 4.3.0 or greater from [here](https://github.com/Microsoft/BotFramework-Emulator/releases)
23+
24+
- Connect to the bot using Bot Framework Emulator
25+
26+
- Launch Bot Framework Emulator
27+
- File -> Open Bot
28+
- Enter a Bot URL of `http://localhost:3978/api/messages`
29+
30+
## Deploy the bot to Azure
31+
32+
As described on [Deploy your bot](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-deploy-az-cli), you will perform the first 4 steps to setup the Azure app, then deploy the code using the azure-webapp Maven plugin.
33+
34+
### 1. Login to Azure
35+
From a command (or PowerShell) prompt in the root of the bot folder, execute:
36+
`az login`
37+
38+
### 2. Set the subscription
39+
`az account set --subscription "<azure-subscription>"`
40+
41+
If you aren't sure which subscription to use for deploying the bot, you can view the list of subscriptions for your account by using `az account list` command.
42+
43+
### 3. Create an App registration
44+
`az ad app create --display-name "<botname>" --password "<appsecret>" --available-to-other-tenants`
45+
46+
Replace `<botname>` and `<appsecret>` with your own values.
47+
48+
`<botname>` is the unique name of your bot.
49+
`<appsecret>` is a minimum 16 character password for your bot.
50+
51+
Record the `appid` from the returned JSON
52+
53+
### 4. Create the Azure resources
54+
Replace the values for `<appid>`, `<appsecret>`, `<botname>`, and `<groupname>` in the following commands:
55+
56+
#### To a new Resource Group
57+
`az deployment sub create --name "multiTurnPromptBotDeploy" --location "westus" --template-file ".\deploymentTemplates\template-with-new-rg.json" --parameters appId="<appid>" appSecret="<appsecret>" botId="<botname>" botSku=S1 newAppServicePlanName="multiTurnPromptBotPlan" newWebAppName="multiTurnPromptBot" groupLocation="westus" newAppServicePlanLocation="westus"`
58+
59+
#### To an existing Resource Group
60+
`az deployment group create --resource-group "<groupname>" --template-file ".\deploymentTemplates\template-with-preexisting-rg.json" --parameters appId="<appid>" appSecret="<appsecret>" botId="<botname>" newWebAppName="multiTurnPromptBot" newAppServicePlanName="multiTurnPromptBotPlan" appServicePlanLocation="westus" --name "multiTurnPromptBot"`
61+
62+
### 5. Update app id and password
63+
In src/main/resources/application.properties update
64+
- `MicrosoftAppPassword` with the botsecret value
65+
- `MicrosoftAppId` with the appid from the first step
66+
67+
### 6. Deploy the code
68+
- Execute `mvn clean package`
69+
- Execute `mvn azure-webapp:deploy -Dgroupname="<groupname>" -Dbotname="<botname>"`
70+
71+
If the deployment is successful, you will be able to test it via "Test in Web Chat" from the Azure Portal using the "Bot Channel Registration" for the bot.
72+
73+
After the bot is deployed, you only need to execute #6 if you make changes to the bot.
74+
75+
76+
## Further reading
77+
78+
- [Bot Framework Documentation](https://docs.botframework.com)
79+
- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0)
80+
- [Dialogs](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-dialog?view=azure-bot-service-4.0)
81+
- [Gathering Input Using Prompts](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-prompts?view=azure-bot-service-4.0&tabs=csharp)
82+
- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0)
83+
- [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0)
84+
- [Azure Bot Service Documentation](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0)
85+
- [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest)
86+
- [Azure Portal](https://portal.azure.com)
87+
- [Channels and Bot Connector Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-concepts?view=azure-bot-service-4.0)
88+
- [Maven Plugin for Azure App Service](https://docs.microsoft.com/en-us/java/api/overview/azure/maven/azure-webapp-maven-plugin/readme?view=azure-java-stable)
89+
- [Spring Boot](https://spring.io/projects/spring-boot)
90+
- [Azure for Java cloud developers](https://docs.microsoft.com/en-us/azure/java/?view=azure-java-stable)

0 commit comments

Comments
 (0)