Alan Tsai 的學習筆記


學而不思則罔,思而不學則殆,不思不學則“網貸” 記錄軟體開發的點點滴滴 著重於微軟技術、網頁開發、DevOps、C#, Asp .net Mvc、Azure、AI、Chatbot、Docker、Data Science

[chatbot + AI = 下一代操作模式][04]瞭解BotBuilder的組成

[chatbot + AI = 下一代操作模式][04]瞭解BotBuilder的架構.jpg
圖片來源:https://pixabay.com/en/books-spine-colors-pastel-1099067/ 

在上一篇([03]建立第一個chatbot - EchoBot)透過使用Project Template建立出一個EchoBot出來,并且透過了bot emulator瞭解了如何和chatbot做測試。

這篇將會深入一些,看看BotBuilder的組成以及一些比較重要的class。

這篇的程式碼github頁面是alantsai-samples/mhat-hotelbot:blog/chapter-04

BotBuilder的運作方式

首先看一下上一篇建立出來的的VS 專案内容。裡面東西不復雜,可以看到只有幾個資料夾以及class:

devenv_2018-07-08_11-28-39.png
最基本的BotBuilder專案結構

我們可以看一下:

  1. MessagesController.cs
  2. RootDialog.cs

MessageController.cs

之前有提到過,BotBuilder是以Asp .Net Web Api為基地,因此一定會有一個Controller作爲進入點。而這個class就是我們整個服務的進入點。

往裏面看可以看到只有一個Post方法,并且接的參數形態是Activity。然後依照不同的ActivityType,有不同的處理:

public async Task Post([FromBody]Activity activity)
{
	if (activity.GetActivityType() == ActivityTypes.Message)
	{
		await Conversation.SendAsync(activity, () => new Dialogs.RootDialog());
	}
	else
	{
		HandleSystemMessage(activity);
	}
	var response = Request.CreateResponse(HttpStatusCode.OK);
	return response;
}

當ActivityType是訊息類型的時候,我們會呼叫RootDialog,要不然會到另外一個方法裡面處理不同類型的ActivityType。

Activity這個class是什麽東西呢?

Activity

還記得之前的一張圖嗎:

a238a09a-ee30-4106-8ec1-175e92acb902.png
整個Bot Framework的結構

我們提到過,爲了支援不同平臺,BotBuilder會用一個統一格式作爲最後的資料結構,而Activity或者更抽象的說IActivity就是這麽一個統一的形態。

因此BotBuilder每一次收到的都是一個Activity,而Activity又有分形態:

ActivityTypes.Message
最常見的一種形態,只要是使用者傳入的訊息都是這種。
ActivityTypes.ConversationUpdate
當有使用者加入或者退出chatbot的時候
ActivityTypes.DeleteUserData
當使用者退出chatbot并且要求刪除資料。這個可以用來清理chatbot對於某個使用者記錄的訊息。
ActivityTypes.Typing
當使用者正在打字的時候,還沒送出的類型。這種使用情景比較少。
ActivityTypes.Ping
一般來説這種都是平臺用來確定chatbot是不是還活著。

Activity取決於不同的Type也會包含不同的資訊。例如,如果是ActivityTypes.Message,那麽取決於是什麽類型的訊息(文字、圖片或語音)那麽從Activity取得資料的方式也不同。

最基本的文字類型,可以透過Text這個Property取得值。其他的訊息類型後面有遇到在介紹。

RootDialog.cs

Dialog是BotBuilder裡面的一個概念,可以簡單理解成爲:專門處理一件事情的最小單位,所以例如我的chatbot有查訂單和查旅館兩個功能,那麽就有2個dialog分別處理對應事情。

Dialog在後面拆分邏輯的時候會有更加詳細的介紹,以目前來説可以理解為RootDialog是我們的文字訊息處理的主要邏輯。

一個正確的Dialog有兩個條件:

  1. 實作IDialog<T>
  2. 把class訂位Serlizable

整個程式碼如下:

public Task StartAsync(IDialogContext context)
{
	context.Wait(MessageReceivedAsync);

	return Task.CompletedTask;
}

private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object>result)
{
	var activity = await result as Activity;

	// Calculate something for us to return
	int length = (activity.Text ?? string.Empty).Length;

	// Return our reply to the user
	await context.PostAsync($"You sent {activity.Text} which was {length} characters");

	context.Wait(MessageReceivedAsync);
}

StartAsync是IDialog本身要求實作的部分,他透過context.Wait表示等待下一個訊息要直接由 MessageReceivedAsync做處理。

而在MessageReceivedAsync裡面則是從Activity裡面取得了文字内容,并且透過context回傳了文字本身内容以及長度。

最後呼叫了一個context.wait,并且指向同一個方法。換句話説,變成了無限回圈,下一個訊息還是由MessageRecievedAsysnc來處理。

IDialogContext是一個輔助上下文的物件 - 裡面可以取得和這個使用者相關的一些訊息,和控制接下來的chatbot流程。下一篇將會介紹這個部分,因此暫時忽略。

調整chatbot

有了以上的資訊之後,對於如何修改程式就有了基本概念。我們要把理論變成實作。

假設今天有了一個需求:如果使用者輸入了Hello,chatbot回傳World,要不然就保留目前的回傳内容。

那麽怎麽修改呢?

從上面的理解知道所有邏輯都在RootDialog裡面,因此如果在裡面加入一些判斷邏輯就可以啦:

private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
{
	var activity = await result as Activity;

	if (activity.Text == "Hello")
	{
		await context.PostAsync("World");
	}
	else
	{
		// Calculate something for us to return
		int length = (activity.Text ?? string.Empty).Length;

		// Return our reply to the user
		await context.PostAsync($"You sent {activity.Text} which was {length} characters");
	}

	context.Wait(MessageReceivedAsync);
}
Bot Framework Emulator_2018-07-08_12-27-38.png
測試結果

這篇幾個重要Keyword總結

IActivity
整個BotBuilder接受以及傳送的一個共用的資料形態。
IDialog
一個最小單位的功能邏輯 - 透過Dialog可以做到Separtation of Concern。
IDialogContext
處理Chatbot上下文以及流程的物件。

結語

這篇對於整個BotBuilder的運作以及幾個重要物件做了介紹,并且透過一個小修改調整了chatbot的邏輯。

可是接下來有個很重要的問題是,我如果要記錄和使用者有關的訊息要怎麽存?

下一篇([05]深入IDialogContext - 處理上下文、對外的聯係和state),將會看一下專門處理上下文的物件IDialogContext


如果文章對您有幫助,就請我喝杯飲料吧
街口支付QR Code
街口支付QR Code
台灣 Pay QR Code
台灣 Pay QR Code
Line Pay 一卡通 QR Code
Line Pay 一卡通 QR Code
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
comments powered by Disqus