Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -39,6 +39,45 @@ THRESHOLDS = {
|
|
39 |
"projection": 0.09, "recovery phase": 0.33, "threat": 0.15
|
40 |
}
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
# ——— 3) Single-message analysis ——————————————————————————————————————————————
|
44 |
def analyze_message(text):
|
@@ -63,39 +102,58 @@ def analyze_message(text):
|
|
63 |
return {
|
64 |
"emotion_profile": emotion_profile,
|
65 |
"active_patterns": active
|
|
|
66 |
}
|
67 |
|
68 |
|
69 |
-
# ———
|
70 |
-
def analyze_composite(*texts):
|
71 |
-
"""
|
72 |
-
Accept multiple text inputs, run analyze_message on each, and
|
73 |
-
return a single formatted string.
|
74 |
-
"""
|
75 |
outputs = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
for idx, txt in enumerate(texts, start=1):
|
77 |
if not txt:
|
78 |
continue
|
79 |
r = analyze_message(txt)
|
80 |
-
|
81 |
f"── Message {idx} ──\n"
|
82 |
-
f"Emotion Profile: {r['emotion_profile']}\n"
|
83 |
-
f"Active Patterns: {r['active_patterns']}\n"
|
|
|
84 |
)
|
85 |
-
|
86 |
return "\n".join(outputs) if outputs else "Please enter at least one message."
|
87 |
|
88 |
|
89 |
-
# ———
|
90 |
-
# adjust how many message inputs you want here:
|
91 |
message_inputs = [gr.Textbox(label=f"Message {i+1}") for i in range(3)]
|
92 |
|
93 |
iface = gr.Interface(
|
94 |
fn=analyze_composite,
|
95 |
-
inputs=
|
|
|
96 |
outputs=gr.Textbox(label="Analysis"),
|
97 |
-
title="Tether Analyzer (
|
98 |
-
description="emotions, and
|
99 |
)
|
100 |
|
101 |
if __name__ == "__main__":
|
|
|
39 |
"projection": 0.09, "recovery phase": 0.33, "threat": 0.15
|
40 |
}
|
41 |
|
42 |
+
# ——— 3) Emotional-tone tagging (no abuse_score / DARVO) —————————————————————————————
|
43 |
+
def get_emotional_tone_tag(emotion_profile, patterns):
|
44 |
+
anger = emotion_profile.get("anger", 0)
|
45 |
+
disgust = emotion_profile.get("disgust", 0)
|
46 |
+
sadness = emotion_profile.get("sadness", 0)
|
47 |
+
joy = emotion_profile.get("joy", 0)
|
48 |
+
neutral = emotion_profile.get("neutral", 0)
|
49 |
+
fear = emotion_profile.get("fear", 0)
|
50 |
+
|
51 |
+
# 1) Vulnerable: sadness high + recovery-phase
|
52 |
+
if sadness > 0.4 and "recovery phase" in patterns:
|
53 |
+
return "vulnerable"
|
54 |
+
|
55 |
+
# 2) Supportive: joy very high + no other patterns (or only recovery-phase)
|
56 |
+
if joy > 0.5 and (not patterns or patterns == ["recovery phase"]):
|
57 |
+
return "supportive"
|
58 |
+
|
59 |
+
# 3) Confrontational: anger/disgust high + aggressive patterns
|
60 |
+
if (anger + disgust) > 0.5 and any(p in patterns for p in ["insults", "control", "threat"]):
|
61 |
+
return "confrontational"
|
62 |
+
|
63 |
+
# 4) Manipulative: neutral high + classic manipulation patterns
|
64 |
+
if neutral > 0.4 and any(p in patterns for p in ["gaslighting", "dismissiveness", "projection", "guilt tripping", "blame shifting"]):
|
65 |
+
return "manipulative"
|
66 |
+
|
67 |
+
# 5) Feigned Warmth: joy high but manipulative patterns present
|
68 |
+
if joy > 0.5 and any(p in patterns for p in ["gaslighting", "dismissiveness", "projection", "guilt tripping", "blame shifting"]):
|
69 |
+
return "feigned warmth"
|
70 |
+
|
71 |
+
# 6) Defensive: anger high + contradictory statements
|
72 |
+
if anger > 0.4 and "contradictory statements" in patterns:
|
73 |
+
return "defensive"
|
74 |
+
|
75 |
+
# 7) Neutral: pure neutral dominates all
|
76 |
+
if neutral > max(anger, disgust, sadness, joy, fear):
|
77 |
+
return "neutral"
|
78 |
+
|
79 |
+
return None
|
80 |
+
|
81 |
|
82 |
# ——— 3) Single-message analysis ——————————————————————————————————————————————
|
83 |
def analyze_message(text):
|
|
|
102 |
return {
|
103 |
"emotion_profile": emotion_profile,
|
104 |
"active_patterns": active
|
105 |
+
"tone_tag": tone_tag
|
106 |
}
|
107 |
|
108 |
|
109 |
+
# ——— 5) Composite wrapper (handles .txt or image + text boxes) ——————————————————————
|
110 |
+
def analyze_composite(uploaded_file, *texts):
|
|
|
|
|
|
|
|
|
111 |
outputs = []
|
112 |
+
|
113 |
+
if uploaded_file is not None:
|
114 |
+
raw = uploaded_file.read()
|
115 |
+
name = uploaded_file.name.lower()
|
116 |
+
if name.endswith((".png", ".jpg", ".jpeg", ".tiff", ".bmp", ".gif")):
|
117 |
+
img = Image.open(io.BytesIO(raw))
|
118 |
+
content = pytesseract.image_to_string(img)
|
119 |
+
else:
|
120 |
+
try:
|
121 |
+
content = raw.decode("utf-8")
|
122 |
+
except UnicodeDecodeError:
|
123 |
+
content = raw.decode("latin-1")
|
124 |
+
|
125 |
+
r = analyze_message(content)
|
126 |
+
outputs.append(
|
127 |
+
"── Uploaded File ──\n"
|
128 |
+
f"Emotion Profile : {r['emotion_profile']}\n"
|
129 |
+
f"Active Patterns : {r['active_patterns']}\n"
|
130 |
+
f"Emotional Tone : {r['tone_tag']}\n"
|
131 |
+
)
|
132 |
+
|
133 |
for idx, txt in enumerate(texts, start=1):
|
134 |
if not txt:
|
135 |
continue
|
136 |
r = analyze_message(txt)
|
137 |
+
outputs.append(
|
138 |
f"── Message {idx} ──\n"
|
139 |
+
f"Emotion Profile : {r['emotion_profile']}\n"
|
140 |
+
f"Active Patterns : {r['active_patterns']}\n"
|
141 |
+
f"Emotional Tone : {r['tone_tag']}\n"
|
142 |
)
|
143 |
+
|
144 |
return "\n".join(outputs) if outputs else "Please enter at least one message."
|
145 |
|
146 |
|
147 |
+
# ——— 6) Gradio interface ————————————————————————————————————————————————
|
|
|
148 |
message_inputs = [gr.Textbox(label=f"Message {i+1}") for i in range(3)]
|
149 |
|
150 |
iface = gr.Interface(
|
151 |
fn=analyze_composite,
|
152 |
+
inputs=gr.File(file_types=[".txt", ".png", ".jpg", ".jpeg"], label="Upload text or image")
|
153 |
+
+ message_inputs,
|
154 |
outputs=gr.Textbox(label="Analysis"),
|
155 |
+
title="Tether Analyzer (with Tone Tags)",
|
156 |
+
description="Extracts motifs, emotions, patterns—and now an emotional tone tag—no abuse score or DARVO."
|
157 |
)
|
158 |
|
159 |
if __name__ == "__main__":
|