Unity 工具 之 Azure 微软连续语音识别ASR的简单整理

news2024/11/17 5:50:32

Unity 工具 之 Azure 微软连续语音识别ASR的简单整理

目录

Unity 工具 之 Azure 微软连续语音识别ASR的简单整理

一、简单介绍

二、实现原理

三、注意实现

四、实现步骤

 五、关键脚本


一、简单介绍

Unity 工具类,自己整理的一些游戏开发可能用到的模块,单独独立使用,方便游戏开发。

本节介绍,这里在使用微软的Azure 进行语音合成的两个方法的做简单整理,这里简单说明,如果你有更好的方法,欢迎留言交流。

官网注册:

面向学生的 Azure - 免费帐户额度 | Microsoft Azure

官网技术文档网址:

技术文档 | Microsoft Learn

官网的TTS:

语音转文本快速入门 - 语音服务 - Azure AI services | Microsoft Learn

Azure Unity SDK  包官网:

安装语音 SDK - Azure Cognitive Services | Microsoft Learn

SDK具体链接:

https://aka.ms/csspeech/unitypackage

二、实现原理

1、官网申请得到语音识别对应的 SPEECH_KEY 和 SPEECH_REGION

2、因为语音识别需要用到麦克风,移动端需要申请麦克风权限

3、开启语音识别,监听语音识别对应事件,即可获取到识别结果

三、注意实现

1、注意如果有卡顿什么的,注意主子线程切换,可能可以适当解决你的卡顿现象

2、注意电脑端(例如windows)运行可以不申请麦克风权限,但是移动端(例如Android)运行要申请麦克风权限,不然无法开启识别成功,可能会报错:Exception with an error code: 0x15

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

System.ApplicationException: Exception with an error code: 0x15 at Microsoft.CognitiveServices.Speech.Internal.SpxExceptionThrower.ThrowIfFail (System.IntPtr hr) [0x00000] in <00000000000000000000000000000000>:0 at Microsoft.CognitiveServices.Speech.Recognizer.StartContinuousRecognition () [0x00000] in <00000000000000000000000000000000>:0 at Microsoft.CognitiveServices.Speech.Recognizer.DoAsyncRecognitionAction (System.Action recoImplAction) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.Task.Execute () [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <00000000000000000000000000000000>:0 at System.Threading.Tasks.Task.ExecuteWithThreadLocal (System.Threading.Tasks.Task& currentTaskSlot) [0x00000] in

四、实现步骤

1、下载好SDK 导入

2、简单的搭建场景

3、编写对应脚本,测试语音识别功能

4、把测试脚本添加到场景中,并赋值

5、如果移动端,例如 Android 端,勾选如下,添加麦克风权限

<uses-permission android:name="android.permission.RECORD_AUDIO"/>

5、运行,点击对应按钮,开始识别,Console 中可以看到识别结果

 五、关键脚本

1、TestSpeechRecognitionHandler


using UnityEngine;
using UnityEngine.Android;
using UnityEngine.UI;

public class TestSpeechRecognitionHandler : MonoBehaviour
{
    #region Data
    
    /// <summary>
    /// 按钮,文本
    /// </summary>
    public Button QuitButton;
    public Button ASRButton;
    public Button StopASRButton;
    public Text ASRText;

    /// <summary>
    /// m_SpeechAndKeywordRecognitionHandler
    /// </summary>
    SpeechRecognitionHandler m_SpeechAndKeywordRecognitionHandler;
    #endregion
    #region Liefecycle function

    /// <summary>
    /// Start
    /// </summary>
    void Start()
    {
        QuitButton.onClick.AddListener(OnClickQuitButton);
        ASRButton.onClick.AddListener(OnClickASRButton);
        StopASRButton.onClick.AddListener(OnClickStopASRButton);

        // 请求麦克风权限
        RequestMicrophonePermission();
    }

    /// <summary>
    /// 应用退出
    /// </summary>
    async void OnApplicationQuit() {
        await m_SpeechAndKeywordRecognitionHandler.StopContinuousRecognizer();
    }

    #endregion

    #region Private function
    /// <summary>
    /// RequestMicrophonePermission
    /// </summary>
    void RequestMicrophonePermission()
    {
        // 检查当前平台是否为 Android
        if (Application.platform == RuntimePlatform.Android)
        {
            // 检查是否已经授予麦克风权限
            if (!Permission.HasUserAuthorizedPermission(Permission.Microphone))
            {
                // 如果没有权限,请求用户授权
                Permission.RequestUserPermission(Permission.Microphone);
            }
        }
        else
        {
            // 在其他平台上,可以执行其他平台特定的逻辑
            Debug.LogWarning("Microphone permission is not needed on this platform.");
        }

        SpeechInitialized();
    }

    /// <summary>
    /// SpeechInitialized
    /// </summary>
    private void SpeechInitialized() {
        ASRText.text = "";
        m_SpeechAndKeywordRecognitionHandler = new SpeechRecognitionHandler();
        m_SpeechAndKeywordRecognitionHandler.onRecognizingAction = (str) => { Debug.Log("onRecognizingAction: " + str); };
        m_SpeechAndKeywordRecognitionHandler.onRecognizedSpeechAction = (str) => { Loom.QueueOnMainThread(() => ASRText.text += str);  Debug.Log("onRecognizedSpeechAction: " + str); };
        m_SpeechAndKeywordRecognitionHandler.onErrorAction = (str) => { Debug.Log("onErrorAction: " + str); };
        m_SpeechAndKeywordRecognitionHandler.Initialized();
    }
    /// <summary>
    /// OnClickQuitButton
    /// </summary>
    private void OnClickQuitButton() {
#if UNITY_EDITOR
        UnityEditor.EditorApplication.isPlaying = false;

#else
                Application.Quit();
#endif 
    }
    /// <summary>
    /// OnClickASRButton
    /// </summary>
    private void OnClickASRButton() {
        m_SpeechAndKeywordRecognitionHandler.StartContinuousRecognizer();
    }

    /// <summary>
    /// OnClickStopASRButton
    /// </summary>
    private async void OnClickStopASRButton()
    {
        await m_SpeechAndKeywordRecognitionHandler.StopContinuousRecognizer();
    }

    #endregion
}

2、SpeechRecognitionHandler

using UnityEngine;
using Microsoft.CognitiveServices.Speech;
using Microsoft.CognitiveServices.Speech.Audio;
using System;
using Task = System.Threading.Tasks.Task;

/// <summary>
/// 语音识别转文本和关键词识别
/// </summary>
public class SpeechRecognitionHandler
{
    #region Data

    /// <summary>
    /// 
    /// </summary>
    const string TAG = "[SpeechAndKeywordRecognitionHandler] ";

    /// <summary>
    /// 识别配置
    /// </summary>
    private SpeechConfig m_SpeechConfig;

    /// <summary>
    /// 音频配置
    /// </summary>
    private AudioConfig m_AudioConfig;

    /// <summary>
    /// 语音识别
    /// </summary>
    private SpeechRecognizer m_SpeechRecognizer;

    /// <summary>
    /// LLM 大模型配置
    /// </summary>
    private ASRConfig m_ASRConfig;

    /// <summary>
    /// 识别的事件
    /// </summary>
    public Action<string> onRecognizingAction;
    public Action<string> onRecognizedSpeechAction;
    public Action<string> onErrorAction;
    public Action<string> onSessionStoppedAction;


    #endregion
    #region Public function

    /// <summary>
    /// 初始化
    /// </summary>
    /// <returns></returns>
    public async void Initialized()
    {
        m_ASRConfig = new ASRConfig();

        Debug.Log(TAG + "m_LLMConfig.AZURE_SPEECH_RECOGNITION_LANGUAGE " + m_ASRConfig.AZURE_SPEECH_RECOGNITION_LANGUAGE);
        Debug.Log(TAG + "m_LLMConfig.AZURE_SPEECH_REGION " + m_ASRConfig.AZURE_SPEECH_REGION);

        m_SpeechConfig = SpeechConfig.FromSubscription(m_ASRConfig.AZURE_SPEECH_KEY, m_ASRConfig.AZURE_SPEECH_REGION);
        m_SpeechConfig.SpeechRecognitionLanguage = m_ASRConfig.AZURE_SPEECH_RECOGNITION_LANGUAGE;


        m_AudioConfig = AudioConfig.FromDefaultMicrophoneInput();

        Debug.Log(TAG + " Initialized 2 ====");

        // 根据自己需要处理(不需要也行)
        await Task.Delay(100);
    }

    #endregion

    #region Private function

    /// <summary>
    /// 设置识别回调事件
    /// </summary>
    private void SetRecoginzeCallback()
    {
        Debug.Log(TAG + " SetRecoginzeCallback == ");
        if (m_SpeechRecognizer != null)
        {
            m_SpeechRecognizer.Recognizing += OnRecognizing;

            m_SpeechRecognizer.Recognized += OnRecognized;

            m_SpeechRecognizer.Canceled += OnCanceled;

            m_SpeechRecognizer.SessionStopped += OnSessionStopped;

            Debug.Log(TAG+" SetRecoginzeCallback OK ");
        }
    }

    #endregion

    #region Callback
    /// <summary>
    /// 正在识别
    /// </summary>
    /// <param name="s"></param>
    /// <param name="e"></param>
    private void OnRecognizing(object s, SpeechRecognitionEventArgs e)
    {
        Debug.Log(TAG + "RecognizingSpeech:" + e.Result.Text + " :[e.Result.Reason]:" + e.Result.Reason);
        if (e.Result.Reason == ResultReason.RecognizingSpeech )
        {
            Debug.Log(TAG + " Trigger onRecognizingAction is null :" + onRecognizingAction == null);

            onRecognizingAction?.Invoke(e.Result.Text);
        }
    }

    /// <summary>
    /// 识别结束
    /// </summary>
    /// <param name="s"></param>
    /// <param name="e"></param>
    private void OnRecognized(object s, SpeechRecognitionEventArgs e)
    {
        Debug.Log(TAG + "RecognizedSpeech:" + e.Result.Text + " :[e.Result.Reason]:" + e.Result.Reason);
        if (e.Result.Reason == ResultReason.RecognizedSpeech )
        {
            bool tmp = onRecognizedSpeechAction == null;
            Debug.Log(TAG + " Trigger onRecognizedSpeechAction is null :" + tmp);

            onRecognizedSpeechAction?.Invoke(e.Result.Text);
        }
    }

    /// <summary>
    /// 识别取消
    /// </summary>
    /// <param name="s"></param>
    /// <param name="e"></param>
    private void OnCanceled(object s, SpeechRecognitionCanceledEventArgs e)
    {
        Debug.LogFormat(TAG+"Canceled: Reason={0}", e.Reason );

        if (e.Reason == CancellationReason.Error)
        {
            onErrorAction?.Invoke(e.ErrorDetails);
        }
    }

    /// <summary>
    /// 会话结束
    /// </summary>
    /// <param name="s"></param>
    /// <param name="e"></param>
    private void OnSessionStopped(object s, SessionEventArgs e)
    {
        Debug.Log(TAG+"Session stopped event." );
        onSessionStoppedAction?.Invoke("Session stopped event.");
    }

    
    #endregion


    #region 连续语音识别转文本

    /// <summary>
    /// 开启连续语音识别转文本
    /// </summary>
    public void StartContinuousRecognizer()
    {
        Debug.LogWarning(TAG + "StartContinuousRecognizer");

        try
        {
            // 转到异步中(根据自己需要处理)
            Loom.RunAsync(async () => {
                try
                {
                    if (m_SpeechRecognizer != null)
                    {
                        m_SpeechRecognizer.Dispose();
                        m_SpeechRecognizer = null;
                    }

                    if (m_SpeechRecognizer == null)
                    {
                        m_SpeechRecognizer = new SpeechRecognizer(m_SpeechConfig, m_AudioConfig);

                        SetRecoginzeCallback();
                    }

                    await m_SpeechRecognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);

                    Loom.QueueOnMainThread(() => {
                        Debug.LogWarning(TAG + "StartContinuousRecognizer QueueOnMainThread ok");
                    });
                    Debug.LogWarning(TAG + "StartContinuousRecognizer RunAsync ok");
                }
                catch (Exception e)
                {
                    Loom.QueueOnMainThread(() =>
                    {
                        Debug.LogError(TAG + " StartContinuousRecognizer 0 " + e);
                    });
                }

            });
        }
        catch (Exception e)
        {
            Debug.LogError(TAG + " StartContinuousRecognizer 1 " + e);
        }

    }

    /// <summary>
    /// 结束连续语音识别转文本
    /// </summary>
    public async Task StopContinuousRecognizer()
    {
        try
        {
            if (m_SpeechRecognizer != null)
            {
                await m_SpeechRecognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
                //m_SpeechRecognizer.Dispose();
                //m_SpeechRecognizer = null;
                Debug.LogWarning(TAG + " StopContinuousRecognizer");
            }
        }
        catch (Exception e)
        {
            Debug.LogError(TAG + " StopContinuousRecognizer Exception : " + e);
        }
    }

    #endregion

}

3、ASRConfig



public class ASRConfig 
{
    #region Azure ASR

    /// <summary>
    /// AZURE_SPEECH_KEY
    /// </summary>
    public virtual string AZURE_SPEECH_KEY { get; } = @"098dc5aa21a14758a347dcac36d7eb66";
    /// <summary>
    /// AZURE_SPEECH_REGION
    /// </summary>
    public virtual string AZURE_SPEECH_REGION { get; } = @"eastasia";
    /// <summary>
    /// AZURE_SPEECH_RECOGNITION_LANGUAGE
    /// </summary>
    public virtual string AZURE_SPEECH_RECOGNITION_LANGUAGE { get; } = @"zh-CN";

    #endregion
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1376492.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用MATLAB求最短路径(graphshortestpath)和求最小生成树(minspantree),代码演示

求最短路径&#xff08;graphshortestpath&#xff09;&#xff0c;求最小生成树&#xff08;minspantree&#xff09; 文章目录 求最短路径&#xff08;graphshortestpath&#xff09;&#xff0c;求最小生成树&#xff08;minspantree&#xff09;1、最短路径问题2、最小生成…

写点东西《Docker入门(下)》

写点东西《Docker入门(下)》 Docker ComposeDocker 注册表Docker 引擎Linux 容器和 Windows 容器的概念:容器编排Docker SwarmDocker Compose Docker Compose 是一个方便的工具,可帮助您轻松运行和连接不同的软件服务,就好像它们都是同一事件的一部分一样。 Docker Compo…

【设计模式】01-前言

23 Design Patterns implemented by C. 从本文开始&#xff0c;一系列的文章将揭开设计模式的神秘面纱。本篇博文是参考了《设计模式-可复用面向对象软件的基础》这本书&#xff0c;由于该书的引言 写的太好了&#xff0c;所以本文基本是对原书的摘抄。 0.前言 评估一个面向对…

C++力扣题目111--二叉树的最小深度

力扣题目链接(opens new window) 给定一个二叉树&#xff0c;找出其最小深度。 最小深度是从根节点到最近叶子节点的最短路径上的节点数量。 说明: 叶子节点是指没有子节点的节点。 示例: 给定二叉树 [3,9,20,null,null,15,7], 返回它的最小深度 2 思路 看完了这篇104.二…

RuntimeError: Placeholder storage has not been allocated on MPS device!解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

Web安全测试基础

SQL注入 当下最常用的一个攻击手段&#xff0c;就是通过SQL命令插入到Web表单中或页面请求查询字符串中&#xff0c;最终达到欺骗服务器执行恶意的SQL语句的目的&#xff0c;SQL注入一旦成功&#xff0c;轻则直接绕开服务器验证&#xff0c;直接登录成功&#xff0c;重则将服务…

Stream流递归查询部门树

Java 递归查询树是很常见的功能&#xff0c;也有很多写法&#xff0c;小编这里记录stream流递归部门树写法&#xff0c;自从小编用上stream流之后&#xff0c;是爱不释手&#xff0c;的确是个不错的好东西&#xff0c;话不多说&#xff0c;直接上代码 第一步&#xff1a;先创建…

用通俗易懂的方式讲解:大模型 RAG 技术,从入门到精通

本文基于IVAN ILIN发布于Towards AI的博客[1]进行总结归纳&#xff0c;感谢原作者的精彩讲解。 检索增强生成&#xff08;Retrieval Augmented Generation&#xff0c;简称RAG&#xff09;为大型语言模型&#xff08;LLMs&#xff09;提供了从某些数据源检索到的信息&#xff0…

RISC-V是如何与X86、ARM三分天下

目录 1.行业CPU指令集格局 2.汽车中的RISC-V进展 2.1 国际进展 2.2 国内进展 3.小结 2023年3月2日&#xff0c;在平头哥牵头举办的玄铁RISC-V生态大会上&#xff0c;工程院院士倪光南表示&#xff0c;基于RISC-V模块化、可扩展、容易定制、不受垄断制约等优势&#xff0c;…

2019年认证杯SPSSPRO杯数学建模C题(第一阶段)保险业的数字化变革全过程文档及程序

2019年认证杯SPSSPRO杯数学建模 基于 CART 决策树和 SVR 的客户续保概率预测 C题 保险业的数字化变革 原题再现&#xff1a; 车险&#xff0c;即机动车辆保险。保险自身是一种分散风险、消化损失的经济补偿制度&#xff0c;车险即为分散机动车辆在行驶过程中可能发作的未知风…

SpringBoot多环境配置Maven Profile组

Maven profile组 注意切换配置时 mvn clean下 或者 clean 加install 或者compile 编译 clean之后 install下 或者compile 编译 nohup java -Xms256m -Xmx512m -Dfile.encodingUTF-8 -jar demo.jar --spring.profiles.activeprod > system.log 2>&1 &

2024年A特种设备相关管理(电梯)证考试题库及A特种设备相关管理(电梯)试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年A特种设备相关管理&#xff08;电梯&#xff09;证考试题库及A特种设备相关管理&#xff08;电梯&#xff09;试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲…

Word不同部分(分节)设置页眉和页码的使用指南——附案例操作

Word页眉和页码分节设置的使用指南 目录 Word页眉和页码分节设置的使用指南摘要1. 插入分节符2. 设置不同的页眉3. 设置不同的页码4. 调整页码的起始值5. 删除或更改分节6. 预览和调整 摘要 在撰写word文档时&#xff0c;我们经常需要在不同的部分应用不同的页眉和页码格式。在…

靶机实战(10):OSCP备考之VulnHub Tre 1

靶机官网&#xff1a;Tre: 1[1] 实战思路&#xff1a; 一、主机发现二、端口发现&#xff08;服务、组件、版本&#xff09;三、漏洞发现&#xff08;获取权限&#xff09; 8082端口/HTTP服务 组件漏洞URL漏洞&#xff08;目录、文件&#xff09;80端口/HTTP服务 组件漏洞URL漏…

基于JAVA+ssm开发的在线报名系统设计与实现【附源码】

基于JAVAssm开发的在线报名系统设计与实现【附源码】 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; &#x1f345; 查看下方微信号获取联系方式 承接各种定制系统 …

前端页面优化做的工作

1.分析模块占用空间 new (require(webpack-bundle-analyzer).BundleAnalyzerPlugin)() 2.使用谷歌浏览器中的layers&#xff0c;看下有没有影响性能的模块&#xff0c;或者应该销毁没销毁的 3.由于我们页面中含有很大的序列帧动画&#xff0c;所以会导致页面性能低&#xff0…

JavaScript系列——Promise

文章目录 概要Promise三种状态状态改变Promise链式调用Promise处理并发promise.all()promise.allSettled&#xff08;&#xff09;Promise.any()promise.race() 小结 概要 Promise中文翻译过来就是承诺、预示、有可能的意思。 在JavaScript里面&#xff0c;Promise 是一个对象…

九州金榜|为什么本科生“回炉”读职校?

近年来&#xff0c;“本科学历&#xff0b;技能证书”成为不少大学毕业生求职时的配置&#xff0c;本科毕业生“回炉”职业院校学习技能的现象引发社会关注。 为什么会引发这种现象发生呢&#xff1f;现在学校教育学的是理论知识&#xff0c;而“回炉”确实学习的实操&#xff…

Mac robotframework+pycharm运行suite报错情况:ImportError: No module named request

报错实例&#xff1a; 当前Preferences–>Tool–>External Tools Suite配置&#xff0c;显示使用的python为2.7版本&#xff0c;robotframework安装在当前版本的python中&#xff1a; 但是我pycharm现在的环境配置的python为3.11&#xff0c;当前使用的RF与当前使用的py…

钥匙翻转了一个面,该怎么识别匹配?

工业自动化中&#xff0c;我们经常遇到这样的问题&#xff0c;两面一样&#xff0c;上料时&#xff0c;翻转了&#xff0c;没人知道&#xff0c;该怎么匹配到&#xff1f;让机器人能抓取上&#xff1f; 两面相似&#xff0c;翻转了&#xff0c;该怎么识别匹配&#xff0c;来料…