Spaces:
Build error
Build error
| """ | |
| NLP Evaluation API - Production Deployment | |
| ========================================== | |
| Multi-task NLP model for interview evaluation | |
| """ | |
| from fastapi import FastAPI, HTTPException | |
| from pydantic import BaseModel | |
| import torch | |
| import torch.nn as nn | |
| from transformers import RobertaTokenizer, RobertaModel | |
| import uvicorn | |
| app = FastAPI(title="NLP Evaluation API", version="1.0.0") | |
| # Model configuration | |
| TASKS = { | |
| "sentiment": {"labels": ["negative", "neutral", "positive"], "num_labels": 3}, | |
| "emotion": {"labels": ["nervous", "confident", "stressed", "calm", "motivated"], "num_labels": 5}, | |
| "communication": {"labels": ["poor", "fair", "good", "excellent"], "num_labels": 4}, | |
| "confidence_level": {"labels": ["low", "medium", "high"], "num_labels": 3}, | |
| "stress_level": {"labels": ["low", "medium", "high"], "num_labels": 3} | |
| } | |
| class MultiTaskRoBERTa(nn.Module): | |
| def __init__(self): | |
| super().__init__() | |
| self.roberta = RobertaModel.from_pretrained("roberta-base") | |
| hidden_size = 768 | |
| self.classifiers = nn.ModuleDict({ | |
| task: nn.Sequential( | |
| nn.Dropout(0.1), | |
| nn.Linear(hidden_size, hidden_size//2), | |
| nn.ReLU(), | |
| nn.Dropout(0.1), | |
| nn.Linear(hidden_size//2, info["num_labels"]) | |
| ) | |
| for task, info in TASKS.items() | |
| }) | |
| def forward(self, input_ids, attention_mask): | |
| outputs = self.roberta(input_ids=input_ids, attention_mask=attention_mask) | |
| pooled = outputs.last_hidden_state[:, 0, :] | |
| return {task: classifier(pooled) for task, classifier in self.classifiers.items()} | |
| # Load model | |
| print("🧠 Loading model...") | |
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | |
| model = MultiTaskRoBERTa().to(device) | |
| checkpoint = torch.load("best_model_ultimate.pt", map_location=device) | |
| model.load_state_dict(checkpoint["model_state_dict"]) | |
| model.eval() | |
| print(f"✅ Model loaded on {device}") | |
| # Load tokenizer | |
| print("🔤 Loading tokenizer...") | |
| tokenizer = RobertaTokenizer.from_pretrained("roberta-base") | |
| print("✅ Tokenizer loaded") | |
| class AnalyzeRequest(BaseModel): | |
| text: str | |
| class AnalyzeResponse(BaseModel): | |
| sentiment: str | |
| emotion: str | |
| communication: str | |
| confidence_level: str | |
| stress_level: str | |
| scores: dict | |
| def root(): | |
| return { | |
| "message": "NLP Evaluation API", | |
| "version": "1.0.0", | |
| "status": "running", | |
| "model": "RoBERTa-base Multi-Task (126M params)", | |
| "tasks": list(TASKS.keys()) | |
| } | |
| def health(): | |
| return {"status": "healthy", "model_loaded": True} | |
| def analyze(request: AnalyzeRequest): | |
| try: | |
| # Tokenize | |
| encoding = tokenizer( | |
| request.text, | |
| max_length=256, | |
| padding="max_length", | |
| truncation=True, | |
| return_tensors="pt" | |
| ) | |
| input_ids = encoding["input_ids"].to(device) | |
| attention_mask = encoding["attention_mask"].to(device) | |
| # Predict | |
| with torch.no_grad(): | |
| logits = model(input_ids, attention_mask) | |
| # Get predictions and scores | |
| predictions = {} | |
| scores = {} | |
| for task, task_logits in logits.items(): | |
| probs = torch.softmax(task_logits, dim=1) | |
| pred_idx = torch.argmax(probs, dim=1).item() | |
| pred_label = TASKS[task]["labels"][pred_idx] | |
| pred_score = probs[0][pred_idx].item() | |
| predictions[task] = pred_label | |
| scores[task] = round(pred_score, 4) | |
| return AnalyzeResponse( | |
| sentiment=predictions["sentiment"], | |
| emotion=predictions["emotion"], | |
| communication=predictions["communication"], | |
| confidence_level=predictions["confidence_level"], | |
| stress_level=predictions["stress_level"], | |
| scores=scores | |
| ) | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| if __name__ == "__main__": | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |