Soru sorup bilgi toplamak, botun kullanıcılarla etkileşim kurmasının ana yollarından biridir. İletişim kutusu kitaplığı, belirli bir veri türüyle eşleştiğinden veya özel doğrulama kurallarına uyduğundan emin olmak için soru sormayı ve yanıtı doğrulamayı kolaylaştıran istem sınıfları gibi kullanışlı yerleşik özellikler sağlar.
İletişim kutusu kitaplığını kullanarak doğrusal ve daha karmaşık konuşma akışlarını yönetebilirsiniz. Doğrusal etkileşimde bot sabit bir adım dizisinde çalışır ve konuşma tamamlar. Bot kullanıcıdan bilgi toplaması gerektiğinde iletişim kutusu kullanışlıdır.
Bu makalede, istemler oluşturup bunları şelale iletişim kutusundan çağırarak doğrusal konuşma akışının nasıl uygulandığı gösterilmektedir.
İletişim kutusu kitaplığını kullanmadan kendi istemlerinizi yazma örnekleri için Kullanıcı girişi toplamak için kendi istemlerinizi oluşturma makalesine bakın.
Çok dönüşlü istemler örneği, kullanıcıya bir dizi soru soran doğrusal bir etkileşim oluşturmak için şelale iletişim kutusu, birkaç istem ve bileşen iletişim kutusu kullanır. Kod, şu adımlar arasında geçiş yapmak için bir iletişim kutusu kullanır:
Son olarak evet yanıtı verdiyseniz toplanan bilgileri görüntüleyin; aksi takdirde, kullanıcıya bilgilerinin saklanmayacağını söyleyin.
İletişim kutularını kullanmak için Microsoft.Bot.Builder.Dialogs NuGet paketini yükleyin.
Bot, aracılığıyla UserProfileDialog
kullanıcıyla etkileşim kurar. Bot DialogBot
sınıfı oluşturulurken, UserProfileDialog
ana iletişim kutusu olarak ayarlanır. Bot daha sonra iletişim kutusuna erişmek için bir Run
yardımcı yöntemi kullanır.
İletişim Kutuları\UserProfileDialog.cs
sınıfından türetilen ComponentDialog
ve yedi adımı olan öğesini oluşturarak UserProfileDialog
başlayın.
Oluşturucuda UserProfileDialog
şelale adımlarını, istemlerini ve şelale iletişim kutusunu oluşturun ve bunları iletişim kutusu kümesine ekleyin. İstemlerin, kullanıldıkları iletişim kutusunda olması gerekir.
public UserProfileDialog(UserState userState)
: base(nameof(UserProfileDialog))
{
_userProfileAccessor = userState.CreateProperty<UserProfile>("UserProfile");
// This array defines how the Waterfall will execute.
var waterfallSteps = new WaterfallStep[]
{
TransportStepAsync,
NameStepAsync,
NameConfirmStepAsync,
AgeStepAsync,
PictureStepAsync,
SummaryStepAsync,
ConfirmStepAsync,
};
// Add named dialogs to the DialogSet. These names are saved in the dialog state.
AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps));
AddDialog(new TextPrompt(nameof(TextPrompt)));
AddDialog(new NumberPrompt<int>(nameof(NumberPrompt<int>), AgePromptValidatorAsync));
AddDialog(new ChoicePrompt(nameof(ChoicePrompt)));
AddDialog(new ConfirmPrompt(nameof(ConfirmPrompt)));
AddDialog(new AttachmentPrompt(nameof(AttachmentPrompt), PicturePromptValidatorAsync));
// The initial child Dialog to run.
InitialDialogId = nameof(WaterfallDialog);
}
Ardından, iletişim kutusunun giriş isteminde kullandığı adımları ekleyin. İstemi kullanmak için, bunu iletişim kutunuzdaki bir adımdan çağırın ve kullanarak stepContext.Result
aşağıdaki adımda istem sonucunu alın. Arka planda istemler iki adımlı bir iletişim kutusu olur. İlk olarak, istem giriş ister. Ardından geçerli değeri döndürür veya geçerli bir giriş alana kadar baştan başlayıp yeniden üretmeye başlar.
Her zaman bir şelale adımından null DialogTurnResult
olmayan bir değer döndürmelisiniz. Aksi takdirde iletişim kutunuz tasarlandığı gibi çalışmayabilir. Şelale iletişim kutusunda uygulaması aşağıda NameStepAsync
gösterilmiştir.
private static async Task<DialogTurnResult> NameStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["transport"] = ((FoundChoice)stepContext.Result).Value;
return await stepContext.PromptAsync(nameof(TextPrompt), new PromptOptions { Prompt = MessageFactory.Text("Please enter your name.") }, cancellationToken);
}
içinde AgeStepAsync
, istem ayrıştıramadığı bir biçimde olduğundan veya giriş doğrulama ölçütlerinde başarısız olduğundan kullanıcının girişi doğrulanamadığından için bir yeniden deneme istemi belirtin. Bu durumda, yeniden deneme istemi sağlanmamışsa, istem ilk istem metnini kullanarak kullanıcıyı giriş için yeniden oluşturur.
private async Task<DialogTurnResult> AgeStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
if ((bool)stepContext.Result)
{
// User said "yes" so we will be prompting for the age.
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
var promptOptions = new PromptOptions
{
Prompt = MessageFactory.Text("Please enter your age."),
RetryPrompt = MessageFactory.Text("The value entered must be greater than 0 and less than 150."),
};
return await stepContext.PromptAsync(nameof(NumberPrompt<int>), promptOptions, cancellationToken);
}
else
{
// User said "no" so we will skip the next step. Give -1 as the age.
return await stepContext.NextAsync(-1, cancellationToken);
}
}
UserProfile.cs
Kullanıcının taşıma, ad ve yaş modu sınıfın UserProfile
bir örneğine kaydedilir.
public class UserProfile
{
public string Transport { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Attachment Picture { get; set; }
}
İletişim Kutuları\UserProfileDialog.cs
Son adımda, önceki şelale adımında adı verilen iletişim kutusu tarafından döndürüleni denetleyin stepContext.Result
. Dönüş değeri true ise, kullanıcı profili erişimcisi kullanıcı profilini alır ve güncelleştirir. Kullanıcı profilini almak için öğesini çağırın GetAsync
ve ardından , userProfile.Name
userProfile.Age
ve userProfile.Picture
özelliklerinin değerlerini userProfile.Transport
ayarlayın. Son olarak, iletişim kutusunu sona erdiren çağrısından EndDialogAsync
önce kullanıcının bilgilerini özetleyin. İletişim kutusunu sonlandırmak, iletişim kutusu yığınını kapatır ve iletişim kutusunun üst öğesine isteğe bağlı bir sonuç döndürür. Üst öğe, yeni sona eren iletişim kutusunu başlatan iletişim kutusu veya yöntemdir.
else
{
msg += $" Your profile will not be kept.";
}
await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is the end.
return await stepContext.EndDialogAsync(cancellationToken: cancellationToken);
}
private async Task<DialogTurnResult> SummaryStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
stepContext.Values["picture"] = ((IList<Attachment>)stepContext.Result)?.FirstOrDefault();
// Get the current profile object from user state.
var userProfile = await _userProfileAccessor.GetAsync(stepContext.Context, () => new UserProfile(), cancellationToken);
userProfile.Transport = (string)stepContext.Values["transport"];
userProfile.Name = (string)stepContext.Values["name"];
userProfile.Age = (int)stepContext.Values["age"];
userProfile.Picture = (Attachment)stepContext.Values["picture"];
var msg = $"I have your mode of transport as {userProfile.Transport} and your name as {userProfile.Name}";
if (userProfile.Age != -1)
{
msg += $" and your age as {userProfile.Age}";
}
msg += ".";
await stepContext.Context.SendActivityAsync(MessageFactory.Text(msg), cancellationToken);
if (userProfile.Picture != null)
{
try
{
await stepContext.Context.SendActivityAsync(MessageFactory.Attachment(userProfile.Picture, "This is your profile picture."), cancellationToken);
}
catch
{
await stepContext.Context.SendActivityAsync(MessageFactory.Text("A profile picture was saved but could not be displayed here."), cancellationToken);
İletişim kutularını kullanmak için projenizin botbuilder-dialogs npm paketini yüklemesi gerekir.
Bot, aracılığıyla UserProfileDialog
kullanıcıyla etkileşim kurar. bot'un DialogBot
UserProfileDialog
öğesini oluştururken, ana iletişim kutusu olarak ayarlanır. Bot daha sonra iletişim kutusuna erişmek için bir run
yardımcı yöntemi kullanır.
iletişim kutuları/userProfileDialog.js
sınıfından türetilen ComponentDialog
ve yedi adımı olan öğesini oluşturarak UserProfileDialog
başlayın.
Oluşturucuda UserProfileDialog
şelale adımlarını, istemlerini ve şelale iletişim kutusunu oluşturun ve bunları iletişim kutusu kümesine ekleyin. İstemlerin, kullanıldıkları iletişim kutusunda olması gerekir.
constructor(userState) {
super('userProfileDialog');
this.userProfile = userState.createProperty(USER_PROFILE);
this.addDialog(new TextPrompt(NAME_PROMPT));
this.addDialog(new ChoicePrompt(CHOICE_PROMPT));
this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT));
this.addDialog(new NumberPrompt(NUMBER_PROMPT, this.agePromptValidator));
this.addDialog(new AttachmentPrompt(ATTACHMENT_PROMPT, this.picturePromptValidator));
this.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
this.transportStep.bind(this),
this.nameStep.bind(this),
this.nameConfirmStep.bind(this),
this.ageStep.bind(this),
this.pictureStep.bind(this),
this.summaryStep.bind(this),
this.confirmStep.bind(this)
]));
this.initialDialogId = WATERFALL_DIALOG;
}
Ardından, iletişim kutusunun giriş isteminde kullandığı adımları ekleyin. İstem kullanmak için, bunu iletişim kutunuzdaki bir adımdan çağırın ve aşağıdaki adımdaki istem sonucunu adım bağlamından alın; bu durumda kullanarak step.result
. Arka planda istemler iki adımlı bir iletişim kutusu olur. İlk olarak, istem giriş ister. Ardından geçerli değeri döndürür veya geçerli bir giriş alana kadar baştan başlayıp yeniden üretmeye başlar.
Her zaman bir şelale adımından null DialogTurnResult
olmayan bir değer döndürmelisiniz. Aksi takdirde iletişim kutunuz tasarlandığı gibi çalışmayabilir. Aşağıda şelale iletişim kutusundaki uygulaması nameStep
gösterilmiştir.
async nameStep(step) {
step.values.transport = step.result.value;
return await step.prompt(NAME_PROMPT, 'Please enter your name.');
}
içinde ageStep
, kullanıcının girişi, istemin ayrıştıramadığı bir biçimde olduğundan veya giriş yukarıdaki oluşturucuda belirtilen doğrulama ölçütlerinde başarısız olduğundan doğrulanamadığından için bir yeniden deneme istemi belirtin. Bu durumda, yeniden deneme istemi sağlanmamışsa, istem ilk istem metnini kullanarak kullanıcıyı giriş için yeniden oluşturur.
async ageStep(step) {
if (step.result) {
// User said "yes" so we will be prompting for the age.
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
const promptOptions = { prompt: 'Please enter your age.', retryPrompt: 'The value entered must be greater than 0 and less than 150.' };
return await step.prompt(NUMBER_PROMPT, promptOptions);
} else {
// User said "no" so we will skip the next step. Give -1 as the age.
return await step.next(-1);
}
}
userProfile.js
Kullanıcının taşıma, ad ve yaş modu sınıfın UserProfile
bir örneğine kaydedilir.
class UserProfile {
constructor(transport, name, age, picture) {
this.transport = transport;
this.name = name;
this.age = age;
this.picture = picture;
}
}
iletişim kutuları/userProfileDialog.js
Son adımda, önceki şelale adımında adı verilen iletişim kutusu tarafından döndürüleni denetleyin step.result
. Dönüş değeri true ise, kullanıcı profili erişimcisi kullanıcı profilini alır ve güncelleştirir. Kullanıcı profilini almak için öğesini çağırın get
ve ardından , userProfile.name
userProfile.age
ve userProfile.picture
özelliklerinin değerlerini userProfile.transport
ayarlayın. Son olarak, iletişim kutusunu sona erdiren çağrısından endDialog
önce kullanıcının bilgilerini özetleyin. İletişim kutusunu sonlandırmak, iletişim kutusu yığınını kapatır ve iletişim kutusunun üst öğesine isteğe bağlı bir sonuç döndürür. Üst öğe, yeni sona eren iletişim kutusunu başlatan iletişim kutusu veya yöntemdir.
await step.context.sendActivity(msg);
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
return await step.endDialog();
}
async summaryStep(step) {
step.values.picture = step.result && step.result[0];
// Get the current profile object from user state.
const userProfile = await this.userProfile.get(step.context, new UserProfile());
userProfile.transport = step.values.transport;
userProfile.name = step.values.name;
userProfile.age = step.values.age;
userProfile.picture = step.values.picture;
let msg = `I have your mode of transport as ${ userProfile.transport } and your name as ${ userProfile.name }`;
if (userProfile.age !== -1) {
msg += ` and your age as ${ userProfile.age }`;
}
msg += '.';
await step.context.sendActivity(msg);
if (userProfile.picture) {
try {
await step.context.sendActivity(MessageFactory.attachment(userProfile.picture, 'This is your profile picture.'));
} catch {
await step.context.sendActivity('A profile picture was saved but could not be displayed here.');
}
Şelale iletişim kutusunu çalıştırmak için uzantı yöntemini oluşturma
run
içinde userProfileDialog
tanımlanan bir yardımcı yöntemi, iletişim kutusu bağlamını oluşturmak ve bu bağlama erişmek için kullanılır. burada, accessor
iletişim kutusu durum özelliği için durum özelliği erişimcisi ve this
kullanıcı profili bileşeni iletişim kutusudur. Bileşen iletişim kutuları bir iç iletişim kutusu kümesi tanımladığından, ileti işleyici koduna görünür ve bir iletişim kutusu bağlamı oluşturmak için kullanılan bir dış iletişim kutusu kümesi oluşturulmalıdır.
İletişim kutusu bağlamı yöntemi çağrılarak createContext
oluşturulur ve bot'un dönüş işleyicisinin içinden iletişim kutusu kümesiyle etkileşim kurmak için kullanılır. İletişim kutusu bağlamı geçerli dönüş bağlamını, üst iletişim kutusunu ve iletişim kutusu içinde bilgileri korumak için bir yöntem sağlayan iletişim kutusu durumunu içerir.
İletişim kutusu bağlamı, dize kimliğiyle bir iletişim kutusu başlatmanıza veya geçerli iletişim kutusuna (birden çok adım içeren şelale iletişim kutusu gibi) devam etmenizi sağlar. İletişim kutusu bağlamı tüm bot iletişim kutularına ve şelale adımlarına geçirilir.
async run(turnContext, accessor) {
const dialogSet = new DialogSet(accessor);
dialogSet.add(this);
const dialogContext = await dialogSet.createContext(turnContext);
const results = await dialogContext.continueDialog();
if (results.status === DialogTurnStatus.empty) {
await dialogContext.beginDialog(this.id);
}
}
Bot, aracılığıyla UserProfileDialog
kullanıcıyla etkileşim kurar. Bot DialogBot
sınıfı oluşturulurken, UserProfileDialog
ana iletişim kutusu olarak ayarlanır. Bot daha sonra iletişim kutusuna erişmek için bir Run
yardımcı yöntemi kullanır.
UserProfileDialog.java
sınıfından türetilen ComponentDialog
ve yedi adımı olan öğesini oluşturarak UserProfileDialog
başlayın.
Oluşturucuda UserProfileDialog
şelale adımlarını, istemlerini ve şelale iletişim kutusunu oluşturun ve bunları iletişim kutusu kümesine ekleyin. İstemlerin, kullanıldıkları iletişim kutusunda olması gerekir.
public UserProfileDialog(UserState withUserState) {
super("UserProfileDialog");
userProfileAccessor = withUserState.createProperty("UserProfile");
WaterfallStep[] waterfallSteps = {
UserProfileDialog::transportStep,
UserProfileDialog::nameStep,
this::nameConfirmStep,
this::ageStep,
UserProfileDialog::pictureStep,
this::confirmStep,
this::summaryStep
};
// Add named dialogs to the DialogSet. These names are saved in the dialog state.
addDialog(new WaterfallDialog("WaterfallDialog", Arrays.asList(waterfallSteps)));
addDialog(new TextPrompt("TextPrompt"));
addDialog(new NumberPrompt<Integer>("NumberPrompt", UserProfileDialog::agePromptValidator, Integer.class));
addDialog(new ChoicePrompt("ChoicePrompt"));
addDialog(new ConfirmPrompt("ConfirmPrompt"));
addDialog(new AttachmentPrompt("AttachmentPrompt", UserProfileDialog::picturePromptValidator));
// The initial child Dialog to run.
setInitialDialogId("WaterfallDialog");
}
Ardından, iletişim kutusunun giriş isteminde kullandığı adımları ekleyin. İstemi kullanmak için, bunu iletişim kutunuzdaki bir adımdan çağırın ve kullanarak stepContext.getResult()
aşağıdaki adımda istem sonucunu alın. Arka planda istemler iki adımlı bir iletişim kutusu olur. İlk olarak, istem giriş ister. Ardından geçerli değeri döndürür veya geçerli bir giriş alana kadar baştan başlayıp yeniden üretmeye başlar.
Her zaman bir şelale adımından null DialogTurnResult
olmayan bir değer döndürmelisiniz. Aksi takdirde iletişim kutunuz tasarlandığı gibi çalışmayabilir. Şelale iletişim kutusunda uygulaması aşağıda nameStep
gösterilmiştir.
private static CompletableFuture<DialogTurnResult> nameStep(WaterfallStepContext stepContext) {
stepContext.getValues().put("transport", ((FoundChoice) stepContext.getResult()).getValue());
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Please enter your name."));
return stepContext.prompt("TextPrompt", promptOptions);
}
içinde ageStep
, istem ayrıştıramadığı bir biçimde olduğundan veya giriş doğrulama ölçütlerinde başarısız olduğundan kullanıcının girişi doğrulanamadığından için bir yeniden deneme istemi belirtin. Bu durumda, yeniden deneme istemi sağlanmamışsa, istem ilk istem metnini kullanarak kullanıcıyı giriş için yeniden oluşturur.
private CompletableFuture<DialogTurnResult> ageStep(WaterfallStepContext stepContext) {
if ((Boolean)stepContext.getResult()) {
// User said "yes" so we will be prompting for the age.
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Please enter your age."));
promptOptions.setRetryPrompt(MessageFactory.text("The value entered must be greater than 0 and less than 150."));
return stepContext.prompt("NumberPrompt", promptOptions);
}
// User said "no" so we will skip the next step. Give -1 as the age.
return stepContext.next(-1);
}
UserProfile.java
Kullanıcının taşıma, ad ve yaş modu sınıfın UserProfile
bir örneğine kaydedilir.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.multiturnprompt;
import com.microsoft.bot.schema.Attachment;
/**
* This is our application state.
*/
public class UserProfile {
public String transport;
public String name;
public Integer age;
public Attachment picture;
}
UserProfileDialog.java
Son adımda, önceki şelale adımında adı verilen iletişim kutusu tarafından döndürüleni denetleyin stepContext.Result
. Dönüş değeri true ise, kullanıcı profili erişimcisi kullanıcı profilini alır ve güncelleştirir. Kullanıcı profilini almak için öğesini çağırın get
ve ardından , userProfile.Name
userProfile.Age
ve userProfile.Picture
özelliklerinin değerlerini userProfile.Transport
ayarlayın. Son olarak, iletişim kutusunu sona erdiren çağrısından endDialog
önce kullanıcının bilgilerini özetleyin. İletişim kutusunu sonlandırmak, iletişim kutusu yığınını kapatır ve iletişim kutusunun üst öğesine isteğe bağlı bir sonuç döndürür. Üst öğe, yeni sona eren iletişim kutusunu başlatan iletişim kutusu veya yöntemdir.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.microsoft.bot.sample.multiturnprompt;
import com.microsoft.bot.builder.MessageFactory;
import com.microsoft.bot.builder.StatePropertyAccessor;
import com.microsoft.bot.builder.UserState;
import com.microsoft.bot.connector.Channels;
import com.microsoft.bot.dialogs.ComponentDialog;
import com.microsoft.bot.dialogs.DialogTurnResult;
import com.microsoft.bot.dialogs.WaterfallDialog;
import com.microsoft.bot.dialogs.WaterfallStep;
import com.microsoft.bot.dialogs.WaterfallStepContext;
import com.microsoft.bot.dialogs.choices.ChoiceFactory;
import com.microsoft.bot.dialogs.choices.FoundChoice;
import com.microsoft.bot.dialogs.prompts.AttachmentPrompt;
import com.microsoft.bot.dialogs.prompts.ChoicePrompt;
import com.microsoft.bot.dialogs.prompts.ConfirmPrompt;
import com.microsoft.bot.dialogs.prompts.NumberPrompt;
import com.microsoft.bot.dialogs.prompts.PromptOptions;
import com.microsoft.bot.dialogs.prompts.PromptValidatorContext;
import com.microsoft.bot.dialogs.prompts.TextPrompt;
import com.microsoft.bot.schema.Attachment;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.apache.commons.lang3.StringUtils;
public class UserProfileDialog extends ComponentDialog {
private final StatePropertyAccessor<UserProfile> userProfileAccessor;
public UserProfileDialog(UserState withUserState) {
super("UserProfileDialog");
userProfileAccessor = withUserState.createProperty("UserProfile");
WaterfallStep[] waterfallSteps = {
UserProfileDialog::transportStep,
UserProfileDialog::nameStep,
this::nameConfirmStep,
this::ageStep,
UserProfileDialog::pictureStep,
this::confirmStep,
this::summaryStep
};
// Add named dialogs to the DialogSet. These names are saved in the dialog state.
addDialog(new WaterfallDialog("WaterfallDialog", Arrays.asList(waterfallSteps)));
addDialog(new TextPrompt("TextPrompt"));
addDialog(new NumberPrompt<Integer>("NumberPrompt", UserProfileDialog::agePromptValidator, Integer.class));
addDialog(new ChoicePrompt("ChoicePrompt"));
addDialog(new ConfirmPrompt("ConfirmPrompt"));
addDialog(new AttachmentPrompt("AttachmentPrompt", UserProfileDialog::picturePromptValidator));
// The initial child Dialog to run.
setInitialDialogId("WaterfallDialog");
}
private static CompletableFuture<DialogTurnResult> transportStep(WaterfallStepContext stepContext) {
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
// Running a prompt here means the next WaterfallStep will be run when the user's response is received.
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Please enter your mode of transport."));
promptOptions.setChoices(ChoiceFactory.toChoices("Car", "Bus", "Bicycle"));
return stepContext.prompt("ChoicePrompt", promptOptions);
}
private static CompletableFuture<DialogTurnResult> nameStep(WaterfallStepContext stepContext) {
stepContext.getValues().put("transport", ((FoundChoice) stepContext.getResult()).getValue());
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Please enter your name."));
return stepContext.prompt("TextPrompt", promptOptions);
}
private CompletableFuture<DialogTurnResult> nameConfirmStep(WaterfallStepContext stepContext) {
stepContext.getValues().put("name", stepContext.getResult());
// We can send messages to the user at any point in the WaterfallStep.
return stepContext.getContext().sendActivity(MessageFactory.text(String.format("Thanks %s.", stepContext.getResult())))
.thenCompose(resourceResponse -> {
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Would you like to give your age?"));
return stepContext.prompt("ConfirmPrompt", promptOptions);
});
}
private CompletableFuture<DialogTurnResult> ageStep(WaterfallStepContext stepContext) {
if ((Boolean)stepContext.getResult()) {
// User said "yes" so we will be prompting for the age.
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Please enter your age."));
promptOptions.setRetryPrompt(MessageFactory.text("The value entered must be greater than 0 and less than 150."));
return stepContext.prompt("NumberPrompt", promptOptions);
}
// User said "no" so we will skip the next step. Give -1 as the age.
return stepContext.next(-1);
}
private static CompletableFuture<DialogTurnResult> pictureStep(WaterfallStepContext stepContext) {
stepContext.getValues().put("age", (Integer) stepContext.getResult());
String msg = (Integer)stepContext.getValues().get("age") == -1
? "No age given."
: String.format("I have your age as %d.", (Integer)stepContext.getValues().get("age"));
// We can send messages to the user at any point in the WaterfallStep.
return stepContext.getContext().sendActivity(MessageFactory.text(msg))
.thenCompose(resourceResponse -> {
if (StringUtils.equals(stepContext.getContext().getActivity().getChannelId(), Channels.MSTEAMS)) {
// This attachment prompt example is not designed to work for Teams attachments, so skip it in this case
return stepContext.getContext().sendActivity(MessageFactory.text("Skipping attachment prompt in Teams channel..."))
.thenCompose(resourceResponse1 -> stepContext.next(null));
}
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Please attach a profile picture (or type any message to skip)."));
promptOptions.setRetryPrompt(MessageFactory.text("The attachment must be a jpeg/png image file."));
return stepContext.prompt("AttachmentPrompt", promptOptions);
});
}
private CompletableFuture<DialogTurnResult> confirmStep(WaterfallStepContext stepContext) {
List<Attachment> attachments = (List<Attachment>)stepContext.getResult();
stepContext.getValues().put("picture", attachments == null ? null : attachments.get(0));
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is a Prompt Dialog.
PromptOptions promptOptions = new PromptOptions();
promptOptions.setPrompt(MessageFactory.text("Is this ok?"));
return stepContext.prompt("ConfirmPrompt", promptOptions);
}
private CompletableFuture<DialogTurnResult> summaryStep(WaterfallStepContext stepContext) {
if ((Boolean)stepContext.getResult()) {
// Get the current profile object from user state.
return userProfileAccessor.get(stepContext.getContext(), () -> new UserProfile())
.thenCompose(userProfile -> {
userProfile.transport = (String) stepContext.getValues().get("transport");
userProfile.name = (String) stepContext.getValues().get("name");
userProfile.age = (Integer) stepContext.getValues().get("age");
userProfile.picture = (Attachment) stepContext.getValues().get("picture");
String msg = String.format(
"I have your mode of transport as %s and your name as %s",
userProfile.transport, userProfile.name
);
if (userProfile.age != -1) {
msg += String.format(" and your age as %s", userProfile.age);
}
msg += ".";
return stepContext.getContext().sendActivity(MessageFactory.text(msg))
.thenApply(resourceResponse -> userProfile);
})
.thenCompose(userProfile -> {
if (userProfile.picture != null) {
try {
return stepContext.getContext().sendActivity(
MessageFactory.attachment(userProfile.picture,
"This is your profile picture."
));
} catch(Exception ex) {
return stepContext.getContext().sendActivity(
MessageFactory.text(
"A profile picture was saved but could not be displayed here."
));
}
}
return stepContext.getContext().sendActivity(
MessageFactory.text("A profile picture wasn't attached.")
);
})
.thenCompose(resourceResponse -> stepContext.endDialog());
}
// WaterfallStep always finishes with the end of the Waterfall or with another dialog; here it is the end.
return stepContext.getContext().sendActivity(MessageFactory.text("Thanks. Your profile will not be kept."))
.thenCompose(resourceResponse -> stepContext.endDialog());
}
private static CompletableFuture<Boolean> agePromptValidator(
PromptValidatorContext<Integer> promptContext
) {
// This condition is our validation rule. You can also change the value at this point.
return CompletableFuture.completedFuture(
promptContext.getRecognized().getSucceeded()
&& promptContext.getRecognized().getValue() > 0
&& promptContext.getRecognized().getValue() < 150);
}
private static CompletableFuture<Boolean> picturePromptValidator(
PromptValidatorContext<List<Attachment>> promptContext
) {
if (promptContext.getRecognized().getSucceeded()) {
List<Attachment> attachments = promptContext.getRecognized().getValue();
List<Attachment> validImages = new ArrayList<>();
for (Attachment attachment : attachments) {
if (StringUtils.equals(
attachment.getContentType(), "image/jpeg") || StringUtils.equals(attachment.getContentType(), "image/png")
) {
validImages.add(attachment);
}
}
promptContext.getRecognized().setValue(validImages);
// If none of the attachments are valid images, the retry prompt should be sent.
return CompletableFuture.completedFuture(!validImages.isEmpty());
}
else {
// We can return true from a validator function even if Recognized.Succeeded is false.
return promptContext.getContext().sendActivity("No attachments received. Proceeding without a profile picture...")
.thenApply(resourceResponse -> true);
}
}
}
İletişim kutularını kullanmak için bir terminalden çalıştırarak pip install botbuilder-ai
pip install botbuilder-dialogs
botbuilder-dialogs ve botbuilder-ai PyPI paketlerini yükleyin.
Bot, aracılığıyla UserProfileDialog
kullanıcıyla etkileşim kurar. Bot DialogBot
sınıfı oluşturulduğunda, UserProfileDialog
ana iletişim kutusu olarak ayarlanır. Bot daha sonra iletişim kutusuna erişmek için bir run_dialog
yardımcı yöntemi kullanır.
iletişim kutuları\user_profile_dialog.py
sınıfından türetilen ComponentDialog
ve yedi adımı olan öğesini oluşturarak UserProfileDialog
başlayın.
Oluşturucuda UserProfileDialog
şelale adımlarını, istemlerini ve şelale iletişim kutusunu oluşturun ve bunları iletişim kutusu kümesine ekleyin. İstemlerin, kullanıldıkları iletişim kutusunda olması gerekir.
def __init__(self, user_state: UserState):
super(UserProfileDialog, self).__init__(UserProfileDialog.__name__)
self.user_profile_accessor = user_state.create_property("UserProfile")
self.add_dialog(
WaterfallDialog(
WaterfallDialog.__name__,
[
self.transport_step,
self.name_step,
self.name_confirm_step,
self.age_step,
self.picture_step,
self.summary_step,
self.confirm_step,
],
)
)
self.add_dialog(TextPrompt(TextPrompt.__name__))
self.add_dialog(
NumberPrompt(NumberPrompt.__name__, UserProfileDialog.age_prompt_validator)
)
self.add_dialog(ChoicePrompt(ChoicePrompt.__name__))
self.add_dialog(ConfirmPrompt(ConfirmPrompt.__name__))
self.add_dialog(
AttachmentPrompt(
AttachmentPrompt.__name__, UserProfileDialog.picture_prompt_validator
)
)
self.initial_dialog_id = WaterfallDialog.__name__
Ardından, iletişim kutusunun giriş isteminde kullandığı adımları ekleyin. İstemi kullanmak için, bunu iletişim kutunuzdaki bir adımdan çağırın ve kullanarak step_context.result
aşağıdaki adımda istem sonucunu alın. Arka planda istemler iki adımlı bir iletişim kutusu olur. İlk olarak, istem giriş ister. Ardından geçerli değeri döndürür veya geçerli bir giriş alana kadar baştan başlayıp yeniden üretmeye başlar.
Her zaman bir şelale adımından null DialogTurnResult
olmayan bir değer döndürmelisiniz. Aksi takdirde iletişim kutunuz tasarlandığı gibi çalışmayabilir. Burada şelale iletişim kutusunda için name_step
uygulamasını görebilirsiniz.
async def name_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
step_context.values["transport"] = step_context.result.value
return await step_context.prompt(
TextPrompt.__name__,
PromptOptions(prompt=MessageFactory.text("Please enter your name.")),
)
içinde age_step
, kullanıcının girişi, istemin ayrıştıramadığı bir biçimde olduğundan veya giriş yukarıdaki oluşturucuda belirtilen doğrulama ölçütlerinde başarısız olduğundan doğrulanamadığından için bir yeniden deneme istemi belirtin. Bu durumda, yeniden deneme istemi sağlanmamışsa, istem ilk istem metnini kullanarak kullanıcıyı giriş için yeniden oluşturacaktır
async def age_step(self, step_context: WaterfallStepContext) -> DialogTurnResult:
if step_context.result:
# User said "yes" so we will be prompting for the age.
# WaterfallStep always finishes with the end of the Waterfall or with another dialog,
# here it is a Prompt Dialog.
return await step_context.prompt(
NumberPrompt.__name__,
PromptOptions(
prompt=MessageFactory.text("Please enter your age."),
retry_prompt=MessageFactory.text(
"The value entered must be greater than 0 and less than 150."
),
),
)
# User said "no" so we will skip the next step. Give -1 as the age.
return await step_context.next(-1)
data_models\user_profile.py
Kullanıcının taşıma, ad ve yaş modu sınıfın UserProfile
bir örneğine kaydedilir.
class UserProfile:
"""
This is our application state. Just a regular serializable Python class.
"""
def __init__(self, name: str = None, transport: str = None, age: int = 0, picture: Attachment = None):
self.name = name
self.transport = transport
self.age = age
self.picture = picture
iletişim kutuları\user_profile_dialog.py
Son adımda, önceki şelale adımında adı verilen iletişim kutusu tarafından döndürüleni denetleyin step_context.result
. Dönüş değeri true ise, kullanıcı profili erişimcisi kullanıcı profilini alır ve güncelleştirir. Kullanıcı profilini almak için öğesini çağırın get
ve ardından , user_profile.name
ve user_profile.age
özelliklerinin değerlerini user_profile.transport
ayarlayın. Son olarak, iletişim kutusunu sona erdiren çağrısından end_dialog
önce kullanıcının bilgilerini özetleyin. İletişim kutusunu sonlandırmak, iletişim kutusu yığınını kapatır ve iletişim kutusunun üst öğesine isteğe bağlı bir sonuç döndürür. Üst öğe, yeni sona eren iletişim kutusunu başlatan iletişim kutusu veya yöntemdir.
async def summary_step(
self, step_context: WaterfallStepContext
) -> DialogTurnResult:
step_context.values["picture"] = (
None if not step_context.result else step_context.result[0]
)
# Get the current profile object from user state. Changes to it
# will saved during Bot.on_turn.
user_profile = await self.user_profile_accessor.get(
step_context.context, UserProfile
)
user_profile.transport = step_context.values["transport"]
user_profile.name = step_context.values["name"]
user_profile.age = step_context.values["age"]
user_profile.picture = step_context.values["picture"]
msg = f"I have your mode of transport as {user_profile.transport} and your name as {user_profile.name}."
if user_profile.age != -1:
msg += f" And age as {user_profile.age}."
await step_context.context.send_activity(MessageFactory.text(msg))
if user_profile.picture:
await step_context.context.send_activity(
MessageFactory.attachment(
user_profile.picture, "This is your profile picture."
)
)
else:
await step_context.context.send_activity(
"A profile picture was saved but could not be displayed here."
)
# WaterfallStep always finishes with the end of the Waterfall or with another
# dialog, here it is the end.
return await step_context.prompt(
ConfirmPrompt.__name__,
Şelale iletişim kutusunu çalıştırmak için uzantı yöntemini oluşturma
yardımcı run_dialog()
yöntemi, iletişim kutusu bağlamını oluşturmak ve erişmek için kullanılan yardımcılar\dialog_helper.py tanımlanır. burada, accessor
iletişim kutusu durum özelliği için durum özelliği erişimcisi ve dialog
kullanıcı profili bileşeni iletişim kutusudur. Bileşen iletişim kutuları bir iç iletişim kutusu kümesi tanımladığından, ileti işleyici koduna görünür bir dış iletişim kutusu kümesi oluşturulmalıdır ve bunu kullanarak bir iletişim kutusu bağlamı oluşturun.
bot'un dönüş işleyicisinin içinden iletişim kutusu kümesiyle etkileşim kurmak için kullanılan öğesini çağırarak create_context
iletişim kutusu bağlamını oluşturun. İletişim kutusu bağlamı geçerli dönüş bağlamını, üst iletişim kutusunu ve iletişim kutusu içinde bilgileri korumak için bir yöntem sağlayan iletişim kutusu durumunu içerir.
İletişim kutusu bağlamı, dize kimliğiyle bir iletişim kutusu başlatmanıza veya geçerli iletişim kutusuna (birden çok adım içeren şelale iletişim kutusu gibi) devam etmenizi sağlar. İletişim kutusu bağlamı tüm bot iletişim kutularına ve şelale adımlarına geçirilir.
class DialogHelper:
@staticmethod
async def run_dialog(
dialog: Dialog, turn_context: TurnContext, accessor: StatePropertyAccessor
):
dialog_set = DialogSet(accessor)
dialog_set.add(dialog)
dialog_context = await dialog_set.create_context(turn_context)
results = await dialog_context.continue_dialog()
if results.status == DialogTurnStatus.Empty:
await dialog_context.begin_dialog(dialog.id)
Bu örnek, iletişim kutusunun içinden kullanıcı profili durumunu güncelleştirir. Bu uygulama bazı botlarda kullanılabilir, ancak bir iletişim kutusunu botlar arasında yeniden kullanmak istiyorsanız çalışmaz.
İletişim kutusu adımlarını ve bot durumunu ayrı tutmak için çeşitli seçenekler vardır. Örneğin, iletişim kutunuz tüm bilgileri topladıktan sonra şunları yapabilirsiniz: