手机网游
手机网游
休闲娱乐
模拟经营
赛车驾驶
冒险解谜
恋爱养成
策略塔防
战争对抗
体育竞速
卡牌对阵
VR游戏
3D手游
武侠修仙
动作闯关
射击枪战
音乐舞蹈
横板格斗
双人游戏
换装游戏
橙光游戏
其他游戏
传奇手游
安卓软件
安卓软件
主题壁纸
购物优惠
资讯阅读
健康美食
地图出行
影音播放
教育学习
游戏辅助
摄影摄像
其他软件
金融理财
言情小说
生活服务
电竞赛事
通讯社交
系统工具
效率办公
安卓游戏
安卓游戏
益智休闲
动作冒险
网络游戏
模拟经营
儿童教育
体育竞速
策略塔防
冒险解谜
角色扮演
音乐游戏
飞行射击
赛车游戏
破解游戏
传奇手游
其他游戏
攻略资讯
攻略资讯
游戏资讯
游戏攻略
游戏问答
软件教程
合集
合集
教程合集
游戏合集
软件合集
文章合集
首页 > 攻略资讯 > 游戏资讯

用Unity制作一个Siri问答软件

编辑:啊妹 2017-10-24

大家好,我是云图。 之前项目有个需求要做一个简单的siri类似的问答系统,经过一番周折,终于还是实现出来了,软件不单可以在pc上面运行,也可以打包到安卓,ios平台,真正实现一键跨平台打包。

现在我们先说一些实现的思路,所谓问答系统,第一步就是用户首先说一句话,然后我们的软件把听到的话转换成文字。那现在问题有了,

第二步我们就需要一个地方,把我们的问题文字转化成我们软件回答的答案内容。

第三步就是把要回答的文字读出来。

思路有了,开始动手,首先,我们把用户输入的语音,要转成文字,经过我几个挑选,我发现百度语音和讯飞语音都不错,只不过讯飞语音的接入麻烦了点,

所以就采用了百度的语音识别

private string token; //access_token

private string cuid = "随便写的d"; //用户标识

private string format = "pcm"; //语音格式

private int rate = 8000; //采样率

private int channel = 1; //声道数

private string speech; //语音数据,进行base64编码

private int len; //原始语音长度

private string lan = "zh"; //语种

private string grant_Type = "client_credentials";

private string client_ID = "9152186"; //百度appkey

private string client_Secret = "14c703ce0f900eae40e95b2cdd564472"; //百度Secret Key

private string baiduAPI = "http://vop.baidu.com/server_api";

private string getTokenAPIPath =

"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=ekGb1G5XHY4BIVSA8nLzX5cA&client_secret=14c703ce0f900eae40e95b2cdd564472";

private Byte[] clipByte;

///

/// 转换出来的TEXT

///

public static string audioToString;

private AudioSource aud;

private int audioLength;//录音的长度

public void StartRecord()

{

Debug.Log("开始说话");

if (Microphone.devices.Length == 0) return;

Microphone.End(null);

aud.clip = Microphone.Start(null, false, 10, rate);

}

public void EndRecord()

{

Debug.Log("结束说话");

int lastPos = Microphone.GetPosition(null);

if (Microphone.IsRecording(null))

audioLength = lastPos / rate;//录音时长

else

audioLength = 10;

Microphone.End(null);

clipByte = GetClipData();

len = clipByte.Length;

speech = Convert.ToBase64String(clipByte);

StartCoroutine(GetToken(getTokenAPIPath));

StartCoroutine(GetAudioString(baiduAPI));

}

///

/// 把录音转换为Byte[]

///

///

public Byte[] GetClipData()

{

if (aud.clip == null)

{

Debug.LogError("录音数据为空");

return null;

}

float[] samples = new float[aud.clip.samples];

aud.clip.GetData(samples, 0);

Byte[] outData = new byte[samples.Length * 2];

int rescaleFactor = 32767; //to convert float to Int16

for (int i = 0; i < samples.Length; i )

{

short temshort = (short)(samples[i] * rescaleFactor);

Byte[] temdata = System.BitConverter.GetBytes(temshort);

outData[i * 2] = temdata[0];

outData[i * 2 1] = temdata[1];

}

if (outData == null || outData.Length <= 0)

{

Debug.LogError("录音数据为空");

return null;

}

return outData;

}

///

/// 获取百度用户令牌

///

/// 获取的url

///

private IEnumerator GetToken(string url)

{

WWW getTW = new WWW(url);

yield return getTW;

if (getTW.isDone)

{

if (getTW.error == null)

{

token = getTW.text;

StartCoroutine(GetAudioString(baiduAPI));

}

else

{

Debug.LogError("获取令牌出错" getTW.error);

}

}

else

{

Debug.LogError("下载出错" getTW.error);

}

}

///

/// 把语音转换为文字

///

///

///

private IEnumerator GetAudioString(string url)

{

JsonWriter jw = new JsonWriter();

jw.WriteObjectStart();

jw.WritePropertyName("format");

jw.Write(format);

jw.WritePropertyName("rate");

jw.Write(rate);

jw.WritePropertyName("channel");

jw.Write(channel);

jw.WritePropertyName("token");

jw.Write(token);

jw.WritePropertyName("cuid");

jw.Write(cuid);

jw.WritePropertyName("len");

jw.Write(len);

jw.WritePropertyName("speech");

jw.Write(speech);

jw.WriteObjectEnd();

WWW getASW = new WWW(url, Encoding.Default.GetBytes(jw.ToString()));

yield return getASW;

if (getASW.isDone)

{

if (getASW.error == null)

{

JsonData getASWJson = JsonMapper.ToObject(getASW.text);

if (getASWJson["err_msg"].ToString() == "success.")

{

audioToString = getASWJson["result"][0].ToString();

if (audioToString.Substring(audioToString.Length - 1) == ",")

audioToString = audioToString.Substring(0, audioToString.Length - 1);

Debug.Log("说话的问题是:" audioToString);

GetAnswer(audioToString);

}

else

{

Debug.LogWarning("没有成功:" getASWJson["err_msg"].ToString());

}

}

else

{

Debug.LogError(getASW.error);

}

}

}

首先你要去百度语音官网申请一个开发者权限,这些细节在这里就不讨论了,很简单。重要的就是两个参数 client_ID和client_Secret 的内容,填写到获取token的网页中发上去,获取到token后百度就知道我们是哪个用户哪个软件在调用语音识别了。这里在ios运行的时候有时候会显示获取不到token,原因是苹果不给我们这样发信息获取内容,说不安全,需要用其他办法。其他办法有很多,最笨的方法就是提前获取到token,然后写死在程序,坏处就是一个月会变一次,比较麻烦。好了,现在我们的语音已经传上百度然后转成文字下来, 下一步我采用的是图灵的文字问答系统。图灵这个做的也是非常好用的,直接把我们的问题文字写到url里面打开链接,就可以返回答案了。

private string url = "http://www.tuling123.com/openapi/api?key=d91b25b8866fef13f82cd28c0d523c8a&info=";

private string QuestionUrl= "http://www.tuling123.com/openapi/api?key=d91b25b8866fef13f82cd28c0d523c8a&info=";

public string msg = "";

///

/// 获取图灵返回的答案

///

/// 提问的问题

public void GetAnswer(string msg)

{

StartCoroutine(GetTuLingtoken(url msg));

}

private string TuLingtoken = "";

///

/// 图灵的问答系统

///

/// 要问的问题

///

private IEnumerator GetTuLingtoken(string url)

{

WWW getTW = new WWW(url);

yield return getTW;

if (getTW.isDone)

{

if (getTW.error == null)

{

TuLingtoken = getTW.text;

TuLingtoken = JsonMapper.ToObject(getTW.text)["text"].ToString();

PlayAudio(TuLingtoken);

}

else

{

Debug.LogError(getTW.error);

}

}

}

到这里我们就获取到我们要回答用户答案的音频了,回答的答案特别骚气。

我相信到这一步很多做类似项目的也有不少人做到了,可就是这里没办法做下去了,为什么呢,

因为要用unity把网络的音频下载下来播放是非常麻烦的事情,我至今都没找到办法,就算用c#的办法解决了,可是安卓和ios呢,根本调用不了,再者就是就算你下载下来了,unity好像没有提供外部播放音频的功能,我不知道是我能力不足还是unity的问题,感觉很基本的事情居然没有解决方案。自我怀疑中。。。。

你可能要问了,那么有没有一种办法能解决这个多平台播放音频的问题呢? 当然有了,我用了FMOD这个插件,可以直接播放网页的在线音频,

用了一个插件集成进来,最后一步就把网页音频地址传进去,就解决了播放的问题,而且是跨平台的,ios ,安卓,pc都能用。

//要播放的语音文字

public string AudioMsg = "";

private string urlForward = @"http://tsn.baidu.com/text2audio?tex=";

public string AudioUrl = "";

public AudioStreamDemo asDemo;

public void PlayAudio(string content)

{

Debug.Log(content);

AudioUrl = @"http://tsn.baidu.com/text2audio?tex=" content "&lan=zh&cuid=随便写的&ctp=1&tok=" token;//

string[] arrPunc = { ",", "。", "”", ";", "“", " " };

for (int i = 0; i < arrPunc.Length; i)

{

//用空白字符来替换指定的标点符号,也就相当于删除掉了标点符号

AudioUrl = AudioUrl.Replace(arrPunc[i], " ");

}

asDemo.SetUrlContext(AudioUrl);

asDemo.OnPlay();

}

就这么点代码,当初找不到方案的时候头疼了2个星期。 好在在不放弃的坚持下还是搞定了,中间走了不少弯路,好在有 MemoryC 大神的帮助下, 也一个个解决了,为 MemoryC大神打call 我把这三步骤已经缩减到一个类里面,方便大家查阅,提一下目前这个功能的一点短处,就是说完话以后要尽快点结束,让语音不浪费那么多空间, 增快识别速度,最快的时候可以在2秒内读出答案,网速好的话比较好。我测试在安卓读的最快,然后是pc,最慢是ios,测试的机器是iphone5,不知道和这个有没有关系。再说点这个东西的拓展,比如一些项目有一些运行了windows系统的机器人,展厅的一些全息 投影之类的项目,都可以接入这个功能,让项目更有可玩性。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

良心推荐

今天乖乖手游为大家带来一些跟螃蟹有关的游戏,在这里玩家可以自由操控螃蟹进行战斗,游戏角色都是以螃蟹为主的,趣味关卡非常多,感兴趣的玩家可以下载一试。

相关资讯