nlp-analysis-api / lib /routes.py
karim323's picture
Fix HF Spaces deployment: use port 7860, async model loading, immediate health checks
b82bbd8
"""
API routes for the NLP application
"""
from fastapi import APIRouter, HTTPException, Depends, Request
from lib.models import (
ParaphraseResponse,
SummarizationResponse,
TextInput,
BatchTextInput,
TranslationInput,
SentimentResponse,
TranslationResponse,
NERResponse,
BatchSentimentResponse
)
from lib.services import ParaphraseService, SentimentService, NERService, SummarizationService, TranslationService
from lib.rate_limiter import limiter
# Create router
router = APIRouter()
def get_sentiment_service() -> SentimentService:
"""Dependency to get sentiment service"""
from main import sentiment_service
return sentiment_service
def get_ner_service() -> NERService:
"""Dependency to get NER service"""
from main import ner_service
return ner_service
def get_translation_service() -> TranslationService:
"""Dependency to get translation service"""
from main import translation_service
return translation_service
def get_paraphrase_service() -> ParaphraseService:
"""Dependency to get paraphrase service"""
from main import paraphrase_service
return paraphrase_service
def get_summarization_service() -> SummarizationService:
"""Dependency to get summarization service"""
from main import summarization_service
return summarization_service
# Health check endpoints
@router.get("/")
@limiter.limit("60/minute")
async def root(request: Request):
"""Basic API status endpoint"""
return {"message": "NLP Analysis API is running!", "version": "2.0.0"}
@router.get("/health")
@limiter.limit("30/minute")
async def health_check(request: Request):
"""Detailed health check endpoint with model status"""
# Always return healthy - models load in background
# This allows HF Spaces health checks to pass immediately
try:
from main import sentiment_model, ner_model, paraphrase_model, summarization_model
return {
"status": "healthy",
"message": "API is running. Models may still be loading.",
"models": {
"sentiment": sentiment_model.is_loaded() if sentiment_model else False,
"ner": ner_model.is_loaded() if ner_model else False,
"paraphrase": paraphrase_model.is_loaded() if paraphrase_model else False,
"summarization": summarization_model.is_loaded() if summarization_model else False
}
}
except Exception:
# Even if models aren't initialized yet, return healthy
# This ensures HF Spaces health checks pass
return {
"status": "healthy",
"message": "API is starting. Models loading in background.",
"models": {
"sentiment": False,
"ner": False,
"paraphrase": False,
"summarization": False
}
}
# Sentiment analysis endpoints
@router.post("/analyze", response_model=SentimentResponse)
@limiter.limit("20/minute")
async def analyze_sentiment(
request: Request,
input_data: TextInput,
service: SentimentService = Depends(get_sentiment_service)
):
"""
Analyze the sentiment of the provided text
Rate limited to 20 requests per minute per IP
"""
try:
return service.analyze_sentiment(input_data.text)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Analysis failed: {str(e)}")
@router.post("/analyze-batch", response_model=BatchSentimentResponse)
@limiter.limit("10/minute")
async def analyze_batch_sentiment(
request: Request,
input_data: BatchTextInput,
service: SentimentService = Depends(get_sentiment_service)
):
"""
Analyze sentiment for multiple texts at once
Rate limited to 10 requests per minute (more expensive operation)
"""
try:
results = service.analyze_batch(input_data.texts)
return BatchSentimentResponse(results=results)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Batch analysis failed: {str(e)}")
# NER endpoints
@router.post("/ner", response_model=NERResponse)
@limiter.limit("15/minute")
async def extract_entities(
request: Request,
input_data: TextInput,
service: NERService = Depends(get_ner_service)
):
"""
Extract named entities from the provided text
Rate limited to 15 requests per minute (compute-intensive)
"""
try:
return service.extract_entities(input_data.text)
except Exception as e:
raise HTTPException(status_code=500, detail=f"NER failed: {str(e)}")
# Translation endpoints
@router.post("/translate", response_model=TranslationResponse)
@limiter.limit("15/minute")
async def translate_text(
request: Request,
input_data: TranslationInput,
service: TranslationService = Depends(get_translation_service)
):
"""
Translate text from source language to target language
Rate limited to 15 requests per minute (loads models dynamically)
"""
try:
translated_text = service.translate(
input_data.text,
input_data.source_lang,
input_data.target_lang
)
return TranslationResponse(translated_text=translated_text)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))
except Exception as e:
raise HTTPException(status_code=500, detail=f"Translation failed: {str(e)}")
# Paraphrasing endpoints
@router.post("/paraphrase", response_model=ParaphraseResponse)
@limiter.limit("15/minute")
async def paraphrase_text(
request: Request,
input_data: TextInput,
service: ParaphraseService = Depends(get_paraphrase_service)
):
"""
Paraphrase the provided text
Rate limited to 15 requests per minute
"""
try:
return service.paraphrase(input_data.text)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Paraphrasing failed: {str(e)}")
# Summarization endpoints
@router.post("/summarize", response_model=SummarizationResponse)
@limiter.limit("15/minute")
async def summarize_text(
request: Request,
input_data: TextInput,
service: SummarizationService = Depends(get_summarization_service)
):
"""
Summarize the provided text
Rate limited to 15 requests per minute
"""
try:
return service.summarize(input_data.text)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Summarization failed: {str(e)}")