如何製作Android語音機器人
- 首先在製作android語音機器人之前,我們要認識一家公司–科大訊飛,科大訊飛從事語音開發有些年頭,也做得相當不錯。本項目就用到這家公司裏面的一個語音開放平臺!還有就是項目的功能:我們這個項目是自己語言說話,然後我們的話能以文字的形式顯示到對話框中,接着我們的Android機器人會對我們的話進行解析,語音回答並且也會以文字的形式顯示到對話框中同時還會攜帶一些圖片。
- 現在讓我們一起開發這款有趣的軟件吧~
- 首先找到科大訊飛中的開放平臺之後登陸找到資料庫中的Android開發文檔開發文檔中可以很明確的教你使用一個語音SDK,並且非常詳細的教你在android項目當中的assets,libs,和清單文件中加一些固定的內容以及文件資源。
- Android項目代碼中的程序入口先要加一段代碼
- SpeechUtility.createUtility(this, SpeechConstant.APPID + "=55cfe490");
進行初始化其中APPID要與你在科技訊飛平臺創建應用產生的APPID碼一致。接下來我們就要開始自己做一個語音聊天機器人的佈局。
- 一開始肯定是寫整體佈局
activity_main代碼如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ListView
android:id="@+id/iv_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:divider="@null"
>
</ListView>
<LinearLayout
android:id="@+id/ll_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bottom_bar"
android:gravity="center"
>
<Button
android:id="@+id/btn_siri"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="點擊進行聊天"
android:onClick="startListenUI"
android:background="@drawable/tbn_selector"
/>
</LinearLayout>
</LinearLayout>
接下來該是Activity中對佈局控件的綁定然後對ListView設置Adapter
代碼如下:
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return mListBean.size();
}
@Override
public TextBean getItem(int position) {
return mListBean.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
viewHodler mHolder = null;
if(convertView == null){
convertView = View.inflate(getApplicationContext(), R.layout.item_pager, null);
mHolder = new viewHodler();
mHolder.tvAsk = (TextView) convertView.findViewById(R.id.tv_ask);
mHolder.tvAnswer = (TextView) convertView.findViewById(R.id.tv_answer);
mHolder.llAnswer = (LinearLayout) convertView.findViewById(R.id.ll_answer);
mHolder.ivAnswer = (ImageView) convertView.findViewById(R.id.iv_answer);
convertView.setTag(mHolder);
}else{
mHolder = (viewHodler) convertView.getTag();
}
TextBean item = getItem(position);
if(item.isAsk){
mHolder.tvAsk.setVisibility(View.VISIBLE);
mHolder.llAnswer.setVisibility(View.GONE);
mHolder.tvAsk.setText(item.text);
}else{
mHolder.tvAsk.setVisibility(View.GONE);
mHolder.llAnswer.setVisibility(View.VISIBLE);
mHolder.tvAnswer.setText(item.text);
if(item.image>0){//回答內容有圖片
mHolder.ivAnswer.setVisibility(View.VISIBLE);
mHolder.ivAnswer.setImageResource(item.image);
}else{
mHolder.ivAnswer.setVisibility(View.GONE);
}
}
return convertView;
}
}
static class viewHodler{
public TextView tvAsk;
public TextView tvAnswer;
public LinearLayout llAnswer;
public ImageView ivAnswer;
}
}
顯示聊天的樣式inflate中用到的佈局效果爲
item_pager的代碼如下:
<?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" >
<TextView
android:id="@+id/tv_ask"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:textSize="20dp"
android:paddingTop="10dp"
android:background="@drawable/asker_bubble"
android:gravity="center"
android:text="TextView" />
<LinearLayout
android:id="@+id/ll_answer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@drawable/answer_bubble"
android:layout_marginTop="40dp"
>
<TextView
android:id="@+id/tv_answer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20dp"
android:layout_alignParentLeft="true"
android:layout_below="@+id/textView1"
android:gravity="center"
android:text="TextView" />
<ImageView
android:id="@+id/iv_answer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
</LinearLayout>
</RelativeLayout>
佈局都有了現在的問題就是數據的顯示。前面的功能中我們提到了我們自己語言說話能在對話框中顯示其實是語音SDK中自動識別了我們的話進行Json解析語音SDK中有提到也會有示例代碼其中部分代碼如下:
// 語音聽寫UI
public void startListenUI(View view) {
// 1.創建RecognizerDialog對象
RecognizerDialog mDialog = new RecognizerDialog(this, null);
// 2.設置accent、language等參數
mDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
mDialog.setParameter(SpeechConstant.ACCENT, "mandarin");
// 3.設置回調接口
mDialog.setListener(new RecognizerDialogListener() {
@Override
public void onResult(RecognizerResult results, boolean isLast) {
String parseResult = parseData(results.getResultString());
其中的onResult回調方法中就會得到results也就是語音得到的json數據其中就包含我們我的文字。
既然是Json數據那麼就要對它進行解析。方法就是syso在控制檯中Json數據然後查看Json數據從而解析,小編就是用Gson對其進行解析,注意要引入Gson的庫文件,當然還少不了javabean咯!VoiceBean代碼如下
package com.song.mysiri;
import java.util.ArrayList;
public class VoiceBean {
public ArrayList<wsBean> ws;
public class wsBean {
public ArrayList<cwBean> cw;
public class cwBean {
public String w;
}
}
}
好了javabean也有了現在就是寫一個方法進行簡單的解析唄代碼如下:
protected String parseData(String resultString) {
Gson gson = new Gson();
VoiceBean voiceBean = gson.fromJson(resultString, VoiceBean.class);
StringBuffer sb = new StringBuffer();
ArrayList<wsBean> ws = voiceBean.ws;
for (wsBean wsBean : ws) {
ArrayList<cwBean> cw = wsBean.cw;
String word = cw.get(0).w;
sb.append(word);
}
return sb.toString();
}
解析完後就可以得到我們說入的連貫的文字。好,得到了文字現在就是要對文字進行封裝吧!因此寫一個javabean,其中要考慮三個屬性1.文本,2.是我們說的文本還是機器人說的文本,3.是不是會有圖片,畢竟我們說話不可能攜帶圖片吧!TextBean的代碼如下:
package com.song.mysiri;
public class TextBean {
public String text;
public boolean isAsk;
public int image = -1;
public TextBean(String text, boolean isAsk, int image) {
this.text = text;
this.isAsk = isAsk;
this.image = image;
}
}
現在有了javabean現在就是把文本,是否是我們說的話,是否有圖片這三個屬性傳到javabean中進行封裝,同時來一個容器mListBean把對象放進去:
//把說的文字進行封裝
//提問finalResult
TextBean askBean = new TextBean(finalResult, true, -1);
mListBean.add(askBean);
終於有對象了(哈哈程序員難找對象~)然後就是對ListVieiw的適配器進行適配。代碼上面都有了固定語句,全是套路~!我們說的話就可以成功顯示在對話框中,顯示就是要解決機器人的對話框了,在這裏我們的機器人用的是自己輸入固定的對話語句代碼如下:
Random random = new Random();
String answer = UnKnow[random.nextInt(UnKnow.length)];
int imageId = -1;
if(finalResult.contains("你好")){
answer = "你特麼真好!";
}else if(finalResult.contains("還好嗎")){
answer = "我很好 謝謝!";
}else if(finalResult.contains("你是")){
answer = "我是你的語音小助手啊!";
}else if(finalResult.contains("美女")){
answer = Answer[random.nextInt(Answer.length)];
imageId = Image[random.nextInt(Image.length)];
}
//回答把回答的文字進行封裝
TextBean answerBean = new TextBean(answer, false, imageId);
mListBean.add(answerBean);
終於到了最後一步!就是讓機器人讀出這些話,好吧其實這也是SDK要做的事情,開發文檔中肯定也會有,代碼如下:
// 語音合成
public void startSpeak(String text) {
// 1.創建SpeechSynthesizer對象, 第二個參數:本地合成時傳InitListener
SpeechSynthesizer mTts = SpeechSynthesizer
.createSynthesizer(this, null);
// 2.合成參數設置,詳見《科大訊飛MSC API手冊(Android)》SpeechSynthesizer 類
// 設置發音人(更多在線發音人,用戶可參見 附錄12.2
mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoqi"); // 設置發音人
mTts.setParameter(SpeechConstant.SPEED, "50");// 設置語速
mTts.setParameter(SpeechConstant.VOLUME, "80");// 設置音量,範圍0~100
mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); // 設置雲端
// mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH,
// "./sdcard/iflytek.pcm");
// 3.開始合成
mTts.startSpeaking(text, null);
}
MainActivity的代碼如下:
package com.song.mysiri;
import java.util.ArrayList;
import java.util.Random;
import com.google.gson.Gson;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SpeechUtility;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;
import com.song.mysiri.VoiceBean.wsBean;
import com.song.mysiri.VoiceBean.wsBean.cwBean;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private ListView iv_list;
private LinearLayout ll_layout;
private Button btn_siri;
StringBuffer mBuffer = new StringBuffer();
public ArrayList<TextBean> mListBean = new ArrayList<TextBean>(); //把文字對象放在容器中
private MyAdapter myAdapter;
public String [] Answer = new String[]{"你怎麼這麼壞,給你吧!", "以後不要找我要啊!",
"好吧給你一張", "我不會告訴女主人的!"};
public int [] Image = new int[]{R.drawable.p1,R.drawable.p2,R.drawable.p3,R.drawable.p4};
public String[] UnKnow = new String[]{"不好意思,我注入的詞彙不夠!", "我還是個孩子啊!別問那麼多問題!",
"媽的傻屌,說了不要亂問!", "我聽不懂!", "你還是別知道太多了!"};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SpeechUtility.createUtility(this, SpeechConstant.APPID + "=55cfe490");
iv_list = (ListView) findViewById(R.id.iv_list);
ll_layout = (LinearLayout)findViewById(R.id.ll_layout);
btn_siri = (Button)findViewById(R.id.btn_siri);
myAdapter = new MyAdapter();
iv_list.setAdapter(myAdapter);
}
// 語音聽寫UI
public void startListenUI(View view) {
// 1.創建RecognizerDialog對象
RecognizerDialog mDialog = new RecognizerDialog(this, null);
// 2.設置accent、language等參數
mDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
mDialog.setParameter(SpeechConstant.ACCENT, "mandarin");
// 3.設置回調接口
mDialog.setListener(new RecognizerDialogListener() {
@Override
public void onResult(RecognizerResult results, boolean isLast) {
String parseResult = parseData(results.getResultString());
// System.out.println(parseResult);
mBuffer.append(parseResult);
// System.out.println("isLast:" + isLast);
if(isLast){
String finalResult = mBuffer.toString();
System.out.println();
mBuffer = new StringBuffer(); //相當於StrinBuffer清空
//把說的文字進行封裝
//提問finalResult
TextBean askBean = new TextBean(finalResult, true, -1);
mListBean.add(askBean);
Random random = new Random();
String answer = UnKnow[random.nextInt(UnKnow.length)];
int imageId = -1;
if(finalResult.contains("你好")){
answer = "你特麼真好!";
}else if(finalResult.contains("還好嗎")){
answer = "我很好 謝謝!";
}else if(finalResult.contains("你是")){
answer = "我是你的語音小助手啊!";
}else if(finalResult.contains("美女")){
answer = Answer[random.nextInt(Answer.length)];
imageId = Image[random.nextInt(Image.length)];
}
//回答把回答的文字進行封裝
TextBean answerBean = new TextBean(answer, false, imageId);
mListBean.add(answerBean);
myAdapter.notifyDataSetChanged();
iv_list.setSelection(mListBean.size()-1);
startSpeak(answer);
}
}
@Override
public void onError(SpeechError arg0) {
}
});
// 4.顯示dialog,接收語音輸入
mDialog.show();
}
// 語音合成
public void startSpeak(String text) {
// 1.創建SpeechSynthesizer對象, 第二個參數:本地合成時傳InitListener
SpeechSynthesizer mTts = SpeechSynthesizer
.createSynthesizer(this, null);
// 2.合成參數設置,詳見《科大訊飛MSC API手冊(Android)》SpeechSynthesizer 類
// 設置發音人(更多在線發音人,用戶可參見 附錄12.2
mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoqi"); // 設置發音人
mTts.setParameter(SpeechConstant.SPEED, "50");// 設置語速
mTts.setParameter(SpeechConstant.VOLUME, "80");// 設置音量,範圍0~100
mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); // 設置雲端
// mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH,
// "./sdcard/iflytek.pcm");
// 3.開始合成
mTts.startSpeaking(text, null);
}
protected String parseData(String resultString) {
Gson gson = new Gson();
VoiceBean voiceBean = gson.fromJson(resultString, VoiceBean.class);
StringBuffer sb = new StringBuffer();
ArrayList<wsBean> ws = voiceBean.ws;
for (wsBean wsBean : ws) {
ArrayList<cwBean> cw = wsBean.cw;
String word = cw.get(0).w;
sb.append(word);
}
return sb.toString();
}
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return mListBean.size();
}
@Override
public TextBean getItem(int position) {
return mListBean.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
viewHodler mHolder = null;
if(convertView == null){
convertView = View.inflate(getApplicationContext(), R.layout.item_pager, null);
mHolder = new viewHodler();
mHolder.tvAsk = (TextView) convertView.findViewById(R.id.tv_ask);
mHolder.tvAnswer = (TextView) convertView.findViewById(R.id.tv_answer);
mHolder.llAnswer = (LinearLayout) convertView.findViewById(R.id.ll_answer);
mHolder.ivAnswer = (ImageView) convertView.findViewById(R.id.iv_answer);
convertView.setTag(mHolder);
}else{
mHolder = (viewHodler) convertView.getTag();
}
TextBean item = getItem(position);
if(item.isAsk){
mHolder.tvAsk.setVisibility(View.VISIBLE);
mHolder.llAnswer.setVisibility(View.GONE);
mHolder.tvAsk.setText(item.text);
}else{
mHolder.tvAsk.setVisibility(View.GONE);
mHolder.llAnswer.setVisibility(View.VISIBLE);
mHolder.tvAnswer.setText(item.text);
if(item.image>0){//回答內容有圖片
mHolder.ivAnswer.setVisibility(View.VISIBLE);
mHolder.ivAnswer.setImageResource(item.image);
}else{
mHolder.ivAnswer.setVisibility(View.GONE);
}
}
return convertView;
}
}
static class viewHodler{
public TextView tvAsk;
public TextView tvAnswer;
public LinearLayout llAnswer;
public ImageView ivAnswer;
}
}
終於一個聊天機器人就成功完成咯!自己做的肯定會有一丟丟成就感~