Artificial Intelligence API Quick Start Guide
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 Show detailed instructions
- Login or create an account if you have not done so already.
- Go to Console/Apps and click 'Create App' button.
- Select "REST API App" under "What type of app are you creating?" Click "Next."
- Under "Auth" select "JWT auth flow."
- Under "Security" add the following permissions:
- RingOut
- 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, and graduate it to production.
Download and edit a .env
file
Follow the instructions found in our guide to running Developer Guide code samples. Or:
- Download our env-template and save it as a file named
.env
. - 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 aboveRC_CLIENT_SECRET
- set to the Client Secret of the app you created aboveRC_JWT
- set to the JWT credential you created for yourselfRC_MEDIA_URL
- set to a publicly accessible URL for a file you want to transcribe (a functioning default value 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. Two sample servers are provided below in Javascript and Python. Both use ngrok to proxy requests from RingCentral to the server running on your local development machine. To keep your first application simple, this server does nothing more than acknowledge receipt and echo the payload of anything it receives to the console. You are free to use these sample servers, or setup your own web server to process the responses transmitted by RingCentral.
Start ngrok
Download and install ngrok if you have not already. Then start your ngrok server and make note of its https URL. You will enter that URL in the server you create in the next step.
$ ngrok http 5000
Forwarding https://xxx-yyy-zzz.ngrok.io -> https://localhost:5000
Create and start your server
First, install the prerequisites.
$ npm install @ringcentral/sdk
$ npm install dotenv
Create a file called server.js
using the contents below. Edit server.js
to properly reference the NGROK_URL
generated in the previous step.
const http = require('http');
const PORT = 8080;
// Create a server to receive callback from RingCentral
const server = http.createServer( function(req, res) {
if (req.method == 'POST' && req.url == "/webhook") {
console.log("Response received from RingCentral...");
if (req.headers.hasOwnProperty("validation-token")) {
res.setHeader('Content-type', 'application/json');
res.setHeader('Validation-Token', req.headers['validation-token']);
}
let body = []
req.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
body = Buffer.concat(body).toString();
console.log(JSON.stringify(JSON.parse(body),null,4));
res.statusCode = 200;
res.end();
});
} else {
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
First, install the prerequisites.
$ pip install pprintpp
Create a file called server.py
using the contents below. Edit server.py
to properly reference the NGROK_URL
generated in the previous step.
import os,sys
import logging
import requests
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
# Server config. Set this to your local server and port
HOSTNAME = "localhost"
PORT = 8080
# Handle Incoming HTTP requests
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):
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)
print( json.dumps(json.loads(post_data), indent=2, sort_keys=True))
self._set_response()
def run(server_class=HTTPServer, handler_class=S, hostName='localhost', port=8080):
logging.basicConfig(level=logging.INFO)
server_address = (HOSTNAME, port)
httpd = server_class(server_address, handler_class)
logging.info('Artificial Intelligence response server running at: https://%s:%s\n', hostName, port)
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
httpd.server_close()
logging.info('Artificial Intelligence response server stopping...\n')
try:
run( hostName = HOSTNAME, port=PORT )
except Exception as e:
print(e)
Finally, start your server.
$ python server.py
Convert speech to text
Setup your project
$ npm install @ringcentral/sdk
$ npm install dotenv
Finally, add your .env
file you created earlier to your project directory.
Create and edit index.js
Copy and paste the code from below in index.js
. Be sure the values in your .env
file have been set properly, including the RC_MEDIA_URL
variable.
const RC = require('@ringcentral/sdk').SDK;
require('dotenv').config();
// Read instructions on running code samples to include all required variables
// https://developers.ringcentral.com/guide/basics/code-samples
NGROK = "<INSERT NGROK URL>"
WEBHOOK_URL = NGROK + "/webhook";
CONTENT_URI = 'https://github.com/ringcentral/ringcentral-api-docs/blob/main/resources/sample1.wav?raw=true'
// 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
});
const platform = rcsdk.platform();
platform.login({'jwt': process.env.RC_JWT})
platform.on(platform.events.loginSuccess, () => {
speechToText();
})
async function speechToText() {
try {
console.log("Calling RingCentral Speech To Text API");
let resp = await platform.post("/ai/audio/v1/async/speech-to-text?webhook=" + WEBHOOK_URL, {
"contentUri": CONTENT_URI,
"encoding": "Wav",
"languageCode": "en-US",
"source": "RingCentral",
"audioType": "Meeting",
"enablePunctuation": true,
"enableSpeakerDiarization": false
});
let json = await resp.json();
console.log("Request: " + resp.statusText);
console.log("Status code: " + resp.status);
if (resp.status == 202) {
console.log("Job ID: " + json.jobId);
console.log("Ready to receive response at: " + WEBHOOK_URL);
} 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 above to send the request to RingCentral and recive the response.
$ node index.js
Setup your project
$ pip install ringcentral
$ pip install python-dotenv
Finally, add your .env
file you created earlier to your project directory.
Create and edit index.py
Copy and paste the code from below in index.py
. Be sure the values in your .env
file have been set properly, including the RC_MEDIA_URL
variable.
#!/usr/bin/env python
from ringcentral import SDK
import os,sys,urllib.parse
from dotenv import load_dotenv
load_dotenv()
# Read instructions on running code samples to include all required variables
# https://developers.ringcentral.com/guide/basics/code-samples
NGROK = "<INSERT NGROK URL>"
WEBHOOK_URL = NGROK + "/webhook"
CONTENT_URI = 'https://github.com/ringcentral/ringcentral-api-docs/blob/main/resources/sample1.wav?raw=true'
rcsdk = SDK( os.environ.get('RC_CLIENT_ID'),
os.environ.get('RC_CLIENT_SECRET'),
os.environ.get('RC_SERVER_URL') )
platform = rcsdk.platform()
try:
platform.login( jwt=os.environ.get('RC_JWT') )
except Exception as e:
sys.exit("Unable to authenticate to platform: " + str(e))
resp = platform.post("/ai/audio/v1/async/speech-to-text?webhook=" + urllib.parse.quote(WEBHOOK_URL), {
"contentUri": CONTENT_URI,
"encoding": "Wav",
"languageCode": "en-US",
"source": "RingCentral",
"audioType": "Meeting",
"enablePunctuation": True,
"enableSpeakerDiarization": False
})
print(f'Request: {resp.response().reason}');
print(f'Status code: {resp.response().status_code}');
if resp.response().status_code == 202:
print(f'Job ID: {resp.json().jobId}');
print(f'Ready to receive response at: {WEBHOOK_URL}');
else:
print(f'An error occurred posting the request.');
Run your code
You are almost done. Now run your script above to send the request to RingCentral and recive the response.
$ python index.py
Install RingCentral PHP SDK
$ curl -sS https://getcomposer.org/installer | php
$ php composer.phar require ringcentral/ringcentral-php vlucas/phpdotenv
Create and edit index.php
Create a file called index.php
. Be sure the values in your .env
file have been set properly, including the RC_MEDIA_URL
variable.
<?php
// Remember to modify the path to where you installed the RingCentral SDK and saved your .env file!
require('./../vendor/autoload.php');
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../');
$dotenv->load();
// For the purpose of testing the code, we put the SMS recipient number in the environment variable.
// Feel free to set the SMS recipient directly.
$RECIPIENT = $_ENV['SMS_RECIPIENT'];
# 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'] ] );
read_extension_phone_number_detect_sms_feature();
} catch (\RingCentral\SDK\Http\ApiException $e) {
exit("Unable to authenticate to platform. Check credentials. " . $e->message . PHP_EOL);
}
/*
Read phone number(s) that belongs to the authenticated user and detect if a phone number
has the SMS capability
*/
function read_extension_phone_number_detect_sms_feature(){
global $platform;
$endpoint = "/restapi/v1.0/account/~/extension/~/phone-number";
$resp = $platform->get($endpoint);
$jsonObj = $resp->json();
foreach ($resp->json()->records as $record){
foreach ($record->features as $feature){
if ($feature == "SmsSender"){
// If a user has multiple phone numbers, check and decide which number
// to be used for sending SMS message.
return send_sms($record->phoneNumber);
}
}
}
if (count($jsonObj->records) == 0){
exit("This user does not own a phone number!");
}else{
exit("None of this user's phone number(s) has the SMS capability!");
}
}
/*
Send a text message from a user own phone number to a recipient number
*/
function send_sms($fromNumber){
global $platform, $RECIPIENT;
try {
$requestBody = array(
'from' => array ('phoneNumber' => $fromNumber),
'to' => array( array('phoneNumber' => $RECIPIENT) ),
// To send group messaging, add more (max 10 recipients) 'phoneNumber' object. E.g.
/*
'to' => array(
array('phoneNumber' => $RECIPIENT),
array('phoneNumber' => 'Recipient-Phone-Number')
),
*/
'text' => 'Hello World!'
);
$endpoint = "/account/~/extension/~/sms";
$resp = $platform->post($endpoint, $requestBody);
$jsonObj = $resp->json();
print("SMS sent. Message id: " . $jsonObj->id . PHP_EOL);
check_message_status($jsonObj->id);
} catch (\RingCentral\SDK\Http\ApiException $e) {
exit("Error message: " . $e->message . PHP_EOL);
}
}
/*
Check the sending message status until it's out of the queued status
*/
function check_message_status($messageId){
global $platform;
try {
$endpoint = "/restapi/v1.0/account/~/extension/~/message-store/".$messageId;
$resp = $platform->get($endpoint);
$jsonObj = $resp->json();
print("Message status: " . $jsonObj->messageStatus . PHP_EOL);
if ($jsonObj->messageStatus == "Queued"){
sleep(2);
check_message_status($jsonObj->id);
}
} catch (\RingCentral\SDK\Http\ApiException $e) {
exit("Error message: " . $e->message . PHP_EOL);
}
}
?>
<?php
/**********************************************************
Code snippet section for boostrap testing purpose
**********************************************************/
$RECIPIENT2 = $_ENV['SMS_RECIPIENT2'];
boostrap_test_function();
function boostrap_test_function(){
/*
print_r ("Test reading number features". PHP_EOL);
sleep(2);
include_once (__DIR__ .'/code-snippets/number-features.php');
return
print_r ("Test sending MMS". PHP_EOL);
sleep(2);
include_once (__DIR__ .'/code-snippets/send-mms.php');
print_r ("Test sending Fax". PHP_EOL);
sleep(2);
include_once (__DIR__ .'/code-snippets/send-fax.php');
print_r ("Test reading message store". PHP_EOL);
sleep(2);
include_once (__DIR__ .'/code-snippets/message-store.php');
print_r ("Test export message store". PHP_EOL);
sleep(2);
include_once (__DIR__ .'/code-snippets/message-store-export.php');
*/
print_r ("Test sending a2p SMS". PHP_EOL);
sleep(2);
include_once (__DIR__ .'/code-snippets/send-a2p-sms.php');
}
?>
Run your code
You are almost done. Now run your script.
$ php index.php
Await receipt of a response from RingCentral
In time, 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.
{
"status":"Success",
"response":{
"transcript":"Thunderstorms could produce large, hail isolated tornadoes and heavy rain.",
"confidence":0.87,
"words":[
{
"word":"thunderstorms",
"start":1.74,
"end":2.46,
"confidence":0.819
},
{
"word":"could",
"start":2.46,
"end":2.7,
"confidence":0.967
},
{
"word":"produce",
"start":2.7,
"end":3.1,
"confidence":0.982
},
{
"word":"large",
"start":3.1,
"end":3.42,
"confidence":0.826
},
{
"word":"hail",
"start":3.58,
"end":3.9,
"confidence":0.888
},
{
"word":"isolated",
"start":4.14,
"end":4.46,
"confidence":0.827
},
{
"word":"tornadoes",
"start":4.54,
"end":5.18,
"confidence":0.844
},
{
"word":"and",
"start":5.18,
"end":5.34,
"confidence":0.99
},
{
"word":"heavy",
"start":5.42,
"end":5.74,
"confidence":0.87
},
{
"word":"rain",
"start":5.82,
"end":5.9,
"confidence":0.902
}
],
"audio_duration":7.096599
}
}