Spaces:
Build error
Build error
| 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) |