Detect Emotions in Text
Emotion detection goes beyond positive/negative sentiment. It classifies text into specific emotional categories: happiness, anger, sadness, fear, and neutral. This gives applications a deeper understanding of user intent and tone. LM-Kit.NET's EmotionDetection class provides this capability with confidence scoring, neutral support, and cancellation token support, all running locally.
Why Emotion Detection Matters
Two enterprise problems that on-device emotion detection solves:
- Customer support triage. Routing angry customers to senior agents vs happy ones to upsell flows requires understanding the specific emotion, not just polarity. Emotion detection lets you build routing rules that match the customer's actual state to the right response team.
- Employee engagement monitoring. Detecting fear or sadness patterns in internal surveys without sending data to the cloud keeps sensitive HR data on-premises. Local emotion analysis lets you surface trends across teams without creating privacy risks.
Prerequisites
| Requirement | Minimum |
|---|---|
| .NET SDK | 8.0+ |
| VRAM | 2+ GB |
| Disk | ~2 GB free for model download |
Step 1: Create the Project
dotnet new console -n EmotionQuickstart
cd EmotionQuickstart
dotnet add package LM-Kit.NET
Step 2: Basic Emotion Detection
using System.Text;
using LMKit.Model;
using LMKit.TextAnalysis;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// ──────────────────────────────────────
// 1. Load model
// ──────────────────────────────────────
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("gemma3:1b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// ──────────────────────────────────────
// 2. Create emotion detector
// ──────────────────────────────────────
var detector = new EmotionDetection(model)
{
NeutralSupport = true // enable neutral category
};
// ──────────────────────────────────────
// 3. Analyze sample texts
// ──────────────────────────────────────
string[] texts =
{
"I'm thrilled with the new features in this release!",
"This is completely unacceptable. I want a refund immediately.",
"I lost my job today and I don't know what to do.",
"What if the system crashes during the demo tomorrow?",
"The package arrived on Tuesday as expected."
};
Console.WriteLine("Emotion Detection Results:\n");
foreach (string text in texts)
{
EmotionDetection.EmotionCategory emotion = detector.GetEmotionCategory(text);
float confidence = detector.Confidence;
Console.WriteLine($" Text: \"{text}\"");
Console.WriteLine($" Emotion: {emotion} (confidence: {confidence:F2})\n");
}
Expected output:
Text: "I'm thrilled with the new features in this release!"
Emotion: Happiness (confidence: 0.95)
Text: "This is completely unacceptable. I want a refund immediately."
Emotion: Anger (confidence: 0.92)
Text: "I lost my job today and I don't know what to do."
Emotion: Sadness (confidence: 0.89)
Text: "What if the system crashes during the demo tomorrow?"
Emotion: Fear (confidence: 0.84)
Text: "The package arrived on Tuesday as expected."
Emotion: Neutral (confidence: 0.91)
Step 3: Batch Processing with Async
Process a file of customer reviews asynchronously and generate a summary report:
using System.Text;
using LMKit.Model;
using LMKit.TextAnalysis;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// ──────────────────────────────────────
// 1. Load model
// ──────────────────────────────────────
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("gemma3:1b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// ──────────────────────────────────────
// 2. Create emotion detector
// ──────────────────────────────────────
var detector = new EmotionDetection(model)
{
NeutralSupport = true // enable neutral category
};
// Process a batch of customer reviews asynchronously
string[] reviews = File.ReadAllLines("reviews.txt");
var results = new List<(string Text, EmotionDetection.EmotionCategory Emotion, float Confidence)>();
foreach (string review in reviews)
{
if (string.IsNullOrWhiteSpace(review)) continue;
var emotion = await detector.GetEmotionCategoryAsync(review);
results.Add((review, emotion, detector.Confidence));
}
// Group by emotion category
var grouped = results.GroupBy(r => r.Emotion);
Console.WriteLine("── Emotion Summary ──\n");
foreach (var group in grouped.OrderByDescending(g => g.Count()))
{
Console.WriteLine($" {group.Key,-12} {group.Count(),4} reviews (avg confidence: {group.Average(r => r.Confidence):F2})");
}
Step 4: Binary Emotion Mode (Without Neutral)
When you need every input classified into a specific emotion, disable NeutralSupport to force the model to pick one of the four core categories:
using System.Text;
using LMKit.Model;
using LMKit.TextAnalysis;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// ──────────────────────────────────────
// 1. Load model
// ──────────────────────────────────────
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("gemma3:1b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
var binaryDetector = new EmotionDetection(model)
{
NeutralSupport = false // only: Happiness, Anger, Sadness, Fear
};
This is useful when ambiguous inputs should still receive a definitive classification. The model will select the closest matching emotion even for neutral-sounding text.
Step 5: Emotion-Based Routing
Use detected emotions to route customer messages to the appropriate support queue:
using System.Text;
using LMKit.Model;
using LMKit.TextAnalysis;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// ──────────────────────────────────────
// 1. Load model
// ──────────────────────────────────────
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("gemma3:1b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// ──────────────────────────────────────
// 2. Create emotion detector
// ──────────────────────────────────────
var detector = new EmotionDetection(model)
{
NeutralSupport = true // enable neutral category
};
EmotionDetection.EmotionCategory emotion = detector.GetEmotionCategory(customerMessage);
string queue = emotion switch
{
EmotionDetection.EmotionCategory.Anger => "priority-escalation",
EmotionDetection.EmotionCategory.Fear => "reassurance-team",
EmotionDetection.EmotionCategory.Sadness => "empathy-response",
EmotionDetection.EmotionCategory.Happiness => "upsell-opportunity",
_ => "general-queue"
};
Console.WriteLine($"Routing to: {queue}");
Step 6: Interactive Detector
using System.Text;
using LMKit.Model;
using LMKit.TextAnalysis;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// ──────────────────────────────────────
// 1. Load model
// ──────────────────────────────────────
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("gemma3:1b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// ──────────────────────────────────────
// 2. Create emotion detector
// ──────────────────────────────────────
var detector = new EmotionDetection(model)
{
NeutralSupport = true // enable neutral category
};
Console.WriteLine("Enter text to detect emotion (or 'quit' to exit):\n");
while (true)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("Text: ");
Console.ResetColor();
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || input.Equals("quit", StringComparison.OrdinalIgnoreCase))
break;
EmotionDetection.EmotionCategory emotion = detector.GetEmotionCategory(input);
float confidence = detector.Confidence;
Console.ForegroundColor = emotion switch
{
EmotionDetection.EmotionCategory.Happiness => ConsoleColor.Green,
EmotionDetection.EmotionCategory.Anger => ConsoleColor.Red,
EmotionDetection.EmotionCategory.Sadness => ConsoleColor.Blue,
EmotionDetection.EmotionCategory.Fear => ConsoleColor.Yellow,
_ => ConsoleColor.Gray
};
Console.Write($" {emotion}");
Console.ResetColor();
Console.WriteLine($" (confidence: {confidence:P0})\n");
}
Emotion Categories Reference
| Value | Category | Description |
|---|---|---|
| 0 | Neutral |
No strong emotion detected (requires NeutralSupport = true) |
| 1 | Happiness |
Joy, excitement, satisfaction, gratitude |
| 2 | Anger |
Frustration, outrage, irritation |
| 3 | Sadness |
Disappointment, grief, loss |
| 4 | Fear |
Worry, anxiety, concern, apprehension |
Common Issues
| Problem | Cause | Fix |
|---|---|---|
| All results are Neutral | NeutralSupport enabled with ambiguous text |
Set NeutralSupport = false for forced classification |
| Low confidence scores | Short or ambiguous input text | Provide more context in the input text |
| Wrong emotion detected | Model too small for nuanced emotion | Use a larger model (gemma3:4b or qwen3:4b) |
Next Steps
- Analyze Customer Sentiment at Scale: sentiment analysis with batch processing.
- Detect Sarcasm and Irony in Text: layer sarcasm detection on top of emotion analysis.
- Build a Content Moderation Filter: combine emotion detection with content moderation.
- Samples: Emotion Detection: full emotion detection demo.