四、简单的语音交互

如果你能和你的移动设备通话,向它询问信息或者让它做点什么,那不是很好吗?本章着眼于简单的语音交互,让你做到这一点。两个教程示例将向您展示如何实现查询来搜索信息以及请求在您的设备上启动一个应用。

语音识别并不完美,因此实施一些机制来选择最佳的识别结果是有趣的。在前几章中,我们研究了如何获得置信度。在本章中,我们将介绍两种新的机制:将识别的输入与用户所说的进行比较的相似性度量,以及直接询问用户系统是否理解正确的确认。

到本章结束时,您应该能够开发简单的语音交互来请求信息并在设备上执行命令。您还应该知道如何使用相似性度量并确认用户所说的内容。

语音交互

正如第 1 章在安卓设备上的发言中所讨论的,谷歌语音动作是在中的简单交互,用户说出一个问题或命令,应用以动作或口头回应(或两者的组合)进行回应。

以下是具有简单结构并涉及少量转弯的类似相互作用的示例:

例 1

用户:英国广播公司新闻

App:(推出 BBC 新闻)

例 2

App:你的疑问是什么?

用户:法国的首都是哪里?

App:(返回关于巴黎和法国的网页)

交互很简单如下:

  • 有限对话管理:交互最多两三次。
  • 有限的口语理解:用户受限于由单个单词或短语组成的输入,例如网站或应用的名称,或者可以由谷歌搜索引擎处理的一段文本。

语音搜索应用

本 app 说明如下:

  1. 当点击按钮说出选项时,提示用户说一些话。
  2. 用户说一些话。
  3. VoiceSearch基于用户说出的单词发起搜索查询。

开始屏幕有一个按钮,要求用户按下并说话。按下按钮,下一屏显示谷歌语音提示你的查询是什么?结果显示在浏览器窗口中。

在这种情况下,app 使用之前开发的两个库:TTSLib(参见第二章文本到语音合成)和ASRLib(参见第三章语音识别)。他们的jar文件包含在VoiceSearch项目的libs文件夹中。ASR 方法用于识别用户输入并将其用作搜索标准。TTS 用于向用户提供关于应用状态的口头反馈。

该应用结合了已经为TTSWithLib ( 第 2 章文本到语音合成)和ASRWithLib ( 第 3 章语音识别)应用提供的代码。它在TTSWithLib中使用了一个 TTS 实例,在ASRWithDemo中使用了相同的 ASR 方法。它还通过改变按钮的颜色和文本来提供关于应用是否在听用户说话的视觉反馈。

一旦人工智能产生结果,它就被用来使用网络搜索意图进行谷歌搜索,如 processAsrResults方法所示:

public void processAsrResults(ArrayList<String> nBestList, float[] nBestConfidences) {
      String bestResult = nBestList.get(0); 
      indicateSearch(bestResult); //Provides feedback to the user that search 
      //is going to be started 
      //Carries out a web search with the words recognized 
      Intent intent = new Intent(Intent.ACTION_WEB_SEARCH); 
      intent.putExtra(SearchManager.QUERY, bestResult); 
      startActivity(intent); 
}

可以观察到,应用总是使用最佳结果启动网络搜索。然而,系统可能会误解用户所说的话,在这种情况下,启动的搜索将是不正确的。为了避免这种情况,可以使用确认。本章末尾将介绍确认书和使用VoiceSearch应用的简单示例。

语音启动应用

该应用的功能如下:

  1. 点击按键说话按钮时,会提示用户输入某个应用的名称。
  2. 用户说出应用的名称。
  3. VoiceLaunch将识别的输入与设备中安装的所有应用的名称进行比较,并启动名称最相似的应用。

VoiceLaunch这样的应用不需要任何界面,因为用户可以说出他们想要启动的应用的名称。但是,为了便于说明,我们创建了一个简单的界面,用户可以在其中选择两个参数的值:相似性阈值和相似性标准,如下图所示。截图显示了用户要求发送邮件的场景。VoiceLaunch显示图中屏幕,启动 邮件应用(相似度最高的那个,本例中为 1.00 ):

VoiceLaunch app

我们已经引入了相似性准则的技术来展示如何改进来自 ASR 的结果。例如,当您有一个想要识别的关键词列表,但您不能限制 ASR 只听那些单词时,识别结果可能与您期望的关键词不完全相同。例如,如果你的关键词是冰淇淋口味,你可以考虑巧克力草莓香草,但如果你的 ASR 不受限制,那么草莓的识别结果可能是蔓越莓。如果你的应用期望一个精确的匹配,它会放弃识别结果。然而,通过相似性度量,你的应用会知道用户说了类似于草莓的话。

VoiceLaunch中,相似性标准用于控制应用如何测量识别的名称和安装在设备中的应用的名称之间的相似性。采用相似性阈值,使得如果应用的名称与从用户输入中识别出的名称不够相似,则不启动该应用。

我们考虑以下两个选项来计算相似度:

  • 正字法相似度 : VoiceLaunch计算单词之间的莱文斯坦距离。该度量标准将单词 A 和 B 之间的距离视为必须在 A 中执行的字符插入、删除或替换的最小数量,以获得 B。VoiceLaunch将距离值转换为 0 到 1 之间的相似度值。
  • 语音相似度 : VoiceLaunch使用 Soundex 算法计算姓名之间的语音相似度。所使用的实现只对英语有效,这就是为什么VoiceLaunch app 只提供这种语言。这样,即使拼写不同,听起来相同的单词也会被认为是相似的。相似性也是使用从 0 到 1 的间隔来测量的。

考虑的距离有许多替代方案:欧几里德距离、雅克卡索引、海明距离、索伦森相似性索引或隐喻。

通常同音字的有相似的拼写,所以正字法和语音相似度的值几乎是一样的,比如了,或者面粉了。可以观察到,在处理 ASR 结果时,语音相似性更方便,而在处理拼写错误更频繁的文本的结果时,拼写相似性更好。下表显示了一些示例:

|

相似性标准

|

示例单词对

| | --- | --- | |   | 添加–版本 | 鲜花粉 | 平面–平面 | 浏览器-邮件 | | 正字法相似性 | Zero point seven five | Zero point six six | Zero point six | Zero | | 语音相似性 | Zero point seven five | One | One | Zero |

这本书的网页上有一个制作测试的小型 Java 项目。您可以使用ComparisonTest java 项目进行自己的测试。为了使用它,您必须包含 Soundex 的 apache 库,并包含要作为运行参数进行比较的单词。要使用 Eclipse 包含库,右键单击项目 | 属性 | | 添加外部 JARs 。要运行项目,右键单击运行为 | 运行配置,在程序参数下的参数选项卡中,包括用空格分隔的两个字(例如to too)。

处理 ASR 和 TTS 的代码类似于VoiceSearch应用。但是,识别完成后,VoiceLaunch必须找到与用户识别出的词相似的应用,并启动最相似的应用。这是在processAsrResults方法中完成的(请看一下VoiceLaunch项目下VoiceLaunch.java文件中的代码包),它调用了方法getSimilarAppsSortedlaunchApp ,这将在后面的页面中描述。

类型

你有没有注意到……

在所有应用中使用 ASR 库使它们能够具有类似的结构,其中识别信息的处理以processAsrResults方法进行。例如,在VoiceSearch应用中,它以公认的标准开始搜索,而在VoiceLaunch中,它获得已安装的相似应用列表,并启动最相似的应用。

此外,VoiceLaunch必须存储和管理设备上可用应用的信息。为了在不损失代码易读性的情况下高效地做到这一点,我们创建了一个名为 MyApp的辅助类(您可以在代码包中找到它,在VoiceLaunch项目下的VoiceLaunch.java中),其中我们为每个应用保存了它的用户友好名称(例如,Adobe Reader)、它的安卓可识别的包名称(例如,com.adobe.reader)以及它与用户输入的相似性(例如,0 到 1 的值,0.7)。

由于有必要对已安装的应用进行排序,我们还为MyApp类的对象定义了一个比较器。如果第一个元素小于第二个元素,比较器返回负数,如果它们相等,则返回 0,如果第一个元素大于第二个元素,则返回正数。然后可以使用它们从最小值到最大值对集合进行排序。在我们的例子中,我们希望从最高到最低的相似度对MyApps的集合进行排序。因此,我们将相似度值比较器的结果乘以-1,得到相反顺序的结果:

private class AppComparator implements Comparator<MyApp>{ 
    @Override 
    public int compare(MyApp app1, MyApp app2) { 
      return (- Double.compare(app1.getSimilarity(), app2\. getSimilarity())); // Multiply by -1 to get reverse ordering (from most to least similar) 
    } 
}

如前所述,VoiceLaunch使用方法getSimilarAppsSorted 获取设备中按相似度排序的应用列表,但它只考虑那些与识别名称相似度高于指定阈值的应用。

从代码包中可以看出(在VoiceLaunch项目下的VoiceLaunch.java中),该过程通过以下步骤进行:

  1. 从软件包管理器中检索所有已安装应用的列表。
  2. 对于列表中的每个应用,使用用户在图形用户界面中选择的算法计算其与识别名称的相似度。如果获得的相似度值高于阈值,则通过创建MyApp类的实例来保存应用的名称、包名和相似度值,该实例被添加到 similarApps集合中。
  3. similarApps集合使用我们的相似性比较器进行排序:Collections.sort(similarApps, new AppComparator());
  4. 信息保存在日志中,这样开发者就可以知道哪些应用是根据相似性考虑的。

    ```java public void processAsrResults(ArrayList nBestList, float[] nBestConfidences) {

      //Obtains the best recognition result 
      String bestResult = nBestList.get(0);
    
      //Read the values for the similarity parameters from the GUI 
      readGUIParameters(); 
      //Obtains the apps installed in the device sorted from most to least similar name regarding the user input
    
      //String[] = [0] = name, [1] = package, [2] = similarity 
      ArrayList<MyApp> sortedApps = getSimilarAppsSorted(bestRes ult);
    
      //Shows the matching apps and their similarity values in a list 
      showMatchingNames(sortedApps);
    
      //Launches the best matching app (if there is any) 
      if(sortedApps.size()<=0) 
      { 
          Toast toast = Toast.makeText(getApplicationContex t(),"No app found with sufficiently similar name", Toast.LENGTH_ SHORT); 
          toast.show(); 
          Log.e(LOGTAG, "No app has a name with similarity > 
          "+similarityThreshold); 
      }
      else 
          launchApp(sortedApps.get(0));
    

    } ```

类型

也可以试试…

可以使用额外的方法,使得系统不选择相似性度量之一,而是考虑两种方法的结果来选择最相似的应用,例如,使用加权投票方法。

根据所采用的相似性算法,getSimilarAppsSorted调用以下方法之一:compareOrthographiccomparePhonetic (参见代码包中VoiceLaunch项目下的VoiceLaunch.java)。前者使用 Levenshtein 度量计算正字法距离,后者使用 Soundex 算法计算语音距离。

为了计算 Levenshtein 距离,我们使用com.voicedemos包中的LevenshteinDistance.java类。它基于 wikibooks 提出的代码,可在http://en . wikibooks . org/wiki/Algorithm _ Implementation/Strings/Levenshtein _ distance # Java上获得,我们在其中添加了代码,将距离转换为 0 到 1 之间的相似值。

为了计算语音距离,我们使用了 Apache Commons 在 http://commons.apache.org/proper/commons-codec/index.html 提供的 Soundex 实现。为此,我们在VoiceLaunch项目的libs文件夹中添加了commons-code-1.8 lib对应的jar文件。

两种相似度计算方法的输入参数都是两个字符串,分别对应考虑的 app 名称和识别的输入。这些字符串以前是通过删除空格和使用小写字母来规范化的:

    private String normalize(String text){
        return text.trim().toLowerCase();
    }

为了应对用户只说出两个单词名字中的一个单词的情况,可以执行更复杂的规范化,例如, kindle 而不是 kindle reader

一旦应用被订购,最相似的应用将使用launchApp方法启动,该方法使用带有应用包名的launchintent (您可以在代码包中的VoiceLaunch.java文件中找到它)。

语音搜索确认应用

确认是交易对话的一个非常重要的方面,在服务交易中也被人们广泛使用,以确保一切都被正确理解。由于目前的语音识别技术不能保证应用完全听到用户说的话,因此应用应该确认用户想要什么,尤其是如果下一个动作可能导致不可恢复的后果。然而,确认应该被明智地使用,因为它们延长了交互,如果它们被过度使用,可能会让用户感到讨厌。

VoiceSearchConfirmation应用的功能与VoiceSearch相同,但它会在执行搜索前确认搜索标准。两个与该应用的交互示例如下:

  • 确认场景 : 该场景的特征在于以下步骤:
    1. 用户按下按钮说话,并说贝尔法斯特的天气
    2. 系统了解贝尔法斯特的天气并询问你说的是贝尔法斯特的天气吗?
    3. 用户按下按钮通话并说
    4. 系统以贝尔法斯特天气为标准启动搜索。
  • 否定场景:是特征如下步骤:
    1. 用户按下按钮说话,并说【格拉纳达的天气】。
    2. 系统了解加拿大天气并询问你说的是加拿大天气吗?
    3. 用户按下按钮通话并说
    4. 对话返回到步骤 1,直到用户满意为止。

只要自动驾驶仪从用户输入中识别出什么,就会调用processResults方法。因此,为了向应用提供确认能力,有必要区分该方法是在识别搜索标准之后被调用的,还是它从确认请求中识别出是/否响应的。为了做到这一点,我们引入了新的属性 searchCriterion,它存储了已识别的标准。如果它为空,我们尝试识别新的标准,如果不是,我们确认它的值。您可以查看代码包的VoiceSearchConfirmation项目下的VoiceSearchConfirmation.java文件中的代码。

类型

其他相似性度量和技术

格雷格·米莱特(Greg Milette)和亚当·斯特劳德(Adam Stroud)在名为《专业安卓传感器编程》(T0)的书中描述了增强谷歌语音识别器返回的结果的其他相似性度量和技术。讨论的技术包括:

使用词干来改进单词识别,也就是说,通过删除后缀来减少单词的词根,例如,减少走、走、走和走到同一个词根。

语音索引,即匹配发音相似的单词,例如,如果识别器返回发音相似的单词上诉,则能够返回 apple

使用 Lucene 进行匹配,Lucene 是为搜索文本而设计的搜索引擎库。

总结

在这一章中,我们展示了如何使用谷歌语音识别和 TTS APIs 开发简单的语音交互。第一个例子展示了如何从用户那里获得一些单词的输入并启动搜索查询。第二个例子涉及使用语音在设备上启动应用。这里我们介绍了使用相似性度量来比较用户输入的识别和可能已经说过的内容的技术。举例说明了两种不同的度量:正字法相似性和语音相似性。最后一个例子展示了如何使用确认来检查用户系统是否正确识别了输入。这些技术,以及前一章中介绍的置信度得分的使用,是开发支持语音的应用的有用工具。

然而,这些相互作用在两个方面受到限制。首先,它们不涉及使用对话状态信息来控制交互和确定应用应该说什么和做什么。该应用的行为在特定的语音动作中被硬编码。其次,交互将用户限制为简单的一个单词或一个短短语输入。更复杂的对话需要对话状态的表示和更高级的口语理解。第 5 章填表对话展示了如何包含对话状态的表示,以便提供更灵活的对话管理,而第 6 章对话语法展示了如何使用语法来实现更高级的口语理解。

就确认而言,对于只需确认一条数据的情况,我们给出了一个非常天真的解决方案。在接下来的章节中,我们将研究如何创建一种更复杂的行为,在这种行为中,可以确认几条数据以及考虑到识别置信度的确认策略。我们还将介绍一种无需按下按钮就能说话的方法。