| import os |
| import re |
| import string |
| import emoji |
| import torch |
| import torch.nn as nn |
| from fastapi import FastAPI |
| from pydantic import BaseModel |
| import uvicorn |
|
|
| |
| |
| |
| os.environ["HF_HOME"] = "/tmp/hf_cache" |
| os.makedirs("/tmp/hf_cache", exist_ok=True) |
|
|
| |
| |
| |
| class EnhancedBERT(nn.Module): |
| def __init__(self, hidden_dropout=0.3, bert_model=None): |
| super(EnhancedBERT, self).__init__() |
| self.bert = bert_model |
| self.dropout = nn.Dropout(hidden_dropout) |
| self.fc = nn.Linear(self.bert.config.hidden_size, 2) |
|
|
| def forward(self, input_ids, attention_mask): |
| outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask) |
| pooled_output = outputs.pooler_output |
| pooled_output = self.dropout(pooled_output) |
| logits = self.fc(pooled_output) |
| return logits |
|
|
| |
| |
| |
| app = FastAPI(title="Hate Speech Detection API") |
|
|
| class TextInput(BaseModel): |
| text: str |
|
|
| device = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
| model = None |
| tokenizer = None |
| model_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Enhanced_BERT_Text.pt') |
|
|
| |
| |
| |
| @app.on_event("startup") |
| def load_model(): |
| global model, tokenizer |
|
|
| from transformers import BertModel, BertTokenizerFast |
|
|
| cache_dir = "/tmp/hf_cache" |
|
|
| |
| tokenizer = BertTokenizerFast.from_pretrained( |
| "bert-base-multilingual-cased", |
| cache_dir=cache_dir, |
| force_download=False |
| ) |
|
|
| |
| bert_model = BertModel.from_pretrained( |
| "bert-base-multilingual-cased", |
| cache_dir=cache_dir, |
| force_download=False |
| ) |
|
|
| |
| model = EnhancedBERT(bert_model=bert_model).to(device) |
|
|
| if not os.path.exists(model_path): |
| raise FileNotFoundError(f"[ERROR] Model file not found: {model_path}") |
|
|
|
|
| |
| state_dict = torch.load(model_path, map_location=device) |
| |
| new_state_dict = {} |
| for k, v in state_dict.items(): |
| if k.startswith("module."): |
| new_key = k[len("module."):] |
| else: |
| new_key = k |
| new_state_dict[new_key] = v |
| |
| model.load_state_dict(new_state_dict) |
|
|
| model.eval() |
| print("[INFO] Model loaded successfully") |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
|
|
| |
| |
|
|
| def preprocess_text(text, max_len=75): |
| encoding = tokenizer( |
| text, |
| add_special_tokens=True, |
| max_length=max_len, |
| padding='max_length', |
| truncation=True, |
| return_tensors='pt' |
| ) |
| return encoding |
|
|
| def predict_text_input(text): |
| encoding = preprocess_text(text) |
| input_ids = encoding['input_ids'].to(device) |
| attention_mask = encoding['attention_mask'].to(device) |
|
|
| with torch.no_grad(): |
| logits = model(input_ids, attention_mask) |
| probabilities = torch.softmax(logits, dim=1).cpu().numpy()[0] |
| label_idx = probabilities.argmax() |
| label = "Hate Speech" if label_idx == 1 else "Non-Hate Speech" |
| probability = probabilities[label_idx] |
|
|
| return { |
| 'prediction': label, |
| 'probability': float(probability) |
| } |
|
|
| |
| |
| |
| @app.get("/") |
| async def root(): |
| return {"message": "API is running. Use POST /predict"} |
|
|
| @app.post("/predict") |
| @app.post("/predict/") |
| async def predict_route(input_data: TextInput): |
| result = predict_text_input(input_data.text) |
| return { |
| "label": result['prediction'], |
| "probability": round(result['probability'], 4) |
| } |
|
|
| |
| |
| |
| if __name__ == "__main__": |
| uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=False) |
|
|