Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -98,6 +98,47 @@ def generate_risk_snippet(abuse_score, top_label):
|
|
98 |
title, summary, advice = RISK_SNIPPETS[risk_level]
|
99 |
return f"\n\n{title}\n{summary} (Pattern: **{top_label}**)\n💡 {advice}"
|
100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
# --- Escalation Quiz Questions & Weights ---
|
102 |
ESCALATION_QUESTIONS = [
|
103 |
("Partner has access to firearms or weapons", 4),
|
@@ -150,6 +191,12 @@ def analyze_composite(msg1, msg2, msg3, *answers_and_none):
|
|
150 |
out = f"Abuse Intensity: {composite_abuse}%\n"
|
151 |
out += f"Escalation Potential: {escalation_level} ({escalation_score}/{sum(w for _,w in ESCALATION_QUESTIONS)})"
|
152 |
out += generate_risk_snippet(composite_abuse, top_pattern)
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
return out
|
154 |
|
155 |
textbox_inputs = [
|
@@ -170,4 +217,4 @@ iface = gr.Interface(
|
|
170 |
)
|
171 |
|
172 |
if __name__ == "__main__":
|
173 |
-
iface.launch()
|
|
|
98 |
title, summary, advice = RISK_SNIPPETS[risk_level]
|
99 |
return f"\n\n{title}\n{summary} (Pattern: **{top_label}**)\n💡 {advice}"
|
100 |
|
101 |
+
# --- DARVO Detection ---
|
102 |
+
DARVO_PATTERNS = {
|
103 |
+
"blame shifting", "projection", "dismissiveness", "guilt tripping", "contradictory statements"
|
104 |
+
}
|
105 |
+
DARVO_MOTIFS = [
|
106 |
+
"i guess i’m the bad guy", "after everything i’ve done", "you always twist everything",
|
107 |
+
"so now it’s all my fault", "i’m the villain", "i’m always wrong", "you never listen",
|
108 |
+
"you’re attacking me", "i’m done trying", "i’m the only one who cares"
|
109 |
+
]
|
110 |
+
|
111 |
+
def detect_contradiction(message):
|
112 |
+
contradiction_flag = False
|
113 |
+
contradiction_phrases = [
|
114 |
+
(r"\b(i love you).{0,15}(i hate you|you ruin everything)", re.IGNORECASE),
|
115 |
+
(r"\b(i’m sorry).{0,15}(but you|if you hadn’t)", re.IGNORECASE),
|
116 |
+
(r"\b(i’m trying).{0,15}(you never|why do you)", re.IGNORECASE),
|
117 |
+
(r"\b(do what you want).{0,15}(you’ll regret it|i always give everything)", re.IGNORECASE),
|
118 |
+
(r"\b(i don’t care).{0,15}(you never think of me)", re.IGNORECASE),
|
119 |
+
(r"\b(i guess i’m just).{0,15}(the bad guy|worthless|never enough)", re.IGNORECASE),
|
120 |
+
]
|
121 |
+
for pattern, flags in contradiction_phrases:
|
122 |
+
if re.search(pattern, message, flags):
|
123 |
+
contradiction_flag = True
|
124 |
+
break
|
125 |
+
return contradiction_flag
|
126 |
+
|
127 |
+
def calculate_darvo_score(patterns, sentiment_before, sentiment_after, motifs_found, contradiction_flag=False):
|
128 |
+
pattern_hits = len([p.lower() for p in patterns if p.lower() in DARVO_PATTERNS])
|
129 |
+
pattern_score = pattern_hits / len(DARVO_PATTERNS)
|
130 |
+
sentiment_shift_score = max(0.0, sentiment_after - sentiment_before)
|
131 |
+
motif_hits = len([m.lower() for m in motifs_found if m.lower() in DARVO_MOTIFS])
|
132 |
+
motif_score = motif_hits / len(DARVO_MOTIFS)
|
133 |
+
contradiction_score = 1.0 if contradiction_flag else 0.0
|
134 |
+
darvo_score = (
|
135 |
+
0.3 * pattern_score +
|
136 |
+
0.3 * sentiment_shift_score +
|
137 |
+
0.25 * motif_score +
|
138 |
+
0.15 * contradiction_score
|
139 |
+
)
|
140 |
+
return round(min(darvo_score, 1.0), 3)
|
141 |
+
|
142 |
# --- Escalation Quiz Questions & Weights ---
|
143 |
ESCALATION_QUESTIONS = [
|
144 |
("Partner has access to firearms or weapons", 4),
|
|
|
191 |
out = f"Abuse Intensity: {composite_abuse}%\n"
|
192 |
out += f"Escalation Potential: {escalation_level} ({escalation_score}/{sum(w for _,w in ESCALATION_QUESTIONS)})"
|
193 |
out += generate_risk_snippet(composite_abuse, top_pattern)
|
194 |
+
|
195 |
+
avg_darvo = round(sum([r[3] for r in results]) / len(results), 3)
|
196 |
+
if avg_darvo > 0.25:
|
197 |
+
darvo_descriptor = "moderate" if avg_darvo < 0.65 else "high"
|
198 |
+
out += f"\n\nDARVO Score: {avg_darvo} → This indicates a **{darvo_descriptor} likelihood** of narrative reversal (DARVO), where the speaker may be denying, attacking, or reversing blame."
|
199 |
+
|
200 |
return out
|
201 |
|
202 |
textbox_inputs = [
|
|
|
217 |
)
|
218 |
|
219 |
if __name__ == "__main__":
|
220 |
+
iface.launch()
|