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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:10:54