vichter commited on
Commit
20f81b6
·
verified ·
1 Parent(s): 1da56b9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +57 -37
app.py CHANGED
@@ -1,52 +1,72 @@
1
- from fastapi import FastAPI, HTTPException
2
- from pydantic import BaseModel
3
- from transformers import pipeline
4
- import logging
 
 
 
 
5
 
6
- logging.basicConfig(level=logging.INFO)
7
- logger = logging.getLogger(__name__)
8
 
9
- app = FastAPI(title="Panoptifi Sentiment API")
 
10
 
11
- logger.info("Loading FinBERT model...")
12
- classifier = pipeline(
13
- "sentiment-analysis",
14
- model="ProsusAI/finbert",
15
- tokenizer="ProsusAI/finbert"
16
- )
17
- logger.info("Model loaded")
18
 
 
 
19
 
20
- class TextInput(BaseModel):
21
- text: str
 
 
22
 
 
 
 
 
 
 
 
23
 
24
- class BatchInput(BaseModel):
25
- texts: list[str]
26
 
 
 
27
 
28
- class SentimentResult(BaseModel):
29
- label: str
30
- score: float
31
 
 
 
32
 
33
- @app.get("/health")
34
- def health():
35
- return {"status": "healthy", "model": "ProsusAI/finbert"}
36
 
 
 
 
37
 
38
- @app.post("/analyze", response_model=SentimentResult)
39
- def analyze(input: TextInput):
40
- if not input.text.strip():
41
- raise HTTPException(400, "Text cannot be empty")
42
- result = classifier(input.text[:2000])[0]
43
- return SentimentResult(label=result["label"], score=result["score"])
44
 
 
 
 
 
45
 
46
- @app.post("/analyze/batch", response_model=list[SentimentResult])
47
- def analyze_batch(input: BatchInput):
48
- if len(input.texts) > 50:
49
- raise HTTPException(400, "Max 50 texts per batch")
50
- texts = [t[:2000] for t in input.texts if t.strip()]
51
- results = classifier(texts)
52
- return [SentimentResult(label=r["label"], score=r["score"]) for r in results]
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Header, Depends, Request
2
+ from pydantic import BaseModel
3
+ from transformers import pipeline
4
+ from slowapi import Limiter, _rate_limit_exceeded_handler
5
+ from slowapi.util import get_remote_address
6
+ from slowapi.errors import RateLimitExceeded
7
+ import logging
8
+ import os
9
 
10
+ logging.basicConfig(level=logging.INFO)
11
+ logger = logging.getLogger(__name__)
12
 
13
+ # Rate limiter - by IP address
14
+ limiter = Limiter(key_func=get_remote_address)
15
 
16
+ app = FastAPI(title="Panoptifi Sentiment API")
17
+ app.state.limiter = limiter
18
+ app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
 
 
 
 
19
 
20
+ # API key protection
21
+ API_KEY = os.environ.get("API_KEY", "")
22
 
23
+ def verify_api_key(x_api_key: str = Header(None, alias="X-API-Key")):
24
+ if API_KEY and x_api_key != API_KEY:
25
+ raise HTTPException(status_code=401, detail="Invalid API key")
26
+ return True
27
 
28
+ logger.info("Loading FinBERT model...")
29
+ classifier = pipeline(
30
+ "sentiment-analysis",
31
+ model="ProsusAI/finbert",
32
+ tokenizer="ProsusAI/finbert"
33
+ )
34
+ logger.info("Model loaded")
35
 
 
 
36
 
37
+ class TextInput(BaseModel):
38
+ text: str
39
 
 
 
 
40
 
41
+ class BatchInput(BaseModel):
42
+ texts: list[str]
43
 
 
 
 
44
 
45
+ class SentimentResult(BaseModel):
46
+ label: str
47
+ score: float
48
 
 
 
 
 
 
 
49
 
50
+ @app.get("/health")
51
+ @limiter.limit("60/minute")
52
+ def health(request: Request):
53
+ return {"status": "healthy", "model": "ProsusAI/finbert"}
54
 
55
+
56
+ @app.post("/analyze", response_model=SentimentResult)
57
+ @limiter.limit("30/minute") # Max 30 requests per minute per IP
58
+ def analyze(request: Request, input: TextInput, _: bool = Depends(verify_api_key)):
59
+ if not input.text.strip():
60
+ raise HTTPException(400, "Text cannot be empty")
61
+ result = classifier(input.text[:2000])[0]
62
+ return SentimentResult(label=result["label"], score=result["score"])
63
+
64
+
65
+ @app.post("/analyze/batch", response_model=list[SentimentResult])
66
+ @limiter.limit("10/minute") # Batch is heavier, limit more
67
+ def analyze_batch(request: Request, input: BatchInput, _: bool = Depends(verify_api_key)):
68
+ if len(input.texts) > 50:
69
+ raise HTTPException(400, "Max 50 texts per batch")
70
+ texts = [t[:2000] for t in input.texts if t.strip()]
71
+ results = classifier(texts)
72
+ return [SentimentResult(label=r["label"], score=r["score"]) for r in results]