: import gradio as gr import re from transformers import pipeline as hf_pipeline # Load SST model (temporary baseline) sst_classifier = hf_pipeline( "text-classification", model="distilbert-base-uncased-finetuned-sst-2-english", top_k=None, truncation=True ) # Load emotion classifier emotion_pipeline = hf_pipeline( "text-classification", model="j-hartmann/emotion-english-distilroberta-base", top_k=None, truncation=True ) # Lexicon enhancement preprocessing negations = {"not", "never", "no", "none", "nobody", "nothing", "neither", "nowhere", "hardly", "scarcely", "barely"} amplifiers = {"very", "really", "extremely", "so", "totally", "completely", "absolutely", "utterly", "super"} softeners = {"slightly", "somewhat", "a bit", "a little", "mildly", "fairly", "kind of"} def preprocess_sentiment_text(text): words = text.lower().split() modified = [] negate = False for word in words: stripped = re.sub(r'\W+', '', word) if stripped in negations: negate = True modified.append("") continue if stripped in amplifiers: modified.append(f"{word}") continue if stripped in softeners: modified.append(f"{word}") continue if negate: modified.append(f"{word}") negate = False else: modified.append(word) return " ".join(modified) # Emotion mapping def get_emotion_profile(text): emotions = emotion_pipeline(text) if isinstance(emotions, list) and isinstance(emotions[0], list): emotions = emotions[0] return {e['label'].lower(): round(e['score'], 3) for e in emotions} # Tone tagging logic def get_emotional_tone_tag(emotions, sentiment, patterns, abuse_score=0): sadness = emotions.get("sadness", 0) joy = emotions.get("joy", 0) neutral = emotions.get("neutral", 0) disgust = emotions.get("disgust", 0) anger = emotions.get("anger", 0) fear = emotions.get("fear", 0) if sadness > 0.4 and any(p in patterns for p in ["blame shifting", "guilt tripping", "recovery phase"]) and (sentiment == "undermining" or abuse_score > 40): return "performative regret" if (joy > 0.3 or sadness > 0.4) and any(p in patterns for p in ["control", "gaslighting"]) and sentiment == "undermining": return "coercive warmth" if (neutral + disgust) > 0.5 and any(p in patterns for p in ["dismissiveness", "projection", "obscure language"]) and sentiment == "undermining": return "cold invalidation" if (sadness + fear) > 0.5 and sentiment == "supportive" and all(p in ["recovery phase"] for p in patterns): return "genuine vulnerability" if (anger + disgust) > 0.5 and any(p in patterns for p in ["control", "threat", "insults", "dismissiveness"]) and sentiment == "undermining": return "emotional threat" if sadness > 0.6 and any(p in patterns for p in ["guilt tripping", "projection"]) and sentiment == "undermining": return "weaponized sadness" if neutral > 0.5 and any(p in patterns for p in ["dismissiveness", "obscure language"]) and sentiment == "undermining": return "toxic resignation" return None # Main function def analyze_message(text): preprocessed = preprocess_sentiment_text(text) sst_output = sst_classifier(preprocessed) sentiment = sst_output[0] sentiment_label = "supportive" if sentiment["label"] == "POSITIVE" else "undermining" sentiment_score = round(sentiment["score"] * 100, 2) emotions = get_emotion_profile(text) emotion_summary = "\n".join([f"{k.title()}: {v:.2f}" for k, v in emotions.items()]) # Temporarily pass empty abuse pattern list until Tether model is added tone_tag = get_emotional_tone_tag(emotions, sentiment_label, patterns=[]) tone_output = tone_tag if tone_tag else "None detected" return ( f"🧠 Sentiment: {sentiment_label.title()} ({sentiment_score}%)\n\n" f"🎭 Emotional Profile:\n{emotion_summary}\n\n" f"🔍 Tone Tag: {tone_output}" ) # Interface iface = gr.Interface( fn=analyze_message, inputs=gr.Textbox(lines=4, placeholder="Paste a message here..."), outputs="text", title="Tether SST + Emotional Tone Tagger", description="Applies lexicon-enhanced preprocessing, classifies sentiment, profiles emotion, and infers tone tags based on behavior logic." ) iface.launch()