File size: 10,506 Bytes
2539bae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
πŸ“š 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.