我想在我的家庭自动化应用程序中加入连续(免提)语音命令识别

2023-12-30

我创建了一个简单的 Android 应用程序来控制连接到我的 Raspberry Pi 的继电器。我使用按钮以及基本的语音识别来触发这些按钮并打开/关闭相应的中继通道。

到目前为止,语音识别部分是由 RecognizerIntent 处理的,其中我需要按下应用程序上的按钮来打开 Google 语音提示,该提示会监听我的语音命令并激活/停用控制继电器开关的相应按钮。

我想做同样的事情连续语音识别允许应用程序连续听取我的命令,而无需用户按下应用程序上的按钮,从而允许免提操作。

这是我现有的代码,一种非常简单的语音识别方法,它允许我打开和关闭连接到继电器的各种设备的按钮:

public void micclick(View view) {
        if(view.getId()==R.id.mic)
        {promptSpeechInput();}
}

private void promptSpeechInput() {
    Intent i= new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
    i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
    i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
    i.putExtra(RecognizerIntent.EXTRA_PROMPT,"Speak!");
    try{
        startActivityForResult(i,100);

    }
    catch (ActivityNotFoundException a)
    {
        Toast.makeText(MainActivity.this,"Sorry your device doesn't support",Toast.LENGTH_SHORT).show();
    }
}
public void onActivityResult(int requestCode, int resultCode, Intent i) {
    super.onActivityResult(requestCode, resultCode, i);
    String voicetxt;
    switch (requestCode) {
        case 100:
            if (resultCode == RESULT_OK && i != null) {
                ArrayList<String> result2 = i.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
                voicetxt = result2.get(0);
                if (voicetxt.equals("fan on")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton1.setChecked(true);
                    result.append("Fan: ").append(toggleButton1.getText());
                    sc.onRelayNumber="a";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("fan of")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton1.setChecked(false);
                    result.append("Fan: ").append(toggleButton1.getText());
                    sc.onRelayNumber = "a_off";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("light on")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton2.setChecked(true);
                    result.append("Light: ").append(toggleButton2.getText());
                    sc.onRelayNumber = "b";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("light off")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton2.setChecked(false);
                    result.append("Light: ").append(toggleButton2.getText());
                    sc.onRelayNumber = "b_off";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("air conditioner on")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton3.setChecked(true);
                    result.append("AC: ").append(toggleButton3.getText());
                    sc.onRelayNumber = "c";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("air conditioner of")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton3.setChecked(false);
                    result.append("AC: ").append(toggleButton3.getText());
                    sc.onRelayNumber = "c_off";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("heater on")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton4.setChecked(true);
                    result.append("Heater: ").append(toggleButton4.getText());
                    sc.onRelayNumber = "d";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
                if (voicetxt.equals("heater off")) {
                    StringBuffer result=new StringBuffer();
                    toggleButton4.setChecked(false);
                    result.append("Heater: ").append(toggleButton4.getText());
                    sc.onRelayNumber = "d_off";
                    new Thread(sc).start();
                    Toast.makeText(MainActivity.this, result.toString(),Toast.LENGTH_SHORT).show();
                }
            }
            break;
    }
}

我想无需按下按钮即可实现相同的功能。请注意,我是 Android 应用程序开发新手。如果可能的话,请描述外部库的使用情况(如果需要),因为我认为 Google 的 RecognizerIntent 无法实现连续识别。我推测我可能需要包含类似的库CMUS狮身人面像,但我不知道该怎么做。


对于连续识别/听写模式,您可以执行多种操作。您可以使用Android本身的谷歌语音识别功能,不建议连续识别(如上所述https://developer.android.com/reference/android/speech/SpeechRecognizer.html https://developer.android.com/reference/android/speech/SpeechRecognizer.html)

该 API 的实现可能会将音频流传输到远程 服务器来执行语音识别。因此这个 API 不是 旨在用于连续识别,这将消耗 大量的电池和带宽。

但如果您确实需要它,可以通过创建自己的类并继承 IRecognitionListener 来解决。 (我在xamarin-android上写的,语法与原生android非常相似)

public class CustomRecognizer : Java.Lang.Object, IRecognitionListener, TextToSpeech.IOnInitListener
{
    private SpeechRecognizer _speech;

    private Intent _speechIntent;


    public string Words;


    public CustomRecognizer(Context _context)
    {
        this._context = _context;
        Words = "";
        _speech = SpeechRecognizer.CreateSpeechRecognizer(this._context);
        _speech.SetRecognitionListener(this);
        _speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
        _speechIntent.PutExtra(RecognizerIntent.ExtraLanguageModel, RecognizerIntent.LanguageModelFreeForm);
        _speechIntent.PutExtra(RecognizerIntent.ActionRecognizeSpeech, RecognizerIntent.ExtraPreferOffline);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1000); 
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1000);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 1500);
    }

    void startover()
    {
        _speech.Destroy();
        _speech = SpeechRecognizer.CreateSpeechRecognizer(this._context);
        _speech.SetRecognitionListener(this);
        _speechIntent = new Intent(RecognizerIntent.ActionRecognizeSpeech);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputCompleteSilenceLengthMillis, 1000);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputPossiblyCompleteSilenceLengthMillis, 1000);
        _speechIntent.PutExtra(RecognizerIntent.ExtraSpeechInputMinimumLengthMillis, 1500);
    StartListening();
    }
    public void StartListening()
    {
        _speech.StartListening(_speechIntent);
    }

    public void StopListening()
    {
        _speech.StopListening();
    }

    public void OnBeginningOfSpeech()
    {

    }

    public void OnBufferReceived(byte[] buffer)
    {
    }

    public void OnEndOfSpeech()
    {

    }

    public void OnError([GeneratedEnum] SpeechRecognizerError error)
    {
        Words = error.ToString();
        startover();
    }

    public void OnEvent(int eventType, Bundle @params)
    {
    }

    public void OnPartialResults(Bundle partialResults)
    {
    }

    public void OnReadyForSpeech(Bundle @params)
    {
    }

    public void OnResults(Bundle results)
    {

        var matches = results.GetStringArrayList(SpeechRecognizer.ResultsRecognition);
        if (matches == null)
            Words = "Null";
        else
            if (matches.Count != 0)
            Words = matches[0];
        else
            Words = "";

        //do anything you want for the result
        }
        startover();
    }

    public void OnRmsChanged(float rmsdB)
    {

    }

    public void OnInit([GeneratedEnum] OperationResult status)
    {
        if (status == OperationResult.Error)
            txtspeech.SetLanguage(Java.Util.Locale.Default);
    }


}

在活动中调用它:

void StartRecording()
    {
        string rec = PackageManager.FeatureMicrophone;

        if (rec != "android.hardware.microphone")
        {
            // no microphone, no recording. Disable the button and output an alert
            Toast.MakeText(this, "NO MICROPHONE", ToastLength.Short);
        }
        else
        {

            //you can pass any object you want to connect to your recognizer here (I am passing the activity)
            CustomRecognizer voice = new CustomRecognizer(this);
            voice.StartListening();

        }
    }

不要忘记请求使用麦克风的许可!

解释 :

- 这将消除烦人的“点击开始录制”

-这将始终记录您调用 StartListening() 的那一刻,并且永远不会停止,因为每次完成录制时我总是调用 startover() 或 StartListening()

-这是一个非常糟糕的解决方法,因为在处理录音的那一刻,录音机在调用 StartListening() 之前不会获得任何声音输入(对此没有解决方法)

-谷歌识别对于语音命令来说并不是很好,因为语言模型是“[lang]句子”,所以你不能限制单词,谷歌总是会尝试做出一个“好句子”。

为了更好的结果和用户体验,我真的建议你使用Google Cloud API(但它必须是在线的,而且成本很高),第二个建议是CMUSphinx / PocketSphinx,它是开源的,可以做离线模式,但你必须做所有的事情手动

PocketSphinx 的优势:

  1. 您可以创建自己的词典
  2. 兼容离线模式

  3. 您可以自行训练声学模型(语音等),因此您可以根据您的环境和发音进行配置

  4. 您可以通过访问“PartialResult”获取实时结果

PocketSphinx 的缺点:您必须手动完成所有操作,从设置声学模型、字典、语言模型、阈值等(如果您想要简单的东西就太过分了)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我想在我的家庭自动化应用程序中加入连续(免提)语音命令识别 的相关文章

  • 如何清除所有WebView存储的信息?

    我有一个 Android 浏览器 我可以选择清除缓存 存储 cookie 等 代码如下所示 webView clearCache true webView clearFormData webView clearHistory webView
  • Android - 从资产中解析巨大(超大)JSON 文件的最佳方法

    我正在尝试从资产文件夹中解析一些巨大的 JSON 文件 我如何加载并添加到 RecyclerView 我想知道解析这种大文件 大约 6MB 的最佳方法是什么 以及您是否知道可以帮助我处理此文件的良好 API 我建议您使用GSON lib h
  • 卸载后 Web 应用程序不显示“添加到主屏幕”

    这是我第一次创建网络应用程序 我设法解决了这个问题 所以我得到了实际的 chrome 提示 将其添加到主屏幕 然后我从手机上卸载了该网络应用程序 因为我想将其展示给我的同事 但是 屏幕上不再出现提示 问题 这是有意为之的行为还是我的应用程序
  • 找不到 com.google.firebase:firebase-core:9.0.0 [重复]

    这个问题在这里已经有答案了 在遵循有些不一致的指示之后here https firebase google com docs admob android quick start name your project and here http
  • 当文本输入聚焦在 React Native for Android 的底部工作表上时,视图移出屏幕

    我正在使用图书馆 https github com osdnk react native reanimated bottom sheet https github com osdnk react native reanimated bott
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • Android SIP 来电使用带有广播接收器的服务

    大家好 其实我正在尝试创建一个应用程序 支持基于 SIP 通过互联网进行音频呼叫 这里使用本机 sip 我遇到了来电问题 我已经完成了服务的注册部分 但是在接听电话时我无法接听电话 请帮助我 Service file package exa
  • 是否必须删除 Intent extra?

    这可能是一个愚蠢的问题 但是是否有一条规则规定消费活动必须显式删除 Intent 额外内容 或者只有在回收 Intent 对象时才如此 换句话说 如果我总是通过执行以下操作来链接到下一个活动 Intent i new Intent MyCu
  • 带有 EditText 和 Spinner 的对话框

    我有一个按钮 单击后会弹出一个对话框 我希望对话框有一个EditText and a Spinner对话框内 我不知道如何设置它的视图 我有一个代码AlertDialog它有效 只是EditText and Spinner我需要将其放入其中
  • Android:捕获的图像未显示在图库中(媒体扫描仪意图不起作用)

    我遇到以下问题 我正在开发一个应用程序 用户可以在其中拍照 附加到帖子中 并将图片保存到外部存储中 我希望这张照片也显示在图片库中 并且我正在使用媒体扫描仪意图 但它似乎不起作用 我在编写代码时遵循官方的Android开发人员指南 所以我不
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 在 android DatePickerDialog 中将语言设置为法语

    有什么办法可以让日期显示在DatePickerDialog用法语 我已经搜索过这个但没有找到结果 这是我的代码 Calendar c Calendar getInstance picker new DatePickerDialog Paym
  • Android Studio - Windows 7 上的 Android SDK 问题

    我对 Google i o 2013 上发布的最新开发工具 Android Studio 有疑问 我已经成功安装了该程序并且能够正常启动 我可以导入现有项目并对其进行编辑 但是 当我尝试单击 SDK 管理器图标或 AVD 管理器图标时 或者
  • Android 中麦克风的后台访问

    是否可以通过 Android 手机上的后台应用程序 服务 持续监控麦克风 我想做的一些想法 不断聆听背景中的声音信号 收到 有趣的 音频信号后 执行一些网络操作 如果前台应用程序需要的话 后台应用程序必须能够智能地放弃对麦克风的访问 除非可
  • Android向menuItem添加子菜单,addSubMenu()在哪里?

    我想根据我的参数以编程方式将 OptionsMenu 内的子菜单添加到 menuItem 中 我检查了android sdk中的 MenuItem 没有addSubMenu 方法 尽管你可以找到 hasSubMenu 和 getSubMen
  • 如何根据 gradle 风格设置变量

    我想传递一个变量test我为每种风格设置了不同的值作为 NDK 的定义 但出于某种原因 他总是忽略了最后味道的价值 这是 build gradle apply plugin com android library def test andr
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 实现滚动选择 ListView 中的项目

    我想使用 ListView 您可以在其中滚动列表来选择一个项目 它应该像一个 Seekbar 但拇指应该是固定的 并且您必须使用该栏来调整它 我面临的一个问题是 我不知道这种小部件是如何调用的 这使得我很难搜索 所以我制作了下面这张图片 以
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • android sdk 的位置尚未在 Windows 操作系统的首选项中设置

    在 Eclipse 上 我转到 windows gt Android SDK 和 AVD Manager 然后弹出此消息 Android sdk 的位置尚未在首选项中设置 进入首选项 在侧边栏找到 Android 然后会出现一个 SDK 位

随机推荐

  • NodeJS 热代码推送

    我一直在尝试找出 Node js 上的 热代码推送 基本上 我的主文件 当您键入时运行node app js 由一些设置 配置和初始化组成 在该文件中 我有一个使用 chokidar 的文件观察器 添加文件后 我只需require文件 如果
  • Qt Creator 编译后不会运行应用程序

    我使用 SVN 将托管在 google code 上的 Qt 项目检出到本地文件夹 当我在 Qt Creator 上打开它时 它成功编译了该项目 但是当它尝试运行编译后的程序时 应用程序输出上出现了一条错误消息 该进程无法启动 怎么了 我通
  • 对 Firestore 文档进行排序

    有什么可能的方法可以根据特定字段值的数字对集合的 Cloud Firestore 文档进行排序 例如在集合中ids有一些文档 每个文档中都有一个名为idNumber 该 idNumber 的值是 0 然后在下一个文档中是 1 然后是 2 等
  • 将用户定义属性添加到域类

    我需要允许用户在系统实体之一中定义一些自定义字段 您有任何建议 模式 插件可以帮助我将此功能添加到我的应用程序中吗 thanks Meni 您可以将 Map 属性添加到域类并在其中存储任意数据 但它相当有限 它将生成一个包含 varchar
  • $window.focus() 不适用于 iOS Safari 中的现有选项卡

    当我打开一个新窗口时var win window open name 然后使用聚焦窗口win focus 这是首次在 iOS Safari 中运行 但是 当使用 window open 通过名称再次引用现有窗口时 我无法在 iOS Safa
  • 如何“完成”新行

    所以今晚我的 c windows 窗体应用程序遇到了一些麻烦 当当前选定的新行仍为其默认值时 是否可以将新行插入到 datagridview 中 或者 如果我想以编程方式更改值 如何模拟用户编辑文本框以完成该行 为了澄清 当一行是新行时 并
  • 如何从状态“False(MissingEndpoints)”启用 kube-system/metrics-server?

    我的指标服务器突然无法工作并得到以下信息 kubectl get apiservices egrep metrics v1beta1 metrics k8s io kube system metrics server False Missi
  • jQuery 类选择器性能(困惑)

    So is table selectable td capable input text 优于 table selectable td input text 换句话说 指定一个类会加速还是减慢选择速度 假设在这种情况下不是绝对需要的 我没有
  • 当我无法设置“DYLD_LIBRARY_PATH”时,如何在 macOS 上便携式安装 ImageMagick?

    我正在为 macOS Mojave 开发一个命令行实用程序 它使用 ImageMagick 来操作图像 我想将它作为一个独立的应用程序进行共享 以便其他人可以开箱即用 而无需安装任何额外的 dylib 或框架 ImageMagick 的 H
  • WPF Expander 在 Canvas 内部时不会向左扩展

    我有一个有 4 列的网格 第一列是一个 ZIndex 为 99 的 Canvas 里面有一个扩展器 展开方向设置为 RIGHT 当我单击标题时 扩展器会扩展至第 2 列的顶部 这正是我想要的 我试图在第 4 列内复制此内容 仅相反方向 以便
  • 如何将 Iterator 作为 Iterator<&str> 传递?

    fn my print lt a gt args impl Iterator
  • undefined 不是一个函数(评估 'decorator(target, property, desc)')

    我想整合mobx https mobx js org and mobx 坚持 https github com pinqy520 mobx persist with 反应导航 https reactnavigation org 我读过这些文
  • AJAX ToolKit TabContainer:我可以捕获“活动选项卡面板更改”事件吗

    我有一个AJAX 工具包 TabContainer控制几个TabPanels 我想验证当前活动的内容TabPanel防止用户在数据无效的情况下处理其他数据 如果您需要在服务器端执行 TabPanelChangingEvent 则需要通过更改
  • 递归 MySql 触发器不起作用

    我正在尝试设置一个 MySql 触发器 以便在 ODBC 中插入 更新数据后运行 我的触发器如下 CREATE TRIGGER myTrigger AFTER INSERT ON testTable FOR EACH ROW UPDATE
  • 有人用SvnMapper吗?

    首先我下载 SvnMapper svnmapper tigris org http svnmapper tigris org 并安装它 然后我启动SvnMapper GUI需要输入subversion的URL 我在这一步失败了 我有一个本地
  • 当一个操作“接近 O(1)”而不是“是 O(1)”时,这意味着什么?

    例如 考虑 NET Framework 4 5 的文档Dictionary
  • GitHub Desktop 中有强制推送选项吗?

    使用版本 1 0 4 我找不到任何强制推送选项 命令行是使用武力的唯一方法吗 推不动 https i stack imgur com ZjW5E jpg and 拉不动 https i stack imgur com Rbfoc jpg 2
  • 用于保护 S3 文档的 Rails 实施

    我想通过 Rails 应用程序保护我的 s3 文档 这样如果我转到 www myapp com attachment 5 应在显示 下载文档之前对用户进行身份验证 我在 stackoverflow 上读过类似的问题 但我不确定我是否看到了任
  • Swing 中精美的工具提示

    我有一个 JTable 我想为列中的特定单元格显示一个精美的工具提示 基本上是一个 JTextArea 我正在使用自定义单元格渲染器 因此如果我能够弄清楚当我将鼠标悬停在单元格渲染器的组件上时如何弹出一个窗口 那就很容易了 有没有关于如何执
  • 我想在我的家庭自动化应用程序中加入连续(免提)语音命令识别

    我创建了一个简单的 Android 应用程序来控制连接到我的 Raspberry Pi 的继电器 我使用按钮以及基本的语音识别来触发这些按钮并打开 关闭相应的中继通道 到目前为止 语音识别部分是由 RecognizerIntent 处理的