2016年4月1日

用Bot Framework開發一個Chat Bot

Bot Framework是微軟在//BUILD 2016大會上所公布的新服務,透過Bot Framework讓開發人員更容易開發可以掛在網頁上、Slack或是Skype等等應用程式中的Chat Bot。

所有相關文件都在Bot Framework官網:https://dev.botframework.com;下面我會以撰寫一個簡單的Bot,在對話中透過先前定義好的LUIS Application分析語意,再根據語意做相對應的處理。

  • 首先,讓我們到Bot Framework首頁註冊一個Bot

 

  • 輸入相關資訊,這邊的Endpoint是稍後我們Bot程式接收訊息的端點,我的例子裏會把這個Bot佈署到Azure上;這邊要注意,因為bot程式說到底還是個MVC WEB API,因此Endpoint這邊格式是https://<FQDN>/api/messagesC:\temp\snip_20160401104405.png

snip_20160401104405

  • 下方AppID的地方給自己的Bot一個好記的名稱即可C:\temp\snip_20160401104637.png

snip_20160401104637

  • 按下註冊就完成Bot註冊程序了
  • 接著回到Bot Framework主頁,打開剛剛完成的Bot,記下Primary Key

snip_20160401104917

  • 如果是第一次開發Bot,請到這裡下載VS Template :http://aka.ms/bf-bc-vstemplate
  • 下載後將ZIP檔複製到:“%USERPROFILE%\Documents\Visual Studio 2015\Templates\ProjectTemplates\Visual C#"
  • 然後開啟Visual Studio 2015,建立新的BOT專案

snip_20160401105200

  • 打開後會發現這其實是個MVC WEB API專案,我們所要修改的部分主要都在MessageController.cs
  • 在這裡我想做的事,是讓使用者輸入”find azure sql database updates”;Bot透過搜尋引擎找到SQL Database相關的更新資訊。因此在開始寫這個Bot之前,我已經先建好了一個LUIS專案並訓練他相關的語意了。
  • 我將我的MessageController.cs中的Post()方法改成以下的樣子

public async Task<Message> Post([FromBody]Message message)
{
    if (message.Type == "Message")
    {
        var action = ChatReactionHelper.FindAction(message.Text);
        var result = action.DoAction(message.Text);
        var reply = message.CreateReplyMessage(result);

        return reply;
    }
    else
    {
        return HandleSystemMessage(message);
    }
}

    • 其中,ChatReactionHelper會呼叫LUIS幫我找出使用者的語意,並建立相對應的Action Handler
    • 將使用者輸入的語句,傳入Action Handler後,Action Handler就會進行相對應的動作;目前我這裡僅是簡單的將要查詢的服務丟到搜尋引擎去,然後將搜尋結果回傳。
    • 最後,透過message.CreateReplyMessage()組出回傳訊息丟給前端
  • ChatReactionHelper裡只有一個Method:透過ActionFactory取得正確的Action

public class ChatReactionHelper
{
    public static IAction FindAction(string message)
    {
        return ActionFactory.FindAction(message);
    }
}

  • ActionFactory主要的method()定義如下:
    • LUIS():呼叫LUIS,將使用者輸入的語句傳入,讓LUIS回傳intent與entity,然後透過Reflection建立Action Object。

private url = “<YOUR LUIS QUERY URL>”;

private static IAction LUIS(string utterance)
{
    var wc = new WebClient();
    using (var stream = wc.OpenRead(string.Format(url, utterance)))
    {
        using (var sr = new StreamReader(stream))
        {
            var result = sr.ReadToEnd();
            var luisResult = ParseResult(result);

            if(luisResult.intents.Count == 0)
            {
                throw new ArgumentOutOfRangeException("Can't find proper intents");
            }
            var type = Type.GetType($"AzureBotConversationHelper.Actions.IMPL.{luisResult.intents[0].intent.Replace("$", "")}_Action");
            IAction action = Activator.CreateInstance(type, new object[] { new string[] { (string)luisResult.entities[0].entity } }) as IAction;
           
            return action;

        }
    }

}
public static IAction FindAction(string message)
{
    return LUIS(message);
}

  • Action Handler的處理很簡單,只是把查詢的服務名稱丟給Google,把結果丟給前端

public override string DoAction(string request)
        {
            string url = $"http://www.google.com.tw/search?hl=zh-TW&q={queryTexts[0]}";
            var wc = new WebClient();
            using (var stream = wc.OpenRead(url))
            {
                using (var sr = new StreamReader(stream))
                {
                    return  sr.ReadToEnd();
                 }
            }
            return null;
        }

  • 完成之後,打開Web.Config,找到以下的設定,將AppId改為先前在bot framework上註冊的AppID;將AppSecret改為先前複製下來的Key

snip_20160401110308

  • 然後就可以佈署到Azure上了;佈署完成後,回到Bot Framework頁面;可以在這裡做個簡單的測試。

snip_20160401110432

  • 接著可以在右方找到將Bot embed到各類應用程式的方法。

snip_20160401110545

snip_20160401110722

About Me