前言:用过苹果和三星的小伙伴们,肯定对其中的语音助手 Siri 和 Bixby一定不陌生,今天我们基于百度AI技术,一起来实现这个功能。
效果图:
百度AI文档说明连接:http://ai.baidu.com/docs#/UNIT-v2-service-API/top
第一步:获取Access_token:
public class AuthService {
/**
* 获取权限token
*/
public static String getAuth() {
// 官网获取的 API Key 更新为你注册的
String clientId = "百度ai申请的API Key";
// 官网获取的 Secret Key 更新为你注册的
String clientSecret = "百度ai申请的Secret Key";
return getAuth(clientId, clientSecret);
}
/**
* 获取API访问token
* 该token有一定的有效期,需要自行管理,当失效时需重新获取.
*
* @param ak - 百度云官网获取的 API Key
* @param sk - 百度云官网获取的 Securet Key
* @return assess_token 示例:
* "24.460da4889caad24cccdb1fea17221975.2592000.1491995545.282335-1234567"
*/
public static String getAuth(String ak, String sk) {
// 获取token地址
String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
String getAccessTokenUrl = authHost
// 1. grant_type为固定参数
+ "grant_type=client_credentials"
// 2. 官网获取的 API Key
+ "&client_id=" + ak
// 3. 官网获取的 Secret Key
+ "&client_secret=" + sk;
try {
URL realUrl = new URL(getAccessTokenUrl);
// 打开和URL之间的连接
HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
connection.setRequestMethod("GET");
connection.connect();
// 获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.err.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String result = "";
String line;
while ((line = in.readLine()) != null) {
result += line;
}
/**
* 返回结果示例
*/
System.err.println("result:" + result);
JSONObject jsonObject = new JSONObject(result);
String access_token = jsonObject.getString("access_token");
return access_token;
} catch (Exception e) {
System.err.printf("获取token失败!");
e.printStackTrace(System.err);
}
return null;
}
}
第二步:调用请求接口,获取反馈结果:
public class UnitService {
/**
* 重要提示代码中所需工具类
* FileUtil,Base64Util,HttpUtil,GsonUtils请从
* https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
* https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
* https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
* https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
* 下载
*/
/**
*
* @参数一 具体可以参考百度官方说明
* @参数二 你提出的问题 (不能为空)
*/
public static String utterance(String session_id, String query) {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("log_id", "UNITTEST_10000"); //参数说明,具体可以参考百度官方说明
jsonObject.put("version", "2.0");
jsonObject.put("service_id", "S15007");
jsonObject.put("session_id", session_id);
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("query", query);
jsonObject1.put("user_id", "88888");
jsonObject.put("request", jsonObject1);
} catch (JSONException e) {
e.printStackTrace();
}
String string = jsonObject.toString();
System.out.println("获取到的json: " + string);
// 请求URL
String talkUrl = "https://aip.baidubce.com/rpc/2.0/unit/service/chat";
try {
// 请求参数
String accessToken = AuthService.getAuth();
String result = HttpUtil.post(talkUrl, accessToken, "application/json", string);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String getIMEI(Context context) {
TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(context.TELEPHONY_SERVICE);
String imei = telephonyManager.getDeviceId();
return imei;
}
}
通过以上两步,基本实现了功能,下面我们来实现对话聊天框的实现:
原理分析:基于RecycleView 来实现这个功能, 对于提问方和回答方给出两个不同的type来判断
具体实现代码如下:
页面布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/rl_title"
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@color/btn_background">
<TextView
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:text="小沐"
android:textColor="@color/white"
android:textSize="18dp"/>
</RelativeLayout>
<Button
android:id="@+id/btn_speech"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_margin="5dp"
android:text="按住说话"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/btn_speech"
android:layout_below="@id/rl_title"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv_show"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<RelativeLayout
android:id="@+id/rl_show"
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_centerInParent="true"
android:background="@color/gray2"
android:visibility="gone">
<ImageButton
android:id="@+id/iv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@mipmap/ease_record_animate_01"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/iv_show"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:text="手指松开,录音结束"
android:textColor="@color/black"
android:textSize="16sp"/>
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
主要业务代码:
private void initView() {
mRl_show = (RelativeLayout) findViewById(R.id.rl_show);
mIv_show = (ImageButton) findViewById(R.id.iv_show);
mRv_show = (RecyclerView) findViewById(R.id.rv_show);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
mRv_show.setLayoutManager(layoutManager);
adapter = new MsgAdapter(msgList); //创建MsgAdapter的实例并将数据传入到MsgAdapter的构造函数中
mRv_show.setAdapter(adapter);
Button btn_speech = (Button) findViewById(R.id.btn_speech);
btn_speech.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN://按下
mIv_show.setBackgroundResource(R.drawable.voice_audio);
mBackground = (AnimationDrawable) mIv_show.getBackground();
mBackground.start();
mRl_show.setVisibility(View.VISIBLE);
mSpeechRecognizerTool.startASR(MainActivity.this);
break;
case MotionEvent.ACTION_UP://抬起
mBackground.stop();
mRl_show.setVisibility(View.GONE);
mSpeechRecognizerTool.stopASR();
break;
default:
return false;
}
return true;
}
});
}
语音识别后的处理:
@Override
public void onResults(final String result) {
if (result.isEmpty()) {
return;
}
msgList.add(new MsgBean(result, MsgBean.TYPE_SENT));
adapter.notifyItemInserted(msgList.size() - 1);
mRv_show.scrollToPosition(msgList.size() - 1);
new Thread(new Runnable() {
@Override
public void run() {
String utterance = UnitService.utterance(session_id, result);
RobotBean robotBean = GsonUtils.fromJson(utterance, RobotBean.class);
final String say = robotBean.getResult().getResponse_list().get(0).getAction_list().get(0).getSay();
session_id = robotBean.getResult().getSession_id();
runOnUiThread(new Runnable() {
@Override
public void run() {
msgList.add(new MsgBean(say, MsgBean.TYPE_RECEIVED));
adapter.notifyItemInserted(msgList.size() - 1);
mRv_show.scrollToPosition(msgList.size() - 1);
}
});
speek(say);
}
}).start();
}
项目中用到的语音识别和语音合成的实现这里就不贴出来了,具体如何实现可以参考百度AI里面的接口文档说明
资源下载地址:https://download.csdn.net/download/abner_crazy/11019672