zoukankan      html  css  js  c++  java
  • 为你的应用装上“耳朵”

    背景:

      公司每年会给出两天时间让大家各自提出、准备、实现和展示自己的idea。源于这次活动,对于语音识别做了一番了解,并对一些工具和API做了一些实战调用。最后选择调用一个神奇的js库实现了语音识别和指令识别,融入了项目当中。

      Demo的视频地址:http://pan.baidu.com/s/1c1OsQYk  提取密码:229p

     

      起初,准备使用百度语音API实现语音识别,但是面临下面的困扰:

        1.REST方式,百度推出的基于跨平台的REST 方式的语音识别,但是API文档中明确说明,该方式只支持音频文件上传的方式

        2.Android平台,搭建好android环境并导入项目后,Demo程序可以运行,而且导出的apk文件也可以在android真机上运行。但是我们的产品是web应用,要将android平台的代码抽出来放进产品,从时间上来说,显然不够

     

      后来,我们找到了一个js库——annyang。

        该库是一个很小的JavaScript库,可以让你的访客用语音命令来控制你的网站。annyang支持多国语言,没有依赖性,重量仅为2KB,可以免费使用。

     

    所以今天的主要内容分为以下三部分

    百度语音Android平台

    1.导入项目代码  

      在上篇《玩转百度语音识别,就是这么简单》我们已经搭建了android的环境,并导入百度给出的Android Demo代码。但是之前我们只看到了一个名为"Speech Recorder"的应用,后来我再次启动模拟器的时候,除了"Speech Recorder"以外还有一个"百度语音示例(2.x)"的应用。

      在模拟器中似乎没有办法访问到麦克风,于是安装到android机上测试。当然首先你需要将代码Export为apk文件,具体操作网上很多。

      

    2.安装过程和测试过程

      安装完成

      应用界面:

      语音输入及识别结果

                                            (太不要脸了,但是说的都是大实话^^)

      至此,亲测android平台可用,而且从识别结果来看,还是蛮准确的。

    百度语音REST API

      在上篇中我们也对REST API的方式做了介绍并亲测上传录制好的音频文件再调用API是能够返回结果的。REST API的调用方式跨平台,轻便好用,但是需要录好音频文件上传后才能得到语音识别的结果,显得不是很方便。

    1.设计思路

    • 绘制一个界面包含开始和结束用于控制语音输入
    • 点击开始时,开始调用麦克风
    • 添加线程监控麦克风,将麦克风输入的内容存储为指定音频格式的文件
    • 当点击停止按钮时,调用语音识别的REST API,读取刚刚生成的音频文件
    • 请求远程识别服务,返回音频文件识别后的结果

    有了以上思路,具体实现的代码如下

    package com.baidu.speech.serviceapi;
    
    import javax.swing.*;
    import javax.xml.bind.DatatypeConverter;
    
    import org.json.JSONObject;
    
    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import javax.sound.sampled.*;
    
    public class AudioUI extends JFrame {
    
    	AudioFormat audioFormat;
    	TargetDataLine targetDataLine;
    
    	final JButton captureBtn = new JButton("Capture");
    	final JButton stopBtn = new JButton("Stop");
    
    	final JPanel btnPanel = new JPanel();
    	final ButtonGroup btnGroup = new ButtonGroup();
    	final JRadioButton aifcBtn = new JRadioButton("AIFC");
    	final JRadioButton aiffBtn = new JRadioButton("AIFF");
    	final JRadioButton auBtn = // selected at startup
    	new JRadioButton("AU", true);
    	final JRadioButton sndBtn = new JRadioButton("SND");
    	final JRadioButton waveBtn = new JRadioButton("WAVE");
    	
    	//definition variable for REST 
    	private static final String serverURL = "http://vop.baidu.com/server_api";
          private static String token = "";
          private static final String testFileName = "C:\Users\Administrator\workspace\speechrecognition\output.wav";
          //put your own params here
          private static final String apiKey = "***";//这里的apiKey就是前面申请在应用卡片中的apiKey
          private static final String secretKey = "***";//这里的secretKey就是前面申请在应用卡片中的secretKey
          private static final String cuid = "***";//cuid是设备的唯一标示,因为我用的是PC,所以这里用的是网卡Mac地址
    
    	public static void main(String args[]) {
    		new AudioUI();
    	}// end main
    
    	public AudioUI() {// constructor
    		captureBtn.setEnabled(true);
    		stopBtn.setEnabled(false);
    
    		// Register anonymous listeners
    		captureBtn.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				captureBtn.setEnabled(false);
    				stopBtn.setEnabled(true);
    				// Capture input data from the
    				// microphone until the Stop button is
    				// clicked.
    				captureAudio();
    			}// end actionPerformed
    		}// end ActionListener
    		);// end addActionListener()
    
    		stopBtn.addActionListener(new ActionListener() {
    			public void actionPerformed(ActionEvent e) {
    				captureBtn.setEnabled(true);
    				stopBtn.setEnabled(false);
    				// Terminate the capturing of input data
    				// from the microphone.
    				targetDataLine.stop();
    				targetDataLine.close();
    				try {
    					getToken();
    					method1();
    			        method2();
    				} catch (Exception e1) {
    					// TODO Auto-generated catch block
    					e1.printStackTrace();
    				}
    		        
    			}// end actionPerformed
    		}// end ActionListener
    		);// end addActionListener()
    
    		// Put the buttons in the JFrame
    		getContentPane().add(captureBtn);
    		getContentPane().add(stopBtn);
    
    		// Include the radio buttons in a group
    		btnGroup.add(aifcBtn);
    		btnGroup.add(aiffBtn);
    		btnGroup.add(auBtn);
    		btnGroup.add(sndBtn);
    		btnGroup.add(waveBtn);
    
    		// Add the radio buttons to the JPanel
    		btnPanel.add(aifcBtn);
    		btnPanel.add(aiffBtn);
    		btnPanel.add(auBtn);
    		btnPanel.add(sndBtn);
    		btnPanel.add(waveBtn);
    
    		// Put the JPanel in the JFrame
    		getContentPane().add(btnPanel);
    
    		// Finish the GUI and make visible
    		getContentPane().setLayout(new FlowLayout());
    		setTitle("Copyright 2003, R.G.Baldwin");
    		setDefaultCloseOperation(EXIT_ON_CLOSE);
    		setSize(300, 120);
    		setVisible(true);
    	}// end constructor
    
    	// This method captures audio input from a
    	// microphone and saves it in an audio file.
    	private void captureAudio() {
    		try {
    			// Get things set up for capture
    			audioFormat = getAudioFormat();
    			DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
    			targetDataLine = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
    
    			// Create a thread to capture the microphone
    			// data into an audio file and start the
    			// thread running. It will run until the
    			// Stop button is clicked. This method
    			// will return after starting the thread.
    			new CaptureThread().start();
    		} catch (Exception e) {
    			e.printStackTrace();
    			System.exit(0);
    		} // end catch
    	}// end captureAudio method
    
    	// This method creates and returns an
    	// AudioFormat object for a given set of format
    	// parameters. If these parameters don't work
    	// well for you, try some of the other
    	// allowable parameter values, which are shown
    	// in comments following the declarations.
    	private AudioFormat getAudioFormat() {
    		float sampleRate = 8000.0F;
    		// 8000,11025,16000,22050,44100
    		int sampleSizeInBits = 16;
    		// 8,16
    		int channels = 1;
    		// 1,2
    		boolean signed = true;
    		// true,false
    		boolean bigEndian = false;
    		// true,false
    		return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
    	}// end getAudioFormat
    	// =============================================//
    
    	// Inner class to capture data from microphone
    	// and write it to an output audio file.
    	class CaptureThread extends Thread {
    		public void run() {
    			AudioFileFormat.Type fileType = null;
    			File audioFile = null;
    
    			// Set the file type and the file extension
    			// based on the selected radio button.
    			if (aifcBtn.isSelected()) {
    				fileType = AudioFileFormat.Type.AIFC;
    				audioFile = new File("output.aifc");
    			} else if (aiffBtn.isSelected()) {
    				fileType = AudioFileFormat.Type.AIFF;
    				audioFile = new File("output.aif");
    			} else if (auBtn.isSelected()) {
    				fileType = AudioFileFormat.Type.AU;
    				audioFile = new File("output.au");
    			} else if (sndBtn.isSelected()) {
    				fileType = AudioFileFormat.Type.SND;
    				audioFile = new File("output.snd");
    			} else if (waveBtn.isSelected()) {
    				fileType = AudioFileFormat.Type.WAVE;
    				audioFile = new File("output.wav");
    			} // end if
    
    			try {
    				targetDataLine.open(audioFormat);
    				targetDataLine.start();
    				AudioSystem.write(new AudioInputStream(targetDataLine), fileType, audioFile);
    			} catch (Exception e) {
    				e.printStackTrace();
    			} // end catch
    
    		}// end run
    	}// end inner class CaptureThread
    	// =============================================//
    	
    	private static 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");
        }
    
        private static void method1() throws Exception {
            File pcmFile = new File(testFileName);
            HttpURLConnection conn = (HttpURLConnection) new URL(serverURL).openConnection();
    
            // construct params
            JSONObject params = new JSONObject();
            params.put("format", "pcm");
            params.put("rate", 8000);
            params.put("lan", "en");
            params.put("channel", "1");
            params.put("token", token);
            params.put("cuid", cuid);
            params.put("len", pcmFile.length());
            params.put("speech", DatatypeConverter.printBase64Binary(loadFile(pcmFile)));
    
            // add request header
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "application/json; charset=utf-8");
    
            conn.setDoInput(true);
            conn.setDoOutput(true);
    
            // send request
            DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
            wr.writeBytes(params.toString());
            wr.flush();
            wr.close();
    
            printResponse(conn);
        }
    
        private static void method2() throws Exception {
            File pcmFile = new File(testFileName);
            HttpURLConnection conn = (HttpURLConnection) new URL(serverURL
                    + "?cuid=" + cuid + "&token=" + token).openConnection();
    
            // add request header
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "audio/pcm; rate=8000");
    
            conn.setDoInput(true);
            conn.setDoOutput(true);
    
            // send request
            DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
            wr.write(loadFile(pcmFile));
            wr.flush();
            wr.close();
    
            printResponse(conn);
        }
    
        private static String printResponse(HttpURLConnection conn) throws Exception {
            if (conn.getResponseCode() != 200) {
                // request error
                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('
    ');
            }
            rd.close();
            System.out.println(new JSONObject(response.toString()).toString(4));
            return response.toString();
        }
    
        private static 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;
        }
    
    }
    

      注意上面的apiKey,secretKey,cuid都要填写自己申请后的值。

    2.效果展示

      弹出的ui界面

      选择"wave",点击Capture,开始语音输入,然后点击stop,得到结果

    {
        "access_token": "24.***a82646fffd31.259**2335-7980222",
        "refresh_token": "25.18***6f.315360000.1***-7980222",
        "scope": "public audio_voice_assistant_get wise_adapt lebo_resource_base lightservice_public hetu_basic lightcms_map_poi kaidian_kaidian",
        "session_key": "***URC38LpHQ+crR5n6hQ***zVZRBK/rpVGeNviJXnmJpFIwpsT97C4xvsD",
        "session_secret": "***db82f505cba***",
        "expires_in": 2592000
    }
    {
        "result": [
            "hello how are you, ",
            "hello oh how are you, ",
            "hello how are u, ",
            "halo how are you, ",
            "hollow how are you, "
        ],
        "err_msg": "success.",
        "sn": "776663153181460775167",
        "corpus_no": "6273981573367938505",
        "err_no": 0
    }
    {
        "result": ["哈喽好玩哟,"],
        "err_msg": "success.",
        "sn": "496395116711460775168",
        "corpus_no": "6273981574058301747",
        "err_no": 0
    }
    

      这里LZ输入的语音为“hello,how are you”。从识别结果来看很理想。而且百度语音识别支持三种语言(中文,英语,粤语),这里第一个返回的结果是英文版本,第二个返回的结果是中文版本。

      有了麦克风的支持,REST API的调用方式显得可操作性更强了,你可以将这种方式集成到你的应用,实现在线输入,在线搜索等等功能。

    annyang

    1.annyang介绍

      annyang就是一个js库,可以集成到你的应用中,只有2kb的大小,它到底有多好用我们可以去它的demo网站体验下就知道了

    http://www.jq22.com/yanshi216    annyang1.0.0版本

    https://www.talater.com/annyang/   annyang2.3.0版本

      从console控制台可以看到该网站共加载了四条指令:hello(there), show me * search, show :type report以及let's get started

      这里LZ说出了指令"hello there",产生的效果就是console显示了识别的结果为hello there并与网站加载的指令hello there匹配上了,所以网站会自动跳转到显示hell的部分

      

      这里LZ说的是show me voice search,所以匹配的show me *search指令,并且页面跳转到“show me”的部分

    2.集成annyang到自己的应用

      在自己的github angelloExtend中加入annyang的支持,只需要两步:

    (1)引入annyang.js

      在boot.js中添加

    { file: '//cdnjs.cloudflare.com/ajax/libs/annyang/2.3.0/annyang.min.js'},
    

    (2)在DataCtroller.js中添加一条command并启动annyang服务

    if (annyang) {
    	// Let's define our first command. First the text we expect, and then the function it should call
    	var commands = {
    		 'show bar chart': function() {
    		  alert("hahahha~~~~");
    		  myUser.show('bar');
    	 }
     };
    						
       // Add our commands to annyang
           annyang.addCommands(commands);
    						
      // Start listening. You can call this here, or attach this call to an event, button, etc.
           annyang.start();
     }
    

      具体参见项目:https://github.com/DMinerJackie/angelloExtend

    至此,我们主要介绍了

      1.基于android平台的百度语音识别的测试和验证

      2.基于REST API方式的语音识别,并实现调用麦克风实现在线语音输入和识别的功能

      3.介绍annyang并演示如何使用与集成该库

    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!如果您想持续关注我的文章,请扫描二维码,关注JackieZheng的微信公众号,我会将我的文章推送给您,并和您一起分享我日常阅读过的优质文章。

      

    友情赞助

    如果你觉得博主的文章对你那么一点小帮助,恰巧你又有想打赏博主的小冲动,那么事不宜迟,赶紧扫一扫,小额地赞助下,攒个奶粉钱,也是让博主有动力继续努力,写出更好的文章^^。

        1. 支付宝                          2. 微信

                          

  • 相关阅读:
    HTML元素解释
    Java命名规范
    HDU 1058 Humble Numbers(DP,数)
    HDU 2845 Beans(DP,最大不连续和)
    HDU 2830 Matrix Swapping II (DP,最大全1矩阵)
    HDU 2870 Largest Submatrix(DP)
    HDU 1421 搬寝室(DP)
    HDU 2844 Coins (组合背包)
    HDU 2577 How to Type(模拟)
    HDU 2159 FATE(二维完全背包)
  • 原文地址:https://www.cnblogs.com/bigdataZJ/p/SpeechRecognition2.html
Copyright © 2011-2022 走看看