Real-Time Sentiment Analysis with JavaScript and Symbl.ai
By: Eric Giannini
Tags: Websocket, Sentiment Analysis, API, Web Development, JavaScript

Symbl.ai is non-assumptive, non-invasive, fully extensible, and has a user-friendly API for sentiment analysis that provides insights into the polarity of messages in real-time. Let’s look at what this all means.

1. Non-assumptive

The API is non-assumptive in that results for polarity are not relayed as a particular emotion but as a value w.r.t. negativity or positivity. It doesn’t assume an emotion.

2. Non-invasive

The API is non-invasive, since the result of the analysis is from the completed message, of which a conversation is composed, rather than a voice, a highly personal, non-revocable biometric aspect of human identity.

3. Fully extensible

The API is extensible in that the analysis, which may be as to the conversation itself, its speakers, or their own individual or aggregate messages, is fully programmable. You as a developer decide how create statistics or data around the values derived from sentiments anytime anywhere.

4. User-friendly API

Users, whose aver quantification do not surrender of their unique, individual ‘credentials’, may have no fear any aspect of Symbl.ai’s sentiment analysis, making the API extremely friendly on the user end. It is not a tone analyzer, for instance.

WebSockets for Symbl.ai

WebSockets are a computer protocol for communications as a vast improvement over the request/response model of HTTP. They provide full-duplex channels over a single Transmission Control Protocol (TCP) connection. WebSockets facilitate communications between clients or serves in real-time without the connection suffering from racy, high-latency, and bandwidth-intensive exchange under HTTP. Specified as ws or wss , unencrypted or encrypted, a WebSocket endpoint is a persistent bi-directional channel of communication without any overhead from HTTP residuals such as headers, cookies or artifacts. Here is Symbl.ai’s API for WebSockets:

wss://api.symbl.ai/v1/realtime/

Symbl.ai’s JavaScript WebSocket’s API

In the following blog you will enable Symbl.ai’s JavaScript WebSocket’s API to transcribe live in your browser. To enable live transcription with Symbl.ai’s JavaScript WebSocket’s API in the browser, you: 1) set up your account, 2) configure the WebSocket’s endpoint, 3) run the code in the browser, 4) transcribe live. After setting up the live transcription, you implement Symbl.ai’s non-assumptive, non-invasive, fully extensible, user-friendly API for sentiment analysis.

Set up

Register for an account at Symbl (i.e., https://platform.symbl.ai/). Grab both your appId and your appSecret . With both of those you should authenticate either with a cURL command or with Postman so that you receive your x-api-key . Here is an example with cURL :

Ideally a token server would handle authentication (with code that makes RESTful API call for generating token) so that neither the appSecret nor the appId were ever exposed. However, cURL sets you up immediately anyway. With the x-api-key handy you are now ready to establish a WebSocket endpoint for performing live transcription.

WebSocket’s Endpoint

To enable the WebSocket, you configure two values as query parameters that are fed directly into the WebSocket API’s endpoint. In turn you feed the WebSocket API’s endpoint directly into JavaScript’s own software for enabling real-time conversations.

Here are the first two values:

const uniqueMeetingId = btoa('EMAIL@ADDRESS.COM');

const accessToken = '';

With these two values for the WebSocket’s API endpoint set, you feed these directly into the WebSocket API’s endpoint:

const symblEndpoint = `wss://api.symbl.ai/v1/realtime/insights/${uniqueMeetingId}?access_token=${accessToken}

If you want to test your WebSocket before any further integration, you load that endpoint with the data for uniqueMeetingId together with the accessToken into Hoppscotch.io, a free, fast, sleek API request builder.

Creating an Instance of JavaScript’s native WebSocket API

The next step is to create an instance of JavaScript’s native WebSocket API:

const ws = new WebSocket(symblEndpoint);

On that instance, you call methods specific to handling live transcription.

// Fired when a message is received from the WebSocket server

ws.onmessage = (event) => {

console.log(event);

}; // Fired when the WebSocket closes unexpectedly due to an error or lost connetion

ws.onerror = (err) => {

console.error(err);

}; // Fired when the WebSocket connection has been closed

ws.onclose = (event) => {

console.info('Connection to websocket closed');

}; // Fired when the connection succeeds.

ws.onopen = (event) => {

ws.send(JSON.stringify({

type: 'start_request',

meetingTitle: 'Websockets How-to', // Conversation name

insightTypes: ['question', 'action_item'], // Will enable insight generation

config: {

confidenceThreshold: 0.5,

languageCode: 'en-US',

speechRecognition: {

encoding: 'LINEAR16',

sampleRateHertz: 44100,

}

},

speaker: {

userId: 'example@symbl.ai',

name: 'Example Sample',

}

}));

};

To set up the stream for accessing a user’s media devices such as their laptop’s microphone, program the brower’s navigator accordingly:

const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false });

The code above asks the user for permission to access his or her device through a pop-up. In mobile applications permission for access to devices is hardcoded into the controlling directory of an application binary such as in the manifest for Android of the property list for iOS. JavaScript doesn’t compile so there is no need to ask for permission so that you can ask for permission!

To set up the stream to handle events, program the following:

const handleSuccess = (stream) => {

const AudioContext = window.AudioContext;

const context = new AudioContext();

const source = context.createMediaStreamSource(stream);

const processor = context.createScriptProcessor(1024, 1, 1);

const gainNode = context.createGain();

source.connect(gainNode);

gainNode.connect(processor);

processor.connect(context.destination);

processor.onaudioprocess = (e) => {

// convert to 16-bit payload

const inputData = e.inputBuffer.getChannelData(0) || new Float32Array(this.bufferSize);

const targetBuffer = new Int16Array(inputData.length);

for (let index = inputData.length; index > 0; index--) {

targetBuffer[index] = 32767 * Math.min(1, inputData[index]);

}

// Send to websocket

if (ws.readyState === WebSocket.OPEN) {

ws.send(targetBuffer.buffer);

}

};

};

Trying Out the the Code

It might be a great idea to try out your WebSocket’s connection right now. After running your code directly in the browser, then you see the console logging events in real-time as you speak.

Stopping the Conversation

To stop your live transcription, you close your browsers or you send a stop_request directly to the server from within the browser’s console.

ws.send(JSON.stringify({

"type": "stop_request"

}));

Real-Time Sentiment Analysis

Within the ws method for onmessage program the API endpoint to capture the polarity of Symbl.ai’s conversation’s messages, logging the value to through the console.

The first step is to capture the conversationId as a constant. You capture the conversationId through the parsed data that comes from the WebSocket’s API’s onmessage method.

const conversationId = data.message.data.conversationId;

The second step is to create the request. There are multiple libraries for handling HTTP requests so feel free to refactor the XMLHttpRequest here.

const request = new XMLHttpRequest();

The third step is to configure the request, setting the response’s type to text .

request.responseType = "text";

The fourth step is to configure the endpoint:

The fifth step is to set the request.

request.open("GET", sentimentEndpoint)

The sixth step is to set the request’s headers.

request.setRequestHeader('Authorization', `Bearer ${accessToken}`);

request.setRequestHeader('Content-Type', 'application/json');

The seventh step is to create a function to log the sentiment’s into the console.

request.onreadystatechange=(e)=> {

console.log(request.responseText)

}

The last step is send the request.

request.send()

Here is the fully programmable sentiment analysis API implemented in your ws method for onmessage in your WebSocket:



ws.onmessage = (event) => {

// You can find the conversationId in event.message.data.conversationId;

const data = JSON.parse(event.data);

if (data.type === 'message' && data.message.hasOwnProperty('data')) {

console.log('conversationId', data.message.data.conversationId);

const conversationId = data.message.data.conversationId;

console.log('onmessage event', event);

// You can log sentiments on messages from data.message.data.conversationId

const request = new XMLHttpRequest();

request.responseType = "text";

const sentimentEndpoint = `

request.open("GET", sentimentEndpoint)

request.setRequestHeader('Authorization', `Bearer ${accessToken}`);

request.setRequestHeader('Content-Type', 'application/json');

request.onreadystatechange=(e)=> {

console.log(request.responseText)

}

request.send()

}

}; // Fired when a message is received from the WebSocket serverws.onmessage = (event) => {// You can find the conversationId in event.message.data.conversationId;const data = JSON.parse(event.data);if (data.type === 'message' && data.message.hasOwnProperty('data')) {console.log('conversationId', data.message.data.conversationId);const conversationId = data.message.data.conversationId;console.log('onmessage event', event);// You can log sentiments on messages from data.message.data.conversationIdconst request = new XMLHttpRequest();request.responseType = "text";const sentimentEndpoint = ` https://api.symbl.ai/v1/conversations/${conversationId}/messages?sentiment=true `;request.open("GET", sentimentEndpoint)request.setRequestHeader('Authorization', `Bearer ${accessToken}`);request.setRequestHeader('Content-Type', 'application/json');request.onreadystatechange=(e)=> {console.log(request.responseText)request.send()};

If your console logged sentiments upon a change in the state of events, then your code delivered real-time sentiment analysis in API!

What’s Next?

A Symbl.ai conversation configured to relay messages over a real-time websocket with its sentiment analysis API is neither the beginning nor the end of conversation data.

If you look closely at the data from your live WebSocket connection, the conversationId may be applied to new API calls to access to more AI insights for action items, topics, or analytics. Within a fully programmable Symbl.ai conversation you receive not just sentiment analysis but access to an analytics API that provides access to the following conversation data:

Speaker Ratio — Speaker’s talk and listen ratio and time. Talk Time — Overall duration of the conversation. Silence — Overall duration of silence. Pace — Words per minute spoken in the conversation. Overlap — When more than 1 speaker are speaking the same time, then conversation has overlap.

With Speaker Ratio, Talk Time, Silence, Pace, or Overlap, you have the ability to create application logic or notifications that augment conversational experiences to a step far beyond merely transcribing a speaker or speakers in a real-time speech-to-text application or automating speech recognition through no more than a single a API endpoint.

Since real-time sentiment analysis is based on messages rather than tonality, Symbl.ai’s API for topics, which aggregates the most salient subjects of a conversation in a set of word groups called ‘topics’, are fully programmable as data on messages not unlike the data on messages for speaker events.

Analytics into data for sentiment or speaker events in general is but a part of Symbl.ai’s extensible, fully programmable, developer platform for conversations. Symbl.ai’s real-time sentiment analysis or analytics APIs operate across protocols, channels, companies freely for developers to create freely augmented conversation experiences.

Community

Stuck? Free feel to ask us any questions on our Slack Channel or send us an email at devrelations@symbl.ai.