體驗 Microsoft Azure 語音服務(C#)

馮三益 2019/11/04 10:22:19
60

一、 什麼是語音辨識:

                            語音辨識speech recognition) 技術,也被稱為自動語音辨識、

       電腦語音識別或是語音轉文字識別,

       其目標是以電腦自動將人類的語音內容轉換為相應的文字。

二、 Microsoft Azure 語音服務:

       語音服務會將語音轉文字、文字轉語音及語音翻譯,

       整合至單一 Azure 訂用帳戶。

       藉由語音 SDK、語音裝置 SDK REST API

       可輕易地透過語音來啟用您的應用程式、工具和裝置。

三、 使用語音服務前準備(.Net Core):

       1. .NET Core SDK

       2. Visual Studio 2017 或更新版本

       3. 語音服務的 Azure 訂用帳戶金鑰

四、 使用語音服務(.Net Core 主控台應用程式):

       1. 取得 Azure 訂用帳戶金鑰

          參考 免費試用語音服務 取得帳戶金鑰

       2. 啟動 Visual Studio 並建立 主控台應用程式 專案,並修改名稱為

          SpeechRecognitionSample

       

       3. 在方案 SpeechRecognitionSample 點選滑鼠右鍵,

          點選 [加入] -> 新增專案

       

       建立類別庫專案(.NET Core),名稱叫做 Interfaces ,點選確定

            

      在專案Interfaces點選滑鼠右鍵,點選滑鼠右鍵,點選 [加入] -> 新增資料夾

              

       修改 資料夾名稱為 BusinessModels

       建立 RecognizeBM類別,設定屬性

using System;
using System.Collections.Generic;
using System.Text;

namespace Interfaces
{
    /// <summary>
    /// 語音辨識基本設定用 BM
    /// </summary>
    public class RecognizeBM
    {
        /// <summary>
        /// 訂用帳戶金鑰
        /// </summary>
        public string Subkey { get; set; }

        /// <summary>
        /// 訂用帳戶服務的所在區域
        /// </summary>
        public string Region { get; set; }

        /// <summary>
        /// 要辨識的語言
        /// </summary>
        public string Language { get; set; }

        /// <summary>
        /// 輸入的文字
        /// </summary>
        public string Text { get; set; }
    }
}

       修改預設的class.cs檔案為介面檔,名稱為ISpeechService,並建立方法

using Interfaces;
using System;
using System.Threading.Tasks;

namespace Interfaces
{
    /// <summary>
    /// 語音辨識用介面
    /// </summary>
    public interface ISpeechService
    {
        /// <summary>
        /// 辨識輸入語音為文字
        /// </summary>
        /// <param name="configBM">語音辨識基本設定用</param>
        /// <returns>辨識後的文字</returns>
        Task<string> SpeakToText(RecognizeBM configBM);

        /// <summary>
        /// 辨識輸入文字為語音
        /// </summary>
        /// <param name="textToSpeakBM">輸入文字為語音用</param>
        /// <returns></returns>
        Task TextToSpeak(RecognizeBM recognizeBM);
    }
}

   4.在方案 SpeechRecognitionSample點選滑鼠右鍵,點選 [加入] -> 新增專案

   

   建立類別庫專案(.NET Core),名稱叫做 Services,點選確定 

     

   在專案Services點選滑鼠右鍵,點選 [管理NuGet套件]

接著瀏灠,輸入組件名稱[Microsoft.CognitiveServices.Speech]

再點按組件[Microsoft.CognitiveServices.Speech]

右方的下箭頭鈕(安裝Microsoft.CognitiveServices.Speech v1.7.0)

修改預設的class.cs檔案名稱為SpeechService

繼承 ISpeechService,並實作方法

using Interfaces;
using Microsoft.CognitiveServices.Speech;
using System;
using System.Threading.Tasks;

namespace Services
{
    // 語音服務的語言,語音名稱設定等可參考
    // https://github.com/MicrosoftDocs/azure-docs.zh-tw/blob/master/articles/cognitive-services/Speech-Service/language-support.md#text-to-speech 

    /// <summary>
    /// 語音辨識
    /// </summary>
    public class SpeechService : ISpeechService
    {
        private string recognizeText = string.Empty;

        /// <summary>
        /// 辨識輸入語音為文字
        /// </summary>
        /// <param name="recognizeBM">語音辨識基本設定用</param>
        /// <returns>辨識後的文字</returns>
        public async Task<string> SpeakToText(RecognizeBM recognizeBM)
        {
            // 設定語音服務設定
            var config = this.GetSpeechConfig(recognizeBM);

            // 建立語音辨識器類別
            using (var recognizer = new SpeechRecognizer(config))
            {
                // RecognizeOnceAsync 此方法 僅適用於單個語音識別,如命令或查詢,輸入時間小於 15 秒
                // 如果需要長時間運行的多話語識別,請改用 StartContinuousRecognitionAsync(), 
                // 輸入時間大於 15 秒
                var result = await recognizer.RecognizeOnceAsync();
                
                // 判斷回傳執行結果狀態
                this.CheckReason(result);

                return recognizeText;
            }
        }

        /// <summary>
        /// 辨識輸入文字為語音
        /// </summary>
        /// <param name="textToSpeakBM">輸入文字為語音用</param>
        /// <returns></returns>
        public async Task TextToSpeak(RecognizeBM recognizeBM)
        {
            // 設定語音服務設定
            var config = this.GetSpeechConfig(recognizeBM);

            // 建立語音合成器類別
            using (var synthesizer = new SpeechSynthesizer(config))
            {
                Console.WriteLine("處理中...");

                // 判斷輸入是否為空白
                if (string.IsNullOrEmpty(recognizeBM.Text.Trim()))
                    recognizeBM.Text = "無法辨識輸入,請重新輸入\n";

                // 將文字合成為語音
                using (var result = await synthesizer.SpeakTextAsync(recognizeBM.Text))
                {
                    // 判斷回傳執行結果狀態
                    this.CheckReason(result);

                    Console.WriteLine($"系統辨識為: {recognizeBM.Text}\n");
                }
            }
        }

        /// <summary>
        /// 設定語音服務設定
        /// </summary>
        /// <param name="recognizeBM"></param>
        /// <returns></returns>
        private SpeechConfig GetSpeechConfig(RecognizeBM recognizeBM)
        {
            // 設定 訂用帳戶金鑰 與 訂用帳戶服務的所在區域
            // 免費試用的服務所在區域都是 westus
            var speechConfig =
                SpeechConfig.FromSubscription(recognizeBM.Subkey, recognizeBM.Region);

            // 要辨識的語言
            speechConfig.SpeechRecognitionLanguage = recognizeBM.Language;

            // 設定語音名稱
            speechConfig = this.SetVoiceName(recognizeBM.Language, speechConfig);

            return speechConfig;
        }

        /// <summary>
        /// 設定語音名稱
        /// </summary>
        /// <param name="language">要辨識的語言</param>
        /// <param name="speechConfig">語音服務設定</param>
        /// <returns></returns>
        private SpeechConfig SetVoiceName(string language, SpeechConfig speechConfig)
        {
            // 根據要辨識的語言設定對應的語音名稱
            // 中文 zh-TW-Yating-Apollo、zh-TW-HanHanRUS、zh-TW-Zhiwei-Apollo
            if (language == "zh-TW")
                speechConfig.SpeechSynthesisVoiceName = "zh-TW-Yating-Apollo";

            return speechConfig;
        }

        /// <summary>
        /// 判斷回傳執行結果狀態
        /// </summary>
        /// <param name="result"></param>
        /// <returns></returns>
        private bool CheckReason(dynamic result)
        {
            // 發生錯誤
            if (result.Reason == ResultReason.Canceled)
            {
                var typeName = result.GetType().Name;

                // 發生錯誤,提示訊息
                if (typeName == "RecognitionResult")
                    this.DisPlayMessage(CancellationDetails.FromResult(result));

                if (typeName == "SpeechSynthesisResult")
                    this.DisPlayMessage(SpeechSynthesisCancellationDetails.FromResult(result));
            }

            // 如果 執行結果為 語音轉文字類型
            // 設定 辨識後的文字
            if (result as RecognitionResult != null)
                recognizeText = result.Text;

            // 無法辨識輸入結果
            if (result.Reason == ResultReason.NoMatch)
            {
                recognizeText = $"無法辨識輸入語音,請重新輸入\n";
            }

            return true;
        }

        /// <summary>
        /// 發生錯誤,提示訊息
        /// </summary>
        /// <param name="cancellation"></param>
        private void DisPlayMessage(dynamic cancellation)
        {
            Console.WriteLine($"CANCELED: Reason={cancellation.Reason}");

            if (cancellation.Reason == CancellationReason.Error)
            {
                Console.WriteLine($"CANCELED: ErrorCode={cancellation.ErrorCode}");
                Console.WriteLine($"CANCELED: ErrorDetails={cancellation.ErrorDetails}");
                Console.WriteLine($"CANCELED: Did you update the subscription info?");
            }

            throw new Exception("發生系統錯誤,請重新執行");
        }
    }
}

       5. 修改 Program.cs 內容

          1.修改專案的 SpeechRecognitionSample.csproj 檔

            以文字檔開啟後 修改 <PropertyGroup></PropertyGroup> 內容

            

            加入 <LangVersion>7.1</LangVersion> 設定使用語言版本

            

          2.修改 static void Main(string[] args) 方法 為

            static async Task Main(string[] args),

            程式碼如下:

using Interfaces;
using Services;
using System;
using System.Threading.Tasks;

namespace SpeechRecognitionSample
{
    class Program
    {
        static ISpeechService speechService;

        static async Task Main(string[] args)
        {
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("模式切換方式如下:");
            Console.WriteLine("語音輸入模式下,說出 手動輸入 或 切換,即切換為手動輸入模式");
            Console.WriteLine("手動輸入模式下,輸入 語音輸入 或 切換,即切換為語音輸入模式");
            Console.WriteLine("任一模式下,輸入 關閉 或 結束,即結束應用程式");
            Console.ForegroundColor = ConsoleColor.White;

            // 實體化 語音辨識 服務
            speechService = new SpeechService();

            // 實體化 語音辨識基本設定用 BM
            var recognizeBM = new RecognizeBM();

            // 要辨識的語言
            recognizeBM.Language = "zh-TW";

            Console.WriteLine("輸入帳戶金鑰:");

            // 取得金鑰
            recognizeBM.Subkey = Console.ReadLine();

            // 取得服務端點位置,免費試用帳戶都為 westus
            recognizeBM.Region = "westus";

            // 預設程式啟動提示訊息
            recognizeBM.Text = "語音服務啟動";

            try
            {
                // 執行文字轉語音
                await speechService.TextToSpeak(recognizeBM);

                // 用來切換模式的 flag
                var isTextMode = false;

                while (true)
                {
                    if (isTextMode)
                    {
                        Console.WriteLine("手動輸入:");

                        // 取得輸入文字
                        recognizeBM.Text = Console.ReadLine();

                        // 執行文字轉語音
                        isTextMode = await StartTextToSpeak(recognizeBM, "語音輸入", isTextMode);
                    }
                    else
                    {
                        Console.WriteLine("語音輸入:");

                        // 取得輸入文字
                        recognizeBM.Text = await speechService.SpeakToText(recognizeBM);

                        // 執行文字轉語音
                        isTextMode = await StartTextToSpeak(recognizeBM, "手動輸入", isTextMode);
                    }
                }
            }
            catch
            {
                Console.WriteLine("應用程式執行失敗,請重新執行");
                Console.ReadLine();
            }
        }

        /// <summary>
        /// 執行文字轉語音
        /// </summary>
        /// <param name="recognizeBM">語音辨識設定</param>
        /// <param name="keyWord">切換 手動/語音模式 關鍵字</param>
        /// <param name="modeStatus">模式狀態</param>
        /// <returns></returns>
        private async static Task<bool> StartTextToSpeak(
            RecognizeBM recognizeBM, string keyWord, bool modeStatus)
        {
            // 輸入關閉或結束,結束應用程式
            if (recognizeBM.Text.Contains("關閉") || recognizeBM.Text.Contains("結束"))
            {
                Console.WriteLine("應用程式結束,請輸入任意鍵繼續...");
                Console.ReadLine();
                Environment.Exit(0);
            }
                
            // 執行文字轉語音
            await speechService.TextToSpeak(recognizeBM);

            if (recognizeBM.Text.Contains(keyWord) || recognizeBM.Text == "切換")
                return !modeStatus;

            return modeStatus;
        }
    }
}

       6.按 F5 啟動專案進行測試,執行結果如下,

         可以發現成功的將 文字轉換成語音輸出,及輸入的語音轉換成文字

       

五、結語:

       這篇介紹了如何簡單的運用 Microsoft Azure 語音服務

       來實現語音操作應用程式的方法,

       Microsoft Azure 還有提供許多的認知服務

       有興趣的人可以再自行研究學習。

六、參考資料:

       Microsoft Azure 語音服務文件

       語音服務的語言和區域支援

 

       

 

 

馮三益