Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, HTTPException | |
| from pydantic import BaseModel | |
| from sentence_transformers import SentenceTransformer | |
| from huggingface_hub import hf_hub_download | |
| import joblib | |
| import json | |
| import re | |
| import os | |
| app = FastAPI(title="On-Task Participation Detector") | |
| # ββ Load model files from HuggingFace Hub ββββββββββββββββββββ | |
| REPO_ID = "ethnmcl/ontask-participation-classifier" | |
| print("Loading model files...") | |
| clf_path = hf_hub_download(repo_id=REPO_ID, filename="classifier.pkl") | |
| metadata_path = hf_hub_download(repo_id=REPO_ID, filename="metadata.json") | |
| clf = joblib.load(clf_path) | |
| metadata = json.load(open(metadata_path)) | |
| THRESHOLD = metadata.get("threshold", 0.40) | |
| print("Loading embedder...") | |
| embedder = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2") | |
| print(f"β Model loaded β threshold: {THRESHOLD}") | |
| # ββ Utils βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def clean_text(text: str) -> str: | |
| text = str(text).strip() | |
| text = re.sub(r'http\S+|www\S+', ' ', text) | |
| text = re.sub(r'<[^>]+>', ' ', text) | |
| text = re.sub(r'\s+', ' ', text) | |
| return text.strip() | |
| # ββ Request / Response schemas ββββββββββββββββββββββββββββββββ | |
| class CheckinRequest(BaseModel): | |
| yesterday_checkin: str | |
| today_checkin: str | |
| class CheckinResponse(BaseModel): | |
| on_task: bool | |
| confidence: float | |
| threshold_used: float | |
| label: str | |
| # ββ Routes ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def root(): | |
| return { | |
| "name": "On-Task Participation Detector", | |
| "repo": REPO_ID, | |
| "threshold": THRESHOLD, | |
| "auc_roc": metadata.get("auc_roc"), | |
| "status": "ready" | |
| } | |
| def health(): | |
| return {"status": "ok"} | |
| def predict(req: CheckinRequest): | |
| if not req.today_checkin.strip(): | |
| raise HTTPException(status_code=400, detail="today_checkin cannot be empty") | |
| text = f"Yesterday: {clean_text(req.yesterday_checkin)} Today: {clean_text(req.today_checkin)}" | |
| emb = embedder.encode([text]) | |
| proba = float(clf.predict_proba(emb)[0][1]) | |
| label = proba >= THRESHOLD | |
| return CheckinResponse( | |
| on_task = bool(label), | |
| confidence = round(proba, 3), | |
| threshold_used = THRESHOLD, | |
| label = "on_task" if label else "not_on_task" | |
| ) | |
| def predict_batch(requests: list[CheckinRequest]): | |
| if len(requests) > 100: | |
| raise HTTPException(status_code=400, detail="Max 100 requests per batch") | |
| texts = [ | |
| f"Yesterday: {clean_text(r.yesterday_checkin)} Today: {clean_text(r.today_checkin)}" | |
| for r in requests | |
| ] | |
| embs = embedder.encode(texts) | |
| probas = clf.predict_proba(embs)[:, 1] | |
| return [ | |
| { | |
| "on_task": bool(p >= THRESHOLD), | |
| "confidence": round(float(p), 3), | |
| "threshold_used": THRESHOLD, | |
| "label": "on_task" if p >= THRESHOLD else "not_on_task" | |
| } | |
| for p in probas | |
| ] |