Azure AI 服務之語音識別


筆者在前文《Azure AI 服務之文本翻譯》中簡單介紹了 Azure 認知服務中的文本翻譯 API,通過這些簡單的 REST API 調用就可以輕松地進行機器翻譯。如果能在程序中簡單的集成語音轉文本的功能會不會非常贊!本文我們就介紹如何使用必應的語音識別 API(Bing Speech API) 把語音轉換成文本:

使用 Bing Speech API 可以輕松地開發出下面的應用:

你點擊 "開始錄音" 按鈕,然后對着麥克風說話,就能夠識別輸出你說的內容並輸出成文本。上面的截圖是 Azure 官方提供的 demo,為了演示語音識別 API 的用法,我們寫一個丑點的,但是可以輸出詳細信息的程序:

該程序會以不同的模式識別我們 hardcode 的兩段音頻數據,然后輸出識別的結果。其中上面的文本框會輸出大量的中間識別結果,而下面的文本框則輸出最終的識別結果。

創建 Azure 服務

要使用 Azure 的翻譯服務需要先在 Azure 上創建對應的實例,比如我們需要先創建一個 "Bing Speech API" 服務實例:

說明:對於學習和練習來說,你可以創建免費的 Azure 賬號並創建免費版的上述實例,詳細信息請參考 Azure 官網。

創建 WPF 程序

Bing Speech API 服務同時提供了 REST API 和客戶端類庫,因為 REST API 提供的服務會有一些限制,所以我們在演示程序中使用客戶端類庫。客戶端類庫分為 x86 和 x64 兩個版本,筆者引用的是 x64 的版本 Microsoft.ProjectOxford.SpeechRecognition-x64:

因而需要把工程的 platform target 也設置為 x64。

需要注意的是,Azure 提供的認知服務 API 都是需要認證信息的。具體的方式就是把我們創建的服務的 key 隨 API 發送的服務器端進行認證。你可以在創建的服務實例的詳情界面獲得對應的 key,我們在程序中通過定義的常量來保存它們:

const string SUBSCRIPTIONKEY = "your bing speech API key";

由於 demo 的代碼比較長,為了能集中精力介紹 Azure AI 相關的內容,本文中只貼出相關的代碼。完整的 demo 代碼在這里

識別模式

語音識別區分不同的識別模式來應對不同的使用場景,如對話模式、聽寫模式和交互式模式。

  • 對話模式(conversation) 在對話模式中,使用者參與的是人與人之間的對話。
  • 聽寫模式(dictation) 在聽寫模式中,使用者說出一段較長的語音然后等待語音識別的結果。
  • 交互式模式(interactive) 在交互模式中, 使用者發出簡短的請求, 並期望應用程序執行響應操作。

遺憾的是在我們使用的客戶端類庫中,相關的模式類型並不是與上面的三種模式一一對應,類庫中提供一個叫 SpeechRecognitionMode 的枚舉:

public enum SpeechRecognitionMode
{
    ShortPhrase = 0,
    LongDictation = 1
}

它定義了 ShortPhraseLongDictation 兩種識別模式。ShortPhrase 模式最長支持 15 秒的語音。語音數據被分塊發送到服務端,服務端會及時的返回部分的識別結果,所以客戶端會收到多個部分結果和一個包含多個 n-best 選項的最終結果。LongDictation 模式支持最長兩分鍾的語音。語音數據被分塊發送到服務器,根據服務端分辨出的語句間的停頓,客戶端會受到多個部分結果和多個最終結果。

代碼中我們要通過它們來告訴語音識別 API 執行識別的類型。比如要識別比 15s 短的語音,可以使用 ShortPhrase 模式構建 CreateDataClient 類型的實例:

// 使用工廠類型的 CreateDataClient 方法創建 DataRecognitionClient 類型的實例。
this.dataClient = SpeechRecognitionServiceFactory.CreateDataClient(
    SpeechRecognitionMode.ShortPhrase ,             // 指定語音識別的模式。
    "en-US",          // 我們把語音中語言的類型 hardcode 為英語,因為我們的兩個 demo 文件都是英語語音。
    SUBSCRIPTIONKEY); // Bing Speech API 服務實例的 key。

如果要識別長於 15s 的語音,就需要使用 SpeechRecognitionMode.LongDictation 模式。

分塊傳輸音頻

為了能得到近乎實時的識別效果,我們必須把音頻數據以適當大小的塊連續發送給服務端,下面代碼中使用的塊大小為 1024:

/// <summary>
/// 向服務端發送語音數據。
/// </summary>
/// <param name="wavFileName">wav 格式文件的名稱。</param>
private void SendAudioHelper(string wavFileName)
{
    using (FileStream fileStream = new FileStream(wavFileName, FileMode.Open, FileAccess.Read))
    {
        // Note for wave files, we can just send data from the file right to the server.
        // In the case you are not an audio file in wave format, and instead you have just
        // raw data (for example audio coming over bluetooth), then before sending up any
        // audio data, you must first send up an SpeechAudioFormat descriptor to describe
        // the layout and format of your raw audio data via DataRecognitionClient's sendAudioFormat() method.
        int bytesRead = 0;
        // 創建大小為 1024 的 buffer。
        byte[] buffer = new byte[1024];

        try
        {
            do
            {
                // 把文件數據讀取到 buffer 中。
                bytesRead = fileStream.Read(buffer, 0, buffer.Length);

                // 通過 DataRecognitionClient 類型的實例把語音數據發送到服務端。
                this.dataClient.SendAudio(buffer, bytesRead);
            }
            while (bytesRead > 0);
        }
        finally
        {
            // 告訴服務端語音數據已經傳送完了。
            this.dataClient.EndAudio();
        }
    }
}

注意,在數據傳送結束后需要通過 EndAudio() 方法顯式的告訴服務端數據傳送結束。

部分結果與最終結果

部分結果
把數據分塊發送給語音識別服務端,我們就能得到近乎實時的識別效果。服務器端通過 OnPartialResponseReceived 事件不斷把識別的結果發送到客戶端。比如 demo 中演示的 ShortPhrase 模式實例,我們會得到下面的中間結果(在上面的輸出框中):

--- Partial result received by OnPartialResponseReceivedHandler() ---
why

--- Partial result received by OnPartialResponseReceivedHandler() ---
what's

--- Partial result received by OnPartialResponseReceivedHandler() ---
what's the weather

--- Partial result received by OnPartialResponseReceivedHandler() ---
what's the weather like

在識別的過程中 OnPartialResponseReceived 事件被觸發了 4 次,識別的結果也越來越完整。如果應用程序能夠根據這些中間結果不斷地向使用者做出反饋,則應用程序就具備了實時性。

最終結果
當使用者結束語音的輸入后,demo 中就是調用了 EndAudio() 函數。語音識別服務在完成識別后會觸發 OnResponseReceived 事件,我們通過下面的函數把結果輸出到 UI 中:

/// <summary>
/// 把服務端返回的語音識別結果輸出到 UI。
/// </summary>
/// <param name="e"><see cref="SpeechResponseEventArgs"/>該類型的實例包含語音識別的結果。</param>
private void WriteResponseResult(SpeechResponseEventArgs e)
{
    if (e.PhraseResponse.Results.Length == 0)
    {
        this.WriteLine("No phrase response is available.");
    }
    else
    {
        this.WriteLine("********* Final n-BEST Results *********");
        for (int i = 0; i < e.PhraseResponse.Results.Length; i++)
        {
            this.WriteLine(
                "[{0}] Confidence={1}, Text=\"{2}\"",
                i,
                e.PhraseResponse.Results[i].Confidence,
                e.PhraseResponse.Results[i].DisplayText);
        }
        this.WriteLine();
    }
}

數據的結果大體如下:

--- OnDataShortPhraseResponseReceivedHandler ---
********* Final n-BEST Results *********
[0] Confidence=High, Text="What's the weather like?"

上面是 ShortPhrase 模式的一個識別結果,它的特點是只有一個最終的返回結果,其中會包含多個識別結果並被稱為 n-best。n-best 中的每個結果都包含 Confidence,DisplayText,InverseTextNormalizationResult,LexicalForm,MaskedInverseTextNormalizationResult 等屬性,比如我們可以根據 Confidence 屬性判斷識別的結果是否可靠:

上圖是實際的返回結果,因為太簡單了,所以 n-best 列表中只有一條(Azure 上的語言材料,發音還是很標准的)。

對於 LongDictation 模式的識別,客戶端事件 OnResponseReceived  會被觸發多次,並返回分階段的識別結果,結果中的內容和 ShortPhrase 模式類似。更詳細的內容請大家直接看代碼吧,很簡單的。

支持語言

筆者圖省事直接使用了 Azure 文檔中提供的英語語音作為 demo 數據,其實 Bing Speech API 對中文支持還是比較全面的,現在支持的所有模式都支持中文。如果你還有其它需求,可以從這里查看詳細的語言支持列表。

總結

筆者最早接觸語音識別是在 2000 年左右,當時感覺太神奇了。只是識別的效果不太好,並且要求反復的讀一個基准文檔…
這么多年過去了,其實語言相關的技術發展並不算很快。 AI 的興起讓我們看到了一線希望,在介紹了 Azure AI 的語音識別服務后,讓我們接着探索如何通過 AI 讓程序理解文本的內容。

參考:
Bing Speech Recognition API in C# for .NET


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM