admin管理员组文章数量:1562608
前言
最近项目是做机器人,机器人最大的(普通的)AI功能就是语音交流,所以AIUI就是一个很好的选择。AIUI是封装了,讯飞的语音合成、语音识别等功能,重点是它有个兜底功能选择,还有技能工作室的加持,虽然在开发应用中有很多的吐槽,但是本人对讯飞还是非常佩服的。而且在做项目时,发现目前unity跟aiui开发的技术文档少,所以还是想写个技术文档希望对看到的人有帮助。(第一次写技术博客,如果有不满,请多多包涵,多多指教,谢谢)
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、AIUI平台配置
- 二、开发步骤
- 1.开发环境
- 2.开发代码
- 总结
- 补充
前言
最近项目是做机器人,机器人最大的(普通的)AI功能就是语音交流,所以AIUI就是一个很好的选择。AIUI是封装了,讯飞的语音合成、语音识别等功能,重点是它有个兜底功能选择,还有技能工作室的加持,虽然在开发应用中有很多的吐槽,但是本人对讯飞还是非常佩服的。而且在做项目时,发现目前unity跟aiui开发的技术文档少,所以还是想写个技术文档希望对看到的人有帮助。(第一次写技术博客,如果有不满,请多多包涵,多多指教,谢谢)
一、AIUI平台配置
示例: 在讯飞申请的应用中—>其他—>AIUI平台,开通AIUI功能。上面有技术文档,是官方AIUI开发技术文档。(如下图)
AIUI平台的应用配置很重要,在里面可以配置你项目的基本技能跟信息。其中的语音技能是亮点一,在里面你能选择你需要的技能,无需你再次开发,是不是超棒的。其中有个自定义技能,这里你可以自己做你要的技能,解决了你项目的独立需求要求。关于自定义技能,可以再写一篇技术博客,因为我在上面遇到不少坑,我好想吐槽它,但是它也是真的很棒。语义技能中的设备人设也是很棒的,你可以把你的产品人设直接做到这个机器人设中,加入到基本技能里面,那么你的产品就有了它的自己人设,快捷方便。设备人设也是在技能工作室中设置。
AIUI的第二个亮点是它的兜底功能,里面有三个兜底选要项,多选,喜欢你就都选,不想要那么多就单选,不喜欢就多不选。如果要用到该AIUI功能,一定要发布。所以请提交审核上线。
到这里AIUI技能就已经网页配置好了,因为我的项目系统时安卓,而我开发环境是unity,所以我选择是AIUI SDK在Android Studio开发,然后导出jar到unity在调用接口。
二、开发步骤
1.开发环境
Unity,androidStudio
前面(示例):
2.开发代码
代码如下(示例):
下载AIUI SDK 后解压把相应的资源提出(如下图),配置到你的Androidstudio项目模块中。讯飞项目的资源文件是跟你申请的项目挂钩的,所以一定要用你申请的AIUI SDK
中的配置资源。如果你需要唤醒功能需要再下载唤醒SDK(看上图,里面有唤醒sdk),把里面的jet放到assets/ivw/中。
unity与androidStudio交互网上有很多技术文档,多可以看,这里我就不累赘了(跳过,因为我很懒)。
接下来就是写代码实现功能。这部分很重要(看图),appid是应用信息里面的APPID不能错了哦,错了就不能调用实现讯飞的功能。
然后是监听信息:
AIUIListener mAIUILis=new AIUIListener() {
@Override
public void onEvent(AIUIEvent aiuiEvent) {
switch (aiuiEvent.eventType) {
//唤醒事件
case AIUIConstant.EVENT_CONNECTED_TO_SERVER:
tips = "已连接服务器";
break;
case AIUIConstant.EVENT_SERVER_DISCONNECTED:
tips = "与服务器断连" ;
break;
case AIUIConstant.EVENT_WAKEUP:
tips = "进入识别状态" ;
break;
//结果事件(包含听写,语义,离线语法结果)
case AIUIConstant.EVENT_RESULT:
if (aiuiEvent.info != null) {
int node = 0;//结果解析事件
// s1
try {
JSONObject bizParamJson = new JSONObject(aiuiEvent.info);
JSONObject data = bizParamJson.getJSONArray("data").getJSONObject(0);
JSONObject params = data.getJSONObject("params");
node = 2;
JSONObject content = data.getJSONArray("content").getJSONObject(0);
long rspTime = aiuiEvent.data.getLong("eos_rslt", -1); //响应时间
// 听写结果(iat) 语义结果(nlp) 后处理服务结果(tpp) 云端tts结果(tts) 翻译结果(itrans)
String sub = params.optString("sub");
if (content.has("cnt_id") && !"tts".equals(sub)) //查询对象是否包含该key,返回boolean,与Map.containsKey(key)用法一致
{
String cnt_id = content.getString("cnt_id");
node = 0;
JSONObject cntJson = new JSONObject(new String(aiuiEvent.data.getByteArray(cnt_id), "utf-8"));
// 语义结果
if ("nlp".equals(sub)) {
NLPResult(cntJson);
}
// 听写结果
else if ("iat".equals(sub)) {
IATResult(cntJson);
}
} else if ("tts".equals(sub)) {
TTSResult(aiuiEvent, content);
//endregion
} else {
tips = "cnt_id is null" ;
}
} catch (Throwable e) {
}
} else {
tips = "info is null";
}
break;
case AIUIConstant.EVENT_TTS:
switch (aiuiEvent.arg1) {
case AIUIConstant.TTS_SPEAK_BEGIN:
tips = ("开始播放");
if (isRecording) {
String params = "data_type=audio,sample_rate=16000";
//停止写入
AIUIMessage msg = new AIUIMessage(AIUIConstant.CMD_STOP_RECORD, 0, 0, params, null);
mAIUI.sendMessage(msg);
}
break;
case AIUIConstant.TTS_SPEAK_COMPLETED:
tips = ("播放完成");
}
break;
}
break;
//region START
//休眠事件
case AIUIConstant.EVENT_SLEEP:
tips = "休眠";
break;
// 状态事件
case AIUIConstant.EVENT_STATE:
mAIUIState = aiuiEvent.arg1;
switch (aiuiEvent.arg1) {
// 闲置状态,AIUI未开启
case AIUIConstant.STATE_IDLE:
tips = "0:未开启";
break;
// AIUI已就绪,等待唤醒
case AIUIConstant.STATE_READY:
tips = "1:等待唤醒";
break;
// AIUI工作中,可进行交互
case AIUIConstant.STATE_WORKING:
// tips="2:可进行交互";
break;
}
break;
//错误事件
case AIUIConstant.EVENT_ERROR:
tips = "错误: " + aiuiEvent.arg1 + "\n" + aiuiEvent.info;
//aiuiEvent.arg1 =20006 没有开启录音
break;
case AIUIConstant.EVENT_START_RECORD: {
//开始录音事件
// tips="开始录音 ";
}
break;
case AIUIConstant.EVENT_STOP_RECORD: {
//停止录音事件
tips = "停止录音 ";
}
break;
}
}
};
听写解析代码:
void IATResult(JSONObject iatjson)
{
JSONObject text=iatjson.optJSONObject("text");
//
StringBuffer iatText=new StringBuffer();
try
{
JSONArray words=text.getJSONArray("ws");
boolean iatResult=text.optBoolean("ls");
for(int node=0;node<words.length();node++)
{
JSONArray cwWord=words.optJSONObject(node).optJSONArray("cw");
for(int snode=0;snode<cwWord.length();snode++)
{
iatText.append(cwWord.optJSONObject(snode).opt("w"));
}
}
if(!TextUtils.isEmpty(iatText))
{
// tips=iatText+"\n iat="+text.toString();
messageAS=new MessageAS("iat",iatText.toString());
tips=messageAS.ToString();
return;
}
}catch(Exception e)
{
}
}
播报解析代码:
```java
void TTSResult(AIUIEvent event,JSONObject content)
{
if(content.has("cnt_id"))
{
String sid = event.data.getString("sid");
try
{
String cnt_id = content.getString("cnt_id");
byte[] audio = event.data.getByteArray(cnt_id); //合成音频数据
int id=content.getInt("frame_id");
seg =content.getString("text_seg");
if(seg.length()==0||seg==null||seg.equals(",")||seg.equals(" ,"))
{
return;
}
else if(textMap.containsKey(id))
{
textMap.replace(id,seg);
}
else if(!textMap.containsValue(seg))
{
textMap.put(id,seg);
}
tips=textMap.values().ToString();
}
catch (Exception e)
{
}
}
}
void NLPResult(JSONObject cntJson)
{
JSONObject result = cntJson.optJSONObject("intent");//?
if(result.length() != 0 && result!=null)
return;
tips=result.toString();
}
前面说了讯飞的资源是根据你申请的AIUI配置,是一对一的,再调用讯飞接口时,你会明显感觉它的配置让你想:就不能简单一点。自己配置可以实现多元化的功能需求,但是也是操作麻烦(AIUI的工程师大神,这真的有些烦人)。资源里有配置文件aiui_phone.cfg,各种配置多是跟它有密切关系,请一定要把它放好到assets/scf中,然后解析读取,配置到讯飞的创建中。
private String getAIUIParams() {
String params = "";
AssetManager assetManager = getResources().getAssets();
try {
InputStream ins = assetManager.open( "cfg/aiui_phone.cfg" );
byte[] buffer = new byte[ins.available()];
ins.read(buffer);
ins.close();
params = new String(buffer);
} catch (IOException e) {
tips="cfg:"+e.toString();
OnTips(tips);
}
return params;
}
快结束了,申请收音代码:
public void startVoice()
{
AIUIMessage setMsg0=new AIUIMessage(AIUIConstant.CMD_TTS, AIUIConstant.PAUSE, 0, null, null);
String params = "sample_rate=16000,data_type=audio";
params+=",vad={\"vad_enable\":\"1\",\"engine_type\":\"meta\", \"res_type\":\"assets\",\"res_path\":\"vad/meta_vad_16k.jet\"}";
AIUIMessage writeMsg = new AIUIMessage( AIUIConstant.CMD_START_RECORD, 0, 0, params, null );
String setParams = "{\"global\":{\"scene\":\"main_box\"}}";
AIUIMessage setMsg = new AIUIMessage(AIUIConstant.CMD_SET_PARAMS, 0 , 0, setParams, null);
}
//取消录音
public void stopVoice()
{
String params = "data_type=audio,sample_rate=16000";
//停止写入
AIUIMessage msg = new AIUIMessage(AIUIConstant.CMD_STOP_RECORD, 0, 0, params, null);
mAIUI.sendMessage(msg);
}
Unity调用讯飞接口跟AIUI SDK交接,你就可以聊天了。
public AndroidJavaObject andObj;
void Start()
{
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
andObj = jc.GetStatic<AndroidJavaObject>("currentActivity");
}
//调用接口跟讯飞语音交流
void OnVoiceNlp()
{
// print("fff");
try
{
andObj.Call("startVoice";
}
catch (Exception e)
{
tips = e.ToString();
}
}
//获取讯飞语音内容
public void UITips(string str)
{
textjson.text =str;
}
把解析信息反馈到Unity。
总结
到这里Unity与讯飞的AIUISDK的交互就是完成了,你已经能够再快速的完成一款AI聊天设备。哦,一定要再Android Studio的AndroidManifest.xml里面添加需要的权限,权限代码在讯飞的开发文档里就可以找到。
补充
UnityPlayer 函数调用,在AS 的对应Module的lib加入Classes.jar
UnityPlayer.UnitySendMessage("ObjName","FunctionName","传递信息");
版权声明:本文标题:Unity与讯飞的aiui交互 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/xitong/1727479748a1116678.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论