Проблема с субязыком Microsoft SAPI

Моя проблема заключается в следующем: мой распознаватель SAPI inproc отказывается загружать мой файл грамматики, когда для языка отображения Windows 10 установлено значение Английский (Великобритания).

Язык отображения системы установлен в Великобритании. Язык распознавания речи - Великобритания. Язык системы - Великобритания. В грамматике SAPI xml-формата даже указывается 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;
}

Я получаю сообщение об ошибке "Не удается загрузить грамматику. Пожалуйста, проверьте языковые настройки" каждый раз, когда язык дисплея не английский (США), даже если я подтверждаю, что ВСЕ НАСТРОЙКИ совпадают...

Был бы очень признателен за любые идеи от людей, более знающих, чем я

Фарли

2 ответа

Решение

Проблема заключалась в том, что я неправильно истолковал значение параметра "language" в LoadCmdFromResource(). Я буду винить в этом неоднозначную документацию SAPI, хотя, если бы у меня был опыт загрузки некоторых других типов ресурсов, прежде чем я мог быть предупрежден об этом.;) Я думал, что он каким-то образом используется SAPI и должен соответствовать языку системы и распознавателя (именно так это звучало в документации). Оказывается, на самом деле он просто указывает язык, используемый для компиляции файла.RC, в который включена грамматика (предположительно, для включения нескольких переводов в отдельные файлы.rc).

Код работает отлично, как первоначально опубликовано, до тех пор, пока я заменяю "GetUserDefaultUI()" на явный "0x409" (язык, указанный в компиляторе ресурсов) при вызове LoadCmdFromResource(). Теперь он работает с американским английским, британским английским языком и, вероятно, со всеми распознавателями английского языка и загружает распознаватель, выбранный на панели управления речью, независимо от настройки языка дисплея (которая может быть даже не английской).

Большое, большое спасибо Эрику Брауну за то, что предупредили меня об этом, я начал сходить с ума.

Фарли

Вам нужно явно загрузить распознаватель для вашего предпочтительного языка. В частности, это:

//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 в шестнадцатеричное число.

Другие вопросы по тегам