GitHub Actions
Auto-deploy new version [skip ci]
1180a53
import os
from fastapi import FastAPI, Request, Form
from pydantic import BaseModel
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from transformers import AutoTokenizer, AutoModelForSequenceClassification
from datasets import load_from_disk
import torch
import random
import subprocess
import json
# Caricamento del modello e dei dati se già scaricati
MODEL = "cardiffnlp/twitter-roberta-base-sentiment-latest"
TWEET_PROCESSED_PATH = "data/processed/tweet_eval_tokenized"
YT_PROCESSED_PATH = "data/processed/youtube_tokenized"
tokenizer = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForSequenceClassification.from_pretrained(MODEL)
labels = ["negative", "neutral", "positive"]
# TWEET EVAL
if not os.path.exists(TWEET_PROCESSED_PATH):
print(f"Dataset Tweet Eval non trovato in {TWEET_PROCESSED_PATH}. Lo genero...")
if not os.environ.get("SKIP_DATA_PREP"):
if not os.path.exists(TWEET_PROCESSED_PATH):
subprocess.run(["python", "src/data_preparation.py", "tweet_eval"], check=True)
tweet_eval = load_from_disk(TWEET_PROCESSED_PATH)
# YOUTUBE COMMENTS
if not os.path.exists(YT_PROCESSED_PATH):
print(f" Dataset YouTube non trovato in {YT_PROCESSED_PATH}. Lo genero...")
if not os.environ.get("SKIP_DATA_PREP"):
if not os.path.exists(YT_PROCESSED_PATH):
subprocess.run(["python", "src/data_preparation.py", "youtube"], check=True)
youtube_ds = load_from_disk(YT_PROCESSED_PATH)
app = FastAPI(title="Sentiment Analysis API")
templates = Jinja2Templates(directory="app_templates/")
class TextInput(BaseModel):
text: str
def predict_sentiment(text: str):
inputs = tokenizer(text, return_tensors="pt", truncation=True, padding=True)
with torch.no_grad():
outputs = model(**inputs)
probs = torch.nn.functional.softmax(outputs.logits, dim=-1)
pred = torch.argmax(probs, dim=1).item()
confidence = probs[0][pred].item()
return {"label": labels[pred], "confidence": round(confidence, 3)}
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
@app.get("/random_tweet", response_class=HTMLResponse)
def random_tweet(request: Request):
# sample = random.choice(tweet_eval["test"])
sample = tweet_eval["test"][random.randrange(len(tweet_eval["test"]))]
text = (
sample["text"]
if "text" in sample
else tokenizer.decode(sample["input_ids"], skip_special_tokens=True)
)
result = predict_sentiment(text)
true_label = labels[sample["label"]]
return templates.TemplateResponse(
"random_tweet.html",
{"request": request, "text": text, "true_label": true_label, "result": result},
)
@app.get("/predict", response_class=HTMLResponse)
def predict_page(request: Request):
return templates.TemplateResponse("predict.html", {"request": request, "result": None})
@app.post("/predict", response_class=HTMLResponse)
def predict_text(request: Request, text: str = Form(...)):
result = predict_sentiment(text)
return templates.TemplateResponse(
"predict.html", {"request": request, "text": text, "result": result}
)
@app.get("/random_youtube_comment", response_class=HTMLResponse)
def random_youtube_comment(request: Request):
sample = random.choice(youtube_ds["train"])
text = sample["text"] if "text" in sample else sample["text"]
true_label = sample["label"] if "label" in sample else "N/A"
if isinstance(true_label, int):
label_map = {0: "negative", 1: "neutral", 2: "positive"}
true_label = label_map.get(true_label, "N/A")
result = predict_sentiment(text)
return templates.TemplateResponse(
"random_youtube.html",
{"request": request, "text": text, "true_label": true_label, "result": result},
)
@app.get("/admin", response_class=HTMLResponse)
async def admin_dashboard(request: Request):
"""Pagina principale dell'area admin."""
metrics = None
metrics_path = "reports/metrics.json"
if os.path.exists(metrics_path):
with open(metrics_path, "r") as f:
metrics = json.load(f)
return templates.TemplateResponse("admin.html", {"request": request, "metrics": metrics})
@app.post("/admin/train")
async def retrain_model():
"""Lancia lo script di training."""
subprocess.run(["python", "src/train.py"], check=True)
return {"status": "Training completato"}
@app.post("/admin/monitor")
async def run_monitoring():
"""Esegue il monitoring e aggiorna metrics.json."""
subprocess.run(["python", "src/monitoring.py"], check=True)
return {"status": "Monitoring completato"}
@app.get("/admin/metrics", response_class=HTMLResponse)
def view_metrics(request: Request):
"""Visualizza i risultati del monitoring in forma tabellare e grafica."""
metrics_path = "reports/metrics.json"
metrics = None
if os.path.exists(metrics_path):
with open(metrics_path, "r") as f:
metrics = json.load(f)
return templates.TemplateResponse("metrics.html", {"request": request, "metrics": metrics})
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)