Skip to content

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:

blocked
I'm furious — this is completely unacceptable and I want answers NOW.

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:

Response delivered: I'd be happy to help you set that up. Here's w...
Response flagged — tone review required: This question has been ask...