File size: 2,953 Bytes
a0a882d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel, Field
from transformers import pipeline
from typing import Dict, List
from contextlib import asynccontextmanager
import torch, logging
from datetime import datetime, timezone

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("sentiment-api")

MODEL_ID = "Javeriakhalid15/my-sentiment-analyzer"
ml_models: Dict[str, object] = {}

@asynccontextmanager
async def lifespan(app: FastAPI):
    logger.info(f"Loading model: {MODEL_ID}")
    try:
        ml_models["classifier"] = pipeline(
            "sentiment-analysis", model=MODEL_ID,
            device=0 if torch.cuda.is_available() else -1,
        )
        logger.info("Model loaded.")
    except Exception as e:
        logger.error(f"Failed: {e}")
        ml_models["classifier"] = None
    yield
    ml_models.clear()

app = FastAPI(title="Sentiment Analysis API", version="1.0.0", lifespan=lifespan)
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"])

class TextRequest(BaseModel):
    text: str = Field(..., min_length=1, max_length=5000)

class BatchRequest(BaseModel):
    texts: List[str] = Field(..., min_length=1, max_length=50)

class SentimentResponse(BaseModel):
    text: str
    label: str
    confidence: float
    probabilities: Dict[str, float]
    timestamp: str

@app.get("/")
async def root():
    return {"message": "Sentiment Analysis API", "docs": "/docs", "health": "/health"}

@app.get("/health")
async def health():
    loaded = ml_models.get("classifier") is not None
    return {"status": "healthy" if loaded else "degraded", "model_loaded": loaded}

@app.post("/predict", response_model=SentimentResponse)
async def predict(request: TextRequest):
    clf = ml_models.get("classifier")
    if clf is None:
        raise HTTPException(503, "Model not loaded.")
    result = clf(request.text)[0]
    other = "LABEL_0" if result["label"] == "LABEL_1" else "LABEL_1"
    return SentimentResponse(
        text=request.text[:200],
        label=result["label"],
        confidence=round(result["score"], 4),
        probabilities={result["label"]: round(result["score"], 4), other: round(1 - result["score"], 4)},
        timestamp=datetime.now(timezone.utc).isoformat(),
    )

@app.post("/predict/batch")
async def predict_batch(request: BatchRequest):
    clf = ml_models.get("classifier")
    if clf is None:
        raise HTTPException(503, "Model not loaded.")
    results = clf(request.texts)
    return {
        "results": [{"text": t[:100], "label": r["label"], "confidence": round(r["score"], 4)}
                    for t, r in zip(request.texts, results)],
        "total": len(results),
    }

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=7860)