Flask实时推送日志至Streamlit前端失败问题求助
解决Flask日志实时推送到Streamlit前端的问题
你的核心问题在于两处:一是Flask端要等predict.main执行完才开始读取日志,无法实时捕获输出;二是Streamlit端仅打印日志到终端,没有更新前端组件。以下是具体解决方案:
Flask端修改(实时捕获并推送日志)
方案1:用subprocess调用predict脚本(推荐)
直接通过子进程运行predict脚本,实时捕获stdout输出并yield,避免函数阻塞导致日志延迟:
from flask import Flask, request, Response import argparse import subprocess import sys api = Flask(__name__) @api.route('/predict', methods=['POST']) def make_predictions(): url = request.get_json(force=True) # 直接构造参数对象,避免argparse干扰Flask启动参数 opt_weights = 'best.pt' def stream_logs(): # 启动predict子进程,实时捕获输出 proc = subprocess.Popen( [sys.executable, 'predict.py', '--weights', opt_weights, '--source', url], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, # 合并stderr到stdout一起推送 text=True, bufsize=1, # 行缓冲,确保实时输出 universal_newlines=True ) # 逐行读取并推送日志 for line in iter(proc.stdout.readline, ''): yield line proc.wait() return Response(stream_logs(), mimetype='text/plain') if __name__ == '__main__': api.run(host='0.0.0.0', port=8080, threaded=True)
方案2:重定向stdout捕获predict.main的输出
如果必须直接调用predict.main函数,可通过重定向sys.stdout实时捕获print输出:
from flask import Flask, request, Response import argparse import sys from io import StringIO import predict api = Flask(__name__) @api.route('/predict', methods=['POST']) def make_predictions(): url = request.get_json(force=True) opt = argparse.Namespace(weights=['best.pt'], source=url) def stream_logs(): # 自定义管道类,捕获stdout输出 class LogStream(StringIO): def write(self, msg): # 每次写入就推送日志片段 yield msg old_stdout = sys.stdout try: log_stream = LogStream() sys.stdout = log_stream # 执行预测,同时捕获输出 predict.main(opt) # 推送剩余输出 yield from log_stream.getvalue() finally: sys.stdout = old_stdout return Response(stream_logs(), mimetype='text/plain') if __name__ == '__main__': api.run(host='0.0.0.0', port=8080, threaded=True)
Streamlit端修改(实时更新前端日志)
需要用st.empty()创建占位符,实时追加并显示日志内容:
import streamlit as st import requests with st.form(key='my_form'): url = st.text_input("Image / Video URL", placeholder="Please enter image url") submit = st.form_submit_button(label='Submit') if submit: # 创建日志显示占位符 log_container = st.empty() full_log = "" # 发送流式请求 response = requests.post( 'http://localhost:8080/predict', json=url, # requests自动处理json序列化,无需手动dumps stream=True ) # 实时读取并更新前端 for chunk in response.iter_content(chunk_size=1024, decode_unicode=True): if chunk: full_log += chunk # 更新占位符内容,实现实时刷新 log_container.text(full_log)
关键修改说明
- Flask端:
- 避免在路由中使用
argparse.parse_args,防止和Flask自身启动参数冲突,直接构造Namespace对象更安全。 - 用子进程或stdout重定向的方式,确保日志生成时立即推送,而非等待
predict.main执行完毕。
- 避免在路由中使用
- Streamlit端:
- 使用
st.empty()作为日志容器,每次获取新片段就更新内容,实现前端实时同步。 - 直接传递Python对象给
requests.post的json参数,无需手动序列化。
- 使用
内容的提问来源于stack exchange,提问作者John Jam
相关产品推荐
相关产品推荐

