使用Java编写一个与图灵机器人进行对话的工具。
但图灵机器人只支持文本对话,并不支持语音交互,所以本程序运用了第三方库百度语音识别/合成,来实现语音交互。
我们还可以将下载好的音乐放入指定文件夹,进行简单的配置后还能点歌。
1.登录图灵机器人官网:http://www.turingapi.com/,完成注册、身份认证、创建机器人。一般一到两天后就能身份审核成功,创建好机器人之后就会生成自己的apikey:
2.登录百度智能云官网:http://ai.baidu.com/,右上角“控制台”进入登录界面。登录后点击“语音技术”、“创建应用”,应用创建好后就是呢过程自己的AppID,API Key,Secret Key:
3.完成以上准备工作就可以开始编码了。我们可以参考相关文档,以及下载SDK。不同语言有不同的SDK,根据自己所需来下载。我这里使用的Java语言编写,所以下载的是“识别、合成 RESTful API JAVA SDK”。
4.以下就是相关代码:
Record类完成录音、播放音频文件:
package com.feng.robot;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import java.io.*;
import java.util.Scanner;
import javax.sound.sampled.*;
/**
* 录音record(),录音完毕后将音频文件保存到指定文件夹中
* 播放音频文件play(音频文件路径)
*/
public class Record {
private static AudioFormat audioFormat;
static TargetDataLine targetDataLine;
public File record() {
System.out.println("想聊天,请按y。结束讲话,请按n。");
Scanner input = new Scanner(System.in);
String Sinput = input.next();
if(Sinput.equals("y")){
System.out.println("讲话中……");
captureAudio();//调用录音方法
}
Scanner input_2 = new Scanner(System.in);
String Sinput_2 = input_2.next();
if(Sinput_2.equals("n")){
targetDataLine.stop();
targetDataLine.close();
System.out.println("结束讲话。");
}
//结束录音后便在指定路径生成一个record.wav文件
File audioFile = new File("F:\\record.wav");
return audioFile;
}
//录音方法
public void captureAudio(){
try {
audioFormat = new AudioFormat(16000,16,1,true,false);
DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
new CaptureThread().start();//开启线程
} catch (Exception e){
e.printStackTrace();
System.exit(0);
}
}
class CaptureThread extends Thread {
public void run() {
AudioFileFormat.Type fileType = null;
//指定的文件类型
File audioFile = null;
//设置文件类型和文件扩展名
//根据选择的单选按钮。
fileType = AudioFileFormat.Type.WAVE;
audioFile = new File("F://record.wav");
try {
targetDataLine.open(audioFormat);
targetDataLine.start();
//当开始音频捕获或回放时,生成 START 事件。
AudioSystem.write(new AudioInputStream(targetDataLine),fileType, audioFile);
} catch (Exception e) {
e.printStackTrace();
}
}
}
//播放音频文件
public void play(String filePathName){
File file = new File(filePathName);
try {
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
Player player = new Player(bis);
player.play();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JavaLayerException e) {
e.printStackTrace();
}
}
}
SpeechRec类完成百度语音识别/合成:
package com.feng.robot;
import com.baidu.aip.speech.AipSpeech;
import com.baidu.aip.speech.TtsResponse;
import org.json.JSONObject;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
/**
* 百度语音识别ASR() & 合成TTS()
*/
public class SpeechRec {
private static final String serverURL = "http://vop.baidu.com/server_api";
private static String token = "";
private static final String apiKey = "自己的API Key";
private static final String secretKey = "自己的Secret Key";
private static final String cuid = "自己的App ID";
public static void main(String[] args) throws Exception {
Record record = new Record();
SpeechRec s = new SpeechRec();
record.record();
s.getToken();
String str = s.ASR(new File("F:\\record.wav"));
System.out.println(str);
}
//语音识别:音频-->文本,并返回解析后的文本
public String ASR(File recordFile) throws Exception {
HttpURLConnection conn = (HttpURLConnection) new URL(serverURL
+ "?cuid=" + cuid + "&token=" + token).openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "audio/wav; rate=16000");
conn.setDoInput(true);
conn.setDoOutput(true);
// 发送请求
DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
wr.write(loadFile(recordFile));
wr.flush();
wr.close();
String recordText = parseJson(printResponse(conn));//解析后的识别文本
return recordText;
}
public void getToken() throws Exception {
String getTokenURL = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials" +
"&client_id=" + apiKey + "&client_secret=" + secretKey;
HttpURLConnection conn = (HttpURLConnection) new URL(getTokenURL).openConnection();
token = new JSONObject(printResponse(conn)).getString("access_token");
}
public String printResponse(HttpURLConnection conn) throws Exception {
if (conn.getResponseCode() != 200) {
System.out.println("conn.getResponseCode() = " + conn.getResponseCode());
return "";
}
InputStream is = conn.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer response = new StringBuffer();
while ((line = rd.readLine()) != null) {
response.append(line);
response.append('\r');
}
rd.close();
return response.toString();
}
private byte[] loadFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
long length = file.length();
byte[] bytes = new byte[(int) length];
int offset = 0;
int numRead = 0;
while (offset < bytes.length
&& (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
offset += numRead;
}
if (offset < bytes.length) {
is.close();
throw new IOException("Could not completely read file " + file.getName());
}
is.close();
return bytes;
}
//解析后,得到百度语音识别后的文本
public String parseJson(String response){
if(response == null){
return "";
}
net.sf.json.JSONObject ASRResult = net.sf.json.JSONObject.fromObject(response);
String resultText = "";
if(ASRResult.get("result") == null){
resultText = "[\"\"]";
}else{
resultText = ASRResult.get("result").toString();
}
//resultText = ASRResult.get("result").toString();
resultText = resultText.substring(2,resultText.length()-2);
return resultText;
}
//语音合成,文本-->音频,返回得到的音频文件
public File TTS(String text){
AipSpeech aipSpeech = new AipSpeech(cuid,apiKey,secretKey);
HashMap options = new HashMap();
options.put("spd","5");
options.put("pit","5");
options.put("per","4");
TtsResponse ttsResponse = aipSpeech.synthesis(text,"zh",1,options);
byte[] aa = ttsResponse.getData();
getFile(aa,"F:\\play.wav");
File file = new File("F:\\play.wav");
return file;
}
//合成的二进制数据放入文件中
private void getFile(byte[] binData, String filePathName) {
BufferedOutputStream bos = null;
FileOutputStream fos = null;
File file = new File(filePathName);
try {
fos = new FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(binData);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{//关闭流
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}if(fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
TulingRobot类完成与图灵机器人进行对话的操作:
package com.feng.robot;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import net.sf.json.JSONObject;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
/**
* 图灵机器人
*/
public class TulingRobot {
private static final String url = "http://www.tuling123.com/openapi/";
private static final String api_key = "自己的apiKey";
//获取响应,得到响应的json字符串
public String getResult( String message ) {
//图灵api接口
String apiUrl = url+"api?key="+api_key+"&info=";
try {
//设置编码格式
message = URLEncoder.encode(message, "utf-8");
//拼接url
apiUrl = apiUrl + message;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//封装请求头
HttpPost request = new HttpPost(apiUrl);
String result = "";
try {
//发送http请求
HttpResponse response = HttpClients.createDefault().execute(request);
//获取响应码
int code = response.getStatusLine().getStatusCode();
if (code == 200) {
//获取返回的结果
result = EntityUtils.toString(response.getEntity());
} else {
System.out.println("code=" + code);
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result; //返回结果{"code":xxx,"text":xxx}
}
//解析Json字符串
public String parseJson(String jsonStirng){
if(jsonStirng == null){
return "";
}
//json字符串 --> json对象
JSONObject results = JSONObject.fromObject(jsonStirng);
String result = results.getString("text");
return result;
}
}
RobotYuanYuan类中包含了要运行的主方法,也可以在主方法添加音乐,进行点歌:
package com.feng.robot;
import java.io.File;
/**
* 机器人圆圆
*/
public class YuanYuan {
private static File recordFile = new File("F:\\record.wav");
private static String playFileName = "F:\\play.wav";
public static void main(String[] args){
/**
* 录音-->百度语音识别,获取到文本-->文本传入到图灵机器人与之对话-->拿到图灵机器人的回话
* -->百度语音合成,将回话转为音频文件-->播放音频文件
* 以上完成一次完整的对话
* 若我说:退出-->百度语音识别为“退出”-->百度语音合成文本“好的,那下次再见了”-->播放音频文件-->退出程序
* 若我说的是歌名-->播放音乐(前提是音乐已经下载好了)
*/
Record record = new Record();
SpeechRec speechRec = new SpeechRec();
TulingRobot tulingRobot = new TulingRobot();
while(true){
record.record();//录音
try {
speechRec.getToken();
String recordText = speechRec.ASR(recordFile);//百度语音识别
if(recordText.equals("退出。")){
speechRec.TTS("好的,那下次再见了");
System.out.println("(我):退出");
System.out.println("(圆圆):"+"好的,那下次再见了");
record.play(playFileName);//播放合成的音频文件
System.exit(0);//退出程序
}
if(recordText.equals("")){
speechRec.TTS("你啥也不说,我如何作答呀");
System.out.println("(我):"+recordText);
System.out.println("(圆圆):"+"你啥也不说,我如何作答呀");
record.play(playFileName);//播放合成的音频文件
continue;
}
/**
* 播放音乐(可配置)
* 配置过程:在指定文件夹下添加下载好的音乐-->如果识别的是音乐名,播放音频文件即可
*/
if(recordText.equals("意外。")){
System.out.println("音乐播放中...");
record.play("F:\\music\\意外.mp3");
continue;
}
if(recordText.equals("告白之夜。")){
System.out.println("音乐播放中...");
record.play("F:\\music\\告白之夜.mp3");
continue;
}
if(recordText.equals("工资向北走。")){//百度语音识别总是将“公子”识别成“工资”,可能是我发音不对吧哈哈 record.play("F:\\music\\公子向北走.mp3");
System.out.println("音乐播放中...");
record.play("F:\\music\\公子向北走.mp3");
continue;
}//按以上格式添加配置即可
String result = tulingRobot.parseJson(tulingRobot.getResult(recordText));//得到图灵机器人的回话
speechRec.TTS(result);//百度语音合成
System.out.println("(我):"+recordText);
System.out.println("(圆圆):"+result);
record.play(playFileName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
我们简单的运行一下:
对机器人说歌名,就可以播放音乐了:
如果想退出聊天了,说“退出”:
程序还存在缺点:播放音乐时,必须整首歌播放完之后才能继续聊天,不能中途打断。
后期可以进行扩展:不想听歌了输入相关指令停止音乐播放。
也可以进行以下扩展:让机器人打开网站进行关键词搜索等命令。