16. AI功能
目前已开发的AI相关功能有:AI云服务、AI表盘
Important
公版发出去的项目工程,编译是无法正常使用AI相关功能的。需要先前往科大讯飞注册开通相关功能。在对应位置进行配置【APPID】【APISecret】【APIKey】。
16.1. AI云服务
Note
为兼容AI表盘功能,若App用到AI云服务功能的话,需要使用优化后的AI云服务功能(AIManager),不能使用优化前的AI云服务功能(AIServeManager)。如何区分AI云服务功能,是优化前还是优化后?优化后的AI云服务功能是集成在 AIManager.class 内,优化前是单独在 AIServeManager.class 实现
固件对应的功能:【科大讯飞AI】
App对应的功能:【设备】->【AI云服务】。
初始化设备时,设备端告诉App是否支持AI云服务功能。
设备端开始录音时,发送RCSP命令告诉App端开始录音。然后就开始传输录音数据。
设备端停止录音,发送RCSP命令告诉App端停止录音,是否需要传输录音识别结果,是否需要传输语义识别结果,是否需要播放TTS。
App收到开始录音后,开始把接受到的实时录音数据进行Opus转码成PCM数据,转码PCM结果发送给科大讯飞服务器。App收到停止录音后,发送录音结束命令给科大讯飞服务器。科大讯飞先返回语言识别结果,再返回语音识别结果,再返回语义识别结果,App根据语义识别结果进行TTS转换。
App端把语音识别结果、语义识别结果,TTS播放状态发送给设备端。
16.1.1. 时序图
16.1.2. 科大讯飞配置
如不使用科大讯飞的SDK,改用其他平台的AISDK。可跳过这一步。
公版发出去的HealthAide项目,编译后是无法正常使用AI云服务功能。需要先前往科大讯飞注册开通【星火认知大模型-星火大模型V1.5】、【语音识别】、【语音合成】功能。
在 IflytekChatWrapper.class IflytekIatWrapper.class IflytekTtsWrapper.class 对应位置配置【APPID】【APISecret】【APIKey】。
//IflytekChatWrapper.class
public IflytekChatWrapper(Context context) {
......
if (!TextUtils.isEmpty(BuildConfig.IFLYTEK_APP_ID)) {//TODO 需要注释掉这一行
//TODO 请先在科大讯飞平台申请,请填写正确appId,appKey,apiSecret。否则会闪退
final AiHelper.Params.Builder params = AiHelper.Params.builder()
.appId("ffffffff"/**APPID**/)
.apiKey("fffffffffffffffffffffffffffffff"/**APIKey**/)
.apiSecret("ffffffffffffffffffffffffffffffff"/**APISecret**/)
.workDir(rootFile.getPath());
......
}
}
//IflytekIatWrapper.class
public IflytekIatWrapper(Context context) {
//开log
Setting.setShowLog(true);
//初始化即创建语音配置对象
if (!TextUtils.isEmpty(BuildConfig.IFLYTEK_APP_ID)) {//TODO 需要注释掉这一行
//TODO 请先在科大讯飞平台申请,请填写正确appId。否则会闪退
SpeechUtility.createUtility(context, SpeechConstant.APPID + "=" + "ffffffff"/**APPID**/);
}
//初始化识别无UI识别对象
mSpeechRecognizer = SpeechRecognizer.createRecognizer(context, mIatInitListener);
}
//IflytekTtsWrapper.class
public IflytekTtsWrapper(Context context) {
//开log
Setting.setShowLog(true);
//初始化即创建语音配置对象
if (!TextUtils.isEmpty(BuildConfig.IFLYTEK_APP_ID)) {//TODO 需要注释掉这一行
//TODO 请先在科大讯飞平台申请,请填写正确appId。否则会闪退
SpeechUtility.createUtility(context, SpeechConstant.APPID + "=" + "ffffffff"/**APPID**/);
}
// 初始化合成对象
mTts = SpeechSynthesizer.createSynthesizer(context, mTtsInitListener);
}
16.1.3. 使用示例
/**
* @ClassName: AICloudServerDemo
* @Description: AI云服务功能示例
* @Author: ZhangHuanMing
* @CreateDate: 2023/12/28 11:23
*/
public class AICloudServerDemo {
private AIManager mAIManager;
private final Observer<SessionInfo> mRecordStatusObserver = sessionInfo -> {
if (sessionInfo != null) {
switch (sessionInfo.getStatus()) {
case SessionInfo.STATE_RECORD_START://开始录音
case SessionInfo.STATE_RECORDING://录音中
case SessionInfo.STATE_IDLE://默认状态
case SessionInfo.STATE_RECORD_END://录音结束
case SessionInfo.STATE_IAT_END://语音识别结束
case SessionInfo.STATE_NLP_END://语义识别结束
case SessionInfo.STATE_FAIL://异常
//获取当前对话消息
List<AICloudMessage> aiCloudMessageList= sessionInfo.getSessionMessageList();
for (AICloudMessage aiCloudMessage:aiCloudMessageList) {
//获取对话的类型。0;用户,1;AI
int itemType = aiCloudMessage.getItemType();
//获取消息的数据实体
AICloudMessageEntity entity = aiCloudMessage.getEntity();
entity.getAiCloudState();//此消息的语音识别状态
entity.getDevMac();//设备mac
entity.getId();//消息的唯一id
entity.getRevId();//消息对应的回复消息的id
entity.getRole();//消息的角色,0;用户,1;AI
entity.getText();//消息的文本
entity.getTime();//消息的时间
entity.getUid();//用户的唯一id
}
break;
}
}
};
/**
* 初始化AIManager
*/
@Test
public void init(Context context){
//Step1. 初始化
AIManager.init(context, WatchManager.getInstance());
mAIManager = AIManager.getInstance();
//Step2. 监听对话状态。请根据使用场景选择observeForever或observe
mAIManager.getAICloudServe().currentSessionMessageMLD.observeForever(mRecordStatusObserver);
}
/**
* 获取录音开始时间
*/
@Test
public long getStartRecordTime(){
return mAIManager.getAICloudServe().getStartRecordTime();
}
/**
* 停止语音合成
*/
@Test
public void stopTTS(){
mAIManager.getAICloudServe().stopTTS();
}
}
16.1.4. 接入其他AI平台
请参考 IflytekAICloudServeHandler.class、 IflytekAIIatHandler.class 调用 BaseAICloudServeHandler、 BaseAIIatHandler 的方法
//BaseAIIatHandler.class
//基础语音识别处理
public abstract class BaseAIIatHandler extends BaseAIHandler {
/**
* 需要实现
*/
//设备断开
abstract void onDeviceDisconnect();
// 开始录音
abstract void onRecordStart();
// 收到录音数据(已解码成PCM格式)
abstract void onRecordData(byte[] recordData);
// 录音结束
abstract void onRecordStop();
// 录音取消
abstract void onRecordCancel();
/**
* 需要调用
*/
//语音识别异常标志位
void setRecognizerFail(boolean recognizerFail);
//网络异常标志位
void setNetworkWrong(boolean networkWrong);
//识别结果
void onRecognizerResult(String iatString);
//识别失败
void onRecognizerFail();
}
//BaseAICloudServeHandler.class
//AI云服务处理流程
public abstract class BaseAICloudServeHandler extends BaseAIChatHandler {
/**
* 需要实现
*/
/**
* 停止TTS合成播放
*/
abstract void onStopTTS();
/**
* 开始TTS合成播放
*/
abstract void onStartTTS(String ttsText);
/**
* 开始对话
*
* @param userText 用户文本
*/
abstract void onStartChat(String userText);
/**
* 处理对话状态
*/
abstract void onHandlerSessionStatus(int status);
/**
* 需要调用
*/
//添加语义文本对话内容
protected void addNlpTTSMessage(String nlpText);
//开始语义对话
protected void onStartChat();
//播放tts失败
protected void onPlayTTSFail();
//播放tts结束
protected void onPlayTTSStop();
}
16.1.5. 是否支持AI云服务
如何判断设备是否支持AI云服务功能
WatchConfigure configure mWatchManager.getWatchConfigure(device);
boolean isSupportAICloud = configure == null || configure.getFunctionOption() != null && configure.getFunctionOption().isSupportAICloud();;
16.2. AI表盘
固件对应的功能:【AI表盘】
App对应的功能:【设备】->【AI表盘】。
初始化设备时,设备端告诉App是否支持AI表盘功能。
设备进入AI表盘界面,发送RCSP命令告诉App端在使用AI表盘功能。
设备端开始录音时,发送RCSP命令告诉App端开始录音。然后就开始传输录音数据。
设备端停止录音,发送RCSP命令告诉App端停止录音。
App收到开始录音后,开始把接受到的实时录音数据进行Opus转码成PCM数据,转码PCM结果发送给科大讯飞服务器。App收到停止录音后,发送录音结束命令给科大讯飞服务器。科大讯飞先返回语音识别结果,再返回语音识别结果。
App同步语音识别结果给设备,设备显示语音识别结果。用户确认生成AI表盘
App调用文生图接口生成图片,根据屏幕尺寸裁剪生成缩略图发送给设备。用户确认安装表盘
App根据图片生成自定义表盘,给设备安装
16.2.1. 时序图
16.2.2. 科大讯飞配置
如不使用科大讯飞的SDK,改用其他平台的AISDK。可跳过这一步。**
公版发出去的HealthAide项目,编译后是无法正常使用AI表盘功能。需要先前往科大讯飞注册开通【星火认知大模型-图片生成】、【语音识别】、【语音合成】功能。
在 IflytekChatWrapper.class IflytekIatWrapper.class IflytekTextToImageWrapper.class 对应位置配置【APPID】【APISecret】【APIKey】。
//IflytekChatWrapper.class
public IflytekChatWrapper(Context context) {
......
if (!TextUtils.isEmpty(BuildConfig.IFLYTEK_APP_ID)) {//TODO 需要注释掉这一行
//TODO 请先在科大讯飞平台申请,请填写正确appId,appKey,apiSecret。否则会闪退
final AiHelper.Params.Builder params = AiHelper.Params.builder()
.appId("ffffffff"/**APPID**/)
.apiKey("fffffffffffffffffffffffffffffff"/**APIKey**/)
.apiSecret("ffffffffffffffffffffffffffffffff"/**APISecret**/)
.workDir(rootFile.getPath());
......
}
}
//IflytekIatWrapper.class
public IflytekIatWrapper(Context context) {
//开log
Setting.setShowLog(true);
//初始化即创建语音配置对象
if (!TextUtils.isEmpty(BuildConfig.IFLYTEK_APP_ID)) {//TODO 需要注释掉这一行
//TODO 请先在科大讯飞平台申请,请填写正确appId。否则会闪退
SpeechUtility.createUtility(context, SpeechConstant.APPID + "=" + "ffffffff"/**APPID**/);
}
//初始化识别无UI识别对象
mSpeechRecognizer = SpeechRecognizer.createRecognizer(context, mIatInitListener);
}
//IflytekTextToImageWrapper.class
public void startChat(String usrInputText, TextToImageCallback callback) throws Exception {
String appid = "ffffffff";/**APPID**/
String apiSecret = "fffffffffffffffffffffffffffffff";/**APIKey**/
String apiKey = "ffffffffffffffffffffffffffffffff";/**APISecret**/
......
}
16.2.3. 使用示例
/**
* @ClassName: AIDialDemo
* @Description: AI表盘功能示例
* @Author: ZhangHuanMing
* @CreateDate: 2023/12/28 11:39
*/
public class AIDialDemo {
private AIManager mAIManager;
/**
* 初始化AIManager
*/
@Test
public void init(Context context){
//Step1. 初始化
AIManager.init(context, WatchManager.getInstance());
mAIManager = AIManager.getInstance();
}
/**
* 设置AI表盘风格
*/
@Test
public void setStyle(String style){
mAIManager.getAIDial().setCurrentAIDialStyle(style);
}
}
16.2.4. 接入其他AI平台
请参考 IflytekAIDialHandler.class 、 IflytekAIIatHandler.class 调用 BaseAIDialHandler、 BaseAIIatHandler 的方法
//BaseAIIatHandler.class
//基础语音识别处理
public abstract class BaseAIIatHandler extends BaseAIHandler {
/**
* 需要实现
*/
//设备断开
abstract void onDeviceDisconnect();
// 开始录音
abstract void onRecordStart();
// 收到录音数据(已解码成PCM格式)
abstract void onRecordData(byte[] recordData);
// 录音结束
abstract void onRecordStop();
// 录音取消
abstract void onRecordCancel();
/**
* 需要调用
*/
//语音识别异常标志位
void setRecognizerFail(boolean recognizerFail);
//网络异常标志位
void setNetworkWrong(boolean networkWrong);
//识别结果
void onRecognizerResult(String iatString);
//识别失败
void onRecognizerFail();
}
//BaseAIDialHandler.class
//AI表盘处理流程
public abstract class BaseAIDialHandler extends BaseAIChatHandler {
/**
* 开始对话(文生图),需要实现
*/
abstract void onStartAIChat(String userText);
/**
* 处理AI图片(文生图),需要调用
* @param srcImagePath 本地图片路径
*/
protected void handleAIChatImage(String srcImagePath);
}
16.2.5. 是否支持AI表盘
如何判断设备是否支持AI表盘功能
WatchConfigure configure mWatchManager.getWatchConfigure(device);
boolean isSupportAIDial = configure == null || configure.getFunctionOption() != null && configure.getFunctionOption().isSupportAIDial();;
16.2.6. 本地测试AI表盘
在测试过程中为避免浪费服务器的文生图资源,AI表盘有本地测试功能。在发布正式版时,请关闭。
在打开App时,将assert/aidial 的资源拷贝至/Android/data/com.jieli.healthaide/files/aidial。(从1到10轮询选择一张图片进行AI表盘生成)
关闭本地测试功能:
//HealthConstant.class
public class HealthConstant {
.....
//测试AI表盘功能
public final static boolean TEST_AI_DIAL_FUNCTION = false;
.....
}
16.2.7. AI表盘缩略图
目前AI表盘的缩略图文件大小默认为240*240,设备端可在进入AI表盘界面时推送缩略图大小。如需修改默认缩略图大小,请修改 AIDialWrapper.java 的thumbHeight和thumbWidth属性。
//AIDialWrapper.class
private final OnWatchCallback mWatchCallback = new OnWatchCallback() {
@Override
public void onRcspCommand(BluetoothDevice device, CommandBase command) {
super.onRcspCommand(device, command);
if (command.getId() == Command.CMD_AI_OPERATE) {
AIOperateCmd aiOperateCmd = (AIOperateCmd) command;
AIOperateParam param = aiOperateCmd.getParam();
if (param.getOp() == AttrAndFunCode.AI_OP_AI_DIAL) {
switch (param.getFlag()) {
case AttrAndFunCode.AI_DIAL_OP_UI://设备通知AppAI表盘界面变化
Integer state = param.getAiDialFunUIState();
Integer scaleZoomHeight = param.getScaleZoomHeight();
Integer scaleZoomWidth = param.getScaleZoomWidth();
if (state != null) {
onDevNotifyAIDialUIChange(state);
}
if (scaleZoomHeight != null) {
thumbHeight = scaleZoomHeight;
} else {
thumbHeight = 240;
}
if (scaleZoomWidth != null) {
thumbWidth = scaleZoomWidth;
} else {
thumbWidth = 240;
}
break;
}
aiOperateCmd.setParam(new AIOperateParam.AIOperateResultParam(0));
aiOperateCmd.setStatus(StateCode.STATUS_SUCCESS);
mWatchManager.sendCommandResponse(mWatchManager.getConnectedDevice(), aiOperateCmd, null);
}
}
}
};
16.3. 代码架构