He estado buscando en Google por un tiempo y no pude encontrar una manera de hacer esto. Tengo una aplicación Flask simple que toma un archivo CSV, lo lee en un marco de datos de Pandas, lo convierte y lo genera como un nuevo archivo CSV. He logrado subirlo y convertirlo con éxito con 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>donde después de hacer clic en enviar, ejecuta la conversión en segundo plano durante un tiempo y activa automáticamente una descarga una vez que finaliza. El código que toma result_df y desencadena la descarga parece
@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 Me gustaría agregar una barra de progreso a pd_convert que es esencialmente una operación de aplicación de pandas. Descubrí que tqdm ahora funciona con pandas y tiene un método progress_apply en lugar de apply . Pero no estoy seguro de si es relevante para hacer una barra de progreso en una página web. Supongo que debería serlo, ya que funciona en portátiles Jupyter. ¿Cómo agrego una barra de progreso para pd_convert() aquí?
El resultado final que quiero es:
1 y 2 están listos ahora. Entonces la siguiente pregunta es cómo activar la descarga. Por ahora, mi función de convert activa la descarga sin problemas porque la respuesta se forma con un archivo. Si quiero renderizar la página, formulo una respuesta con return render_template(...) . Dado que solo puedo tener una respuesta, ¿es posible tener 3 y 4 con solo una llamada a /convert ?
No es un desarrollador web, todavía está aprendiendo sobre los conceptos básicos. ¡Gracias por adelantado!
====EDITAR====
Probé el ejemplo aquí con algunas modificaciones. Obtengo el progreso del índice de fila en un bucle for en el marco de datos y lo pongo en Redis. El cliente obtiene el progreso de Redis de la secuencia al preguntarle a este nuevo punto final /progress . Algo como
@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')Actualmente está funcionando pero con algunos problemas. La razón es definitivamente mi falta de comprensión en esta solución.
Cuestiones:
submit . Probé varios lugares para restablecerlo a 0 pero aún no he encontrado la versión que funcione. Definitivamente está relacionado con mi falta de comprensión sobre cómo funciona la transmisión. Ahora solo se reinicia cuando actualizo la página.job_id aleatorio para cada evento de submit y convertirlo en la clave en Redis. Como no necesito la entrada después de que termine cada trabajo, solo eliminaré la entrada después de que esté lista. Siento que mi parte faltante es la comprensión de text/event-stream . Siento que estoy cerca de una solución que funcione. Comparta su opinión sobre cuál es la forma "adecuada" de hacer esto. Solo estoy adivinando y tratando de armar algo que funcione con mi comprensión muy limitada.