Spaces:
Sleeping
Sleeping
| import joblib | |
| import os | |
| from fastapi import FastAPI, HTTPException | |
| from pydantic import BaseModel | |
| # ------------------------------------------------------------------ | |
| # App setup | |
| # ------------------------------------------------------------------ | |
| app = FastAPI( | |
| title="GitHub Spam Detector API", | |
| description="Predicts whether a GitHub comment is spam (1) or not spam (0). " | |
| "Trained on 100k+ real GitHub comments using TF-IDF + LinearSVC.", | |
| version="1.0.0", | |
| ) | |
| # ------------------------------------------------------------------ | |
| # Model loading (once at startup, never per-request) | |
| # ------------------------------------------------------------------ | |
| MODEL_PATH = os.getenv("MODEL_PATH", "spam_detector_model_cv.pkl") | |
| def load_model(): | |
| global model | |
| if not os.path.exists(MODEL_PATH): | |
| raise RuntimeError(f"Model file not found at: {MODEL_PATH}") | |
| model = joblib.load(MODEL_PATH) | |
| print(f"Model loaded successfully from {MODEL_PATH}") | |
| # ------------------------------------------------------------------ | |
| # Request / Response schemas | |
| # ------------------------------------------------------------------ | |
| class PredictRequest(BaseModel): | |
| text: str | |
| class Config: | |
| json_schema_extra = { | |
| "example": { | |
| "text": "Please fix the bug at line 56, it causes a null pointer exception." | |
| } | |
| } | |
| class PredictResponse(BaseModel): | |
| text: str | |
| prediction: int # 0 = Not Spam, 1 = Spam | |
| label: str # Human-readable label | |
| # ------------------------------------------------------------------ | |
| # Endpoints | |
| # ------------------------------------------------------------------ | |
| def root(): | |
| """Health check endpoint.""" | |
| return {"status": "ok", "message": "Spam Detector API is running."} | |
| def predict(request: PredictRequest): | |
| """ | |
| Predict whether a piece of text is spam or not. | |
| - **text**: The comment / text to classify. | |
| Returns: | |
| - **prediction**: `0` (Not Spam) or `1` (Spam) | |
| - **label**: Human-readable string `"spam"` or `"not_spam"` | |
| """ | |
| if not request.text or not request.text.strip(): | |
| raise HTTPException(status_code=422, detail="Input text cannot be empty.") | |
| raw_pred = model.predict([request.text])[0] | |
| prediction = int(raw_pred) | |
| label = "spam" if prediction == 1 else "not_spam" | |
| return PredictResponse( | |
| text=request.text, | |
| prediction=prediction, | |
| label=label, | |
| ) | |