Alan Tsai 的學習筆記


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

[Bot Framework V4][08]改用TextPrompt詢問使用者姓名

[Bot Framework V4][08]改用TextPrompt詢問使用者姓名.jpg
圖片來源:https://pixabay.com/en/books-spine-colors-pastel-1099067/ 

在上一篇([07]Dialog - 控制流程的元件介紹)介紹了Dialog的原件之後,接下來就是要實際使用看看是什麽感覺。

這篇先用最基本的TextPrompt,看看如何簡化詢問姓名的邏輯。

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

修改方式

還記得之前上一篇提到了關於Dialog會被放在在DialogSet裡面,然後由Bot執行啓動。

DialogSet會需要State Accessor用來記錄執行過程的一些信息。

有了這些概念之後,接下來的調整就是:

  1. 安裝Dialog的package套件
  2. 建立出一個DialogState的Accessor
  3. 調整Startup初始化Accessor
  4. 建立出DialogSet以及TextPrompt
  5. 測試

安裝Dialog的package套件

Dialog是一個額外的套件,因此要使用需要額外安裝套件,可以透過Package Management Console執行: Install-Package Microsoft.Bot.Builder.Dialogs

安裝了之後,要使用的地方需要加入using Microsoft.Bot.Builder.Dialogs;

建立出一個DialogState的Accessor

打開EchoBotAccessors.cs并且增加:

public class EchoBotAccessors
{
	...
	public static string DialogStateName { get; } = 
		$"{nameof(EchoBotAccessors)}.DialogState";
		
	public IStatePropertyAccessor<DialogState> DialogState { get; set; }
	...
}

再來就是要new這個Accessor啦。

調整Startup初始化Accessor

再來切換到Startup.cs,這個時候在設定EchoBotAccessor的時候,要增加一段:

services.AddSingleton<EchoBotAccessors>(sp =>
{
	var accessors = new EchoBotAccessors
		(conversationState, userState)
	{
		....
		DialogState = conversationState.CreateProperty<DialogState>
			(EchoBotAccessors.DialogStateName)
	};

	return accessors;
}

這樣Accessor的部分就準備好了。

建立出DialogSet以及TextPrompt

再來打開EchoWithCounterBot.cs,準備修改邏輯。

首先是Constructor的部分:

public class EchoWithCounterBot : IBot
{
	...
	private readonly DialogSet _dialogs;
	
	public EchoWithCounterBot(EchoBotAccessors accessors,
		ILoggerFactory loggerFactory)
	{
		....
		_dialogs = new DialogSet(_accessors.DialogState);
		_dialogs.Add(new TextPrompt("askName"));
	}
}

這邊建立出一個DialogSet,并且在這個DialogSet增加了一個TextPrompt叫做askName

再來調整OnTurnAsync的邏輯:

public async Task OnTurnAsync(ITurnContext turnContext, CancellationToken cancellationToken = default(CancellationToken))
{
	if (turnContext.Activity.Type == ActivityTypes.Message)
	{
		var state = await _accessors.CounterState.GetAsync
			(turnContext, () => new CounterState());

		var userInfo = await _accessors.UserInfo.GetAsync
			(turnContext, () => new Model.UserInfo());

		var dialogContext = await _dialogs.CreateContextAsync
			(turnContext, cancellationToken);
		var dialogResult = await dialogContext.ContinueDialogAsync
			(cancellationToken);

		if (string.IsNullOrEmpty(userInfo.Name) 
				&& dialogResult.Status == DialogTurnStatus.Empty)
		{
			await dialogContext.PromptAsync(
					"askName",
					new PromptOptions
						{ Prompt = MessageFactory.Text("請問尊姓大名?") },
					cancellationToken);

		}
		else if(dialogResult.Status == DialogTurnStatus.Complete)
		{
			if (dialogResult.Result != null)
			{
				userInfo.Name = dialogResult.Result.ToString();

				await _accessors.UserInfo.SetAsync(turnContext, userInfo);
				await _accessors.UserState.SaveChangesAsync(turnContext);

				await turnContext.SendActivityAsync($"{userInfo.Name} 您好");
			}
		}
		else
		{
			// 原本的EchoBot邏輯
		}
	}
	else
	{
		.....
	}

	await _accessors.ConversationState.SaveChangesAsync(turnContext);
}

測試

上面修改完成之後,接下來就是測試的時候啦。

Bot Framework Emulator_2018-10-24_21-25-32.png
調整完成之後的測試結果

從這邊會發現,整個操作感覺和之前沒有差。

結語

這篇把原本自己管理的ConversationState,改成使用TextPrompt來管理。

從結果來説,兩邊的結果是一致的,但是從程式碼的角度來説其實沒什麽太大差異。

就算用了TextPrompt好像和自己管理沒什麽差,那爲什麽要用呢?

原因是目前的例子太簡單了,下一篇([09]使用waterfall建立表單式填寫)把問題用複雜一點,看看搭配waterfall的dialog整體使用感覺如何。


如果文章對您有幫助,就請我喝杯飲料吧
街口支付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