当“可选”时如何从 System.Speech.Recognition 返回默认语义项目被省略?

发布于 2024-11-02 02:52:17 字数 3311 浏览 4 评论 0原文

我是一名中级 C# 程序员,但绝对是 System.Speech 的初学者。我正在通过一些示例来了解 API 的工作原理,并且我已经挂在第一个示例上...我想做的是拥有一个语法,它可以返回一个或多个预期选择的默认语义如果用户没有明确提供这些选项之一的值。 (抱歉,如果我的术语不太正确...)我使用的是带有 Visual Studio 2010(试用版)的 Windows Vista,并且安装了 .NET 4.0。

我从下面的文章中的“披萨订购”示例开始,该示例似乎在论坛上出现很多:

http://msdn.microsoft.com/en-us/magazine/cc163663.aspx#S5

我开始使用的代码位于该文章的图 9 中。不幸的是,由于某种原因(可能从一个版本的 SAPI 更改为下一个版本?),许多函数调用在 .NET 4.0/SAPI 5.3 中实际上无效,例如 GrammarBuilder.AppendChoices() 和 GrammarBuilder.AppendResultKeyValue() 。如果用户只指定配料(即“请吃奶酪披萨”),则后一个调用应该为我们提供“大小”和“外壳”键的默认选择(即“请吃奶酪披萨”),手背尺寸=大,外壳=厚,配料=奶酪)...所以我想弄清楚如何使这项工作成功。

这是我的代码的相关部分(应该只是对上面文章中的代码的重写):

// [I'd like] a [< size >] [< crust >] [< topping >] pizza [please]

// build the core set of choices  
GrammarBuilder grbSizes = new GrammarBuilder(new Choices("small", "regular", "large"));  
GrammarBuilder grbCrusts = new GrammarBuilder(new Choices("thin crust", "thick crust"));  
GrammarBuilder grbToppings = new GrammarBuilder(new Choices("vegetarian", "pepperoni", "cheese"));    

// Wrap them in semantic result keys
SemanticResultKey skeySize = new SemanticResultKey("size", grbSizes);  
SemanticResultKey skeyCrust = new SemanticResultKey("crust", grbCrusts);  
SemanticResultKey skeyTopping = new SemanticResultKey("topping", grbToppings);  

// And some default values for later on...    
SemanticResultKey skeyDefaultSize = new SemanticResultKey("size", new GrammarBuilder(new SemanticResultValue("large")));  
SemanticResultKey skeyDefaultCrust = new SemanticResultKey("crust", new GrammarBuilder(new SemanticResultValue("thick crust")));  


// [...snip...]  
// Here's the builder for one of several sub-grammars, the one with two default  
// values... This should allow "cheese" in "A cheese pizza" to be intepreted  
// as large+thick-crust+cheese

//choose topping only, and assume the rest
GrammarBuilder toppingOnly = new GrammarBuilder();
toppingOnly += skeyTopping;
toppingOnly += skeyDefaultSize;
toppingOnly += skeyDefaultCrust;

// [...snip...]
// Later code builds up the full pattern just as in the original article

我知道 SemanticResultKey 构造函数的 MSDN 页面 包含一条警告:“在指定的 GrammarBuilder 对象中应该有且只有一个未标记的 SemanticResultValue 实例通过builders参数”,否则你会得到一个异常。事实上,当我对识别器说“奶酪披萨”之类的内容时,我确实收到了 TargetInitationException 。

所以我的第一个问题是,有人可以向我解释一下这是怎么回事吗?我不一定期望此约束适用于此,因为 (a) 我认为我对 skeyDefaultSize 和 skeyDefaultCrust 的声明确实将 SemanticResultValues 与 SemanticResultKeys 相关联,因此这些值不应被视为“未标记”; (b) 所讨论的两个 SemanticResultValue 实际上来自不同的 GrammarBuilder,而这些 GrammarBuilder 又位于不同的 SemanticResultKey 内,这似乎不是 MSDN 页面上描述的场景。

那么我的第二个问题是,为什么下面的代码有效?唯一的区别是我重新排序了一些行,以便两个“默认”键不会连续附加到语法中。

//choose topping only, and assume the rest
GrammarBuilder toppingOnly = new GrammarBuilder();
toppingOnly += skeyDefaultSize;
toppingOnly += skeyTopping;
toppingOnly += skeyDefaultCrust;

当我说“奶酪披萨”时,这给出了确切的期望结果 - 所有键(“大小”,“外壳”,“顶部”)都存在于我在 SpeechRecognized 处理程序中捕获的 SemanticValue 中,并具有所需的默认值大小和外壳的值加上用户指定的配料值。

我想第三个也是最重要的问题是:有没有办法正确地做到这一点?显然,调整附加的顺序太“神奇”,并不总是一个可行的解决方案。

很抱歉问了这个大问题,非常感谢您的帮助!

I am an intermediate C# programmer but an absolute beginner with System.Speech. I am working through some examples to get the feel of how the API works, and I'm already hung up on the first example... What I am trying to do is have a grammar which returns default semantics for one or more expected choices if the user does not explicitly provide a value for one of those choices. (Sorry if my terminology's not quite right...) I am on Windows Vista with Visual Studio 2010 (trial version), and .NET 4.0 installed.

I started from the "pizza ordering" example in the following article, which seems to come up on the forums quite a bit:

http://msdn.microsoft.com/en-us/magazine/cc163663.aspx#S5

The code I started with is in Figure 9 of that article. Unfortunately, for some reason (possibly changes from one version of SAPI to the next?), a number of the function calls are not actually valid in .NET 4.0/SAPI 5.3, for example GrammarBuilder.AppendChoices() and GrammarBuilder.AppendResultKeyValue(). The latter call is what is supposed to give us default choices for the "size" and "crust" keys if the user only specifies toppings (i.e. "A cheese pizza, please" hands back size=large, crust=thick, and topping=cheese)... so I am trying to figure out how to make this work.

Here's the relevant section of my code (which is supposed to be just a rewrite of the code in the above article):

// [I'd like] a [< size >] [< crust >] [< topping >] pizza [please]

// build the core set of choices  
GrammarBuilder grbSizes = new GrammarBuilder(new Choices("small", "regular", "large"));  
GrammarBuilder grbCrusts = new GrammarBuilder(new Choices("thin crust", "thick crust"));  
GrammarBuilder grbToppings = new GrammarBuilder(new Choices("vegetarian", "pepperoni", "cheese"));    

// Wrap them in semantic result keys
SemanticResultKey skeySize = new SemanticResultKey("size", grbSizes);  
SemanticResultKey skeyCrust = new SemanticResultKey("crust", grbCrusts);  
SemanticResultKey skeyTopping = new SemanticResultKey("topping", grbToppings);  

// And some default values for later on...    
SemanticResultKey skeyDefaultSize = new SemanticResultKey("size", new GrammarBuilder(new SemanticResultValue("large")));  
SemanticResultKey skeyDefaultCrust = new SemanticResultKey("crust", new GrammarBuilder(new SemanticResultValue("thick crust")));  


// [...snip...]  
// Here's the builder for one of several sub-grammars, the one with two default  
// values... This should allow "cheese" in "A cheese pizza" to be intepreted  
// as large+thick-crust+cheese

//choose topping only, and assume the rest
GrammarBuilder toppingOnly = new GrammarBuilder();
toppingOnly += skeyTopping;
toppingOnly += skeyDefaultSize;
toppingOnly += skeyDefaultCrust;

// [...snip...]
// Later code builds up the full pattern just as in the original article

I am aware that the MSDN page for the SemanticResultKey constructor includes a warning that "There should be one, and only one, untagged SemanticResultValue instance in the GrammarBuilder objects specified by the builders parameter", or else you'll get an exception. And indeed, I do get a TargetInvocationException here when I say something like "A cheese pizza" into the recognizer.

So my first question is, can someone explain to me what is going on here? I wouldn't necessarily have expected this constraint to apply here, since (a) I thought that my declarations for skeyDefaultSize and skeyDefaultCrust were indeed associating the SemanticResultValues with SemanticResultKeys, so these Values should not be considered as "untagged"; and (b) the two SemanticResultValues in question are actually from different GrammarBuilders which are in turn inside of different SemanticResultKeys, which doesn't seem to be the scenario described on the MSDN page.

Then my second question is, why DOES the following code work? The only difference is that I have re-ordered some lines so that the two "default" keys are not appended to the grammar consecutively.

//choose topping only, and assume the rest
GrammarBuilder toppingOnly = new GrammarBuilder();
toppingOnly += skeyDefaultSize;
toppingOnly += skeyTopping;
toppingOnly += skeyDefaultCrust;

This gives the exact desired result when I say e.g. "A cheese pizza"-- all the keys ("size", "crust", "topping") are present in the SemanticValue that I catch in my SpeechRecognized handler, with the desired default values for size and crust plus the user-specified value for the topping.

I guess the third and most important question is: Is there some way to do this properly? Obviously, tweaking the order of the appends is too "magical" and will not always be a viable solution.

Sorry for the huge question, and thanks a lot for your help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一口甜 2024-11-09 02:52:17

我在MSDN文章中学习时遇到了同样的问题。我不知道我的解决方案是“最好的”,但这就是我更新 Pizza 语法并处理默认选择的方式。

首先,这就是我创建披萨语法的方式:

private Grammar CreatePizzaGrammar()
{
    //create the pizza grammar
    GrammarBuilder pizzaRequest = CreatePizzaGrammarBuilder();
    Grammar pizzaGrammar = new Grammar(pizzaRequest);
    return pizzaGrammar;
}

private GrammarBuilder CreatePizzaGrammarBuilder()
{
    // this is adapted from the sample in http://msdn.microsoft.com/en-us/magazine/cc163663.aspx
    // but the API changed before Vista was released so some changes were made.

    //[I'd like] a [<size>] [<crust>] [<topping>] pizza [please]

    //build the core set of choices

    // size
    Choices sizes = new Choices();
    SemanticResultValue sizeSRV;
    sizeSRV = new SemanticResultValue("small", "small");
    sizes.Add(sizeSRV);
    sizeSRV = new SemanticResultValue("regular", "regular");
    sizes.Add(sizeSRV);
    sizeSRV = new SemanticResultValue("medium", "regular");
    sizes.Add(sizeSRV);
    sizeSRV = new SemanticResultValue("large", "large");
    sizes.Add(sizeSRV);
    SemanticResultKey sizeSemKey = new SemanticResultKey("size", sizes);

    // crust
    Choices crusts = new Choices();
    SemanticResultValue crustSRV;
    crustSRV = new SemanticResultValue("thin crust", "thin crust");
    crusts.Add(crustSRV);
    crustSRV = new SemanticResultValue("thin", "thin crust");
    crusts.Add(crustSRV);
    crustSRV = new SemanticResultValue("thick crust", "thick crust");
    crusts.Add(crustSRV);
    crustSRV = new SemanticResultValue("thick", "thick crust");
    crusts.Add(crustSRV);
    SemanticResultKey crustSemKey = new SemanticResultKey("crust", crusts);

    // toppings
    Choices toppings = new Choices();
    SemanticResultValue toppingSRV;
    toppingSRV = new SemanticResultValue("vegetarian", "vegetarian");
    toppings.Add(toppingSRV);
    toppingSRV = new SemanticResultValue("veggie", "vegetarian");
    toppings.Add(toppingSRV);
    toppingSRV = new SemanticResultValue("pepperoni", "pepperoni");
    toppings.Add(toppingSRV);
    toppingSRV = new SemanticResultValue("cheese", "cheese");
    toppings.Add(toppingSRV);
    toppingSRV = new SemanticResultValue("plain", "cheese");
    toppings.Add(toppingSRV);
    SemanticResultKey toppingSemKey = new SemanticResultKey("topping", toppings);

    //build the permutations of choices...

    // 1. choose all three
    GrammarBuilder sizeCrustTopping = new GrammarBuilder();
    sizeCrustTopping.Append(sizeSemKey);
    sizeCrustTopping.Append(crustSemKey);
    sizeCrustTopping.Append(toppingSemKey);

    // 2. choose size and topping
    GrammarBuilder sizeAndTopping = new GrammarBuilder();
    sizeAndTopping.Append(sizeSemKey);
    sizeAndTopping.Append(toppingSemKey);
    // sizeAndTopping.Append(new SemanticResultKey("crust", "thick crust"));
    // sizeAndTopping.AppendResultKeyValue("crust", "thick crust");

    // 3. choose size and crust, and assume cheese
    GrammarBuilder sizeAndCrust = new GrammarBuilder();
    sizeAndCrust.Append(sizeSemKey);
    sizeAndCrust.Append(crustSemKey);

    // 4. choose topping and crust, and assume cheese
    GrammarBuilder toppingAndCrust = new GrammarBuilder();
    toppingAndCrust.Append(crustSemKey);
    toppingAndCrust.Append(toppingSemKey);


    // 5. choose topping only, and assume the rest
    GrammarBuilder toppingOnly = new GrammarBuilder();
    toppingOnly.Append(toppingSemKey);         //, "topping");

    // 6. choose size only, and assume the rest
    GrammarBuilder sizeOnly = new GrammarBuilder();
    sizeOnly.Append(sizeSemKey);

    // 7. choose crust only, and assume the rest
    GrammarBuilder crustOnly = new GrammarBuilder();
    crustOnly.Append(crustSemKey);


    //assemble the permutations             
    Choices permutations = new Choices();
    permutations.Add(sizeCrustTopping);
    permutations.Add(sizeAndTopping);
    permutations.Add(sizeAndCrust);
    permutations.Add(toppingAndCrust);
    permutations.Add(toppingOnly);
    permutations.Add(sizeOnly);
    permutations.Add(crustOnly);

    GrammarBuilder permutationList = new GrammarBuilder();
    permutationList.Append(permutations);

    //now build the complete pattern...
    GrammarBuilder pizzaRequest = new GrammarBuilder();
    //pre-amble "[I'd like] a"
    pizzaRequest.Append(new Choices("I'd like a", "a", "I need a", "I want a"));
    //permutations "[<size>] [<crust>] [<topping>]"
    pizzaRequest.Append(permutationList, 0, 1);
    //post-amble "pizza [please]"
    pizzaRequest.Append(new Choices("pizza", "pizza please", "pie", "pizza pie"));

    return pizzaRequest;
}

然后我为 SpeechRecognized 事件设置一个事件处理程序:

void recognizer_SpeechRecognizedPizza(object sender, SpeechRecognizedEventArgs e)
{

    // set the default semantic key values if the result does not include these
    string size = "regular";
    string crust = "thick crust";
    string topping = "cheese";

    if (e.Result.Semantics != null && e.Result.Semantics.Count != 0)
    {
        if (e.Result.Semantics.ContainsKey("size"))
        {
            size = e.Result.Semantics["size"].Value.ToString();
            AppendTextOuput(String.Format("\r\n  Size = {0}.", size));
        }

        if (e.Result.Semantics.ContainsKey("crust"))
        {
            crust = e.Result.Semantics["crust"].Value.ToString();
            AppendTextOuput(String.Format("\r\n  Crust = {0}.", crust));
        }

        if (e.Result.Semantics.ContainsKey("topping"))
        {
            topping = e.Result.Semantics["topping"].Value.ToString();
            AppendTextOuput(String.Format("\r\n  Topping = {0}.", topping));
        }
    }
    String sOutput = String.Format("\r\nRecognized: You have orderd a {0}, {1}, {2} pizza.", size, crust, topping);
    AppendTextOuput(sOutput);
}

AppendTextOuput 只是我自己的小输出字符串方法。

显式布局语法中所有可能的排列似乎需要大量工作。但是,它的效果确实很好。

正如您所看到的,我最终避免了让语法提供默认值的问题,只是将其构建到事件处理程序中。可能有更好的方法。

了解更多信息的另一步骤是使用 SrgsDocument.WriteSrgs() 方法并写出表示语法的 SRGS XML 文档。规则和语义标签在 XML 中更容易可视化。

I ran into the same problem learning from the MSDN article. I don't know that my solution is "the best", but this is how I updated the Pizza grammar and handled the default selections.

First, this is how I create the pizza grammar:

private Grammar CreatePizzaGrammar()
{
    //create the pizza grammar
    GrammarBuilder pizzaRequest = CreatePizzaGrammarBuilder();
    Grammar pizzaGrammar = new Grammar(pizzaRequest);
    return pizzaGrammar;
}

private GrammarBuilder CreatePizzaGrammarBuilder()
{
    // this is adapted from the sample in http://msdn.microsoft.com/en-us/magazine/cc163663.aspx
    // but the API changed before Vista was released so some changes were made.

    //[I'd like] a [<size>] [<crust>] [<topping>] pizza [please]

    //build the core set of choices

    // size
    Choices sizes = new Choices();
    SemanticResultValue sizeSRV;
    sizeSRV = new SemanticResultValue("small", "small");
    sizes.Add(sizeSRV);
    sizeSRV = new SemanticResultValue("regular", "regular");
    sizes.Add(sizeSRV);
    sizeSRV = new SemanticResultValue("medium", "regular");
    sizes.Add(sizeSRV);
    sizeSRV = new SemanticResultValue("large", "large");
    sizes.Add(sizeSRV);
    SemanticResultKey sizeSemKey = new SemanticResultKey("size", sizes);

    // crust
    Choices crusts = new Choices();
    SemanticResultValue crustSRV;
    crustSRV = new SemanticResultValue("thin crust", "thin crust");
    crusts.Add(crustSRV);
    crustSRV = new SemanticResultValue("thin", "thin crust");
    crusts.Add(crustSRV);
    crustSRV = new SemanticResultValue("thick crust", "thick crust");
    crusts.Add(crustSRV);
    crustSRV = new SemanticResultValue("thick", "thick crust");
    crusts.Add(crustSRV);
    SemanticResultKey crustSemKey = new SemanticResultKey("crust", crusts);

    // toppings
    Choices toppings = new Choices();
    SemanticResultValue toppingSRV;
    toppingSRV = new SemanticResultValue("vegetarian", "vegetarian");
    toppings.Add(toppingSRV);
    toppingSRV = new SemanticResultValue("veggie", "vegetarian");
    toppings.Add(toppingSRV);
    toppingSRV = new SemanticResultValue("pepperoni", "pepperoni");
    toppings.Add(toppingSRV);
    toppingSRV = new SemanticResultValue("cheese", "cheese");
    toppings.Add(toppingSRV);
    toppingSRV = new SemanticResultValue("plain", "cheese");
    toppings.Add(toppingSRV);
    SemanticResultKey toppingSemKey = new SemanticResultKey("topping", toppings);

    //build the permutations of choices...

    // 1. choose all three
    GrammarBuilder sizeCrustTopping = new GrammarBuilder();
    sizeCrustTopping.Append(sizeSemKey);
    sizeCrustTopping.Append(crustSemKey);
    sizeCrustTopping.Append(toppingSemKey);

    // 2. choose size and topping
    GrammarBuilder sizeAndTopping = new GrammarBuilder();
    sizeAndTopping.Append(sizeSemKey);
    sizeAndTopping.Append(toppingSemKey);
    // sizeAndTopping.Append(new SemanticResultKey("crust", "thick crust"));
    // sizeAndTopping.AppendResultKeyValue("crust", "thick crust");

    // 3. choose size and crust, and assume cheese
    GrammarBuilder sizeAndCrust = new GrammarBuilder();
    sizeAndCrust.Append(sizeSemKey);
    sizeAndCrust.Append(crustSemKey);

    // 4. choose topping and crust, and assume cheese
    GrammarBuilder toppingAndCrust = new GrammarBuilder();
    toppingAndCrust.Append(crustSemKey);
    toppingAndCrust.Append(toppingSemKey);


    // 5. choose topping only, and assume the rest
    GrammarBuilder toppingOnly = new GrammarBuilder();
    toppingOnly.Append(toppingSemKey);         //, "topping");

    // 6. choose size only, and assume the rest
    GrammarBuilder sizeOnly = new GrammarBuilder();
    sizeOnly.Append(sizeSemKey);

    // 7. choose crust only, and assume the rest
    GrammarBuilder crustOnly = new GrammarBuilder();
    crustOnly.Append(crustSemKey);


    //assemble the permutations             
    Choices permutations = new Choices();
    permutations.Add(sizeCrustTopping);
    permutations.Add(sizeAndTopping);
    permutations.Add(sizeAndCrust);
    permutations.Add(toppingAndCrust);
    permutations.Add(toppingOnly);
    permutations.Add(sizeOnly);
    permutations.Add(crustOnly);

    GrammarBuilder permutationList = new GrammarBuilder();
    permutationList.Append(permutations);

    //now build the complete pattern...
    GrammarBuilder pizzaRequest = new GrammarBuilder();
    //pre-amble "[I'd like] a"
    pizzaRequest.Append(new Choices("I'd like a", "a", "I need a", "I want a"));
    //permutations "[<size>] [<crust>] [<topping>]"
    pizzaRequest.Append(permutationList, 0, 1);
    //post-amble "pizza [please]"
    pizzaRequest.Append(new Choices("pizza", "pizza please", "pie", "pizza pie"));

    return pizzaRequest;
}

Then I set up an event handler for the SpeechRecognized event as:

void recognizer_SpeechRecognizedPizza(object sender, SpeechRecognizedEventArgs e)
{

    // set the default semantic key values if the result does not include these
    string size = "regular";
    string crust = "thick crust";
    string topping = "cheese";

    if (e.Result.Semantics != null && e.Result.Semantics.Count != 0)
    {
        if (e.Result.Semantics.ContainsKey("size"))
        {
            size = e.Result.Semantics["size"].Value.ToString();
            AppendTextOuput(String.Format("\r\n  Size = {0}.", size));
        }

        if (e.Result.Semantics.ContainsKey("crust"))
        {
            crust = e.Result.Semantics["crust"].Value.ToString();
            AppendTextOuput(String.Format("\r\n  Crust = {0}.", crust));
        }

        if (e.Result.Semantics.ContainsKey("topping"))
        {
            topping = e.Result.Semantics["topping"].Value.ToString();
            AppendTextOuput(String.Format("\r\n  Topping = {0}.", topping));
        }
    }
    String sOutput = String.Format("\r\nRecognized: You have orderd a {0}, {1}, {2} pizza.", size, crust, topping);
    AppendTextOuput(sOutput);
}

AppendTextOuput is just my own little output string method.

This seemed like a lot of work to explicitly layout all the possible permutations in the grammar. But, it works really well.

As you can see, I ended up avoiding the issue of having the grammar provide the default and simply built it into the event handler. There is probably a better way.

One other step to learn more is to use the SrgsDocument.WriteSrgs() method and write out an SRGS XML document that represents the grammar. The rule and semantic tags are much easier to visualize in XML.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文