上篇回顾

https://blog.csdn.net/weixin_42208093/article/details/106277629
在上篇文章中,我们讲到了讯飞的语音识别和合成以及百度的UNIT 人机交互。
但由于百度的语义技能过少达不到我们想要的要求。类如音乐、故事部分并没有实际的内容,所以我又重新好好研究了一下讯飞AIUI。但由于Window版本的AIUIDLL我们无法使用,就选择了使用WebAPI版AIUI,效果也是一样的。

WebAPI AIUI

WebAPI创建就不说了,在创建好WebAPI AIUI项目后,项目中的开发工具中有C#的示例代码

我们只需要稍微修改下就行,这里就直接贴出修改好的代码。

注意:
1.APPID、API_KEY 是WebAPI的,和之前的SDK版本不一样。
2.另外AUTH_ID 是自己定义的,如果不知道怎么定义可以直接复制【开发工具】中的 “authId”。
3.示例代码中private const string SCENE = “main”; 修改为 “main_box”,不然会出现询问问题,没有回答的情况 【当前页面配置修改仅在测试环境生效,设备端体验需要SDK传参时在情景模式后加“_box”或“更新发布”至生产环境体验。】
4.询问的问题,需要是已添加的商店技能里的问题才能做出正确的回答

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;public class AIUI : MonoBehaviour
{private const string URL = "http://openapi.xfyun.cn/v2/aiui";private const string APPID = "";private const string API_KEY = "";private const string AUE = "raw";private const string AUTH_ID = "2049a1b2fdedae553bd03ce6f4820ac5";private const string DATA_TYPE = "audio";private const string SAMPLE_RATE = "16000";private const string SCENE = "main_box";//需要加_boxprivate const string RESULT_LEVEL = "plain";private string FILE_PATH = "";void Start(){//测试FILE_PATH = Application.streamingAssetsPath + "/Baidu-TTS.pcm";Dictionary<string, string> header = buildHeader();byte[] dataByteArray = readFile(FILE_PATH);print(aiui(dataByteArray));}public static string aiui(byte[] boby){Dictionary<string, string> header = buildHeader();string result = HttpPost(URL, header, boby);return result;}/// <summary>/// http post访问/// </summary>/// <param name="url">链接</param>/// <param name="headerDic">头字典</param>/// <param name="body">主体</param>/// <returns></returns>private static string HttpPost(string url, Dictionary<string, string> headerDic, byte[] body){HttpWebRequest httpWebRequest = null;HttpWebResponse httpWebResponse = null;string result = "";try{httpWebRequest = (HttpWebRequest)WebRequest.Create(url);httpWebRequest.Method = "post";httpWebRequest.Headers.Add("X-Param", headerDic["X-Param"]);httpWebRequest.Headers.Add("X-CurTime", headerDic["X-CurTime"]);httpWebRequest.Headers.Add("X-CheckSum", headerDic["X-CheckSum"]);httpWebRequest.Headers.Add("X-Appid", headerDic["X-Appid"]);httpWebRequest.ContentLength = body.Length;httpWebRequest.GetRequestStream().Write(body, 0, body.Length);httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();Stream responseStream = httpWebResponse.GetResponseStream();result = new StreamReader(responseStream, Encoding.UTF8).ReadToEnd();responseStream.Close();httpWebRequest.Abort();httpWebResponse.Close();}catch (Exception ex){Debug.LogError("Error: " + ex.ToString());}return result;}/// <summary>/// 头字典/// </summary>/// <returns></returns>private static Dictionary<string, string> buildHeader(){TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);string curTime = Convert.ToInt64(ts.TotalSeconds).ToString();//请求参数string param = "{\"aue\":\"" + AUE + "\",\"result_level\":\"" + RESULT_LEVEL + "\",\"sample_rate\":\"" + SAMPLE_RATE + "\",\"auth_id\":\"" + AUTH_ID + "\",\"data_type\":\"" + DATA_TYPE + "\",\"scene\":\"" + SCENE + "\"}";string paramBase64 = Convert.ToBase64String(Encoding.Default.GetBytes(param));string checkSum = EncryptWithMD5(API_KEY + curTime + paramBase64);Dictionary<string, string> header = new Dictionary<string, string>();header.Add("X-Param", paramBase64);header.Add("X-CurTime", curTime);header.Add("X-CheckSum", checkSum);header.Add("X-Appid", APPID);return header;}/// <summary>/// MD5加密/// </summary>/// <param name="source">参数</param>/// <returns></returns>private static string EncryptWithMD5(string source){byte[] sor = Encoding.UTF8.GetBytes(source);MD5 md5 = MD5.Create();byte[] result = md5.ComputeHash(sor);StringBuilder strbul = new StringBuilder(40);for (int i = 0; i < result.Length; i++){//加密结果"x2"结果为32位,"x3"结果为48位,"x4"结果为64位strbul.Append(result[i].ToString("x2"));}return strbul.ToString();}private byte[] readFile(string filePath){FileStream fs = new FileStream(filePath, FileMode.Open);byte[] data = new byte[fs.Length];fs.Read(data, 0, data.Length);fs.Close();return data;}
}

测试

下面我们先简单的测试一下,把AIUI能够跑通。我们需要一段询问问题(类如问天气)的音频文件,可以自己录一段,也可以用语音合成生成一段。我是用的百度的语音合成的,然后直接下载。
https://ai.baidu.com/tech/speech/tts_online

下载下来是Mp3格式的音频,我们还需要做个格式转换,转换成AIUI能识别的.pcm或者.wav
这里我用的是【Cool Edit Pro 2.1】百度自己下一个就行。
另存为:windows pcm 格式就行

添加到unity中 修改脚本音频路径。

运行


通常回答的答案都是在 answer.text中,个别有提供是url,就不是在这了。
json 解析这部分就不说了。

优化

讯飞语音合成这一块做的并不是特别好,Windows 在线版的,其他的不了解。处理合成的时间会随着合成内容的大小而发生变化,100多字的内容,差不多需要5-6秒的处理时间,这个还是很影响用户体验的。百度了一下微软有自己的C#语音合成库:Interop.SpeechLib。处理合成比讯飞快的不是一点点,用法也是特别的简单。需要用线程的来做,不然unity会有假死的状态。

MP3转WAV

AIUI中的【故事】【国学】【音乐】【相声】等技能都是提供的url链接,格式为MP3的格式,unity的WWW或者UnityWebRequest无法加载MP3格式的,就需要我们将MP3转成WAV或者其他可用的格式。
这里使用了NAudio.dll 引用 using NAudio.Wave;

    /// <summary>/// UnityWebRequest 加载MP3播放/// </summary>/// <param name="url"></param>/// <param name="audio"></param>/// <returns></returns>public IEnumerator OnMP3LoadAndPlay(string url, AudioSource audio){UnityWebRequest www = UnityWebRequest.Get(url);yield return www.SendWebRequest();audio.clip = FromMp3Data(www.downloadHandler.data);audio.Play();}/// <summary>/// mp3转wav/// </summary>/// <param name="data">byte[]</param>/// <returns></returns>AudioClip FromMp3Data(byte[] data){//将数据加载到流中MemoryStream mp3stream = new MemoryStream(data);//将流中的数据转换为WAV格式Mp3FileReader mp3audio = new Mp3FileReader(mp3stream);WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(mp3audio);//转换为WAV数据WAV wav = new WAV(AudioMemStream(waveStream).ToArray());AudioClip audioClip = AudioClip.Create("testSound", wav.SampleCount, 1, wav.Frequency, false);audioClip.SetData(wav.LeftChannel, 0);return audioClip;}/// <summary>/// 内存流/// </summary>/// <param name="waveStream">byte[]</param>/// <returns></returns>MemoryStream AudioMemStream(WaveStream waveStream){MemoryStream outputStream = new MemoryStream();using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat)){byte[] bytes = new byte[waveStream.Length];waveStream.Position = 0;waveStream.Read(bytes, 0, Convert.ToInt32(waveStream.Length));waveFileWriter.Write(bytes, 0, bytes.Length);waveFileWriter.Flush();}return outputStream;}

WAV.cs

/* From http://answers.unity3d.com/questions/737002/wav-byte-to-audioclip.html */
public class WAV
{// convert two bytes to one float in the range -1 to 1static float bytesToFloat(byte firstByte, byte secondByte){// convert two bytes to one short (little endian)short s = (short)((secondByte << 8) | firstByte);// convert to range from -1 to (just below) 1return s / 32768.0F;}static int bytesToInt(byte[] bytes, int offset = 0){int value = 0;for (int i = 0; i < 4; i++){value |= ((int)bytes[offset + i]) << (i * 8);}return value;}// propertiespublic float[] LeftChannel { get; internal set; }public float[] RightChannel { get; internal set; }public int ChannelCount { get; internal set; }public int SampleCount { get; internal set; }public int Frequency { get; internal set; }public WAV(byte[] wav){// Determine if mono or stereoChannelCount = wav[22];     // Forget byte 23 as 99.999% of WAVs are 1 or 2 channels// Get the frequencyFrequency = bytesToInt(wav, 24);// Get past all the other sub chunks to get to the data subchunk:int pos = 12;   // First Subchunk ID from 12 to 16// Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal))while (!(wav[pos] == 100 && wav[pos + 1] == 97 && wav[pos + 2] == 116 && wav[pos + 3] == 97)){pos += 4;int chunkSize = wav[pos] + wav[pos + 1] * 256 + wav[pos + 2] * 65536 + wav[pos + 3] * 16777216;pos += 4 + chunkSize;}pos += 8;// Pos is now positioned to start of actual sound data.SampleCount = (wav.Length - pos) / 2;     // 2 bytes per sample (16 bit sound mono)if (ChannelCount == 2) SampleCount /= 2;        // 4 bytes per sample (16 bit stereo)// Allocate memory (right will be null if only mono sound)LeftChannel = new float[SampleCount];if (ChannelCount == 2) RightChannel = new float[SampleCount];else RightChannel = null;// Write to double array/s:int i = 0;int maxInput = wav.Length - (RightChannel == null ? 1 : 3);// while (pos < wav.Length)while ((i < SampleCount) && (pos < maxInput)){LeftChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);pos += 2;if (ChannelCount == 2){RightChannel[i] = bytesToFloat(wav[pos], wav[pos + 1]);pos += 2;}i++;}}public override string ToString(){return string.Format("[WAV: LeftChannel={0}, RightChannel={1}, ChannelCount={2}, SampleCount={3}, Frequency={4}]", LeftChannel, RightChannel, ChannelCount, SampleCount, Frequency);}
}

Unity AIUI相关推荐

  1. Unity与讯飞的aiui交互

    前言最近项目是做机器人,机器人最大的(普通的)AI功能就是语音交流,所以AIUI就是一个很好的选择.AIUI是封装了,讯飞的语音合成.语音识别等功能,重点是它有个兜底功能选择,还有技能工作室的加持,虽 ...

  2. Unity与讯飞语音交互:使用aiui技能

    语音交互 说到人工智能,离不开语音,大家会认为一个设备可以跟人对话是有智能的体现,在国内语音智能研发,讯飞是公认的做的最好的,在了解语音智能时,客户提的是讯飞,因为他们目标是要做一个好的语音交互.客户 ...

  3. unity接入讯飞AIUI(Windows SDK)

    一.什么是AIUI AIUI 是一套人机交互解决方案,整合了语音唤醒.语音识别.语义理解.内容平台.语音合成(比普通的语音合成多一个发音人)等能力. 新用户有20个免费的装机量,每天有500交互次数 ...

  4. Unity XCode交互(unity调用讯飞的AIUI技能ios的sdk)

    最近要做ios的讯飞语音(aiui技能) 文章目录 前言 一.讯飞项目 二.XCode 1. 2.设置AIUI 2.创建AIUI 3.唤醒,录音,停止录音AIUI,文本写入 4.AIUI数据监听 5. ...

  5. Unity AI 语音识别、语音合成、人机交互(一)

    自我介绍 大家好,我是VAIN,这是我在CSDN的第一篇文章,之前一直在微博博客上写文章,今后会用CSDN给大家更新一些技术帖,还希望大家多多关照! 项目介绍 因为公司项目要求,今天给大家分享一个un ...

  6. Unity制作批量配音制作工具

    最近一直在忙项目,都没有时间和大家分享文章了.今天是来送福利的,送个大家一个语音合成音频工具,当然这也是用Unity制作的.看到讯飞官网有个配音制作,还需要收费,我就不能忍啊,就把之前之前做的批量配音 ...

  7. [Unity WWW] 跨域访问解决方法

    什么是跨域访问 域(Domain)是Windows网络中独立运行的单位,域之间相互访问则需要建立信任关系(即Trust Relation).信任关系是连接在域与域之间的桥梁.当一个域与其他域建立了信任 ...

  8. unity人物旋转移动代码_Unity3D研究院之脚本实现模型的平移与旋转(六)

    123 说: 雨松大大,有个问题想请教一下,我用UNET构建了个小场景,在电脑上可以客户端可以连接到服务器,Windows和Linux都可以,发布到安卓缺连不了,这是问什么呢 说: 求教一下,刚刚接触 ...

  9. unity课设小游戏_Unity制作20个迷你小游戏实例训练视频教程

    本教程是关于Unity制作20个迷你小游戏实例训练视频教程,时长:20小时,大小:3.8 GB,MP4高清视频格式,教程使用软件:Unity,附源文件,作者:Raja Biswas,共97个章节,语言 ...

最新文章

  1. 解决THINKPHP 支付宝接口异步notify 无效可能的问题。
  2. 『中级篇』docker之wordpress容器SSL(番外篇)(78)
  3. php$后面加点有什么用,css和js后加问号和数字有什么用
  4. 删除fedora多余内核:解决每次升级后旧内核还会存在的问题
  5. java 代码块 作用_Java核心(三):代码块的作用
  6. Storm精华问答 | Kafka在Storm中的角色是什么?
  7. 在装有raid卡的服务器上安装Ubuntu
  8. Spring AOP 的切点切在Controller上没有起作用的问题。
  9. windows录屏_ApowerREC for Mac(屏幕录屏工具) V1.2.7.10激活版
  10. 《梦断代码》读书笔记——第3、4、5章
  11. 作死把mysql root用户的权限给去掉了或者忘记密码了怎么办
  12. 电脑连接电视方法详解_笔记本连接电视有哪些设置方法
  13. Spring的开幕式——Spring概述与设计思想
  14. 数值分析期末考试复习(引论)
  15. 实现局部滚动的两种方法:1.三行css代码2.使用BScroll框架
  16. LED驱动程序的编写
  17. 微软 MSCRM 教育成功案例 界面展示
  18. STL 自定义sort 前缀和差分练习
  19. 创造一个计算机语言,世界上第一个文言文编程语言诞生,创造它的是一个大学生...
  20. kubernetes 二进制安装(v1.20.16)(四)部署 master

热门文章

  1. 如何快速完成一份学术型PPT
  2. 经典电影台词系列【3】——无间道
  3. c++11 regex
  4. C++正则表达式(regex_match、regex_search与regex_replace)
  5. Kubernetes学习-K8S安装篇-Kubeadm安装高可用K8S集群
  6. java 获取指定日期的前几天或后几天
  7. css保持长宽比拉伸,使用CSS保持div的长宽比
  8. 史上最经典的10大反间计
  9. suse报:passwd: Module is unknown passwd: password unchanged 或 passwd: Permission denied
  10. Leetcode-二分+递归/回溯-1723. 完成所有工作的最短时间