You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:04:57