部署Python Streamlit唇读应用至streamlit.io时遇FileNotFoundError
解决Streamlit部署至streamlit.io时的FileNotFoundError问题
问题现象
部署到streamlit.io平台时触发以下错误:
File “/home/appuser/venv/lib/python3.8/site-packages/streamlit/runtime/scriptrunner/script_runner.py”, line 565, in _run_script exec(code, module.dict) File “/app/lipreading/app/streamlitapp.py”, line 20, in options = os.listdir(os.path.join(‘…’, ‘data’, ‘s1’))
本地运行正常,但部署后无法读取指定目录文件,核心问题出在路径解析和文件上传环节。
解决方案
1. 修复相对路径,使用绝对路径定位文件
本地环境的工作目录与streamlit.io的部署环境存在差异,相对路径../data/s1在部署环境中无法正确解析。修改为基于脚本文件位置构建绝对路径:
import streamlit as st import os # ... 其他导入保持不变 # 新增:获取项目根目录绝对路径 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Set the layout to the Streamlit app as wide st.set_page_config(layout='wide') # ... 侧边栏代码保持不变 # 修改路径生成逻辑 options = os.listdir(os.path.join(BASE_DIR, 'data', 's1')) selected_video = st.selectbox('Choose video', options) # ... 后续file_path也同步修改 file_path = os.path.join(BASE_DIR, 'data', 's1', selected_video)
2. 确保data目录完整上传至GitHub
streamlit.io从GitHub仓库拉取代码,若data/s1中的视频文件未被上传(比如因文件过大被.gitignore排除),会导致部署后目录为空。解决方式:
- 检查仓库根目录的
.gitignore文件,确保未排除data/目录或.mpg文件 - 由于视频文件体积较大,使用Git LFS管理大文件:
- 安装Git LFS
- 在仓库中执行
git lfs track "*.mpg" - 提交
.gitattributes文件和视频文件到仓库
3. 验证部署环境的路径(可选调试步骤)
在代码中加入路径调试代码,确认部署环境的实际工作目录和文件位置:
# 在路径相关代码前添加 st.write("当前工作目录:", os.getcwd()) st.write("项目根目录:", BASE_DIR) st.write("目标目录路径:", os.path.join(BASE_DIR, 'data', 's1'))
部署后查看Streamlit应用中的输出,确认路径是否正确。
4. 优化临时文件存储路径
代码中生成的test_video.mp4和animation.gif默认存在当前工作目录,部署环境可能存在权限问题,建议使用Streamlit的临时目录:
# 替换输出路径 import tempfile # 生成临时文件路径 with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp: output_path = tmp.name # 后续视频处理使用output_path video_clip = VideoFileClip(file_path) video_clip.write_videofile(output_path, codec='libx264')
修改后的核心代码片段
import streamlit as st import os import tempfile from moviepy.editor import VideoFileClip import imageio import tensorflow as tf from utils import load_data, num_to_char from modelutil import load_model # 获取项目根目录 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) st.set_page_config(layout='wide') # 侧边栏代码保持不变 st.markdown("<h1 style='text-align: center; color: white;'>LipNet</h1>", unsafe_allow_html=True) # 生成视频选项列表 options = os.listdir(os.path.join(BASE_DIR, 'data', 's1')) selected_video = st.selectbox('Choose video', options) col1, col2 = st.columns(2) if options: with col1: st.info('The video below displays the converted video in mp4 format') file_path = os.path.join(BASE_DIR, 'data', 's1', selected_video) # 使用临时文件存储转换后的视频 with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as tmp: output_path = tmp.name video_clip = VideoFileClip(file_path) video_clip.write_videofile(output_path, codec='libx264') video = open(output_path, 'rb') video_bytes = video.read() st.video(video_bytes) # 清理临时文件 os.unlink(output_path) with col2: st.info('This is all the machine learning model sees when making a prediction') video, annotations = load_data(tf.convert_to_tensor(file_path)) # 使用临时文件存储GIF with tempfile.NamedTemporaryFile(suffix='.gif', delete=False) as tmp: gif_path = tmp.name imageio.mimsave(gif_path, video, fps=10) st.image(gif_path, width=400) # 清理临时文件 os.unlink(gif_path) # 后续模型预测代码保持不变 st.info('This is the output of the machine learning model as tokens') model = load_model() yhat = model.predict(tf.expand_dims(video, axis=0)) decoder = tf.keras.backend.ctc_decode(yhat, [75], greedy=True)[0][0].numpy() st.text(decoder) st.info('Decode the raw tokens into words') converted_prediction = tf.strings.reduce_join(num_to_char(decoder)).numpy().decode('utf-8') st.text(converted_prediction)
内容的提问来源于stack exchange,提问作者Amith A G
相关产品推荐
相关产品推荐

