2016-10-09 60 views
-1

首先讓我解釋我的目標。我正在努力的目標是提供一個輸入.wav文件,將其發送到某種語音識別API中,並返回一個帶有轉錄的文本文件。我想到的應用程序非常簡單。我不要求它被解析爲語法或標點符號。它可以返回一個很大很長的句子 - 這很好。我會將每個轉錄詞作爲文本文件(.tsv或.csv格式)中的觀察值對待使用SAPI或同等功能的音頻文件到文本SR

但是,不要向用戶提供這種數據),我需要的是每個單詞的[0.00 - 1.00]置信度分數,SR對其進行猜測。我想將這些數據存儲在包含以.tsv或.csv格式轉錄的文本的文本文件的新列中。

就是這樣。這是我的目標。看來我的目標是可能的:這裏是從專家報價在相關的帖子:

Convert Audio(Wav file) to Text using SAPI?

SAPI當然可以做你想做的。從一個進程內識別器開始, 將音頻作爲文件流連接起來,設置聽寫模式,然後關閉 。

這裏是.WAV轉錄信心分數的相關文件:

https://msdn.microsoft.com/en-us/library/jj127911.aspx

https://msdn.microsoft.com/en-us/library/microsoft.speech.recognition.recognizedwordunit.confidence(v=office.14).aspx

大家都使得它聽起來很簡單,但現在讓我來解釋這個問題;爲什麼我發佈一個問題。問題在於,對我而言,我的目標遙不可及,因爲我幾乎不知道C++或COM。我認爲SAPI是日常的Windows體驗的一部分,並有一個專門的,友好的用戶界面。所以我越來越驚訝,我越研究這個程序。但我仍然相信原則上這是一件非常簡單的事情,所以我很樂觀。

我有Python和一點JS的知識。我知道Python對其他語言具有代碼魔法,所以我確信Python可以通過這種方式與SAPI進行交互,但由於我不知道C++,因此我認爲這不會讓我變得更好。

所以,爲了重申一下,儘管技能不匹配,我仍然偏愛SAPI,因爲所有用戶友好的替代品,如Dragon,Nuance,Chrome插件等都不提供我需要的數據粒度。

現在讓我去我的問題的心臟:

  1. 能有人給我自己的評價對我的「目標」難度如上所述?它可以在一個單一的.bat文件中完成嗎?示例代碼將不勝感激。
+0

這是一個相當開放的問題,我會很高興有任何輸入,無論大小。請記住,我不是世界上最熟練的程序員。所以我可能無法掌握所有這些領域特定的術語,但我正在盡我所能。 –

回答

2

這可能不言而喻,但我認爲如果你沒有強大的C語言處理能力,你會發現很難與SAPI的C接口一起工作。我編寫了一個程序,幾乎完全符合您前段時間討論的測試概念。首先代碼轉儲:

#include "dirent.h" 
#include <iostream> 
#include <string> 
#include <sapi.h> 
#include <sphelper.h> 

int main(int argc, char* argv[]){ 

    DIR *dir; 
    struct dirent* entry; 
    struct stat* statbuf; 
    ::CoInitialize(NULL); 
    if((dir = opendir(".")) != NULL){ 
     while((entry = readdir(dir)) != NULL){ 
      char extCheck[260]; 
      strcpy(extCheck, entry->d_name); 
      if(strlen(extCheck) > 4 && !strcmp(strlwr(extCheck) + strlen(extCheck)-4, ".wav")){ 
       //printf("%s\n",entry->d_name); 
       //1. Find the wav files 
       //2. Check the wavs to make sure they're the correct format 
       //3. Output any errors to the error log 
       //4. Produce the text files for the wavs 
       //5. Cleanup and exit 
       FILE* fp; 
       std::string fileName = std::string(entry->d_name,entry->d_name + strlen(entry->d_name)-4); 
       fileName += ".txt"; 
       fp = fopen(fileName.c_str(), "w+"); 
       HRESULT hr = S_OK; 
       CComPtr<ISpStream> cpInputStream; 
       CComPtr<ISpRecognizer> cpRecognizer; 
       CComPtr<ISpRecoContext> cpRecoContext; 
       CComPtr<ISpRecoGrammar> cpRecoGrammar; 
       CSpStreamFormat sInputFormat; 
       hr = cpRecognizer.CoCreateInstance(CLSID_SpInprocRecognizer); 
       hr = cpInputStream.CoCreateInstance(CLSID_SpStream); 
       hr = sInputFormat.AssignFormat(SPSF_16kHz16BitStereo); 
       std::string sInputFileName = entry->d_name; 
       std::wstring wInputFileName = std::wstring(sInputFileName.begin(), sInputFileName.end()); 
       hr = cpInputStream->BindToFile(wInputFileName.c_str(), SPFM_OPEN_READONLY, &sInputFormat.FormatId(), sInputFormat.WaveFormatExPtr(), SPFEI_ALL_EVENTS); 
       hr = cpRecognizer->SetInput(cpInputStream, TRUE); 
       hr = cpRecognizer->CreateRecoContext(&cpRecoContext); 
       hr = cpRecoContext->CreateGrammar(NULL, &cpRecoGrammar); 
       hr = cpRecoGrammar->LoadDictation(NULL,SPLO_STATIC); 

       hr = cpRecoContext->SetNotifyWin32Event(); 
       auto hEvent = cpRecoContext->GetNotifyEventHandle(); 
       hr = cpRecoContext->SetInterest(SPFEI(SPEI_RECOGNITION) | SPFEI(SPEI_END_SR_STREAM), SPFEI(SPEI_RECOGNITION) | SPFEI(SPEI_END_SR_STREAM)); 
       hr = cpRecoGrammar->SetDictationState(SPRS_ACTIVE); 
       BOOL fEndStreamReached = FALSE; 
       unsigned int timeOut = 0; 
       //WaitForSingleObject(hEvent, INFINITE); 
       while (!fEndStreamReached && S_OK == cpRecoContext->WaitForNotifyEvent(INFINITE)){ 
        CSpEvent spEvent; 

        while (!fEndStreamReached && S_OK == spEvent.GetFrom(cpRecoContext)){ 

         switch (spEvent.eEventId){ 

          case SPEI_RECOGNITION: 
           { 
            auto pPhrase = spEvent.RecoResult(); 
            SPPHRASE *phrase = nullptr;// new SPPHRASE(); 
            LPWSTR* text = new LPWSTR(L""); 
            pPhrase->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, TRUE, text, NULL); 
            pPhrase->GetPhrase(&phrase); 

            if(phrase != NULL && phrase->pElements != NULL) { 
             std::wstring wRuleName = L""; 

             if(nullptr != phrase && phrase->Rule.pszName != NULL) { 
              wRuleName = phrase->Rule.pszName; 
             } 

             std::wstring recognizedText = L""; 
             bool firstWord = true; 
             for(ULONG i = 0; i < (ULONG)phrase->Rule.ulCountOfElements; ++i) { 

              if(phrase->pElements[i].pszDisplayText != NULL) { 

               std::wstring outString = phrase->pElements[i].pszDisplayText; 
               std::string soutString = std::string(outString.begin(), outString.end()); 
               if(!firstWord){ 
                soutString = " " + soutString; 
                firstWord = false; 
               } 
               soutString = soutString + " "; 
               fputs(soutString.c_str(),fp); 
               /*if(recognizedText != L"") { 
                recognizedText += L" " + outString; 
               } else { 
                recognizedText += outString; 
               }*/ 
              } 
             } 

            } 
            delete[] text; 

            break; 
           } 

          case SPEI_END_SR_STREAM: 
           { 
            fEndStreamReached = TRUE; 
            break; 
           } 

         } 

         // clear any event data/object references 
         spEvent.Clear(); 
        } 
       } 

       hr = cpRecoGrammar->SetDictationState(SPRS_INACTIVE); 
       hr = cpRecoGrammar->UnloadDictation(); 
       hr = cpInputStream->Close(); 

       fclose(fp); 
      } 
     } 
     closedir(dir); 
    } else { 
     perror("Error opening directory"); 
    } 

    ::CoUninitialize(); 

    std::printf("Press any key to continue..."); 
    std::getchar(); 
    return 0; 
} 

我沒有在很長一段時間運行它,但你必須爲它工作得到dirent.h。除了試用外,我沒有其他理由玩這個圖書館。

使用提供的代碼,您可能會開始考慮在識別步驟中生成的置信度值。如果你願意,你也可以調整這個從批處理文件運行。

,我所面臨的問題有以下幾條:

  1. 精度是一個問題,爲了提高它,我必須培養識別器,這是將需要比我有更多的時間。
  2. 我發現,直接翻譯成文本並不是我真正想要的。事實證明,音素數據比較重要。有了這個,你可以形成你自己的信心計劃,並開發你自己的替代具體到你的應用程序。
  3. 窗口識別器雖然好,但不會識別它不知道的單詞。你必須弄清楚如何將你的詞彙添加到Windows的語音識別器詞典中。

這樣說,使用股票窗口桌面語音識別器不是一件小事。我會看看現有的一些API。如果您不僅僅限於客戶端應用程序,您最好查看其他API。

+0

您的所有觀點都很好。感謝您展示SAPI的能力以及它的侷限性。這正是我評估SR項目未來所需要的。 –

2

說實話,鑑於你在問題中描述的方法,這相當困難。現有的SAPI引擎或者不會通過(例如,可通過Microsoft.Speech.Recognition獲得的「服務器」引擎)進行聽寫,或者需要通過訓練學習給定語音的細節(例如,通過System.Speech.Recognition可用的「桌面」引擎)。

Windows運行時識別器(Windows.Media.SpeechRecognition)支持口述並提供置信度值,但不支持來自流的識別。

使用您描述的方法,我會使用Bing Speech API,因爲它通過REST API提供了您想要的置信度值。

相關問題