# new VideoSentimentAnalyzer()
Examples
// Basic single video analysis
import { VideoSentimentAnalyzer } from 'muziertcclient';
const analyzer = new VideoSentimentAnalyzer({
detectionInterval: 200, // Check every 200ms
minConfidence: 0.6, // Higher confidence threshold
smoothing: true // Enable emotion smoothing
});
// Initialize (loads face-api.js and models)
await analyzer.initialize();
// Listen for emotion events with engagement
analyzer.addEventListener('emotions', (event) => {
const { videoId, participants, summary, timestamp } = event.detail;
console.log(`${videoId}: ${summary}`);
participants.forEach(participant => {
const { dominantEmotion, confidence, boundingBox, engagement } = participant;
console.log(`Participant ${participant.id}: ${dominantEmotion.emotion} (${Math.round(confidence * 100)}%)`);
console.log(`Engagement: ${Math.round(engagement * 100)}%`);
});
});
// Listen for loading events
analyzer.addEventListener('loading', (event) => {
console.log('Loading:', event.detail.status);
});
analyzer.addEventListener('ready', (event) => {
console.log('Ready:', event.detail.status);
});
analyzer.addEventListener('error', (event) => {
console.error('Error:', event.detail.error);
});
// Start analyzing a video element
const videoElement = document.getElementById('localVideo');
await analyzer.analyzeVideo(videoElement, 'local-participant');
// Stop analysis when done
analyzer.stopAnalysis();
// Multiple video management with lazy loading
import { loadMultiVideoSentimentManager } from 'muziertcclient';
// Lazy load the sentiment analysis classes (face-api.js only loads here)
const MultiVideoSentimentManager = await loadMultiVideoSentimentManager();
const manager = new MultiVideoSentimentManager({
detectionInterval: 150,
minConfidence: 0.5,
smoothing: true,
smoothingFactor: 0.8,
debug: true,
engagementWeights: {
faceDetection: 0.4, // Emphasize face detection
eyeOpenness: 0.3, // Emphasize alertness
headPose: 0.15, // De-emphasize head pose
emotionalExpression: 0.1,
faceSize: 0.05
}
});
// Initialize once for all videos
await manager.initialize();
// Listen for emotions from any video
manager.addEventListener('emotions', (event) => {
const { videoId, participants, summary } = event.detail;
updateUI(videoId, participants, summary);
});
// Add multiple videos for analysis
await manager.addVideo('participant-1', videoElement1);
await manager.addVideo('participant-2', videoElement2);
await manager.addVideo('participant-3', videoElement3);
// Remove specific video when participant leaves
manager.removeVideo('participant-2');
// Clean up all resources
manager.destroy();
// Integration with WebRTC/video conferencing
import { Client, loadMultiVideoSentimentManager } from 'muziertcclient';
class VideoConferenceWithEmotions {
constructor() {
this.client = new Client();
this.sentimentManager = null;
}
async enableEmotionDetection() {
if (!this.sentimentManager) {
const MultiVideoSentimentManager = await loadMultiVideoSentimentManager();
this.sentimentManager = new MultiVideoSentimentManager({
detectionInterval: 200,
minConfidence: 0.6
});
await this.sentimentManager.initialize();
this.sentimentManager.addEventListener('emotions', (event) => {
this.handleEmotionUpdate(event.detail);
});
}
}
async addParticipant(userId, videoElement) {
if (this.sentimentManager) {
await this.sentimentManager.addVideo(userId, videoElement);
}
}
removeParticipant(userId) {
if (this.sentimentManager) {
this.sentimentManager.removeVideo(userId);
}
}
handleEmotionUpdate({ videoId, participants, summary }) {
// Update participant mood indicators
participants.forEach(participant => {
const moodElement = document.querySelector(`[data-participant="${videoId}"] .mood-indicator`);
if (moodElement) {
moodElement.textContent = participant.dominantEmotion.emotion;
moodElement.className = `mood-indicator mood-${participant.dominantEmotion.emotion}`;
}
});
// Update room mood summary
const roomMoodElement = document.querySelector('.room-mood');
if (roomMoodElement) {
roomMoodElement.textContent = summary;
}
}
}
// Advanced configuration and custom model URLs
const analyzer = new VideoSentimentAnalyzer({
detectionInterval: 100, // Detect every 100ms (faster)
modelUrl: '/models/face-api', // Custom model path
minConfidence: 0.7, // Higher confidence threshold
smoothing: true, // Enable smoothing
smoothingFactor: 0.6, // Less aggressive smoothing
});
// Handle all possible events
analyzer.addEventListener('loading', ({ detail }) => {
showLoadingIndicator(detail.status);
});
analyzer.addEventListener('ready', ({ detail }) => {
hideLoadingIndicator();
console.log('Sentiment analysis ready');
});
analyzer.addEventListener('emotions', ({ detail }) => {
const { videoId, participants, summary, timestamp } = detail;
// Log detailed emotion data
participants.forEach(participant => {
const allEmotions = Object.entries(participant.emotions)
.map(([emotion, score]) => `${emotion}: ${Math.round(score * 100)}%`)
.join(', ');
console.log(`Participant ${participant.id} emotions: ${allEmotions}`);
console.log(`Bounding box:`, participant.boundingBox);
});
});
analyzer.addEventListener('error', ({ detail }) => {
console.error('Sentiment analysis error:', detail.error);
showErrorMessage('Emotion detection failed. Please check your camera.');
});
Classes
Methods
# async analyzeVideo(videoElement, videoId) → {Promise.<void>}
Start emotion detection on a video element
Parameters:
| Name | Type | Description |
|---|---|---|
videoElement |
HTMLVideoElement
|
The video element to analyze |
videoId |
string
|
Unique identifier for this video |
Promise.<void>
# calculateHeadPose()
Calculate head‑pose engagement (≈ looking‑at‑camera score) 1 → eyes centred on camera 0 → head turned / tilted significantly
# async canDetectFaces(videoElementopt) → {Object}
Check if face detection is possible with the current configuration
Parameters:
| Name | Type | Attributes | Default | Description |
|---|---|---|---|---|
videoElement |
HTMLVideoElement
|
<optional> |
null | Optional video element to test |
Detection capability status
Object
# cleanupParticipant(participantVideoId)
Clean up all data associated with a specific participant/video Call this when a participant disconnects to prevent memory leaks
Parameters:
| Name | Type | Description |
|---|---|---|
participantVideoId |
string
|
The video ID of the participant to clean up |
# async detectEmotions()
Detect emotions in the current video frame Stable IDs + cleanup + safety checks
# getDiagnostics() → {Object}
Get diagnostic information about the analyzer state
Diagnostic information
Object
# async initialize() → {Promise.<void>}
Initialize face-api models (lazy loads the library first)
Promise.<void>
# setDebugMode(enabled)
Enable or disable debug mode
Parameters:
| Name | Type | Description |
|---|---|---|
enabled |
boolean
|
Whether to enable debug logging |
# validateVideoElement(videoElement)
Validate video element for face detection capability
Parameters:
| Name | Type | Description |
|---|---|---|
videoElement |
HTMLVideoElement
|
Video element to validate |
If video element is not suitable for detection
Error