在上一篇([06]不只能輸出文字 - 看看各種内建卡片模式以及可自定的Adaptive Card)介紹了如何透過Rich Card把bot輸出的内容變成更加漂亮的卡片樣式。
到目前爲止,所有的邏輯都在一起,作爲開發人員會開始覺得程式碼已經開始有些味道了(smell)了。如果今天我們想要透過交談對話中取得一些使用者的資訊,例如填寫表單,那可以想象要寫更多的if/else來處理。感覺程式碼會更加臟。
還好Bot Builder SDK在表單類型的溝通有一個模組叫做FormFlow
,在這一篇將來介紹如何使用FormFlow來設計從使用者收集資料。
FormFlow是什麽?
我們使用服務性類型的網站多多少少都需要填寫表單,例如,搜索飯店需要輸入一些條件,要注冊帳號需要輸入使用者資訊等。這些類型資訊可以統稱為表單類型的輸入。
回到chatbot角度,想一下這種表單開發在bot裡面要怎麽做?以我們現有知識的做法其實就是一堆if/else,同時還要記錄上下文(知道那些欄位有輸入過,那些沒有),并且要提供功能讓使用者看目前輸入了那些,并且如何修改已經輸入過的欄位 等等。
因此,要做好一個流程以及體驗需要花蠻多時間,因此Bot Builder SDK有提供了一個模組叫做FormFlow
。透過FormFlow,我們在開發這種表單輸入將會變得非常簡單。我們就來看看怎麽使用FormFlow。
如何使用FormFlow
如果有寫過MVC的會知道,當我們要開發一個表單的時候,第一件事情先定義出最後表單的Model。因爲透過Model我們可以做Model Binding得到强型別的物件,在C#處理會變得更加方便。
同樣道理,Bot Builder SDK的FormFlow也是從Model開始。我們定義出一個我們表單的模型,并且透過使用Attribute調整呈現内容,最後我們收到的結果就會是這個Model。
實際使用FormFlow
我們會經歷過幾個步奏:
- 定義Model
- 把Model轉成FormFlow
- 觸發FormFlow
1. 定義Model
在我們的使用情景來説,訂房者想透過chatbot來訂房,那我們就會問一些問題來取得一些資訊,我們會需要:
- 從那天入住
- 住幾個晚上
- 幾個人
- 床大小
因此我們可以先建立一個Model有這些資訊:
public enum BedSizeOptions
{
King = 1,
Queen,
Single
}
[Serializable]
public class RoomReservation
{
public DateTime StartDate { get; set; }
public int NumberOfNightToStay { get; set; }
public int NumberOfOccupants { get; set; }
public BedSizeOptions BedSize { get; set; }
}
這邊可以看到有不同的欄位形態,我們的床大小使用的是enum,透過enum可以限制使用者不要亂輸入。
然後我們的model需要定義爲Serializable
2. 把Model轉成FormFlow
Model有了之後,再來是我們要一個方法把Model轉換成爲一個FormFlow。直接在RoomReservation
裡面定義一個方法:
...
public static IForm<RoomReservation> BuildForm()
{
return new FormBuilder<RoomReservation>()
.Build();
}
3. 觸發FormFlow
最後,只需要在需要的時候觸發即可。FormFlow的結果是用CallBack方式來接:...
else if(activity.Text == "訂房v2")
{
var reserveRoomForm =
FormDialog.FromForm(RoomReservation.BuildForm,
FormOptions.PromptInStart);
context.Call(reserveRoomForm, AfterReserveRoomAsync);
}
...
private async Task AfterReserveRoomAsync(IDialogContext context
, IAwaitable<RoomReservation> result)
{
RoomReservation reservation = null;
reservation = await result;
await context.PostAsync($"得到的結果:{Environment.NewLine} {JsonConvert.SerializeObject(reservation)}");
context.Wait(MessageReceivedAsync);
}
context.Wait(MessageReceivedAsync)
不能集中在一個地方,而是每一個else裡面要放一個,然後FormFlow放在結束的callback裡面
測試FormFlow
首先可以測試順的流程(輸入的内容都對),可以參考以下的git動畫:
不過其實在輸入的過程當中是有形態保護,例如,如果日期我輸入錯誤:
在表單填寫過程其實有些特殊指令,這些可以從輸入Help看到有哪些:
假設想要看到目前輸入那些内容,可以輸入status:
結語
透過這篇可以看到要有個好使用的表單輸入流程並不容易,需要考慮怎麽防呆欄位,怎麽修改目前已經輸入的内容等等。而這些FormFlow都幫我們處理好了。
不過透過這篇我們會發現,目前介紹的FormFlow雖然夠用,但是使用上還不那麽順暢。例如,英文當然沒有什麽問題,但是如果中文客戶怎麽辦?如果要退出FormFlow如何讓使用者看到更友善的訊息? 因此,下一篇([08]如何微調FormFlow讓使用上更流暢)將會對如何調整FormFlow在做個介紹。