EmotionScanner
Detect emotional tone in text — from user distress signals to LLM response sentiment.
When to Use This
EmotionScanner identifies emotional states expressed in text, letting you route or respond to users based on how they feel — before the LLM ever sees the message. It can also audit LLM responses for unintended emotional tone before delivery.
Common use cases: detecting angry or distressed user messages before LLM processing, routing sad or fearful messages to a human support agent, flagging high-frustration inputs for priority handling, auditing LLM responses for unintended angry or dismissive tone, building sentiment-aware moderation pipelines, and supporting mental health platforms that need to detect distress signals in real time.
Quick Example
from meshulash_guard import Guard, Action
from meshulash_guard.scanners import EmotionScanner, EmotionLabel
guard = Guard(api_key="sk-your-api-key", tenant_id="your-tenant-id")
emotion = EmotionScanner(
labels=[EmotionLabel.ANGER, EmotionLabel.FEAR],
action=Action.BLOCK,
)
result = guard.scan_input(
"I'm furious — this is completely unacceptable and I want answers NOW.",
scanners=[emotion],
)
print(result.status) # "blocked"
print(result.processed_text) # original text unchanged (Action.BLOCK keeps text)
Expected output:
Labels
EmotionScanner classifies text into 30 emotion categories. Labels are grouped into primary emotions (broad, universally recognised states) and secondary/complex emotions (nuanced or socially influenced states).
Primary Emotions
| Label | What It Detects |
|---|---|
EmotionLabel.ANGER |
Hostile, furious, or aggressive language expressing strong displeasure |
EmotionLabel.FEAR |
Expressions of being scared, threatened, or anxious about harm |
EmotionLabel.JOY |
Happiness, delight, or positive excitement |
EmotionLabel.SADNESS |
Sorrow, unhappiness, or expressions of loss |
EmotionLabel.SURPRISE |
Unexpected reactions — both positive and negative |
EmotionLabel.DISGUST |
Strong aversion or revulsion toward something |
EmotionLabel.NEUTRAL |
Emotionally flat or factual language with no strong sentiment |
Secondary and Complex Emotions
| Label | What It Detects |
|---|---|
EmotionLabel.ADMIRATION |
Respect and positive regard for someone or something |
EmotionLabel.AMUSEMENT |
Light-hearted enjoyment, humour, or entertainment |
EmotionLabel.ANNOYANCE |
Mild irritation or frustration, less intense than anger |
EmotionLabel.APPROVAL |
Agreement, endorsement, or positive assessment |
EmotionLabel.CARING |
Warmth, empathy, and concern for others' wellbeing |
EmotionLabel.CONFUSION |
Uncertainty, bewilderment, or lack of understanding |
EmotionLabel.CURIOSITY |
Interest in learning, exploring, or understanding something |
EmotionLabel.DESIRE |
Longing, wanting, or craving something |
EmotionLabel.DISAPPOINTMENT |
Let-down feelings when expectations are not met |
EmotionLabel.DISAPPROVAL |
Negative judgement or criticism of something |
EmotionLabel.EMBARRASSMENT |
Social discomfort, shame, or feeling awkward |
EmotionLabel.EXCITEMENT |
Energised anticipation or enthusiasm |
EmotionLabel.EXPECTATION |
Anticipation of a future event, neutral or positive in tone |
EmotionLabel.GRATITUDE |
Thankfulness and appreciation |
EmotionLabel.GRIEF |
Deep sorrow, mourning, or bereavement |
EmotionLabel.LOVE |
Affection, deep care, or romantic attachment |
EmotionLabel.NERVOUSNESS |
Anxiety, apprehension, or unease before an event |
EmotionLabel.OPTIMISM |
Hopefulness and confidence about the future |
EmotionLabel.PRIDE |
Satisfaction in one's own or others' achievements |
EmotionLabel.REALIZATION |
The moment of understanding or sudden insight |
EmotionLabel.RELIEF |
Ease of tension after a threat or worry is resolved |
EmotionLabel.REMORSE |
Regret and guilt over past actions |
EmotionLabel.TRUST |
Confidence and faith in someone or something |
EmotionLabel.ALL |
Shorthand to include all 30 emotion labels |
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
labels |
list[EmotionLabel] |
required | Emotion categories to detect. Cannot be empty. Use EmotionLabel.ALL to detect all categories. |
action |
Action |
Action.BLOCK |
Action when the emotion is detected. |
condition |
Condition |
Condition.ANY |
Gating condition — when the scanner triggers. |
threshold |
float |
None |
Confidence threshold (0.0–1.0). Detections below this score are ignored. Useful for tuning false-positive rates. |
allowlist |
list[str] |
None |
Values to allow through even when detected. |
Actions and Conditions
EmotionScanner defaults to Action.BLOCK to immediately reject messages matching the specified emotional states. Set threshold to tune sensitivity — lower values (e.g., 0.5) catch subtle emotional signals, while higher values (e.g., 0.85) only trigger on clearly dominant emotions.
For routing and analytics without blocking, use Action.LOG. This records detections server-side and returns status="clean" so your application continues normally. Pair Action.LOG with EmotionLabel.ALL to build a full emotion analytics dashboard over your traffic.
See the Concepts page for the full reference on Actions and Conditions.
scan_input Example
Routing distressed users to a human support agent before passing messages to an LLM:
from meshulash_guard import Guard, Action, Condition
from meshulash_guard.scanners import EmotionScanner, EmotionLabel
guard = Guard(api_key="sk-your-api-key", tenant_id="your-tenant-id")
# Block high-distress signals before the LLM sees them
emotion = EmotionScanner(
labels=[EmotionLabel.SADNESS, EmotionLabel.FEAR],
action=Action.BLOCK,
condition=Condition.ANY,
threshold=0.7,
)
messages = [
"Can you help me understand my invoice from last month?",
"I'm scared I'm going to lose everything. I don't know what to do anymore.",
]
for msg in messages:
result = guard.scan_input(msg, scanners=[emotion])
print(f"[{result.status}] {msg[:60]}")
Expected output:
[clean] Can you help me understand my invoice from last month?
[blocked] I'm scared I'm going to lose everything. I don't know w
scan_output Example
Auditing LLM responses for unintended angry or dismissive tone before returning them to users:
from meshulash_guard import Guard, Action
from meshulash_guard.scanners import EmotionScanner, EmotionLabel
guard = Guard(api_key="sk-your-api-key", tenant_id="your-tenant-id")
# Log all emotional tone in LLM responses for quality monitoring
emotion = EmotionScanner(
labels=[EmotionLabel.ALL],
action=Action.LOG,
)
# Simulated LLM responses
responses = [
"I'd be happy to help you set that up. Here's what you need to do:",
"This question has been asked countless times. Just read the documentation.",
]
for response in responses:
result = guard.scan_output(response, scanners=[emotion])
if result.status == "blocked":
print(f"Response flagged — tone review required: {response[:60]}...")
else:
print(f"Response delivered: {response[:60]}...")
Expected output: