【问题标题】:Microsoft SAPI Sub-language issueMicrosoft SAPI 子语言问题
【发布时间】:2015-12-03 19:27:02
【问题描述】:

我的问题是:当 Windows 10 显示语言设置为英语(英国)时,我的 SAPI inproc 识别器拒绝加载我的语法文件。

系统显示语言设置为英国。语音识别语言是英国。系统区域设置为英国。 SAPI xml-format Grammar 甚至指定 LANGID=809 - 据我所知,一切都设置为 EN-GB,但语法仍然无法加载。

但是当显示语言设置为英语(美国)时,它可以正常加载和工作。

有人知道这是怎么回事吗?这非常令人沮丧......希望我只是错过了一些简单的东西。

SAPI 初始化代码:

    //////////////INITIALIZE SAPI ENGINE AND GRAMMAR//////////////////////////////
HRESULT SpeechObject::Initialize(){
    //INITIALIZE SR ENGINE
    if (FAILED(test=::CoInitialize(NULL)))
        SRError(L"COM Initialization Fail");

    //Create recognizer instance
    if (FAILED(test=cpEngine.CoCreateInstance(CLSID_SpInprocRecognizer))){
        SRError(L"Can't Load Reco Engine");
            return test;
    }

    //Load the audio Input (in seperate function to facilitate reload)
    LoadAudio(); //should I check this?

    //load Default recognizer settings
    cpEngine->SetRecognizer(NULL);

    //get and load default reco profile
    if (FAILED(SpGetDefaultTokenFromCategoryId(SPCAT_RECOPROFILES, &cpObjectToken)))
        SRError(L"Can't Find Recognition Profile");
    if (FAILED(cpEngine->SetRecoProfile(cpObjectToken)))
        SRError(L"Can't Load Recognition Profile");

    //create reco context
    if (FAILED(test=cpEngine->CreateRecoContext(&cpContext))){
        SRError(L"Can't Create Reco Context");
        return test;
    }

    //send pSpeechObject to global callback function
    cpContext->SetNotifyCallbackFunction(
        (SPNOTIFYCALLBACK*)SpeechCallBack,
        NULL, (LPARAM)this);

    if(FAILED(cpContext->CreateGrammar(NULL, &cpGrammar)))
        SRError(L"Can't Create context");

    char str[80]; ////TEST
    sprintf(str, "LANGID: %X", GetUserDefaultUILanguage());
    MessageBoxA(GetActiveWindow(), str,0,0);

    //load grammar from compiled grammar resource
    if (FAILED(test = cpGrammar->LoadCmdFromResource(
        hModule, MAKEINTRESOURCE(GRAMMARCFG),
        L"FILE", GetUserDefaultUILanguage(), SPLO_STATIC))){
        SRError(L"Can't Load Grammar. Please check language settings");
        return test;
    }

    //(comment above and uncomment following to load from raw xml file for testing)
    //cpGrammar->LoadCmdFromFile(L"Grammar.xml", SPLO_STATIC);

    //Enable Engine and Reco Context
    cpEngine->SetRecoState(SPRST_ACTIVE);
    cpContext->SetContextState(SPCS_ENABLED);

    //enable ALWAYS ACTIVE and GROUND ENGINES ON commands
    return(cpGrammar->SetRuleState(NULL, NULL, SPRS_ACTIVE));

}

////////////LOAD (AND RELOAD) AUDIO INPUT//////////////////////
HRESULT SpeechObject::LoadAudio(bool dlgFlag){
    if (FAILED(test = SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOIN, &cpAudioIn))){
        SRError(L"Can't Find Default Audio Input");
        return test;
    }

    if (FAILED(test = cpEngine->SetInput(cpAudioIn, TRUE))){
        if (!dlgFlag)
            SRError(L"Can't Set Audio Input");
        return test;
    }

    if (pSRDisplay)
        pSRDisplay->DisplayText("Audio Reloaded");
    if (pDLog)
        pDLog->LogEvent("Audio Reloaded");
    //RecoState must be reenabled after audio reset
    cpEngine->SetRecoState(SPRST_ACTIVE);
    if (pDLog)
        pDLog->LogEvent("SR ENABLED");
    return test;
}

只要显示语言不是英语(美国),即使我确认所有设置都匹配...

非常感谢比我知识渊博的人的任何见解。

法利

【问题讨论】:

    标签: windows speech-recognition speech sapi microsoft-speech-api


    【解决方案1】:

    您需要为您的首选语言显式加载识别器。特别是:

    //load Default recognizer settings
    cpEngine->SetRecognizer(NULL);
    

    始终加载语音控制面板中指定的识别器。你可能想要这样的东西:

    CComPtr<ISpObjectToken> cpEngineToken;
    hr = SpFindBestToken(SPCAT_RECOGNIZERS, L"Language=<hex language id>", NULL, &cpEngineToken);
    // check hr
    hr = cpEngine->SetRecognizer(cpEngineToken);
    

    您需要将 LCID 从 GetUserDefaultUILanguage 转换为十六进制数字。

    【讨论】:

    • 不幸的是,这似乎不起作用。事实上,考虑到语音控制面板中的设置已经与显示语言匹配,如果确实如此,我会感到非常惊讶。所有设置都匹配。不过,我真的很感谢你的帮助,我很想听听任何其他的想法!
    • 适用于显示语言 409(美国),但不适用于 809(英国)。 SpFindBestToken() 和 SetRecognizer() 都不会失败。换句话说,我仍然有完全相同的问题。
    • 事实上,您是否为 en-UK 安装了识别器引擎?例如,我的 Win10 机器没有。
    • 是的,先生。我自己安装了它,当我尝试将不同的语言代码传递给 SpFindBestToken() 时,所有调用都返回“失败”,除了“Language=409”和“Language=809”,我有两个引擎已安装。
    • 使用 inproc 识别器,语音控制面板中的设置或多或少无关紧要。你负责设置一切。此时,我将切换到 LoadGrammarFromFile 或 LoadGrammarFromMemory,这样您就可以将“完全加载语法”与“从资源文件中加载语法”分开 - 因为 LoadCmdFromResource 文件的 langid 是资源文件,而不是语法的 langid。
    【解决方案2】:

    问题是我误解了 LoadCmdFromResource() 中“语言”参数的含义。我会把它归咎于模棱两可的 SAPI 文档,但如果我在被告知之前有加载其他类型资源的经验,我可能会被告知。 ;) 我曾认为它以某种方式被 SAPI 使用,并且应该与系统和识别器的语言相匹配(这就是它在文档中听起来的样子)。事实证明,它实际上只是指定了用于编译包含语法的 .RC 文件的语言(大概是为了允许将多个翻译包含在单独的 .rc 中)。

    只要我在调用 LoadCmdFromResource() 时将“GetUserDefaultUI()”替换为显式“0x409”(资源编译器中指定的语言),代码就可以完美运行。现在它可以与美国英语、英国英语和大概所有英语识别器一起使用,并且无论显示语言设置如何(甚至可以是非英语),都会加载在语音控制面板中选择的识别器。

    非常感谢 Eric Brown 向我透露了这一点,我开始失去理智了。

    法利

    【讨论】:

      猜你喜欢
      • 2019-07-07
      • 2012-08-09
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 2011-01-04
      • 2011-07-10
      • 2010-11-27
      • 1970-01-01
      相关资源
      最近更新 更多