news 2026/4/15 11:15:57

基于Qwen3-ASR-1.7B的会议记录系统:Vue3前端与Node.js后端整合

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于Qwen3-ASR-1.7B的会议记录系统:Vue3前端与Node.js后端整合

基于Qwen3-ASR-1.7B的会议记录系统:Vue3前端与Node.js后端整合

每次开完会,你是不是也经常对着录音文件发愁?从头到尾听一遍,再手动整理成文字,一两个小时就这么没了。要是会议内容再复杂点,人名、专业术语满天飞,那整理起来更是让人头疼。

现在,很多团队开始尝试用语音识别技术来解决这个问题。但市面上的通用识别工具,往往对会议场景下的多人对话、专业词汇、口语化表达支持得不够好,识别出来的文字需要大量人工校对,效率提升有限。

最近,我们团队基于Qwen3-ASR-1.7B这个专门优化的语音识别模型,结合Vue3和Node.js,搭建了一套智能会议记录系统。它不仅能实时把语音转成文字,还能在网页上同步显示,会后一键导出整理好的记录。用下来感觉,对于日常的团队会议、项目讨论,能节省不少时间。

这篇文章,我就来分享一下我们是怎么做的,把前端界面、后端服务以及语音识别的整合过程,用大白话讲清楚。如果你也想给团队弄个类似的工具,或许能给你一些参考。

1. 这个系统能解决什么问题?

在动手之前,我们先看看传统会议记录有哪些麻烦,以及我们想用技术解决哪些点。

首先,是效率问题。一场一小时的会议,人工回听、整理、润色,至少需要两到三个小时。如果会议频繁,这块的时间成本就非常可观。

其次,是准确性和一致性问题。不同的人做记录,重点可能不同,风格也可能不一样。有时候还会漏掉一些关键讨论点或者决策。用语音识别来转写,至少能保证“原汁原味”地记录下所有发言内容。

再者,是实时性的需求。有些会议,比如线上评审会,参会人员可能希望实时看到识别出的文字,方便确认或即时补充。这比会后发一份文档的体验要好得多。

最后,是定制化的需求。每个公司、每个团队都有自己的“黑话”、产品名、技术术语。通用的识别模型在这些专有名词上很容易“翻车”。Qwen3-ASR-1.7B这类模型的好处是,它有一定的“学习”能力,我们可以用自己领域的少量数据去微调它,让它更懂我们的话。

所以,我们这套系统的目标就很明确了:做一个能实时转写、准确率较高(特别是对专业词汇)、并且用起来很方便的网页版会议记录工具。前端用Vue3是因为它开发现代化、生态好,做复杂交互比较顺手;后端用Node.js,看中它处理I/O密集型任务(比如音频流)的天然优势;核心的识别能力,则交给Qwen3-ASR-1.7B模型。

2. 系统是怎么工作的?

整个系统跑起来,大概是这么个流程,我画个简单的图可能更直观:

用户说话 (麦克风) -> Vue3前端 (采集音频流,简单处理) -> Node.js后端 (接收音频数据块) -> Qwen3-ASR-1.7B模型 (将音频转为文字) -> Node.js后端 (整理识别结果) -> Vue3前端 (实时显示文字,并存储)

前端(Vue3)主要负责两件事:

  1. 音频采集与发送:利用浏览器的Web Audio APIgetUserMedia,获取用户的麦克风输入。这里不是等用户录完一整段再发送,而是将音频数据切成一小块一小块(比如每1秒或每2秒),通过WebSocket源源不断地发送给后端。这样做的好处是延迟低,能实现“准实时”的转写效果。
  2. 结果展示与交互:接收后端返回的文字,并像聊天软件一样,一行行地显示在网页上。同时,还要提供一些控制按钮,比如开始/停止录音、标记发言人、插入时间戳、导出文本等。

后端(Node.js + Express/Socket.io)也主要负责两件事:

  1. 通信枢纽:建立WebSocket服务,稳定地接收前端发来的音频数据块,并将模型识别出的文字结果推送给前端。用WebSocket而不是普通的HTTP请求,就是为了满足这种双向、持续的数据流需求。
  2. 模型调度与处理:它是连接前端和AI模型的桥梁。它把收到的音频数据整理成模型需要的格式,调用Qwen3-ASR-1.7B模型进行识别,然后把识别出的文本稍作处理(比如加上时间戳、合并句子),再发回前端。

核心(Qwen3-ASR-1.7B):这就是系统的“大脑”,一个专门用于自动语音识别的AI模型。它的任务很单纯:给你一段音频,它告诉你这段音频里说了什么话。我们选择1.7B这个版本,是在精度和推理速度之间做了一个平衡,让它能在普通的服务器上比较快地跑起来。

3. 前端Vue3部分:打造实时录音界面

前端我们用的是Vue 3和Composition API,代码结构会更清晰。这里我挑几个关键部分说说。

3.1 核心状态与音频处理

首先,我们需要一些状态来管理整个录音过程:

<script setup> import { ref, reactive } from 'vue'; import { useWebSocket } from './composables/useWebSocket'; // 假设我们封装了WebSocket逻辑 // 核心状态 const isRecording = ref(false); const transcriptText = ref(''); // 存放识别出的全部文本 const realtimeText = ref(''); // 存放当前正在识别的片段 const audioChunks = reactive([]); // 存放采集的音频数据块(用于调试或备选方案) // 初始化WebSocket连接 const { sendAudioChunk, closeConnection } = useWebSocket({ onMessage: (data) => { // 收到后端推送的识别结果 if (data.type === 'partial') { // 中间结果,还在识别当前这句话 realtimeText.value = data.text; } else if (data.type === 'final') { // 最终结果,当前这句话识别完毕 transcriptText.value += data.text + '\n'; realtimeText.value = ''; // 清空实时显示 } }, onError: (error) => { console.error('WebSocket错误:', error); } }); </script>

3.2 录音控制逻辑

接下来是控制录音开始和停止的逻辑。我们使用浏览器的MediaRecorderAPI,它相对简单易用。

<script setup> // ... 上面的状态定义 let mediaRecorder = null; let audioStream = null; const startRecording = async () => { try { // 1. 获取麦克风权限和音频流 audioStream = await navigator.mediaDevices.getUserMedia({ audio: true }); // 2. 创建MediaRecorder实例,设置音频参数(这里用WebM格式,opus编码) const options = { mimeType: 'audio/webm;codecs=opus' }; mediaRecorder = new MediaRecorder(audioStream, options); // 3. 监听数据可用事件,当有音频数据块产生时 mediaRecorder.ondataavailable = (event) => { if (event.data.size > 0) { // 将Blob数据发送到后端 sendAudioChunk(event.data); } }; // 4. 启动录音,每1000毫秒(1秒)生成一个数据块 mediaRecorder.start(1000); isRecording.value = true; console.log('录音已开始'); } catch (err) { console.error('无法访问麦克风或启动录音:', err); alert('请确保已授予麦克风权限。'); } }; const stopRecording = () => { if (mediaRecorder && isRecording.value) { mediaRecorder.stop(); // 停止录音 mediaRecorder.stream.getTracks().forEach(track => track.stop()); // 关闭音频轨道 mediaRecorder = null; audioStream = null; isRecording.value = false; closeConnection(); // 关闭WebSocket连接 console.log('录音已停止'); } }; </script>

3.3 界面展示

界面部分就比较直观了,主要是展示识别结果和一些控制按钮。

<template> <div class="meeting-recorder"> <h1>智能会议记录系统</h1> <div class="control-panel"> <button @click="startRecording" :disabled="isRecording" class="btn btn-start" > 🎤 开始录音 </button> <button @click="stopRecording" :disabled="!isRecording" class="btn btn-stop" > ⏹ 停止录音 </button> <button @click="exportText" :disabled="transcriptText.length === 0" class="btn btn-export" > 导出文本 </button> </div> <div class="transcript-container"> <h2>会议记录</h2> <div class="final-text"> <pre>{{ transcriptText }}</pre> </div> <!-- 实时识别区域,显示当前正在说的话 --> <div v-if="realtimeText" class="realtime-text"> <strong>正在识别:</strong> {{ realtimeText }} </div> </div> </div> </template> <script setup> // ... 之前的脚本逻辑 const exportText = () => { const blob = new Blob([transcriptText.value], { type: 'text/plain' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `会议记录_${new Date().toLocaleString()}.txt`; link.click(); }; </script>

这样,一个最基本的前端录音和展示界面就搭好了。用户点击开始,网页就会请求麦克风权限,然后一边录音一边把数据发往后端,并实时显示识别回来的文字。

4. 后端Node.js部分:连接前端与AI模型

后端服务我们使用Node.js的Express框架来提供HTTP接口,并用ws库或者socket.io来处理WebSocket连接。这里为了清晰,我用socket.io来举例,因为它对房间、广播等高级功能支持得更好,适合未来扩展多人会议场景。

4.1 项目初始化与依赖

首先,创建一个新的Node.js项目,并安装必要的依赖:

npm init -y npm install express socket.io cors # 假设我们有封装好的Qwen3-ASR模型调用SDK npm install @my-org/qwen3-asr-client

4.2 WebSocket服务与音频接收

创建主服务文件server.js

const express = require('express'); const http = require('http'); const { Server } = require('socket.io'); const cors = require('cors'); const { transcribeAudio } = require('./asrService'); // 封装的模型调用函数 const app = express(); app.use(cors()); const server = http.createServer(app); // 初始化Socket.io,允许前端连接 const io = new Server(server, { cors: { origin: "http://localhost:5173", // 你的Vue开发服务器地址 methods: ["GET", "POST"] } }); // 存储每个socket连接对应的状态或缓冲区(如果需要) const sessionMap = new Map(); io.on('connection', (socket) => { console.log('客户端已连接:', socket.id); // 为这个连接初始化一个音频缓冲区(如果需要累积一定数据再识别) sessionMap.set(socket.id, { audioBuffer: [], }); // 监听前端发送的音频数据块 socket.on('audio_chunk', async (chunkData) => { try { // chunkData 可能是Base64字符串,也可能是ArrayBuffer,取决于前端怎么传 // 这里假设前端发送的是ArrayBuffer const audioBuffer = Buffer.from(chunkData); // 调用语音识别服务 const result = await transcribeAudio(audioBuffer); // 将识别结果发送回这个特定的客户端 // 这里简单处理,实际可以根据模型返回的中间/最终结果来区分发送 socket.emit('transcript', { type: 'final', // 或 'partial' text: result.text, isFinal: result.isFinal }); } catch (error) { console.error(`处理音频数据出错 (socket: ${socket.id}):`, error); socket.emit('error', { message: '语音识别处理失败' }); } }); // 监听断开连接 socket.on('disconnect', () => { console.log('客户端断开连接:', socket.id); sessionMap.delete(socket.id); }); }); // 启动HTTP服务器,也可以提供一些健康检查接口 app.get('/health', (req, res) => { res.json({ status: 'ok', service: 'meeting-asr-backend' }); }); const PORT = process.env.PORT || 3000; server.listen(PORT, () => { console.log(`后端服务运行在 http://localhost:${PORT}`); });

4.3 集成Qwen3-ASR-1.7B模型

最核心的部分来了,就是怎么调用Qwen3-ASR模型。这部分代码我们封装在asrService.js里。具体调用方式取决于模型是如何部署的(本地部署还是调用远程API)。

假设模型以HTTP API形式提供服务(例如部署在另一台GPU服务器上):

// asrService.js const axios = require('axios'); // 配置模型服务的地址 const ASR_API_URL = process.env.ASR_API_URL || 'http://your-asr-server:8000/v1/transcribe'; async function transcribeAudio(audioBuffer) { try { // 将音频Buffer转换为模型API接受的格式,例如FormData或Base64 // 这里假设API接受multipart/form-data格式的音频文件 const formData = new FormData(); // 注意:Node.js环境原生的FormData可能不同,这里用`form-data`库更佳,此处为示意 const blob = new Blob([audioBuffer], { type: 'audio/webm' }); formData.append('audio', blob, 'chunk.webm'); formData.append('model', 'qwen3-asr-1.7b'); formData.append('language', 'zh'); // 指定中文 const response = await axios.post(ASR_API_URL, formData, { headers: { ...formData.getHeaders(), // 如果使用`form-data`库 'Accept': 'application/json', }, timeout: 10000, // 10秒超时 }); // 假设API返回 { text: "识别出的文字", is_final: true } return { text: response.data.text, isFinal: response.data.is_final !== false, }; } catch (error) { console.error('调用ASR API失败:', error.message); throw new Error(`语音识别服务异常: ${error.message}`); } } module.exports = { transcribeAudio };

如果模型是直接加载在本地Node.js进程里,那调用方式会更直接,但需要处理模型加载、GPU内存等更复杂的问题。这里就不展开了,通常更推荐用独立的API服务来承载模型推理。

5. 实际跑起来看看效果

把前后端代码都准备好之后,分别启动它们。

  1. 启动后端:在终端进入后端目录,运行node server.js
  2. 启动前端:在终端进入前端目录,运行npm run dev(假设使用Vite)。

打开浏览器,访问前端地址(如http://localhost:5173)。点击“开始录音”按钮,允许网页使用麦克风。然后你就可以对着麦克风说话了,比如:

“大家好,我们开始本周的项目例会。首先回顾一下上周的进度,前端完成了用户登录模块的Vue3组件重构,后端接口也已经联调通过。”

很快,你应该能在网页上看到识别出的文字一行行地出现。虽然可能有些标点符号不太准,或者个别词有误差,但整体的意思已经非常清楚了。停止录音后,点击“导出文本”,就能得到一份完整的文字记录。

我们试了一下,对于普通话比较标准的会议讨论,这个系统的识别准确率还是挺不错的。特别是如果我们提前用一些项目相关的文档、术语列表去微调一下Qwen3-ASR模型,那它在专业词汇上的表现会更好。

6. 总结

折腾这么一圈下来,感觉用现代Web技术(Vue3 + Node.js)去整合一个像Qwen3-ASR这样的AI模型,并没有想象中那么难。核心思路就是前端负责采集和展示,后端负责调度和通信,AI模型负责最核心的智能处理

这套方案的优势在于:

  • 实时性好:WebSocket让文字几乎能跟着语音同步出来,体验很流畅。
  • 部署相对灵活:前端是静态页面,可以随便放;后端和AI模型可以分开部署,根据压力扩容。
  • 有一定定制潜力:Qwen3-ASR模型支持微调,这意味着我们可以让它越来越贴合自己公司的语言环境。

当然,现在这只是一个最基础的版本。真要放到生产环境给团队用,还有很多可以打磨的地方,比如:

  • 区分说话人:如果能结合声纹识别,自动区分“谁在说话”,记录就更清晰了。
  • 智能摘要:会后让大模型自动提炼会议纪要和待办事项。
  • 多人会议支持:扩展后端,让多个人的录音能同步到同一个会议记录中。
  • 错误处理和重试机制:网络不好或者模型服务暂时不可用时,要有更友好的应对。

不过,作为第一步,这个能跑通的系统已经能解决“快速把会议录音变成文字”这个核心痛点了。如果你也有类似的需求,不妨也动手试试,从最简单的版本开始,再慢慢加上你想要的功能。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 11:14:22

CrystalDiskInfo硬盘健康监控工具全攻略:从预警到维护的完整指南

CrystalDiskInfo硬盘健康监控工具全攻略&#xff1a;从预警到维护的完整指南 【免费下载链接】CrystalDiskInfo CrystalDiskInfo 项目地址: https://gitcode.com/gh_mirrors/cr/CrystalDiskInfo 当你正在处理重要项目时&#xff0c;电脑突然蓝屏&#xff1b;当你准备保存…

作者头像 李华
网站建设 2026/4/8 9:48:21

nlp_gte_sentence-embedding_chinese-large在舆情监控中的应用实践

nlp_gte_sentence-embedding_chinese-large在舆情监控中的应用实践 1. 为什么舆情监控需要更懂中文的向量模型 做舆情监控的朋友可能都遇到过这样的情况&#xff1a;系统每天抓取上万条社交媒体评论、新闻报道和论坛帖子&#xff0c;但真正能帮业务决策的关键信息却像大海捞针…

作者头像 李华
网站建设 2026/4/15 10:00:09

translategemma-4b-it架构揭秘:2K上下文窗口与256图token的设计逻辑

translategemma-4b-it架构揭秘&#xff1a;2K上下文窗口与256图token的设计逻辑 1. 模型架构解析 1.1 核心设计理念 translategemma-4b-it作为Google基于Gemma 3构建的轻量级翻译模型&#xff0c;其架构设计体现了几个关键理念。首先是效率优先&#xff0c;4B参数规模在保证…

作者头像 李华
网站建设 2026/3/27 12:06:41

零成本实现云盘与播放器直连:2024实测全攻略

零成本实现云盘与播放器直连&#xff1a;2024实测全攻略 【免费下载链接】115proxy-for-kodi 115原码播放服务Kodi插件 项目地址: https://gitcode.com/gh_mirrors/11/115proxy-for-kodi 为什么90%的电视用户都在做错这件事&#xff1f;他们花费数千元购买高端智能电视&…

作者头像 李华
网站建设 2026/4/12 8:20:17

4个步骤解决FanControl传感器检测失败 - 2026最新方案

4个步骤解决FanControl传感器检测失败 - 2026最新方案 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/FanControl…

作者头像 李华