自定义语音识别规则

来源:CSDN 发布时间:Nov 15, 2020, 5:51:40 PM 原地址:https://blog.csdn.net/qq_41708190/article/details/109699550

添加自定义规则的方法是将实现了ISpeechRecognitionConstraint接口的语法约束实例添加到SpeechRecogtnizer对象的Constraints集合中,这些类型包括:

  • SpeechRecognitionGrammarFileConstraint: 通过自定义的SGRS(Speech Recognition Grammer Specification)文件来定义语法规则。SGRS文件实质上是一个XML文件,而且需要遵循W3C组织制定的与语音识别相关的语法标准。
  • SpeechRecognitionListConstraint: 设定一系列短语,在接收语音时,用户必须说出短语列表中所指定的任意一个关键词才能正确识别。
  • SpeechRecognitionTopicConstraint: 设置识别模式和主题。识别模式分为"听写模式"和"搜索模式",主题是由开发者所指定的一个字符串,如"人名"、“天气”等。该约束只是为了提高语音识别的精确率而设的,它不直接控制识别过程中的语法规则。
  • SpeechRecognitionVoiceCommandDefinitionConstraint: 该类没有构造函数,不直接使用。该约束只在通过由VCD(Voice Command Definition)文件所定义的语音指令激活应用程序时才会使用,可以访问SpeechRecognitionResult对象的Constraint属性来获取SpeechRecognitionVoiceCommandDefinitionConstraint实例。

另外,还需要注意的是,如果Constraints集合中已添加了一个SpeechRecognitionTopicConstraint约束后,同一集合中只能添加SpeechRecognitionGrammarFileConstraint类型的约束。简而言之,就是SpeechRecognitionTopicConstraint和SpeechRecognitionGrammarFileConstraint可以配合使用。

1. 自定义SGRS文件

本小节将通过一个例子来帮助读者初步掌握如何使用SRGS文件来约束语音识别的结果。当识别系统应用了自定义的SRGS文件后,语音识别过程只遵循SRGS文件中定义的规则,如果用户说出的内容不符合SRGS文件中的规则,那么语音识别系统将无法正确识别,至少识别的准确性会很低。

首先,需要编写一个SRGS文件,该文件实质上是一个XML文件,因此只需要向应用项目中添加一个新的XML文件即可。

默认情况下,新的XML文件添加后会自动用XML文档编辑窗口打开,此时,打开"属性"窗口,单击"架构"右边的省略号按钮,。随后会打开一个窗口,用来选择该XML文档将用到哪些XML架构文件。找到命名空间 http://www.w3.org/2001./06/grammar,然后单击其所在行最左边的单元格,从下拉菜单中选择"使用该架构"。

进行以上操作是为了在编写SRGS文档的时候让Visual Studio给出智能提示,可以提升SRGS文档的准确性和编写效率。

在刚才新建的XML文档中输入以下内容:

<?xml version="1.0" encoding="utf-8" ?>
<grammar xmlns="http://www.w3.org/2001/06/grammar" tag-format="semantics/1.0" version="1.0" xml:lang="zh-cn" root="color">
  <rule id="color">
    <item repeat="0-1">把</item>
    <item>颜色</item>
    <one-of>
      <item>改为</item>
      <item>设置为</item>
    </one-of>
    <one-of>
      <item>红色</item>
      <item>白色</item>
      <item>蓝色</item>
    </one-of>
  </rule>
</grammar>

从上面的XML文档中可以看出,SRGS文档的根元素为grammar,并为该元素指定以下属性:

  • xmlns: XML文档的命名空间,必须设置为 http:///www.w3.org/201/06/grammar。
  • tag-forfmat: tag元素的语法格式,本文档中并未使用tag元素,因此该值可以不考虑。
  • version: 必须指定为1.0。
  • xml: lang: 文档所使用的区域和语言,zh-cn表示简体中文。
  • root: 必须指定SRGS文档中某一条语法规则的名字,此规则在SRGS被加载时将作为默认规则使用。如果不设置该值,SRGS文档可以正常编译,DNA语音识别引擎不会进行识别。该文档中只有一条名为color的规则,因此root的值也应该为color。

在grammar元素下可以使用rule元素来定义规则,每个rule元素表示一条规则,必须通过id属性设置规则的名字,而且该名字在整个SRGS文档中也应该时唯一的,不能出现重复的规则名字。

随后,在rule元素之下,可以使用item元素来定义一个短语,短语可以是任意的合法的字符串。该字符串指定语音识别引擎应该听到的内容。如果使用了one-of元素,则表明one-of元素下的item元素中所指定的短语只能识别一条。例如上面SRGS文档中最后一个one-of元素如下:

    <one-of>
      <item>红色</item>
      <item>白色</item>
      <item>蓝色</item>
    </one-of>

这表明,识别引擎只能侦听以上列出的颜色短语,其他内容则不会被正确识别。

上面的SRGS文档中第一个item元素(即“把”字短语所在的元素)设置了repeat=="0-1",表示用户在说话时,可以说出"把"字,也可以不说出,因为"把"字短语的出现次数被指定为0到1个,要么出现0次,要么出现1次,表示该短语是可选的。

SRGS文件编写完成后,需要设计示例程序的用户界面,核心的XAML代码如下:

    <StackPanel>
        <Button x:Name="btn" Content="开始说话" Tapped="tbn_Tapped"/>
        <TextBlock TextWrapping="Wrap" FontSize="20"/>
        <TextBlock x:Name="tbRes" FontSize="24" TextWrapping="Wrap"/>
    </StackPanel>do

处理按钮的Click事件,并将识别的结果显示在TextBlock控件中。

        private async void tbn_Tapped(object sender, TappedRoutedEventArgs e)
        {
            btn.IsEnabled = false;
            using (SpeechRecognizer recognizer = new SpeechRecognizer())
            {
                try
                {
                    //加载语法文件
                    var sgrsFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///srgs.xml"));
                    //创建识别约束
                    SpeechRecognitionGrammarFileConstraint grammarFileConstraint = new SpeechRecognitionGrammarFileConstraint(sgrsFile);
                    //加入到约束集合中
                    recognizer.Constraints.Add(grammarFileConstraint);
                    //编译约束
                    SpeechRecognitionCompilationResult compilationResult = await recognizer.CompileConstraintsAsync();
                    if (compilationResult.Status == SpeechRecognitionResultStatus.Success)
                    {
                        //开始识别
                        SpeechRecognitionResult result = await recognizer.RecognizeAsync();
                        if (result.Status == SpeechRecognitionResultStatus.Success)
                        {
                            tbRes.Text = $"识别结果:{result.Text}";
                        }
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
            }
            btn.IsEnabled = true;
        }

先通过StorageFile.GetFileFormApplicationUriAsync静态方法从项目目录中加载SRGS文件,接着创建SpeechRecognitionGrammarFileConstraint实例,并把SRGS文件传递到它的构造函数中,完成初始化。

然后将SpeechRecognitionGrammarFileConstraint实例添加到Constraints集合中,再调用COmpileConstraingtsAsync方法编译所有语音识别的约束对象。最后就可以调用RecognizeAsync方法开始识别了。

2. 短语列表约束

SpeechRecognitionListConstraint类允许开发者使用一个字符串列表(如一个字符串数组)来约束语音识别的过程。当该约束被添加到识别组件的约束集合中后,语音识别引擎只会侦听字符串列表中出现的短语。

下面通过一个示例来演示一下如何使用短语列表来约束语音识别的过程。

用户界面布局请参考以下XAML代码来完成:

    <StackPanel>
        <TextBlock Text="请说出你最喜欢的体育运动:"/>
        <Button Content="开始识别" Width="200" Tapped="Button_Tapped"/>
        <ListBox x:Name="listBox">
            <x:String>足球</x:String>
            <x:String>排球</x:String>
            <x:String>跑步</x:String>
            <x:String>羽毛球</x:String>
            <x:String>橄榄球</x:String>
            <x:String>结束</x:String>
        </ListBox>
    </StackPanel>

稍后使用的约束列表与ListBox中的子项相同,当用户说出列表中的第一个项时,ListBox控件会选中该项。

以下代码初始化语音识别引擎,并添加作为约束的短语列表。

        private async void Page_Loaded(object sender,object e)
        {
            _recognizer = new SpeechRecognizer();
            //创建自定义短语约束
            string[] arrgy = { "足球", "排球", "跑步", "羽毛球", "橄榄球","结束" };
            SpeechRecognitionListConstraint listConstraint = new SpeechRecognitionListConstraint(arrgy);
            //添加约束实例到集合中
            _recognizer.Constraints.Add(listConstraint);
            //编译约束
            await _recognizer.CompileConstraintsAsync();
        }

 

        private void Page_UnLoaded(object sender, RoutedEventArgs e)
        {
            //释放资源
            _recognizer.Dispose();
        }

处理按钮的Click事件,开始语音识别:

        private async void Button_Tapped(object sender, TappedRoutedEventArgs e)
        {
            try
            {
                while (true)
                {
                    SpeechRecognitionResult result = await _recognizer.RecognizeAsync();
                    if (result.Status == SpeechRecognitionResultStatus.Success)
                    {
                        //处理识别结果
                        listBox.SelectedItem = result.Text;
                        if (result.Text == "结束")
                        {
                            return;
                        }
                    }
                }

            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
            }
        }

要让ListBox选中某个项,只需要设置其SelectedItem属性引用要选中的字符串即可,在以上代码中,直接将语音识别的结果赋值给SelectedItem属性就可以了。

运行应用程序,单击"开始识别"按钮,然后说出ListBox控件中的其中一个子项,当识别成功后,被说出的项会处于选中状态。