前言
因爲項目中用到了語音識別的技術,但是項目源碼我不能公開,所以,重新寫一個簡單的集成教程,不喜可不看,不做鍵盤俠,文明你我他。
效果圖
識別結果
最終效果
正文
下面是詳細步驟,不漏過任何一個細節,力求讓你一步到位
① 創建平臺應用
既然使用了百度語音,自然免不了要註冊該平臺的賬號,否則憑什麼讓你使用,點擊百度智能雲進入,沒有賬號的可以先註冊賬號,註冊應該就不用我講解了吧?這裏默認都有賬號了,然後登錄
然後左側導航欄點擊找到語音技術
然後會進入一個應用總覽頁面,
然後點擊創建應用
立即創建
點擊查看應用詳情
這幾個值都是等下項目中要用的,請注意,最好是複製粘貼,不要手打,上圖中有一個下載SDK,點擊進入下載頁面,第一個就是
點擊下載到本地,下載之後是一個壓縮文件,解壓之後先不用管它,然後在Android Studio裏面創建一個項目
② 創建Android項目並配置
這時候你運行到自己的手機上,如果出現Hello World!,就說明你這個項目沒有問題。哎呀~不得了啊!你真是一個百年不遇的代碼奇才! 繼續啊!
File → New → Import Module…
通過上面的步驟,插入一個模塊進來
點擊OK
很明顯,我找到了,你呢?找到了就找到了,說個🔨啊,人格分裂 繼續啊,點擊Finish 就會在你當前的項目中加入這個模塊,與app是平級的。
這裏就是在加載模塊中的文件了,加載完畢之後,你可以打開settings.gradle,會發現多了一個 ‘:core’,當然這是在工程中加入了這個模塊。
還要在你的app裏面加入這個才能使用,
加入的方法有兩個,
1. 手動選擇
點擊OK,然後再點擊一次OK
模塊已經添加進來了,當然這樣比較繁瑣,還有更簡單的辦法下面可以自動添加依賴。
2. 自動添加依賴
找到app下面的build.gradle配置文件,在dependencies閉包下,加入
implementation project(path: ':core')
然後右上角點擊 Sync 同步到項目中
下面修改core的AndroidManifest.xml文件中的APP_ID、API_KEY、SECRET_KEY,裏面的值修改爲之前在平臺註冊應用生成的值。
改好之後,請注意,每個人都是不一樣,你如果發現你創建的應用的配置的值和我創建的是一模一樣的,你馬上去百度提BUG,他們的程序員要就要下崗了~
OK,現在配置也完成了,接下來就是使用了。
③ 使用
首先是修改
佈局修改的代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:gravity="center"
android:id="@+id/tv_txt"
android:padding="20dp"
android:textColor="#000"
android:text="識別到的內容"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/btn_stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="停止" />
<Button
android:id="@+id/btn_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="開始" />
</LinearLayout>
說道語音識別自然要用到這個麥克風,這個權限是需要動態申請的。
/**
* android 6.0 以上需要動態申請權限
*/
private void initPermission() {
String permissions[] = {Manifest.permission.RECORD_AUDIO,
Manifest.permission.ACCESS_NETWORK_STATE,
Manifest.permission.INTERNET,
Manifest.permission.WRITE_EXTERNAL_STORAGE
};
ArrayList<String> toApplyList = new ArrayList<String>();
for (String perm : permissions) {
if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, perm)) {
toApplyList.add(perm);
}
}
String tmpList[] = new String[toApplyList.size()];
if (!toApplyList.isEmpty()) {
ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
}
}
/**
* 權限申請回調,可以作進一步處理
* @param requestCode
* @param permissions
* @param grantResults
*/
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// 此處爲android 6.0以上動態授權的回調,用戶自行實現。
}
得到權限之後就可以進行下一步了,首先是初始化控件以及語音是被的核心SDK
protected TextView txtResult;//識別結果
protected Button startBtn;//開始識別 一直不說話會自動停止,需要再次打開
protected Button stopBtn;//停止識別
private EventManager asr;//語音識別核心庫
/**
* 初始化控件
*/
private void initView() {
txtResult = (TextView) findViewById(R.id.tv_txt);
startBtn = (Button) findViewById(R.id.btn_start);
stopBtn = (Button) findViewById(R.id.btn_stop);
startBtn.setOnClickListener(new View.OnClickListener() {//開始
@Override
public void onClick(View v) {
asr.send(SpeechConstant.ASR_START, null, null, 0, 0);
}
});
stopBtn.setOnClickListener(new View.OnClickListener() {//停止
@Override
public void onClick(View v) {
asr.send(SpeechConstant.ASR_STOP, null, null, 0, 0);
}
});
}
在onCreate方法中調用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initPermission();
//初始化EventManager對象
asr = EventManagerFactory.create(this, "asr");
//註冊自己的輸出事件類
asr.registerListener(this); // EventListener 中 onEvent方法
}
同時還需要實現EventListener,注意到這個實現的是百度的,不是自帶的。
實現之後還需要一個回調方法,如下:
/**
* 自定義輸出事件類 EventListener 回調方法
*/
@Override
public void onEvent(String name, String params, byte[] data, int offset, int length) {
if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {
// 識別相關的結果都在這裏
if (params == null || params.isEmpty()) {
return;
}
if (params.contains("\"final_result\"")) {
// 一句話的最終識別結果
txtResult.setText(params);
}
}
}
最後就是在onDestroy裏面關閉和處理
@Override
protected void onDestroy() {
super.onDestroy();
//發送取消事件
asr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
//退出事件管理器
// 必須與registerListener成對出現,否則可能造成內存泄露
asr.unregisterListener(this);
}
可以運行了
點擊開始,然後說 “你好”,識別出結果
可以看到,識別的結果還是蠻精準的,但是我們要的數據就只有那兩個字而已,所以要進行數據的解析了
④ JSON數據解析
通過剛纔代碼的中大日誌打印拿到JSON字符串,將這個字符串轉成實體bean.
轉出來的實體bean, 命名爲ASRresponse,代碼如下:
package com.llw.asrdemo;
import java.util.List;
public class ASRresponse {
/**
* results_recognition : ["你好,"]
* result_type : final_result
* best_result : 你好,
* origin_result : {"asr_align_begin":80,"asr_align_end":130,"corpus_no":6835867007181645805,"err_no":0,"raf":133,"result":{"word":["你好,"]},"sn":"82d975e0-6eb4-43ac-a0e7-850bb149f28e"}
* error : 0
*/
private String result_type;
private String best_result;
private OriginResultBean origin_result;
private int error;
private List<String> results_recognition;
public String getResult_type() {
return result_type;
}
public void setResult_type(String result_type) {
this.result_type = result_type;
}
public String getBest_result() {
return best_result;
}
public void setBest_result(String best_result) {
this.best_result = best_result;
}
public OriginResultBean getOrigin_result() {
return origin_result;
}
public void setOrigin_result(OriginResultBean origin_result) {
this.origin_result = origin_result;
}
public int getError() {
return error;
}
public void setError(int error) {
this.error = error;
}
public List<String> getResults_recognition() {
return results_recognition;
}
public void setResults_recognition(List<String> results_recognition) {
this.results_recognition = results_recognition;
}
public static class OriginResultBean {
/**
* asr_align_begin : 80
* asr_align_end : 130
* corpus_no : 6835867007181645805
* err_no : 0
* raf : 133
* result : {"word":["你好,"]}
* sn : 82d975e0-6eb4-43ac-a0e7-850bb149f28e
*/
private int asr_align_begin;
private int asr_align_end;
private long corpus_no;
private int err_no;
private int raf;
private ResultBean result;
private String sn;
public int getAsr_align_begin() {
return asr_align_begin;
}
public void setAsr_align_begin(int asr_align_begin) {
this.asr_align_begin = asr_align_begin;
}
public int getAsr_align_end() {
return asr_align_end;
}
public void setAsr_align_end(int asr_align_end) {
this.asr_align_end = asr_align_end;
}
public long getCorpus_no() {
return corpus_no;
}
public void setCorpus_no(long corpus_no) {
this.corpus_no = corpus_no;
}
public int getErr_no() {
return err_no;
}
public void setErr_no(int err_no) {
this.err_no = err_no;
}
public int getRaf() {
return raf;
}
public void setRaf(int raf) {
this.raf = raf;
}
public ResultBean getResult() {
return result;
}
public void setResult(ResultBean result) {
this.result = result;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public static class ResultBean {
private List<String> word;
public List<String> getWord() {
return word;
}
public void setWord(List<String> word) {
this.word = word;
}
}
}
}
這裏我用GSON來解析JSON數據。
//GSON
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
記得Sync一下
然後回到MainActivity
修改的代碼如下:
Gson gson = new Gson();
ASRresponse asRresponse = gson.fromJson(params, ASRresponse.class);//數據解析轉實體bean
if(asRresponse == null) return;
//從日誌中,得出Best_result的值纔是需要的,但是後面跟了一箇中文輸入法下的逗號,
if(asRresponse.getBest_result().contains(",")){//包含逗號 則將逗號替換爲空格,這個地方還會問題,還可以進一步做出來,你知道嗎?
txtResult.setText(asRresponse.getBest_result().replace(',',' ').trim());//替換爲空格之後,通過trim去掉字符串的首尾空格
}else {//不包含
txtResult.setText(asRresponse.getBest_result().trim());
}
然後再運行一下
OK,搞定了。