구성 요소 대화 상자를 사용하면 독립적인 대화 상자를 만들어 특정 시나리오를 처리할 수 있으며, 큰 대화 상자를 보다 관리하기 쉬운 조각으로 분할할 수 있습니다. 이러한 각 조각에는 고유한 대화 집합이 있으며 외부의 대화 집합과 이름 충돌을 방지합니다. 구성 요소 대화 상자는 다음과 같은 경우에 다시 사용할 수 있습니다.
다중 턴 프롬프트 샘플에서는 폭포 대화 상자, 몇 가지 프롬프트 및 구성 요소 대화 상자를 사용하여 사용자에게 일련의 질문을 하는 상호 작용을 만듭니다. 코드는 대화 상자를 사용하여 다음 단계를 순환합니다.
마지막으로, '예'라고 대답하면 수집된 정보를 표시합니다. 그렇지 않으면 사용자에게 해당 정보가 유지되지 않는다고 알릴 수 있습니다.
구성 요소 대화 상자는 하나 이상의 대화 상자를 캡슐화합니다. 구성 요소 대화 상자에는 내부 대화 집합이 있으며, 이 내부 대화 집합에 추가하는 대화 상자와 프롬프트에는 구성 요소 대화 상자 내에서만 볼 수 있는 고유한 ID가 있습니다.
대화를 사용하려면 Microsoft.Bot.Builder.Dialogs NuGet 패키지를 설치합니다.
Dialogs\UserProfileDialog.cs
여기서 UserProfileDialog
클래스는 ComponentDialog
클래스에서 파생됩니다.
public class UserProfileDialog : ComponentDialog
생성자 내에서 메서드는 AddDialog
대화 상자를 추가하고 구성 요소 대화 상자에 프롬프트를 표시합니다. 이 메서드를 사용하여 추가하는 첫 번째 항목은 초기 대화 상자로 설정됩니다. 속성을 명시적으로 설정 InitialDialogId
하여 초기 대화 상자를 변경할 수 있습니다. 구성 요소 대화 상자를 시작하면 해당 초기 대화 상자 가 시작됩니다.
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);
}
다음 코드는 폭포 대화 상자의 첫 번째 단계를 나타냅니다.
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);
}
폭포 대화 구현에 대한 자세한 내용은 순차적 대화 흐름을 구현하는 방법을 참조하세요.
대화 상자를 사용하려면 프로젝트에서 botbuilder-dialogs npm 패키지를 설치해야 합니다.
dialogs/userProfileDialog.js
여기서 클래스는 UserProfileDialog
확장됩니다.ComponentDialog
class UserProfileDialog extends ComponentDialog {
생성자 내에서 메서드는 AddDialog
대화 상자를 추가하고 구성 요소 대화 상자에 프롬프트를 표시합니다. 이 메서드를 사용하여 추가하는 첫 번째 항목은 초기 대화 상자로 설정됩니다. 속성을 명시적으로 설정 InitialDialogId
하여 초기 대화 상자를 변경할 수 있습니다. 구성 요소 대화 상자를 시작하면 해당 초기 대화 상자 가 시작됩니다.
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;
}
다음 코드는 폭포 대화 상자의 첫 번째 단계를 나타냅니다.
async transportStep(step) {
// 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.
return await step.prompt(CHOICE_PROMPT, {
prompt: 'Please enter your mode of transport.',
choices: ChoiceFactory.toChoices(['Car', 'Bus', 'Bicycle'])
});
}
폭포 대화 구현에 대한 자세한 내용은 순차적 대화 흐름을 구현하는 방법을 참조하세요.
UserProfileDialog.java
여기서 UserProfileDialog
클래스는 ComponentDialog
클래스에서 파생됩니다.
public class UserProfileDialog extends ComponentDialog {
생성자 내에서 메서드는 addDialog
대화 상자를 추가하고 구성 요소 대화 상자에 프롬프트를 표시합니다. 이 메서드를 사용하여 추가하는 첫 번째 항목은 초기 대화 상자로 설정됩니다. 메서드를 호출 setInitialDialogId
하여 초기 대화 상자를 변경하고 초기 대화 상자의 이름을 제공할 수 있습니다. 구성 요소 대화 상자를 시작하면 해당 초기 대화 상자 가 시작됩니다.
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> 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);
}
폭포 대화 구현에 대한 자세한 내용은 순차적 대화 흐름을 구현하는 방법을 참조하세요.
대화 상자를 사용하려면 터미널에서 실행 pip install botbuilder-dialogs
pip install botbuilder-ai
하여 botbuilder-dialogs 및 botbuilder-ai PyPI 패키지를 설치합니다.
dialogs/user_profile_dialog.py
여기서 클래스는 UserProfileDialog
확장됩니다.ComponentDialog
class UserProfileDialog(ComponentDialog):
생성자 내에서 메서드는 add_dialog
대화 상자를 추가하고 구성 요소 대화 상자에 프롬프트를 표시합니다. 이 메서드를 사용하여 추가하는 첫 번째 항목은 초기 대화 상자로 설정됩니다. 속성을 명시적으로 설정 initial_dialog_id
하여 초기 대화 상자를 변경할 수 있습니다. 구성 요소 대화 상자를 시작하면 해당 초기 대화 상자 가 시작됩니다.
class UserProfileDialog(ComponentDialog):
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__
다음 코드는 폭포 대화 상자의 첫 번째 단계를 나타냅니다.
async def transport_step(
self, step_context: WaterfallStepContext
) -> DialogTurnResult:
# 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 users response is received.
return await step_context.prompt(
ChoicePrompt.__name__,
PromptOptions(
prompt=MessageFactory.text("Please enter your mode of transport."),
choices=[Choice("Car"), Choice("Bus"), Choice("Bicycle")],
),
)
폭포 대화 구현에 대한 자세한 내용은 순차적 대화 흐름을 구현하는 방법을 참조하세요.
런타임에 구성 요소 대화 상자는 자체의 고유한 대화 상자 스택을 유지 관리합니다. 구성 요소 대화 상자가 시작되는 경우:
부모 컨텍스트는 구성 요소를 활성 대화 상자로 봅니다. 그러나 구성 요소 내의 컨텍스트에서는 초기 대화 상자가 활성 대화 상자인 것처럼 보입니다.
구성 요소 대화 상자를 추가한 외부 대화 상자 집합에는 구성 요소 대화 상자에서 만든 ID가 있습니다. 외부 집합에서 구성 요소는 프롬프트처럼 단일 대화 상자처럼 보입니다.
구성 요소 대화 상자를 사용하려면 봇의 대화 상자 집합에 해당 인스턴스를 추가합니다.
Bots\DialogBot.cs
샘플에서 이 작업은 봇의 OnMessageActivityAsync
메서드에서 호출된 RunAsync
메서드를 사용하여 수행됩니다.
protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
{
Logger.LogInformation("Running dialog with Message Activity.");
// Run the Dialog with the new message Activity.
await Dialog.RunAsync(turnContext, ConversationState.CreateProperty<DialogState>(nameof(DialogState)), cancellationToken);
}
dialogs/userProfileDialog.js
샘플에서는 사용자 프로필 대화 상자에 메서드를 추가 run
했습니다.
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);
}
}
bots/dialogBot.js
메서드는 run
봇의 onMessage
메서드에서 호출됩니다.
this.onMessage(async (context, next) => {
console.log('Running dialog with Message Activity.');
// Run the Dialog with the new message Activity.
await this.dialog.run(context, this.dialogState);
await next();
});
DialogBot.java
샘플에서 이 작업은 봇의 onMessageActivity
메서드에서 호출된 run
메서드를 사용하여 수행됩니다.
@Override
protected CompletableFuture<Void> onMessageActivity(
TurnContext turnContext
) {
LoggerFactory.getLogger(DialogBot.class).info("Running dialog with Message Activity.");
// Run the Dialog with the new message Activity.
return Dialog.run(dialog, turnContext, conversationState.createProperty("DialogState"));
}
도우미/dialog_helper.py
샘플에서는 사용자 프로필 대화 상자에 메서드를 추가 run_dialog
했습니다.
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)
run_dialog
봇의 메서드에서 호출되는 메서드입니다on_message_activity
.
bots/dialog_bot.py
async def on_message_activity(self, turn_context: TurnContext):
await DialogHelper.run_dialog(
self.dialog,
turn_context,
self.conversation_state.create_property("DialogState"),
)
분기되고 반복되는 복잡한 대화를 만드는 방법에 대해 알아봅니다.