Spaces:
Running
Running
import gradio as gr | |
import torch | |
import numpy as np | |
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM | |
from transformers import RobertaForSequenceClassification, RobertaTokenizer | |
from motif_tagging import detect_motifs | |
import re | |
# --- Sentiment Model: T5-based Emotion Classifier --- | |
sentiment_tokenizer = AutoTokenizer.from_pretrained("mrm8488/t5-base-finetuned-emotion") | |
sentiment_model = AutoModelForSeq2SeqLM.from_pretrained("mrm8488/t5-base-finetuned-emotion") | |
EMOTION_TO_SENTIMENT = { | |
"joy": "supportive", | |
"love": "supportive", | |
"surprise": "supportive", | |
"neutral": "supportive", | |
"sadness": "undermining", | |
"anger": "undermining", | |
"fear": "undermining", | |
"disgust": "undermining", | |
"shame": "undermining", | |
"guilt": "undermining" | |
} | |
# --- Abuse Detection Model --- | |
model_name = "SamanthaStorm/autotrain-jlpi4-mllvp" | |
model = RobertaForSequenceClassification.from_pretrained(model_name, trust_remote_code=True) | |
tokenizer = RobertaTokenizer.from_pretrained(model_name, trust_remote_code=True) | |
LABELS = [ | |
"blame shifting", "contradictory statements", "control", "dismissiveness", | |
"gaslighting", "guilt tripping", "insults", "obscure language", | |
"projection", "recovery phase", "threat" | |
] | |
THRESHOLDS = { | |
"blame shifting": 0.3, | |
"contradictory statements": 0.32, | |
"control": 0.48, | |
"dismissiveness": 0.45, | |
"gaslighting": 0.30, | |
"guilt tripping": 0.20, | |
"insults": 0.34, | |
"obscure language": 0.25, | |
"projection": 0.35, | |
"recovery phase": 0.25, | |
"threat": 0.25 | |
} | |
PATTERN_WEIGHTS = { | |
"gaslighting": 1.3, | |
"control": 1.2, | |
"dismissiveness": 0.8, | |
"blame shifting": 0.8, | |
"contradictory statements": 0.75 | |
} | |
EXPLANATIONS = { | |
"blame shifting": "Blame-shifting is when one person redirects responsibility onto someone else to avoid accountability.", | |
"contradictory statements": "Contradictory statements confuse the listener by flipping positions or denying previous claims.", | |
"control": "Control restricts another person’s autonomy through coercion, manipulation, or threats.", | |
"dismissiveness": "Dismissiveness is belittling or disregarding another person’s feelings, needs, or opinions.", | |
"gaslighting": "Gaslighting involves making someone question their own reality, memory, or perceptions.", | |
"guilt tripping": "Guilt-tripping uses guilt to manipulate someone’s actions or decisions.", | |
"insults": "Insults are derogatory or demeaning remarks meant to shame, belittle, or hurt someone.", | |
"obscure language": "Obscure language manipulates through complexity, vagueness, or superiority to confuse the other person.", | |
"projection": "Projection accuses someone else of the very behaviors or intentions the speaker is exhibiting.", | |
"recovery phase": "Recovery phase statements attempt to soothe or reset tension without acknowledging harm or change.", | |
"threat": "Threats use fear of harm (physical, emotional, or relational) to control or intimidate someone." | |
} | |
RISK_SNIPPETS = { | |
"low": ( | |
"🟢 Risk Level: Low", | |
"The language patterns here do not strongly indicate abuse.", | |
"Continue to check in with yourself and notice how you feel in response to repeated patterns." | |
), | |
"moderate": ( | |
"⚠️ Risk Level: Moderate to High", | |
"This language includes control, guilt, or reversal tactics.", | |
"These patterns often lead to emotional confusion and reduced self-trust. Document these messages or talk with someone safe." | |
), | |
"high": ( | |
"🛑 Risk Level: High", | |
"Language includes threats or coercive control, which are strong indicators of escalation.", | |
"Consider creating a safety plan or contacting a support line. Trust your sense of unease." | |
) | |
} | |
def generate_risk_snippet(abuse_score, top_label): | |
if abuse_score >= 85: | |
risk_level = "high" | |
elif abuse_score >= 60: | |
risk_level = "moderate" | |
else: | |
risk_level = "low" | |
title, summary, advice = RISK_SNIPPETS[risk_level] | |
return f"\n\n{title}\n{summary} (Pattern: **{top_label}**)\n💡 {advice}" | |
# --- Escalation Quiz Questions & Weights --- | |
ESCALATION_QUESTIONS = [ | |
("Partner has access to firearms or weapons", 4), | |
("Partner threatened to kill you", 3), | |
("Partner threatened you with a weapon", 3), | |
("Partner ever choked or strangled you", 4), | |
("Partner injured or threatened your pet(s)", 3), | |
("Partner destroyed property to intimidate you", 2), | |
("Partner forced you into unwanted sexual acts", 3), | |
("Partner threatened to take away your children", 2), | |
("Violence has increased in frequency or severity", 3), | |
("Partner monitors your calls/GPS/social media", 2) | |
] | |
# --- Core Analysis Functions (unchanged) --- | |
# ... (analyze_single_message, calculate_darvo_score, etc.) | |
# --- Composite Analysis with Escalation Quiz --- | |
def analyze_composite(msg1, msg2, msg3, *answers_and_none): | |
# split args: first len(ESCALATION_QUESTIONS) are checkboxes, last is none_of_above | |
responses = answers_and_none[:len(ESCALATION_QUESTIONS)] | |
none_selected = answers_and_none[-1] | |
# compute escalation score | |
if none_selected: | |
escalation_score = 0 | |
else: | |
escalation_score = sum(w for (_, w), a in zip(ESCALATION_QUESTIONS, responses) if a) | |
# bucket | |
if escalation_score >= 16: | |
escalation_level = "High" | |
elif escalation_score >= 8: | |
escalation_level = "Moderate" | |
else: | |
escalation_level = "Low" | |
# existing abuse analysis | |
thresholds = THRESHOLDS.copy() | |
messages = [msg1, msg2, msg3] | |
active = [m for m in messages if m.strip()] | |
if not active: | |
return "Please enter at least one message." | |
results = [analyze_single_message(m, thresholds, []) for m in active] | |
abuse_scores = [r[0] for r in results] | |
top_pattern = max({label for r in results for label in r[2]}, key=lambda l: abuse_scores[0]) | |
composite_abuse = round(sum(abuse_scores)/len(abuse_scores),2) | |
# build output | |
out = f"Abuse Intensity: {composite_abuse}%\n" | |
out += f"Escalation Potential: {escalation_level} ({escalation_score}/{sum(w for _,w in ESCALATION_QUESTIONS)})" | |
# abuse snippet | |
out += generate_risk_snippet(composite_abuse, top_pattern) | |
return out | |
# --- Gradio Interface --- | |
textbox_inputs = [ | |
gr.Textbox(label="Message 1"), | |
gr.Textbox(label="Message 2"), | |
gr.Textbox(label="Message 3") | |
] | |
# Escalation quiz inputs | |
quiz_boxes = [gr.Checkbox(label=q) for q, _ in ESCALATION_QUESTIONS] | |
none_box = gr.Checkbox(label="None of the above") | |
iface = gr.Interface( | |
fn=analyze_composite, | |
inputs=textbox_inputs + quiz_boxes + [none_box], | |
outputs=gr.Textbox(label="Results"), | |
title="Abuse Pattern Detector + Escalation Quiz", | |
allow_flagging="manual" | |
) | |
if __name__ == "__main__": | |
iface.launch() | |