当前位置: 首页 > article >正文

Vue2项目实战:用js-audio-recorder和阿里云WebSocket搞定网页录音转文字(附完整代码)

Vue2实战基于js-audio-recorder与阿里云WebSocket的语音转文字解决方案在当今的Web应用中语音交互功能正变得越来越普遍。无论是语音输入、实时字幕还是语音助手将语音转换为文字的需求日益增长。本文将带你从零开始在Vue2项目中实现一个完整的网页录音转文字功能使用js-audio-recorder处理录音并通过阿里云智能语音服务的WebSocket接口实现实时语音识别。1. 项目准备与环境配置在开始编码前我们需要准备好开发环境和必要的服务账号。这个项目主要依赖以下几个关键组件Vue2作为前端框架js-audio-recorder用于网页录音的JavaScript库阿里云智能语音交互服务提供语音转文字的核心能力首先创建一个新的Vue2项目如果已有项目可跳过此步vue create voice-to-text-demo cd voice-to-text-demo然后安装项目所需依赖npm install js-audio-recorder element-ui --save提示Element UI是可选的这里用它提供美观的UI组件。你也可以使用其他UI库或原生HTML元素。接下来需要在阿里云开通智能语音交互服务登录阿里云控制台搜索智能语音交互开通服务并创建项目获取AppKey和AccessKey用于生成Token2. 录音功能实现js-audio-recorder是一个轻量级的网页录音库支持多种音频格式和配置选项。我们先实现基本的录音功能。在Vue组件中引入并初始化录音器import Recorder from js-audio-recorder export default { data() { return { recorder: null, isRecording: false, audioBlob: null } }, methods: { initRecorder() { this.recorder new Recorder({ sampleBits: 16, // 采样位数 sampleRate: 16000, // 采样率阿里云推荐16kHz numChannels: 1 // 单声道 }) }, async startRecording() { try { await Recorder.getPermission() // 获取麦克风权限 this.recorder.start() this.isRecording true } catch (error) { console.error(录音权限获取失败:, error) } }, stopRecording() { this.recorder.stop() this.isRecording false this.audioBlob this.recorder.getPCMBlob() // 获取PCM格式音频数据 } }, mounted() { this.initRecorder() } }在模板中添加简单的控制界面template div el-button typeprimary clickstartRecording :disabledisRecording 开始录音 /el-button el-button clickstopRecording :disabled!isRecording 停止录音 /el-button /div /template注意阿里云语音识别服务要求音频为16位采样位数、16kHz采样率的单声道PCM格式。上述配置已符合这些要求。3. 阿里云WebSocket连接管理阿里云智能语音交互服务提供了WebSocket接口可以实现实时语音识别。我们需要建立并维护WebSocket连接处理各种状态和消息。首先创建一个工具类来管理WebSocket连接// utils/aliyunSpeech.js export default class AliyunSpeech { constructor(options) { this.token options.token this.appKey options.appKey this.onTextReceived options.onTextReceived this.onError options.onError this.ws null this.taskId this.generateUUID() } connect() { const wsUrl wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1?token${this.token} this.ws new WebSocket(wsUrl) this.ws.onopen () this.handleOpen() this.ws.onmessage (e) this.handleMessage(e) this.ws.onerror (e) this.onError(e) this.ws.onclose (e) this.handleClose(e) } handleOpen() { const startMessage { header: { message_id: this.generateUUID(), task_id: this.taskId, namespace: SpeechTranscriber, name: StartTranscription, appkey: this.appKey }, payload: { format: PCM, sample_rate: 16000, enable_intermediate_result: true, enable_punctuation_prediction: true, enable_inverse_text_normalization: true } } this.sendMessage(startMessage) } handleMessage(e) { const data JSON.parse(e.data) const { name } data.header if (name TranscriptionResultChanged) { this.onTextReceived(data.payload.result) } else if (name SentenceEnd) { this.onTextReceived(data.payload.result \n) } } sendAudio(audioData) { if (this.ws this.ws.readyState WebSocket.OPEN) { this.ws.send(audioData) } } sendStopCommand() { const stopMessage { header: { message_id: this.generateUUID(), task_id: this.taskId, namespace: SpeechTranscriber, name: StopTranscription, appkey: this.appKey } } this.sendMessage(stopMessage) } sendMessage(message) { if (this.ws this.ws.readyState WebSocket.OPEN) { this.ws.send(JSON.stringify(message)) } } generateUUID() { return xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx.replace(/[xy]/g, function(c) { const r Math.random() * 16 | 0 const v c x ? r : (r 0x3 | 0x8) return v.toString(16) }) } close() { if (this.ws) { this.ws.close() } } }4. 音频数据处理与发送从麦克风获取的音频数据需要经过适当处理才能发送给阿里云服务。主要考虑以下几点数据分片大块音频数据需要分成小片发送格式转换确保数据格式符合服务要求时序控制合理控制发送间隔在Vue组件中集成音频发送逻辑export default { data() { return { speechClient: null, recognitionText: , isProcessing: false } }, methods: { initSpeechClient() { this.speechClient new AliyunSpeech({ token: your-aliyun-token, // 应从后端获取 appKey: your-app-key, onTextReceived: (text) { this.recognitionText text }, onError: (error) { console.error(语音识别错误:, error) } }) }, async sendAudioToRecognize() { if (!this.audioBlob) return this.isProcessing true this.recognitionText this.speechClient.connect() // 等待连接建立 await new Promise(resolve setTimeout(resolve, 500)) // 分片发送音频数据 const chunkSize 3200 // 阿里云推荐的分片大小 const blobReader new FileReader() blobReader.onload () { const audioArrayBuffer blobReader.result const audioData new Uint8Array(audioArrayBuffer) for (let i 0; i audioData.length; i chunkSize) { const chunk audioData.slice(i, i chunkSize) this.speechClient.sendAudio(chunk) } this.speechClient.sendStopCommand() this.isProcessing false } blobReader.readAsArrayBuffer(this.audioBlob) } }, mounted() { this.initRecorder() this.initSpeechClient() } }5. 完整实现与优化现在我们将所有部分整合起来并添加一些优化措施Token动态获取Token应该从后端获取避免在前端暴露敏感信息连接状态管理处理WebSocket的各种状态变化错误处理增强错误处理和用户反馈UI优化提供更好的用户体验完整组件代码template div classvoice-recognition-container el-card shadowhover div slotheader span语音转文字演示/span /div div classcontrol-panel el-button typeprimary clickstartRecording :disabledisRecording || isProcessing iconel-icon-microphone 开始录音 /el-button el-button clickstopRecording :disabled!isRecording iconel-icon-video-pause 停止录音 /el-button el-button clicksendAudioToRecognize :disabled!audioBlob || isProcessing iconel-icon-upload2 识别语音 /el-button /div div classstatus-info el-alert :titlestatusMessage :typestatusType :closablefalse show-icon / /div div classresult-container el-input typetextarea :rows8 placeholder识别结果将显示在这里... v-modelrecognitionText readonly / /div /el-card /div /template script import Recorder from js-audio-recorder import AliyunSpeech from /utils/aliyunSpeech export default { data() { return { recorder: null, isRecording: false, audioBlob: null, speechClient: null, recognitionText: , isProcessing: false, status: idle // idle, recording, processing, success, error } }, computed: { statusMessage() { const messages { idle: 准备就绪点击开始录音按钮开始, recording: 正在录音... 点击停止录音按钮结束, processing: 正在识别语音..., success: 识别完成, error: 发生错误请重试 } return messages[this.status] || }, statusType() { const types { idle: info, recording: warning, processing: info, success: success, error: error } return types[this.status] || info } }, methods: { initRecorder() { this.recorder new Recorder({ sampleBits: 16, sampleRate: 16000, numChannels: 1 }) }, async startRecording() { try { this.status recording this.recognitionText await Recorder.getPermission() this.recorder.start() this.isRecording true } catch (error) { console.error(录音权限获取失败:, error) this.status error this.$message.error(无法获取麦克风权限) } }, stopRecording() { this.recorder.stop() this.isRecording false this.audioBlob this.recorder.getPCMBlob() this.status idle }, initSpeechClient() { // 实际项目中应从后端API获取token和appKey this.getTokenAndAppKey().then(({ token, appKey }) { this.speechClient new AliyunSpeech({ token, appKey, onTextReceived: (text) { this.recognitionText text }, onError: (error) { console.error(语音识别错误:, error) this.status error this.isProcessing false this.$message.error(语音识别失败) } }) }) }, async getTokenAndAppKey() { // 这里应该是调用后端API获取token和appKey // 模拟API调用 return new Promise(resolve { setTimeout(() { resolve({ token: your-token-from-backend, appKey: your-app-key-from-backend }) }, 300) }) }, async sendAudioToRecognize() { if (!this.audioBlob) return this.status processing this.isProcessing true this.recognitionText try { this.speechClient.connect() // 等待连接建立 await new Promise((resolve, reject) { const checkInterval setInterval(() { if (this.speechClient.ws this.speechClient.ws.readyState WebSocket.OPEN) { clearInterval(checkInterval) resolve() } }, 100) setTimeout(() { clearInterval(checkInterval) reject(new Error(连接超时)) }, 3000) }) // 分片发送音频数据 const chunkSize 3200 await new Promise((resolve) { const blobReader new FileReader() blobReader.onload () { const audioArrayBuffer blobReader.result const audioData new Uint8Array(audioArrayBuffer) let index 0 const sendNextChunk () { if (index audioData.length) { this.speechClient.sendStopCommand() this.status success this.isProcessing false resolve() return } const chunk audioData.slice(index, index chunkSize) this.speechClient.sendAudio(chunk) index chunkSize // 控制发送速率 setTimeout(sendNextChunk, 30) } sendNextChunk() } blobReader.readAsArrayBuffer(this.audioBlob) }) } catch (error) { console.error(识别过程中出错:, error) this.status error this.isProcessing false this.$message.error(语音识别失败) } } }, mounted() { this.initRecorder() this.initSpeechClient() }, beforeDestroy() { if (this.speechClient) { this.speechClient.close() } } } /script style scoped .voice-recognition-container { max-width: 800px; margin: 0 auto; padding: 20px; } .control-panel { margin-bottom: 20px; } .control-panel button { margin-right: 10px; } .status-info { margin-bottom: 20px; } .result-container { margin-top: 20px; } /style6. 常见问题与解决方案在实际开发中你可能会遇到以下问题权限问题浏览器麦克风权限被拒绝解决方案在用户交互事件中请求权限如点击按钮并提供清晰的权限请求说明音频格式不匹配阿里云服务对音频格式有严格要求确保使用PCM格式、16kHz采样率、16位采样位数、单声道WebSocket连接不稳定网络问题可能导致连接中断实现重连机制监听onclose事件并尝试重新连接分片大小问题过大的分片可能导致识别延迟阿里云推荐分片大小为1600或3200字节Token过期阿里云Token通常有有效期限制实现Token刷新机制或在每次识别前获取新Token跨域问题本地开发时可能遇到跨域限制配置开发服务器代理或使用后端API中转WebSocket连接7. 性能优化与扩展为了使这个语音识别功能更加完善可以考虑以下优化和扩展方向实时语音识别修改录音逻辑边录音边发送数据实现真正的实时识别多语言支持利用阿里云服务支持的多语言识别能力语音唤醒添加关键词唤醒功能离线支持使用WebAssembly实现本地基础语音识别语音指令结合NLP处理识别结果实现语音控制功能音频可视化添加音频波形显示提升用户体验实时语音识别的实现思路// 修改录音开始方法 async startRealTimeRecording() { await Recorder.getPermission() this.speechClient.connect() // 边录音边处理 this.recorder.onprogress (params) { const chunk this.recorder.getNextData() if (chunk this.speechClient) { this.speechClient.sendAudio(chunk) } } this.recorder.start() this.isRecording true }在真实项目中这种语音识别功能可以应用于多种场景在线会议实时字幕、语音笔记、语音搜索、无障碍访问等。关键在于根据具体需求调整参数和优化用户体验。

相关文章:

Vue2项目实战:用js-audio-recorder和阿里云WebSocket搞定网页录音转文字(附完整代码)

Vue2实战:基于js-audio-recorder与阿里云WebSocket的语音转文字解决方案 在当今的Web应用中,语音交互功能正变得越来越普遍。无论是语音输入、实时字幕还是语音助手,将语音转换为文字的需求日益增长。本文将带你从零开始,在Vue2项…...

Qwen3-VL-4B Pro快速部署指南:开箱即用的视觉语言模型,看图说话超简单

Qwen3-VL-4B Pro快速部署指南:开箱即用的视觉语言模型,看图说话超简单 1. 项目简介与核心价值 Qwen3-VL-4B Pro是基于阿里通义千问团队开发的Qwen/Qwen3-VL-4B-Instruct模型构建的视觉语言模型服务。相比轻量版的2B模型,4B版本在视觉语义理…...

15|Prompt 结构化:目标-上下文-约束-输出格式

本篇目标:这是卷 2(提示工程实战)的第一篇。我们将告别“聊天式提问”,学会像写代码一样写 Prompt,让 AI 的回答从“看运气”变成“稳定交付”。一、为什么你的 Prompt 总是不稳定? 很多人的提问方式是碎片…...

Python实战:用朴素贝叶斯分类器预测西瓜好坏(附完整代码)

Python实战:用朴素贝叶斯分类器预测西瓜品质的完整指南 在农产品质量检测领域,机器学习技术正发挥着越来越重要的作用。本文将带您从零开始,使用Python实现一个基于朴素贝叶斯算法的西瓜品质分类器。不同于简单的理论讲解,我们将聚…...

Nginx交叉编译实战:从Ubuntu20.04到ARM64 Linux的完整移植记录

Nginx交叉编译实战:从Ubuntu20.04到ARM64 Linux的完整移植记录 在嵌入式开发和边缘计算场景中,将高性能Web服务器Nginx移植到ARM64架构的需求日益增长。无论是物联网网关、智能摄像头还是工业控制设备,都需要轻量级但功能完整的Web服务能力。…...

无刷电机PWM控制实战:从占空比到转速曲线的完整测试记录

无刷电机PWM控制实战:从占空比到转速曲线的完整测试记录 去年夏天调试四轴飞行器时,我对着失控的电机发呆了整整三小时——明明PWM占空比已经调到0.08,电机却像喝醉似的时转时停。这次经历让我意识到,教科书上的理论曲线和实际电机…...

别再让大文件撑爆你的Git仓库了!手把手教你用Git LFS管理视频和数据集

别再让大文件撑爆你的Git仓库了!手把手教你用Git LFS管理视频和数据集 你是否经历过这样的场景:团队协作时,某个同事不小心把10GB的训练数据集推送到Git仓库,导致所有人git pull时卡在99%?或是发现.git目录悄悄吞噬了…...

告别经纬度模糊聚合!用Uber H3 Java库实现六边形地理网格的5个实战场景

告别经纬度模糊聚合!用Uber H3 Java库实现六边形地理网格的5个实战场景 当我们需要分析城市热力图或规划物流配送区域时,传统基于圆形或矩形的聚合方法常面临边界模糊、计算量大等问题。Uber开源的H3六边形网格系统,通过将地球表面划分为数百…...

移远EC600SCN-AA模组QuecPython开发环境搭建全攻略(含驱动+固件+工具链)

移远EC600SCN-AA模组QuecPython开发环境搭建实战指南 1. 硬件准备与驱动安装 在开始QuecPython开发之前,确保您已准备好以下硬件组件: 移远EC600SCN-AA模组开发板USB Type-C数据线(建议使用带屏蔽层的高质量线缆)稳定的5V/2A电源适…...

实测有效:ERNIE-4.5-0.3B镜像部署,Chainlit界面聊天体验分享

实测有效:ERNIE-4.5-0.3B镜像部署,Chainlit界面聊天体验分享 1. 开箱即用的ERNIE-4.5体验 最近在测试各种开源大语言模型时,发现百度ERNIE-4.5系列中的0.3B版本特别适合快速部署和体验。这个轻量级模型虽然参数规模不大,但在文本…...

FLAC3D结果太抽象?手把手教你用Tecplot做出期刊级云图(从导入到出图全流程)

FLAC3D结果太抽象?手把手教你用Tecplot做出期刊级云图(从导入到出图全流程) 在岩土工程数值模拟领域,FLAC3D作为行业标准工具,其计算结果的专业性和可靠性毋庸置疑。但许多研究者都面临一个共同痛点:软件自…...

ChatGLM3-6B在金融领域的应用:智能投顾与风险分析

ChatGLM3-6B在金融领域的应用:智能投顾与风险分析 1. 引言 金融行业每天都要处理海量的市场数据、公司财报和投资报告,传统的人工分析方法往往效率低下且容易出错。想象一下,一位投资经理需要同时分析几十家上市公司的季度财报,…...

针对开源开发者的GitHub钓鱼攻击与加密钱包窃取机制研究

摘要 随着开源软件生态系统的日益繁荣,针对开发者群体的定向网络攻击呈现出高度专业化与场景化的趋势。本文以2026年3月爆发的针对OpenClaw项目的GitHub钓鱼攻击为案例,深入剖析了攻击者如何利用社交工程学与代码混淆技术构建的完整攻击链条。研究表明&a…...

Linux内核内存管理:虚拟内存、伙伴系统与页表机制

1. Linux内核内存管理机制深度解析Linux内核的内存管理是操作系统最核心、最复杂的子系统之一。它不仅承担着物理内存资源的组织与调度任务,更通过虚拟内存抽象层为上层应用提供统一、安全、高效的内存访问接口。理解其设计思想与实现细节,对嵌入式系统开…...

ODD Platform:数据治理的开源技术实践

ODD Platform:数据治理的开源技术实践 【免费下载链接】odd-platform First open-source data discovery and observability platform. We make a life for data practitioners easy so you can focus on your business. 项目地址: https://gitcode.com/gh_mirror…...

el-dialog 弹窗多层嵌套后边框不显示问题

一、问题描述我的项目用的 vue3element-plus, 业务需要使用了多层嵌套的弹窗 el-dialog。然后就发生了上层的第二(三)层的 弹窗在第二次弹出时会显示不了边框的问题。其实,如果我们挪动底层弹窗的位置,然后再打开上层…...

漏洞扫描从入门到精通:3个技巧让你效率翻倍(附工具包)

漏洞扫描从入门到精通:3个技巧让你效率翻倍(附工具包) 漏洞扫描从入门到精通:3个技巧让你效率翻倍(附工具包) 🔍 漏洞扫描从入门到精通:3个技巧让你效率翻倍(附工具包&…...

探索改进型低电压穿越控制策略:光伏并网逆变器的关键突破

改进型低电压穿越控制策略(附带低穿新国标文件)1、限制直流母线过压和网侧过流的两级式三相光伏并网逆变器低电压穿越控制策略 光伏侧:PV板和Boost电路组成 逆变侧:LCL滤波器和电网 2、本仿真在传统两极式三相光伏并网逆变器低电压…...

5分钟搞定图像分类:通用物体识别ResNet18镜像实战体验

5分钟搞定图像分类:通用物体识别ResNet18镜像实战体验 1. 镜像核心能力速览 今天要介绍的「通用物体识别-ResNet18」镜像,是一个开箱即用的图像分类解决方案。基于PyTorch官方TorchVision库构建,它集成了经典的ResNet-18模型,能…...

别再为部署大模型发愁了!手把手教你用vLLM在双GPU上跑通secGpt14b(附完整命令解析)

双GPU实战:从零部署secGpt14b大模型的完整避坑指南 当开发者第一次尝试在本地服务器部署数十GB参数的大语言模型时,往往会遇到显存不足、并行计算配置复杂、API服务不稳定等典型问题。本文将以工业级推理框架vLLM为核心工具,通过双NVIDIA GPU…...

DS3232M高精度RTC芯片驱动开发与工业级时间同步实践

1. DS3232M高精度实时时钟芯片技术解析与嵌入式驱动开发实践1.1 芯片定位与工程价值DS3232M是Maxim Integrated(现属Analog Devices)推出的工业级IC接口实时时钟(RTC)芯片,其核心价值在于2 ppm温度补偿精度&#xff08…...

华为云Flexus云服务器X实战:5分钟快速部署jumpserver堡垒机(附安全组配置技巧)

华为云Flexus云服务器极速部署JumpServer堡垒机全指南 1. 为什么选择华为云Flexus部署JumpServer? 在当今多云混合架构盛行的时代,企业IT基础设施管理面临前所未有的复杂性。JumpServer作为一款开源的堡垒机解决方案,已经成为众多企业实现统一…...

小白也能懂:GME多模态向量-Qwen2-VL-2B搭建企业智能文档库

小白也能懂:GME多模态向量-Qwen2-VL-2B搭建企业智能文档库 1. 为什么企业需要智能文档库? 1.1 传统文档管理的痛点 想象一下这样的场景:你记得某个重要数据在一份PDF的第37页的图表里,但用关键词搜索怎么也找不到;或…...

如何把 OpenClaw 打造成家庭的智能中心

如何把 OpenClaw 打造成家庭的智能中心 过去几年里,智能家居的问题已经不再是“设备不够多”,而是系统之间缺少统一的大脑。扫地机器人、灯光、温湿度计、音箱、摄像头、财务系统、健康数据,各自都有 App,但它们很少形成一个稳定、…...

第二十四章:Python-Cartopy库进阶:动态地理数据可视化实战

1. 动态地理数据可视化的魅力 第一次看到气象卫星云图实时变化时,我就被动态地理数据的表现力震撼了。传统静态地图就像一张照片,而动态可视化更像是部纪录片——台风如何形成、交通流量如何变化、疫情如何扩散,这些时空演变过程通过CartopyM…...

本地AI画师养成记:Asian Beauty Z-Image Turbo从部署到创作全攻略

本地AI画师养成记:Asian Beauty Z-Image Turbo从部署到创作全攻略 想拥有一个完全听你指挥、永不疲倦、且审美在线的私人AI画师吗?特别是当你痴迷于东方美学,想生成独具韵味的古风美人、温婉的现代少女,或是充满故事感的东方场景…...

2026年3月23日:工业智能的“奇点”时刻与安全防线的重构——深度解析西门子全栈战略、OpenClaw安全危机与Golang实战防御

摘要: 2026年3月23日,星期一。这一天被业界视为人工智能发展史上的一个微小但关键的“奇点”。在北京,西门子科技大会以“全栈落地”宣告工业AI从概念走向现实;在网络安全前线,国家互联网应急中心(CNCERT)紧急发布《OpenClaw安全使用实践指南》,为狂飙突进的开源智能体…...

TwinCAT3 Modbus-TCP双端通信实战:从环境配置到寄存器操作

1. TwinCAT3与Modbus-TCP通信基础 工业自动化领域最让人头疼的就是设备间的通信问题。我刚开始接触TwinCAT3时,面对各种通信协议也是一头雾水。直到掌握了Modbus-TCP这个"万能翻译官",才发现原来不同设备之间的对话可以如此简单。Modbus-TCP就…...

新手也能上手,全场景通用一键生成论文工具,千笔AI VS 知文AI

还在为选题→大纲→初稿→文献→降重→查重→格式→答辩PPT的全流程焦头烂额?千笔AI以八大核心功能实现全流程一站式覆盖,从选题到答辩PPT生成全程护航,让论文写作从“耗时耗力”变成“高效规范”,真正实现“选题快、框架稳、修改…...

GLM-OCR与Matlab集成:科研图像中的数据自动提取与分析

GLM-OCR与Matlab集成:科研图像中的数据自动提取与分析 每次做实验,最头疼的是什么?对我来说,不是设计复杂的实验流程,也不是调试精密的仪器,而是处理完实验后,面对那一堆堆的图表截图、仪器读数…...