Workshop / app.py
llauravalente's picture
Update app.py
8e2eb61 verified
import os
import re
import json
import time
import traceback
from pathlib import Path
from typing import Dict, Any, List, Optional, Tuple
import pandas as pd
import gradio as gr
import papermill as pm
# Optional LLM (HuggingFace Inference API)
try:
from huggingface_hub import InferenceClient
except ImportError:
InferenceClient = None
# =========================================================
# CONFIG
# =========================================================
BASE_DIR = Path(__file__).resolve().parent
NB1 = os.environ.get("NB1", "datacreation.ipynb").strip()
NB2 = os.environ.get("NB2", "pythonanalysis.ipynb").strip()
NB3 = os.environ.get("NB3", "ranalysis.ipynb").strip()
RUNS_DIR = BASE_DIR / "runs"
ART_DIR = BASE_DIR / "artifacts"
PY_FIG_DIR = ART_DIR / "py" / "figures"
PY_TAB_DIR = ART_DIR / "py" / "tables"
R_FIG_DIR = ART_DIR / "r" / "figures"
R_TAB_DIR = ART_DIR / "r" / "tables"
PAPERMILL_TIMEOUT = int(os.environ.get("PAPERMILL_TIMEOUT", "1800"))
MAX_PREVIEW_ROWS = int(os.environ.get("MAX_FILE_PREVIEW_ROWS", "50"))
# =========================================================
# HELPERS
# =========================================================
def ensure_dirs():
for p in [RUNS_DIR, ART_DIR, PY_FIG_DIR, PY_TAB_DIR, R_FIG_DIR, R_TAB_DIR]:
p.mkdir(parents=True, exist_ok=True)
def _ls(dir_path: Path, exts: Tuple[str, ...]) -> List[str]:
if not dir_path.is_dir():
return []
return sorted(p.name for p in dir_path.iterdir() if p.is_file() and p.suffix.lower() in exts)
def artifacts_index() -> Dict[str, Any]:
return {
"python": {
"figures": _ls(PY_FIG_DIR, (".png", ".jpg", ".jpeg")),
"tables": _ls(PY_TAB_DIR, (".csv", ".json")),
},
"r": {
"figures": _ls(R_FIG_DIR, (".png", ".jpg", ".jpeg")),
"tables": _ls(R_TAB_DIR, (".csv", ".json")),
},
}
# =========================================================
# PIPELINE RUNNERS
# =========================================================
def run_notebook(nb_name: str) -> str:
ensure_dirs()
nb_in = BASE_DIR / nb_name
if not nb_in.exists():
return f"ERROR: {nb_name} non trovato."
nb_out = RUNS_DIR / f"run_{time.strftime('%Y%m%d-%H%M%S')}_{nb_name}"
pm.execute_notebook(
input_path=str(nb_in),
output_path=str(nb_out),
cwd=str(BASE_DIR),
log_output=True,
progress_bar=False,
execution_timeout=PAPERMILL_TIMEOUT,
)
return f"Eseguito {nb_name}"
def run_full_pipeline():
try:
r1 = run_notebook(NB1)
r2 = run_notebook(NB2)
r3 = run_notebook(NB3)
return f"Pipeline Completata!\n1. {r1}\n2. {r2}\n3. {r3}"
except Exception as e:
return f"ERRORE: {str(e)}"
# =========================================================
# UI LOGIC
# =========================================================
def refresh_gallery():
idx = artifacts_index()
figs = []
for p in sorted(PY_FIG_DIR.glob("*.png")):
figs.append((str(p), f"Python | {p.stem}"))
for p in sorted(R_FIG_DIR.glob("*.png")):
figs.append((str(p), f"R | {p.stem}"))
table_choices = [f"python/{t}" for t in idx["python"]["tables"]] + [f"r/{t}" for t in idx["r"]["tables"]]
return figs, gr.update(choices=table_choices), pd.DataFrame()
def on_table_select(choice):
if not choice: return pd.DataFrame()
scope, name = choice.split("/", 1)
path = (PY_TAB_DIR if scope == "python" else R_TAB_DIR) / name
try:
return pd.read_csv(path).head(MAX_PREVIEW_ROWS) if path.suffix == ".csv" else pd.DataFrame([json.load(open(path))])
except:
return pd.DataFrame({"Stato": ["Dati non ancora disponibili"]})
def ai_chat(user_msg, history):
# Logica di risposta semplificata per compatibilità
reply = "Ho analizzato la tua richiesta sui dati."
fig_out = None
if "trend" in user_msg.lower():
target = PY_FIG_DIR / "sales_trends_sampled_titles.png"
if target.exists(): fig_out = str(target)
history = history or []
history.append((user_msg, reply))
return history, "", fig_out
# =========================================================
# GRADIO INTERFACE
# =========================================================
ensure_dirs()
with gr.Blocks(theme=gr.themes.Soft()) as demo:
# BANNER SUPERIORE
gr.Image("background_top.png", show_label=False, container=False, interactive=False)
gr.Markdown("# 🚀 RX12 - Dashboard Integrata Python & R")
with gr.Tab("1. Esecuzione Analisi"):
gr.Markdown("Avvia la pipeline per generare report e grafici.")
log_box = gr.Textbox(label="Log di Sistema", lines=8)
run_btn = gr.Button("Lancia Pipeline Completa", variant="primary")
run_btn.click(run_full_pipeline, outputs=log_box)
# BANNER CENTRALE
gr.Image("background_mid.png", show_label=False, container=False, interactive=False)
with gr.Tab("2. Galleria Risultati"):
refresh_btn = gr.Button("🔄 Aggiorna Visualizzazioni")
gallery = gr.Gallery(label="Grafici Analitici", columns=2)
with gr.Row():
table_drop = gr.Dropdown(label="Seleziona Tabella", choices=[])
table_out = gr.Dataframe(label="Anteprima Dati")
refresh_btn.click(refresh_gallery, outputs=[gallery, table_drop, table_out])
table_drop.change(on_table_select, inputs=table_drop, outputs=table_out)
with gr.Tab("3. AI Dashboard"):
with gr.Row():
with gr.Column(scale=1):
chatbot = gr.Chatbot(label="Assistente Virtuale") # type="messages" RIMOSSO
msg = gr.Textbox(label="Chiedi all'AI", placeholder="Es: Mostrami i trend...")
with gr.Column(scale=1):
ai_img = gr.Image(label="Grafico Suggerito")
msg.submit(ai_chat, [msg, chatbot], [chatbot, msg, ai_img])
# BANNER INFERIORE
gr.Image("background_bottom.png", show_label=False, container=False, interactive=False)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=7860)