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

求助:基于Streamlit实现终端式文本RPG交互页面异常排查

问题分析与解决方案

问题根源

  • Streamlit基于会话驱动和页面重渲染机制,原代码中的while循环会持续阻塞主线程,导致页面一直处于加载状态,无法响应用户交互。
  • st.text_input在页面每次重渲染时都会重置,且无法在循环中实时捕获输入并传递给子进程。
  • 子进程的stdout.readline()是阻塞式调用,会进一步卡住页面流程。

修复方案

利用Streamlit的会话状态(st.session_state)保存子进程实例、输出历史,改用非阻塞方式读取子进程输出,通过按钮触发输入提交,避免阻塞主线程。

完整修复代码

import streamlit as st
import subprocess
import select

st.title("Danse Macabre 文本RPG")

# 初始化会话状态
if "process" not in st.session_state:
    # 启动子进程,设置非阻塞的stdout/stderr
    st.session_state.process = subprocess.Popen(
        ["python", "danse_macabre.py"],
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        universal_newlines=True,
        bufsize=1
    )
    st.session_state.output_history = []

# 非阻塞读取子进程的输出和错误
def read_non_blocking(stream):
    data = ""
    while select.select([stream], [], [], 0.1)[0]:
        line = stream.readline()
        if not line:
            break
        data += line
    return data

# 读取新输出并更新历史
stdout_output = read_non_blocking(st.session_state.process.stdout)
stderr_output = read_non_blocking(st.session_state.process.stderr)

if stdout_output:
    st.session_state.output_history.append(stdout_output.strip())
if stderr_output:
    st.session_state.output_history.append(f"[ERROR] {stderr_output.strip()}")

# 显示历史输出
st.text_area("游戏输出", value="\n".join(st.session_state.output_history), height=400, disabled=True)

# 用户输入区域
user_input = st.text_input("输入你的选择", key="user_input")
if st.button("提交") and user_input and st.session_state.process.poll() is None:
    # 传递输入给子进程
    st.session_state.process.stdin.write(user_input + "\n")
    st.session_state.process.stdin.flush()
    # 清空输入框(通过更新会话状态触发重渲染)
    st.session_state.user_input = ""

# 检查子进程是否结束
if st.session_state.process.poll() is not None:
    st.info("游戏已结束")

关键修复点说明

  • 会话状态存储:用st.session_state保存子进程实例和输出历史,确保页面重渲染时不会重复启动进程或丢失输出。
  • 非阻塞读取:通过select模块实现非阻塞的输出读取,避免阻塞Streamlit的主线程。
  • 输入提交机制:用按钮触发输入提交,防止输入框每次重渲染重置,同时避免重复传递输入给子进程。
  • 统一输出区域:用st.text_area展示所有历史输出,避免创建大量独立的st.text组件,提升页面性能。

内容的提问来源于stack exchange,提问作者Taiko

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 01:13:16