
Phi-3 Forest Lab保姆级教程Streamlit WebRTC集成实现实时语音输入想让你的AI对话终端不仅能“看懂”文字还能“听懂”你的声音吗想象一下在一个充满森林气息的界面里你只需动动嘴就能与拥有128K超长记忆的Phi-3模型进行流畅对话这体验是不是瞬间拉满了今天我们就来手把手教你如何为那个治愈系的Phi-3 Forest Lab项目集成Streamlit WebRTC组件实现实时语音输入功能。从此与AI的交流从指尖敲击升级为自然对话。1. 我们要做什么—— 项目目标与价值在开始敲代码之前我们先明确一下这个功能的价值和最终效果。核心目标在现有的Phi-3 Forest Lab文字聊天界面上增加一个“语音输入”按钮。点击后浏览器会请求麦克风权限用户说话语音被实时转写成文字并自动填入输入框用户只需点击发送即可与AI对话。你将学到如何在Streamlit应用中集成streamlit-webrtc组件。如何捕获和处理浏览器端的实时音频流。如何将捕获的音频发送到后端进行语音识别Speech-to-Text, STT。如何将识别结果无缝填充回Streamlit的聊天输入框。最终效果预览你的Forest Lab界面将新增一个显眼的麦克风图标按钮。点击后按钮状态变化开始录制你的语音。你说话时转写的文字会实时显示或最终填入下方的输入框就像使用手机语音助手一样方便。2. 环境准备安装必要的工具确保你已经成功部署了基础的Phi-3 Forest Lab项目。接下来我们需要安装实现语音功能的核心库。打开你的终端命令行进入项目目录执行以下安装命令# 安装实时音视频通信组件 pip install streamlit-webrtc # 安装用于音频处理和语音识别的库 # 我们使用开源且轻量的Vosk模型也可以选择其他服务 pip install vosk # 安装音频处理工具 pip install sounddevice pydub简单解释一下streamlit-webrtc 这是一个Streamlit的自定义组件它封装了WebRTC技术让你能在Streamlit应用里轻松处理实时音频、视频流。vosk 一个离线的、开源语音识别工具包识别速度快准确度不错支持多种语言。我们用它来把音频转换成文字。sounddevice和pydub 用于播放、录制和处理音频文件的基础库。安装完成后建议重启一下你的Streamlit应用服务。3. 核心概念快速理解在动手写代码前花两分钟了解两个关键概念后面就不会懵了。WebRTC是什么你可以把它想象成浏览器内置的一个“实时通信引擎”。它允许网页应用比如我们的Streamlit应用直接捕获用户的麦克风和摄像头数据并进行实时传输无需安装任何插件。streamlit-webrtc组件帮我们简化了在Streamlit中使用这个引擎的复杂过程。语音识别STT流程是怎样的整个过程就像一场接力赛拾音 用户点击按钮streamlit-webrtc启动通过WebRTC拿到用户麦克风的实时音频流。传递 音频流被分成一个个小数据块帧从前端浏览器发送到我们写的后端Python处理函数。转写 后端的vosk识别器接收到音频数据块立刻进行识别并输出当前识别出的文字片段。展示 识别出的文字片段被实时传回前端显示在界面上。当用户停止说话最终完整的句子就会被填入输入框。了解这个流程代码结构就清晰了。4. 分步代码实现我们现在开始修改你的app.py或你的主Streamlit文件。我们将分模块添加功能。4.1 第一步导入库与初始化识别器在你原有导入库的部分添加以下新需要的库。# 原有导入... import streamlit as st # ... 其他原有导入 # 新增导入 from streamlit_webrtc import webrtc_streamer, WebRtcMode, AudioProcessorBase import av # 音频视频容器处理 from vosk import Model, KaldiRecognizer import json import queue import threading接下来我们需要初始化Vosk语音识别模型。你需要先下载一个模型文件。这里以小型英文模型为例中文模型可在Vosz官网下载。# 在初始化模型的部分附近添加语音模型初始化 # 假设你将模型解压到了项目目录下的 model 文件夹中 VOICE_MODEL_PATH ./model/vosk-model-small-en-us-0.15 # 请根据你的模型路径修改 st.cache_resource # 使用缓存避免重复加载模型 def load_vosk_model(): try: model Model(VOICE_MODEL_PATH) st.success(语音识别模型加载成功) return model except Exception as e: st.error(f加载语音模型失败: {e}) return None vosk_model load_vosk_model()4.2 第二步创建音频处理类这是最核心的部分。我们需要创建一个类来定义当音频流到来时该如何处理。class VoiceInputProcessor(AudioProcessorBase): def __init__(self): super().__init__() # 创建一个队列用于存放识别出的文本片段 self.text_queue queue.Queue() self.recognizer None self.model vosk_model def recv(self, frame: av.AudioFrame) - av.AudioFrame: # 这个函数会被WebRTC反复调用传入音频帧 if self.model and self.recognizer is None: # 初始化识别器采样率需要和音频帧一致 self.recognizer KaldiRecognizer(self.model, frame.sample_rate) audio_data frame.to_ndarray().tobytes() if self.recognizer and self.recognizer.AcceptWaveform(audio_data): # 当识别出一句完整的话有停顿 result json.loads(self.recognizer.Result()) text result.get(text, ) if text: self.text_queue.put(text) # 将完整句子放入队列 else: # 获取部分识别结果实时反馈 partial_result json.loads(self.recognizer.PartialResult()) partial_text partial_result.get(partial, ) # 这里可以实时更新UI显示部分结果我们先存起来 if partial_text: # 为了简单我们只处理完整句。你可以扩展这里实现实时字幕。 pass # 必须返回原始的音频帧如果要做回声抵消等处理可以在这里改 return frame def get_last_text(self): 从队列中获取最新识别到的文本如果没有则返回空字符串 try: return self.text_queue.get_nowait() except queue.Empty: return 4.3 第三步在Streamlit UI中集成语音组件现在我们要在界面上放置语音按钮和WebRTC流。我们把它放在聊天输入框的旁边。找到你原来放置st.chat_input或文本输入框的部分。我们将其改造一下。# 假设你原来的输入部分是这样的 # user_input st.chat_input(向森林深处发出的讯息...) # 我们将其改为一个布局容器并列放置输入框和语音按钮 col1, col2 st.columns([6, 1]) # 6:1的比例分配宽度 with col1: # 使用一个文本输入框以便我们可以用代码设置它的值 user_input st.text_input( 向森林深处发出的讯息..., keyuser_input, label_visibilitycollapsed # 隐藏标签 ) with col2: # 这个按钮用于触发/关闭语音输入 voice_button st.button(, keyvoice_toggle, help点击开始语音输入) # 初始化session state用于存储语音识别结果和控制流状态 if voice_text not in st.session_state: st.session_state.voice_text if webrtc_ctx not in st.session_state: st.session_state.webrtc_ctx None # 如果语音按钮被点击并且模型已加载则启动/重置WebRTC流 if voice_button and vosk_model: st.session_state.voice_text # 清空之前的识别结果 # 使用webrtc_streamer创建音频流 # 关键将我们自定义的处理器类传进去 webrtc_ctx webrtc_streamer( keyvoice-input, modeWebRtcMode.SENDONLY, # 我们只需要发送音频从用户到服务器 audio_processor_factoryVoiceInputProcessor, # 使用我们的处理器 media_stream_constraints{audio: True, video: False}, # 只启用音频 rtc_configuration{iceServers: [{urls: [stun:stun.l.google.com:19302]}]} # STUN服务器帮助建立连接 ) st.session_state.webrtc_ctx webrtc_ctx st.info( 语音输入已激活请开始说话...点击界面其他区域或按钮可关闭) # 如果WebRTC上下文存在且正在运行则尝试获取识别结果 if st.session_state.get(webrtc_ctx) and st.session_state.webrtc_ctx.state.playing: # 从处理器中获取识别到的文本 # 这里需要一点技巧来访问处理器实例通常可以通过回调或重新设计来获取。 # 为了教程简洁我们采用一个简化的方法使用全局变量或更复杂的状态管理。 # 以下是一个简化示意实际可能需要将processor实例保存在session_state中。 pass # 一个更实用的简化方案使用一个独立的“确认”按钮来填充文本 # 在实际项目中你可能需要利用streamlit的自定义组件通信或更高级的状态管理。 # 这里我们先实现一个基础版本当语音识别运行时用一个循环去检查并更新输入框。 # 注意由于Streamlit的架构实时、低延迟地更新输入框值比较棘手。 # 一个常见的模式是语音识别完成后将结果填充到一个变量然后通过按钮或自动方式填入输入框。 # 例如我们可以在侧边栏或输入框下方显示识别结果并提供一个“使用此文本”的按钮。 if st.session_state.voice_text: st.write(f识别结果: {st.session_state.voice_text}) if st.button(使用此文本并发送): # 这里需要将识别结果设置到user_input变量并触发发送逻辑。 # 由于Streamlit的执行模型直接设置输入框值并模拟发送比较复杂。 # 一个替代方案是将识别结果直接作为消息放入聊天历史然后清空输入。 # 我们选择另一种使用session_state来传递值并在下一次运行时生效。 st.session_state[pending_voice_input] st.session_state.voice_text st.session_state.voice_text st.rerun() # 重新运行脚本 # 在脚本开始处检查是否有待处理的语音输入 if pending_voice_input in st.session_state and st.session_state.pending_voice_input: # 将待处理的输入赋值给输入框并立即发送这里需要结合你的聊天逻辑 # 假设你有一个处理消息的函数 process_message user_input_for_chat st.session_state.pending_voice_input del st.session_state.pending_voice_input # 这里调用你的消息处理逻辑例如 # if user_input_for_chat: # with st.chat_message(user): # st.markdown(user_input_for_chat) # st.session_state.messages.append({role: user, content: user_input_for_chat}) # # ... 调用模型生成回复 ... st.info(f已发送语音输入: {user_input_for_chat}) # 注意自动发送可能会打断用户体验请根据你的交互设计调整。上面的代码是一个基础框架和思路。直接将识别结果实时填入输入框并自动发送在Streamlit中需要处理其单线程、重运行的特点可能会比较繁琐。一个更稳定、用户体验更好的做法是语音识别独立运行WebRTC在后台持续识别。结果显示在专门区域将实时识别出的文字显示在输入框上方的一个固定区域如st.empty()容器。用户确认后发送用户说完后看到识别结果点击一个“发送”按钮将显示区域的文字填入真正的聊天流程。4.4 第四步整合与调试将上述代码块整合到你的现有app.py中注意处理好与你原有聊天逻辑消息历史、模型调用等的衔接。重点调试步骤模型路径确保VOICE_MODEL_PATH指向正确的、已下载解压的Vosk模型目录。麦克风权限首次点击语音按钮时浏览器会弹出权限请求务必点击“允许”。控制台日志打开浏览器的开发者工具F12查看Console和Network标签页排查WebRTC连接或音频传输的错误。简化验证可以先注释掉复杂的UI更新逻辑只测试VoiceInputProcessor是否能正确打印识别结果到后台终端。5. 进阶优化与问题排查功能跑通后你可以考虑以下优化点中文支持去Vosk官网下载中文模型如vosk-model-small-cn-0.22替换模型路径即可。实时反馈修改VoiceInputProcessor类将partial结果也通过某种方式如WebSocket或自定义组件通信传回前端实现“边说边显”的字幕效果。UI/UX优化将语音按钮设计得更美观添加录音动画、音量可视化等。错误处理增加网络不佳、麦克风不可用、模型加载失败等情况的友好提示。常见问题没反应/不识别检查浏览器控制台是否有错误。确保模型路径正确且音频采样率匹配Vosk模型通常是16000或8000Hzwebrtc_streamer默认是48000Hz需要在recv函数中做重采样或配置webrtc_streamer的音频参数。权限被拒绝确保浏览器设置允许该网站使用麦克风并检查是否被其他应用占用。Streamlit频繁重载WebRTC连接在Streamlit脚本重跑时可能会中断。确保相关状态保存在st.session_state中并考虑使用st.experimental_singleton缓存处理器实例。6. 总结恭喜你通过本教程你已经为静谧的Phi-3 Forest Lab赋予了“聆听”的能力。我们利用了streamlit-webrtc的强大能力捕获实时音频并通过轻量级的 Vosk 引擎将其转化为文字最终汇入与Phi-3模型的智慧对话中。回顾一下关键步骤安装工具-理解流程-编写音频处理器-集成到UI-调试优化。这个过程不仅适用于本项目你也可以将这套实时语音输入方案迁移到任何基于Streamlit的交互应用中。现在你的森林实验室不再只有键盘的敲击声。点击那个麦克风按钮对着它说出你的问题感受声音化作文字流入森林深处等待那个拥有128K记忆的智慧给予回响。技术不再是冰冷的代码而是连接自然与思维的桥梁。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。