Buat permintaan Anda sendiri untuk mengumpulkan input pengguna
Artikel
BERLAKU UNTUK: SDK v4
Percakapan antara bot dan pengguna sering melibatkan meminta (meminta) pengguna untuk informasi, mengurai respons pengguna, lalu bertindak berdasarkan informasi tersebut. Bot Anda harus melacak konteks percakapan, sehingga dapat mengelola perilakunya dan mengingat jawaban atas pertanyaan sebelumnya. Status bot adalah informasi yang dilacaknya untuk merespons pesan masuk dengan tepat.
Tip
Pustaka dialog menyediakan perintah bawaan yang menyediakan lebih banyak fungsionalitas yang dapat digunakan pengguna. Contoh perintah tersebut dapat ditemukan di artikel Terapkan alur percakapan berurutan.
Catatan
Bot Framework JavaScript, C#, dan Python SDK akan terus didukung, namun, Java SDK dihentikan dengan dukungan jangka panjang akhir yang berakhir pada November 2023.
Bot yang ada yang dibangun dengan Java SDK akan terus berfungsi.
Kode dalam artikel ini didasarkan pada sampel Prompt Users for Input. Anda akan memerlukan salinan sampel C#, sampel JavaScript, sampel Java, atau sampel Python.
Contoh bot mengajukan serangkaian pertanyaan kepada pengguna, memvalidasi beberapa jawaban mereka, dan menyimpan input mereka. Diagram berikut menunjukkan hubungan antara bot, profil pengguna, dan kelas alur percakapan.
Kelas UserProfile untuk informasi pengguna yang akan dikumpulkan bot.
Kelas ConversationFlow untuk mengontrol status percakapan kami saat mengumpulkan informasi pengguna.
Enumerasi dalam ConversationFlow.Question untuk melacak di mana Anda berada dalam percakapan.
Kelas userProfile untuk informasi pengguna yang akan dikumpulkan bot.
Kelas conversationFlow untuk mengontrol status percakapan kami saat mengumpulkan informasi pengguna.
Enumerasi dalam conversationFlow.question untuk melacak di mana Anda berada dalam percakapan.
Kelas UserProfile untuk informasi pengguna yang akan dikumpulkan bot.
Kelas ConversationFlow untuk mengontrol status percakapan kami saat mengumpulkan informasi pengguna.
Enumerasi dalam ConversationFlow.Question untuk melacak di mana Anda berada dalam percakapan.
Kelas UserProfile untuk informasi pengguna yang akan dikumpulkan bot.
Kelas ConversationFlow untuk mengontrol status percakapan kami saat mengumpulkan informasi pengguna.
Enumerasi dalam ConversationFlow.Question untuk melacak di mana Anda berada dalam percakapan.
Status pengguna akan melacak nama pengguna, usia, dan tanggal yang dipilih, dan status percakapan akan melacak apa yang terakhir Anda tanyakan kepada pengguna.
Karena Anda tidak berencana untuk menyebarkan bot ini, Anda akan mengonfigurasi status pengguna dan percakapan untuk menggunakan penyimpanan memori.
Anda menggunakan penangan giliran pesan bot ditambah properti status pengguna dan percakapan untuk mengelola alur percakapan dan kumpulan input. Di bot, Anda akan merekam informasi properti status yang diterima selama setiap perulangan penangan giliran pesan.
Buat objek status pengguna dan percakapan saat startup dan gunakan melalui injeksi dependensi di konstruktor bot.
Startup.cs
// Create the Bot Adapter with error handling enabled.
services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
// Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
services.AddSingleton<IStorage, MemoryStorage>();
// Create the User state.
services.AddSingleton<UserState>();
// Create the Conversation state.
services.AddSingleton<ConversationState>();
Buat objek status pengguna dan percakapan di index.js dan gunakan di konstruktor bot.
index.js
// Catch-all for errors.
adapter.onTurnError = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
// NOTE: In production environment, you should consider logging this to Azure
bot/customPromptBot.js
class CustomPromptBot extends ActivityHandler {
constructor(conversationState, userState) {
super();
// The state management objects for the conversation and user.
this.conversationState = conversationState;
this.userState = userState;
Buat CustomPromptBot dalam metode getBot menggunakan instans ConversationState dan UserState yang disediakan oleh kontainer Spring. Konstruktor CustomPromptBot akan menyimpan referensi ke ConversationState dan UserState yang disediakan selama startup.
Application.java
@Bean
public Bot getBot(
ConversationState conversationState,
UserState userState
) {
return new CustomPromptBot(conversationState, userState);
}
CustomPromptBot.java
private final BotState userState;
private final BotState conversationState;
public CustomPromptBot(ConversationState conversationState, UserState userState) {
this.conversationState = conversationState;
this.userState = userState;
Buat objek status pengguna dan percakapan di app.py dan gunakan di konstruktor bot.
app.py
CONVERSATION_STATE = ConversationState(MEMORY)
# Create Bot
BOT = CustomPromptBot(CONVERSATION_STATE, USER_STATE)
# Listen for incoming requests on /api/messages.
bot/custom_prompt_bot.py
class CustomPromptBot(ActivityHandler):
def __init__(self, conversation_state: ConversationState, user_state: UserState):
if conversation_state is None:
raise TypeError(
"[CustomPromptBot]: Missing parameter. conversation_state is required but None was given"
)
if user_state is None:
raise TypeError(
"[CustomPromptBot]: Missing parameter. user_state is required but None was given"
)
self.conversation_state = conversation_state
self.user_state = user_state
Sebelum belokan berakhir, panggil saveChanges untuk menulis perubahan status apa pun pada penyimpanan.
/**
* Override the ActivityHandler.run() method to save state changes after the bot logic completes.
*/
async run(context) {
await super.run(context);
// Save any state changes. The load happened during the execution of the Dialog.
await this.conversationState.saveChanges(context, false);
await this.userState.saveChanges(context, false);
}
Buat aksesor properti untuk profil pengguna dan properti alur percakapan lalu panggil get untuk mengambil nilai properti dari status.
Di konstruktor, Anda membuat pengaktif properti status dan menyiapkan objek manajemen status (dibuat di atas) untuk percakapan kami.
bot/custom_prompt_bot.py
async def on_message_activity(self, turn_context: TurnContext):
# Get the state properties from the turn context.
profile = await self.profile_accessor.get(turn_context, UserProfile)
flow = await self.flow_accessor.get(turn_context, ConversationFlow)
Sebelum belokan berakhir, panggil SaveChangesAsync untuk menulis perubahan status apa pun pada penyimpanan.
# Save changes to UserState and ConversationState
await self.conversation_state.save_changes(turn_context)
await self.user_state.save_changes(turn_context)
Penangan giliran pesan
Saat menangani aktivitas pesan, handler pesan menggunakan metode pembantu untuk mengelola percakapan dan meminta pengguna. Metode pembantu dijelaskan di bagian berikut.
async def on_message_activity(self, turn_context: TurnContext):
# Get the state properties from the turn context.
profile = await self.profile_accessor.get(turn_context, UserProfile)
flow = await self.flow_accessor.get(turn_context, ConversationFlow)
await self._fill_out_user_profile(flow, profile, turn_context)
# Save changes to UserState and ConversationState
await self.conversation_state.save_changes(turn_context)
await self.user_state.save_changes(turn_context)
Mengisi profil pengguna
Bot meminta informasi kepada pengguna, berdasarkan pertanyaan mana, jika ada, yang diminta bot pada giliran sebelumnya. Input diurai menggunakan metode validasi.
Setiap metode validasi mengikuti desain serupa:
Nilai pengembalian menunjukkan apakah input adalah jawaban yang valid untuk pertanyaan ini.
Jika validasi lolos, validasi menghasilkan nilai yang diurai dan dinormalisasi untuk disimpan.
Jika validasi gagal, bot dapat meminta informasi lagi.
{
var input = turnContext.Activity.Text?.Trim();
string message;
switch (flow.LastQuestionAsked)
{
case ConversationFlow.Question.None:
await turnContext.SendActivityAsync("Let's get started. What is your name?", null, null, cancellationToken);
flow.LastQuestionAsked = ConversationFlow.Question.Name;
break;
case ConversationFlow.Question.Name:
if (ValidateName(input, out var name, out message))
{
profile.Name = name;
await turnContext.SendActivityAsync($"Hi {profile.Name}.", null, null, cancellationToken);
await turnContext.SendActivityAsync("How old are you?", null, null, cancellationToken);
flow.LastQuestionAsked = ConversationFlow.Question.Age;
break;
}
else
{
await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
break;
}
case ConversationFlow.Question.Age:
if (ValidateAge(input, out var age, out message))
{
profile.Age = age;
await turnContext.SendActivityAsync($"I have your age as {profile.Age}.", null, null, cancellationToken);
await turnContext.SendActivityAsync("When is your flight?", null, null, cancellationToken);
flow.LastQuestionAsked = ConversationFlow.Question.Date;
break;
}
else
{
await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
break;
}
case ConversationFlow.Question.Date:
if (ValidateDate(input, out var date, out message))
{
profile.Date = date;
await turnContext.SendActivityAsync($"Your cab ride to the airport is scheduled for {profile.Date}.");
await turnContext.SendActivityAsync($"Thanks for completing the booking {profile.Name}.");
await turnContext.SendActivityAsync($"Type anything to run the bot again.");
flow.LastQuestionAsked = ConversationFlow.Question.None;
profile = new UserProfile();
break;
}
else
{
await turnContext.SendActivityAsync(message ?? "I'm sorry, I didn't understand that.", null, null, cancellationToken);
break;
}
}
}
bot/customPromptBot.js
// Manages the conversation flow for filling out the user's profile.
static async fillOutUserProfile(flow, profile, turnContext) {
const input = turnContext.activity.text;
let result;
switch (flow.lastQuestionAsked) {
// If we're just starting off, we haven't asked the user for any information yet.
// Ask the user for their name and update the conversation flag.
case question.none:
await turnContext.sendActivity("Let's get started. What is your name?");
flow.lastQuestionAsked = question.name;
break;
// If we last asked for their name, record their response, confirm that we got it.
// Ask them for their age and update the conversation flag.
case question.name:
result = this.validateName(input);
if (result.success) {
profile.name = result.name;
await turnContext.sendActivity(`I have your name as ${ profile.name }.`);
await turnContext.sendActivity('How old are you?');
flow.lastQuestionAsked = question.age;
break;
} else {
// If we couldn't interpret their input, ask them for it again.
// Don't update the conversation flag, so that we repeat this step.
await turnContext.sendActivity(result.message || "I'm sorry, I didn't understand that.");
break;
}
// If we last asked for their age, record their response, confirm that we got it.
// Ask them for their date preference and update the conversation flag.
case question.age:
result = this.validateAge(input);
if (result.success) {
profile.age = result.age;
await turnContext.sendActivity(`I have your age as ${ profile.age }.`);
await turnContext.sendActivity('When is your flight?');
flow.lastQuestionAsked = question.date;
break;
} else {
// If we couldn't interpret their input, ask them for it again.
// Don't update the conversation flag, so that we repeat this step.
await turnContext.sendActivity(result.message || "I'm sorry, I didn't understand that.");
break;
}
// If we last asked for a date, record their response, confirm that we got it,
// let them know the process is complete, and update the conversation flag.
case question.date:
result = this.validateDate(input);
if (result.success) {
profile.date = result.date;
await turnContext.sendActivity(`Your cab ride to the airport is scheduled for ${ profile.date }.`);
await turnContext.sendActivity(`Thanks for completing the booking ${ profile.name }.`);
await turnContext.sendActivity('Type anything to run the bot again.');
flow.lastQuestionAsked = question.none;
profile = {};
break;
} else {
// If we couldn't interpret their input, ask them for it again.
// Don't update the conversation flag, so that we repeat this step.
await turnContext.sendActivity(result.message || "I'm sorry, I didn't understand that.");
break;
}
}
}
CustomPromptBot.java
private static CompletableFuture<Void> fillOutUserProfile(ConversationFlow flow,
UserProfile profile,
TurnContext turnContext) {
String input = "";
if (StringUtils.isNotBlank(turnContext.getActivity().getText())) {
input = turnContext.getActivity().getText().trim();
}
switch (flow.getLastQuestionAsked()) {
case None:
return turnContext.sendActivity("Let's get started. What is your name?", null, null)
.thenRun(() -> {flow.setLastQuestionAsked(ConversationFlow.Question.Name);});
case Name:
Triple<Boolean, String, String> nameValidationResult = validateName(input);
if (nameValidationResult.getLeft()) {
profile.setName(nameValidationResult.getMiddle());
return turnContext.sendActivity(String.format("Hi %s.", profile.getName()), null, null)
.thenCompose(result -> turnContext.sendActivity("How old are you?", null, null))
.thenRun(() -> { flow.setLastQuestionAsked(ConversationFlow.Question.Age); });
} else {
if (StringUtils.isNotBlank(nameValidationResult.getRight())) {
return turnContext.sendActivity(nameValidationResult.getRight(), null, null)
.thenApply(result -> null);
} else {
return turnContext.sendActivity("I'm sorry, I didn't understand that.", null, null)
.thenApply(result -> null);
}
}
case Age:
Triple<Boolean, Integer, String> ageValidationResult = ValidateAge(input);
if (ageValidationResult.getLeft()) {
profile.setAge(ageValidationResult.getMiddle());
return turnContext.sendActivity(String.format("I have your age as %d.", profile.getAge()), null, null)
.thenCompose(result -> turnContext.sendActivity("When is your flight?", null, null))
.thenRun(() -> { flow.setLastQuestionAsked(ConversationFlow.Question.Date); });
} else {
if (StringUtils.isNotBlank(ageValidationResult.getRight())) {
return turnContext.sendActivity(ageValidationResult.getRight(), null, null)
.thenApply(result -> null);
} else {
return turnContext.sendActivity("I'm sorry, I didn't understand that.", null, null)
.thenApply(result -> null);
}
}
case Date:
Triple<Boolean, String, String> dateValidationResult = ValidateDate(input);
AtomicReference<UserProfile> profileReference = new AtomicReference<UserProfile>(profile);
if (dateValidationResult.getLeft()) {
profile.setDate(dateValidationResult.getMiddle());
return turnContext.sendActivity(
String.format("Your cab ride to the airport is scheduled for %s.",
profileReference.get().getDate()))
.thenCompose(result -> turnContext.sendActivity(
String.format("Thanks for completing the booking %s.", profileReference.get().getDate())))
.thenCompose(result -> turnContext.sendActivity("Type anything to run the bot again."))
.thenRun(() -> {
flow.setLastQuestionAsked(ConversationFlow.Question.None);
profileReference.set(new UserProfile());
});
} else {
if (StringUtils.isNotBlank(dateValidationResult.getRight())) {
return turnContext.sendActivity(dateValidationResult.getRight(), null, null)
.thenApply(result -> null);
} else {
return turnContext.sendActivity("I'm sorry, I didn't understand that.", null, null)
.thenApply(result -> null);
}
}
default:
return CompletableFuture.completedFuture(null);
}
bot/custom_prompt_bot.py
async def _fill_out_user_profile(
self, flow: ConversationFlow, profile: UserProfile, turn_context: TurnContext
):
user_input = turn_context.activity.text.strip()
# ask for name
if flow.last_question_asked == Question.NONE:
await turn_context.send_activity(
MessageFactory.text("Let's get started. What is your name?")
)
flow.last_question_asked = Question.NAME
# validate name then ask for age
elif flow.last_question_asked == Question.NAME:
validate_result = self._validate_name(user_input)
if not validate_result.is_valid:
await turn_context.send_activity(
MessageFactory.text(validate_result.message)
)
else:
profile.name = validate_result.value
await turn_context.send_activity(
MessageFactory.text(f"Hi {profile.name}")
)
await turn_context.send_activity(
MessageFactory.text("How old are you?")
)
flow.last_question_asked = Question.AGE
# validate age then ask for date
elif flow.last_question_asked == Question.AGE:
validate_result = self._validate_age(user_input)
if not validate_result.is_valid:
await turn_context.send_activity(
MessageFactory.text(validate_result.message)
)
else:
profile.age = validate_result.value
await turn_context.send_activity(
MessageFactory.text(f"I have your age as {profile.age}.")
)
await turn_context.send_activity(
MessageFactory.text("When is your flight?")
)
flow.last_question_asked = Question.DATE
# validate date and wrap it up
elif flow.last_question_asked == Question.DATE:
validate_result = self._validate_date(user_input)
if not validate_result.is_valid:
await turn_context.send_activity(
MessageFactory.text(validate_result.message)
)
else:
profile.date = validate_result.value
await turn_context.send_activity(
MessageFactory.text(
f"Your cab ride to the airport is scheduled for {profile.date}."
)
)
await turn_context.send_activity(
MessageFactory.text(
f"Thanks for completing the booking {profile.name}."
)
)
await turn_context.send_activity(
MessageFactory.text("Type anything to run the bot again.")
)
flow.last_question_asked = Question.NONE
Mengurai dan memvalidasi input
Bot menggunakan kriteria berikut untuk memvalidasi input.
Nama harus berupa string yang tidak kosong. Ini dinormalisasi dengan memangkas spasi putih.
Usia harus antara 18 dan 120. Ini dinormalisasi dengan mengembalikan bilangan bulat.
Tanggal harus tanggal atau waktu apa pun setidaknya satu jam di masa mendatang.
Ini dinormalisasi dengan mengembalikan hanya bagian tanggal input yang diurai.
Catatan
Untuk input usia dan tanggal, sampel menggunakan pustaka Microsoft/Recognizers-Text untuk melakukan penguraian awal.
Ini hanya salah satu cara untuk mengurai input. Untuk informasi selengkapnya tentang pustaka ini, lihat README proyek.
private static bool ValidateName(string input, out string name, out string message)
{
name = null;
message = null;
if (string.IsNullOrWhiteSpace(input))
{
message = "Please enter a name that contains at least one character.";
}
else
{
name = input.Trim();
}
return message is null;
}
private static bool ValidateAge(string input, out int age, out string message)
{
age = 0;
message = null;
// Try to recognize the input as a number. This works for responses such as "twelve" as well as "12".
try
{
// Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
// The recognizer returns a list of potential recognition results, if any.
var results = NumberRecognizer.RecognizeNumber(input, Culture.English);
foreach (var result in results)
{
// The result resolution is a dictionary, where the "value" entry contains the processed string.
if (result.Resolution.TryGetValue("value", out var value))
{
age = Convert.ToInt32(value);
if (age >= 18 && age <= 120)
{
return true;
}
}
}
message = "Please enter an age between 18 and 120.";
}
catch
{
message = "I'm sorry, I could not interpret that as an age. Please enter an age between 18 and 120.";
}
return message is null;
}
private static bool ValidateDate(string input, out string date, out string message)
{
date = null;
message = null;
// Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "9pm", "tomorrow", "Sunday at 5pm", and so on.
// The recognizer returns a list of potential recognition results, if any.
try
{
var results = DateTimeRecognizer.RecognizeDateTime(input, Culture.English);
// Check whether any of the recognized date-times are appropriate,
// and if so, return the first appropriate date-time. We're checking for a value at least an hour in the future.
var earliest = DateTime.Now.AddHours(1.0);
foreach (var result in results)
{
// The result resolution is a dictionary, where the "values" entry contains the processed input.
var resolutions = result.Resolution["values"] as List<Dictionary<string, string>>;
foreach (var resolution in resolutions)
{
// The processed input contains a "value" entry if it is a date-time value, or "start" and
// "end" entries if it is a date-time range.
if (resolution.TryGetValue("value", out var dateString)
|| resolution.TryGetValue("start", out dateString))
{
if (DateTime.TryParse(dateString, out var candidate)
&& earliest < candidate)
{
date = candidate.ToShortDateString();
return true;
}
}
}
}
message = "I'm sorry, please enter a date at least an hour out.";
}
catch
{
message = "I'm sorry, I could not interpret that as an appropriate date. Please enter a date at least an hour out.";
}
return false;
}
bot/customPromptBot.js
// Validates name input. Returns whether validation succeeded and either the parsed and normalized
// value or a message the bot can use to ask the user again.
static validateName(input) {
const name = input && input.trim();
return name !== undefined
? { success: true, name: name }
: { success: false, message: 'Please enter a name that contains at least one character.' };
};
// Validates age input. Returns whether validation succeeded and either the parsed and normalized
// value or a message the bot can use to ask the user again.
static validateAge(input) {
// Try to recognize the input as a number. This works for responses such as "twelve" as well as "12".
try {
// Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
// The recognizer returns a list of potential recognition results, if any.
const results = Recognizers.recognizeNumber(input, Recognizers.Culture.English);
let output;
results.forEach(result => {
// result.resolution is a dictionary, where the "value" entry contains the processed string.
const value = result.resolution.value;
if (value) {
const age = parseInt(value);
if (!isNaN(age) && age >= 18 && age <= 120) {
output = { success: true, age: age };
return;
}
}
});
return output || { success: false, message: 'Please enter an age between 18 and 120.' };
} catch (error) {
return {
success: false,
message: "I'm sorry, I could not interpret that as an age. Please enter an age between 18 and 120."
};
}
}
// Validates date input. Returns whether validation succeeded and either the parsed and normalized
// value or a message the bot can use to ask the user again.
static validateDate(input) {
// Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "today at 9pm", "tomorrow", "Sunday at 5pm", and so on.
// The recognizer returns a list of potential recognition results, if any.
try {
const results = Recognizers.recognizeDateTime(input, Recognizers.Culture.English);
const now = new Date();
const earliest = now.getTime() + (60 * 60 * 1000);
let output;
results.forEach(result => {
// result.resolution is a dictionary, where the "values" entry contains the processed input.
result.resolution.values.forEach(resolution => {
// The processed input contains a "value" entry if it is a date-time value, or "start" and
// "end" entries if it is a date-time range.
const datevalue = resolution.value || resolution.start;
// If only time is given, assume it's for today.
const datetime = resolution.type === 'time'
? new Date(`${ now.toLocaleDateString() } ${ datevalue }`)
: new Date(datevalue);
if (datetime && earliest < datetime.getTime()) {
output = { success: true, date: datetime.toLocaleDateString() };
return;
}
});
});
return output || { success: false, message: "I'm sorry, please enter a date at least an hour out." };
} catch (error) {
return {
success: false,
message: "I'm sorry, I could not interpret that as an appropriate date. Please enter a date at least an hour out."
};
}
}
CustomPromptBot.java
private static Triple<Boolean, String, String> validateName(String input) {
String name = null;
String message = null;
if (StringUtils.isEmpty(input)) {
message = "Please enter a name that contains at least one character.";
} else {
name = input.trim();
}
return Triple.of(StringUtils.isBlank(message), name, message);
}
private static Triple<Boolean, Integer, String> ValidateAge(String input) {
int age = 0;
String message = null;
// Try to recognize the input as a number. This works for responses such as "twelve" as well as "12".
try {
// Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
// The recognizer returns a list of potential recognition results, if any.
List<ModelResult> results = NumberRecognizer.recognizeNumber(input, PromptCultureModels.ENGLISH_CULTURE);
for (ModelResult result : results) {
// The result resolution is a dictionary, where the "value" entry contains the processed String.
Object value = result.resolution.get("value");
if (value != null) {
age = Integer.parseInt((String) value);
if (age >= 18 && age <= 120) {
return Triple.of(true, age, "");
}
}
}
message = "Please enter an age between 18 and 120.";
}
catch (Throwable th) {
message = "I'm sorry, I could not interpret that as an age. Please enter an age between 18 and 120.";
}
return Triple.of(StringUtils.isBlank(message), age, message);
}
private static Triple<Boolean, String, String> ValidateDate(String input) {
String date = null;
String message = null;
// Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "9pm", "tomorrow", "Sunday at 5pm", and so on.
// The recognizer returns a list of potential recognition results, if any.
try {
List<ModelResult> results = DateTimeRecognizer.recognizeDateTime(input, PromptCultureModels.ENGLISH_CULTURE);
// Check whether any of the recognized date-times are appropriate,
// and if so, return the first appropriate date-time. We're checking for a value at least an hour in the future.
LocalDateTime earliest = LocalDateTime.now().plus(1, ChronoUnit.HOURS);
for (ModelResult result : results) {
// The result resolution is a dictionary, where the "values" entry contains the processed input.
List<Map<String, Object>> resolutions = (List<Map<String, Object>>) result.resolution.get("values");
for (Map<String, Object> resolution : resolutions) {
// The processed input contains a "value" entry if it is a date-time value, or "start" and
// "end" entries if it is a date-time range.
String dateString = (String) resolution.get("value");
if (StringUtils.isBlank(dateString)) {
dateString = (String) resolution.get("start");
}
if (StringUtils.isNotBlank(dateString)){
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime candidate;
try {
candidate = LocalDateTime.from(f.parse(dateString));
} catch (DateTimeParseException err) {
// If the input is a date, it will throw an exception and it will create a datetime
// with the MIN localtime
DateTimeFormatter d = DateTimeFormatter.ofPattern("yyyy-MM-dd");
candidate = LocalDateTime.of(LocalDate.parse(dateString, d), LocalDateTime.MIN.toLocalTime());
}
if (earliest.isBefore(candidate)) {
DateTimeFormatter dateformat = DateTimeFormatter.ofPattern("MM-dd-yyyy");
date = candidate.format(dateformat);
return Triple.of(true, date, message);
}
}
}
}
bot/custom_prompt_bot.py
def _validate_name(self, user_input: str) -> ValidationResult:
if not user_input:
return ValidationResult(
is_valid=False,
message="Please enter a name that contains at least one character.",
)
return ValidationResult(is_valid=True, value=user_input)
def _validate_age(self, user_input: str) -> ValidationResult:
# Attempt to convert the Recognizer result to an integer. This works for "a dozen", "twelve", "12", and so on.
# The recognizer returns a list of potential recognition results, if any.
results = recognize_number(user_input, Culture.English)
for result in results:
if "value" in result.resolution:
age = int(result.resolution["value"])
if 18 <= age <= 120:
return ValidationResult(is_valid=True, value=age)
return ValidationResult(
is_valid=False, message="Please enter an age between 18 and 120."
)
def _validate_date(self, user_input: str) -> ValidationResult:
try:
# Try to recognize the input as a date-time. This works for responses such as "11/14/2018", "9pm",
# "tomorrow", "Sunday at 5pm", and so on. The recognizer returns a list of potential recognition results,
# if any.
results = recognize_datetime(user_input, Culture.English)
for result in results:
for resolution in result.resolution["values"]:
if "value" in resolution:
now = datetime.now()
value = resolution["value"]
if resolution["type"] == "date":
candidate = datetime.strptime(value, "%Y-%m-%d")
elif resolution["type"] == "time":
candidate = datetime.strptime(value, "%H:%M:%S")
candidate = candidate.replace(
year=now.year, month=now.month, day=now.day
)
else:
candidate = datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
# user response must be more than an hour out
diff = candidate - now
if diff.total_seconds() >= 3600:
return ValidationResult(
is_valid=True,
value=candidate.strftime("%m/%d/%y"),
)
return ValidationResult(
is_valid=False,
message="I'm sorry, please enter a date at least an hour out.",
)
except ValueError:
return ValidationResult(
is_valid=False,
message="I'm sorry, I could not interpret that as an appropriate "
"date. Please enter a date at least an hour out.",
)
Menguji bot secara lokal
Unduh dan instal Emulator Kerangka Kerja Bot untuk menguji bot secara lokal.
Jalankan sampel secara lokal di komputer Anda. Jika Anda memerlukan instruksi, lihat README file untuk sampel C#, sampel JS, atau sampel Python.
Uji menggunakan Emulator.
Sumber Daya Tambahan:
Pustaka Dialog menyediakan kelas yang mengotomatiskan banyak aspek pengelolaan percakapan.