ml-services / main.py
ABHINAY2025
feat: add grievance engine, update dependencies and ML pipeline
b170a77
from fastapi import FastAPI
from pydantic import BaseModel
from semantic_engine.pipeline import process_experience as process_raw_text
from grievance_engine.preprocess import preprocess
from grievance_engine.offensiveness import classify_text
from grievance_engine.shap_explain import get_shap_values
from grievance_engine.lexicon import get_lexicon_highlights
from grievance_engine.evolving_lexicon import update_lexicon_if_needed
app = FastAPI()
# ─── Existing Experience Hub endpoint ───────────────────────────────────────
class Request(BaseModel):
text: str
@app.post("/analyze")
def analyze(req: Request):
return process_raw_text(req.text)
# ─── Grievance Module endpoint ───────────────────────────────────────────────
class GrievanceRequest(BaseModel):
text: str
@app.post("/grievance/analyze")
def analyze_grievance(req: GrievanceRequest):
"""
Analyze a student complaint for offensive/hate language.
Returns classification label + SHAP token explanations + lexicon hits.
"""
cleaned = preprocess(req.text)
analysis = classify_text(cleaned)
shap_tokens = get_shap_values(cleaned)
lexicon_hits = get_lexicon_highlights(cleaned)
# ─── Hybrid Logic: Lexicon Override ──────────────────────────────────────
# If the AI says 'neutral' but we found words in our hand-picked lexicon,
# we upgrade it to 'offensive' to ensure campus-level safety.
final_label = analysis["label"]
if final_label == "neutral" and len(lexicon_hits) > 0:
final_label = "offensive"
# Evolving lexicon β€” learns from flagged complaints over time
update_lexicon_if_needed(shap_tokens, final_label)
return {
"label": final_label, # "hate" | "offensive" | "neutral"
"score": analysis["score"], # confidence 0–1
"all_scores": analysis["all_scores"], # original AI probabilities
"shap_tokens": shap_tokens, # [{token, shap_score}]
"lexicon_hits": lexicon_hits, # [{word, start, end}]
"ai_label": analysis["label"] # show what the AI thought raw
}