【h5】实现语音转文字
【h5】实现语音转文字
- 一、需求
- 功能概述是:
- 二、实现过程
- 1、实现按住录音,松开发送。有两个录音按钮。
- a. 获取用户的麦克风声音和创建一个`MediaRecorder`对象:
- b. 启动和停止录音:
- c. 将音频数据上传到服务器,并在处理完后返回结果并在前端展示:
- 2. 上移到特定区域取消。
- a. 获取要监听区域的坐标范围:
- b. 在touchmove事件中判断用户手指的位置是否在指定区域内:
- c. 在被判断为取消区域的情况下,需要为用户提供取消的提示信息。最好的做法是记录用户的取消动作并复原已有界面。例如:
- 3. 略微上移是ASR和展示为文字。
- a. 监听用户手指移动事件。通过touchstart、touchmove、touchend事件获取用户移动手指的位置。
- b. 监听录音停止事件,获取录音的Blob数据,并将其转化为Base64格式。
- c. 将Base64格式的语音数据上传到服务器进行处理,并在处理完成后将结果展示在前端。
- d. 在前端页面上展示语音识别结果。
- 4、查看历史消息。
- a. 在LocalStorage中保存历史消息:
- b. 在前端页面上显示历史消息列表:
- c. 在前端页面上展示历史记录并且提供删除功能。(代码在b步骤中已经给出了)。
- 三、延伸:前端H5实现调用麦克风,录音功能
- 下面是一个简单的实现流程:
- 1. 首先,我们需要请求用户授权使用麦克风。调用Navigator.mediaDevices.getUserMedia()方法即可。在授权成功后,可以通过回调函数来获取到用户的音频输入流。
- 2. 通过获取到的音频输入流,我们可以创建一个MediaRecorder对象,用于进行录音操作。MediaRecorder对象支持多种不同的配置选项,可以根据实际需要进行设置。
- 3. 开始录音:通过调用MediaRecorder对象的start()方法来开始录音。同时通过start()方法的参数可以设置录音的时长限制。
- 4. 停止录音:调用MediaRecorder对象的stop()方法停止录音。在停止录音之后,可以通过ondataavailable事件来获取录音的数据,这里的数据是一个Blob类型的对象。
一、需求

功能概述是:
- 按住录音,松开发送。有两个录音按钮。
- 上移到特定区域取消。
- 略微上移是asr和展示为文字。
- 查看历史消息。
需求是:可以h5开发,即:可以网页版,也打包为apk的安卓包
二、实现过程
1、实现按住录音,松开发送。有两个录音按钮。
a. 获取用户的麦克风声音和创建一个MediaRecorder对象:
// 获取音频输入流
const audioBuffer = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
// 创建MediaRecorder对象
const recorder = new MediaRecorder(audioBuffer);
b. 启动和停止录音:
const startRecordButton = document.getElementById('start-record');
const stopRecordButton = document.getElementById('stop-record');function handleStartRecording() {// 开始录制音频recorder.start();
}function handleStopRecording() {recorder.stop();recorder.ondataavailable = (e) => {// 看后端需要,还有一种处理是: const audioBlob = new Blob([e.data], { type: 'audio/wav' });const audioBlob = e.data;const reader = new FileReader();reader.readAsDataURL(audioBlob);reader.onloadend = () => {const audioBase64 = reader.result.split(',')[1];// 将录制好的音频数据上传到服务器进行处理,并在处理完成后将结果展示在前端postAudioDataToServer(audioBase64);}}
}startRecordButton.addEventListener('touchstart', handleStartRecording);
stopRecordButton.addEventListener('touchend', handleStopRecording);
c. 将音频数据上传到服务器,并在处理完后返回结果并在前端展示:
async function postAudioDataToServer(audioBase64) {const response = await fetch(SERVER_URL, {headers: {'Content-Type': 'application/json'},method: 'POST',body: JSON.stringify({ audio: audioBase64 })});const result = await response.json();// 在前端页面上展示处理后的语音识别结果showAsrResult(result.result);
}
或者:
function sendRecord() {recorder.stop();const audioBlob = new Blob(chunks, { type: 'audio/wav' });const formData = new FormData();formData.append('audio', audioBlob);fetch('/api/asr', {method: 'POST',body: formData}).then(response => response.json()).then(result => {// 将识别结果展示为文字}).catch(error => console.error(error));
}
2. 上移到特定区域取消。
a. 获取要监听区域的坐标范围:
const cancelArea = document.getElementById('cancel-area');
const cancelAreaRect = cancelArea.getBoundingClientRect();
b. 在touchmove事件中判断用户手指的位置是否在指定区域内:
const recordedArea = document.getElementById('recorded-area');function handleTouchMove(e) {const touchY = e.touches[0].clientY;if (touchY < cancelAreaRect.top) {// 用户的手指已经滑出了取消所在的区域recordedArea.classList.remove('cancel');} else {// 用户的手指仍在取消所在区域内recordedArea.classList.add('cancel');}
}document.addEventListener('touchmove', handleTouchMove);
c. 在被判断为取消区域的情况下,需要为用户提供取消的提示信息。最好的做法是记录用户的取消动作并复原已有界面。例如:
function handleTouchEnd(e) {if (recordedArea.classList.contains('cancel')) {// 用户已经划出了取消区域recorder.stop();recorder.ondataavailable = null;recorder = null;// 给用户展示取消信息alert('录音已取消');} else {// 用户完成了一次完整的录音,并且已经成功上传到服务器alert('录音上传成功');}
}document.addEventListener('touchend', handleTouchEnd);
3. 略微上移是ASR和展示为文字。
语音识别功能可以使用第三方语音识别服务(如百度语音识别、科大讯飞语音识别等)来实现语音识别功能。具体步骤如下:
- 在
postAudioDataToServer函数中,停止录制音频,并将录制的音频发送至服务器。- 在服务器端,将接收到的音频数据发送至第三方语音识别服务进行处理,并将识别结果返回给客户端。
- 在客户端,将语音识别结果展示为文字。
a. 监听用户手指移动事件。通过touchstart、touchmove、touchend事件获取用户移动手指的位置。
let startY = 0;
let currentY = 0;function handleTouchStart(e) {startY = e.touches[0].clientY;
}function handleTouchMove(e) {currentY = e.touches[0].clientY;
}function handleTouchEnd(e) {const deltaY = startY - currentY;if (deltaY > MIN_SLIDE_DISTANCE) {// 触发ASR操作shouldAsr = true;}
}document.addEventListener('touchstart', handleTouchStart, { passive: true });
document.addEventListener('touchmove', handleTouchMove, { passive: true });
document.addEventListener('touchend', handleTouchEnd, { passive: true });
b. 监听录音停止事件,获取录音的Blob数据,并将其转化为Base64格式。
recorder.ondataavailable = (e) => {const audioBlob = e.data;const reader = new FileReader();reader.readAsDataURL(audioBlob);reader.onloadend = () => {const audioBase64 = reader.result.split(',')[1];// 将录制好的音频数据上传到服务器进行处理,并在处理完成后将结果展示在前端postAudioDataToServer(audioBase64);}
}
c. 将Base64格式的语音数据上传到服务器进行处理,并在处理完成后将结果展示在前端。
async function postAudioDataToServer(audioBase64) {const response = await fetch(SERVER_URL, {headers: {'Content-Type': 'application/json'},method: 'POST',body: JSON.stringify({ audio: audioBase64 })});const result = await response.json();// 在前端页面上展示语音识别结果showAsrResult(result.result);
}
d. 在前端页面上展示语音识别结果。
function showAsrResult(result) {const asrResultArea = document.getElementById('asr-result');const p = document.createElement('p');p.innerText = result;asrResultArea.appendChild(p);
}
4、查看历史消息。
a. 在LocalStorage中保存历史消息:
// 保存历史消息列表
let historyList = JSON.parse(localStorage.getItem('historyList')) || [];// 在按钮点击事件中将当前的录音数据添加到LocalStorage中
function handleStopRecording() {// ...reader.onloadend = () => {const audioBase64 = reader.result.split(',')[1];// 将录制好的音频数据上传到服务器进行处理,并在处理完成后将结果展示在前端postAudioDataToServer(audioBase64);// 将音频数据添加到历史记录中historyList.push({ audio: audioBase64 });localStorage.setItem('historyList', JSON.stringify(historyList));}
}
或者:
function sendRecord() {recorder.stop();const audioBlob = new Blob(chunks, { type: 'audio/wav' });const formData = new FormData();formData.append('audio', audioBlob);fetch('/api/asr', {method: 'POST',body: formData}).then(response => response.json()).then(result => {// 将识别结果展示为文字}).catch(error => console.error(error));
}
b. 在前端页面上显示历史消息列表:
可以在页面中添加一个历史消息列表,通过查询localStorage获取历史消息数据,并将数据展示在列表中。可以在每条历史消息旁边添加一个删除按钮,点击删除按钮可以将该条历史消息从localStorage删除。
// 渲染历史记录列表在页面上
function renderHistoryList() {const historyList = JSON.parse(localStorage.getItem('historyList')) || [];const historyListArea = document.getElementById('history-list');historyListArea.innerHTML = '';if (historyList.length > 0) {historyList.forEach((item, idx) => {const li = document.createElement('li');const deleteBtn = document.createElement('button');deleteBtn.innerText = 'Delete';// 点击删除按钮,从LocalStorage中删除对应的历史记录deleteBtn.addEventListener('click', () => {historyList.splice(idx, 1);localStorage.setItem('historyList', JSON.stringify(historyList));renderHistoryList();});li.appendChild(deleteBtn);historyListArea.appendChild(li);});} else {historyListArea.innerHTML = '没有历史记录';}
}// 初始化页面时渲染历史记录
renderHistoryList();
c. 在前端页面上展示历史记录并且提供删除功能。(代码在b步骤中已经给出了)。
三、延伸:前端H5实现调用麦克风,录音功能
我们可以通过Web Audio API以及Navigator.mediaDevices.getUserMedia()方法来实现。
下面是一个简单的实现流程:
1. 首先,我们需要请求用户授权使用麦克风。调用Navigator.mediaDevices.getUserMedia()方法即可。在授权成功后,可以通过回调函数来获取到用户的音频输入流。
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(stream => {console.log('获取到麦克风输入流,可以进行录音操作');}).catch(error => {console.log('获取麦克风输入流失败', error);});
2. 通过获取到的音频输入流,我们可以创建一个MediaRecorder对象,用于进行录音操作。MediaRecorder对象支持多种不同的配置选项,可以根据实际需要进行设置。
let recorder = null;navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(stream => {recorder = new MediaRecorder(stream, {mimeType: 'audio/webm;codecs=opus',audioBitsPerSecond: 128000,videoBitsPerSecond: null,});console.log('获取到麦克风输入流,可以进行录音操作');}).catch(error => {console.log('获取麦克风输入流失败', error);});
3. 开始录音:通过调用MediaRecorder对象的start()方法来开始录音。同时通过start()方法的参数可以设置录音的时长限制。
// 开始录音
recorder.start();
4. 停止录音:调用MediaRecorder对象的stop()方法停止录音。在停止录音之后,可以通过ondataavailable事件来获取录音的数据,这里的数据是一个Blob类型的对象。
// 停止录音
recorder.stop();// 获取录音数据
recorder.ondataavailable = (e) => {const audioBlob = e.data;// 这里可以上传录音数据等操作
};
在获取到录音数据之后,我们就可以进行 上传 等其他操作。上传数据可以使用XMLHttpRequest、fetch等常用的浏览器API进行处理。
需要注意的是,由于不同的浏览器可能存在兼容性问题,所以在开发过程中需要进行
兼容性测试。
同时,为了避免产生大量无用的录音数据占用用户空间,可以在录音数据被上传至服务器之后尽早地删除掉该数据。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
