Faffio's picture
Final Update
2d9f3ba
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List
import csv
import os
from datetime import datetime
# Importiamo l'istanza del modello e l'istanza di GoogleNews per ricerca news
from app.model.loader import model_instance
from app.services.news_client import news_instance # Assicurati che il file si chiami news_client.py
# 1. Inizializziamo l'app
app = FastAPI(
title="Reputation Monitor API",
description="API per l'analisi del sentiment della reputazione aziendale sulla base di news estrapolate con Google di un azienda/soggetto dato in input",
version="1.0.0"
)
# --- MONITORAGGIO (Logging su CSV) ---
LOG_FILE = "reputation_logs.csv"
if not os.path.exists(LOG_FILE):
with open(LOG_FILE, mode='w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerow(["timestamp", "query", "text", "sentiment", "confidence"])
def log_prediction(query, text, sentiment, confidence):
with open(LOG_FILE, mode='a', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerow([datetime.now(), query, text, sentiment, confidence])
# --- MODELLI DATI (Pydantic) ---
# 1. Modello per la richiesta singola (/predict)
class SentimentRequest(BaseModel):
text: str
# 2. Modello per la richiesta complessa (/analyze)
class AnalysisRequest(BaseModel):
query: str
limit: int = 5
# 3. Modello per il risultato singolo (usato da entrambi)
class SingleResult(BaseModel):
text: str
sentiment: str
confidence: float
class AnalysisResponse(BaseModel):
query: str
results: List[SingleResult]
summary: dict
# --- ENDPOINTS ---
@app.get("/health")
def health_check():
# VERIFICA: Controlliamo se il modello è stato caricato in memoria
if model_instance.model is not None:
return {"status": "ok", "model_loaded": True}
raise HTTPException(status_code=503, detail="Model not loaded")
# --- ENDPOINT 1: PREVISIONE PURA (Utilizzabile per implementazioni dirette) ---
@app.post("/predict", response_model=SingleResult)
def predict_sentiment(request: SentimentRequest):
"""
Analizza un singolo testo manuale.
Utile per test unitari o integrazioni dirette.
"""
try:
sentiment, confidence = model_instance.predict(request.text)
# Logghiamo usando "MANUAL" come query per distinguerlo nel CSV
log_prediction("MANUAL_INPUT", request.text, sentiment, confidence)
return {
"text": request.text,
"sentiment": sentiment,
"confidence": confidence
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# --- ENDPOINT 2: Scarping + AI Classification
@app.post("/analyze", response_model=AnalysisResponse)
def analyze_company(request: AnalysisRequest):
# --- DEBUG PRINT ---
print(f"🔥 API RECEIVED REQUEST -> Query: {request.query}, Limit: {request.limit}")
# -------------------
"""
1. Cerca news su Google
2. Analizza il sentiment di ogni news
3. Salva i log
4. Restituisce il report completo
"""
try:
# 1. Scarica le News
news_texts = news_instance.search_news(request.query, limit=request.limit)
if not news_texts:
return {"query": request.query, "results": [], "summary": {}}
analyzed_results = []
sentiment_counts = {"positive": 0, "neutral": 0, "negative": 0}
# 2. Analizza ogni notizia col Modello
for text in news_texts:
sentiment, confidence = model_instance.predict(text)
# Aggiorna conteggi
sentiment_counts[sentiment] += 1
# Aggiungi alla lista
analyzed_results.append({
"text": text,
"sentiment": sentiment,
"confidence": confidence
})
# 3. Logga per il monitoraggio (Punto 2 dell'esercizio)
log_prediction(request.query, text, sentiment, confidence)
return {
"query": request.query,
"results": analyzed_results,
"summary": sentiment_counts
}
except Exception as e:
# Se qualcosa va storto, restituiamo errore 500
raise HTTPException(status_code=500, detail=str(e))