Real-time output with PSTN dialing - Telephony API

In this example let's walk through how to get the real-time transcription and insights events in a telephone call.

In this document you'll find references to the following variable names, which you need to replace with your values:

KeyDescription
APP_IDThe application ID you get from the home page of the platform.
APP_SECRETThe application secret you get from the home page of the platform.
AUTH_TOKENThe JWT you get after authentication with Symbl.ai.
YOUR_PHONE_NUMBERA phone number that you want the API to connect to. Be sure to include the country code.
EMAIL_ADDRESSThe email address where you want to send the summary email.
DTMF_MEETING_CODEThe meeting code provided by the meeting provider, such as Zoom.

View the GitHub repo at Realtime Output with PSTN Dial-in using Voice SDK.

Getting started

To get started using this API, you need to sign up for the Symbl Developer Platform and receive your API credentials.

This example uses Node.js and the Symbl.ai JavaScript SDK. You can install them using the Node Package Manager:

npm install @symblai/symbl-js

You can then use the library within your project like this:

const {sdk} = require('@symblai/symbl-js')

Initialize the Symbl.ai JavaScript SDK:

await sdk.init({
  appId: APP_ID,
  appSecret: APP_SECRET,
  basePath: 'https://api.symbl.ai',
});

Open up the connection and pass the configuration options:

const connection = await sdk.startEndpoint({
  endpoint: {
    type: 'pstn',
    phoneNumber: YOUR_PHONE_NUMBER,
  },
  insightTypes: ['action_item', 'question'],
  actions: [
    {
      invokeOn: 'stop',
      name: 'sendSummaryEmail',
      parameters: {
        emails: [EMAIL_ADDRESS], // Add valid email addresses to received email
      },
    },
  ],
  data: {
    session: {
      name: 'My Test Meeting',
    },
  },
});

You'll notice various configuration options available such as endpoint, insightTypes, and actions.

Endpoints

This example uses a PSTN connection but you can also connect via SIP:

endpoint: {  
   dtmf: DTMF_MEETING_CODE,
   type: 'sip',
   uri: 'sip:[email protected]'
}

Insight Types

Symbl.ai provides various insights from the call. The main insights categories are question and action_item. To include insights in processing, you need to specify them in the configuration as follows:

{   
   insightTypes: ['action_item', 'question']
}

Actions

You can specify different actions to happen during the call. The only required action is to specify an email address to receive a summary of the conversation.

actions: [
  {
    invokeOn: 'stop',
    name: 'sendSummaryEmail',
    parameters: {
      emails: [EMAIL_ADDRESS] // Add valid email addresses to received email
    }
  }
]

Getting the Connection ID

For subscribing to the data, you need to use connectionId unique to each active connection. To get it you can simply retrieve it from connection response:

const connectionId = connection.connectionId;

Real-time insights

For subscribing to the data, you need to use the connectionId unique to each active connection. To get it you can retrieve it from connection response:

const connectionId = connection.connectionId;

After you have the connection ID, you can use it to subscribe to our connection:

sdk.subscribeToConnection(connectionId, (data) => {});

data is an object with a type field. Supported types are transcript_response,
insight_response and message_response.

For real-time transcription you want to check for transcript_response:

if (type === 'transcript_response') {
  const {payload} = data;
  process.stdout.write('Live: ' + payload && payload.content + '\r');
}

Transcripts are changing all the time, but once they are processed into reasonable message and not just words, you get a message_response which you need to handle:

if (type === 'message_response') {
  const {messages} = data;
  messages.forEach((message) => {
    process.stdout.write('Message: ' + message.payload.content + '\n');
  })
}

And finally, if there are any questions or action items during conversation, you get insight_response:

if (type === 'insight_response') {
  const {insights} = data;
  insights.forEach((insight) => {
    process.stdout.write(`Insight: ${insight.type} - ${insight.text} \n\n`);
  })
}

Speaker separation

We can send different speaker events to our connection indicating that different speakers started speaking. This returns more personalized insights and a better meeting summary.

In our example, we do this by calling the helper function getScheduleEvent, which we review later in this documenr. We pass SpeakerEvent type to it using SpeakerEvent.types enum from @symblai/symbl-js, passing user data and timestamp:

const scheduleEvent = getScheduleEvent(sdk, connectionId)

setTimeout(() => {
  // Schedule all the events to be sent.
  scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 0)
  scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 5)
}, 1000)

This example retrieves users just from the global array of users. In your implementation, you might retrieve user data from a database:

const users = {
  john: {
    userId: '[email protected]',
    name: 'John'
  },
  mary: {
    userId: '[email protected]',
    name: 'Mary'
  }
}

In order to push event to our connection we create an event as follows:

const speakerEvent = new SpeakerEvent({
  type: eventType,
  user
});

speakerEvent.timestamp = new Date().toISOString();

Then push it using pushEventOnConnection function provided by SDK:

sdk.pushEventOnConnection(connectionId, speakerEvent.toJSON(), (err) => {
  if (err) {
    console.error('Error during push event.', err);
  } else {
    console.log('Event pushed!');
  }
});

This example just touches the surface of what you can do with our Streaming API. If you would like to learn more about it you can visit the Streaming API documentation.

Full Code Example

const {sdk, SpeakerEvent} = require('@symblai/symbl-js')

const getScheduleEvent = (sdk, connectionId) => {
  return (eventType, user, time) => {
    setTimeout(() => {
      const speakerEvent = new SpeakerEvent({
        type: eventType,
        user,
      })
      speakerEvent.timestamp = new Date().toISOString()

      console.log(
        `Pushing event [${speakerEvent.timestamp}] ${speakerEvent.type} : ${speakerEvent.user.name}`,
      )

      sdk.pushEventOnConnection(connectionId, speakerEvent.toJSON(), (err) => {
        if (err) {
          console.error('Error during push event.', err)
        } else {
          console.log('Event pushed!')
        }
      })
    }, time * 1000)
  }
}

const users = {
  john: {
    userId: '[email protected]',
    name: 'John',
  },
  mary: {
    userId: '[email protected]',
    name: 'Mary',
  },
}

;(async () => {
  try {
    // Initialize the SDK
    await sdk.init({
      appId: APP_ID,
      appSecret: APP_SECRET,
      basePath: 'https://api.symbl.ai',
    })

    console.log('SDK Initialized')

    const connection = await sdk.startEndpoint({
      endpoint: {
        type: 'pstn',
        phoneNumber: DEFAULT_PHONE_NUMBER,
      },
      insightTypes: ['action_item', 'question'],
      actions: [
        {
          invokeOn: 'stop',
          name: 'sendSummaryEmail',
          parameters: {
            emails: [EMAIL_ADDRESS], // Add valid email addresses to received email
          },
        },
      ],
      data: {
        session: {
          name: 'My Test Meeting',
        },
      },
    })

    const connectionId = connection.connectionId
    console.log('Successfully connected. Connection ID: ', connectionId)
    const scheduleEvent = getScheduleEvent(sdk, connectionId)

    setTimeout(() => {
      // Schedule all the events to be sent.
      scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 0)
      scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 5)

      scheduleEvent(SpeakerEvent.types.startedSpeaking, users.mary, 5)
      scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.mary, 15)

      scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 15)
      scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 45)

      scheduleEvent(SpeakerEvent.types.startedSpeaking, users.mary, 45)
      scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.mary, 60)
    }, 1000)

    console.log('Subscribing to the live events on the connection.')
    // Subscribe to connection using connectionId.
    // Multiple subscriptions to same connectionId are allowed. It can be useful to get the updates at multiple clients.
    sdk.subscribeToConnection(connectionId, (data) => {
      // console.log(data);
      const {type} = data
      if (type === 'transcript_response') {
        const {payload} = data
        process.stdout.write('Live: ' + payload && payload.content + '\r')
        // console.log('Live: ',payload && payload.content);
      } else if (type === 'message_response') {
        const {messages} = data
        messages.forEach((message) => {
          process.stdout.write('Message: ' + message.payload.content + '\n')
        })
      } else if (type === 'insight_response') {
        const {insights} = data
        insights.forEach((insight) => {
          process.stdout.write(
            `Insight: ${insight.type} - ${insight.text} \n\n`,
          )
        })
      }
    })

    // Scheduling stop endpoint call after 60 seconds
    setTimeout(async () => {
      console.log('Stopping the connection')
      try {
        await sdk.stopEndpoint({
          connectionId: connection.connectionId,
        })
        console.log('Connection stopped.')
        console.log('Summary Info:', connection.summaryInfo)
        console.log('Conversation ID:', connection.conversationId)
      } catch (err) {}
    }, 62 * 1000)
  } catch (e) {}
})()

Running The Example

Create a JavaScript file named app.js and copy the preceding code into the file. Fill in the placeholder values with your own values. Use NPM to install the required libraries: npm install @symblai/symbl-js. In the terminal, run the following command:

$ node app.js

Success returns a response in the console.

📘

If you have any questions or comments about our API, you can join our Support Slack or send us an email at [email protected]