使用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也沒有問題囉 Smile

完整程式碼請參考:
https://github.com/isdaviddong/LinebotConversationExample/blob/master/LinebotConversationExample/Controllers/CICTest2Controller.cs

------------------
相關課程: http://www.studyhost.tw/NewCourses/LineBot
LineBotSDK : https://www.nuget.org/packages/LineBotSDK
如果需要即時取得更多相關訊息,可按這裡加入FB專頁。若這篇文章對您有所幫助,請幫我們分享出去,謝謝您的支持。

留言

Unknown寫道…
老師太棒了...
正在想要實作一個應用情境,是需要Buttons Templat的訊息
沒想到CIC已經可以實作了....
isDavid寫道…
@姜小志,

enjoy it~ :)
阿豪寫道…
這個功能真是不錯,最近也在利用line bot試著寫一個問卷系統,不過客戶要求是根據前一題的回答決定下一題的問題題目,可措沒辦法利用這個CIC來做。
isDavid寫道…
@阿豪,

其實也可以喔...
阿豪寫道…
那這樣是我沒試出來了,看來還是要再多試試功能才行
isDavid寫道…
@阿豪,

過陣子寫一篇給你...
阿豪寫道…
試了一陣子,結果還是沒弄出來 >.<
Unknown寫道…
老師 您好
最近看到您的Line Bot深感興趣,
目前對於使用者的回答來決定下一題的題目,
這項功能不曉得該怎麼實做出來呢?
carlshen寫道…
老師您好
請問ButtonsTemplateQuestion中,如果imageurl不要使用,該如何寫。我有試著留空值但不行,謝謝。
匿名表示…
想問一下
如果我請假流程有一個要上傳假單

class LeaveRequest

要怎樣做到丟圖

這個網誌中的熱門文章

使用LM Studio輕鬆在本地端以API呼叫大語言模型(LLM)

實際嘗試使用DeepSeek API

使用 Dify 以No Code方式建立記帳機器人

使用 Dify API 快速建立一個包含前後文記憶的對談機器人

使用 Dify 建立企業請假機器人