πŸ“š Parte 1: Anatomia del Progetto (File Structure) ROOT_PROJECT/ β”‚ β”œβ”€β”€ .github/ β”‚ └── workflows/ β”‚ └── mlops_pipeline.yaml # πŸ€– Configurazione CI/CD (GitHub Actions) β”‚ β”œβ”€β”€ app/ # 🧠 BACKEND (Logica e API) β”‚ β”œβ”€β”€ api/ β”‚ β”‚ β”œβ”€β”€ __init__.py β”‚ β”‚ └── main.py # Endpoint FastAPI (/analyze, /predict) β”‚ β”œβ”€β”€ model/ β”‚ β”‚ β”œβ”€β”€ __init__.py β”‚ β”‚ └── loader.py # Caricamento Modello RoBERTa (Singleton) β”‚ └── services/ β”‚ β”œβ”€β”€ __init__.py β”‚ └── news_client.py # Scraper Google News β”‚ β”œβ”€β”€ data/ β”‚ └── new_data.csv # πŸ’Ύ Dati grezzi per il Retraining (Vuoto) β”‚ β”œβ”€β”€ src/ β”‚ └── train.py # πŸŽ“ Script di Retraining (Simulazione) β”‚ β”œβ”€β”€ streamlit_app/ # 🎨 FRONTEND β”‚ └── app.py # Dashboard Interattiva β”‚ β”œβ”€β”€ tests/ # πŸ§ͺ QUALITY ASSURANCE β”‚ └── test_api.py # Test automatici (Pytest) β”‚ β”œβ”€β”€ Dockerfile # 🐳 Istruzioni per costruire l'immagine β”œβ”€β”€ entrypoint.sh # 🚦 Script di avvio (FastAPI + Streamlit) β”œβ”€β”€ requirements.txt # πŸ“¦ Lista librerie (dipendenze) β”œβ”€β”€ reputation_logs.csv # πŸ“ Log monitoraggio (generato a runtime) └── README.md # πŸ“„ Documentazione pubblica πŸ› οΈ 1. MLOps & Automazione (Root & Github) Questi file trasformano il codice in un prodotto "vivo" e automatizzato. .github/workflows/mlops_pipeline.yaml: È il "Direttore d'Orchestra". È un file di configurazione per GitHub Actions. Ogni volta che fai git push, questo file dice a GitHub di accendere un computer, scaricare il tuo codice, lanciare i test, provare ad addestrare il modello, costruire il container Docker e spedirlo su Hugging Face. Dockerfile: È la "Ricetta". Dice a Docker come costruire il computer virtuale (Container). Specifica: "Usa Python 3.9, installa queste librerie, copia i miei file, dai i permessi all'utente". entrypoint.sh: È il "Semaforo". Docker di solito lancia un solo programma. Dato che noi vogliamo sia l'API che Streamlit, questo script Bash li avvia entrambi: prima FastAPI in background (&), poi Streamlit in primo piano. requirements.txt: La "Lista della Spesa". Elenca tutte le librerie necessarie (fastapi, streamlit, torch, GoogleNews, etc.) per far girare il progetto. 🧠 2. Il Backend (Cartella app/) Il cervello del sistema che fa i calcoli. app/api/main.py: Il "Centralino". Crea l'API con FastAPI. Definisce gli endpoint (es. /analyze, /health). Riceve le richieste dal frontend, coordina lo scraper e il modello, salva i log e risponde con i dati JSON. app/services/news_client.py: L' "Investigatore". Contiene la classe che usa GoogleNews. Cerca le notizie, gestisce la paginazione, prova prima in inglese e poi fa fallback in italiano se non trova nulla. app/model/loader.py: Il "Magazziniere". Si occupa di caricare il pesante modello RoBERTa in memoria una volta sola all'avvio (Singleton Pattern), evitando che il server esploda ricaricandolo a ogni richiesta. 🎨 3. Il Frontend (Cartella streamlit_app/) La faccia che vede l'utente. streamlit_app/app.py: L' "Interfaccia". È il sito web. Disegna i grafici, le barre di input e le tabelle. Non fa calcoli pesanti: prende l'input dell'utente, lo manda all'API (requests.post) e visualizza la risposta. πŸŽ“ 4. Continuous Training (Cartella src/ & data/) La parte che gestisce l'evoluzione del modello. src/train.py: Il "Simulatore". È lo script che verrebbe lanciato per ri-addestrare il modello. Controlla se ci sono nuovi dati e simula il processo di fine-tuning (poichΓ© su GitHub non abbiamo GPU). data/new_data.csv: Il "Carburante". È il file (attualmente vuoto) dove dovrebbero finire i dati etichettati per il retraining. πŸ§ͺ 5. Testing & Logs tests/: Contiene i test automatici (test_api.py) che verificano se l'API risponde correttamente. reputation_logs.csv: Il "Diario di Bordo". Viene creato automaticamente dall'API. Ogni volta che qualcuno fa una previsione, viene scritta una riga qui. Streamlit legge questo file per la tab "Monitoring". πŸ”„ Parte 2: I Flussi Logici (Architettura) Qui disegniamo come si muovono i dati e le decisioni. A. Architettura del Container (Come girano insieme) Questo schema mostra come abbiamo risolto il problema di avere due programmi (Backend e Frontend) nello stesso spazio. Snippet di codice graph TD User((Utente su Internet)) subgraph "Docker Container (Hugging Face Space)" direction TB Entry[entrypoint.sh] subgraph "Processo 1 (Backend)" FastAPI[FastAPI Server :8000] Model[RoBERTa AI] Scraper[Google News Scraper] end subgraph "Processo 2 (Frontend)" Streamlit[Streamlit App :7860] end Entry -->|Avvia in background| FastAPI Entry -->|Avvia in primo piano| Streamlit Streamlit <-->|HTTP Request (localhost)| FastAPI FastAPI <--> Model FastAPI --> Scraper end User <-->|Vede solo porta 7860| Streamlit Scraper <-->|Cerca Info| Google(Google Web) Come fanno a convivere due programmi nello stesso container su Hugging Face? **Spiegazione del processo** - **Panoramica:** L'app Γ¨ composta da due processi che convivono nello stesso container: un backend che espone un'API per l'analisi dei testi e un frontend Streamlit che fornisce l'interfaccia utente. Lo scopo Γ¨ permettere allo user-facing frontend di richiedere analisi al backend in locale, mantenendo il modello in memoria per efficienza. - **Esecuzione nel container:** Al container viene eseguito uno script di avvio che: - avvia il server API in background; - avvia l'app Streamlit in primo piano; - mantiene Streamlit come processo principale esposto all'utente (porta pubblica), mentre l'API Γ¨ raggiungibile in locale (porta interna). - **Flusso dell'API (/analyze):** - **Input:** richiesta JSON contenente la query e il numero massimo di risultati. - **Scraping:** il servizio ricerca notizie (prima in inglese, poi fallback in italiano), raccoglie titoli e descrizioni e pre-processa il testo. - **Inference:** ogni testo viene passato al modello (caricato una sola volta all'avvio) per ottenere la predizione di sentimento e la probabilitΓ . - **Logging:** ogni previsione viene registrata in un log (CSV) con timestamp, input e risultato per monitoring e retraining. - **Output:** la risposta JSON contiene le statistiche aggregate (conteggi, percentuali) e la lista di risultati analizzati. - **Retraining continuo (simulato):** - Periodicamente o a seguito di nuovi dati, lo script di retraining verifica la presenza di dati etichettati. - Se non ci sono dati nuovi, il retraining viene saltato senza interrompere la pipeline. - Se ci sono dati, viene eseguita una simulazione di fine-tuning e i risultati vengono testati automaticamente. - **Pipeline CI/CD (sintesi):** - **Trigger:** un push sul repository avvia la pipeline. - **Job 1 β€” QualitΓ  & Training:** installa dipendenze, lancia la simulazione di retraining (se necessario) e poi esegue i test automatici. Se i test falliscono, la pipeline si blocca. - **Job 2 β€” Packaging:** solo se i test passano, viene costruita l'immagine Docker e (opzionalmente) pubblicata su un registry. - **Job 3 β€” Deploy:** se il packaging ha successo, l'immagine viene distribuita alla piattaforma di hosting (es. Space). Al termine l'app aggiornata Γ¨ disponibile online. - **Precisione operativa:** il retraining Γ¨ condizionale (salta se mancano dati); l'esecuzione dei test Γ¨ il gate principale che previene il deploy di codice rotto. B. Il Flusso dell'API (/analyze) Cosa succede esattamente quando l'utente clicca "Analyze"? 1. INPUT: Arriva richiesta JSON {"query": "Tesla", "limit": 5}. 2. SCRAPING: Cerco "Tesla" su Google News (EN). Scarico Titoli + Descrizioni. LOOP (Ciclo For): Per ogni notizia trovata: Pulisco il testo. Inference: Passo il testo a RoBERTa -> Ottengo "Positive" (0.98). Logging: Scrivo su reputation_logs.csv. Aggiorno i contatori (es. Positive +1). 3. OUTPUT: Restituisco JSON con statistiche e lista risultati. C. La Pipeline CI/CD (Il file YAML) Cosa succede su GitHub quando fai git push? È una catena di montaggio. Snippet di codice Push[Git Push] -->|Trigger| GitHubActions Questo Γ¨ il trigger, quando fascio push sul ramo main. subgraph "Job 1: Quality & Training" Job centrale per il controllo e retraining del modello (se non passa i test questo viene bloccato il commit) Install[Install Dependencies] --> Retrain[Simulazione Retraining] Prima di tutto installa le dipendenze, poi fa il retrain Retrain --> Test[Run Pytest] Fatto il retrain, eseguiamo il test con pytest (Se fallisce qui, BLOCCA TUTTO πŸ›‘). end subgraph "Job 2: Packaging" Test -->|Se Verde| Build[Docker Build] Build --> PushHub[Push to DockerHub] end subgraph "Job 3: Deploy" PushHub -->|Se Verde| Deploy[Deploy to Hugging Face] end Deploy -->|Fine| LiveApp((App Aggiornata)) Punto Critico: Se Run Pytest fallisce (X Rossa), il Docker Build non parte nemmeno. Questo protegge la produzione da codice rotto. Punto Intelligente: Il retraining (Job 1) controlla se new_data.csv Γ¨ vuoto. Se Γ¨ vuoto, dice "Skipping" e prosegue senza rompere nulla.