Skip to content

Sentiment analysis

The problem. A customer is getting angry and nobody notices before the call goes wrong. Sentiment analysis rates each final sentence as positive, neutral or negative, with its dominant emotion, while the call runs: escalate to a supervisor, flag calls to review, chart a conversation’s mood.

Where it works. Every model. Best in English, French, Spanish, German, Italian, Portuguese, Dutch, Polish, Turkish, Russian, Japanese, Chinese and Arabic.

{ "realtime_processing": { "sentiment_analysis": true } }

Each program streams a 16-bit WAV file and prints what comes back. Put your API key in the GLADIA_API_KEY environment variable, then run python sentiment.py meeting.wav.

sentiment.py
# pip install gladiaio-sdk
import os
import sys
import threading
import wave
from gladiaio_sdk import GladiaClient, LiveV2InitRequest
API_URL = os.environ.get("GLADIA_API_URL", "https://eu1.api.gladia.io")
API_KEY = os.environ["GLADIA_API_KEY"]
with wave.open(sys.argv[1]) as wav: # a 16-bit PCM WAV file
rate, channels = wav.getframerate(), wav.getnchannels()
audio = wav.readframes(wav.getnframes())
config = {
"encoding": "wav/pcm",
"sample_rate": rate,
"bit_depth": 16,
"channels": channels,
"model": "solaria-3",
"language_config": {
"languages": [
"en"
]
},
"realtime_processing": {
"sentiment_analysis": True
}
}
client = GladiaClient(api_key=API_KEY, api_url=API_URL)
session = client.live_v2().start_session(LiveV2InitRequest.from_dict(config))
ended, errors = threading.Event(), []
@session.on("message")
def on_message(message):
if message.type == "transcript" and message.data.is_final:
print(message.data.utterance.text)
elif message.type == "sentiment_analysis":
for result in message.data.results:
print(f" {result.sentiment} ({result.emotion})")
session.on("error", errors.append)
session.once("ended", lambda _: ended.set())
step = rate * channels * 2 // 10 # 100 ms of audio per chunk
for start in range(0, len(audio), step):
session.send_audio(audio[start : start + step]) # live audio: send each chunk as it is captured
session.stop_recording()
ended.wait(timeout=60)
sys.exit(1 if errors or not ended.is_set() else 0)

After each final comes a sentiment_analysis message:

{
"type": "sentiment_analysis",
"error": null,
"data": {
"utterance_id": "01_00000007",
"utterance": { "text": "This is the third time I call about it.", "start": 41.2, "end": 43.6, "language": "en", "channel": 1 },
"results": [
{ "sentiment": "negative", "emotion": "anger", "text": "This is the third time I call about it.", "start": 41.2, "end": 43.6, "channel": 1 }
]
}
}

sentiment is positive, neutral or negative. emotion is one of: adoration, amusement, anger, awe, confusion, contempt, contentment, desire, disappointment, disgust, distress, ecstatic, elation, embarrassment, fear, interest, negative surprise, neutral, pain, positive surprise, realization, relief, sadness, sympathy, triumph (as snake_case), or empty.

  • It needs the number hold. Sentiment comes from the same analysis as the number hold: with turn_router: false, no sentiment_analysis message is sent, and no error either.
  • One sentence at a time. Each final is rated on its own: a call’s overall mood is yours to aggregate.
  • Finals only. Partials are not rated.
  • Not stored. sentiment_analysis messages are not part of the session’s result: keep them as they arrive, on the WebSocket or with a callback (callback_config.receive_realtime_processing_events).
  • Other languages get a rating too, less reliable.
symptom cause fix
no sentiment_analysis message turn_router: false, or receive_realtime_processing_events: false remove turn_router: false; keep the realtime events on
sentiment missing in GET /v2/live/{id} not stored with the result store the messages as they arrive