import gradio as gr import cv2 import os import modules.utilities.utils as utils from modules.binary_classification import binary_classification as binary from modules.image_classification import image_classification as image from modules.multilabel_classification import multi_classification as multi from modules.retina import predict_diabetic_retinopathy as retina_detector from modules.bpo_dispatcher import predict_bpo_ticket import modules.forecasting as forecast # --- CONFIGURAZIONE TEMA --- theme = gr.themes.Soft( primary_hue="purple", neutral_hue="slate", font=[gr.themes.GoogleFont("Inter"), "ui-sans-serif", "system-ui", "sans-serif"], ).set( block_title_text_weight="700", block_shadow="*shadow_drop_lg", block_label_background_fill="*primary_100", ) PATH_ROOT = "./data/gallery" PATH_RETINA = "./data/gallery/retinopaty" PATH_XRAY = "./data/gallery/xray" PATH_FORECAST = "./data/export" # Crea cartella e file demo se non esistono if not os.path.exists(PATH_FORECAST): os.makedirs(PATH_FORECAST) demo_csv_path = os.path.join(PATH_FORECAST, "plan_sample.csv") # Se il file non esiste, ORA generiamo 4 settimane di dati procedurali if not os.path.exists(demo_csv_path): csv_content = forecast.generate_mock_export() with open(demo_csv_path, "w") as f: f.write(csv_content) def forecast_logic(file): if file is None: raise gr.Error("Seleziona un file CSV") if isinstance(file, list): file = file[0] img, text = forecast.predict_workload(file) if img is None: raise gr.Error(text) return img, text def binary_classification(text): if text.strip(): return binary(text) raise gr.Error('Il testo è obbligatorio!') def multi_classification(text): if text.strip(): try: return multi(text) except Exception as e: raise gr.Error(f'Errore nel modello: {str(e)}') raise gr.Error('Il testo è obbligatorio!') def file_change(file): if isinstance(file, list): file = file[0] if file: return cv2.imread(file) return None def image_classification(img): if img is not None: return image(img) raise gr.Error('L\'immagine è obbligatoria!') def retina_classification(retina): if retina is not None: return retina_detector(retina) raise gr.Error('L\'immagine è obbligatoria!') def bpo_dispatch_logic(text): """ Funzione Ponte: Chiama il modulo AI e decide l'azione di business. Restituisce un aggiornamento COMPLETO del componente NER per pulire la grafica. """ try: intent, urgency, entities = predict_bpo_ticket(text) if intent is None: raise gr.Error("Errore nel modello BPO. Verifica i log.") top_intent = max(intent, key=intent.get) action = "Inoltro generico" if top_intent == "Retention / Churn Risk": action = "🚨 ALERT: Assegnazione coda 'Retention' + Chiamata Outbound" elif top_intent == "Supporto Tecnico": action = "🛠️ Apertura Ticket JIRA (Livello 1) - Priorità Tecnica" elif top_intent == "Amministrazione / Billing": action = "💰 Verifica insoluti su SAP + Inoltro Backoffice Amm.vo" html_output = utils.render_ner_html(entities) return intent, urgency, action, html_output except Exception as e: raise gr.Error(f"Errore nell'analisi: {str(e)}") with gr.Blocks(title="NGT AI Platform", theme=theme, css_paths="style.css") as demo: # --- SIDEBAR (FILE EXPLORER) --- with gr.Sidebar(position="left", width=300, visible=False) as main_sidebar: gr.Markdown("### 📂 Risorse Demo") gr.Markdown("Seleziona i file di esempio:") sidebar_explorer = gr.FileExplorer( root_dir=PATH_ROOT, glob="**/*", ignore_glob="*.h5,*.json,*.py,*.pyc", file_count="single", label="Archivio File", height=400, interactive=True ) gr.Markdown("---") gr.Markdown("**Info Sistema:**") gr.Markdown("🟢 Server: Online") gr.Markdown("🟣 GPU: N/A (CPU Mode)") # --- MAIN CONTENT --- with gr.Column(): # --- HEADER --- with gr.Row(elem_classes="header-row"): with gr.Column(scale=0, min_width=80, elem_classes="logo-container"): gr.Image(value="data/icon.png", show_label=False, show_download_button=False, show_share_button=False, container=False, show_fullscreen_button=False, interactive=False, height=80, width=80) with gr.Column(scale=1, elem_classes="header-text-col"): gr.Markdown("""

AI Platform

Advanced Machine Learning Solutions
""") # --- BPO INTELLIGENT DISPATCHER --- with gr.Tab("🧩 BPO Dispatcher") as tab_bpo: gr.Markdown(""" # 🧩 Intelligent Ticket Routing & NER Sistema proprietario per l'analisi automatica dei ticket di assistenza. Il modello identifica l'intento, l'urgenza e i dati sensibili del cliente. """) with gr.Row(elem_classes="responsive-row"): # INPUT with gr.Column(scale=1): bpo_input = gr.Textbox(lines=8, placeholder="Incolla qui il contenuto della mail o del ticket...", label="Contenuto Ticket / Email") analyze_btn_bpo = gr.Button("⚡ Analizza Richiesta", variant="primary") gr.HTML("""
🛠️ Model Architecture: NGT-BERT-Custom (DistilBERT)
📚 Training Data: Synthetic BPO Dataset (2025)
🎯 Tasks: Intent Classification (Multi-class), Entity Extraction (NER)
""") # OUTPUT with gr.Column(scale=1): with gr.Group(): gr.Markdown("#### 📋 Analisi Processata", elem_classes="h4-margin") bpo_intent_output = gr.Label(num_top_classes=3, label="Intento Rilevato") with gr.Row(): bpo_urgency_output = gr.Textbox(label="Livello Urgenza", scale=1) bpo_action_output = gr.Textbox(label="Azione Consigliata (Auto)", scale=1) gr.Markdown("#### 🔍 Dati Estratti (NER)", elem_classes="h4-margin") bpo_ner_output = gr.HTML(label="Visualizzazione Entità") gr.Examples( examples=[ ["Buongiorno, vi scrivo perché la fattura n. 99283 del mese scorso è sbagliata. Non ho consumato così tanto. Il mio codice cliente è 4599201. Attendo rettifica urgente."], ["Salve, il servizio non funziona da ieri. Mi dà errore 504 sul router. Risolvete subito per favore!"], ["Vorrei disdire il contratto con decorrenza immediata se non mi risolvete il problema."] ], inputs=bpo_input ) analyze_btn_bpo.click( bpo_dispatch_logic, inputs=bpo_input, outputs=[bpo_intent_output, bpo_urgency_output, bpo_action_output, bpo_ner_output] ) # --- AI FORECASTER --- with gr.Tab("🔮 AI Forecaster") as tab_forecast: gr.Markdown(""" # 🔮 AI Brain: Predictive Planning Modulo interattivo per la pianificazione dei turni. Confronta in tempo reale il forecast AI con i dati storici effettivi. """) with gr.Row(elem_classes="responsive-row"): with gr.Column(scale=1): gr.Markdown("### 1. Configurazione") with gr.Row(): gr.Dropdown(["Customer Care"], label="Business Unit", value="Customer Care") gr.Dropdown(["Ass. Tecnica"], label="Reparto", value="Ass. Tecnica") gr.Dropdown(["Inbound Calls"], label="Attività", value="Inbound Calls") with gr.Column(scale=1): gr.Markdown("### 2. Dati Storici") with gr.Row(): forecast_file = gr.File( label="Seleziona Export (.csv)", file_types=[".csv"], height=100, interactive=False ) with gr.Row(elem_classes="responsive-row"): forecast_btn = gr.Button("🔮 Genera\nGrafico", variant="primary", scale=1) with gr.Row(elem_classes="responsive-row"): with gr.Column(): gr.Markdown("### 📊 Dashboard Interattiva") # show_label=False rende il grafico più pulito senza il titolino grigio sopra forecast_plot = gr.Plot(show_label=False) with gr.Row(elem_classes="responsive-row"): forecast_stats = gr.Textbox(label="KPI Backtesting & Performance", lines=3) forecast_btn.click( forecast_logic, inputs=forecast_file, outputs=[forecast_plot, forecast_stats] ) # --- Sentiment Analysis (BPO) --- with gr.Tab("📢 Sentiment Analysis (BPO)") as tab_sentiment: # 1. HEADER E GUIDA UTENTE gr.Markdown(""" # 😠/😍 Analizzatore di Sentiment (Dominio Helpdesk) **ATTENZIONE:** Questo modello è **altamente specializzato** nel dominio dell'Assistenza Clienti (Telco/Energy). * ✅ **Usa questo modulo per:** Ticket di guasti, lamentele amministrative, feedback su operatori, richieste di disdetta. * ❌ **NON usare questo modulo per:** Frasi generiche ("Il cielo è blu"), recensioni di film, o linguaggio comune non tecnico. _Il modello potrebbe interpretare frasi generiche positive come negative se non contengono parole chiave del suo vocabolario specifico._ """) # 2. DETTAGLI TECNICI (Nascosti in un Accordion per pulizia) with gr.Accordion("ℹ️ Come funziona questo modello?", open=False): gr.Markdown(""" Questo sistema utilizza una rete neurale leggera addestrata su un dataset proprietario di **1.200 interazioni reali** cliente-operatore. * **Preprocessing:** Lemmatizzazione Spacy + Rimozione Stopwords (con Whitelist per le negazioni). * **Architettura:** Dense Neural Network con Dropout e L2 Regularization. * **Focus:** È calibrato per rilevare l'urgenza nascosta anche in frasi apparentemente calme. """) # 3. INTERFACCIA with gr.Row(elem_classes="responsive-row"): with gr.Column(): # Input Text sentiment_input = gr.Textbox( label="Inserisci il testo del ticket o della mail", placeholder="Es: Non funziona internet e nessuno mi risponde...", lines=3 ) # ESEMPI CLICCABILI (Fondamentali per guidare l'utente!) gr.Examples( examples=[ ["L'assistenza ricevuta è stata pessima, sono deluso."], ["Il router funziona benissimo, grazie per la velocità."], ["Non ho ancora ricevuto la fattura di gennaio."], ["Sono due giorni che ho la linea ferma, è inaccettabile!"], ["L'operatore Marco è stato gentilissimo e ha risolto tutto."] ], inputs=sentiment_input, label="Prova questi esempi BPO:" ) sentiment_btn = gr.Button("Analizza Sentiment", variant="primary") with gr.Column(): # Output Label (Percentuali) sentiment_output = gr.Label(num_top_classes=2, label="Risultato Analisi") # 4. COLLEGAMENTO FUNZIONE sentiment_btn.click( fn=binary, inputs=sentiment_input, outputs=sentiment_output ) # --- News Classification (AI Editor) --- with gr.Tab("📰 Smart Content Tagger") as tab_news: # 1. HEADER & CONTESTO gr.Markdown(""" # 🏷️ Classificazione Editoriale Automatica Questo modulo simula un **assistente editoriale AI**. Analizza il testo di un articolo o di un lancio di agenzia e suggerisce la categoria tematica corretta per l'archiviazione. * **Categorie Supportate:** `Economia`, `Politica`, `Scienza & Tecnica`, `Sport`, `Storia`. * **Tecnologia:** Deep Learning su sequenze di testo (Embedding layer). """) with gr.Row(elem_classes="responsive-row"): # COLONNA INPUT (L'Articolo) with gr.Column(scale=3): multi_input = gr.Textbox( label="Testo dell'articolo", placeholder="Incolla qui il titolo o il corpo del testo (es. news ANSA, Reuters...)", lines=6 ) # Esempi calibrati sulle tue 5 classi gr.Examples( examples=[ ["L'inflazione nell'area euro scende al 2.4%, la BCE valuta il taglio dei tassi di interesse."], # Economia ["Il Parlamento ha approvato il nuovo decreto legge con 200 voti favorevoli. Il Premier esprime soddisfazione."], # Politica ["La sonda spaziale ha inviato nuove immagini ad alta risoluzione della superficie di Marte, rivelando tracce di antichi fiumi."], # Scienza ["Finale incredibile allo stadio: la squadra di casa ribalta il risultato al 90° minuto e vola in testa alla classifica."], # Sport ["Durante gli scavi a Pompei sono emersi nuovi affreschi risalenti al I secolo d.C. perfettamente conservati."] # Storia ], inputs=multi_input, label="Prova questi lanci d'agenzia:" ) analyze_btn_multi = gr.Button("🏷️ Classifica Articolo", variant="primary") # COLONNA OUTPUT (I Tag) with gr.Column(scale=2): with gr.Group(): gr.Markdown("### 📊 Categorie Rilevate", elem_classes="h4-margin") # Usiamo un Label con top_classes=5 per vedere la distribuzione completa multi_output = gr.Label(num_top_classes=5, label="Confidenza del Modello") analyze_btn_multi.click(multi, inputs=multi_input, outputs=multi_output) # --- Chest X-Ray Diagnostics --- with gr.Tab("🩻 Chest X-Ray Diagnostics") as tab_xray: # 1. DISCLAIMER MEDICO (Fondamentale) gr.Markdown(""" # 🩻 Analisi Radiografica Toracica (Supporto Decisionale) **DISCLAIMER:** Questo modulo è un prototipo di ricerca AI. **NON sostituisce il parere di un medico.** Il sistema è addestrato per identificare pattern visivi associati a: * **Polmonite** (Pneumonia) * **Tubercolosi** (Tuberculosis) *Utilizzare gli esempi di radiografiche frontali (Chest X-Ray) recuperabili nella sidebar laterale.* """) with gr.Row(elem_classes="responsive-row"): # COLONNA INPUT with gr.Column(scale=1): image_input = gr.Image(type="numpy", label="Seleziona Radiografia", height=400, interactive=False) analyze_btn_img = gr.Button("🏥 Avvia Diagnosi AI", variant="primary") # COLONNA OUTPUT with gr.Column(scale=1): with gr.Group(): gr.Markdown("#### 📋 Referto AI", elem_classes="h4-margin") output_label = gr.Label(num_top_classes=4, label="Probabilità Patologia") analyze_btn_img.click(image, inputs=image_input, outputs=output_label) # --- Diabetic Retinopathy --- with gr.Tab("👁️ Diabetic Retinopathy") as tab_retina: gr.Markdown(""" # 👁️ Screening Retinopatia Diabetica **DISCLAIMER:** Questo modulo è un prototipo di ricerca AI. **NON sostituisce il parere di un medico.** Sistema di supporto decisionale. Analizza scansioni del fondo oculare. *Utilizzare gli esempi di retinografie digitali recuperabili nella sidebar laterale.* """) with gr.Row(elem_classes="responsive-row"): # COLONNA INPUT with gr.Column(scale=1): image_input_dr = gr.Image( type="numpy", label="Seleziona Scansione Retinica", height=400, sources=["upload", "clipboard"], interactive=False ) analyze_btn_dr = gr.Button("🏥 Analisi Fondo Oculare", variant="primary") # COLONNA OUTPUT with gr.Column(scale=1): with gr.Group(): gr.Markdown("### 📋 Esito Screening", elem_classes="h4-margin") # Output 1: La Diagnosi (Testo) output_dr_diagnosis = gr.Label(label="Diagnosi AI") # Output 2: La Percentuale (Testo/Numero) output_dr_prob = gr.Label(label="Livello di Confidenza (Rischio)") analyze_btn_dr.click( retina_detector, inputs=image_input_dr, outputs=[output_dr_diagnosis, output_dr_prob] ) ui_outputs = [main_sidebar, sidebar_explorer, image_input, image_input_dr] # 1. Click-to-Load (Rimane invariato) sidebar_explorer.change( fn=utils.global_file_loader, inputs=sidebar_explorer, outputs=[bpo_input, forecast_file, image_input, image_input_dr, multi_input, sentiment_input] ) # 2. ESET TOTALE # Questa funzione restituisce valori "vuoti" per tutti i campi sensibili def reset_all_fields(): return ( None, # 1. bpo_input None, # 2. bpo_intent None, # 3. bpo_urgency None, # 4. bpo_action None, # 5. bpo_ner None, # 6. forecast_file None, # 7. forecast_plot None, # 8. forecast_stats None, # 9. image_input None, # 10. output_label None, # 11. image_input_dr None, # 12. output_dr_diag None, # 13. output_dr_prob None, # 14. multi_input None, # 15. multi_output None, # 16. sentiment_input None # 17. sentiment_output ) reset_outputs = [ bpo_input, bpo_intent_output, bpo_urgency_output, bpo_action_output, bpo_ner_output, forecast_file, forecast_plot, forecast_stats, image_input, output_label, image_input_dr, output_dr_diagnosis, output_dr_prob, multi_input, multi_output, sentiment_input, sentiment_output ] # 3. GESTIONE CAMBIO TAB (RESET + SIDEBAR) # Per i Tab NLP: Disabilita Sidebar + Resetta TUTTO tab_bpo.select( fn=utils.disable_sidebar, outputs=ui_outputs ).then( fn=reset_all_fields, outputs=reset_outputs ) tab_forecast.select( fn=lambda: utils.enable_sidebar(PATH_FORECAST), outputs=ui_outputs ).then( fn=reset_all_fields, outputs=reset_outputs ) tab_news.select( fn=utils.disable_sidebar, outputs=ui_outputs ).then( fn=reset_all_fields, outputs=reset_outputs ) tab_sentiment.select( fn=utils.disable_sidebar, outputs=ui_outputs ).then( fn=reset_all_fields, outputs=reset_outputs ) # Per i Tab VISION: Abilita Sidebar specifica + Resetta TUTTO tab_xray.select( fn=lambda: utils.enable_sidebar(PATH_XRAY), outputs=ui_outputs ).then( fn=reset_all_fields, outputs=reset_outputs ) tab_retina.select( fn=lambda: utils.enable_sidebar(PATH_RETINA), outputs=ui_outputs ).then( fn=reset_all_fields, outputs=reset_outputs ) if __name__ == "__main__": demo.launch( server_name="0.0.0.0", server_port=7860, allowed_paths=["data"] )