Spaces:
Sleeping
Sleeping
Modello funzionante su chiamata API
Browse files- app/__pycache__/__init__.cpython-312.pyc +0 -0
- app/api/__pycache__/__init__.cpython-312.pyc +0 -0
- app/api/__pycache__/main.cpython-312.pyc +0 -0
- app/api/main.py +19 -19
- app/model/__pycache__/__init__.cpython-312.pyc +0 -0
- app/model/__pycache__/loader.cpython-312.pyc +0 -0
- app/model/loader.py +46 -0
- requirements.txt +4 -0
app/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (142 Bytes). View file
|
|
|
app/api/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (146 Bytes). View file
|
|
|
app/api/__pycache__/main.cpython-312.pyc
ADDED
|
Binary file (2.07 kB). View file
|
|
|
app/api/main.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
from fastapi import FastAPI, HTTPException
|
| 2 |
from pydantic import BaseModel
|
|
|
|
|
|
|
| 3 |
|
| 4 |
# 1. Inizializziamo l'app
|
| 5 |
app = FastAPI(
|
|
@@ -18,30 +20,28 @@ class SentimentResponse(BaseModel):
|
|
| 18 |
sentiment: str
|
| 19 |
confidence: float
|
| 20 |
|
| 21 |
-
# 3. Endpoint di
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
# Serve a capire se il container è vivo
|
| 23 |
@app.get("/health")
|
| 24 |
def health_check():
|
| 25 |
return {"status": "ok", "message": "Service is running"}
|
| 26 |
|
| 27 |
-
#
|
| 28 |
@app.post("/predict", response_model=SentimentResponse)
|
| 29 |
def predict_sentiment(request: SentimentRequest):
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
# TODO: Qui caricheremo il modello ML vero!
|
| 34 |
-
# Per ora simuliamo una risposta logica
|
| 35 |
-
print(f"Analyzing text: {request.text}")
|
| 36 |
-
|
| 37 |
-
# Logica finta (Mock) per testare l'API
|
| 38 |
-
mock_sentiment = "neutral"
|
| 39 |
-
if "ottimo" in request.text.lower():
|
| 40 |
-
mock_sentiment = "positive"
|
| 41 |
-
elif "pessimo" in request.text.lower():
|
| 42 |
-
mock_sentiment = "negative"
|
| 43 |
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from fastapi import FastAPI, HTTPException
|
| 2 |
from pydantic import BaseModel
|
| 3 |
+
# Importiamo l'istanza del modello che abbiamo appena creato
|
| 4 |
+
from app.model.loader import model_instance
|
| 5 |
|
| 6 |
# 1. Inizializziamo l'app
|
| 7 |
app = FastAPI(
|
|
|
|
| 20 |
sentiment: str
|
| 21 |
confidence: float
|
| 22 |
|
| 23 |
+
# 3. Endpoint di default (la nostra Home che consiglia reindirizzamento a docs)
|
| 24 |
+
@app.get("/")
|
| 25 |
+
def home():
|
| 26 |
+
return {"message": "Reputation Monitor API is running. Go to /docs for Swagger UI."}
|
| 27 |
+
|
| 28 |
+
# 4. Endpoint di Health Check (fondamentale per MLOps e Docker)
|
| 29 |
# Serve a capire se il container è vivo
|
| 30 |
@app.get("/health")
|
| 31 |
def health_check():
|
| 32 |
return {"status": "ok", "message": "Service is running"}
|
| 33 |
|
| 34 |
+
# 5. Endpoint di Previsione (Dummy per ora)
|
| 35 |
@app.post("/predict", response_model=SentimentResponse)
|
| 36 |
def predict_sentiment(request: SentimentRequest):
|
| 37 |
+
try:
|
| 38 |
+
# Chiamiamo la funzione predict del nostro loader
|
| 39 |
+
sentiment, confidence = model_instance.predict(request.text)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
| 41 |
+
return {
|
| 42 |
+
"sentiment": sentiment,
|
| 43 |
+
"confidence": confidence
|
| 44 |
+
}
|
| 45 |
+
except Exception as e:
|
| 46 |
+
# Se qualcosa va storto, restituiamo errore 500
|
| 47 |
+
raise HTTPException(status_code=500, detail=str(e))
|
app/model/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (148 Bytes). View file
|
|
|
app/model/__pycache__/loader.cpython-312.pyc
ADDED
|
Binary file (2.05 kB). View file
|
|
|
app/model/loader.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import AutoTokenizer, AutoModelForSequenceClassification, AutoConfig
|
| 2 |
+
import numpy as np
|
| 3 |
+
from scipy.special import softmax
|
| 4 |
+
|
| 5 |
+
# Questo è il modello specifico richiesto dall'esercizio
|
| 6 |
+
MODEL_NAME = "cardiffnlp/twitter-roberta-base-sentiment-latest"
|
| 7 |
+
|
| 8 |
+
class SentimentModel:
|
| 9 |
+
def __init__(self):
|
| 10 |
+
print(f"🔄 Loading model: {MODEL_NAME}...")
|
| 11 |
+
# Scarichiamo Tokenizer (trasforma testo in numeri) e Modello (Rete Neurale)
|
| 12 |
+
self.tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
|
| 13 |
+
self.config = AutoConfig.from_pretrained(MODEL_NAME)
|
| 14 |
+
self.model = AutoModelForSequenceClassification.from_pretrained(MODEL_NAME)
|
| 15 |
+
print("✅ Model loaded successfully!")
|
| 16 |
+
|
| 17 |
+
def predict(self, text: str):
|
| 18 |
+
# 1. Preprocessing
|
| 19 |
+
# Trasformiamo il testo in input per RoBERTa (truncation=True taglia i tweet troppo lunghi)
|
| 20 |
+
encoded_input = self.tokenizer(text, return_tensors='pt', truncation=True, max_length=512)
|
| 21 |
+
|
| 22 |
+
# 2. Inferenza (Il passaggio nella rete neurale)
|
| 23 |
+
output = self.model(**encoded_input)
|
| 24 |
+
|
| 25 |
+
# 3. Post-processing
|
| 26 |
+
# L'output sono "logits" (punteggi grezzi), usiamo Softmax per avere probabilità (0-1)
|
| 27 |
+
scores = output[0][0].detach().numpy()
|
| 28 |
+
scores = softmax(scores)
|
| 29 |
+
|
| 30 |
+
# 4. Mappatura Etichette
|
| 31 |
+
# Questo modello specifico usa l'ordine: 0 -> Negative, 1 -> Neutral, 2 -> Positive
|
| 32 |
+
labels = ["negative", "neutral", "positive"]
|
| 33 |
+
|
| 34 |
+
# Troviamo l'indice con il punteggio più alto
|
| 35 |
+
ranking = np.argsort(scores)
|
| 36 |
+
ranking = ranking[::-1] # Ordiniamo decrescente
|
| 37 |
+
|
| 38 |
+
top_label_id = ranking[0]
|
| 39 |
+
top_label = labels[top_label_id]
|
| 40 |
+
confidence = scores[top_label_id]
|
| 41 |
+
|
| 42 |
+
return top_label, float(confidence)
|
| 43 |
+
|
| 44 |
+
# Istanziamo il modello UNA VOLTA sola qui.
|
| 45 |
+
# Quando importiamo 'model_instance' negli altri file, sarà già caricato.
|
| 46 |
+
model_instance = SentimentModel()
|
requirements.txt
CHANGED
|
@@ -9,6 +9,10 @@ pydantic==2.6.0
|
|
| 9 |
pandas
|
| 10 |
scikit-learn
|
| 11 |
joblib
|
|
|
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
# --- Testing ---
|
| 14 |
pytest
|
|
|
|
| 9 |
pandas
|
| 10 |
scikit-learn
|
| 11 |
joblib
|
| 12 |
+
torch
|
| 13 |
+
transformers
|
| 14 |
+
scipy
|
| 15 |
+
numpy
|
| 16 |
|
| 17 |
# --- Testing ---
|
| 18 |
pytest
|