Microsoft LUIS (Language Understanding Intelligent Service) 是微軟不久前推出的一項語意識別的服務
透過一段時間的訓練,就可以有效的進行口語化內容的識別,搭配前端程式的撰寫,就可以作出依據發問者的需求作出答覆的應用
本篇文章會說明如何建立LUIS的服務,並進行訓練,最後會加上整合Bot Framework的前端機器人服務作出自動答覆的應用
建立LUIS本身服務的方式不難,但是困難的地方在於如何進行LUIS的訓練,讓伺服器能夠瞭解提出的語意內容
要申請建立LUIS服務的方式,依照下面步驟的執行就可以順利完成了
先連到LUIS的網址https://www.luis.ai/,並點選中間的[Sign in or create an account],若是有Microsoft Account的話,就可以直接進行登入的動作
登入成功之後,在上方的[My Application]頁面中,請點選[New App] => [New Application]
建立一個新的LUIS應用程式,需要填入應用程式的名稱以及語系,在這裡先選擇中文
建立完成後會進入到這個App的設定以及訓練畫面,在這裡看到的第一眼應該會覺得不知道該從何下手
下手的第一步,先從[Entities]開始,[Entities]代表了在一句話中的每一個實體項目,如動詞、名詞、疑問等等的,我先舉一個最簡單的例子,先在[Entities]裡,建立一個[問候]的項目
接著建立一個[人名]與[疑問]的[Entities],目前得到的結果就是像下圖這樣
定義好語句的實體項目後,接著就要到[Intents]這裡去建立語句的意圖,在[Intents]裡建立一個[只是打招呼]的項目,這個[Intents]的項目建立時,會要求先輸入一個範例的語句,以及在這個意圖的語句中,需要包含哪些實體項目就以打招呼的語句來看,需要的[Entities]就是[問候]了,所以我們將[問候]這個[Entities]加到參數中並按下儲存
按下儲存後,會出現範例語句是屬於哪一種意圖的設定,由於一句話中可能會包含多個[Entities],所以在設定一句話的實體時,可以用滑鼠反白後,點選這個語句所屬的實體是哪一個項目,設定完按下[Submit]就可以了
下面是另一個語句的訓練,點選[New utterances]後,輸入要訓練的語句[hi,你好]之後,可以將某段字串反白,並設定該字串的實體項目
按下[Submit]之後,點選左下方的[Train],這樣LUIS才會真正的去進行語意訓練的動作
作完訓練後,可以點選左上方的[Publish],將訓練的結果發佈成一個WebAPI,讓其他的應用程式進行呼叫
發佈完,可以直接在Query的地方輸入要語意識別的內容
LUIS會從WebAPI上回傳識別的結果,並以JSON回傳從回傳的結果可以看到,LUIS判斷有該語句有六成是問候語,如此一來,前端接收LUIS判斷的結果後,就可以作出相對應的回答了
接下來這個例子用到的範圍就比較廣一點,先在[Entities]裡建立[日期]、[航空公司]與[服務]三個項目
然後在[Intents]裡加上[詢問]的語意定義,並加上[疑問]、[航空公司]、[服務]與[日期]四個[Entites],然後給予一個例句
然後在這個例句中,分別定義包含的[Entities],然後設定這句話的Intents為[詢問]
[請問]:疑問
[今天]:日期
[華航]:航空公司
[航班]:服務
當然我們可以作多一點的例句進行訓練動作
訓練完並發佈後,我們在Publish的畫面上輸入一下比較不一樣的語句,看LUIS是否能正確的判斷出結果
得到的結果,LUIS判斷出這是一個問句,並且也把相關的[Entities]抓出來回傳JSON資料了
LUIS的訓練說明先到這邊,接下來要整合Bot Framework的機器人,讓機器人可以將使用者輸入的文字傳入至LUIS後,取得識別的結果再進行判斷
先在LUIS的App畫面上點選左上方的[App Settings],並把[App Id]與[Subscription Key]記下來,等一下會用到
打開Visual Studio,開啟Bot Framework機器人的專案,並在Models的資料夾中建立一個CognitiveModels.cs的類別庫,加上下面的程式碼
public class LUISResult
{
public string query { get; set; }
public List<Intent> intents { get; set; }
public List<Entity> entities { get; set; }
public class Intent
{
public string intent { get; set; }
public float score { get; set; }
public List<Action> actions { get; set; }
}
public class Action
{
public bool triggered { get; set; }
public string name { get; set; }
public List<Parameter> parameters { get; set; }
}
public class Parameter
{
public string name { get; set; }
public bool required { get; set; }
public List<Value> value { get; set; }
}
public class Value
{
public string entity { get; set; }
public string type { get; set; }
public float score { get; set; }
}
public class Entity
{
public string entity { get; set; }
public string type { get; set; }
public int startIndex { get; set; }
public int endIndex { get; set; }
public float score { get; set; }
}
}
這個Model主要是用來接收從LUIS上回傳的識別結果,並從JSON轉換為物件類別用
在Web.Config檔案中加上前面步驟中記下來的兩個設定,分別是LUIS上的[App Id]與[Subscription Key]
<add key="LUISAPIKey" value="[LUIS上的Subscription Key]"/>
<add key="LUISAppId" value="[LUIS上的App Id]"/>
接著,在Controllers\MessagesControlles.cs這個主要用來接收與回傳Bot機器人訊息的控制器中,將原本Post的程式碼,置換成下面的程式碼
public async Task<Message> Post([FromBody]Activity activity)
{
// Activity 是Bot Framework 3.0的寫法,若是改版後這種寫法無法使用
// 請在文章下方留言告訴我,以進行內容的更新與修改
if (activity.Type == ActivityTypes.Message)
{
string strLuisKey = ConfigurationManager.AppSettings["LUISAPIKey"].ToString();
string strLuisAppId = ConfigurationManager.AppSettings["LUISAppId"].ToString();
string strMessage = HttpUtility.UrlEncode(activity.Text);
string strLuisUrl = $"https://api.projectoxford.ai/luis/v1/application?id={strLuisAppId}&subscription-key={strLuisKey}&q={strMessage}";
// 收到文字訊息後,往LUIS送
WebRequest request = WebRequest.Create(strLuisUrl);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string json = reader.ReadToEnd();
CognitiveModels.LUISResult objLUISRes = JsonConvert.DeserializeObject<CognitiveModels.LUISResult>(json);
string strReply = "無法識別的內容";
if (objLUISRes.intents.Count > 0)
{
string strIntent = objLUISRes.intents[0].intent;
if (strIntent == "詢問")
{
string strDate = objLUISRes.entities.Find((x => x.type == "日期")).entity;
string strAir = objLUISRes.entities.Find((x => x.type == "航空公司")).entity;
string strService = objLUISRes.entities.Find((x => x.type == "服務")).entity;
strReply = $"您要詢問的航空公司:{strAir},日期:{strDate},相關服務是:{strService}。我馬上幫您找出資訊";
strReply += ".....這裡加上後續資料的呈現.....";
}
if (strIntent == "只是打招呼")
{
strReply = "您好,有什麼能幫得上忙的呢?";
}
if (strIntent == "None")
{
strReply = "您在說什麼,我聽不懂~~~(轉圈圈";
}
}
Activity reply = activity.CreateReply(strReply);
await connector.Conversations.ReplyToActivityAsync(reply);
}
else
{
return HandleSystemMessage(activity);
}
}
這段程式碼主要是從LUIS上取得語意辨識的結果後,判斷[Intent]的與用來決定語句語義的[Entities]項目,然後回傳結果內容至前端的機器人上,最後得到的畫面如下回傳至前端Bot Framework的訊息,確定是從LUIS上判斷得到的結果,前端的機器人也可以順利的取得回答的文字內容了
透過LUIS與Bot Framework的整合,可以很快的建構出一個簡單的線上即時問答與服務的對話機器人,對於企業在提供線上服務、與客服對話以及整體的人機運用架構上會有相關大的改變與突破。