最近被要求做一个Demo,为了实现语音输入,因为客户是日本的,所以基本上使用Google比较大路数。本来以为是几个小时的事情,没想到遇到好几个坑,结果搞了好久,2天才完成。大概的过程基本就不描述了,最终的成果代码简单记录一下。        

        光Google的方案就有2种,

        方案1:直接端调用客户端Android的GoogleSpeechAPI,

            这个方案的好处:1,最重要的是不要钱,免费的。2,代码实现方便。3,应该API录音与传输同部进行,所以速度感觉上相对较快

            相对的坏处也有:1,无法改变界面。2,依赖Android环境,Google助手,Google框架必须。3,需要手机段能够直接链接Google的服务器(比如天朝的环境,或者某些商用的环境,所有端末必须在一个专有网络)

        方案2:在服务端使用GoogleSpeechAPI,客户端录音之后上传到服务端,通过服务端联系GoogleAPI实现语音识别

            相对第一种好处:1,自定义界面.,无所谓客户端技术,你网页,应用,APP一切皆可,更加不依赖于Android;2,只要服务端能链接Goolgle即可,客户端可以在专有网络内部

            坏处也是相对的:1,最重要是收费的,一次0.0006刀。折合日元0.8日元,5分钱人民币,看着少用着多;2,代码实现相对复杂一点。

        下面说说坑:

            首先前端Ionic3,这东西方便是方便,但是调试很麻烦,特别涉及Android或者IOS原生的机能,如果只是数据展示,那是相当推荐,确实简化很多东西,但是你要一会用个录音机,一会用个相机,一会又要调用下系统磁盘,都要上插件。虽说插件是一句话的事情,但是各种版本,相互掣肘,坑那是相当多。这次因为只是Demo。所以为了方便,用了原先自己好玩搭的客户端IONIC,服务端则是直接在另一个Spring项目里面新建了个Controlor,节省时间。

        废话不多说,直接上代码

        首先是方案1:(英语好的同学可用插件名直接Google)

                1,添加插件

ionic cordova plugin add cordova-plugin-speechrecognition
npm install --save @ionic-native/speech-recognition

                2,代码

//引入包
import { SpeechRecognition } from '@ionic-native/speech-recognition';
//构造引入
constructor(private speechRecognition: SpeechRecognition) { }
//使用就是一句话的事情
this.speechRecognition.startListening(options).subscribe(matches => {
      this.matches = matches;   //结果列表,传到前台用于显示
});

        到这里方案1,结束;所以方案1也就是分分钟的事情…

        下面是方案2

                 1,添加插件(media插件,file插件,http插件)

--media插件
ionic cordova plugin add cordova-plugin-media
npm install --save @ionic-native/media
--file插件
ionic cordova plugin add cordova-plugin-file
npm install --save @ionic-native/file
--http插件
ionic cordova plugin add cordova-plugin-advanced-http
$ npm install --save @ionic-native/http

                 2,主要代码的使用(media插件,file插件,http插件)

//引入包
import { Media, MediaObject } from '@ionic-native/media';
import { File } from '@ionic-native/file';
import { HTTP } from '@ionic-native/http';
//构造引入
constructor(
            private media: Media, 
            private file: File,
            //public http: Http) {}
//代码
audio: MediaObject;
//开始录音
this.audio = this.media.create(this.filePath);
//结束录音,并保存到文件
this.audio.startRecord();
//读取文件
this.file.readAsDataURL(folder, 'record.wav')
    .then(content => {
         //文件读取到Base64,真实代码这里调用POST请求
    }).catch(err => {//异常系});
//定义一个发送数据集
let postData = {
    "userid": "Customer004",
    "file": inContent, //真实代码这里放读到的文件BASE64内容
}
//发送POST请求
this.http.post(link, postData, {})
    .then(data => {
        //POST请求成功
    })
    .catch(error => {//异常系});

        到这里,客户端就结束了,看着简单,其实过程遇到很多坑。可能是学的不扎实,ionic要在后台读取文件,直接POST请求,似乎有点困难(除非界面有INPUT)。有些插件 比如定义一个File,或者File转一个BLOB能行,但是配合POST的插件,Spring控件那边识别不了等等,各种坑,时间原因直接先在客户端文件转BASE64变成字符串,POST到服务端,Spring那边最后能获得数据,那这个DEMO的客户端基本就OK了。

下面是服务端,小问题不少,

        首先是BASE64转文件

fileBase64 = fileBase64.replace("data:audio/x-wav;base64,","");  //要切掉头
byte[] decodedImg = Base64.getDecoder().decode(fileBase64.getBytes(StandardCharsets.UTF_8));    //Base64转Byte数组
Files.write(destinationFile, decodedImg); //保存文件

        由于GoogleSpeechAPI只支持单声道的音频文件输入,所以对上传的文件还要转格式,一阵搜索,找到一个包

MAVEN添加,(https://github.com/a-schild/jave2 支持多系统,乖乖好像要200兆,其实是JAVA封装的ffmpeg项目)

<dependency>
	<groupId>ws.schild</groupId>
	<artifactId>jave-all-deps</artifactId>
	<version>2.4.4</version>
</dependency>

使用这个,音频文件转格式

File source = new File(inputFile);
File target = new File(outputFile);
// Audio Attributes
AudioAttributes audio = new AudioAttributes();
audio.setCodec("flac");
audio.setBitRate(128000);
audio.setChannels(1);
audio.setSamplingRate(16000);
// Encoding attributes
EncodingAttributes attrs = new EncodingAttributes();
attrs.setFormat("flac");
attrs.setAudioAttributes(audio);
// Encode
Encoder encoder = new Encoder();
encoder.encode(new MultimediaObject(source), target, attrs);

转好了FLAC文件调用GoogleAPI,那就是Google的例子直接能用了

try (SpeechClient speechClient = SpeechClient.create()) {
	// Reads the audio file into memory
	Path path = Paths.get(fileName);
	byte[] data = Files.readAllBytes(path);
	ByteString audioBytes = ByteString.copyFrom(data);
	// Builds the sync recognize request
	RecognitionConfig config = RecognitionConfig.newBuilder()
	.setEncoding(AudioEncoding.FLAC).setSampleRateHertz(16000).setLanguageCode("ja-JP").build();
	RecognitionAudio audio = RecognitionAudio.newBuilder().setContent(audioBytes).build();
	RecognizeResponse response = speechClient.recognize(config, audio);
	List<SpeechRecognitionResult> results = response.getResultsList();
	for (SpeechRecognitionResult result : results) {
		// There can be several alternative transcripts for a given chunk of speech.
		// Just use the
		// first (most likely) one here.
		SpeechRecognitionAlternative alternative = result.getAlternativesList().get(0);
		strResult =  alternative.getTranscript();
		System.out.printf("Transcription: %s%n", alternative.getTranscript());
	}
} catch (Exception e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
}

到这里基本就结束了,启动Springboot的时候需要系统环境里添加API认证用的Key,Linux用export命令,Windows环境用系统变量。这里就不多说了,具体可以Google 【GOOGLE_APPLICATION_CREDENTIALS】。

最后修改日期: 2022年6月13日

作者