vichter's picture
Update app.py
20f81b6 verified
from fastapi import FastAPI, HTTPException, Header, Depends, Request
from pydantic import BaseModel
from transformers import pipeline
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
import logging
import os
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Rate limiter - by IP address
limiter = Limiter(key_func=get_remote_address)
app = FastAPI(title="Panoptifi Sentiment API")
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
# API key protection
API_KEY = os.environ.get("API_KEY", "")
def verify_api_key(x_api_key: str = Header(None, alias="X-API-Key")):
if API_KEY and x_api_key != API_KEY:
raise HTTPException(status_code=401, detail="Invalid API key")
return True
logger.info("Loading FinBERT model...")
classifier = pipeline(
"sentiment-analysis",
model="ProsusAI/finbert",
tokenizer="ProsusAI/finbert"
)
logger.info("Model loaded")
class TextInput(BaseModel):
text: str
class BatchInput(BaseModel):
texts: list[str]
class SentimentResult(BaseModel):
label: str
score: float
@app.get("/health")
@limiter.limit("60/minute")
def health(request: Request):
return {"status": "healthy", "model": "ProsusAI/finbert"}
@app.post("/analyze", response_model=SentimentResult)
@limiter.limit("30/minute") # Max 30 requests per minute per IP
def analyze(request: Request, input: TextInput, _: bool = Depends(verify_api_key)):
if not input.text.strip():
raise HTTPException(400, "Text cannot be empty")
result = classifier(input.text[:2000])[0]
return SentimentResult(label=result["label"], score=result["score"])
@app.post("/analyze/batch", response_model=list[SentimentResult])
@limiter.limit("10/minute") # Batch is heavier, limit more
def analyze_batch(request: Request, input: BatchInput, _: bool = Depends(verify_api_key)):
if len(input.texts) > 50:
raise HTTPException(400, "Max 50 texts per batch")
texts = [t[:2000] for t in input.texts if t.strip()]
results = classifier(texts)
return [SentimentResult(label=r["label"], score=r["score"]) for r in results]