HoloLens (第 1 代) 和 Azure 303:自然語言理解 (LUIS)


注意

混合實境學院教學課程的設計是以 HoloLens (第 1 代) 和混合實境沉浸式頭戴裝置為準。 因此,對於仍在尋找這些裝置開發指引的開發人員而言,我們覺得這些教學課程很重要。 這些教學課程不會使用用於 HoloLens 2 的最新工具組或互動進行更新。 系統會保留這些資訊,以繼續在支援的裝置上運作。 未來將會張貼一系列新的教學課程,以示範如何開發 HoloLens 2。 發佈這些教學課程時,將會更新此通知的連結。


在此課程中,您將瞭解如何使用 Azure 認知服務與 Language Understanding API,將 Language Understanding 整合到混合實境應用程式中。

實驗室成果

Language Understanding (LUIS) 是一項 Microsoft Azure 服務,可讓應用程式能夠從使用者輸入中產生意義,例如,透過擷取人員可能想要的內容,以自己的字組來擷取。 這是透過機器學習來達成,其可瞭解並學習輸入資訊,然後可以使用詳細的相關信息來回復。 如需詳細資訊,請流覽 Azure Language Understanding (LUIS) 頁面

完成本課程之後,您將擁有混合實境沉浸式頭戴式裝置應用程式,能夠執行下列動作:

  1. 使用附加至沉浸式頭戴式裝置的麥克風來擷取使用者輸入語音。
  2. 傳送擷取的聽寫 Azure Language Understanding Intelligent Service (LUIS) 。
  3. 從傳送資訊中取得 LUIS 擷取意義,這會進行分析,並嘗試判斷使用者的要求意圖。

開發將包含建立應用程式,讓用戶能夠使用語音和/或注視來變更場景中物件的大小和色彩。 不會涵蓋動作控制器的使用。

在您的應用程式中,您可以瞭解如何將結果與設計整合。 本課程旨在教導您如何整合 Azure 服務與您的 Unity 專案。 您的工作是使用您從本課程獲得的知識來增強混合實境應用程式。

請準備數次訓練 LUIS,這 在第 12 章中涵蓋。 您將得到更好的結果,LUIS 已定型的時間愈多。

裝置支援

課程 HoloLens 沉浸式頭戴裝置
MR 和 Azure 303:自然語言理解 (LUIS) ✔️ ✔️

注意

雖然本課程主要著重於 Windows Mixed Reality 沉浸式 (VR) 頭戴式裝置,但您也可以將此課程中學到的內容套用至 Microsoft HoloLens。 當您跟著課程進行時,您會看到可能需要採用以支援 HoloLens 之任何變更的附注。 使用 HoloLens 時,您可能會在語音擷取期間注意到一些回應。

必要條件

注意

本教學課程專為具備 Unity 和 C# 基本經驗的開發人員所設計。 另請注意,本檔中的必要條件和書面指示代表在 2018 年 5 月撰寫 () 時已經過測試及驗證的內容。 您可以免費使用最新的軟體,如 安裝工具 一文中所列,但不應假設本課程中的資訊會完全符合您在較新軟體中找到的內容,而不是下面所列的內容。

針對本課程,我們建議使用下列硬體和軟體:

開始之前

  1. 為了避免建置此專案時發生問題,強烈建議您在根資料夾或近根資料夾中建立本教學課程中所提及的專案, (長資料夾路徑可能會導致建置時間) 的問題。

  2. 若要允許您的計算機啟用聽寫,請移至 Windows 設定 > 隱私權 > 語音、筆跡 & 輸入 ,然後按 [ 開啟語音服務和輸入建議] 按鈕。

  3. 本教學課程中的程式代碼可讓您從計算機上設定 的預設麥克風裝置 錄製。 請確定 [預設麥克風裝置] 已設定為您想要用來擷取語音的裝置。

  4. 如果您的頭戴式裝置有內建的麥克風,請確定在 [Mixed Reality 入口網站設定中開啟 [當我戴上頭戴式裝置時,切換至頭戴式裝置麥克風] 選項。

    設定沉浸式頭戴式裝置

第 1 章 – 設定 Azure 入口網站

若要在 Azure 中使用 Language Understanding 服務,您必須將服務的實例設定為可供您的應用程式使用。

  1. 登入 Azure 入口網站

    注意

    如果您還沒有 Azure 帳戶,則必須建立一個帳戶。 如果您在教室或實驗室情況中遵循本教學課程,請詢問講師或其中一個專業課程,以協助設定您的新帳戶。

  2. 登入之後,按兩下左上角的 [新增],然後搜尋 Language Understanding,然後按兩下 Enter

    建立 LUIS 資源

    注意

    在較新的入口網站中, [新增 ] 這個字可能已取代為 建立資源

  3. 右側的新頁面將提供 Language Understanding 服務的描述。 在此頁面左下方,選取 [ 建立 ] 按鈕,以建立此服務的實例。

    LUIS 服務建立 - 法律聲明

  4. 按兩下 [建立]:

    1. 插入此服務實例所需的 Name

    2. 選取 [訂用帳戶] 。

    3. 選取適合您的 定價層 ,如果這是第一次建立 LUIS 服務,您應該可以使用名為 F0) 的免費層 (。 免費配置應該足以供本課程使用。

    4. 選擇 資源群組 或建立新的群組。 資源群組提供一種方式來監視、控制存取、布建和管理 Azure 資產集合的計費。 建議您保留與單一專案相關聯的所有 Azure 服務 (,例如這些課程) 在通用資源群組) 下。

      如果您想要深入瞭解 Azure 資源群組,請 造訪資源群組一文

    5. 如果您要建立新的資源群組) ,請判斷資源群組的位置 (。 在理想情況下,位置會位於應用程式執行所在的區域中。 某些 Azure 資產僅適用於特定區域。

    6. 您也必須確認您已瞭解此服務適用的條款及條件。

    7. 選取 [建立]。

      建立 LUIS 服務 - 使用者輸入

  5. 按兩下 [ 建立] 之後,您必須等候服務建立,這可能需要一分鐘的時間。

  6. 建立服務實例之後,入口網站中會出現通知。

    新增 Azure 通知映像

  7. 按兩下通知以探索新的服務實例。

    成功建立資源通知

  8. 按兩下通知中的 [ 移至資源 ] 按鈕,以探索新的服務實例。 系統會將您帶至新的 LUIS 服務實例。

    存取 LUIS 金鑰

  9. 在本教學課程中,您的應用程式必須呼叫您的服務,這可透過使用服務的訂用帳戶密鑰來完成。

  10. LUIS API 服務的 [快速啟動] 頁面,流覽至第一個步驟[擷取金鑰],然後按下 [金鑰] (您也可以按下位於服務導覽功能表中的藍色超連結 [金鑰],以) 表示。 這會顯示您的服務 金鑰

  11. 擷取其中一個顯示的金鑰複本,因為您稍後會在專案中用到此複本。

  12. 在 [服務] 頁面中,按兩下 [Language Understanding 入口網站] 以重新導向至您將在 LUIS 應用程式內用來建立新服務的網頁。

第 2 章 – Language Understanding 入口網站

在本節中,您將瞭解如何在 LUIS 入口網站上建立 LUIS 應用程式。

重要

請注意,在本節中設定 實體意圖語句 只是建置 LUIS 服務的第一個步驟:您也需要重新定型服務,數次,以便更精確。 本課程 的最後一章 涵蓋重新定型您的服務,因此請確定您完成。

  1. 到達 Language Understanding 入口網站時,如果您尚未使用與 Azure 入口網站 相同的認證,您可能需要登入。

    LUIS 登入頁面

  2. 如果這是您第一次使用 LUIS,您必須向下捲動至歡迎頁面底部,才能尋找並按兩下 [ 建立 LUIS 應用程式 ] 按鈕。

    建立 LUIS 應用程式頁面

  3. 登入之後,如果您目前不在該區段) ,請按兩下 [ 我的應用程式 ] (。 接著,您可以按兩下 [ 建立新的應用程式]。

    LUIS - 我的應用程式映射

  4. 提供應用程式名稱

  5. 如果您的應用程式應該瞭解與英文不同的語言,您應該將 文化 特性變更為適當的語言。

  6. 您也可以在這裡新增新 LUIS 應用程式 的描述

    LUIS - 建立新的應用程式

  7. 按下 [完成] 之後,您將輸入新 LUIS 應用程式的 [建置] 頁面。

  8. 以下是一些重要的概念:

    • 意圖,表示將在使用者查詢之後呼叫的方法。 意圖可能有一或多個實體
    • 實體是查詢的元件,可描述 與 INTENT 相關的資訊。
    • 語句是開發人員所提供的查詢範例,LUIS 將用來訓練本身。

如果這些概念不完全清楚,請不要擔心,因為本課程會進一步釐清本章中的概念。

您將從建立建置本課程所需的 實體 開始。

  1. 在頁面左側,按兩下 [ 實體],然後按兩下 [ 建立新實體]。

    建立新的實體

  2. 呼叫新的實體 色彩,將其類型設定為 Simple,然後按 [完成]。

    建立簡單實體 - 色彩

  3. 重複此程式,以建立三個 (3 個) 名為 的簡單實體:

    • upsize
    • 縮小
    • 目標

結果看起來應該像下圖:

實體建立的結果

此時,您可以開始建立 意圖

警告

請勿刪除 None 意圖。

  1. 在頁面左側,按兩下 [ 意圖],然後按兩下 [ 建立新意圖]。

    建立新的意圖

  2. 呼叫新的 IntentChangeObjectColor

    重要

    意圖 名稱會在本課程稍後的程式代碼中使用,因此為了獲得最佳結果,請完全依照所提供的方式使用此名稱。

確認名稱之後,系統會將您導向至意圖頁面。

LUIS - 意圖頁面

您會注意到有一個文字框要求您輸入 5 或更多不同的 語句

注意

LUIS 會將所有語句轉換成小寫。

  1. 在頂端文字框中 插入下列語句 (目前有 大約 5 個範例的文字類型... ) ,然後按 Enter
The color of the cylinder must be red

您會注意到新的 語句 會出現在下方的清單中。

遵循相同的程式,插入下列六個 (6) 語句:

make the cube black

make the cylinder color white

change the sphere to red

change it to green

make this yellow

change the color of this object to blue

針對您已建立的每個語句,您必須識別 LUIS 應該使用哪些字組做為實體。 在此範例中,您必須將所有色彩標示為 色彩 實體,以及目標的所有可能參考作為 目標 實體。

  1. 若要這樣做,請嘗試按兩下第一個語句中的 文字圓柱 ,然後選取 目標

    識別語句目標

  2. 現在,按兩下第一個語句中的 紅色 字,然後選取 色彩

    識別語句實體

  3. 也為下一行加上標籤,其中 Cube 應該是 目標而黑色 應該是 色彩。 另請注意,使用 'this''it''this object' 這兩個字,我們提供這個字,因此也提供非特定目標類型。

  4. 重複上述程式,直到所有語句都標示為 [實體]。 如果您需要協助,請參閱下圖。

    提示

    選取字組將其標示為實體時:

    • 對於單字,只要按兩下即可。
    • 針對兩個或多個單字集,按兩下開頭,然後在集合結尾。

    注意

    您可以使用 [ 令牌檢視 ] 切換按鈕,在 [實體/ 令牌檢視] 之間切換!

  5. 結果應該如下列影像所示,其中顯示 [實體/ 令牌檢視]:

    令牌 & 實體檢視

  6. 此時,請按頁面右上方的 [定 型] 按鈕,並等候小圓角指示器開啟綠色。 這表示 LUIS 已成功定型以辨識此意圖。

    訓練 LUIS

  7. 作為練習,請使用實體目標upsize 和 downsize,建立名為 ChangeObjectSize 的新意圖。

  8. 遵循與上一個意圖相同的程式,針對 Size 變更插入下列八個 (8) 語句:

    increase the dimensions of that
    
    reduce the size of this
    
    i want the sphere smaller
    
    make the cylinder bigger
    
    size down the sphere
    
    size up the cube
    
    decrease the size of that object
    
    increase the size of this object
    
  9. 結果應該類似下圖中的結果:

    設定 ChangeObjectSize Token/ 實體

  10. 一旦這兩個意圖 、ChangeObjectColorChangeObjectSize 都已建立並定型,請按兩下頁面頂端的 [ 發佈 ] 按鈕。

    發佈 LUIS 服務

  11. 在 [ 發佈 ] 頁面上,您將完成併發佈 LUIS 應用程式,使其可供程式代碼存取。

    1. 將 [ 發佈至 ] 下拉式清單設定為 生產環境

    2. 時區 設定為時區。

    3. 核取 [ 包含所有預測意圖分數] 方塊。

    4. 按兩下 [ 發佈至生產位置]。

      發佈設定

  12. [資源和金鑰] 區段中:

    1. 選取您在 Azure 入口網站中針對服務實例設定的區域。
    2. 您會注意到下方 Starter_Key 元素,請忽略它。
    3. 按兩下 [ 新增金鑰 ],然後在您建立服務實例時,插入您在 Azure 入口網站中取得的 密鑰 。 如果您的 Azure 和 LUIS 入口網站登入相同的使用者,系統會提供租使用者名稱、用帳戶名稱,以及您想要使用之密鑰的下拉功能表, (與您先前在 Azure 入口網站中提供的名稱相同。

    重要

    [端點] 底下,擷取對應至您所插入密鑰的端點複本,您很快就會在程式碼中使用它。

第 3 章 – 設定 Unity 專案

以下是使用混合實境進行開發的一般設定,因此是其他專案的良好範本。

  1. 開啟 Unity ,然後按兩下 [ 新增]。

    啟動新的 Unity 專案。

  2. 您現在必須提供 Unity 項目名稱,插入 MR_LUIS。 請確定專案類型已設定為 3D。 將 [位置 ] 設定為適合您 (記住,較接近根目錄的較佳) 。 然後按兩下 [ 建立專案]。

    提供新 Unity 專案的詳細數據。

  3. 開啟 Unity 時,值得檢查預設 腳本編輯器 已設定為 Visual Studio。 移至 [編輯 > 喜好設定],然後從新視窗中流覽至 [外部工具]。 將 外部腳本編輯器 變更為 Visual Studio 2017。 關閉 [喜好設定] 視窗。

    更新文本編輯器喜好設定。

  4. 接下來,移至 [檔案>建置設定],然後按兩下 [切換平臺] 按鈕,將平臺切換為 通用 Windows 平台

    [建置設定] 視窗,將平臺切換至 UWP。

  5. 移至 [檔案 > 組建設定 ],並確定:

    1. 目標裝置 設定為 [任何裝置]

      針對 Microsoft HoloLens,將 [目標裝置] 設定為 HoloLens

    2. 組建類型 設定為 D3D

    3. SDK 設定為 [最新安裝]

    4. Visual Studio 版本 設定為 [最新安裝]

    5. [建置並執行 ] 設定為 [本機計算機]

    6. 儲存場景,並將它新增至組建。

      1. 選取 [ 新增開啟場景] 來執行此動作。 隨即會出現儲存視窗。

        按兩下 [新增開啟的場景] 按鈕

      2. 為此建立新的資料夾,以及任何未來的場景,然後選取 [ 新增資料夾 ] 按鈕,以建立新的資料夾,將它命名為 Scenes

        建立新的腳本資料夾

      3. 開啟新建立 的 Scenes 資料夾,然後在 [ 檔名:文字] 字段中,輸入 MR_LuisScene,然後按 [ 儲存]。

        為新的場景指定名稱。

    7. 其餘設定在 [建置設定] 中,現在應該保留為預設值。

  6. 在 [ 建置設定 ] 視窗中,按兩下 [ 播放機設定 ] 按鈕,這會在 Inspector 所在的空間中開啟相關的面板。

    開啟播放機設定。

  7. 在此面板中,需要驗證一些設定:

    1. 在 [ 其他設定] 索引 標籤中:

      1. 腳本運行時間版本 應該是 穩定 (.NET 3.5 對等) 。

      2. 腳本後端 應該是 .NET

      3. API 相容性層級 應該是 .NET 4.6

        更新其他設定。

    2. 在 [ 發佈設定] 索引標籤的 [ 功能] 底下,檢查:

      1. InternetClient

      2. Microphone (麥克風)

        更新發佈設定。

    3. 在面板的下方,在 [XR 設定] (中找到 [發佈設定]) [支援虛擬實境],確定已新增 Windows Mixed Reality SDK

      更新 X R 設定。

  8. 回到 組建設定Unity C# 專案不再呈現灰色;勾選此旁邊的複選框。

  9. 關閉 [建置設定] 視窗。

  10. 儲存場景和專案 (檔案 > 儲存場景/檔案 > 儲存專案) 。

第 4 章 – 建立場景

重要

如果您想要略過本課程的 Unity 設定 元件,並繼續進入程式碼,請隨意下載此 .unitypackage、將它匯入您的專案作為 自定義套件,然後從 第 5 章繼續進行。

  1. 以滑鼠右鍵按兩下 [ 階層面板] 的空白區域,在 [3D 物件] 底下新增 平面

    建立平面。

  2. 請注意,當您再次以滑鼠右鍵按兩下 [階層 ] 內以建立更多物件時,如果您仍然選取最後一個物件,則選取的物件將會是新物件的父代。 請避免在 [階層] 內的空白空間中按下滑鼠左鍵,然後按下滑鼠右鍵。

  3. 重複此程式以新增下列物件:

    1. Sphere
    2. 圓柱
    3. 立方體
    4. 3D 文字
  4. 產生的場景 階層 應該像下圖中的階層:

    場景階層設定。

  5. 以滑鼠左鍵按兩下 主要相機 以選取它,查看 [偵測器面板 ],您會看到 [相機] 物件及其所有元件。

  6. 按兩下位於 [偵測器面板] 底部的 [新增元件] 按鈕。

    新增音訊來源

  7. 搜尋稱為 音訊來源的元件,如上所示。

  8. 此外,也請確定主相機的 [轉換] 元件設定為 [ (0,0,0) ],方法是按下相機轉換元件旁的齒輪圖示,然後選取 [重設]。 然後,轉換元件看起來應該像這樣:

    1. 位置 設定為 0、0、0
    2. 旋轉 設定為 0、0、0

    注意

    針對 Microsoft HoloLens,您也必須變更下列專案,這是主相機上的相機元件的一部分:

    • 清除旗標: 純色。
    • 背景 'Black, Alpha 0' – 十六進位色彩: #000000000。
  9. 按兩下 [ 平面 ] 以選取它。 在 [偵測器面板 ] 中,使用下列值來設定 [轉換 ] 元件:

    X 軸 Y 軸 Z 軸
    0 -1 0
  10. 按兩下 [Sphere ] 以選取它。 在 [偵測器面板 ] 中,使用下列值來設定 [轉換 ] 元件:

    X 軸 Y 軸 Z 軸
    2 1 2
  11. 以滑鼠左鍵按兩下 [圓柱] 加以選取。 在 [偵測器面板 ] 中,使用下列值來設定 [轉換 ] 元件:

    X 軸 Y 軸 Z 軸
    -2 1 2
  12. 以滑鼠左鍵按兩下 Cube 加以選取。 在 [偵測器面板 ] 中,使用下列值來設定 [轉換 ] 元件:

轉換 - 位置

X Y Z
0 1 4

轉換 - 旋轉

X Y Z
45 45 0
  1. 以滑鼠左鍵按兩下 [新增文字 ] 物件以選取它。 在 [偵測器面板 ] 中,使用下列值設定 轉換 元件:

轉換 - 位置

X Y Z
-2 6 9

轉換 - 調整

X Y Z
0.1 0.1 0.1
  1. 文字網格元件中的字型大小變更為 50

  2. Text Mesh 物件的名稱變更為聽寫文字

    建立 3D Text 物件

  3. 您的階層面板結構現在看起來應該像這樣:

    場景檢視中的文字網格

  4. 最終場景看起來應該像下圖:

    場景檢視。

第 5 章 – 建立 MicrophoneManager 類別

您要建立的第一個腳本是 MicrophoneManager 類別。 在此之後,您將建立 LuisManager行為類別 ,最後一個 是 Gaze 類別 (立即建立所有這些類別,不過當您到達每個章節) 時,將會加以涵蓋。

MicrophoneManager 類別負責:

  • 偵測附加至頭戴式裝置或機器的錄製裝置, (哪一個是預設) 。
  • 擷取音訊 (語音) ,並使用聽寫將其儲存為字串。
  • 語音暫停之後,請將聽寫提交至 LuisManager 類別。

若要建立此類別:

  1. 以滑鼠右鍵按兩下 [項目面板] 的 [ 建立 > 資料夾]。 呼叫 [腳稿] 資料夾。

    建立文稿資料夾。

  2. 建立 [腳本 ] 資料夾后,按兩下即可開啟。 然後,在該資料夾中,以滑鼠右鍵按兩下 [ 建立 > C# 腳本]。 將腳本命名為 MicrophoneManager

  3. 按兩下 [麥克風][管理] ,以使用 Visual Studio 開啟它。

  4. 將下列命名空間新增至檔案頂端:

        using UnityEngine;
        using UnityEngine.Windows.Speech;
    
  5. 然後在 MicrophoneManager 類別中新增下列變數:

        public static MicrophoneManager instance; //help to access instance of this object
        private DictationRecognizer dictationRecognizer;  //Component converting speech to text
        public TextMesh dictationText; //a UI object used to debug dictation result
    
  6. 現在必須新增 Awake () Start () 方法的程序代碼。 當 類別初始化時,將會呼叫下列專案:

        private void Awake()
        {
            // allows this class instance to behave like a singleton
            instance = this;
        }
    
        void Start()
        {
            if (Microphone.devices.Length > 0)
            {
                StartCapturingAudio();
                Debug.Log("Mic Detected");
            }
        }
    
  7. 現在,您需要應用程式用來啟動和停止語音擷取的方法,並將它傳遞至 LuisManager 類別,您很快就會建置。

        /// <summary>
        /// Start microphone capture, by providing the microphone as a continual audio source (looping),
        /// then initialise the DictationRecognizer, which will capture spoken words
        /// </summary>
        public void StartCapturingAudio()
        {
            if (dictationRecognizer == null)
            {
                dictationRecognizer = new DictationRecognizer
                {
                    InitialSilenceTimeoutSeconds = 60,
                    AutoSilenceTimeoutSeconds = 5
                };
    
                dictationRecognizer.DictationResult += DictationRecognizer_DictationResult;
                dictationRecognizer.DictationError += DictationRecognizer_DictationError;
            }
            dictationRecognizer.Start();
            Debug.Log("Capturing Audio...");
        }
    
        /// <summary>
        /// Stop microphone capture
        /// </summary>
        public void StopCapturingAudio()
        {
            dictationRecognizer.Stop();
            Debug.Log("Stop Capturing Audio...");
        }
    
  8. 新增語音暫停時所叫用的 聽寫處理程式 。 這個方法會將聽寫文字傳遞至 LuisManager 類別。

        /// <summary>
        /// This handler is called every time the Dictation detects a pause in the speech. 
        /// This method will stop listening for audio, send a request to the LUIS service 
        /// and then start listening again.
        /// </summary>
        private void DictationRecognizer_DictationResult(string dictationCaptured, ConfidenceLevel confidence)
        {
            StopCapturingAudio();
            StartCoroutine(LuisManager.instance.SubmitRequestToLuis(dictationCaptured, StartCapturingAudio));
            Debug.Log("Dictation: " + dictationCaptured);
            dictationText.text = dictationCaptured;
        }
    
        private void DictationRecognizer_DictationError(string error, int hresult)
        {
            Debug.Log("Dictation exception: " + error);
        }
    

    重要

    刪除 Update () 方法,因為這個類別不會使用它。

  9. 請務必先將變更儲存在 Visual Studio 中,再返回 Unity

    注意

    此時,您會注意到 Unity 編輯器主控台面板中出現錯誤。 這是因為程式代碼會參考您將在下一章中建立的 LuisManager 類別。

第 6 章 – 建立 LUISManager 類別

您可以建立 LuisManager 類別,以呼叫 Azure LUIS 服務。

此類別的目的是要接收來自 MicrophoneManager 類別的聽寫文字,並將其傳送至要分析的 Azure Language Understanding API

這個類別會還原串行化 JSON 回應,並呼叫 Actionss 類別的適當方法來觸發動作。

若要建立此類別:

  1. 按兩下 [文稿 ] 資料夾,以開啟它。

  2. [腳本] 資料夾內按下滑鼠右鍵,按兩下 [ 建立 > C# 腳稿]。 將腳本命名為 LuisManager

  3. 按兩下腳本以使用Visual Studio加以開啟。

  4. 將下列命名空間新增至檔案頂端:

        using System;
        using System.Collections;
        using System.Collections.Generic;
        using System.IO;
        using UnityEngine;
        using UnityEngine.Networking;
    
  5. 首先,您會在相同腳本檔案內的 LuisManager 類別建立三個類別 (,在 [開始] () 方法) ,以代表來自 Azure 的還原串行化 JSON 回應。

        [Serializable] //this class represents the LUIS response
        public class AnalysedQuery
        {
            public TopScoringIntentData topScoringIntent;
            public EntityData[] entities;
            public string query;
        }
    
        // This class contains the Intent LUIS determines 
        // to be the most likely
        [Serializable]
        public class TopScoringIntentData
        {
            public string intent;
            public float score;
        }
    
        // This class contains data for an Entity
        [Serializable]
        public class EntityData
        {
            public string entity;
            public string type;
            public int startIndex;
            public int endIndex;
            public float score;
        }
    
  6. 接下來,在 LuisManager 類別內新增下列變數:

        public static LuisManager instance;
    
        //Substitute the value of luis Endpoint with your own End Point
        string luisEndpoint = "https://westus.api.cognitive... add your endpoint from the Luis Portal";
    
  7. 請務必將 LUIS 端點放在現在 (您從 LUIS 入口網站) 。

  8. 現在必須新增 Awake () 方法的程式代碼。 當 類別初始化時,將會呼叫這個方法:

        private void Awake()
        {
            // allows this class instance to behave like a singleton
            instance = this;
        }
    
  9. 現在您需要此應用程式用來將從 MicrophoneManager 類別收到的聽寫傳送至 LUIS 的方法,然後接收和還原串行化回應。

  10. 一旦判斷意圖和相關聯的實體值之後,它們就會傳遞至 Actionss 類別的實例,以觸發預期的動作。

        /// <summary>
        /// Call LUIS to submit a dictation result.
        /// The done Action is called at the completion of the method.
        /// </summary>
        public IEnumerator SubmitRequestToLuis(string dictationResult, Action done)
        {
            string queryString = string.Concat(Uri.EscapeDataString(dictationResult));
    
            using (UnityWebRequest unityWebRequest = UnityWebRequest.Get(luisEndpoint + queryString))
            {
                yield return unityWebRequest.SendWebRequest();
    
                if (unityWebRequest.isNetworkError || unityWebRequest.isHttpError)
                {
                    Debug.Log(unityWebRequest.error);
                }
                else
                {
                    try
                    {
                        AnalysedQuery analysedQuery = JsonUtility.FromJson<AnalysedQuery>(unityWebRequest.downloadHandler.text);
    
                        //analyse the elements of the response 
                        AnalyseResponseElements(analysedQuery);
                    }
                    catch (Exception exception)
                    {
                        Debug.Log("Luis Request Exception Message: " + exception.Message);
                    }
                }
    
                done();
                yield return null;
            }
        }
    
  11. 建立名為 AnalyseResponseElements () 的新方法,以讀取產生的 分析查詢 並判斷實體。 一旦判斷這些實體,這些實體就會傳遞至 Actionss 類別的實例,以便在動作中使用。

        private void AnalyseResponseElements(AnalysedQuery aQuery)
        {
            string topIntent = aQuery.topScoringIntent.intent;
    
            // Create a dictionary of entities associated with their type
            Dictionary<string, string> entityDic = new Dictionary<string, string>();
    
            foreach (EntityData ed in aQuery.entities)
            {
                entityDic.Add(ed.type, ed.entity);
            }
    
            // Depending on the topmost recognized intent, read the entities name
            switch (aQuery.topScoringIntent.intent)
            {
                case "ChangeObjectColor":
                    string targetForColor = null;
                    string color = null;
    
                    foreach (var pair in entityDic)
                    {
                        if (pair.Key == "target")
                        {
                            targetForColor = pair.Value;
                        }
                        else if (pair.Key == "color")
                        {
                            color = pair.Value;
                        }
                    }
    
                    Behaviours.instance.ChangeTargetColor(targetForColor, color);
                    break;
    
                case "ChangeObjectSize":
                    string targetForSize = null;
                    foreach (var pair in entityDic)
                    {
                        if (pair.Key == "target")
                        {
                            targetForSize = pair.Value;
                        }
                    }
    
                    if (entityDic.ContainsKey("upsize") == true)
                    {
                        Behaviours.instance.UpSizeTarget(targetForSize);
                    }
                    else if (entityDic.ContainsKey("downsize") == true)
                    {
                        Behaviours.instance.DownSizeTarget(targetForSize);
                    }
                    break;
            }
        }
    

    重要

    刪除 Start () Update () 方法,因為這個類別不會使用這些方法。

  12. 請務必先將變更儲存在 Visual Studio 中,再返回 Unity

注意

此時,您會注意到 Unity 編輯器控制台面板中出現數個錯誤。 這是因為程式代碼會參考您將在下一章中建立 的行為類別

第 7 章 – 建立行為類別

Actionss 類別會使用 LuisManager 類別所提供的實體來觸發動作。

若要建立此類別:

  1. 按兩下 [文稿 ] 資料夾,以開啟它。

  2. [腳本] 資料夾內按下滑鼠右鍵,按兩下 [ 建立 > C# 腳稿]。 將腳本命名為 行為

  3. 按兩下腳本以使用 Visual Studio加以開啟。

  4. 然後在 行為 類別內新增下列變數:

        public static Behaviours instance;
    
        // the following variables are references to possible targets
        public GameObject sphere;
        public GameObject cylinder;
        public GameObject cube;
        internal GameObject gazedTarget;
    
  5. 新增 Awake () 方法程序代碼。 當 類別初始化時,將會呼叫這個方法:

        void Awake()
        {
            // allows this class instance to behave like a singleton
            instance = this;
        }
    
  6. LuisManager 類別會呼叫下列方法, (您先前建立) 來判斷哪個對像是查詢的目標,然後觸發適當的動作。

        /// <summary>
        /// Changes the color of the target GameObject by providing the name of the object
        /// and the name of the color
        /// </summary>
        public void ChangeTargetColor(string targetName, string colorName)
        {
            GameObject foundTarget = FindTarget(targetName);
            if (foundTarget != null)
            {
                Debug.Log("Changing color " + colorName + " to target: " + foundTarget.name);
    
                switch (colorName)
                {
                    case "blue":
                        foundTarget.GetComponent<Renderer>().material.color = Color.blue;
                        break;
    
                    case "red":
                        foundTarget.GetComponent<Renderer>().material.color = Color.red;
                        break;
    
                    case "yellow":
                        foundTarget.GetComponent<Renderer>().material.color = Color.yellow;
                        break;
    
                    case "green":
                        foundTarget.GetComponent<Renderer>().material.color = Color.green;
                        break;
    
                    case "white":
                        foundTarget.GetComponent<Renderer>().material.color = Color.white;
                        break;
    
                    case "black":
                        foundTarget.GetComponent<Renderer>().material.color = Color.black;
                        break;
                }          
            }
        }
    
        /// <summary>
        /// Reduces the size of the target GameObject by providing its name
        /// </summary>
        public void DownSizeTarget(string targetName)
        {
            GameObject foundTarget = FindTarget(targetName);
            foundTarget.transform.localScale -= new Vector3(0.5F, 0.5F, 0.5F);
        }
    
        /// <summary>
        /// Increases the size of the target GameObject by providing its name
        /// </summary>
        public void UpSizeTarget(string targetName)
        {
            GameObject foundTarget = FindTarget(targetName);
            foundTarget.transform.localScale += new Vector3(0.5F, 0.5F, 0.5F);
        }
    
  7. 新增 FindTarget () 方法,以判斷哪一個 GameObjects 是目前 Intent 的目標。 如果實體中未定義明確的目標,這個方法會將目標預設為 「注視」的 GameObject

        /// <summary>
        /// Determines which object reference is the target GameObject by providing its name
        /// </summary>
        private GameObject FindTarget(string name)
        {
            GameObject targetAsGO = null;
    
            switch (name)
            {
                case "sphere":
                    targetAsGO = sphere;
                    break;
    
                case "cylinder":
                    targetAsGO = cylinder;
                    break;
    
                case "cube":
                    targetAsGO = cube;
                    break;
    
                case "this": // as an example of target words that the user may use when looking at an object
                case "it":  // as this is the default, these are not actually needed in this example
                case "that":
                default: // if the target name is none of those above, check if the user is looking at something
                    if (gazedTarget != null) 
                    {
                        targetAsGO = gazedTarget;
                    }
                    break;
            }
            return targetAsGO;
        }
    

    重要

    刪除 Start () Update () 方法,因為這個類別不會使用這些方法。

  8. 請務必先將變更儲存在 Visual Studio 中,再返回 Unity

第 8 章 – 建立注視類別

您需要完成此應用程式的最後一個類別是 Gaze 類別。 這個類別會更新目前在用戶視覺焦點中的 GameObject 參考。

若要建立此類別:

  1. 按兩下 [文稿 ] 資料夾,以開啟它。

  2. [腳本] 資料夾內按下滑鼠右鍵,按兩下 [ 建立 > C# 腳稿]。 將腳本命名為 Gaze

  3. 按兩下腳本以使用 Visual Studio加以開啟。

  4. 為此類別插入下列程式代碼:

        using UnityEngine;
    
        public class Gaze : MonoBehaviour
        {        
            internal GameObject gazedObject;
            public float gazeMaxDistance = 300;
    
            void Update()
            {
                // Uses a raycast from the Main Camera to determine which object is gazed upon.
                Vector3 fwd = gameObject.transform.TransformDirection(Vector3.forward);
                Ray ray = new Ray(Camera.main.transform.position, fwd);
                RaycastHit hit;
                Debug.DrawRay(Camera.main.transform.position, fwd);
    
                if (Physics.Raycast(ray, out hit, gazeMaxDistance) && hit.collider != null)
                {
                    if (gazedObject == null)
                    {
                        gazedObject = hit.transform.gameObject;
    
                        // Set the gazedTarget in the Behaviours class
                        Behaviours.instance.gazedTarget = gazedObject;
                    }
                }
                else
                {
                    ResetGaze();
                }         
            }
    
            // Turn the gaze off, reset the gazeObject in the Behaviours class.
            public void ResetGaze()
            {
                if (gazedObject != null)
                {
                    Behaviours.instance.gazedTarget = null;
                    gazedObject = null;
                }
            }
        }
    
  5. 請務必先將變更儲存在 Visual Studio 中,再返回 Unity

第 9 章 – 完成場景設定

  1. 若要完成場景的設定,請將您建立的每個腳本從 [腳本資料夾] 拖曳到 [階層面板] 中的 [主要相機] 物件。

  2. 選取 主要相機 並查看 偵測器面板,您應該可以看到您已附加的每個腳本,而且您會注意到每個尚未設定的腳本上有參數。

    設定相機參考目標。

  3. 若要正確設定這些參數,請遵循下列指示:

    1. MicrophoneManager

      • 從 [ 階層面板] 中,將 [聽寫文字 ] 物件拖曳到 [聽寫文字 ] 參數值方塊中。
    2. 來自階層面板的行為

      • Sphere 物件拖曳到 [Sphere 參考目標] 方塊中。
      • [圓柱圖 ] 拖曳到 [ 圓柱 參考目標] 方塊中。
      • Cube 拖曳到 [Cube 參考目標] 方塊中。
    3. 注視

      • 如果注視距離上限尚未) ,請將 [注視距離上限 ] 設定為 300 (。
  4. 結果看起來應該像下圖:

    顯示相機參考目標,現在已設定。

第 10 章 – 在 Unity 編輯器中測試

測試場景設定是否已正確實作。

請確定:

  • 所有腳本都會附加至 Main Camera 物件。
  • 主要相機偵測器面板中的所有欄位都會正確指派。
  1. Unity 編輯器中按 [播放] 按鈕。 應用程式應該在附加沉浸式頭戴式裝置內執行。

  2. 請嘗試幾個語句,例如:

    make the cylinder red
    
    change the cube to yellow
    
    I want the sphere blue
    
    make this to green
    
    change it to white
    

    注意

    如果您在 Unity 控制台中看到有關預設音訊裝置變更的錯誤,場景可能無法如預期般運作。 這是因為混合實境入口網站處理內建麥克風的方式,適用於具有它們的頭戴式裝置。 如果您看到此錯誤,只要停止場景並再次啟動它,而且應該如預期般運作。

第 11 章 – 建置和側載 UWP 解決方案

確定應用程式在 Unity 編輯器中運作之後,您就可以開始建置和部署。

若要建置:

  1. 按兩下 [ 檔案 > 儲存] 以儲存目前的場景。

  2. 移至 [檔案 > 建置設定]。

  3. 勾選名為 Unity C# 專案的 方塊 (在建立 UWP 專案後查看和偵錯程式代碼很有用。

  4. 按兩下 [ 新增開啟場景],然後按兩下 [ 建置]。

    [建置設定] 視窗

  5. 系統會提示您選取您要建置解決方案的資料夾。

  6. 建立 BUILDS 資料夾,並在該資料夾中建立另一個具有所選適當名稱的資料夾。

  7. 按兩下 [選取資料夾 ] 開始在該位置建置。

    建立組建資料夾選取組建資料夾

  8. 一旦 Unity 完成建置 (可能需要一些時間) ,它應該會在組建的位置開啟 檔案總管 視窗。

若要在本機電腦上部署:

  1. Visual Studio 中,開啟上 一章中建立的方案檔案。

  2. [解決方案平臺] 中,選取 [x86]、[ 本機計算機]。

  3. 在 [ 方案組態 ] 中,選取 [ 偵錯]。

    針對 Microsoft HoloLens,您可能會發現將它設定為遠端電腦更容易,因此您不會連線到您的電腦。 不過,您也必須執行下列動作:

    • 瞭解 HoloLens 的 IP 位址 ,您可以在 [ 設定 > 網络] & [因特網 > ] Wi-Fi > [進階選項] 中找到;IPv4 是您應該使用的位址。
    • 確定開發人員模式開啟;在 [設定更新] & 開發人員的安全性>中找到>

    部署應用程式

  4. 移至 [ 建置] 功能表 ,然後按下 [ 部署方案 ] 以側載應用程式到您的電腦。

  5. 您的應用程式現在應該會出現在已安裝的應用程式清單中,準備好啟動!

  6. 啟動之後,應用程式會提示您授權 存取麥克風。 使用 動作控制器語音輸入,或 鍵盤[是 ] 按鈕。

第 12 章 – 改善 LUIS 服務

重要

本章非常重要,可能需要多次逐一查看,因為它有助於改善 LUIS 服務的精確度:請確定您完成這項作業。

若要改善 LUIS 所提供的了解層級,您需要擷取新的語句,並使用它們來重新定型 LUIS 應用程式。

例如,您可能已將 LUIS 定型為瞭解「增加」和「Upsize」,但不想讓應用程式也瞭解「放大」之類的字?

一旦您多次使用應用程式,您說的所有項目都會由 LUIS 收集,並在 LUIS 入口網站中提供。

  1. 請移至遵循此 LINK 的入口網站應用程式,然後登入。

  2. 使用 MS 認證登入之後,請按下您的應用程式 名稱

  3. 按兩下頁面左側的 [ 檢閱端點語句 ] 按鈕。

    檢閱語句

  4. 您會看到混合實境應用程式已傳送至 LUIS 的語句清單。

    語句清單

您會注意到一些醒目提示的 實體

藉由將滑鼠停留在每個醒目提示的單字上,您可以檢閱每個語句,並判斷哪些實體已正確辨識、哪些實體錯誤,以及遺漏哪些實體。

在上述範例中,發現「spear」 一詞已醒目提示為目標,因此必須更正錯誤,方法是將滑鼠停留在文字上並按兩下 [ 移除卷標]。

檢查語句移除標籤影像

  1. 如果您發現語句完全錯誤,您可以使用畫面右側的 [ 刪除 ] 按鈕加以刪除。

    刪除錯誤的語句

  2. 或者,如果您認為 LUIS 已正確解譯語句,您可以使用 [ 新增至對齊意圖 ] 按鈕來驗證其瞭解。

    新增至對齊的意圖

  3. 排序所有顯示的語句之後,請嘗試重載頁面以查看是否有更多可用。

  4. 請務必盡可能重複此程式多次,以改善您的應用程式瞭解。

祝您順利!

您已完成的 LUIS 整合式應用程式

恭喜,您已建置混合實境應用程式,利用 Azure Language Understanding Intelligence Service 來了解使用者所說的內容,並處理該資訊。

實驗室結果

額外練習

練習 1

使用此應用程式時,您可能會注意到,如果您注視 Floor 物件並要求變更其色彩,它將會這麼做。 您可以瞭解如何阻止應用程式變更 Floor 色彩?

練習 2

嘗試擴充 LUIS 和應用程式功能,為場景中的物件新增其他功能;例如,視使用者說出的內容而定,在注視點擊點建立新的物件,然後能夠搭配現有的命令使用這些物件與目前的場景物件。