【问题标题】:SAPI identifying more than 2 propertiesSAPI 识别超过 2 个属性
【发布时间】:2015-12-18 15:22:38
【问题描述】:

我在搜索有关 SAPI 识别短语的一些信息时在 google 上找到了这个。此示例显示规则中是否只有一个属性。那么如果该规则中有 2 个或更多属性怎么办?一个人将如何为此编写代码?我仍然对 SAPI 感到困惑并试图理解它。欢迎任何帮助,谢谢!

The alternate method is add a property to your list tag/items [you appear to
 be familiar with properties], iterate through the property tree to find the
property, and then retrieve the associated item from the property. Note if
this is the only property in your recognized rule, then it is fairly easy to
retrieve the property [no need to navigate the property tree].
For example, you could change your rule to be the following:

<RULE ID="VID_Vcs">
<L PROPNAME="NAME_LIST">
   <P VAL="1">Mike </P>
   <P VAL="2">Davor </P>
   <P VAL="3">Kurt </P>
   <P VAL="4">Steve </P>
</L>
</RULE>


Use the following code to retrieve the list item value/phrase text
SPPHRASE* pPhrase = NULL;
hr = cpRecoResult->GetPhrase(&pPhrase);
// Check hr

// Let's assume that you only have one property in your rule, so there is only one property in the property tree.
// ASSERT: NULL == pPhrase->pProperties->pNextSibling && NULL == pPhrase->pProperties->pFirstChild
// ASSERT: NULL != pPhrase->pProperties->pszName && 0 == wcscmp(pPhrase->pProperties->pszName, L"NAME_LIST")

// retrieve the list item index [e.g. 1-4], see VAL XML tags in aforementioned grammar
long lRecognizedListItemIndex = pPhrase->pProperties->vValue.lVal;

// retrieve the phrase text
hr = cpRecoResult->GetText(pPhrase->pProperties->ulFirstElement, pPhrase->pProperties->ulCOuntOfElements, FALSE, &pwszListItem, NULL);
// Check hr

// pwszListItem now contains the recognized list item


//compared to the phrase tag of the dictionary (XML)
if(SUCCEEDED (hResult)) {
    if ((pPhrase->pProperties != nullptr) &&         (pPhrase->pProperties->pFirstChild != nullptr)){
        const SPPHRASEPROPERTY* pRule = pPhrase->pProperties->pFirstChild ;
        if (pRule->SREngineConfidence->confidence Threshold) {
            if ( wcscmp ( L"word one", pRule->pszValue) == 0 ) {
                //do stuff here
            }
            else if ( wcscmp ( L"word two", pRule->pszValue) == 0 ) {
                //do stuff here
            }
            else if ( wcscmp ( L"word three", pRule->pszValue) == 0 ) {
                //do stuff here
            }
            else if ( wcscmp ( L"word four", pRule->pszValue ) == 0) {
                //do stuff
            }
        }
    }
}

【问题讨论】:

  • 您真的需要动态修改语法的能力吗?如果没有,您可以编写一个 SRGS 语法并调用 LoadCmdFromFile(, SPLO_STATIC) 来加载您的语法并开始运行。
  • @Lesley Gushurst - 我不熟悉 SRGS,但我可以看到好处。但是,我正在尝试使用属性方法或上面显示的方式来做到这一点。我只是不确定如何扫描树的多个属性。

标签: c++ sapi


【解决方案1】:

好的,抱歉让您久等了。我编写了一个简单的程序,可以帮助你弄清楚你想要做什么。

这是我的语法文件:

<GRAMMAR LANGID="409">
    <DEFINE>
        <ID NAME="LIKE_VAL" VAL="1"/>
        <ID NAME="SUBJECT_VAL" VAL="2"/>
        <ID NAME="COMBINED_VAL" VAL="3"/>
        <ID NAME="EXIT_VAL" VAL="4"/>
    </DEFINE>
    <RULE NAME="LIKE_VAL" TOPLEVEL="ACTIVE">
        <L>
            <P>I <O>really</O> like</P>
            <P>I <O>really</O> do not like</P>
        </L>
    </RULE>
    <RULE NAME="SUBJECT_VAL" TOPLEVEL="ACTIVE">
        <P>ponies.</P>
    </RULE>
    <RULE NAME="COMBINED_VAL" TOPLEVEL="ACTIVE">
        <RULEREF NAME="LIKE_VAL"/>
        <RULEREF NAME="SUBJECT_VAL"/>
    </RULE>
    <RULE NAME="EXIT_VAL" TOPLEVEL="ACTIVE">
        <L>
            <P>Exit</P>
            <P>Quit</P>
            <P>Terminate</P>
            <P>Deluminate</P>
        </L>
    </RULE>
</GRAMMAR>

这是一个使用它的完整程序:

#include "sphelper.h"
#include <Windows.h>
#include <string>

int main(int argc, char* argv[])
{
    CComPtr<ISpRecognizer> cpReco;
    CComPtr<ISpRecoContext> cpRecoCtx;
    CComPtr<ISpRecoGrammar>  cpRecoGram;

    ULONGLONG ullEvents = SPFEI(SPEI_RECOGNITION)|
       SPFEI(SPEI_FALSE_RECOGNITION);

    ISpObjectToken* pInputToken;
    ISpRecoResult* cpRecoRslt;
    HRESULT hr = S_OK;

    hr = ::CoInitialize(NULL);
    hr = cpReco.CoCreateInstance(CLSID_SpInprocRecognizer);
    hr = cpReco->CreateRecoContext(&cpRecoCtx);
    hr = cpRecoCtx->CreateGrammar(0, &cpRecoGram);
    hr = cpRecoCtx->SetNotifyWin32Event();

    hr = cpRecoCtx->SetInterest(ullEvents, ullEvents);
    hr = SpGetDefaultTokenFromCategoryId(SPCAT_AUDIOIN, &pInputToken);
    hr = cpReco->SetInput(pInputToken, FALSE);
    hr = cpRecoGram->LoadCmdFromFile(L"Your_Test_File.cfg",SPLO_STATIC);
    hr = cpReco->SetRecoState(SPRST_ACTIVE);
    hr = cpRecoCtx->SetContextState(SPCS_ENABLED);
    hr = cpRecoGram->SetGrammarState(SPGS_ENABLED);
    hr = cpRecoGram->SetRuleState(NULL, NULL, SPRS_ACTIVE);
    std::wstring strExit = L"Exit";
    std::wstring strExitRuleName = L"EXIT_VAL";
    CSpEvent spEvent;
    bool isListening = true;
    do{
        hr = cpRecoCtx->WaitForNotifyEvent(INFINITE);
        if(spEvent.GetFrom(cpRecoCtx) == S_OK)
        {
            switch(spEvent.eEventId){
                case SPEI_RECOGNITION:{

                    WCHAR* strReco = 0;
                    cpRecoRslt = spEvent.RecoResult();
                    cpRecoRslt->GetText(SP_GETWHOLEPHRASE, SP_GETWHOLEPHRASE, TRUE, &strReco, NULL);
                    printf("%ls\n",strReco);

                    SPPHRASE *phrase = NULL;
                    cpRecoRslt->GetPhrase(&phrase);
                    if(phrase){
                        std::wstring ruleName = phrase->Rule.pszName;
                        if(strExitRuleName.compare(strExit)==0){
                            isListening = false;
                        }
                    }
                    break;
                }
                case SPEI_FALSE_RECOGNITION:{
                    printf("False Recognition\n");
                    break;
                }
            }
        }
    }while(isListening);

    cpRecoGram.Release();
    cpRecoCtx.Release();
    cpReco.Release();

    ::CoUninitialize();
    printf("Press any key to continue...");
    getchar();

    return 0;
}

您必须更改加载语法调用的加载路径。据我了解,您尝试做的是在上下文无关的语法文件中创建语法,并尝试以编程方式执行此操作。通常,您从语法文件开始,并在需要时进行修改。

但是,如果您真的真的需要以编程方式添加新语法,例如当有人输入新语法以被识别时,那么您可能会将 SPLO_STATIC 设置为 SPLO_DYNAMIC 并开始实现您在后半部分看到的代码你看到的 MSDN 帖子。

我完全忽略了任何错误检查。如果您需要访问您正在查看的规则的其他属性,请使用 pPhrase->GetPhrase(&phrase) 区域。除了规则的名称,您还可以获得它的 ID。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-04
    • 1970-01-01
    • 2020-12-30
    • 2022-01-22
    相关资源
    最近更新 更多