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
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
comments powered by Disqus