1.1. Local Sdk Tool 文档
1.1.1. 目录
1.1.2. 一、概述
Rokid 语音SDK 本地技能快速开发工具,方便开发配合Rokid语音SDK一起使用的本地技能。
主要功能:
提供将nlp、action解析成通用实体类的工具;
设置当前技能到技能栈栈顶、清空技能栈;
设置或取消“关键词”二次确认(confim)功能;
提供公共TTS功能,可以把“文字“转换成tts语音播放出来;
方便语音本地技能开发,保证基础功能体验统一。
主要开发步骤:
1、 在Rokid开发者网站注册相应的本地技能;
2、补全语音交互中的意图和词表配置,并编译通过;
3、将技能ID配置到AndroidManifest.xml的Activity或Service中;
4、直接使用LocalSdkManager开发复杂本地语音技能,或者使用handy工具开发简易本地语音技能;
5、完善每个意图所对应的实际功能。
1.1.3. 二、各步骤详细说明
本地技能注册
在 https://developer.rokid.com/ 注册开发者帐号;
登录后,选择“控制台”,点击技能开发,按照技能开发步骤,进行填写;
详细技能开发文档:https://rokid.github.io/docs/2-RokidDocument/1-SkillsKit/getting-started/creat-and-publish.html
意图或词表补全
意图、词表填写测试步骤请参考详细技能开发文档 https://rokid.github.io/docs/2-RokidDocument/1-SkillsKit/getting-started/creat-and-publish.html ;
意图介绍:
- 技能进入:"ROKID.INTENT.WELCOME"
- 技能初次Confirm失败后再次确认:"ROKID.INTENT.CONFIRM_RETRY"
- 其他:https://developer.rokid.com/docs/2-RokidDocument/1-SkillsKit/important-concept/intend.html
词表介绍:
本地技能App配置
主要概念:
"com.rokid.ai.skill.local.ID"
:SKILL_ID,Manifest文件中技能ID meta-data 描述。"com.rokid.ai.skill.local.FORM"
:SKILL_FORM, Manifest文件中技能FORM 信息 meta-data 描述, cut、scene、service。"com.rokid.ai.skill.local.TYPE"
:SKILL_TYPE, Manifest文件中技能TYPE 信息 meta-data 描述, activity、service。"com.rokid.ai.skill.local.COMPONENT"
:SKILL_COMPONENT,Manifest文件中技能COMPONENT 信息 meta-data 描述,可以取技能承接的Activity或Service的全名,如 "com.rokid.localskills.TestHandyActivity"。"com.rokid.ai.skill.local.EXTRA"
:SKILL_EXTRA,Manifest文件中技能EXTRA 信息 meta-data 描述, 意图命中后会回传给相应的Activity或Service。"cmd"
:SEND_PARAM_CMD,技能启动参数:cmd,值为”send_nlp“代表本地技能nlp命中。"send_nlp"
:SEND_CMD_VALUE,技能启动参数cmd的值:"send_nlp"。"id"
:SEND_PARAM_ID,技能id,在bundle中传递。"type"
:SEND_PARAM_TYPE,技能type,在bundle中传递,可以为"activity"、"service""form"
:SEND_PARAM_FORM,技能form,在bundle中传递,可以为"cut"、"scene"、"service""extra"
:SEND_PARAM_EXTRA,技能extra,在bundle中传递,一般用来传递一些附加信息"nlp"
:SEND_PARAM_NLP,技能nlp,在bundle中传递"action"
:SEND_PARAM_ACTION,技能action,在bundle中传递"asr"
:SEND_PARAM_ASR,技能asr,在bundle中传递
技能承接配置: 本地技能能够被Rokid语音SDK识别并发现,需要在app的AndroidManifest.xml中做技能信息的相关配置。
* Android中,只有Activity和Service能够用来承接一个本地技能,当做技能承接者。 * 一个技能承接者只能承接一个本地技能,不支持承接多个。 * 一个App可以有多个本地技能承接者,但推荐一个app只用来整体承接一个本地技能。
Application 方式:
<application ... > <meta-data android:name="com.rokid.ai.skill.local.ID" android:value="R92F3639E0DA4E9E983BE1B09D2F6893"></meta-data> <meta-data android:name="com.rokid.ai.skill.local.FORM" android:value="scene"></meta-data> <meta-data android:name="com.rokid.ai.skill.local.TYPE" android:value="activity"></meta-data> <meta-data android:name="com.rokid.ai.skill.local.COMPONENT" android:value="com.rokid.localskills.TestHandyActivity"></meta-data> <meta-data android:name="com.rokid.ai.skill.local.EXTRA" android:value="hello, hello, hello"></meta-data> </application>
- Activity 方式:
<activity android:name="com.rokid.localskills.TestHandyActivity" android:launchMode="singleTask" android:enabled="true" android:exported="true"> <meta-data android:name="com.rokid.ai.skill.local.ID" android:value="REF7DAAECE0946918BD3F2683FCCFEE7"></meta-data> <meta-data android:name="com.rokid.ai.skill.local.FORM" android:value="scene"></meta-data> <meta-data android:name="com.rokid.ai.skill.local.EXTRA" android:value="handy, handy, handy"></meta-data> </activity>
- Service 方式:
<service android:name="com.rokid.localskills.TestHandyService" android:enabled="true" android:exported="true"> <meta-data android:name="com.rokid.ai.skill.local.ID" android:value="R92F3639E0DA4E9E983BE1B09D2F6893"></meta-data> <meta-data android:name="com.rokid.ai.skill.local.FORM" android:value="scene"></meta-data> <meta-data android:name="com.rokid.ai.skill.local.EXTRA" android:value="hello, hello, hello"></meta-data> </service>
- 注意:
- 必须让 android:enabled="true",android:exported="true"
- 需要本地技能承接者能够让语音SDK所在的app,通过Android启动机制访问到。
本地技能SDK调用
SDk aar 引入;
- 引入localsdk aar
引入 gson (localsdk中部分功能依赖gson)
// 外部用户:先将 localsdk-1.0.3.aar 放入libs目录中 android { ... repositories{ flatDir{ dirs 'libs' } } ... } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation (name:'localsdk-1.0.3', ext:'aar') implementation 'com.google.code.gson:gson:2.8.5' ... } // 内部用户 dependencies { ... implementation 'com.rokid.ai.skill:localsdk:1.0.3' ... }
LocalSdkManager使用实例;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // ... 初始需要处理权限 // 初始化 LocalSdkManager.newInstance(MainActivity.this.getApplicationContext()); dispatchIntent(getIntent()); } /** * 处理Intent * @param intent */ @Override protected void onNewIntent(Intent intent) { dispatchIntent(intent); super.onNewIntent(intent); } /** * 解析nlp,并且处理intent * @param intent */ public void dispatchIntent(Intent intent) { if (intent == null) { Logger.d(TAG, "the intent is null"); return; } if (LocalSdkConfig.SEND_CMD_VALUE.equals(intent.getStringExtra(LocalSdkConfig.SEND_PARAM_CMD))) { String id = intent.getStringExtra(LocalSdkConfig.SEND_PARAM_ID); String action = intent.getStringExtra(LocalSdkConfig.SEND_PARAM_ACTION); String type = intent.getStringExtra(LocalSdkConfig.SEND_PARAM_TYPE); String extra = intent.getStringExtra(LocalSdkConfig.SEND_PARAM_EXTRA); Logger.d(TAG, "dispatchIntent id = " + id); Logger.d(TAG, "dispatchIntent action = " + action); Logger.d(TAG, "dispatchIntent type = " + type); Logger.d(TAG, "dispatchIntent extra = " + extra); } String nlp = intent.getStringExtra(LocalSdkConfig.SEND_PARAM_NLP); Logger.d(TAG, "dispatchIntent nlp = " + nlp); if (TextUtils.isEmpty(nlp)) { Logger.d(TAG, "the nlp is null"); return; } final NlpAsrBean mNlpAsrBean = LocalSdkManager.analysisNlp(nlp); Logger.d(TAG, "the NlpAsrBean is" + mNlpAsrBean.toString()); String intentEvent = mNlpAsrBean.getIntent(); LocalSdkManager.reportSkillStack(mNlpAsrBean.getAppId(), SKILL_TYPE_SCENE); switch (intentEvent) { case "ROKID.INTENT.WELCOME": // 技能入口,这个意图为用户直接说技能入口词进入技能时返回 break; case "意图...": // 用户在注册技能时自定义的意图,由相应的意图词触发 break; case "触发confirm意图": // 用户自己自定义的触发confirm请求的意图,这里用来展示LocalSdkManager的tts功能、confirm功能 try { LocalSdkManager.speakTTS("你喜欢喝什么", new ITtsCallback.Stub() { @Override public void onStart(int id) throws RemoteException { } @Override public void onComplete(int id) throws RemoteException { Logger.d(TAG, "the onComplete callback"); LocalSdkManager.requestConfirm(EAT_INTENT,"food", mNlpAsrBean.getAppId(), "1"); } @Override public void onCancel(int id) throws RemoteException { } @Override public void onError(int id, int err) throws RemoteException { } @Override public void onFilterOut(String content, String key, int existId) throws RemoteException { } }); } catch (Exception e) { e.printStackTrace(); } break; case "food": case "ROKID.INTENT.CONFIRM_RETRY": // food 为用户定义的confirm 技能意图,"ROKID.INTENT.CONFIRM_RETRY"为第一次用户没有说对,自动再次确认的意图 LocalSdkManager.speakTTS("我知道了你喜欢喝" + mNlpAsrBean.getAsr() + "了"); break; default: break; } }
简易意图及confirm形式配置;
{ "intents": [ { "intent": "up_press", "slots": [], "user_says": [ "上一首" ] }, { "intent": "confirmeat", "slots": [], "user_says": [ "我饿了" ] }, { "intent": "next_press", "slots": [], "user_says": [ "下一首" ] }, { "intent": "eat", "slots": [ { "name": "food", "type": "list" } ], "user_says": [ "!$food" ] } ] }
详细参见 意图或词表补全
简易confirm词表配置:
name: food type: list 1. 西瓜 2. 可乐 3. 饺子
详细参见 意图或词表补全
简易意图HandyManager使用:
public class GlassHandyActivity extends Activity { private static final String TAG = GlassHandyActivity.class.getSimpleName(); private TextView mTextView; private HandyManager mHandyManager; /** * 技能ID, 开发者网站创建技能时会自动生成 */ private static final String SKILL_ID = ""; /** * 技能类型,scene为其中一种,还可以是cut、service */ private static final String SKILL_TYPE_SCENE = "scene"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_glass_handy); mTextView = findViewById(R.id.handy_text); mHandyManager = new HandyManager(getApplicationContext(), SKILL_ID, SKILL_TYPE_SCENE); mHandyManager.setHandyListener(mHandyListener); dispatchIntent(getIntent()); } @Override protected void onStart() { super.onStart(); if (mHandyManager != null) { // 当前技能已经运行,需要更新技能栈,将当前技能提升到技能栈顶 mHandyManager.updateStack(); } } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); dispatchIntent(intent); } /** * 解析nlp,并且处理intent * @param intent */ public void dispatchIntent(Intent intent) { if (mHandyManager != null) { mHandyManager.handyIntent(intent); } } private HandyManager.IHandyListener mHandyListener = new HandyManager.IHandyListener() { @Override public boolean dispatchLocal(LocalSdkConfig.LocalBean localBean) { // 如果想要拦截localBean处理,此处返回true,否则返回false,dispatchNlp() return false; } @Override public boolean dispatchNlp(String nlp, LocalSdkConfig.LocalBean localBean) { // 如果想要拦截nlp处理,此处返回true,否则返回false,进入dispatchIntent() return false; } @Override public boolean dispatchIntent(String intent, LocalSdkConfig.LocalBean localBean) { Logger.d(TAG, "dispatchIntent " + intent + ", asr = " + localBean.asr); setText(localBean.asr + "\n" + intent); switch (intent) { case LocalSdkConfig.INTENT_WELCOME: return true; case "自定义意图...": return true; // ... // 如果是主动结束应用程序的意图:如关闭**技能,推荐做一下清空技能栈的操作 // if (mHandyManager != null) { // mHandyManager.clearAllStack(); // } default: break; } return false; } }; private void setText(final String content) { runOnUiThread(new Runnable() { @Override public void run() { if (mTextView != null) { mTextView.setText(content); } } }); } @Override protected void onDestroy() { if (mHandyManager != null) { mHandyManager.onDestroy(); mHandyManager = null; } super.onDestroy(); } }
1.1.4. 三、API参考
LocalSdkManager功能说明
获得LocalSdkManager单例。
public static LocalSdkManager newInstance(Context applicationContext)
解析nlp中的String字符串,获得其中的解析类
public static NlpAsrBean analysisNlp(String nlp)
confirm接口,打开拾音,然后拿到填补技能槽
public void requestConfirm(String confirmIntent, String slot, String appid, String type)
| 参数 | 含义 | |------| ----- | |confirmIntent| 需要填补地技能槽意图| |slot| 填补地技能槽| |appid| 技能appid| |type| 技能类型|
取消confirm
public void cancelConfirm(String appid)
设置云端堆栈队列
public void reportSkillStack(String appId, String type)
|参数|含义| |----|----| |appid| 技能ID| |type| 技能类型|
清空技能堆栈
public static void clearAllSkillStack()
暂停tts的播放
public static void pauseTTS()
停止tts的播放
public static void stopTTS(boolean isNeedCheckRunningStats)
获得action的对应字符串,并且解析
public NLPControlMsgBean analysisAction(String action)
播放文字,文字转换为语音
public static void speakTTS(final String ttsContent, final ITtsCallback callback)
参数 | 含义 |
---|---|
ttsContent | 需要播放地音频文字 |
ITtsCallback | 播放状态的回调接口 |
- ITtsCallback 接口 | 参数 |含义| |----|---| | onStart| 开始播放音频 | | onComplete| 完成音频播放 | | onCancel | 取消播放 | | onError | 播放错误 | | onFilterOut | 过滤掉相同key值的tts |
样例及说明
- SDK 版本:1.0.3
- SDK 地址:https://github.com/Rokid/RokidAiLocalSkillDemo/tree/master/aar
- 使用接口方法可参考sample demo
- 地址: https://github.com/Rokid/RokidAiLocalSkillDemo