Flask+React双向对话转录:主线程为何立即停止退出?
解决Flask后端接收
start_recording后立即退出的方案 核心问题是:处理完WebSocket的start_recording消息后,主线程没有持续运行的逻辑,直接退出导致整个程序终止。time.sleep(100)能临时解决是因为强制阻塞了主线程,让音频转录逻辑有执行时间。以下是几种合理的替代方案:
1. 用后台线程分离音频转录任务
把麦克风采集、Azure转录、WebSocket推送的逻辑放到独立的后台线程中,主线程专注维持WebSocket连接和处理前端消息:
import threading from flask import Flask from flask_socketio import SocketIO app = Flask(__name__) socketio = SocketIO(app, cors_allowed_origins="*") is_recording = False def transcription_task(): global is_recording # 初始化SoundCard流、Azure Conversation Transcriber mic = Microphone() with mic.recorder(samplerate=16000) as recorder: while is_recording: # 采集音频帧并送入Azure转录 audio_frame = recorder.record(numframes=1024) # 执行Azure转录逻辑(此处省略具体调用) transcribed_text = "模拟转录结果" # 推送转录内容到前端 socketio.emit('transcription_result', {'text': transcribed_text}) @socketio.on('start_recording') def handle_start_recording(): global is_recording is_recording = True # 创建并启动后台线程 thread = threading.Thread(target=transcription_task) thread.daemon = False # 避免主线程退出时强制终止任务 thread.start() @socketio.on('stop_recording') def handle_stop_recording(): global is_recording is_recording = False if __name__ == '__main__': socketio.run(app, debug=True)
通过全局变量is_recording控制转录线程的循环,收到前端停止信号时终止任务,避免线程无意义运行。
2. 基于WebSocket消息循环维持主线程活跃
利用Flask-SocketIO的事件循环特性,在处理start_recording后进入监听停止信号的循环,直到收到停止指令再退出:
from flask import Flask from flask_socketio import SocketIO, emit app = Flask(__name__) socketio = SocketIO(app, cors_allowed_origins="*") is_recording = False @socketio.on('start_recording') def handle_start_recording(): global is_recording is_recording = True # 初始化音频流和Azure转录器 mic = Microphone() with mic.recorder(samplerate=16000) as recorder: while is_recording: # 采集音频帧并执行转录 audio_frame = recorder.record(numframes=1024) transcribed_text = "模拟转录结果" emit('transcription_result', {'text': transcribed_text}) # 用socketio.sleep避免阻塞事件循环 socketio.sleep(0.01) @socketio.on('stop_recording') def handle_stop_recording(): global is_recording is_recording = False if __name__ == '__main__': socketio.run(app, debug=True)
这种方式不需要额外线程,直接利用框架的事件循环维持任务运行,同时不会阻塞其他WebSocket消息处理。
3. 切换到异步WebSocket框架
如果原生Flask的WebSocket处理长任务有局限,可以换成异步框架FastAPI,它对WebSocket和后台任务的支持更原生:
from fastapi import FastAPI, WebSocket import asyncio from soundcard import Microphone app = FastAPI() is_recording = False async def transcription_task(websocket: WebSocket): global is_recording mic = Microphone() with mic.recorder(samplerate=16000) as recorder: while is_recording: audio_frame = recorder.record(numframes=1024) # 执行Azure异步转录逻辑(若SDK支持异步) transcribed_text = "模拟转录结果" await websocket.send_json({"text": transcribed_text}) await asyncio.sleep(0.01) @app.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): await websocket.accept() global is_recording while True: data = await websocket.receive_json() if data["action"] == "start_recording": is_recording = True # 启动异步后台任务 asyncio.create_task(transcription_task(websocket)) elif data["action"] == "stop_recording": is_recording = False if __name__ == '__main__': import uvicorn uvicorn.run(app, host="0.0.0.0", port=5000)
异步框架天生适合处理长连接和后台任务,不需要额外处理线程阻塞问题,代码逻辑更简洁。
内容的提问来源于stack exchange,提问作者adityapgupta211
相关产品推荐
相关产品推荐

