Windows系统实现唤醒+合成+命令词智能语音交互

news2024/11/25 15:33:03

1、之前写过离线能力调用,今天来个终极版,实现智能交互或者结合大模型的智能交互示例,下面进入正题。上B站效果离线唤醒+离线合成+离线命令词实现智能交互_哔哩哔哩_bilibili

2、到讯飞开放平台下载唤醒+合成+命令词的离线组合包,找到msc_64.dll复制三份出来,一定要注意路径位置,不然会出现错误。msc直接下载的原封不动的拷贝就行

3、常量类的定义,各位直接复制粘贴即可,注意换自己的APPID,不然报错的

package com.day.config;

import com.sun.jna.ptr.IntByReference;

import javax.sound.sampled.*;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;

public class Constants {
    // 构造16K 16BIT 单声道音频
    public static final String APPID = "5e11538f";  // APPID
    public static final String WORK_DIR = "src/main/resources";

    // 1、唤醒相关  ssb_param,一定注意IVW_SSB_PARAMS的fo|xxx资源的路径,xxx取值是指WORK_DIR目录下/msc/xxx   xxx是以后的路径开始拼接的!!!!!!!!!!!
    public static final AudioFormat IVW_ASR_AUDIO_FORMAT = new AudioFormat(16000F, 16, 1, true, false);
    public static final String IVW_DLL_PATH = "src/main/resources/ivw_msc_x64.dll"; // windows动态库路径
    public static final String IVW_LOGIN_PARAMS = "appid = " + APPID + ", work_dir = " + WORK_DIR;
    public static final String IVW_SSB_PARAMS = "ivw_threshold=0:1450,sst=wakeup,ivw_shot_word=1,ivw_res_path =fo|res/ivw/wakeupresource.jet";
    public static IntByReference IVW_ERROR_CODE = new IntByReference(-100);
    public static final Integer IVW_FRAME_SIZE = 6400;  // 一定要每200ms写10帧,否则会出现唤醒一段时间后无法唤醒的问题,一帧的大小为640B,其他大小可能导致无法唤醒。
    public static Integer IVW_AUDIO_STATUS = 1;
    public static DataLine.Info IVW_ASR_DATA_LINE_INFO = new DataLine.Info(TargetDataLine.class, IVW_ASR_AUDIO_FORMAT);
    public static TargetDataLine IVW_ASR_TARGET_DATA_LINE; // 录音

    static {
        try {
            IVW_ASR_TARGET_DATA_LINE = (TargetDataLine) AudioSystem.getLine(IVW_ASR_DATA_LINE_INFO);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    // 2、合成相关
    public static final AudioFormat TTS_AUDIO_FORMAT = new AudioFormat(16000F, 16, 1, true, false);
    public static final String TTS_DLL_PATH = "src/main/resources/tts_msc_x64.dll"; // windows动态库路径
    public static final String TTS_LOGIN_PARAMS = "appid = " + APPID + ", work_dir = " + WORK_DIR;
    public static final String TTS_SESSION_BEGIN_PARAMS = "engine_type = local, voice_name = xiaoyan, text_encoding = UTF8," +
            " tts_res_path = fo|res/tts/xiaoyan.jet;fo|res/tts/common.jet, sample_rate = 16000, speed = 50, volume = 50, pitch = 50, rdn = 2";
    public static IntByReference TTS_ERROR_CODE = new IntByReference(-100);
    public static IntByReference TTS_AUDIO_LEN = new IntByReference(-100);
    public static IntByReference TTS_SYNTH_STATUS = new IntByReference(-100);
    public static String TTS_TEXT; // 合成文本
    public static Integer TTS_TOTAL_AUDIO_LENGTH; // 合成音频长度
    public static ByteArrayOutputStream TTS_BYTE_ARRAY_OUTPUT_STREAM; // 合成音频流
    public static DataLine.Info TTS_DATA_LINE_INFO = new DataLine.Info(SourceDataLine.class, TTS_AUDIO_FORMAT, AudioSystem.NOT_SPECIFIED);
    public static SourceDataLine TTS_SOURCE_DATA_LINE; // 播放

    static {
        try {
            TTS_SOURCE_DATA_LINE = (SourceDataLine) AudioSystem.getLine(Constants.TTS_DATA_LINE_INFO);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
    }

    // 3、离线命令词相关
    public static final String ASR_DLL_PATH = "src/main/resources/asr_msc_x64.dll"; // windows动态库路径
    public static final String ASR_LOGIN_PARAMS = "appid = " + APPID + ", work_dir = " + WORK_DIR;
    public static final String ASR_CALL_BNF_PATH = "src/main/resources/msc/res/asr/call.bnf";
    public static final String ASR_BUILD_PARAMS = "engine_type = local,asr_res_path = fo|res/asr/common.jet," +
            "sample_rate = 16000,grm_build_path = res/asr/GrmBuilld_x64";
    public static final String ASR_LEX_PARAMS = "engine_type=local,asr_res_path = fo|res/asr/common.jet, " +
            "sample_rate = 16000,grm_build_path =res/asr/GrmBuilld_x64, grammar_list =call";
    public static IntByReference ASR_ERROR_CODE = new IntByReference(-100);
    public static final String ASR_SESSION_PARAMS = "vad_bos =3000 ,vad_eos = 10000,engine_type = local,asr_res_path = fo|res/asr/common.jet, " +
            "sample_rate = 16000,grm_build_path = res/asr/GrmBuilld_x64, local_grammar = call,result_type = json, result_encoding = UTF8";
    public static IntByReference ASR_EP_STATUS = new IntByReference(-100);
    public static IntByReference ASR_RECOG_STATUS = new IntByReference(-100);
    public static Integer ASR_AUDIO_STATUS = 1;
    public static Integer ASR_FRAME_SIZE = 640;   // 16k采样率的16位音频,一帧的大小为640Byte(来自Windows SDK的说明)
    public static FileInputStream ASR_FILE_INPUT_STREAM;
    public static String ASR_GRAMMAR_CONTENT;
    public static IntByReference ASR_RESULT_STATUS = new IntByReference(-100);
}

4、唤醒方法重写(唤醒成功执行回调函数,往下看)

package com.day.service;

import com.day.config.Constants;
import com.day.service.imp.IvwCallback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;

public interface IvwService extends Library {
    /**
     * 重点:
     * 1.char *   对应  String
     * 2.int *    对应  IntByReference
     * 3.void *   对应  Pointer或byte[]
     * 4.int      对应  int
     * 5.无参     对应  无参
     * 6.回调函数  对应  根据文档自定义回调函数,实现接口Callback
     */
    //加载dll动态库并实例化,从而使用其内部的方法
    IvwService INSTANCE = Native.loadLibrary(Constants.IVW_DLL_PATH, IvwService.class);

    //定义登录方法    MSPLogin(const char *usr, const char *pwd, const char *params)
    public Integer MSPLogin(String usr, String pwd, String params);

    //定义开始方法    QIVWSessionbegin(const char *grammarList, const char *params, int *errorCode)
    public String QIVWSessionBegin(String grammarList, String params, IntByReference errorCode);

    //定义写音频方法  QIVWAudioWrite(const char *sessionID, const void *audioData, unsigned int audioLen, int audioStatus)
    public Integer QIVWAudioWrite(String sessionID, byte[] audioData, int audioLen, int audioStatus);

    //定义结束方法    QIVWSessionEnd(const char *sessionID, const char *hints)
    public Integer QIVWSessionEnd(String sessionID, String hints);

    //定义获取结果方法 QIVWRegisterNotify(const char *sessionID, ivw_ntf_handler msgProcCb, void *userData)
    public Integer QIVWRegisterNotify(String sessionID, IvwCallback ivwCallback, byte[] userData);

    //定义退出方法 唤醒一般不用退出
    public Integer MSPLogout();
}

 5、合成方法重写

package com.day.service;

import com.day.config.Constants;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;

public interface TtsService extends Library {
    /**
     * 重点:
     * 1.char *   对应  String
     * 2.int *    对应  IntByReference
     * 3.void *   对应  byte[]/Pointer,回调函数里此类型需用String来对应。
     * 4.int      对应  int
     * 5.无参     对应  void
     * 6.回调函数  对应  根据文档自定义回调函数,实现接口Callback,离线语音合成无回调
     */
    //加载dll动态库并实例化,从而使用其内部的方法
    TtsService INSTANCE = Native.loadLibrary(Constants.TTS_DLL_PATH, TtsService.class);

    //定义登录方法
    public Integer MSPLogin(String usr, String pwd, String params);

    //开始一次普通离线语音合成
    public String QTTSSessionBegin(String params, IntByReference errorCode);

    //写入需要合成的文本
    public Integer QTTSTextPut(String sessionID, String textString, int textLen, String params);

    //获取离线合成的音频
    public Pointer QTTSAudioGet(String sessionID, IntByReference audioLen, IntByReference synthStatus, IntByReference errorCode);

    //结束本次普通离线语音合成
    public Integer QTTSSessionEnd(String sessionID, String hints);

    //定义退出方法
    public Integer MSPLogout();
}

6、离线命令词方法重写

package com.day.service;

import com.day.config.Constants;
import com.day.service.imp.AsrGrammarCallback;
import com.day.service.imp.AsrLexiconCallback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.ptr.IntByReference;

public interface AsrService extends Library {
    /**
     * 重点:
     * 1.char *   对应  String
     * 2.int *    对应  IntByReference
     * 3.void *   对应  byte[],回调函数里此类型需用String来对应。
     * 4.int      对应  int
     * 5.无参     对应  void
     * 6.回调函数  对应  根据文档自定义回调函数,实现接口Callback
     */
    //加载dll动态库并实例化,从而使用其内部的方法
    AsrService INSTANCE = Native.loadLibrary(Constants.ASR_DLL_PATH, AsrService.class);

    //定义登录方法
    public Integer MSPLogin(String usr, String pwd, String params);

    //开始一次语音识别。
    public String QISRSessionBegin(String grammarList, String params, IntByReference errorCode);

    //写入本次识别的音频
    public Integer QISRAudioWrite(String sessionID, byte[] byteArrayAudioData, int waveLen, int audioStatus, IntByReference epStatus, IntByReference recogStatus);

    //获取识别结果。
    public String QISRGetResult(String sessionID, IntByReference rsltStatus, int waitTime, IntByReference errorCode);

    //结束本次语音识别。
    public Integer QISRSessionEnd(String sessionID, String hints);

    //获取当次语音识别信息,如上行流量、下行流量等
    public Integer QISRGetParam(String sessionID, String paramName, String paramValue, IntByReference valueLen);

    //构建语法,生成语法ID。有回调
    public Integer QISRBuildGrammar(String grammarType, String grammarContent, int grammarLength, String params, AsrGrammarCallback asrGrammarCallback, byte[] userData);

    //更新本地语法词典。有回调
    public Integer QISRUpdateLexicon(String lexiconName, String lexiconContent, int lexiconLength, String params, AsrLexiconCallback asrLexiconCallback, byte[] userData);

    //定义退出方法
    public Integer MSPLogout();
}

7、回调函数的定义(1个唤醒的,2个离线命令词的)

package com.day.service.imp;

import com.day.AIMain;
import com.sun.jna.Callback;

public class IvwCallback implements Callback {
    public int cb_ivw_msg_proc(String sessionID, int msg, int param1, int param2,
                               String info, String userData) {
        System.out.println("回调函数返回的唤醒结果...:" + info);
        AIMain.startTts("在的,请说指令");
        AIMain.startAsr(); // 答复完毕调用命令词
        return 0;
    }
}
package com.day.service.imp;

import com.sun.jna.Callback;

public class AsrGrammarCallback implements Callback {
    public int build_grm_cb(int errorCode, String info, String userData) {
        System.out.println("构建语法返回的ID信息...:" + info + ",错误码...:" + errorCode);
        return 0;
    }
}
package com.day.service.imp;

import com.sun.jna.Callback;

public class AsrLexiconCallback implements Callback {
    public int LexiconCallBack(int errorCode, String info, String userData) {
        System.out.println("更新词典返回的信息...:" + info + ",错误码...:" + errorCode);
        return 0;
    }
}

8、为了方便各位看官,上POM文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <!--父工程坐标############################################################################################-->
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <!--自己被别人引用的坐标#########################################################################################-->
    <groupId>com.example</groupId>
    <artifactId>day</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>day</name>
    <description>day</description>
    <!--指定JDK版本################################################################################################-->
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <!--总体依赖JAR################################################################################################-->


    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.10.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.5.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.1.6.RELEASE</version>
            </plugin>
        </plugins>
    </build>

    <!--配置阿里云仓库下载-->
    <repositories>
        <repository>
            <id>nexus-aliyun</id>
            <name>nexus-aliyun</name>
            <url>https://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>public</id>
            <name>nexus-aliyun</name>
            <url>https://maven.aliyun.com/nexus/content/groups/public/</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>

</project>

9、命令词也给一份示例Call.bnf(老生常谈,注意放置位置)

#BNF+IAT 1.0;
!grammar call;
!slot <enter>;
!slot <scanSolicitation>;
!slot <scanDelivery>;
!slot <exit>;
!start <callStart>;
<callStart>:[<enter>][<scanSolicitation>][<scanDelivery>][<exit>];
<enter>:立刻|马上|一分钟后|十分钟后|半小时后;
<scanSolicitation>:打开|关闭|调量|调暗|调高|调低;
<scanDelivery>:主卧|次卧|书房|客厅;
<exit>:空调|点灯|窗户|窗帘|衣柜;

10、实现完美的智能语音交互,感兴趣的可以结合下大模型做智能问答场景。

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

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

相关文章

关于正则表达式的简单介绍以及使用

一、介绍 正则表达式通常被用来检索匹配某种模式&#xff08;规律&#xff09;的文本 日常文本检索&#xff0c;如果单纯检索某个数字&#xff0c;字母&#xff0c;或者单词匹配出来的结果较多&#xff0c;而面对目标文件内容较大的时&#xff0c;我们也不可能肉眼对检索出来的…

Kotlin 新版本 1.9.0重要更新预览

释放 Kotlin 新版本 1.9.0 的强大功能 1. Kotlin K2编译器用于多平台 对K2编译器进行了进一步的改进&#xff0c;使其更加稳定。K2编译器针对JVM目标现已进入Beta版本&#xff0c;并且也可以在多平台项目中使用。 您可以通过将K2配置添加到项目的gradle.properties中&#x…

pytest-allure 生成测试报告

目录 前言&#xff1a; pytest 中 yield 和 return 的区别和相同点 共同点 区别 usefixtures 与传 fixture 区别 Pytest 常用的插件 一键安装多个模块 前言&#xff1a; 在软件测试中&#xff0c;生成清晰、易读的测试报告是非常重要的。pytest-allure是一个流行的测试…

centos逻辑分区磁盘扩展

最近碰到服务器磁盘空间不足&#xff0c;需要扩展逻辑分区的需求&#xff0c;特地做下小笔记&#xff0c;方便后续自己回忆。下图是磁盘的相关概念示意图&#xff1a; 1、查看磁盘空间 [rootlocalhost ~]# df -h #查看磁盘空间&#xff0c;根分区的大小是18G&#xff0c;已经用…

微服务——Eureka和Nacos

目录 提供者和消费者 ​编辑 Eureka注册中心——远程调用的问题 Eureka注册中心——原理分析 Eureka注册中心——搭建eureka服务 步骤: Eureka注册中心——服务注册 Eureka注册中心——服务发现 总结 Ribbon负载均衡——原理 流程: Ribbon负载均衡——策略 Ribbon负载均衡—…

ChatGPT:人工智能语言模型的革命性进步

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

idea中回退远程push过的提交(详细图文操作)

目录 git基本知识回顾git中本地文件保存的3个地方工作区暂存区本地仓库代码提交到远程仓库的流转 reset命令的3个参数softmixedhard 具体操作模拟两次提交远程分支回退到第一次提交第一次reset hard第二次reset soft/mixed git基本知识回顾 git中本地文件保存的3个地方 工作区…

CSS :nth-child

CSS :nth-child :nth-child 伪类根据元素在同级元素中的位置来匹配元素. CSS :nth-child 语法 值是关键词 odd/evenAnB最新的 [of S] 语法权重 浏览器兼容性 很简单的例子, 来直觉上理解这个伪类的意思 <ul><li class"me">Apple</li><li>B…

陪诊小程序搭建|陪诊接单平台开发|医疗陪诊小程序

陪诊小程序是一种提供陪同就诊服务的在线平台&#xff0c;具有广阔的发展前景。下面是对陪诊小程序发展前景的介绍&#xff1a;   随着社会的发展和人们生活水平的提高&#xff0c;人们对医疗服务的需求也越来越高。然而&#xff0c;由于工作繁忙、时间紧张等原因&#xff0c…

【C++】通过栈和队列学会使用适配器和优先队列学会仿函数的使用

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

网络超时导致namenode被kill的定位

交换机升级导致部分网络通信超时, 集群的namenode主从切换后,主namenode进程被杀死。 网络问题导致namenode与zk间的连接超时触发了hadoop集群的防脑裂机制而主动kill掉了超时的namenode进程。 日志分析发现zk和namenode之间的网络连接超时: 超时触发了namenode切换,并将超时…

flex布局进阶

推荐看一下阮一峰老师的flex布局博客【Flex 布局教程&#xff1a;语法篇】(https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html#)&#xff0c;讲的非常清晰。 一、多行布局大小相同的子盒子技巧 使用弹性布局实现多行均匀布局时&#xff0c;如若子盒子数量不能被每行…

AI Chat 设计模式:9. 命令模式

本文是该系列的第九篇&#xff0c;采用问答式的方式展开&#xff0c;问题由我提出&#xff0c;答案由 Chat AI 作出&#xff0c;灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 介绍下命令模式A.1Q.2 详细说说命令模式适用于啥场景呢A.2Q.3 举一个命令模式的例子&a…

网络知识点之-BGP协议

边界网关协议&#xff08;BGP&#xff09;是运行于 TCP 上的一种自治系统的路由协议。 BGP 是唯一一个用来处理像因特网大小的网络的协议&#xff0c;也是唯一能够妥善处理好不相关路由域间的多路连接的协议。 BGP 构建在 EGP 的经验之上。 BGP 系统的主要功能是和其他的 BGP 系…

SQL 连接(JOIN)

SQL 连接&#xff08;JOIN&#xff09;是一种用于将两个或多个表中的数据相互匹配的操作&#xff0c;从而形成一个新的数据集合。JOIN 操作常用于查询和分析数据库中的数据&#xff0c;可以根据不同的连接方式返回不同的结果集。 SQL join 用于把来自两个或多个表的行结合起来…

明解STM32—GPIO理论基础知识篇之寄存器原理​

一、前言 在之前的STM32的GPIO理论基础知识中&#xff0c;分别对基本结构和工作模式进行了详细的介绍。GPIO基本结构中主要对GPIO内部的各个功能电路逐一的进行的分析&#xff1b;GPIO工作模式中主要介绍GPIO应用在不同的使用场景下&#xff0c;GPIO端口的静态特征配置和动态的…

FinClip 小程序桌面端商店上线啦

随着技术的不断进步和用户需求的增长&#xff0c;移动应用程序市场日益蓬勃发展。 然而&#xff0c;开发者们面临着一个严峻的挑战&#xff1a;“如何在不同的操作系统上开发和发布应用程序&#xff0c;以满足不同用户群体的需求&#xff1f;”在这方面&#xff0c;使用小程序…

【C++】深层次了解继承,从基础概念到复杂菱形继承问题(文章结尾有菱形继承常见面试题)

1.继承的概念及定义 继承的概念 继承是面向对象设计使代码可以复用的重要手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生的类&#xff0c;称为派生类。 继承的概念并不是固定的&#xff0c;只要能够通过自己的语言…

浅聊webpack的工作原理

参考文献: https://webpack.docschina.org/concepts/ 简述一下 WebPack 是一个模块打包工具&#xff0c;可以使用 WebPack 管理模块。在 webpack 看来&#xff0c;项目里所有资源皆模块&#xff0c;分析模块间的依赖关系&#xff0c;最终编绎输出模块为 HTML、JavaScript、CS…

C++OpenCV(5):图像模糊操作(四种滤波方法)

&#x1f506; 文章首发于我的个人博客&#xff1a;欢迎大佬们来逛逛 &#x1f506; OpenCV项目地址及源代码&#xff1a;点击这里 文章目录 图像模糊操作均值滤波高斯滤波中值滤波双边滤波 图像模糊操作 关于图片的噪声&#xff1a;指的是图片中存在的不必要或者多余的干扰数…