项目背景
在医疗信息系统的前端项目中,我们需要为 AI 助手模块实现语音交互和富文本展示功能。本文将重点分享语音转文字和Markdown 渲染两个核心功能的实现经验。
一、语音转文字功能实现
1.1 技术选型
经过调研对比,最终选择recorder-core作为录音库:
| 方案 | 优点 | 缺点 |
|---|---|---|
| 原生 MediaRecorder | 零依赖 | 不支持 MP3,格式受限 |
| recorder-core | 支持多种格式,轻量 | 需要额外加载编码器 |
| Web Audio API | 高度可控 | 复杂度高 |
1.2 核心实现
1.2.1 初始化配置
importRecorderfrom"recorder-core";import"recorder-core/src/engine/mp3";import"recorder-core/src/engine/mp3-engine";// 创建录音实例this.recorder=Recorder({type:"mp3",// 输出格式sampleRate:16000,// 采样率bitRate:128,// 比特率});1.2.2 录音流程控制
录音功能需要严格遵循open → start → stop的调用顺序:
// 打开录音设备(必须在用户交互中调用)this.recorder.open(()=>{// 打开成功this.recorder.start();},(msg,isUserNotAllow)=>{// 打开失败(权限问题或设备异常)if(isUserNotAllow){this.$message.error("请在浏览器设置中允许麦克风权限");}});// 停止录音并获取数据this.recorder.stop((blob,duration)=>{// blob 为 MP3 格式的二进制数据this.uploadRecording(blob);});关键注意事项:
open()方法是异步的,必须在回调中调用start()- 必须在用户交互事件(如点击)中触发,否则浏览器会阻止权限请求
1.2.3 文件上传与接口调用
asyncuploadRecording(mp3Blob){// 构建 FormDataconstformData=newFormData();formData.append("file",mp3Blob,"recording.mp3");// 上传文件constuploadResponse=awaituploadFileApi(formData);constaudioUrl=uploadResponse.data[0].fullUrl;// 调用语音转文字接口constrecognizeResponse=awaitflashRecognizer({audioUrl:audioUrl,chatId:Date.now().toString()});// 将结果显示在输入框this.inputMessage=recognizeResponse.data.text;}1.3 常见问题与解决方案
| 问题 | 原因 | 解决方案 |
|---|---|---|
start失败:未open | 调用顺序错误 | 在open()回调中调用start() |
未加载mp3编码器 | 缺少编码器文件 | 引入mp3-engine模块 |
| 录音无声音 | 权限未授予 | 添加权限请求提示 |
二、Markdown 渲染方案
2.1 方案对比与选择
在实现过程中,我们尝试了三种不同的方案:
方案一:自定义正则解析
formatContent(content){// 处理加粗lethtml=content.replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>");// 处理换行html=html.replace(/\n/g,"<br>");// ... 更多规则returnhtml;}优点:零依赖,轻量
缺点:需要维护大量正则,不支持复杂格式(如表格)
方案二:使用 marked 库
npminstallmarked@4.3.0import{marked}from"marked";formatContent(content){returnmarked(content);}问题:Vue2 项目的 webpack 配置不支持 ES Module,导致编译错误
方案三:使用 vue-markdown 组件(最终选择)
npminstallvue-markdown<template><divclass="ai-content"><vue-markdown:source="content"></vue-markdown></div></template><script>importVueMarkdownfrom"vue-markdown";exportdefault{components:{VueMarkdown},}</script>优点:专为 Vue 设计,开箱即用,支持完整 Markdown 语法
2.2 样式定制
为了适配项目的 UI 风格,需要对 vue-markdown 生成的标签进行样式覆盖:
.ai-content{line-height:1.8;}/* 标题样式 */.ai-content h1, .ai-content h2, .ai-content h3, .ai-content h4, .ai-content h5, .ai-content h6{margin:2px 0;font-weight:600;}2.3 支持的 Markdown 格式
| 语法 | 效果 |
|---|---|
**加粗** | 加粗文本 |
*斜体* | 斜体文本 |
- 列表项 | 无序列表 |
1. 列表项 | 有序列表 |
--- | 分隔线 |
|表头||内容| | 表格 |
`代码` | 行内代码 |
三、功能整合与交互设计
3.1 界面布局
3.2 状态管理
data(){return{chatId:"",// 会话IDmessages:[],// 消息列表inputMessage:"",// 输入内容loading:false,// 发送loadingisRecording:false,// 录音状态recordingLoading:false,// 录音处理loading};}3.3 交互流程
用户点击录音 → 权限请求 → 开始录音(isRecording=true) ↓ 用户点击停止 → 停止录音 → 上传文件 → 语音转文字 ↓ 结果显示在输入框 → 用户点击发送 → 调用AI接口 ↓ AI回复 → Markdown渲染展示四、技术总结与最佳实践
4.1 语音转文字要点
- 权限处理:必须在用户交互中请求麦克风权限
- 异步控制:严格遵循 open → start → stop 的调用顺序
- 错误处理:捕获权限拒绝、设备异常等情况
- 格式转换:使用 recorder-core 的 MP3 编码器确保兼容性
4.2 Markdown 渲染要点
- 方案选择:Vue 项目优先使用 vue-markdown 组件
- 样式隔离:使用 scoped CSS 避免全局样式污染
- 性能优化:避免在大型文档中频繁更新 Markdown 内容
- 安全性:对用户输入的 Markdown 进行 XSS 过滤
关键词:Vue2、语音转文字、Markdown、recorder-core、vue-markdown