Artificial Intelligence API Quick Start Guide

Last updated: 2024-03-07Contributors
Edit this page

RingCentral Artificial Intelligence API is in beta

The RingCentral's Artificial Intelligence API is currently in beta. Developers should be aware of the following:

  • Their feature sets are not reflective of the full scope currently planned.
  • Backwards compatibility is not guaranteed from one release to the next during the beta period. Changes can be introduced at any time that may impact your applications with little notice.

Calling the RingCentral API for the first time? We recommend you try out getting started experience.

In this quick start, we are going to help you create your first "Speech to Text" application on the RingCentral platform in just a few minutes. Let's get started.

Create an App

The first thing we need to do is create an app in the RingCentral Developer Portal. This can be done quickly by clicking the "Create AI App" button below. Just click the button, enter a name and description if you choose, and click the "Create" button. If you do not yet have a RingCentral account, you will be prompted to create one.

Create AI App

  1. Login or create an account if you have not done so already.
  2. Go to Console/Apps and click 'Create App' button.
  3. Select "REST API App" under "What type of app are you creating?" Click "Next."
  4. Under "Auth" select "JWT auth flow."
  5. Under "Security" add the following app scopes:
    • AI
  6. Under "Security" select "This app is private and will only be callable using credentials from the same RingCentral account."

Request help from support

Access to the RingCentral Artificial API currently requires help from support in order to grant the "AI" application scope to your application.

Using the AI API in sandbox vs prodcution

The AI API works in both sandbox and production, but sandbox has limitations such as only the first 10 minutes of the audio is processed. Since sandbox is used for testing and development purposes only, we do not expect developers to process large media files in sandbox.

Download and edit a .env file

Follow the instructions found in our guide to running Developer Guide code samples. Or:

  1. Download our env-template and save it as a file named .env.
  2. Edit your newly downloaded .env file, setting its variables with the proper values for the app you created above.
    • RC_CLIENT_ID - set to the Client ID of the app you created above
    • RC_CLIENT_SECRET - set to the Client Secret of the app you created above
    • RC_JWT - set to the JWT credential you created for yourself
    • NGROK_URL - set to your ngrok tunnel address taken from the ngrok setup steps below.
    • CONTENT_URI - set to a publicly accessible URL for your audio/video file you want to transcribe (a test default uri has been provided for you)

Setup a server to process the response asynchronously

The Artificial Intelligence APIs provide responses in an asynchronous manner by posting responses to a URL specified by the developer when the request is made. Our first step therefore is setting up a simple web server to display the response we will receive from RingCentral. The sample servers below use ngrok to proxy requests from RingCentral to the server running on your local machine. To keep your first application simple, this server does nothing more than printing the payload of anything it receives to the console (for the PHP server, it writes the payload to a file.). Feel free to use these sample servers, or setup your own web server to receive and process the responses.

Start ngrok

Download and install ngrok if you haven't done so. Then start your ngrok server and copy the https URL and set it to the NGROK_URL variable in your .env file as discussed above.

$ ngrok http 3000
  Forwarding https://xxxx-yy-181-201-33.ngrok-free.app -> https://localhost:3000

Create and start your server app

Create a file called server.js using the contents below. Set the PORT to the same port number opening for the ngrok tunnel.

const http = require('http');
const fs = require('fs')
const PORT = 3000;

// Create a server to receive callback from RingCentral
const server = http.createServer( function(req, res) {
    if (req.method == 'POST' && req.url == "/webhook") {
        let body = []
        req.on('data', function(chunk) {
            body.push(chunk);
        }).on('end', function() {
            body = Buffer.concat(body).toString();
            jsonObj = JSON.parse(body)
            console.log(JSON.stringify(JSON.parse(body),null,4))
        });
        res.statusCode = 200
        res.end()
    } else {
      console.log(req.method, req.url)
      console.log("Unknown HTTP content received")
    }
});

// Start the server
try {
    server.listen(PORT);
} catch (e) {
    console.log("There was a problem starting the server: " + e)
}
console.log("Artificial Intelligence response server running at: https://localhost:" + PORT)

Finally, start your server.

$ node server.js

Create a file called server.py using the contents below. Set the PORT to the same PORT number opening for the ngrok tunnel.

from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
import os, json

HOSTNAME = "localhost"
PORT     = 3000

class S(BaseHTTPRequestHandler):
    def _set_response(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_POST(self):
        path = self.path
        if path == "/webhook":
            content_len = int(self.headers.get('Content-Length'))
            body = self.rfile.read(content_len)
            jsonObj = json.loads(body)
            print( json.dumps(jsonObj, indent=2, sort_keys=True))
            self._set_response()
        else:
            print ("Ignore this")


def run(server_class = HTTPServer, handler_class = S):
    server_address = (HOSTNAME, PORT)
    httpd = server_class(server_address, handler_class)
    print (f'Artificial Intelligence response server running at: https://{HOSTNAME}:{PORT}')
    httpd.serve_forever()

if __name__ == "__main__":
    from sys import argv

if len(argv) == 2:
    run(port=int(argv[1]))
else:
    run()

Finally, start your server.

$ python server.py

Create a folder named webhook and navigate to the new folder then create a file called server.php using the contents below.

<?php
if (isset($_REQUEST['webhook'])){
    $jsonStr = file_get_contents('php://input');
    $jsonObj = json_decode($jsonStr, TRUE);
    print_r ($jsonObj);
    file_put_contents("response.json", $jsonStr);
}else{
  echo ("Ignore this");
}
?>

Finally, start your server.

php -S localhost:3000

First, install the prerequisites.

$ pip install sinatra

Create and edit server.rb

Create a file called server.rb using the contents below. Set the PORT to the same PORT number opening for the ngrok tunnel.

require 'sinatra'
require 'json'

set :port, 3000
post '/webhook' do
    body = request.body.read
    jsonObj = JSON.parse(body)
    puts (jsonObj)
    status 200
    body 'OK'
end

Run your code

Finally, start your server.

$ ruby server.rb

We use .NET core which is cross-platform. You can get it here.

Create a Web server solution

mkdir server
cd server
dotnet new web
dotnet add package Newtonsoft.Json

Edit the Startup.cs file and override its content with code below:

using System;
using System.IO;
using System.Text;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

namespace server
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment()) app.UseDeveloperExceptionPage();

            app.Run( async (context) =>
            {
                if (context.Request.Path == "/webhook" && context.Request.Method == "POST")
                {
                    using (StreamReader reader = new StreamReader(context.Request.Body, Encoding.UTF8))
                    {
                        var eventPayload = await reader.ReadToEndAsync();
                        dynamic jsonObj = JsonConvert.DeserializeObject(eventPayload);
                        Console.WriteLine("JobId: " + jsonObj.jobId);
                        Console.WriteLine("Status: " + jsonObj.status);
                        Console.WriteLine("API: " + jsonObj.api);
                        Console.WriteLine("creationTime: " + jsonObj.creationTime);
                        Console.WriteLine("completionTime: " + jsonObj.completionTime);
                        Console.WriteLine("expirationTime: " + jsonObj.expirationTime);
                        Console.WriteLine("==== RESPONSE ====");
                        Console.WriteLine(jsonObj.response);
                    }
                }
            });
        }
    }
}

Run the server code

The default port is 5000 and it is set in the launchSettings.json file under the server/Properties folder. Open the file and change the port number to match the opening port for the ngrok tunnel. E.g.

"applicationUrl": "https://localhost:3001;http://localhost:3000"

Finally, start your server. At the server terminal, run:

dotnet run

Create a WebhookServer project (using Eclipse IDE)

  • Create a new Java project
  • Select the Gradle Project wizard
  • Enter project name "AIServer"
  • Open the build.gradle file and add the dependencies to the project as shown below:
    dependencies {
        // ...
        implementation 'org.eclipse.jetty.aggregate:jetty-all:9.4.51.v20230217'
        implementation: 'javax.servlet:javax.servlet-api:4.0.1'
    }
    
  • Right-click the project in the Package Explorer and choose "Refresh Gradle Project" under the "Gradle" sub-menu

We use jetty-all version 9.4.x for our server. You can get a different version here if you want to.

Create a new Java Class

Select "File -> New -> Class" to create a new Java class named "WebhookServer"

Edit the WebhookServer.java with code below:

package AIServer;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.AbstractHandler;

public class WebhookServer extends AbstractHandler
{
    public static void main( String[] args ) throws Exception
    {
        Server server = new Server(3000);
        server.setHandler(new WebhookServer());
        server.start();
        server.join();
    }

    @Override
    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
    {
        response.setStatus(HttpServletResponse.SC_OK);
        if (request.getMethod() == "POST" && request.getPathInfo().equals("/webhook"))
        {
            String body = request.getReader().lines().collect( java.util.stream.Collectors.joining(System.lineSeparator()) );
            System.out.println(body);
        }
        baseRequest.setHandled(true);
    }
}

Build and run the app from Eclipse.

Implement and run speech to text code

Install RingCentral JS SDK & dotenv library

$ npm install @ringcentral/sdk dotenv

Create and edit speech-to-text.js

Create a file called speech-to-text.js using the contents below.

const RC = require('@ringcentral/sdk').SDK
const fs = require('fs')
const path = require('path')
// Remember to modify the path of your .env file location!
require('dotenv').config({ path: path.resolve(__dirname, '../.env') })

// Initialize the RingCentral SDK and Platform
const rcsdk = new RC({
    'server':       process.env.RC_SERVER_URL,
    'clientId':     process.env.RC_CLIENT_ID,
    'clientSecret': process.env.RC_CLIENT_SECRET
});
var platform = rcsdk.platform();

/* Authenticate a user using a personal JWT token */
platform.login({ 'jwt':  process.env.RC_JWT })

platform.on(platform.events.loginSuccess, function(e){
    speech_to_text()
});

platform.on(platform.events.loginError, function(e){
    console.log("Unable to authenticate to platform. Check credentials.", e.message)
    process.exit(1)
});

/*
* Convert speech to text
*/
async function speech_to_text() {
  try {
    let bodyParams = {
        'contentUri':               process.env.CONTENT_URI,
        'encoding':                 "Mpeg",
        'languageCode':             "en-US",
        'source':                   "RingCentral",
        'audioType':                "CallCenter",
        'enablePunctuation':        true,
        'enableSpeakerDiarization': true
    }
    let callbackAddress = `${process.env.NGROK_URL}/webhook`
    let endpoint = `/ai/audio/v1/async/speech-to-text?webhook=${callbackAddress}`
    let resp = await platform.post(endpoint, bodyParams);
    let jsonObj = await resp.json();
    if (resp.status == 202) {
      console.log("Job ID: " + jsonObj.jobId);
      console.log("Ready to receive response at: " + callbackAddress);
    } else {
      console.log("An error occurred posting the request.");
    }
  } catch (e) {
    console.log("An error occurred : " + e.message);
  }
}

Run your code

You are almost done. Now run your script.

$ node speech-to-text.js

Install RingCentral Python SDK & dotenv library

$ pip install ringcentral
$ pip install python-dotenv

Create and edit speech-to-text.py

Create a file called speech-to-text.py using the contents below.

from ringcentral import SDK
import os,sys,urllib.parse,json
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()

#
#  Convert speech to text
#
def speech_to_text():
    try:
        bodyParams = {
          'contentUri':               os.environ.get('CONTENT_URI'),
          'encoding':                 "Mpeg",
          'languageCode':             "en-US",
          'source':                   "RingCentral",
          'audioType':                "CallCenter",
          'enablePunctuation':        True,
          'enableSpeakerDiarization': True
        }
        callbackAddress = os.environ.get('NGROK_URL') + "/webhook"
        endpoint = "/ai/audio/v1/async/speech-to-text?webhook=" + urllib.parse.quote(callbackAddress)
        resp = platform.post(endpoint, bodyParams)
        jsonObj = resp.json()
        if resp.response().status_code == 202:
            print(f'Job ID: {resp.json().jobId}');
            print(f'Ready to receive response at: {callbackAddress}');
        else:
            print(f'An error occurred posting the request.');
    except Exception as e:
        print ("Unable to call speech to text API. " + str(e))

# Instantiate the SDK and get the platform instance
rcsdk = SDK( os.environ.get('RC_CLIENT_ID'),
             os.environ.get('RC_CLIENT_SECRET'),
             os.environ.get('RC_SERVER_URL') )
platform = rcsdk.platform()

# Authenticate a user using a personal JWT token
def login():
    try:
      platform.login( jwt=os.environ.get('RC_JWT') )
      speech_to_text()
    except Exception as e:
      sys.exit("Unable to authenticate to platform. Check credentials." + str(e))

login()

Run your code

You are almost done. Now run your script.

$ python speech-to-text.py

Install RingCentral PHP SDK & phpdotenv library

$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar require ringcentral/ringcentral-php vlucas/phpdotenv

Create and edit speech-to-text.php

Create a file called speech-to-text.php using the contents below.

<?php
// Remember to modify the path ./../ pointing to the location where the RingCentral SDK was installed and the .env file was saved!
require('./../vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . './../');
$dotenv->load();

# Instantiate the SDK and get the platform instance
$rcsdk = new RingCentral\SDK\SDK( $_ENV['RC_CLIENT_ID'],
                                  $_ENV['RC_CLIENT_SECRET'],
                                  $_ENV['RC_SERVER_URL'] );
$platform = $rcsdk->platform();

// Authenticate a user using a personal JWT token
try {
  $platform->login( [ "jwt" => $_ENV['RC_JWT'] ] );
  speech_to_text();
} catch (\RingCentral\SDK\Http\ApiException $e) {
  exit("Unable to authenticate to platform. Check credentials. " . $e->getMessage() . PHP_EOL);
}

/*
* Convert speech to text
*/
function speech_to_text(){
  global $platform;
  try {
    $bodyParams = array (
      'contentUri' =>               $_ENV['CONTENT_URI'],
      'encoding' =>                 "Mpeg",
      'languageCode' =>             "en-US",
      'source' =>                   "RingCentral",
      'audioType' =>                "CallCenter",
      'enablePunctuation' =>        True,
      'enableSpeakerDiarization' => True
    );
    $callbackAddress = $_ENV['NGROK_URL'] . "/server.php?webhook";
    $endpoint = "/ai/audio/v1/async/speech-to-text?webhook=" . urlencode($callbackAddress);
    $resp = $platform->post($endpoint, $bodyParams);
    $jsonObj = $resp->json();
    if ($resp->response()->getStatusCode() == 202) {
      print_r("Job ID: " . $jsonObj->jobId . PHP_EOL);
      print_r("Ready to receive response at: " . $callbackAddress . PHP_EOL);
    }else{
      print_r("An error occurred posting the request.");
    }
  }catch (\RingCentral\SDK\Http\ApiException $e) {
    // Getting error messages using PHP native interface
    print 'HTTP Error: ' . $e->getMessage() . PHP_EOL;
    // Another way to get message, but keep in mind, that there could be no response if request has failed completely
    print 'Unable to call speech to text API. ' . $e->apiResponse->response()->error() . PHP_EOL;
  }
}
?>

Run your code

You are almost done. Now run your script.

$ php speech-to-text.php

Install RingCentral Ruby SDK & dotenv library

$ gem install ringcentral-sdk dotenv

Create and Edit speech-to-text.rb

Create a file called speech-to-text.rb using the contents below.

require 'ringcentral'
require 'dotenv'
require 'json'

# Remember to modify the path to where you saved your .env file!
Dotenv.load("./../.env")

#
#  Convert speech to text
#
def speech_to_text()
    bodyParams = {
      'contentUri':               ENV['CONTENT_URI'],
      'encoding':                 "Mpeg",
      'languageCode':             "en-US",
      'source':                   "RingCentral",
      'audioType':                "CallCenter",
      'enablePunctuation':        true,
      'enableSpeakerDiarization': true
    }
    callbackAddress = ENV['NGROK_URL'] + "/webhook"
    endpoint = "/ai/audio/v1/async/speech-to-text" #?webhook=" + callbackAddress #CGI.escape(callbackAddress)
    queryParams = {
      'webhook': callbackAddress
    }
    begin
      resp = $platform.post(endpoint, payload: bodyParams, params: queryParams)
      body = resp.body
      if resp.status == 202
          puts('Job ID: ' + body['jobId']);
          puts ('Ready to receive response at: ' + callbackAddress);
      else
          puts ('An error occurred posting the request.')
      end
    rescue StandardError => e
      puts ("Unable to call speech to text API. " + e.to_s)
    end
end

# Instantiate the SDK and get the platform instance
$platform = RingCentral.new( ENV['RC_CLIENT_ID'], ENV['RC_CLIENT_SECRET'], ENV['RC_SERVER_URL'] )

# Authenticate a user using a personal JWT token
def login()
  begin
    $platform.authorize(jwt: ENV['RC_JWT'])
    speech_to_text()
  rescue StandardError => e
    puts ("Unable to authenticate to platform. Check credentials." + e.to_s)
  end
end

login()

Run your code

You are almost done. Now run your script.

$ ruby speech-to-text.rb

Create a C# project using Visual Studio

  • Choose Console Application .Net Core -> App
  • Select Target Framework .NET Core 2.1 or a higher version
  • Enter project name "SpeechToTextQuickStart"
  • Add the RingCentral.Net (6.1.1) SDK and DotEnv NuGet packages
  • Save the .env file under your project folder. E.g. /SpeechToTextQuickStart/bin/Debug/netcoreapp2.2/.env

Edit the file 'Program.cs' using the content below:

using System;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
using RingCentral;
using Newtonsoft.Json;
using dotenv.net;

namespace ConvertSpeechToText {
  class Program {
    static RestClient restClient;

    static async Task Main(string[] args){
      try
      {
        DotEnv.Load();
        // Instantiate the SDK
        restClient = new RestClient(
            Environment.GetEnvironmentVariable("RC_CLIENT_ID"),
            Environment.GetEnvironmentVariable("RC_CLIENT_SECRET"),
            Environment.GetEnvironmentVariable("RC_SERVER_URL"));

        // Authenticate a user using a personal JWT token
        await restClient.Authorize( Environment.GetEnvironmentVariable("RC_JWT") );

        await speech_to_text();
      }
      catch (Exception ex)
      {
        Console.WriteLine("Unable to authenticate to platform. Check credentials. " + ex.Message);
      }
    }
    /*
    * Convert speech to text
    */
    static private async Task speech_to_text()
    {
      try
      {
        var bodyParams = new AsrInput()
                {
                    contentUri = Environment.GetEnvironmentVariable("CONTENT_URI"),
                    encoding = "Mpeg",
                    languageCode = "en-US",
                    source = "RingCentral",
                    audioType = "CallCenter",
                    enablePunctuation = true,
                    enableSpeakerDiarization = true
                };
        var callbackAddress = Environment.GetEnvironmentVariable("NGROK_URL") + "/webhook";
        var queryParams = new CaiSpeechToTextParameters() { webhook = callbackAddress };

        var resp = await restClient.Ai().Audio().V1().Async().SpeechToText().Post(bodyParams, queryParams);

        Console.WriteLine("Job ID: " + resp.jobId);
        Console.WriteLine("Ready to receive response at: " + callbackAddress);
      }
      catch (Exception ex)
      {
        Console.WriteLine("Unable to convert speech to text. " + ex.Message);
      }
    }
  }
}

Run Your Code

You are almost done. Now run your app from Visual Studio.

Create a Java project (using Eclipse IDE)

  • Create a new Java project
  • Select the Gradle Project wizard
  • Enter project name "SpeechToTextQuickStart"
  • Open the build.gradle file and add the RingCentral Java SDK to the project as shown below:
    dependencies {
        // ...
        implementation 'com.ringcentral:ringcentral:3.1.1'
    }
    
  • Right-click the project in the Package Explorer and choose "Refresh Gradle Project" under the "Gradle" sub-menu
  • On Eclipse menu, select "Run" and choose the "Run Configurations" and in the dialog, select your project and select the "Environments" tab then enter the following variables:
    • RC_CLIENT_ID
    • RC_CLIENT_SECRET
    • RC_SERVER_URL
    • RC_JWT
    • NGROK_URL
    • CONTENT_URI

Edit the file 'SpeechToTextQuickStart.java' using the content below:

package SpeechToTextQuickStart;

import java.io.IOException;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;

import com.ringcentral.*;
import com.ringcentral.definitions.*;

public class SpeechToTextQuickStart {
    static RestClient restClient;

    public static void main(String[] args) {
      var obj = new SpeechToTextQuickStart();
      try {
        // Instantiate the SDK
        restClient = new RestClient(System.getenv("RC_CLIENT_ID"), System.getenv("RC_CLIENT_SECRET"), System.getenv("RC_SERVER_URL"));

        // Authenticate a user using a personal JWT token
        restClient.authorize(System.getenv("RC_JWT"));

        obj.speech_to_text();

      } catch (RestException e) {
        System.out.println(e.getMessage());
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    /*
    * Convert speech to text
    */
    private void speech_to_text()
    {
      try {
        var bodyParams = new AsrInput()
                 .contentUri(System.getenv("CONTENT_URI"))
                 .encoding("Mpeg")
                 .languageCode("en-US")
                 .source("RingCentral")
                 .audioType("CallCenter")
                 .enablePunctuation(true)
                 .enableSpeakerDiarization(true);

        var callbackAddress = System.getenv("NGROK_URL") + "/webhook";
        var queryParams = new CaiSpeechToTextParameters().webhook(callbackAddress);

        var resp = restClient.ai().audio().v1().async().speechToText().post(bodyParams, queryParams);
        System.out.println("Job ID: " + resp.jobId);
        System.out.println("Ready to receive response at: " + callbackAddress);
      } catch (Exception ex) {
        System.out.println("Unable to convert speech to text. " + ex.getMessage());
      }
    }
}

Build & Run Your Code

You are almost done. Now run your app from Eclipse and check the console log from the server app.

Wait for a response from RingCentral

When RingCentral has fully processed the request, a response will be posted to the server you created previously. The response should look similar to the following.

{
    "jobId": "c8b1bd02-af17-11ee-93fb-0050568c76a9",
    "api": "/ai/audio/v1/async/speech-to-text",
    "creationTime": "2024-01-09T17:51:58.422Z",
    "completionTime": "2024-01-09T17:56:26.126Z",
    "expirationTime": "2024-01-16T17:51:58.422Z",
    "status": "Success",
    "response": {
        "confidence": 0.9,
        "transcript": "This call is now being recorded. Parker Scarves, how may I help you? I bought a scarf on line for my whites. And it turns out they shipped the wrong color. Oh, I am so sorry, sir. I get it for birthday, which is tonight. And now I am not a 100 % sure what I need to do. Okay, let me see if I can help you. Do you have the item number of the Parker scars? I do not I do not think so. It is called a New Yorker, I think. Excellent, okay. What color did you want The New Yorker in blue, the 1 they shipped was light blue. I wanted the darker 1. Did you want Navy Blue or Royal Blue? What is the difference there? The royal blue is a bit brighter. That is the 1 I want, okay? What zip code are you located in? 1946. It appears that we do not I am sorry that we do have that item in stock at Karen's boutique at the Hunter Mall. Is that close by? It is it is primary office. Okay, what is your name, sir? Charlie Johnson, Charlie Johnson, is that J O H N S O N? Yes, Ma'am and Mr Johnson, do you have the Parker scarf in light blue with you now? I do, they shipped it to my office. It just came in not that long ago, okay? What I will do is make arrangements with Karen's to take for you to exchange the Parker scarf at no additional cost. And in addition, I was able to look up your order in our system. And I am going to send out a special gift to you to make up for the inconvenience. Excellent, thank you so much, you are welcome and thank you for calling Parker scarf, and I hope your wife enjoys your birthday gift. Thank you. Thank you very much. You are very welcome. Goodbye, bye bye.",
        "utterances": [
            {
                "confidence": 0.87,
                "end": 4.800000000000001,
                "speakerId": "0",
                "start": 0.16,
                "text": "This call is now being recorded. Parker Scarves. How may I help you?",
                "wordTimings": [
                    {
                        "confidence": 0.87,
                        "end": 0.24,
                        "speakerId": "0",
                        "start": 0.16,
                        "word": "this"
                    },
                    {
                        "confidence": 0.87,
                        "end": 0.48,
                        "speakerId": "0",
                        "start": 0.4,
                        "word": "call"
                    },
                    {
                        "confidence": 0.87,
                        "end": 0.72,
                        "speakerId": "0",
                        "start": 0.64,
                        "word": "is"
                    },
                    ...
                ]
            },
            {
                "confidence": 0.87,
                "end": 9.78,
                "speakerId": "1",
                "start": 4.800000000000001,
                "text": "I bought a scarf on line for my whites, and it turns out they shipped the wrong color.",
                "wordTimings": [
                    {
                        "confidence": 0.87,
                        "end": 5.36,
                        "speakerId": "1",
                        "start": 4.800000000000001,
                        "word": "i"
                    },
                    ...
                ]
            },
            ...
        ],
        "words": [
            {
                "confidence": 0.87,
                "end": 0.24,
                "start": 0,
                "word": "this"
            },
            {
                "confidence": 0.87,
                "end": 0.48,
                "start": 0.4,
                "word": "call"
            },
            {
                "confidence": 0.87,
                "end": 0.72,
                "start": 0.64,
                "word": "is"
            },
            ...
        ]
    }
}