使用C#開發LineBot(12) – 在連續對話中加入ButtonsTemplate訊息
如果你實際開發過Chat bot,就會發現NLP(自然語言分析)本身就是一個很大的問題,即便現在有LUIS可以幫助我們做語意分析,但實務上分析結果要100%符合用戶(或開發人員)的心意不是易事,倘若可行,在商務應用時,Chat bot與用戶之間的一問一答對談,想要提高可用率,讓用戶以選項的方式回答還是比自然語言對談來的好很多。
舉例來說,在上一篇我們介紹的CIC類別當中,如果我們的chat bot要問用戶要請哪一種假別,與其讓用戶自己回答,不如讓用戶用選的乾脆一些。
原本對談的設計是:
但這風險很高,因為我們開放用戶自己用輸入的方式回答。
如果用戶偏偏要回答:
我今天想請事假
或
請婚假
或
什麼根本沒聽過的假…
對Chat bot來說都要做自然語言分析,就算分析的再正確,在開發上難度也提升不少,但如果用底下這樣的ButtonsTemplated Message詢問用戶,用戶只能在底下的選項中擇一回答,那就容易多了:
上一篇說過,我們要透過繼承自ConversationEntity的LeaveReuqest類別來處理這對話邏輯,而這一版我們加上了支援ButtonsTemplate Message,你只需要使用ButtonsTemplateQuestion這個Attribute即可(注意第3行):
public class LeaveRequestV2 : ConversationEntity | |
{ | |
[ButtonsTemplateQuestion("詢問", "請問您要請的假別是?", "https://arock.blob.core.windows.net/blogdata201706/22-124357-ad3c87d6-b9cc-488a-8150-1c2fe642d237.png", "事假", "病假", "公假", "婚假")] | |
[Order(1)] | |
public string 假別 { get; set; } | |
[Question("請問您的代理人是誰?")] | |
[Order(2)] | |
public string 代理人 { get; set; } | |
[Question("請問您的請假日期是?")] | |
[Order(3)] | |
public DateTime 請假日期 { get; set; } | |
[Question("請問您的開始時間是幾點幾分?")] | |
[Order(4)] | |
public DateTime 開始時間 { get; set; } | |
[Question("請問您要請幾小時?")] | |
[Order(5)] | |
public float 請假時數 { get; set; } | |
} |
我們新建立的這個LeaveRequestV2,跟上一篇的LeaveRequest很像,但第一個詢問假別的問題,改用了ButtonsTemplateQuestion Attribute(注意,你必須把LineBotSDK升級至 0.5.7-beta),程式碼就只需要做這一個小小的調整即可。
由於加上了ButtonsTemplate Message,chat bot WebApi Controller主程式碼也小幅修改一下:
public class CICTest2Controller : ApiController | |
{ | |
[HttpPost] | |
public IHttpActionResult POST() | |
{ | |
string ChannelAccessToken = "!!!!!!!!!!! 請換成你自己的Channel Access Token !!!!!!!!!!!!!!!!!"; | |
var responseMsg = ""; | |
try | |
{ | |
//定義資訊蒐集者 | |
isRock.LineBot.Conversation.InformationCollector<LeaveRequestV2> CIC = | |
new isRock.LineBot.Conversation.InformationCollector<LeaveRequestV2>(ChannelAccessToken); | |
CIC.OnMessageTypeCheck += (s, e) => { | |
switch (e.CurrentPropertyName) | |
{ | |
case "代理人": | |
if (e.ReceievedMessage != "eric") | |
{ | |
e.isMismatch = true; | |
e.ResponseMessage = "我們公司只有eric,代理人請找eric..."; | |
} | |
break; | |
case "假別": | |
if (e.ReceievedMessage != "事假" && e.ReceievedMessage != "病假" && e.ReceievedMessage != "公假") | |
{ | |
e.isMismatch = true; | |
e.ResponseMessage = "你只能輸入事假,病假,事假其中之一"; | |
} | |
break; | |
default: | |
break; | |
} | |
}; | |
//取得 http Post RawData(should be JSO | |
string postData = Request.Content.ReadAsStringAsync().Result; | |
//剖析JSON | |
var ReceivedMessage = isRock.LineBot.Utility.Parsing(postData); | |
//定義接收CIC結果的類別 | |
ProcessResult<LeaveRequestV2> result; | |
if (ReceivedMessage.events[0].message.text == "我要請假") | |
{ | |
//把訊息丟給CIC | |
result = CIC.Process(ReceivedMessage.events[0], true); | |
responseMsg = "開始請假程序\n"; | |
} | |
else | |
{ | |
//把訊息丟給CIC | |
result = CIC.Process(ReceivedMessage.events[0]); | |
} | |
//處理 CIC回覆的結果 | |
switch (result.ProcessResultStatus) | |
{ | |
case ProcessResultStatus.Processed: | |
if (result.ResponseButtonsTemplateCandidate != null) | |
{ | |
//如果有template Message,直接回覆,否則放到後面一起回覆 | |
isRock.LineBot.Utility.ReplyTemplateMessage( | |
ReceivedMessage.events[0].replyToken, | |
result.ResponseButtonsTemplateCandidate, | |
ChannelAccessToken); | |
return Ok(); | |
} | |
//取得候選訊息發送 | |
responseMsg += result.ResponseMessageCandidate; | |
break; | |
case ProcessResultStatus.Done: | |
responseMsg += result.ResponseMessageCandidate; | |
responseMsg += $"蒐集到的資料有...\n"; | |
responseMsg += Newtonsoft.Json.JsonConvert.SerializeObject(result.ConversationState.ConversationEntity); | |
break; | |
case ProcessResultStatus.Pass: | |
responseMsg = $"你說的 '{ReceivedMessage.events[0].message.text}' 我看不懂,如果想要請假,請跟我說 : 『我要請假』"; | |
break; | |
case ProcessResultStatus.Exception: | |
//取得候選訊息發送 | |
responseMsg += result.ResponseMessageCandidate; | |
break; | |
case ProcessResultStatus.Break: | |
//取得候選訊息發送 | |
responseMsg += result.ResponseMessageCandidate; | |
break; | |
case ProcessResultStatus.InputDataFitError: | |
responseMsg += "\n資料型態不合\n"; | |
responseMsg += result.ResponseMessageCandidate; | |
break; | |
default: | |
//取得候選訊息發送 | |
responseMsg += result.ResponseMessageCandidate; | |
break; | |
} | |
//回覆用戶訊息 | |
isRock.LineBot.Utility.ReplyMessage(ReceivedMessage.events[0].replyToken, responseMsg, ChannelAccessToken); | |
//回覆API OK | |
return Ok(); | |
} | |
catch (Exception ex) | |
{ | |
//如果你要偵錯的話 | |
//isRock.LineBot.Utility.PushMessage("!!!!!!!!!!!! 換成你自己的 Admin Line UserId !!!!!!!!!!!!!", ex.Message, ChannelAccessToken); | |
//return Ok(); | |
throw ex; | |
} | |
} | |
} |
只需要配合ButtonsTemplate Message在59-59行針對CIC的Process result,取得ResponseButtonsTemplateCandidat(64行)進行Reply即可。
其他的程式碼跟上一版幾乎完全一樣沒變。
而24-29行只是加了一小段判斷,規定用戶只能選擇事假、病假、公假其中之一…純粹只是寫著玩測試一下。
執行這段對話之後,chat bot可以蒐集用戶的回答,結果如下:
想要在ConversationEntity中使用ButtonsTemplate也沒有問題囉
------------------
相關課程: http://www.studyhost.tw/NewCourses/LineBot
LineBotSDK : https://www.nuget.org/packages/LineBotSDK
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。
留言
正在想要實作一個應用情境,是需要Buttons Templat的訊息
沒想到CIC已經可以實作了....
enjoy it~ :)
其實也可以喔...
過陣子寫一篇給你...
最近看到您的Line Bot深感興趣,
目前對於使用者的回答來決定下一題的題目,
這項功能不曉得該怎麼實做出來呢?
請問ButtonsTemplateQuestion中,如果imageurl不要使用,該如何寫。我有試著留空值但不行,謝謝。
如果我請假流程有一個要上傳假單
class LeaveRequest
要怎樣做到丟圖