65.9K
CodeProject 正在变化。 阅读更多。
Home

制作一个从外部文件读取命令的 Jarvis

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.40/5 (3投票s)

2015年8月20日

CPOL

4分钟阅读

viewsIcon

26680

downloadIcon

1749

制作一个从外部文件读取命令的 Jarvis

本文解决了语音识别程序员在处理包含数十个单词或短语的语法时面临的问题;它加载两个外部文本文件:一个用于命令列表,另一个用于根据命令执行的操作。

背景

本文理想地集成了任何语音识别文章(例如 MSDN 目录或 C.P. 中存在的文章)。

使用代码

本文使用了自 Windows 7 Enterprise(某些版本)以来提供的 System.Speech 功能,并在 Windows 8.x 中进行了改进;SpeechRecognitionEngine 用于根据基于外部文件构建的语法识别口语。

本文使用 VB.NET 处理该问题(该项目是使用 Visual Basic 2010 XE 创建的)。

程序中的第一步是导入我们在编程过程中需要的功能。

Imports System.Speech
Imports System.Speech.Recognition
Imports System.Runtime.InteropServices
Imports System.IO
Imports System.Net

请注意,System.Speech 也应添加为引用。

主类包含几乎所有代码,分为两个部分:'_Load' 和 '_SpeechRecognized' 事件。

在编写这两个主要事件之前,我们需要通过全局变量完成一些设置,并且需要实现识别引擎。

Public Class Vera

Dim WithEvents reco As New Recognition.SpeechRecognitionEngine
   
    Dim commandset() As String
    Dim cmdList As New GrammarBuilder

Load 事件中,我们添加了处理命令集、语法以及对命令的识别/响应的所有代码。

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim npath As String = Application.StartupPath & "\commandlist.txt"
        Dim nsr As StreamReader = File.OpenText(npath)
        Dim i As Integer
        Dim ls As String
        For Each ls In File.ReadLines(npath)
            ReDim Preserve commandset(i)
            commandset(i) = ls
            i += 1
            ListBox1.Items.Add(ls)
            Application.DoEvents()
        Next
        
        reco.SetInputToDefaultAudioDevice()

        cmdList.Append(New Choices(commandset))
        reco.LoadGrammar(New Recognition.Grammar(cmdList))
        reco.RecognizeAsync()
End Sub

如代码所示,表单必须包含一个 ListBox,其中将加载所有命令以供参考;这避免了将所有命令保存在内存中或打开命令列表文件。

commandlist.txt 文件仅包含命令,每行一个,没有空格或空行,例如:

hello computer
what is the timer?
What is your name?
Open chrome
Go full screen
[…]

下一步是设置计算机在识别出包含在 *commandlist.txt* 文件中的命令时必须执行的操作;这在 Reco 对象的 _SpeechRecognized 事件中实现。

实际上,在本示例中,我们使用基于两个事件的方法:RecognizeCompleteSpeechRecognized

第一个只是告诉计算机异步启动另一个识别。

Private Sub reco_RecognizeCompleted(ByVal sender As Object, ByVal e As System.Speech.Recognition.RecognizeCompletedEventArgs) Handles reco.RecognizeCompleted

        reco.RecognizeAsync()
End Sub

第二个将处理所有命令/操作,并将使用 Reco 对象的 SpeechRecognized 事件。这段长代码是程序的“核心”。

在本示例中,我们提供了一种简单但非常有用的方法,该方法基于以下列方式构造的外部文件。

command^action1^commandtype^action2

例程生成的随机数将用于随机允许计算机执行 action1 或 action2;这对于社交命令特别有用,我们可能希望将更多答案与同一命令关联。

这是文件的一个示例(命名为:commandactionlist.txt)

hello vera^Hello creator, how are you?^social^Good morning master, I am ready to operate

honey are you there?^of course I am... where else should i be?^social^Here and running

where are you vera?^come find me, creator!^social^That is a very stupid question! I am trapped in this goddamn computer

open my computer^explorer.exe^comando^noaction

open chrome^chrome.exe^comando^noaction

close chrome^chrome.exe^comando^noaction

open wordpad^wordpad.exe^comando^noaction

navigate to facebook^www.facebook.com^website^noaction

navigate to hotmail^www.hotmail.com^website^noaction

navigate to twitter^http://twitter.com^website^noaction

show commands^noaction^internal^noaction

hide commands^noaction^internal^noaction

go full screen^noaction^internal^noaction

goodbye^It's been a pleasure,^internal^noaction

从代码可以看出,在这种方法中,我们在字符串(commandtype)的第 3rd 个位置使用了四种可能的选择:social、comando、website、internal。

“social”命令类型将仅用于与计算机聊天,计算机不执行任何实际操作,因此 action1 和 action2 将是计算机回答口语命令的 2 个可能的句子;“comando”命令类型将用于处理 windows 已安装程序上的操作,例如在示例中打开写字板等,在这种情况下,我们只需要 action1,因此 action2 设置为中性值;“website”命令类型在形式上与“comando”类型相同,只不过我们传递的是网站地址而不是 exe 文件;“internal”命令类型用于对程序本身进行操作,在上面的例子中,我们使用它来显示和隐藏命令列表框,并将表单设置为全屏。

现在让我们首先看看随机生成。

Public Function getrandom(ByVal min As Integer, ByVal max As Integer) As Integer
        Static generator As System.Random = New System.Random()
        Return generator.Next(min, max)
    End Function

现在我们可以处理四种命令类型。请注意,由于该程序具有社交功能,因此它使用语音合成引擎与用户交互。

Private Sub reco_SpeechRecognized(ByVal sender As Object, ByVal e As System.Speech.Recognition.RecognitionEventArgs) Handles reco.SpeechRecognized
        Dim response As String = ""
        Dim synth As New Synthesis.SpeechSynthesizer
        Dim npath As String = Application.StartupPath & "\commandactionlist.txt"
        Dim nsr As StreamReader = File.OpenText(npath)
        Dim ls As String

以上部分使用与命令列表相同的过程来加载命令/操作文件;这将使用 ^ 作为分隔符将其组件拆分为一个数组进行解析,并且将应用随机数生成来决定必须执行什么操作(这仅对“社交”命令有效)。

        Dim params(3) As String
        Dim execute = e.Result.Text.ToLower
        Dim answer As String = ""
        For Each ls In File.ReadLines(npath)

            Dim value As Integer = getrandom(0, 6)
            params = ls.Split("^"c)
            Dim Command As String = params(0).ToLower
            Dim comtype As String = params(2)
            If comtype = "social" Then

                If value <= 3 Then
                    response = params(1)
                ElseIf value > 3 Then
                    response = params(3)
                End If

            Else
                response = params(1)

            End If
            Dim Action As String = response


            If execute.Contains(Command) And comtype = "social" Then
                Dim robotvoice = CreateObject("sapi.spvoice")
                answer = Action
                robotvoice.Speak(answer)

            ElseIf execute.Contains(Command) And comtype = "comando" Then
                Dim robotvoice = CreateObject("sapi.spvoice")

                If execute.Contains("open") Then
                    answer = "Opening application"
                    robotvoice.Speak(answer)
                    Process.Start(Action)
                ElseIf execute.Contains("close") Then
                    answer = "Closing application"
                    robotvoice.Speak(answer)
                    For Each myprocess As Process In Process.GetProcessesByName(Action)
                        myprocess.CloseMainWindow()
                    Next

                ElseIf execute.Contains(Command) And comtype = "website" Then

                    Try
                        If My.Computer.Network.IsAvailable = True Then

                            answer = "Website is opening in a while"
                            robotvoice.Speak(answer)
                            Process.Start(Action)

                        Else

                            answer = "It looks like there is no Internet connection available"
                            robotvoice.Speak(answer)
                        End If
                    Catch ex As Exception

                    End Try

                End If


            ElseIf execute.Contains(Command) And comtype = "internal" Then
                Dim robotvoice = CreateObject("sapi.spvoice")
                answer = "Ok Creator"
                robotvoice.Speak(answer)
                If Command = "show commands" Then
                    ListBox1.Visible = True

                ElseIf execute.Contains("goodbye") Then
                    answer = Action
                    robotvoice.Speak(answer)
                    reco.UnloadAllGrammars()
                    reco.RecognizeAsyncStop()
                    reco.Dispose()

                    Me.Close()


                ElseIf Command = "hide commands" Then
                    ListBox1.Visible = False


                ElseIf Command = "go full screen" Then
                    Me.WindowState = FormWindowState.Maximized


                End If
                Application.DoEvents()
            End If

        Next

    End Sub

最后一步当然是关闭类。

End Class

关注点

编写此代码的主要兴趣点是当我尝试使用不同的表单使程序处理更复杂的操作(例如处理媒体文件)时。困扰我的一个功能是,当程序说长句子(15 个或更多单词)时,程序会停止所有其他操作。例如,我的程序还包含一个每秒刷新一次的时钟,以及一个“演示”内部命令,使 PC 说“我的名字是 Vera,我是一个语音识别软件,可以处理不同类型的命令并进行社交互动”。当你要求电脑自我介绍时,时钟就会停止。

我将研究这个问题,并希望找到解决方案。

© . All rights reserved.