部署在Modal上的Streamlit文件上传器返回400错误(本地正常)
解决Modal部署Streamlit时
st.file_uploader()返回400 Bad Request的问题 问题根源
出现该错误的核心原因包括:
- Streamlit在容器化环境下未启用无头模式,导致内部上传API逻辑异常
- 未显式指定Streamlit的上传临时目录,与Modal的临时存储路径不匹配
- 使用
subprocess.Popen启动Streamlit是非阻塞模式,可能引发进程管理异常
修复步骤
1. 修正Modal中Streamlit的启动配置
修改modal_app.py的run函数,调整启动命令并确保进程稳定运行:
@app.function() @modal.web_server(8000) def run(): cmd = [ "streamlit", "run", "/root/streamlit_app.py", "--server.port", "8000", "--server.enableCORS=false", "--server.headless=true", # 容器环境必需参数 "--server.upload_dir=/tmp" # 指定上传文件存储目录 ] subprocess.run(cmd, check=True) # 用run替代Popen,确保进程阻塞运行
同时需要补充模型文件的镜像添加步骤(当前配置缺失):
image = ( modal.Image.debian_slim(python_version="3.12") .apt_install("libgl1", "libglib2.0-0", "ffmpeg") .uv_pip_install("streamlit", "ultralytics", "opencv-python", "supabase", "python-dotenv") .add_local_file("src/streamlit_app.py", "/root/streamlit_app.py") .add_local_file("../.env", "/root/.env") .add_local_file("path/to/your/best.pt", "/root/best.pt") # 添加模型文件到镜像 )
2. 优化Streamlit应用的临时文件处理
简化streamlit_app.py的临时文件逻辑,确保文件写入到指定目录:
import streamlit as st from ultralytics import YOLO import tempfile, os from dotenv import load_dotenv load_dotenv("/root/.env") st.title("🦺 PPE Detection App") uploaded_file = st.file_uploader("Upload an image", type=["jpg", "png"]) if uploaded_file: # 在/tmp目录创建临时文件,避免路径权限问题 with tempfile.NamedTemporaryFile(dir="/tmp", suffix=os.path.splitext(uploaded_file.name)[1], delete=False) as temp_file: temp_file.write(uploaded_file.getbuffer()) temp_path = temp_file.name model = YOLO("/root/best.pt") results = model.predict(source=temp_path, save=True, project="/tmp", name="detections") st.success("✅ Detection complete!") # 可选:检测完成后清理临时文件 os.unlink(temp_path)
3. 关键配置说明
--server.headless=true:容器化部署Streamlit的必需参数,禁用GUI相关组件,避免内部API异常--server.upload_dir=/tmp:强制Streamlit将上传文件存储到Modal允许写入的临时目录,解决路径权限问题subprocess.run:替代Popen确保进程持续运行,符合Modal的web服务托管要求
内容的提问来源于stack exchange,提问作者Tommie




