我已经搜索了一段时间,但无法找到解决方法。我有一个简单的Flask应用程序,它接收CSV文件,将其读入Pandas数据框中,转换并输出为新的CSV文件。我已经成功地使用HTML上传和转换了它。
<div class="container">
<form method="POST" action="/convert" enctype="multipart/form-data">
<div class="form-group">
<br />
<input type="file" name="file">
<input type="submit" name="upload"/>
</div>
</form>
</div>
当我点击提交后,它会在后台运行一段时间并在完成后自动触发下载。负责接收result_df并触发下载的代码如下:
@app.route('/convert', methods=["POST"])
def convert(
if request.method == 'POST':
# Read uploaded file to df
input_csv_f = request.files['file']
input_df = pd.read_csv(input_csv_f)
# TODO: Add progress bar for pd_convert
result_df = pd_convert(input_df)
if result_df is not None:
resp = make_response(result_df.to_csv())
resp.headers["Content-Disposition"] = "attachment; filename=export.csv"
resp.headers["Content-Type"] = "text/csv"
return resp
我想为
pd_convert
添加一个进度条,它本质上是一个 Pandas 应用操作。我发现 tqdm
现在可以与 Pandas 一起工作,并且它有一个 progress_apply
方法,而不是 apply
。但我不确定它是否适用于在网页上制作进度条。我猜应该可以,因为它在 Jupyter 笔记本上运行。这里如何为 pd_convert()
添加进度条?我想要的最终结果是:
- 用户点击上传,从他们的文件系统中选择 CSV 文件
- 用户点击提交
- 进度条开始运行
- 一旦进度条达到100%,就会触发下载
convert
函数可以轻松触发下载,因为响应是使用文件形成的。如果我想呈现页面,我使用 return render_template(...)
形成响应。由于我只能有一个响应,所以是否可能通过对 /convert
的一次调用来实现3和4?我不是 Web 开发人员,仍在学习基础知识。先感谢您!
====编辑====
我尝试了这里的示例(链接)并进行了一些修改。我从数据帧上的行索引中获取进度,并将其放入 Redis 中。客户端通过请求此新端点 /progress
从流中从 Redis 获取进度。类似于:
@app.route('/progress')
def progress():
"""Get percentage progress for the dataframe process"""
r = redis.StrictRedis(
host=redis_host, port=redis_port, password=redis_password, decode_responses=True)
r.set("progress", str(0))
# TODO: Problem, 2nd submit doesn't clear progress to 0%. How to make independent progress for each client and clear to 0% on each submit
def get_progress():
p = int(r.get("progress"))
while p <= 100:
p = int(r.get("progress"))
p_msg = "data:" + str(p) + "\n\n"
yield p_msg
logging.info(p_msg)
if p == 100:
r.set("progress", str(0))
time.sleep(1)
return Response(get_progress(), mimetype='text/event-stream')
目前它能够运行但存在一些问题。原因肯定是我对这个解决方案的理解不足。
问题:
- 每次按下
submit
按钮时,我需要将进度重置为0。我尝试了几个地方将其重置为0,但还没有找到可行的版本。这肯定与我对流如何工作的理解有关。现在只有在刷新页面时才会重置。 - 如何处理并发请求,也就是Redis竞争条件?如果多个用户同时发出请求,则每个用户的进度应独立。我考虑为每个
submit
事件提供一个随机的job_id
,并将其作为Redis中的键。由于每个作业完成后我都不需要该条目,所以完成后我将删除该条目。
我感觉我缺少的部分是对text/event-stream
的理解。我觉得我离一个可行的解决方案很近了。请分享您对正确操作方式的看法。我只是在猜测并尝试组合一些东西,以满足我的非常有限的理解。