使用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();
            }
        }
    }
}

我们简单的运行一下:

对机器人说歌名,就可以播放音乐了:

如果想退出聊天了,说“退出”:

程序还存在缺点:播放音乐时,必须整首歌播放完之后才能继续聊天,不能中途打断。

后期可以进行扩展:不想听歌了输入相关指令停止音乐播放。

也可以进行以下扩展:让机器人打开网站进行关键词搜索等命令。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐