Spaces:
Running
Running
Actualizo app.py y requirements
Browse files
app.py
CHANGED
|
@@ -6,6 +6,10 @@ import torch
|
|
| 6 |
import matplotlib.pyplot as plt
|
| 7 |
import matplotlib.dates as mdates
|
| 8 |
from chronos import ChronosPipeline
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
# ----------------------------
|
| 11 |
# Modelo (ligero para Space free)
|
|
@@ -181,6 +185,36 @@ def forecast_fn(file, sku: str, horizon: int = 12, freq: str = "MS"):
|
|
| 181 |
|
| 182 |
return out, plot_path, tmp_path, md
|
| 183 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 184 |
|
| 185 |
def list_skus(file):
|
| 186 |
if file is None:
|
|
@@ -214,6 +248,17 @@ with gr.Blocks(title="Pron贸stico por SKU (Chronos-T5)") as demo:
|
|
| 214 |
download_file = gr.File(label="猬囷笍 Descargar pron贸stico (CSV)", interactive=False)
|
| 215 |
stats_md = gr.Markdown(label="Resumen")
|
| 216 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 217 |
btn.click(
|
| 218 |
forecast_fn,
|
| 219 |
inputs=[file, sku_dd, horizon, freq],
|
|
|
|
| 6 |
import matplotlib.pyplot as plt
|
| 7 |
import matplotlib.dates as mdates
|
| 8 |
from chronos import ChronosPipeline
|
| 9 |
+
import io, base64
|
| 10 |
+
from types import SimpleNamespace
|
| 11 |
+
|
| 12 |
+
|
| 13 |
|
| 14 |
# ----------------------------
|
| 15 |
# Modelo (ligero para Space free)
|
|
|
|
| 185 |
|
| 186 |
return out, plot_path, tmp_path, md
|
| 187 |
|
| 188 |
+
def forecast_from_text(csv_text_or_b64: str, sku: str, horizon: int = 12, freq: str = "MS"):
|
| 189 |
+
"""
|
| 190 |
+
Recibe CSV como texto o base64 (sin 'data:'), lo escribe a un archivo temporal,
|
| 191 |
+
y llama a forecast_fn reutilizando toda tu l贸gica actual.
|
| 192 |
+
Devuelve: (tabla, image filepath, csv filepath, markdown) en el mismo orden.
|
| 193 |
+
"""
|
| 194 |
+
txt = (csv_text_or_b64 or "").strip()
|
| 195 |
+
# 驴Parece base64? Intentar decodificar; si falla, tratar como texto plano.
|
| 196 |
+
try:
|
| 197 |
+
if not ("\n" in txt) and all(c.isalnum() or c in "+/=\n\r" for c in txt):
|
| 198 |
+
raw = base64.b64decode(txt)
|
| 199 |
+
csv_text = raw.decode("utf-8", errors="replace")
|
| 200 |
+
else:
|
| 201 |
+
csv_text = txt
|
| 202 |
+
except Exception:
|
| 203 |
+
csv_text = txt
|
| 204 |
+
|
| 205 |
+
# Escribir a un archivo temporal .csv
|
| 206 |
+
tmp = tempfile.NamedTemporaryFile("w+", suffix=".csv", delete=False)
|
| 207 |
+
tmp.write(csv_text)
|
| 208 |
+
tmp.flush()
|
| 209 |
+
tmp.close()
|
| 210 |
+
|
| 211 |
+
# Crear un objeto con atributo .name para que forecast_fn lo lea como gr.File
|
| 212 |
+
dummy_file = SimpleNamespace(name=tmp.name)
|
| 213 |
+
|
| 214 |
+
# Reusar tu pipeline original
|
| 215 |
+
return forecast_fn(dummy_file, sku, horizon, freq)
|
| 216 |
+
|
| 217 |
+
|
| 218 |
|
| 219 |
def list_skus(file):
|
| 220 |
if file is None:
|
|
|
|
| 248 |
download_file = gr.File(label="猬囷笍 Descargar pron贸stico (CSV)", interactive=False)
|
| 249 |
stats_md = gr.Markdown(label="Resumen")
|
| 250 |
|
| 251 |
+
# Endpoint solo-API que recibe CSV como texto/base64 (sin archivo)
|
| 252 |
+
api_csv_text = gr.Textbox(visible=False)
|
| 253 |
+
|
| 254 |
+
gr.Button(visible=False).click(
|
| 255 |
+
fn=forecast_from_text,
|
| 256 |
+
inputs=[api_csv_text, sku_dd, horizon, freq], # MISMO orden que usar谩 Netlify
|
| 257 |
+
outputs=[out_table, out_plot, download_file, stats_md],
|
| 258 |
+
api_name="/forecast_text"
|
| 259 |
+
)
|
| 260 |
+
|
| 261 |
+
|
| 262 |
btn.click(
|
| 263 |
forecast_fn,
|
| 264 |
inputs=[file, sku_dd, horizon, freq],
|