观察 | 用Unity制作一个Siri问答软件

2017-10-24 16:29

原文链接:http://gad.qq.com/article/detail/34549

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

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

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

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

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

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

privatestringtoken;//access_token

privatestringcuid="随便写的d";//用户标识

privatestringformat="pcm";//语音格式

privateintrate=8000;//采样率

privateintchannel=1;//声道数

privatestringspeech;//语音数据,进行base64编码

privateintlen;//原始语音长度

privatestringlan="zh";//语种

privatestringgrant_Type="client_credentials";

privatestringclient_ID="9152186";//百度appkey

privatestringclient_Secret="14c703ce0f900eae40e95b2cdd564472";//百度SecretKey

privatestringbaiduAPI="http://vop.baidu.com/server_api";

privatestringgetTokenAPIPath=

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

privateByte[]clipByte;

///<summary>

///转换出来的TEXT

///</summary>

publicstaticstringaudioToString;

privateAudioSourceaud;

privateintaudioLength;//录音的长度

publicvoidStartRecord()

{

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

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

Microphone.End(null);

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

}

{

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

intlastPos=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));

}

///<summary>

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

///</summary>

///<returns></returns>

publicByte[]GetClipData()

{

if(aud.clip==null)

{

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

returnnull;

}

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

aud.clip.GetData(samples,0);

Byte[]outData=newbyte[samples.Length*2];

intrescaleFactor=32767;//toconvertfloattoInt16

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

{

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

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

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

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

}

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

{

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

returnnull;

}

returnoutData;

}

///<summary>

///获取百度用户令牌

///</summary>

///<paramname="url">获取的url</param>

///<returns></returns>

privateIEnumeratorGetToken(stringurl)

{

WWWgetTW=newWWW(url);

yieldreturngetTW;

if(getTW.isDone)

{

if(getTW.error==null)

{

token=getTW.text;

StartCoroutine(GetAudioString(baiduAPI));

}

else

{

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

}

}

else

{

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

}

}

///<summary>

///把语音转换为文字

///</summary>

///<paramname="url"></param>

///<returns></returns>

privateIEnumeratorGetAudioString(stringurl)

{

JsonWriterjw=newJsonWriter();

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();

WWWgetASW=newWWW(url,Encoding.Default.GetBytes(jw.ToString()));

yieldreturngetASW;

if(getASW.isDone)

{

if(getASW.error==null)

{

JsonDatagetASWJson=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里面打开链接,就可以返回答案了。

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

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

publicstringmsg="";

///<summary>

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

///</summary>

///<paramname="msg">提问的问题</param>

publicvoidGetAnswer(stringmsg)

{

StartCoroutine(GetTuLingtoken(urlmsg));

}

privatestringTuLingtoken="";

///<summary>

//图灵的问答系统

///</summary>

///<paramname="Question">要问的问题</param>

///<returns></returns>

privateIEnumeratorGetTuLingtoken(stringurl)

{

WWWgetTW=newWWW(url);

yieldreturngetTW;

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都能用。

//要播放的语音文字

publicstringAudioMsg="";

privatestringurlForward=@"http://tsn.baidu.com/text2audio?tex=";

publicstringAudioUrl="";

publicAudioStreamDemoasDemo;

publicvoidPlayAudio(stringcontent)

{

Debug.Log(content);

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

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

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

{

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

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

}

asDemo.SetUrlContext(AudioUrl);

asDemo.OnPlay();

}

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

Ben

Ben

线上线下专访、稿件发布合作请联系QQ或微信:328624956

评论已关闭!

相关资讯