如何制作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中有提到也会有示例代码其中部分代码如下:
public void startListenUI(View view) {
RecognizerDialog mDialog = new RecognizerDialog(this, null);
mDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
mDialog.setParameter(SpeechConstant.ACCENT, "mandarin");
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把对象放进去:
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) {
SpeechSynthesizer mTts = SpeechSynthesizer
.createSynthesizer(this, null);
mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoqi");
mTts.setParameter(SpeechConstant.SPEED, "50");
mTts.setParameter(SpeechConstant.VOLUME, "80");
mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
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()
//把说的文字进行封装
//提问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")
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
}
}
终于一个聊天机器人就成功完成咯!自己做的肯定会有一丢丢成就感~ |