├── .env.default ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── config.yml │ ├── documentation.md │ ├── feature-request.md │ └── feedback-report.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── CODEOWNERS ├── LICENSE ├── README.md ├── examples └── node │ ├── async-upload │ ├── action-items │ │ ├── README.md │ │ └── index.js │ ├── analytics │ │ ├── README.md │ │ └── index.js │ ├── entities │ │ ├── README.md │ │ └── index.js │ ├── follow-ups │ │ ├── README.md │ │ └── index.js │ ├── messages │ │ ├── README.md │ │ └── index.js │ ├── questions │ │ ├── README.md │ │ └── index.js │ ├── redaction │ │ ├── README.md │ │ └── index.js │ ├── summary │ │ ├── README.md │ │ └── index.js │ ├── topics │ │ ├── README.md │ │ └── index.js │ └── trackers │ │ ├── README.md │ │ └── index.js │ ├── async-url │ ├── summary-ui-audio │ │ ├── README.md │ │ └── index.js │ └── summary-ui-video │ │ ├── README.md │ │ └── index.js │ ├── common │ ├── README.md │ ├── async.js │ ├── common.js │ ├── management.js │ ├── post-file.js │ ├── post-url.js │ ├── streaming-output-device.js │ ├── streaming.js │ └── summary-ui.js │ ├── management │ ├── create │ │ ├── README.md │ │ └── index.js │ ├── delete │ │ ├── README.md │ │ └── index.js │ └── list │ │ ├── README.md │ │ └── index.js │ ├── streaming │ ├── action-items │ │ ├── README.md │ │ └── index.js │ ├── enable-all │ │ ├── README.md │ │ └── index.js │ ├── questions │ │ ├── README.md │ │ └── index.js │ ├── topics │ │ ├── README.md │ │ └── index.js │ └── trackers │ │ ├── README.md │ │ └── index.js │ └── telephony │ ├── custom-audio-config │ ├── README.md │ └── index.js │ ├── custom-language-and-timezone │ ├── README.md │ └── index.js │ ├── realtime-insights-transcription │ ├── README.md │ └── index.js │ ├── realtime-intent-detection │ ├── README.md │ └── index.js │ └── speaker-events │ ├── README.md │ └── index.js ├── newPhonecall.mp3 ├── package-lock.json ├── package.json ├── phoneNumber.mp3 ├── run-example.sh ├── tutorials └── node │ └── live-transcript-phone-call │ ├── .gitignore │ ├── README.md │ ├── index.js │ └── package.json └── yarn.lock /.env.default: -------------------------------------------------------------------------------- 1 | # Add your appId here 2 | APP_ID= 3 | 4 | # Add your appSecret here 5 | APP_SECRET= 6 | 7 | # If you have access to a custom domain add it here. 8 | # CUSTOM_DOMAIN= 9 | 10 | SUMMARY_EMAIL= 11 | 12 | # For Telephony API (PSTN) 13 | # Use format: {countryCode}{phoneNumber}, don't use special characters 14 | DEFAULT_PHONE_NUMBER= # E.g. 18296348723, where 1 is country code for US and rest is the number -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: File a bug for something not working as expected. 4 | title: '' 5 | labels: kind/bug, triage/needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | ## Bug Report 12 | 13 | 14 | 15 | ## Expected Behavior 16 | 17 | 18 | 19 | ## Steps to Reproduce the Bug 20 | 21 | 22 | 23 | ## Screenshots or additional information and context 24 | 25 | 26 | 27 | ## Environment Details 28 | 29 | * Operating System: 30 | * Node.js version (`node --version`): 31 | 32 | ## Diagnostics logs 33 | 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Docs Request 3 | about: File a request for incorrect or suggested docs. 4 | title: '' 5 | labels: kind/docs, triage/needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Description 11 | 12 | 13 | 14 | ## Location 15 | 16 | 17 | 18 | ## Additional Context 19 | 20 | 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: File a request for a new feature. 4 | title: '' 5 | labels: kind/feature, triage/needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Feature Request 13 | 14 | 15 | 16 | ## Describe alternatives you've considered 17 | 18 | 19 | 20 | ## Additional context 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feedback-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feedback Report 3 | about: File general feedback on samples in the repo. 4 | title: '' 5 | labels: kind/feedback, triage/needs-triage 6 | assignees: '' 7 | 8 | --- 9 | 10 | 11 | 12 | ## Feedback 13 | 14 | 15 | 16 | ## Suggested Changes 17 | 18 | 19 | 20 | ## Environment Details 21 | 22 | * Operating System: 23 | * Node.js version (`node --version`): 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## What this PR does / why we need it 2 | 5 | 6 | ## Which issue(s) this PR fixes 7 | 10 | Fixes: # 11 | 12 | ## Describe testing done for PR 13 | 16 | 17 | ## Special notes for your reviewer 18 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | node_modules 4 | .env 5 | .DS_Store 6 | tutorials/node/2022-voice-hackathon-symbl-vonage/multiple-devices/learning-opentok-node 7 | tutorials/node/2022-voice-hackathon-symbl-vonage/multiple-devices/opentok-web-samples 8 | tutorials/node/2022-voice-hackathon-symbl-vonage/single-device/opentok-node -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # These owners will be the default owners for everything in the repo. 5 | * @dvonthenen @toshish @avoliva 6 | 7 | # Order is important. The last matching pattern has the most precedence. 8 | # So if a pull request only touches javascript files, only these owners 9 | # will be requested to review. 10 | # *.js 11 | 12 | # You can also use email addresses if you prefer. 13 | # docs/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 David vonThenen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Getting Started - Examples/Samples 2 | 3 | Symbl's APIs empower developers to enable: 4 | - **Real-time** analysis of free-flowing discussions to automatically surface highly relevant summary discussion topics, contextual insights, suggestive action items, follow-ups, decisions, and questions. 5 | - **Voice APIs** that makes it easy to add AI-powered conversation intelligence to either [Telephony][telephony], [Streaming][streaming], or [Async][async] interfaces. 6 | - **Conversation APIs** that provide a REST interface for managing and processing your conversation data. 7 | - **Summary UI** with a fully customizable and editable reference experience that indexes a searchable transcript and shows generated actionable insights, topics, timecodes, and speaker information. 8 | 9 |
10 | 11 | ## List of Examples as Code 12 | 13 | ### Upload a Conversation using the Async APIs 14 | 15 | The Async APIs allow individuals to obtain conversation intelligence on offline, pre-recorded conversations in an audio format (mp3, wav, etc). These examples demonstrate how to upload an audio or video files for processing. 16 | 17 | - [Action-Items](./examples/node/async-upload/action-items) 18 | - [Analytics](./examples/node/async-upload/analytics) 19 | - [Entities](./examples/node/async-upload/entites) 20 | - [Follow-Ups](./examples/node/async-upload/follow-ups) 21 | - [Messages](./examples/node/async-upload/messages) 22 | - [Questions](./examples/node/async-upload/questions) 23 | - [Summary](./examples/node/async-upload/summary) 24 | - [Topics](./examples/node/async-upload/topics) 25 | - [Trackers](./examples/node/async-upload/trackers) 26 | 27 | ### Reference a URL using the Async APIs 28 | 29 | - Action-Items: TODO 30 | - Analytics: TODO 31 | - Entities: TODO 32 | - Follow-Ups: TODO 33 | - Messages: TODO 34 | - Questions: TODO 35 | - Summary: TODO 36 | - Topics: TODO 37 | - Trackers: TODO 38 | - Summary UI for Audio: TODO 39 | - [Summary UI using a Video](./examples/node/async-url/summary-ui-video) 40 | 41 | ### Management (Tracker management) 42 | 43 | The Management APIs allows individuals to create, list, delete Trackers that can be used 44 | to highlight important or significant words, topics, etc in a given conversation. 45 | 46 | - [Create a Tracker](./examples/node/management/create) 47 | - [List all Trackers](./examples/node/management/list) 48 | - [Delete a Tracker](./examples/node/management/delete) 49 | 50 | ### Real-time 51 | 52 | These example applications use WebSockets in order to using the Streaming APIs 53 | get real-time analysis on conversation for a variety of intelligence metrics. These 54 | examples make use of the Microphone in order to demonstrate the real-time 55 | analytics capabilities. 56 | 57 | - [Topics](./examples/node/realtime/topics) 58 | - [Trackers](./examples/node/realtime/trackers) 59 | - [Questions](./examples/node/realtime/questions) 60 | - [Action-Items](./examples/node/realtime/action-items) 61 | 62 | ### Telephony 63 | 64 | These example applications the Telephony APIs to get real-time analysis on conversation 65 | for a variety of intelligence metrics. 66 | 67 | - [Passing different Audio Codecs](./examples/node/telephony/custom-audio-config) 68 | - [Realtime Output with PSTN Dialin using Voice SDK](./examples/node/telephony/realtime-insights-transcription) 69 | - Get the live transcription and insights events in a Telephone call. 70 | - [Intent Detection with PSTN Dial-In using Voice SDK](./examples/node/telephony/realtime-intent-detection) 71 | - Get the intents, real-time in a Telephone call. 72 | - [PSTN Dial-in using Voice SDK](./examples/node/telephony/speaker-events) 73 | - Establishes a connection using a phone number through PSTN, to send speaker 74 | events, generate insights, and display a summary URL with the output. You 75 | can see how to initialize the Voice SDK, connect to the endpoint, push 76 | speaker events and get the summary URL. 77 | 78 | > **_NOTE:_** Validation on the `Telephony` examples are still pending. If you notice an issue, drop us a line! 79 | 80 | ## Install 81 | 82 | Clone this repo on your machine and perform npm install. 83 | 84 | ```bash 85 | git clone https://github.com/symblai/getting-started-samples.git 86 | cd getting-started-samples 87 | npm install # Alternatively, you can also use yarn 88 | ``` 89 | 90 | Code samples in this repo use [dotenv](https://github.com/motdotla/dotenv) for 91 | configurations. Make copy of `.env.default` file as `.env`. 92 | 93 | ```bash 94 | cp .env.default .env 95 | ``` 96 | 97 | Update `APP_ID`, `APP_SECRET`, and `SUMMARY_EMAIL` with valid values. You are 98 | going to new a Symbl account. If you don't have one, you can [sign up here][symbl_signup] 99 | for a free account which will allow you to process 1,000 minutes of conversation each month. 100 | Update any additional configuration such as `DEFAULT_PHONE_NUMBER` may be required for 101 | a particular sample to work properly. 102 | 103 | ## Run 104 | 105 | Make sure your `.env` file is configured correctly. 106 | 107 | Once you've configured the above, execute the `run-examples.sh` script. 108 | 109 | ``` 110 | Syntax: run-example.sh [API_TYPE] 111 | 112 | Required Parameters: 113 | - API_TYPE (required): async-upload, realtime or telephony 114 | 115 | Optional parameters: 116 | - PROJECT_NAME (optional): if missing, will provide a list of projects 117 | - SDK_LANG (optional): environment variable to select the language 118 | - (optional): some action require user input 119 | 120 | Examples: 121 | To list examples for streaming projects, run: 122 | run-example.sh realitime 123 | 124 | To the realtime tracker example, run: 125 | run-example.sh realitime tracker 126 | ``` 127 | 128 | ## Testing for PSTN 129 | 130 | If you're dialing to a regular phone number then you will receive a call. If 131 | you've dialed into a meeting platform, you'll see another participant join the 132 | meeting. Begin speaking after you see new participant, the call will end and 133 | you'll receive an email with the generated insights if you have passed valid 134 | email Id in the code. 135 | 136 | ## Community 137 | 138 | If you have any questions, feel free to reach out to us at devrelations@symbl.ai or through our [Community Slack][slack] or our [forum][developer_community]. 139 | 140 | This guide is actively developed, and we love to hear from you! Please feel free to [create an issue][issues] or [open a pull request][pulls] with your questions, comments, suggestions and feedback. If you liked our integration guide, please star our repo! 141 | 142 | This library is released under the [MIT License][license] 143 | 144 | [telephony]: https://docs.symbl.ai/docs/telephony/overview/post-api 145 | [streaming]: https://docs.symbl.ai/reference/streaming-api-reference 146 | [async]: https://docs.symbl.ai/reference/async-api-1 147 | [developer_community]: https://community.symbl.ai/?_ga=2.134156042.526040298.1609788827-1505817196.1609788827 148 | [slack]: https://join.slack.com/t/symbldotai/shared_invite/zt-4sic2s11-D3x496pll8UHSJ89cm78CA 149 | [signup]: https://platform.symbl.ai/?_ga=2.63499307.526040298.1609788827-1505817196.1609788827 150 | [issues]: https://github.com/symblai/getting-started-samples/issues 151 | [pulls]: https://github.com/symblai/getting-started-samples/pulls 152 | [license]: LICENSE 153 | [symbl_signup]: https://platform.symbl.ai/signup?utm_source=symbl&utm_medium=blog&utm_campaign=devrel&_ga=2.226597914.683175584.1662998385-1953371422.1659457591&_gl=1*mm3foy*_ga*MTk1MzM3MTQyMi4xNjU5NDU3NTkx*_ga_FN4MP7CES4*MTY2MzEwNDQyNi44Mi4xLjE2NjMxMDQ0MzcuMC4wLjA. 154 | -------------------------------------------------------------------------------- /examples/node/async-upload/action-items/README.md: -------------------------------------------------------------------------------- 1 | # Using the ActionItem Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the ActionItem results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on ActionItems using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the ActionItems 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process ActionItems for the audio file 33 | */ 34 | var actionItems = await intelligence.ActionItems(token, result.conversationId); 35 | output = JSON.parse(actionItems); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/action-items/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process ActionItems for the audio file 24 | */ 25 | var actionItems = await async.ActionItems(token, result.conversationId, "none"); 26 | var output = JSON.parse(actionItems); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/analytics/README.md: -------------------------------------------------------------------------------- 1 | # Using the Analytics Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the Analytics results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Analytics using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the Analytics 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process Analytics for the audio file 33 | */ 34 | var analytics = await intelligence.Analytics(token, result.conversationId); 35 | output = JSON.parse(analytics); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/analytics/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process Analytics for the audio file 24 | */ 25 | var analytics = await async.Analytics(token, result.conversationId, "none"); 26 | var output = JSON.parse(analytics); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/entities/README.md: -------------------------------------------------------------------------------- 1 | # Using the Entities Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the Entities results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Entities using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the Entities 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process Entities for the audio file 33 | */ 34 | var entities = await intelligence.Entities(token, result.conversationId); 35 | output = JSON.parse(entities); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/entities/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process Entites for the audio file 24 | */ 25 | var entities = await async.Entities(token, result.conversationId, "none"); 26 | var output = JSON.parse(entities); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/follow-ups/README.md: -------------------------------------------------------------------------------- 1 | # Using the FollowUp Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the FollowUp results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on FollowUps using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the FollowUps 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process FollowUps for the audio file 33 | */ 34 | var followUps = await intelligence.FollowUps(token, result.conversationId); 35 | output = JSON.parse(followUps); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/follow-ups/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process FollowUps for the audio file 24 | */ 25 | var followUps = await async.FollowUps(token, result.conversationId, "none"); 26 | var output = JSON.parse(followUps); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/messages/README.md: -------------------------------------------------------------------------------- 1 | # Using the Message Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the Message results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Messages using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the Messages 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process Messages for the audio file 33 | */ 34 | var messages = await intelligence.Messages(token, result.conversationId); 35 | output = JSON.parse(messages); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/messages/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process Messages for the audio file 24 | */ 25 | var messages = await async.Messages(token, result.conversationId, "none"); 26 | var output = JSON.parse(messages); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/questions/README.md: -------------------------------------------------------------------------------- 1 | # Using the Question Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio fileto the platform and obtain the Question results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Questions using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the Questions 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process Questions for the audio file 33 | */ 34 | var questions = await intelligence.Questions(token, result.conversationId); 35 | output = JSON.parse(questions); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/questions/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process Questions for the audio file 24 | */ 25 | var questions = await async.Questions(token, result.conversationId, "none"); 26 | var output = JSON.parse(questions); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/redaction/README.md: -------------------------------------------------------------------------------- 1 | # Using the Redaction Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the Message with Redacted results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Messages using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the Messages with Redacted Results 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process Messages for the audio file 33 | */ 34 | var messages = await intelligence.Messages(token, result.conversationId, "exclude=[\"LOCATION_STATE\""]&redact=true"); 35 | output = JSON.parse(messages); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/redaction/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process Messages for the audio file 24 | */ 25 | var messages = await async.Messages(token, result.conversationId, "exclude=[\"PERSON_NAME\"]&redact=true"); 26 | var output = JSON.parse(messages); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/summary/README.md: -------------------------------------------------------------------------------- 1 | # Using the Summary Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the Summary results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Summary using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the Summary 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process Summary for the audio file 33 | */ 34 | var summary = await intelligence.summary(token, result.conversationId); 35 | output = JSON.parse(summary); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/summary/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process Summary for the audio file 24 | */ 25 | var summary = await async.Summary(token, result.conversationId, "none"); 26 | var output = JSON.parse(summary); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/topics/README.md: -------------------------------------------------------------------------------- 1 | # Using the Topic Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the Topic results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Topics using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the Topics 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process Topics for the audio file 33 | */ 34 | var topics = await intelligence.Topics(token, result.conversationId); 35 | output = JSON.parse(topics); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/topics/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const async = require('../../common/async.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await post.Post(token, process.env.FILENAME); 21 | 22 | /* 23 | Process Topics for the audio file 24 | */ 25 | var topics = await async.Topics(token, result.conversationId, "none"); 26 | var output = JSON.parse(topics); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-upload/trackers/README.md: -------------------------------------------------------------------------------- 1 | # Using the Tracker Async API 2 | 3 | This is a simple main-style sample application using Symbl's Async API. This application will post an audio file to the platform and obtain the Tracker results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Trackers using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the Trackers 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await post.Post(token, "All_I_Really_Want.mp3"); 30 | 31 | /* 32 | Process Trackers for the audio file 33 | */ 34 | var trackers = await intelligence.Trackers(token, result.conversationId); 35 | output = JSON.parse(trackers); 36 | console.log(output); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-upload/trackers/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config() 2 | const util = require('util') 3 | 4 | const common = require('../../common/common.js'); 5 | const post = require('../../common/post-file.js'); 6 | const async = require('../../common/async.js'); 7 | 8 | async function main() { 9 | /* 10 | Login and get token 11 | */ 12 | var token = await common.Login(); 13 | 14 | /* 15 | Post the audio file to the Symbl platform 16 | */ 17 | var result = await post.Post(token, process.env.FILENAME); 18 | 19 | /* 20 | Process Trackers for the audio file 21 | */ 22 | var trackers = await async.Trackers(token, result.conversationId, "none"); 23 | var output = JSON.parse(trackers); 24 | console.log(util.inspect(output, false, null, true)); 25 | } 26 | 27 | main(); 28 | -------------------------------------------------------------------------------- /examples/node/async-url/summary-ui-audio/README.md: -------------------------------------------------------------------------------- 1 | # Using the Summary-UI API 2 | 3 | This is a simple main-style sample application using Symbl's Summary UI API. This application will post an audio file to the platform and obtain the Summary results via a pre-canned UI when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Summary using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the audio file and wait for the Symbl platform to process it 17 | 3. Retrieve the URL for Summary UI 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the audio file to the Symbl platform 28 | */ 29 | var result = await posturl.PostAudioURL(token, process.env.URL); 30 | 31 | /* 32 | Process Summary for the audio file 33 | */ 34 | var summary = await summaryui.SummaryAudioUI(token, process.env.URL, result.conversationId); 35 | var output = JSON.parse(summary); 36 | console.log(util.inspect(output, false, null, true)); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-url/summary-ui-audio/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const posturl = require('../../common/post-url.js'); 9 | const summaryui = require('../../common/summary-ui.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the audio file to the Symbl platform 19 | */ 20 | var result = await posturl.PostAudioURL(token, process.env.URL); 21 | 22 | /* 23 | Process Summary for the audio file 24 | */ 25 | var summary = await summaryui.SummaryAudioUI(token, process.env.URL, result.conversationId); 26 | var output = JSON.parse(summary); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/async-url/summary-ui-video/README.md: -------------------------------------------------------------------------------- 1 | # Using the Summary-UI API 2 | 3 | This is a simple main-style sample application using Symbl's Summary UI API. This application will post an video file to the platform and obtain the Summary results via a pre-canned UI when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Async Conversation Processing 12 | 13 | Obtaining intelligence on Summary using the Async API is pretty straight forward, the steps are: 14 | 15 | 1. Login 16 | 2. Post the video file and wait for the Symbl platform to process it 17 | 3. Retrieve the URL for Summary UI 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Post the video file to the Symbl platform 28 | */ 29 | var result = await posturl.PostVideoURL(token, process.env.URL); 30 | 31 | /* 32 | Process Summary for the video file 33 | */ 34 | var summary = await summaryui.SummaryVideoUI(token, process.env.URL, result.conversationId); 35 | var output = JSON.parse(summary); 36 | console.log(util.inspect(output, false, null, true)); 37 | } 38 | 39 | main(); 40 | ``` -------------------------------------------------------------------------------- /examples/node/async-url/summary-ui-video/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const posturl = require('../../common/post-url.js'); 9 | const summaryui = require('../../common/summary-ui.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Post the video file to the Symbl platform 19 | */ 20 | var result = await posturl.PostVideoURL(token, process.env.URL); 21 | 22 | /* 23 | Process Summary for the video file 24 | */ 25 | var summary = await summaryui.SummaryVideoUI(token, process.env.URL, result.conversationId); 26 | var output = JSON.parse(summary); 27 | console.log(util.inspect(output, false, null, true)); 28 | } 29 | 30 | main(); 31 | -------------------------------------------------------------------------------- /examples/node/common/README.md: -------------------------------------------------------------------------------- 1 | # Common Libraries for Symbl Javascript SDK 2 | 3 | The `common` library contains functions, configuration, etc that is common to all projects in the `example` folder. You can find a description of each javascript file below. 4 | 5 | ## common.js 6 | 7 | This describes the common or minimal configuration needed to invoke a real-time request `sdk.startRealtimeRequest` on the Symbl platform. We can retreive that using the `GetConfigScaffolding()` function. 8 | 9 | ### Common Configuration Parameters 10 | 11 | The configuration needs a unique id to associate to our Symbl request. We will create this Id using `uuid` package 12 | 13 | `const id = uuid();` 14 | 15 | The minimal required input: 16 | 17 | - `insightTypes` - we need to provide which insights will be detected. Supported ones are `action_item` and `question`. 18 | - `config` - object with meeting title, confidence threshold and the sampleRate. 19 | - `speaker` - object to define who is the speaker. To distinguish between different speakers we also need to provide `userId` with valid email, so after meeting will end, we will receive summary email. 20 | - `handlers` - these handlers are used to detect speech, messages and insights. 21 | - `onSpeechDetected` - This will return live transcription of the call 22 | - `onMessageResponse` - When processed messages are available, this callback will be called 23 | - `onInsightResponse` - When Symbl detects an insight, this callback will be called. 24 | 25 | ## streaming.js 26 | 27 | This describes the basic layout, operation, design of the `streaming.js` library. 28 | 29 | ### High-level Components Used 30 | 31 | This example runs on node, so we will use `@symblai/symbl-js` package. 32 | 33 | ```javascript 34 | require('dotenv').config() 35 | 36 | const {sdk} = require('@symblai/symbl-js') 37 | ``` 38 | 39 | For demo purposes, we're using the audio from microphone and passing it on to websocket connection. 40 | 41 | We use the `mic` module to make sure all requirements for this application are met. For instance, we need `sox` package or `ALSA` tools to be installed. [`mic` installation instructions](https://www.npmjs.com/package/mic#installation) 42 | 43 | For MacOS, it can be as simple as running: 44 | 45 | ```bash 46 | brew install sox 47 | npm install mic 48 | ``` 49 | 50 | ### Initialize Mic 51 | 52 | ```javascript 53 | const mic = require('mic') 54 | 55 | const sampleRateHertz = 16000 56 | 57 | const micInstance = mic({ 58 | rate: sampleRateHertz, 59 | channels: '1', 60 | debug: false, 61 | exitOnSilence: 6, 62 | }) 63 | ``` 64 | 65 | ### Initialize Symbl SDK 66 | 67 | ```javascript 68 | try { 69 | await sdk.init({ 70 | appId: process.env.APP_ID, 71 | appSecret: process.env.APP_SECRET, 72 | basePath: 'https://api.symbl.ai', 73 | }) 74 | .then(() => console.log('SDK Initialized.')) 75 | .catch(err => console.error('Error in initialization.', err)); 76 | } 77 | catch (e) {} 78 | ``` 79 | 80 | ### Where the Magic Happens 81 | 82 | This is where the magic happens and it's quite simple. We start the websocket and then connect the Mic to the websocket. 83 | 84 | ```javascript 85 | // Start Real-time Request (Uses Realtime WebSocket API behind the scenes) 86 | const connection = await sdk.startRealtimeRequest(config); 87 | console.log('Successfully connected. Conversation ID: ', connection.conversationId); 88 | 89 | // get the mic 90 | const micInputStream = micInstance.getAudioStream() 91 | 92 | /** 93 | * Raw audio stream 94 | */ 95 | micInputStream.on('data', (data) => { 96 | // Push audio from Microphone to websocket connection 97 | connection.sendAudio(data) 98 | }) 99 | ``` 100 | -------------------------------------------------------------------------------- /examples/node/common/async.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('./common.js'); 6 | const fetch = require('node-fetch'); 7 | 8 | exports.Topics = async function(token, conversationId, params) { 9 | return processIntelligence(token, "topics", conversationId, params); 10 | } 11 | 12 | exports.Questions = async function(token, conversationId, params) { 13 | return processIntelligence(token, "questions", conversationId, params); 14 | } 15 | 16 | exports.FollowUps = async function(token, conversationId, params) { 17 | return processIntelligence(token, "follow-ups", conversationId, params); 18 | } 19 | 20 | exports.Entities = async function(token, conversationId, params) { 21 | return processIntelligence(token, "entities", conversationId, params); 22 | } 23 | 24 | exports.ActionItems = async function(token, conversationId, params) { 25 | return processIntelligence(token, "action-items", conversationId, params); 26 | } 27 | 28 | exports.Messages = async function(token, conversationId, params) { 29 | return processIntelligence(token, "messages", conversationId, params); 30 | } 31 | 32 | exports.Summary = async function(token, conversationId, params) { 33 | return processIntelligence(token, "summary", conversationId, params); 34 | } 35 | 36 | exports.Analytics = async function(token, conversationId, params) { 37 | return processIntelligence(token, "analytics", conversationId, params); 38 | } 39 | 40 | exports.Trackers = async function(token, conversationId, params) { 41 | return processIntelligence(token, "trackers-detected", conversationId, params); 42 | } 43 | 44 | async function processIntelligence(token, api, conversationId, params) { 45 | // console.log("conversationId: " + conversationId); 46 | 47 | const header = { 48 | "Content-Type": "application/json", 49 | "Authorization": "Bearer " + token, 50 | "Connection": "keep-alive", 51 | }; 52 | 53 | if (params == "all") { 54 | params = "parentRefs=true&sentiment=true" 55 | } 56 | 57 | var uri = `https://api.symbl.ai/v1/conversations/${conversationId}/${api}?${params}`; 58 | if (params == "none" || params == "") { 59 | uri = `https://api.symbl.ai/v1/conversations/${conversationId}/${api}` 60 | } 61 | var response = await common.Query(uri, "GET", header, null); 62 | var text = await response.text(); 63 | // console.log("response: " + response); 64 | // console.log("reason: " + text); 65 | 66 | return new Promise((resolve) => { 67 | if (response.status == 200 || response.status == 201) { 68 | resolve(text); 69 | } else { 70 | throw new Error(`${response.status}: ${text}`); 71 | } 72 | }); 73 | } 74 | -------------------------------------------------------------------------------- /examples/node/common/common.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const fetch = require('node-fetch'); 6 | const uuid = require('uuid').v4 7 | // const util = require('util') 8 | 9 | const sampleRateHertz = 16000 10 | 11 | /* 12 | Simple Login that returns an AccessToken 13 | */ 14 | exports.Login = async function() { 15 | const body = { 16 | 'type': 'application', 17 | 'appId': process.env.APP_ID, 18 | 'appSecret': process.env.APP_SECRET, 19 | }; 20 | var bodyStr = JSON.stringify(body); 21 | 22 | const header = { 23 | 'Content-Type': 'application/json', 24 | }; 25 | 26 | var response = await exports.Query("https://api.symbl.ai/oauth2/token:generate", "POST", header, bodyStr); 27 | var text = await response.text(); 28 | // console.log(util.inspect(response, false, null, true)); 29 | // console.log("reason: " + text); 30 | 31 | return new Promise((resolve) => { 32 | if (response.status == 200 || response.status == 201) { 33 | resolve(JSON.parse(text).accessToken); 34 | } else { 35 | throw new Error(`${response.status}: ${text}`); 36 | } 37 | }); 38 | } 39 | 40 | /* 41 | Get the common configuration used for the Streaming API 42 | */ 43 | exports.GetConfigScaffolding = function() { 44 | // Need unique Id 45 | const id = uuid() 46 | // console.log("uuid: " + id) 47 | 48 | var scaffold = { 49 | id, 50 | config: { 51 | meetingTitle: 'My Test Meeting', 52 | confidenceThreshold: 0.7, 53 | timezoneOffset: 480, // Offset in minutes from UTC 54 | languageCode: 'en-US', 55 | sampleRateHertz, 56 | }, 57 | speaker: { 58 | // Optional, if not specified, will simply not send an email in the end. 59 | userId: process.env.SUMMARY_EMAIL, 60 | name: 'John Doe', 61 | }, 62 | handlers: { 63 | /** 64 | * This will return live speech-to-text transcription of the call. 65 | */ 66 | onSpeechDetected: (data) => { 67 | console.log(JSON.stringify(data)) 68 | // For live transcription 69 | if (data) { 70 | const {punctuated} = data 71 | console.log('Live: ', punctuated && punctuated.transcript) 72 | console.log(''); 73 | } 74 | console.log('onSpeechDetected ', JSON.stringify(data, null, 2)); 75 | }, 76 | /** 77 | * When processed messages are available, this callback will be called. 78 | */ 79 | onMessageResponse: (data) => { 80 | // When a processed message is available 81 | console.log('onMessageResponse', JSON.stringify(data, null, 2)) 82 | }, 83 | /** 84 | * When Symbl detects an insight, this callback will be called. 85 | */ 86 | onInsightResponse: (data) => { 87 | // When an insight is detected 88 | console.log('onInsightResponse', JSON.stringify(data, null, 2)) 89 | }, 90 | } 91 | } 92 | 93 | return scaffold 94 | } 95 | 96 | /* 97 | Simple Query helper function 98 | */ 99 | exports.Query = async function(uri, action, header, body) { 100 | var options = { 101 | method: action, 102 | body: body, 103 | headers: header, 104 | }; 105 | 106 | let response = await fetch(uri, options); 107 | 108 | // var text = await response.text(); 109 | // console.log(util.inspect(response, false, null, true)); 110 | // console.log("reason: " + text); 111 | 112 | return response; 113 | } 114 | 115 | /* 116 | Implements a sleep function 117 | */ 118 | exports.Sleep = function(ms) { 119 | return new Promise((resolve) => { 120 | setTimeout(resolve, ms); 121 | }); 122 | } 123 | 124 | /* 125 | Implements a wait for job completion function 126 | */ 127 | exports.Wait = async function(token, jobId) { 128 | //console.log("jobId: " + jobId); 129 | 130 | const header = { 131 | "Content-Type": "application/json", 132 | "Authorization": "Bearer " + token, 133 | "Connection": "keep-alive", 134 | }; 135 | 136 | var response; 137 | var text; 138 | var count = 0; 139 | while (true) { 140 | var uri = `https://api.symbl.ai/v1/job/${jobId}`; 141 | response = await this.Query(uri, "GET", header, null); 142 | text = await response.text(); 143 | // console.log("response: " + response); 144 | // console.log("reason: " + text); 145 | 146 | if (response.status == 200 || response.status == 201) { 147 | result = JSON.parse(text); 148 | if (result.status != "in_progress") { 149 | break; 150 | } 151 | } else { 152 | break; 153 | } 154 | 155 | ++count; 156 | if (count > 30) { 157 | break; 158 | } 159 | await this.Sleep(5000); 160 | } 161 | 162 | return new Promise((resolve) => { 163 | if (response.status == 200 || response.status == 201) { 164 | resolve(text); 165 | } else { 166 | throw new Error(`${response.status}: ${text}`); 167 | } 168 | }); 169 | } 170 | -------------------------------------------------------------------------------- /examples/node/common/management.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('./common.js'); 6 | const fetch = require('node-fetch'); 7 | 8 | exports.Create = async function(token) { 9 | const body = { 10 | 'name': process.env.TRACKER_NAME, 11 | 'vocabulary': [ 12 | process.env.TRACKER_VALUE, 13 | ], 14 | }; 15 | // console.log(body) 16 | var bodyStr = JSON.stringify(body) 17 | 18 | var response = await management(token, "POST", bodyStr); 19 | var trackers = JSON.parse(response); 20 | // console.log("trackers: " + trackers); 21 | 22 | return new Promise((resolve) => { 23 | resolve(trackers.tracker.id); 24 | }); 25 | } 26 | 27 | exports.Delete = async function(token) { 28 | var response = await management(token, "DELETE", process.env.TRACKER_ID); 29 | var tracker = JSON.parse(response); 30 | // console.log("trackers: " + tracker); 31 | 32 | return new Promise((resolve) => { 33 | if (tracker.deleted) { 34 | resolve(tracker.id); 35 | } else { 36 | throw new Error(`${tracker.id} was not deleted.`); 37 | } 38 | }); 39 | } 40 | 41 | exports.List = async function(token) { 42 | return management(token, "GET", null); 43 | } 44 | 45 | async function management(token, action, tracker) { 46 | // console.log("tracker: " + tracker); 47 | 48 | const header = { 49 | "Content-Type": "application/json", 50 | "Authorization": "Bearer " + token, 51 | "Connection": "keep-alive", 52 | }; 53 | 54 | var uri = `https://api.symbl.ai/v1/manage/tracker`; 55 | if (action == "DELETE") { 56 | uri += `/${tracker}`; 57 | 58 | // reset tracker 59 | tracker=null; 60 | } else if (action == "GET") { 61 | uri += `s`; 62 | } 63 | 64 | var response = await common.Query(uri, action, header, tracker); 65 | var text = await response.text(); 66 | // console.log("response: " + response); 67 | // console.log("reason: " + text); 68 | 69 | return new Promise((resolve) => { 70 | if (response.status == 200 || response.status == 201) { 71 | resolve(text); 72 | } else { 73 | throw new Error(`${response.status}: ${text}`); 74 | } 75 | }); 76 | } 77 | -------------------------------------------------------------------------------- /examples/node/common/post-file.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('./common.js'); 6 | const fetch = require('node-fetch'); 7 | var fs = require('fs'); 8 | 9 | exports.Post = async function(token, filename) { 10 | console.log(`audio: ${filename}\n`); 11 | 12 | var status = await upload(token, filename); 13 | var results = JSON.parse(status); 14 | // console.log("conversationId: " + results.conversationId); 15 | // console.log("jobId: " + results.jobId); 16 | 17 | var status = await common.Wait(token, results.jobId); 18 | // console.log("status: " + status) 19 | console.log(results); 20 | console.log("\n"); 21 | 22 | return results; 23 | } 24 | 25 | async function upload(token, filename) { 26 | // console.log("token: " + token); 27 | // console.log("filename: " + filename); 28 | 29 | const stats = fs.statSync(filename); 30 | const fileSizeInBytes = stats.size; 31 | // console.log("file size: " + fileSizeInBytes); 32 | 33 | const header = { 34 | "Content-Type": "audio/mpeg", 35 | "Authorization": "Bearer " + token, 36 | "Connection": "keep-alive", 37 | }; 38 | 39 | let readStream = fs.createReadStream(filename); 40 | 41 | var uri = `https://api.symbl.ai/v1/process/audio?name=${filename}&languageCode=en-US`; 42 | var response = await common.Query(uri, "POST", header, readStream); 43 | var text = await response.text(); 44 | // console.log("response: " + response); 45 | // console.log("reason: " + text); 46 | 47 | return new Promise((resolve) => { 48 | if (response.status == 200 || response.status == 201) { 49 | resolve(text); 50 | } else { 51 | throw new Error(`${response.status}: ${text}`); 52 | } 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /examples/node/common/post-url.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('./common.js'); 6 | const fetch = require('node-fetch'); 7 | var fs = require('fs'); 8 | 9 | exports.PostAudioURL = async function(token, url) { 10 | return this.PostVideoURL(token, url) 11 | } 12 | 13 | exports.PostVideoURL = async function(token, url) { 14 | console.log(`audio/video: ${url}\n`); 15 | 16 | var status = await sendURL(token, url); 17 | var results = JSON.parse(status); 18 | // console.log("conversationId: " + results.conversationId); 19 | // console.log("jobId: " + results.jobId); 20 | 21 | var status = await common.Wait(token, results.jobId); 22 | // console.log("status: " + status) 23 | console.log(results); 24 | console.log("\n"); 25 | 26 | return results; 27 | } 28 | 29 | async function sendURL(token, url) { 30 | // console.log(`video: ${url}`); 31 | // console.log(`token: ${token}`); 32 | 33 | const header = { 34 | "Content-Type": "application/json", 35 | "Authorization": "Bearer " + token, 36 | "Connection": "keep-alive", 37 | }; 38 | 39 | const data = { 40 | "name": "my-conversation", 41 | "url": url, 42 | } 43 | var dataStr = JSON.stringify(data); 44 | 45 | var uri = `https://api.symbl.ai/v1/process/audio/url` 46 | if (url.includes("mp4")) { 47 | uri = `https://api.symbl.ai/v1/process/video/url`; 48 | } 49 | 50 | var response = await common.Query(uri, "POST", header, dataStr); 51 | var text = await response.text(); 52 | // console.log("response: " + response); 53 | // console.log("reason: " + text); 54 | 55 | return new Promise((resolve) => { 56 | if (response.status == 200 || response.status == 201) { 57 | resolve(text); 58 | } else { 59 | throw new Error(`${response.status}: ${text}`); 60 | } 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /examples/node/common/streaming-output-device.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const {sdk} = require('@symblai/symbl-js') 6 | const AudioRecorder = require('node-audiorecorder') 7 | 8 | const sampleRateHertz = 16000; 9 | 10 | // For demo purposes, we're using mic to simply get audio from microphone and pass it on to websocket connection 11 | const options = { 12 | program: 'rec', 13 | device: 'hw:0,1', // Device Id - 'hw:0,1' indicates first output device 14 | bits: 16, 15 | rate: sampleRateHertz, 16 | channels: '1', 17 | encoding: 'signed-integer', 18 | silence: 6, 19 | keepSilence: true 20 | }; 21 | 22 | const recorder = new AudioRecorder(options, console); 23 | 24 | exports.startCapturing = async function(config) { 25 | try { 26 | // Initialize the SDK 27 | await sdk.init({ 28 | appId: process.env.APP_ID, 29 | appSecret: process.env.APP_SECRET, 30 | basePath: 'https://api.symbl.ai', 31 | }) 32 | .then(() => console.log('SDK Initialized.')) 33 | .catch(err => console.error('Error in initialization.', err)); 34 | 35 | // Start Real-time Request (Uses Realtime WebSocket API behind the scenes) 36 | const connection = await sdk.startRealtimeRequest(config); 37 | console.log('Successfully connected. Conversation ID: ', connection.conversationId); 38 | 39 | // get the mic 40 | const audioStream = recorder.start().stream(); 41 | 42 | /** 43 | * Raw audio stream 44 | */ 45 | audioStream.on('data', (data) => { 46 | // Push audio from Microphone to websocket connection 47 | // console.log("---------------------------") 48 | // console.log(util.inspect(data, false, null, true)); 49 | // console.log("---------------------------") 50 | connection.sendAudio(data) 51 | }) 52 | 53 | audioStream.on('error', function (err) { 54 | console.log('Error in Input Stream: ' + err) 55 | }) 56 | 57 | audioStream.on('startComplete', function () { 58 | console.log('Started listening to Microphone.') 59 | }) 60 | 61 | audioStream.on('silence', function () { 62 | console.log('Got SIGNAL silence') 63 | }) 64 | 65 | 66 | setTimeout(async () => { 67 | // Stop listening to microphone 68 | recorder.stop() 69 | console.log('Stopped listening to output device.') 70 | try { 71 | // Stop connection 72 | await connection.stop() 73 | console.log('Connection Stopped.') 74 | } catch (e) { 75 | console.error('Error while stopping the connection.', e) 76 | } 77 | }, 60 * 1000) // Stop connection after 1 minute i.e. 60 secs 78 | } catch (e) { 79 | console.error('Error: ', e) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/node/common/streaming.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const {sdk} = require('@symblai/symbl-js') 8 | const mic = require('mic') 9 | 10 | const sampleRateHertz = 16000 11 | 12 | // For demo purposes, we're using mic to simply get audio from microphone and pass it on to websocket connection 13 | const micInstance = mic({ 14 | rate: sampleRateHertz, 15 | channels: '1', 16 | debug: false, 17 | exitOnSilence: 6, 18 | }); 19 | 20 | exports.startCapturing = async function(config) { 21 | try { 22 | // Initialize the SDK 23 | await sdk.init({ 24 | appId: process.env.APP_ID, 25 | appSecret: process.env.APP_SECRET, 26 | basePath: 'https://api.symbl.ai', 27 | }) 28 | .then(() => console.log('SDK Initialized.')) 29 | .catch(err => console.error('Error in initialization.', err)); 30 | 31 | // Start Real-time Request (Uses Realtime WebSocket API behind the scenes) 32 | const connection = await sdk.startRealtimeRequest(config); 33 | console.log('Successfully connected. Conversation ID: ', connection.conversationId); 34 | 35 | // get the mic 36 | const micInputStream = micInstance.getAudioStream() 37 | 38 | /** 39 | * Raw audio stream 40 | */ 41 | micInputStream.on('data', (data) => { 42 | // Push audio from Microphone to websocket connection 43 | // console.log("---------------------------") 44 | // console.log(util.inspect(data, false, null, true)); 45 | // console.log("---------------------------") 46 | connection.sendAudio(data) 47 | }) 48 | 49 | micInputStream.on('error', function (err) { 50 | console.log('Error in Input Stream: ' + err) 51 | }) 52 | 53 | micInputStream.on('startComplete', function () { 54 | console.log('Started listening to Microphone.') 55 | }) 56 | 57 | micInputStream.on('silence', function () { 58 | console.log('Got SIGNAL silence') 59 | }) 60 | 61 | micInstance.start() 62 | 63 | setTimeout(async () => { 64 | // Stop listening to microphone 65 | micInstance.stop() 66 | console.log('Stopped listening to Microphone.') 67 | try { 68 | // Stop connection 69 | await connection.stop() 70 | console.log('Connection Stopped.') 71 | } catch (e) { 72 | console.error('Error while stopping the connection.', e) 73 | } 74 | }, 60 * 1000) // Stop connection after 1 minute i.e. 60 secs 75 | return connection; 76 | } catch (e) { 77 | console.error('Error: ', e) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples/node/common/summary-ui.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('./common.js'); 6 | const fetch = require('node-fetch'); 7 | 8 | exports.SummaryAudioUI = async function(token, url, conversationId) { 9 | return this.SummaryVideoUI(token, url, conversationId) 10 | } 11 | 12 | exports.SummaryVideoUI = async function(token, url, conversationId) { 13 | // console.log("conversationId: " + conversationId); 14 | 15 | const header = { 16 | "Content-Type": "application/json", 17 | "Authorization": "Bearer " + token, 18 | "Connection": "keep-alive", 19 | }; 20 | 21 | const data = { 22 | "name": "video-summary", 23 | "videoUrl": url, 24 | "summaryURLExpiresIn": 0 25 | }; 26 | var dataStr = JSON.stringify(data); 27 | 28 | var uri = `https://api.symbl.ai/v1/conversations/${conversationId}/experiences`; 29 | var response = await common.Query(uri, "POST", header, dataStr); 30 | var text = await response.text(); 31 | // console.log("response: " + response); 32 | // console.log("reason: " + text); 33 | 34 | return new Promise((resolve) => { 35 | if (response.status == 200 || response.status == 201) { 36 | resolve(text); 37 | } else { 38 | throw new Error(`${response.status}: ${text}`); 39 | } 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /examples/node/management/create/README.md: -------------------------------------------------------------------------------- 1 | # Using the Management API 2 | 3 | This is a simple main-style sample application using Symbl's Management API. This application will create a Tracker on the platform and return the Tracker ID. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Creating a Tracker 12 | 13 | Creating a Tracker is pretty straight-forward. We obtain some environment variables to help drive 14 | executing this node.js application, but here are the steps: 15 | 16 | 1. Login 17 | 3. Create the Tracker 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Create a Tracker 28 | */ 29 | var trackerId = await management.Create(token); 30 | console.log("trackerId: " + trackerId); 31 | } 32 | 33 | main(); 34 | ``` -------------------------------------------------------------------------------- /examples/node/management/create/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const management = require('../../common/management.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Create a Tracker 19 | */ 20 | var trackerId = await management.Create(token); 21 | console.log("Created Tracker. ID: " + trackerId); 22 | } 23 | 24 | main(); 25 | -------------------------------------------------------------------------------- /examples/node/management/delete/README.md: -------------------------------------------------------------------------------- 1 | # Using the Management API 2 | 3 | This is a simple main-style sample application using Symbl's Management API. This application will delete a Tracker on the platform. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Creating a Tracker 12 | 13 | Deleting a Tracker is pretty straight-forward. We obtain some environment variables to help drive 14 | executing this node.js application, but here are the steps: 15 | 16 | 1. Login 17 | 3. Delete the Tracker 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | Delete a Tracker 28 | */ 29 | var trackerId = await management.Delete(token); 30 | console.log("trackerId: " + trackerId); 31 | } 32 | 33 | main(); 34 | ``` -------------------------------------------------------------------------------- /examples/node/management/delete/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const management = require('../../common/management.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | Delete a Tracker 19 | */ 20 | var trackerId = await management.Delete(token); 21 | console.log("Deleted Tracker. ID: " + trackerId); 22 | } 23 | 24 | main(); 25 | -------------------------------------------------------------------------------- /examples/node/management/list/README.md: -------------------------------------------------------------------------------- 1 | # Using the Management API 2 | 3 | This is a simple main-style sample application using Symbl's Management API. This application will list all Trackers on the platform. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Creating a Tracker 12 | 13 | List all Trackers is pretty straight-forward. We obtain some environment variables to help drive 14 | executing this node.js application, but here are the steps: 15 | 16 | 1. Login 17 | 3. List the Trackers 18 | 19 | ``` 20 | async function main() { 21 | /* 22 | Login and get token 23 | */ 24 | var token = await common.Login(); 25 | 26 | /* 27 | List Trackers 28 | */ 29 | var trackers = await management.List(token); 30 | var output = JSON.parse(trackers); 31 | console.log(util.inspect(output, false, null, true)); 32 | } 33 | 34 | main(); 35 | ``` -------------------------------------------------------------------------------- /examples/node/management/list/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const util = require('util') 6 | 7 | const common = require('../../common/common.js'); 8 | const post = require('../../common/post-file.js'); 9 | const management = require('../../common/management.js'); 10 | 11 | async function main() { 12 | /* 13 | Login and get token 14 | */ 15 | var token = await common.Login(); 16 | 17 | /* 18 | List Trackers 19 | */ 20 | var trackers = await management.List(token); 21 | var output = JSON.parse(trackers); 22 | console.log(util.inspect(output, false, null, true)); 23 | } 24 | 25 | main(); 26 | -------------------------------------------------------------------------------- /examples/node/streaming/action-items/README.md: -------------------------------------------------------------------------------- 1 | # Using the Action Items Streaming API 2 | 3 | This is a simple main-style sample application using Symbl's Streaming API. This application will take the audio stream from the microphone in real-time and obtain the Action Items results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Action Items Configuration 12 | 13 | The Action Items API is among the simpliest of the Symbl APIs as the configuration/input parameters just require the minimal/common configuration provided in the `common.js`. 14 | 15 | ```javascript 16 | config = common.GetConfigScaffolding(); 17 | ``` 18 | 19 | Then we need to hook up the message handler so we can receive Action Items data/results: 20 | 21 | ```javascript 22 | config.handlers.onInsightResponse = (data) => { 23 | console.log('onActionItemsResponse', JSON.stringify(data, null, 2)); 24 | }; 25 | ``` 26 | 27 | ## Real-time Conversation Processing 28 | 29 | That configuration is then passed to the `startCapturing()` function found in `streaming.js` to start the real-time processing by the Symbl platform and hooking up the Mic to that websocket. 30 | -------------------------------------------------------------------------------- /examples/node/streaming/action-items/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('../../common/common.js'); 6 | var streaming = require('../../common/streaming.js'); 7 | 8 | /* 9 | Get basic configuration 10 | */ 11 | config = common.GetConfigScaffolding(); 12 | 13 | /* 14 | 1. Configure to receive action items 15 | 2. When Symbl detects a action items, the event will be triggered onInsightResponse. This can be overwritten. 16 | */ 17 | config.insightTypes = ['action_item']; 18 | 19 | config.handlers.onInsightResponse = (data) => { 20 | // When an insight is detected 21 | console.log('onActionItemResponse', JSON.stringify(data, null, 2)) 22 | }; 23 | 24 | /* 25 | Start real-time Topic gathering 26 | */ 27 | streaming.startCapturing(config); 28 | -------------------------------------------------------------------------------- /examples/node/streaming/enable-all/README.md: -------------------------------------------------------------------------------- 1 | # Complete Example Using Streaming API 2 | 3 | This is a simple main-style sample application that enables all the capabiilities of Symbl's Streaming API. This application will take the audio stream from the microphone in real-time and obtain all conversation insights when the results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Action Items and Questions Configuration 12 | 13 | The Action Items API is among the simpliest of the Symbl APIs as the configuration/input parameters just require the minimal/common configuration provided in the `common.js`. 14 | 15 | ```javascript 16 | config = common.GetConfigScaffolding(); 17 | ``` 18 | 19 | Then we need to hook up the message handler so we can receive Action Items data/results: 20 | 21 | ```javascript 22 | config.handlers.onInsightResponse = (data) => { 23 | console.log('onActionItemsResponse', JSON.stringify(data, null, 2)); 24 | }; 25 | ``` 26 | 27 | ## Topics Configuration 28 | 29 | The Topic API is among the simpliest of the Symbl APIs as the configuration/input parameters just require the minimal/common configuration provided in the `common.js`. 30 | 31 | ```javascript 32 | config = common.GetConfigScaffolding(); 33 | ``` 34 | 35 | Then we need to hook up the message handler so we can receive Topic data/results: 36 | 37 | ```javascript 38 | config.handlers.onTopicResponse = (data) => { 39 | console.log('onTopicResponse', JSON.stringify(data, null, 2)); 40 | }; 41 | ``` 42 | 43 | ## Tracker Configuration 44 | 45 | The Tracker API requires some additional parameters beyond the minimal/common configuration provided in the `common.js`. They include: 46 | 47 | - `trackers` - Array of tracker objects which has two fields 48 | - `name` - Tracker name. 49 | - `vocabulary` - Array of strings to be tracked and detected in the conversation. Each time a phrase in the trackers `vocabulary` array is detected a `tracker_response` will be output in the console. 50 | 51 | Which is seen here in code: 52 | 53 | ```javascript 54 | config.trackers = [ 55 | { 56 | name: 'Denial', 57 | vocabulary: [ 58 | 'No thank you', 59 | 'Not interested', 60 | 'No thanks', 61 | ] 62 | }, 63 | { 64 | name: 'Approval', 65 | vocabulary: [ 66 | 'Yes', 67 | 'Alright', 68 | 'Sounds good', 69 | ] 70 | } 71 | ]; 72 | ``` 73 | 74 | Then we need to hook up the message handler so we can receive Tracker data/results: 75 | 76 | ```javascript 77 | config.handlers.onTrackerResponse = (data) => { 78 | console.log('onTrackerResponse:'); 79 | data.trackers.forEach(tracker=>{ 80 | console.info(` Name: ${tracker.name}`); 81 | tracker.matches.forEach(match=>{ 82 | console.log(`Tracker Value: ${match.value}`); 83 | console.log(`Messages detected against this Tracker`); 84 | match.messageRefs.forEach((messageRef) => { 85 | console.log(`Message ID: ${messageRef.id}`); 86 | console.log(`Message text for which the match was detected: ${messageRef.text}`); 87 | console.log(`\n`); 88 | }); 89 | console.log(`\n`); 90 | 91 | console.log(`Insights detected against this Tracker`); 92 | match.messageRefs.forEach((insightRef) => { 93 | console.log(`Insight ID: ${insightRef.id}`); 94 | console.log(`Insight text for which the match was detected: ${insightRef.text}`); 95 | console.log(`Insight Type: ${insightRef.type}`); 96 | console.log(`\n`); 97 | }); 98 | console.log(`\n\n`); 99 | }) 100 | }); 101 | }; 102 | ``` 103 | 104 | ## Real-time Conversation Processing 105 | 106 | That configuration is then passed to the `startCapturing()` function found in `streaming.js` to start the real-time processing by the Symbl platform and hooking up the Mic to that websocket. 107 | -------------------------------------------------------------------------------- /examples/node/streaming/enable-all/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | const common = require('../../common/common.js'); 6 | const streaming = require('../../common/streaming.js'); 7 | const streamingOutputDevice = require('../../common/streaming-output-device'); 8 | const _ = require('lodash'); 9 | /* 10 | Get basic configuration 11 | */ 12 | config = common.GetConfigScaffolding(); 13 | 14 | /* 15 | 1. Configure to receive topics, action-items, questions, etc 16 | 2. Add input parameters for everything needed... trackers, etc 17 | 3. When Symbl detects an insight or etc, the various callbacks will be called. 18 | */ 19 | config.insightTypes = ['topic', 'action_item', 'question', 'follow_up']; 20 | 21 | config.trackers = [ 22 | { 23 | name: 'Denial', 24 | vocabulary: [ 25 | 'No thank you', 26 | 'Not interested', 27 | 'No thanks', 28 | ] 29 | }, 30 | { 31 | name: 'Approval', 32 | vocabulary: [ 33 | 'Yes', 34 | 'Alright', 35 | 'Sounds good', 36 | ] 37 | } 38 | ]; 39 | 40 | /* 41 | When Symbl detects speech (aka transcription), this callback will be called. 42 | */ 43 | config.handlers.onSpeechDetected = (data) => { 44 | if (data) { 45 | const { 46 | punctuated 47 | } = data 48 | console.log('Live: ', punctuated && punctuated.transcript) 49 | } 50 | } 51 | 52 | /* 53 | When Symbl detects action-items, questions, etc, this callback will be called. 54 | */ 55 | config.handlers.onInsightResponse = (data) => { 56 | // When an insight is detected 57 | console.log('onInsightResponse', JSON.stringify(data, null, 2)) 58 | }; 59 | 60 | /* 61 | When Symbl detects a topic, this callback will be called. 62 | */ 63 | config.handlers.onTopicResponse = (data) => { 64 | console.log('onTopicResponse', JSON.stringify(data, null, 2)); 65 | }; 66 | 67 | /* 68 | When Symbl detects a tracker, this callback will be called. 69 | */ 70 | config.handlers.onTrackerResponse = (data) => { 71 | console.log('onTrackerResponse:'); 72 | data.trackers.forEach(tracker=>{ 73 | console.info(` Name: ${tracker.name}`); 74 | tracker.matches.forEach(match=>{ 75 | console.log(`Tracker Value: ${match.value}`); 76 | console.log(`Messages detected against this Tracker`); 77 | match.messageRefs.forEach((messageRef) => { 78 | console.log(`Message ID: ${messageRef.id}`); 79 | console.log(`Message text for which the match was detected: ${messageRef.text}`); 80 | console.log(`\n`); 81 | }); 82 | console.log(`\n`); 83 | 84 | console.log(`Insights detected against this Tracker`); 85 | match.messageRefs.forEach((insightRef) => { 86 | console.log(`Insight ID: ${insightRef.id}`); 87 | console.log(`Insight text for which the match was detected: ${insightRef.text}`); 88 | console.log(`Insight Type: ${insightRef.type}`); 89 | console.log(`\n`); 90 | }); 91 | console.log(`\n\n`); 92 | }) 93 | }); 94 | }; 95 | 96 | /* 97 | Start real-time Topic gathering 98 | */ 99 | (async () => { 100 | // Capture audio from microphone 101 | const connection = await streaming.startCapturing(config); 102 | console.log('ConnectionId: ', connection.connectionId) 103 | // Capture audio from output device 104 | await streamingOutputDevice.startCapturing({... _.cloneDeep(config), id: connection.connectionId}); 105 | })(); 106 | 107 | -------------------------------------------------------------------------------- /examples/node/streaming/questions/README.md: -------------------------------------------------------------------------------- 1 | # Using the Questions Streaming API 2 | 3 | This is a simple main-style sample application using Symbl's Streaming API. This application will take the audio stream from the microphone in real-time and obtain the Questions results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Questions Configuration 12 | 13 | The Questions API is among the simpliest of the Symbl APIs as the configuration/input parameters just require the minimal/common configuration provided in the `common.js`. 14 | 15 | ```javascript 16 | config = common.GetConfigScaffolding(); 17 | ``` 18 | 19 | Then we need to hook up the message handler so we can receive Questions data/results: 20 | 21 | ```javascript 22 | config.handlers.onInsightResponse = (data) => { 23 | console.log('onQuestionsResponse', JSON.stringify(data, null, 2)); 24 | }; 25 | ``` 26 | 27 | ## Real-time Conversation Processing 28 | 29 | That configuration is then passed to the `startCapturing()` function found in `streaming.js` to start the real-time processing by the Symbl platform and hooking up the Mic to that websocket. 30 | -------------------------------------------------------------------------------- /examples/node/streaming/questions/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('../../common/common.js'); 6 | var streaming = require('../../common/streaming.js'); 7 | 8 | /* 9 | Get basic configuration 10 | */ 11 | config = common.GetConfigScaffolding(); 12 | 13 | /* 14 | 1. Configure to receive question 15 | 2. When Symbl detects a question, the event will be triggered onInsightResponse. This can be overwritten. 16 | */ 17 | config.insightTypes = ['question']; 18 | 19 | config.handlers.onInsightResponse = (data) => { 20 | // When an insight is detected 21 | console.log('onQuestionResponse', JSON.stringify(data, null, 2)) 22 | }; 23 | 24 | /* 25 | Start real-time Topic gathering 26 | */ 27 | streaming.startCapturing(config); 28 | -------------------------------------------------------------------------------- /examples/node/streaming/topics/README.md: -------------------------------------------------------------------------------- 1 | # Using the Topic Streaming API 2 | 3 | This is a simple main-style sample application using Symbl's Streaming API. This application will take the audio stream from the microphone in real-time and obtain the Topic results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Topics Configuration 12 | 13 | The Topic API is among the simpliest of the Symbl APIs as the configuration/input parameters just require the minimal/common configuration provided in the `common.js`. 14 | 15 | ```javascript 16 | config = common.GetConfigScaffolding(); 17 | ``` 18 | 19 | Then we need to hook up the message handler so we can receive Topic data/results: 20 | 21 | ```javascript 22 | config.handlers.onTopicResponse = (data) => { 23 | console.log('onTopicResponse', JSON.stringify(data, null, 2)); 24 | }; 25 | ``` 26 | 27 | ## Real-time Conversation Processing 28 | 29 | That configuration is then passed to the `startCapturing()` function found in `streaming.js` to start the real-time processing by the Symbl platform and hooking up the Mic to that websocket. 30 | -------------------------------------------------------------------------------- /examples/node/streaming/topics/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('../../common/common.js'); 6 | var streaming = require('../../common/streaming.js'); 7 | 8 | /* 9 | Get basic configuration 10 | */ 11 | config = common.GetConfigScaffolding(); 12 | 13 | /* 14 | 1. Configure to receive topics 15 | 2. When Symbl detects a topic, this callback will be called. 16 | */ 17 | config.insightTypes = ['topic']; 18 | 19 | config.handlers.onTopicResponse = (data) => { 20 | console.log('onTopicResponse', JSON.stringify(data, null, 2)); 21 | }; 22 | 23 | /* 24 | Start real-time Topic gathering 25 | */ 26 | streaming.startCapturing(config); 27 | -------------------------------------------------------------------------------- /examples/node/streaming/trackers/README.md: -------------------------------------------------------------------------------- 1 | # Tracker API Using Streaming API 2 | 3 | This is a simple main-style sample application using Symbl's Streaming API. This application will take the audio stream from the microphone in real-time and obtain the Tracker results when they become available. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get APP_ID and APP_SECRET from [https://platform.symbl.ai](https://platform.symbl.ai) 8 | 9 | Most of the heavy lifting is done in the `common` library which you can read about its plumbing [here](../../common/README.md). 10 | 11 | ## Tracker Configuration 12 | 13 | The Tracker API requires some additional parameters beyond the minimal/common configuration provided in the `common.js`. They include: 14 | 15 | - `trackers` - Array of tracker objects which has two fields 16 | - `name` - Tracker name. 17 | - `vocabulary` - Array of strings to be tracked and detected in the conversation. Each time a phrase in the trackers `vocabulary` array is detected a `tracker_response` will be output in the console. 18 | 19 | Which is seen here in code: 20 | 21 | ```javascript 22 | config.trackers = [ 23 | { 24 | name: 'Denial', 25 | vocabulary: [ 26 | 'No thank you', 27 | 'Not interested', 28 | 'No thanks', 29 | ] 30 | }, 31 | { 32 | name: 'Approval', 33 | vocabulary: [ 34 | 'Yes', 35 | 'Alright', 36 | 'Sounds good', 37 | ] 38 | } 39 | ]; 40 | ``` 41 | 42 | Then we need to hook up the message handler so we can receive Tracker data/results: 43 | 44 | ```javascript 45 | config.handlers.onTrackerResponse = (data) => { 46 | console.log('onTrackerResponse:'); 47 | data.trackers.forEach(tracker=>{ 48 | console.info(` Name: ${tracker.name}`); 49 | tracker.matches.forEach(match=>{ 50 | console.log(`Tracker Value: ${match.value}`); 51 | console.log(`Messages detected against this Tracker`); 52 | match.messageRefs.forEach((messageRef) => { 53 | console.log(`Message ID: ${messageRef.id}`); 54 | console.log(`Message text for which the match was detected: ${messageRef.text}`); 55 | console.log(`\n`); 56 | }); 57 | console.log(`\n`); 58 | 59 | console.log(`Insights detected against this Tracker`); 60 | match.messageRefs.forEach((insightRef) => { 61 | console.log(`Insight ID: ${insightRef.id}`); 62 | console.log(`Insight text for which the match was detected: ${insightRef.text}`); 63 | console.log(`Insight Type: ${insightRef.type}`); 64 | console.log(`\n`); 65 | }); 66 | console.log(`\n\n`); 67 | }) 68 | }); 69 | }; 70 | ``` 71 | 72 | ## Real-time Conversation Processing 73 | 74 | That configuration is then passed to the `startCapturing()` function found in `streaming.js` to start the real-time processing by the Symbl platform and hooking up the Mic to that websocket. 75 | -------------------------------------------------------------------------------- /examples/node/streaming/trackers/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | var common = require('../../common/common.js'); 6 | var streaming = require('../../common/streaming.js'); 7 | 8 | /* 9 | Get basic configuration 10 | */ 11 | config = common.GetConfigScaffolding(); 12 | 13 | /* 14 | 1. Configure to receive topics 15 | 2. Add input parameters for trackers 16 | 3. When Symbl detects a topic, this callback will be called. 17 | */ 18 | // config.insightTypes = ['topic']; 19 | 20 | config.trackers = [ 21 | { 22 | name: 'Denial', 23 | vocabulary: [ 24 | 'No thank you', 25 | 'Not interested', 26 | 'No thanks', 27 | ] 28 | }, 29 | { 30 | name: 'Approval', 31 | vocabulary: [ 32 | 'Yes', 33 | 'Alright', 34 | 'Sounds good', 35 | ] 36 | } 37 | ]; 38 | 39 | /* 40 | When Symbl detects a tracker, this callback will be called. 41 | */ 42 | config.handlers.onTrackerResponse = (data) => { 43 | console.log('onTrackerResponse:'); 44 | data.trackers.forEach(tracker=>{ 45 | console.info(` Name: ${tracker.name}`); 46 | tracker.matches.forEach(match=>{ 47 | console.log(`Tracker Value: ${match.value}`); 48 | console.log(`Messages detected against this Tracker`); 49 | match.messageRefs.forEach((messageRef) => { 50 | console.log(`Message ID: ${messageRef.id}`); 51 | console.log(`Message text for which the match was detected: ${messageRef.text}`); 52 | console.log(`\n`); 53 | }); 54 | console.log(`\n`); 55 | 56 | console.log(`Insights detected against this Tracker`); 57 | match.messageRefs.forEach((insightRef) => { 58 | console.log(`Insight ID: ${insightRef.id}`); 59 | console.log(`Insight text for which the match was detected: ${insightRef.text}`); 60 | console.log(`Insight Type: ${insightRef.type}`); 61 | console.log(`\n`); 62 | }); 63 | console.log(`\n\n`); 64 | }) 65 | }); 66 | }; 67 | 68 | /* 69 | Start real-time Topic gathering 70 | */ 71 | streaming.startCapturing(config); 72 | -------------------------------------------------------------------------------- /examples/node/telephony/custom-audio-config/README.md: -------------------------------------------------------------------------------- 1 | # How to pass different audio codecs 2 | 3 | Sometimes you need to pass different audio codecs when passing the audio. This 4 | example shows how to pass them. The ones currently supported are 5 | 6 | [OPUS](https://opus-codec.org/): 7 | - Supported Sample Rates -- 16000Hz, 24000Hz,48000Hz 8 | - Both CBR (Constant Bitrate) and VBR (Variable Bitrate) are supported 9 | - Support for in-band FEC 10 | 11 | [SPEEX](https://www.speex.org/): 12 | - Supported Sample Rates -- 16000Hz 13 | - VBR is not supported 14 | 15 | [LINEAR16](https://tools.ietf.org/html/rfc2586) 16 | - Supported Sample Rates -- 44100Hz 17 | 18 | [MULAW](https://en.wikipedia.org/wiki/G.711#%CE%BC-law) 19 | - Supported Sample Rates -- 8000Hz 20 | 21 | > NOTE: We recommend using OPUS as compared to other codecs because it provides 22 | > the most flexibility in terms of audio transportation and also has packet 23 | > retransmission mechanisms like FEC which work well especially in low-bandwidth 24 | > scenarios. 25 | 26 | ## Getting started 27 | 28 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get 29 | APP_ID and APP_SECRET from 30 | [https://platform.symbl.ai](https://platform.symbl.ai) 31 | 32 | We will use `symbl-node` package. 33 | 34 | ```javascript 35 | require('dotenv').config() 36 | 37 | const {sdk} = require('symbl-node') 38 | ``` 39 | 40 | Let's start by initialising `symbl-node` sdk 41 | 42 | ```javascript 43 | await sdk.init({ 44 | appId: process.env.APP_ID, 45 | appSecret: process.env.APP_SECRET, 46 | basePath: 'https://api.symbl.ai', 47 | }) 48 | ``` 49 | 50 | Now after we initialised, we need to start the connection by running 51 | 52 | ```javascript 53 | const connection = await sdk.startEndpoint(endpointConfig) 54 | ``` 55 | 56 | So how do you pass custom codecs? It's as simple as passing custom audio config 57 | 58 | ```javascript 59 | endpoint: { 60 | //*****************Custom Audio Config****************** 61 | audioConfig: { 62 | encoding: 'OPUS', 63 | sampleRate: 16000, 64 | }, 65 | //****************************************************** 66 | type: 'pstn', 67 | phoneNumber: process.env.DEFAULT_PHONE_NUMBER, 68 | }, 69 | ``` 70 | 71 | If you have a requirement to use a codec not included in the ones above or have 72 | any other queries, please drop an e-mail to support@symbl.ai 73 | -------------------------------------------------------------------------------- /examples/node/telephony/custom-audio-config/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | /* 5 | * This example shows how to pass in different Audio Codecs. The ones currently supported are 6 | * OPUS: 7 | * * Supported Sample Rates -- 16000Hz, 24000Hz, 48000Hz 8 | * * Both CBR (Constant Bitrate) and VBR (Variable Bitrate) are supported 9 | * * Support for in-band FEC 10 | * 11 | * SPEEX: 12 | * * Supported Sample Rates -- 16000Hz 13 | * * VBR is not supported 14 | * 15 | * LINEAR16: 16 | * * Supported Sample Rates -- 44100Hz 17 | * 18 | * MULAW: 19 | * * Supported Sample Rates -- 8000Hz 20 | * 21 | * NOTE: We recommend using OPUS as compared to other codecs because it provides the most flexibility in terms of 22 | * audio transportation and also has packet retransmission mechanisms like FEC which work well especially 23 | * in low-bandwidth scenarios. 24 | * 25 | * If you have a requirement to use a codec not included in the ones above or have any other queries, 26 | * please drop an e-mail to support@symbl.ai 27 | */ 28 | require('dotenv').config() 29 | const {sdk, SpeakerEvent} = require('symbl-node') 30 | 31 | const getScheduleEvent = (sdk, connectionId) => { 32 | return (eventType, user, time) => { 33 | setTimeout(() => { 34 | const speakerEvent = new SpeakerEvent({ 35 | type: eventType, 36 | user, 37 | }) 38 | speakerEvent.timestamp = new Date().toISOString() 39 | 40 | console.log( 41 | `Pushing event [${speakerEvent.timestamp}] ${speakerEvent.type} : ${speakerEvent.user.name}`, 42 | ) 43 | 44 | sdk.pushEventOnConnection(connectionId, speakerEvent.toJSON(), (err) => { 45 | if (err) { 46 | console.error('Error during push event.', err) 47 | } else { 48 | console.log('Event pushed!') 49 | } 50 | }) 51 | }, time * 1000) 52 | } 53 | } 54 | 55 | const users = { 56 | john: { 57 | userId: 'John@example.com', 58 | name: 'John', 59 | }, 60 | mary: { 61 | userId: 'mary@example.com', 62 | name: 'Mary', 63 | }, 64 | tim: { 65 | userId: 'tim@example.com', 66 | name: 'Tim', 67 | }, 68 | jennifer: { 69 | userId: 'jennifer@example.com', 70 | name: 'Jennifer', 71 | }, 72 | } 73 | ;(async () => { 74 | try { 75 | // Initialize the SDK 76 | await sdk.init({ 77 | appId: process.env.APP_ID, 78 | appSecret: process.env.APP_SECRET, 79 | basePath: 'https://api.symbl.ai', 80 | }) 81 | 82 | const connection = await sdk.startEndpoint({ 83 | endpoint: { 84 | //*****************Custom Audio Config****************** 85 | audioConfig: { 86 | encoding: 'OPUS', 87 | sampleRate: 16000, 88 | }, 89 | //****************************************************** 90 | type: 'pstn', 91 | phoneNumber: process.env.DEFAULT_PHONE_NUMBER, 92 | }, 93 | actions: [ 94 | { 95 | invokeOn: 'stop', 96 | name: 'sendSummaryEmail', 97 | parameters: { 98 | emails: ['vladimir.novick@symbl.ai'], 99 | }, 100 | }, 101 | ], 102 | data: { 103 | session: { 104 | name: 'Ship-wide nanomachines, to the center.', 105 | }, 106 | }, 107 | }) 108 | const connectionId = connection.connectionId 109 | console.log('Successfully connected.', connectionId) 110 | 111 | const scheduleEvent = getScheduleEvent(sdk, connectionId) 112 | 113 | setTimeout(() => { 114 | // This is just for interactive purposeas to show the elapsed time. 115 | 116 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 0) 117 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 4) 118 | 119 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.mary, 4) 120 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.mary, 9) 121 | 122 | // Scheduling stop endpoint call after 60 seconds 123 | setTimeout(() => { 124 | console.log('stopping connection ' + connection.connectionId) 125 | sdk 126 | .stopEndpoint({ 127 | connectionId, 128 | }) 129 | .then(() => { 130 | console.log('Stopped the connection') 131 | }) 132 | .catch((err) => 133 | console.error('Error while stopping the connection.', err), 134 | ) 135 | }, 10000) 136 | }, 1000) 137 | } catch (err) { 138 | console.error('Error in SDK initialization.', err) 139 | } 140 | })() 141 | -------------------------------------------------------------------------------- /examples/node/telephony/custom-language-and-timezone/README.md: -------------------------------------------------------------------------------- 1 | # Telephony - passing other than English languages and timezone 2 | 3 | This example shows how to use languages other than English and also how to pass 4 | in `timezone` in which the conversation is taking place. For languages: 5 | Currently the following languages are supported 6 | 7 | ['en-US', 'en-AU', 'en-GB', 'fr-CA', 'fr-FR', 'de-DE', 'it-IT', 'nl-NL', 8 | 'es-US', 'ja-JP'] 9 | 10 | The above are all BCP-47 standard language codes and currently ONLY 1 should be 11 | passed in the `languages` array as shown below. Support for detecting multiple 12 | languages in the same conversation will be added soon! 13 | 14 | For timezone: Please refer to 15 | https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of 16 | timeZones. 17 | 18 | You can also use `moment-timezone` package to obtain a list of timeZones like 19 | the following const timeZones = moment.tz.names() 20 | 21 | NOTE: If `languages` is NOT passed in the `startEndpoint` call the API will 22 | fallback to 'en-US'. If `timezone` is NOT passed the API will fall back to 23 | 'UTC'. 24 | 25 | ## Getting started 26 | 27 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get 28 | APP_ID and APP_SECRET from 29 | [https://platform.symbl.ai](https://platform.symbl.ai) 30 | 31 | We will use `symbl-node` package. 32 | 33 | ```javascript 34 | require('dotenv').config() 35 | 36 | const {sdk} = require('symbl-node') 37 | ``` 38 | 39 | Let's start by initialising `symbl-node` sdk 40 | 41 | ```js 42 | await sdk.init({ 43 | appId: process.env.APP_ID, 44 | appSecret: process.env.APP_SECRET, 45 | basePath: 'https://api.symbl.ai', 46 | }) 47 | ``` 48 | 49 | Now start your endpoint and provide `language` and `timezone` properties: 50 | 51 | ```js 52 | const connection = await sdk.startEndpoint({ 53 | ...config, 54 | languages: ['ja-JP'], 55 | timezone: 'Asia/Tokyo', 56 | }) 57 | ``` 58 | -------------------------------------------------------------------------------- /examples/node/telephony/custom-language-and-timezone/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | /* 5 | * This example shows how to use languages other than English and also how to pass in `timezone` in which the conversation is taking place. 6 | * For languages: Currently the following languages are supported 7 | * 8 | * ['en-US', 'en-AU', 'en-GB', 'fr-CA', 'fr-FR', 'de-DE', 'it-IT', 'nl-NL', 'es-US', 'ja-JP'] 9 | * 10 | * The above are all BCP-47 standard language codes and currently ONLY 1 should be passed in the `languages` array as shown below. 11 | * Support for detecting multiple languages in the same conversation will be added soon! 12 | * 13 | * For timezone: Please refer to https://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a list of timeZones. 14 | * 15 | * You can also use `moment-timezone` package to obtain a list of timeZones like the following 16 | * const timeZones = moment.tz.names() 17 | * 18 | * NOTE: If `languages` is NOT passed in the `startEndpoint` call the API will fallback to 'en-US'. 19 | * If `timezone` is NOT passed the API will fall back to 'UTC'. 20 | */ 21 | require('dotenv').config() 22 | const {sdk, SpeakerEvent} = require('symbl-node') 23 | 24 | const getScheduleEvent = (sdk, connectionId) => { 25 | return (eventType, user, time) => { 26 | setTimeout(() => { 27 | const speakerEvent = new SpeakerEvent({ 28 | type: eventType, 29 | user, 30 | }) 31 | speakerEvent.timestamp = new Date().toISOString() 32 | 33 | console.log( 34 | `Pushing event [${speakerEvent.timestamp}] ${speakerEvent.type} : ${speakerEvent.user.name}`, 35 | ) 36 | 37 | sdk.pushEventOnConnection(connectionId, speakerEvent.toJSON(), (err) => { 38 | if (err) { 39 | console.error('Error during push event.', err) 40 | } else { 41 | console.log('Event pushed!') 42 | } 43 | }) 44 | }, time * 1000) 45 | } 46 | } 47 | 48 | const users = { 49 | john: { 50 | userId: 'john@example.com', 51 | name: 'John', 52 | }, 53 | mary: { 54 | userId: 'mary@example.com', 55 | name: 'Mary', 56 | }, 57 | tim: { 58 | userId: 'tim@example.com', 59 | name: 'Tim', 60 | }, 61 | jennifer: { 62 | userId: 'jennifer@example.com', 63 | name: 'Jennifer', 64 | }, 65 | } 66 | 67 | ;(async () => { 68 | try { 69 | // Initialize the SDK 70 | await sdk.init({ 71 | appId: process.env.APP_ID, 72 | appSecret: process.env.APP_SECRET, 73 | basePath: 'https://api.symbl.ai', 74 | }) 75 | 76 | const connection = await sdk.startEndpoint({ 77 | endpoint: { 78 | //*****************Custom Audio Config****************** 79 | audioConfig: { 80 | encoding: 'OPUS', 81 | sampleRate: 16000, 82 | }, 83 | //****************************************************** 84 | type: 'pstn', 85 | phoneNumber: process.env.DEFAULT_PHONE_NUMBER, 86 | }, 87 | languages: ['ja-JP'], // Can be any 1 of ['en-US', 'en-AU', 'en-GB', 'fr-CA', 'fr-FR', 'de-DE', 'it-IT', 'nl-NL', 'es-US', 'ja-JP'] 88 | timezone: 'Asia/Tokyo', // List of timeZones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones timezone: 'Asia/Tokyo', // List of timeZones: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones 89 | actions: [ 90 | { 91 | invokeOn: 'stop', 92 | name: 'sendSummaryEmail', 93 | parameters: { 94 | emails: [process.env.SUMMARY_EMAIL], 95 | }, 96 | }, 97 | ], 98 | data: { 99 | session: { 100 | name: 'Ship-wide nanomachines, to the center.', 101 | }, 102 | }, 103 | }) 104 | const connectionId = connection.connectionId 105 | console.log('Successfully connected.', connectionId) 106 | 107 | const scheduleEvent = getScheduleEvent(sdk, connectionId) 108 | 109 | setTimeout(() => { 110 | // This is just for interactive purposeas to show the elapsed time. 111 | 112 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 0) 113 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 4) 114 | 115 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.mary, 4) 116 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.mary, 9) 117 | 118 | // Scheduling stop endpoint call after 60 seconds 119 | setTimeout(() => { 120 | console.log('stopping connection ' + connection.connectionId) 121 | sdk 122 | .stopEndpoint({ 123 | connectionId, 124 | }) 125 | .then(() => { 126 | console.log('Stopped the connection') 127 | }) 128 | .catch((err) => 129 | console.error('Error while stopping the connection.', err), 130 | ) 131 | }, 10000) 132 | }, 1000) 133 | } catch (err) { 134 | console.error('Error in SDK initialization.', err) 135 | } 136 | })() 137 | -------------------------------------------------------------------------------- /examples/node/telephony/realtime-insights-transcription/README.md: -------------------------------------------------------------------------------- 1 | # Realtime Output with PSTN Dialin using Voice SDK 2 | 3 | In this example let's walk through how to get the live transcription and 4 | insights events in a Telephone call. 5 | 6 | ## Getting started 7 | 8 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get 9 | APP_ID and APP_SECRET from 10 | [https://platform.symbl.ai](https://platform.symbl.ai) 11 | 12 | We will use `symbl-node` package. 13 | 14 | ```javascript 15 | require('dotenv').config() 16 | 17 | const {sdk} = require('symbl-node') 18 | ``` 19 | 20 | Let's start by initialising `symbl-node` sdk 21 | 22 | ```js 23 | await sdk.init({ 24 | appId: process.env.APP_ID, 25 | appSecret: process.env.APP_SECRET, 26 | basePath: 'https://api.symbl.ai', 27 | }) 28 | ``` 29 | 30 | Now let's start our connection: 31 | 32 | `const connection = await sdk.startEndpoint(endpointConfig)` 33 | 34 | First of all let's provide phone number and endpoint type: 35 | 36 | ```javascript 37 | endpoint: { 38 | type: 'pstn', 39 | phoneNumber: process.env.DEFAULT_PHONE_NUMBER, 40 | }, 41 | ``` 42 | 43 | In case you want to use `sip` connection, you can use `type: sip` and provide 44 | SIP URI to dial-in to. This should be unique for an active call/meeting in your 45 | system. You can also provide `dtmf` code if you have one. You can find this code 46 | on meeting platform invite. You can leave it blank if not connecting to meeting 47 | platform 48 | 49 | ```javascript 50 | dtmf: "", 51 | type: 'sip', 52 | uri: 'sip:124@domain.com' 53 | ``` 54 | 55 | You can also pass custom `audioConfig`. If not provided, it uses PCMU with 800 56 | sample rate. If you want to provide it, you can do it like so: 57 | 58 | ```js 59 | audioConfig: { 60 | encoding: 'OPUS', 61 | sampleRate: 48000 62 | }, 63 | ``` 64 | 65 | ### Insights 66 | 67 | Symbl provide various insights from the call. Main insights categories are 68 | `question` and `action_item`. In order to include insights in processing, you 69 | need to specify them in configuration like so: 70 | 71 | ```js 72 | insightTypes: ['action_item', 'question'], 73 | ``` 74 | 75 | ### Actions 76 | 77 | You can specify different actions to happen during the call. We will define just 78 | one: 79 | 80 | ```javascript 81 | actions: [ 82 | { 83 | invokeOn: 'stop', 84 | name: 'sendSummaryEmail', 85 | parameters: { 86 | emails: [process.env.SUMMARY_EMAIL], // Add valid email addresses to received email 87 | }, 88 | }, 89 | ], 90 | ``` 91 | 92 | When our connection will be stopped, Symbl will send summary mail provided in 93 | `.env` file 94 | 95 | Let's also name our session by providing: 96 | 97 | ```js 98 | data: { 99 | session: { 100 | name: 'My Test Meeting', 101 | }, 102 | }, 103 | ``` 104 | 105 | ### Getting connection Id. 106 | 107 | For subscribing to the data, we will need to use `connectionId` unique to each 108 | active connection. to get it you can simply retrieve it from connection 109 | response: 110 | 111 | ```js 112 | const connectionId = connection.connectionId 113 | ``` 114 | 115 | ## Sending speaker events. 116 | 117 | We can send different speaker events to our connection indicating that different 118 | speakers started speaking. That will give us more personalised insights and get 119 | better meeting summary 120 | 121 | In our example we will do it by calling helper `getScheduleEvent` function, that 122 | we will review in a bit. We pass SpeakerEvent type to it by using 123 | `SpeakerEvent.types` enum from `symbl-node`, passing user data and timestamp 124 | 125 | ```javascript 126 | const scheduleEvent = getScheduleEvent(sdk, connectionId) 127 | 128 | setTimeout(() => { 129 | // Schedule all the events to be sent. 130 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 0) 131 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 5) 132 | }, 1000) 133 | ``` 134 | 135 | We retrieve users just from the global array of users but in real world example 136 | that might be users data retrieved from database. 137 | 138 | ```js 139 | const users = { 140 | john: { 141 | userId: 'john@example.com', 142 | name: 'John', 143 | }, 144 | mary: { 145 | userId: 'mary@example.com', 146 | name: 'Mary', 147 | }, 148 | } 149 | ``` 150 | 151 | In order to push event to our connection we will create an event like so 152 | 153 | ```js 154 | const speakerEvent = new SpeakerEvent({ 155 | type: eventType, 156 | user, 157 | }) 158 | 159 | speakerEvent.timestamp = new Date().toISOString() 160 | ``` 161 | 162 | And push it using `pushEventOnConnection` function provided by SDK 163 | 164 | ```js 165 | sdk.pushEventOnConnection(connectionId, speakerEvent.toJSON(), (err) => { 166 | if (err) { 167 | console.error('Error during push event.', err) 168 | } else { 169 | console.log('Event pushed!') 170 | } 171 | }) 172 | ``` 173 | 174 | ## Realtime insights 175 | 176 | In order to get real time data, we need to subscribe to the connection. We can 177 | do so by using 178 | 179 | ```js 180 | sdk.subscribeToConnection(connectionId, (data) => {}) 181 | ``` 182 | 183 | data has `type` field, so we will check for `transcript_response`, 184 | `insight_response` and `message_response` 185 | 186 | `transcript_response` are our live transcriptions that we want to preview in the 187 | console. 188 | 189 | ```js 190 | if (type === 'transcript_response') { 191 | const {payload} = data 192 | process.stdout.write('Live: ' + payload && payload.content + '\r') 193 | } 194 | ``` 195 | 196 | Transcripts are changing all the time, but once they are processed into 197 | reasonable message and not just words, we will get `message_response` with 198 | messages array 199 | 200 | ```js 201 | if (type === 'message_response') { 202 | const {messages} = data 203 | messages.forEach((message) => { 204 | process.stdout.write('Message: ' + message.payload.content + '\n') 205 | }) 206 | } 207 | ``` 208 | 209 | And finally if there will be any question or action item during conversation, 210 | you will get `insight_response` 211 | 212 | ```js 213 | if (type === 'insight_response') { 214 | const {insights} = data 215 | insights.forEach((insight) => { 216 | process.stdout.write(`Insight: ${insight.type} - ${insight.text} \n\n`) 217 | }) 218 | } 219 | ``` 220 | 221 | As you can see with this data there is a wide array of implementations you can 222 | do 223 | -------------------------------------------------------------------------------- /examples/node/telephony/realtime-insights-transcription/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | 6 | const {sdk, SpeakerEvent} = require('symbl-node') 7 | 8 | const getScheduleEvent = (sdk, connectionId) => { 9 | return (eventType, user, time) => { 10 | setTimeout(() => { 11 | const speakerEvent = new SpeakerEvent({ 12 | type: eventType, 13 | user, 14 | }) 15 | speakerEvent.timestamp = new Date().toISOString() 16 | 17 | console.log( 18 | `Pushing event [${speakerEvent.timestamp}] ${speakerEvent.type} : ${speakerEvent.user.name}`, 19 | ) 20 | 21 | sdk.pushEventOnConnection(connectionId, speakerEvent.toJSON(), (err) => { 22 | if (err) { 23 | console.error('Error during push event.', err) 24 | } else { 25 | console.log('Event pushed!') 26 | } 27 | }) 28 | }, time * 1000) 29 | } 30 | } 31 | 32 | const users = { 33 | john: { 34 | userId: 'john@example.com', 35 | name: 'John', 36 | }, 37 | mary: { 38 | userId: 'mary@example.com', 39 | name: 'Mary', 40 | }, 41 | } 42 | 43 | ;(async () => { 44 | try { 45 | // Initialize the SDK 46 | await sdk.init({ 47 | appId: process.env.APP_ID, 48 | appSecret: process.env.APP_SECRET, 49 | basePath: 'https://api.symbl.ai', 50 | }) 51 | 52 | console.log('SDK Initialized') 53 | 54 | const connection = await sdk.startEndpoint({ 55 | endpoint: { 56 | type: 'pstn', 57 | phoneNumber: process.env.DEFAULT_PHONE_NUMBER, 58 | }, 59 | insightTypes: ['action_item', 'question'], 60 | actions: [ 61 | { 62 | invokeOn: 'stop', 63 | name: 'sendSummaryEmail', 64 | parameters: { 65 | emails: [process.env.SUMMARY_EMAIL], // Add valid email addresses to received email 66 | }, 67 | }, 68 | ], 69 | data: { 70 | session: { 71 | name: 'My Test Meeting', 72 | }, 73 | }, 74 | }) 75 | 76 | const connectionId = connection.connectionId 77 | console.log('Successfully connected. Connection ID: ', connectionId) 78 | const scheduleEvent = getScheduleEvent(sdk, connectionId) 79 | 80 | setTimeout(() => { 81 | // Schedule all the events to be sent. 82 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 0) 83 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 5) 84 | 85 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.mary, 5) 86 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.mary, 15) 87 | 88 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 15) 89 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 45) 90 | 91 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.mary, 45) 92 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.mary, 60) 93 | }, 1000) 94 | 95 | console.log('Subscribing to the live events on the connection.') 96 | // Subscribe to connection using connectionId. 97 | // Multiple subscriptions to same connectionId are allowed. It can be useful to get the updates at multiple clients. 98 | sdk.subscribeToConnection(connectionId, (data) => { 99 | // console.log(data); 100 | const {type} = data 101 | if (type === 'transcript_response') { 102 | const {payload} = data 103 | process.stdout.write('Live: ' + payload && payload.content + '\r') 104 | // console.log('Live: ',payload && payload.content); 105 | } else if (type === 'message_response') { 106 | const {messages} = data 107 | messages.forEach((message) => { 108 | process.stdout.write('Message: ' + message.payload.content + '\n') 109 | }) 110 | } else if (type === 'insight_response') { 111 | const {insights} = data 112 | insights.forEach((insight) => { 113 | process.stdout.write( 114 | `Insight: ${insight.type} - ${insight.text} \n\n`, 115 | ) 116 | }) 117 | } 118 | }) 119 | 120 | // Scheduling stop endpoint call after 60 seconds 121 | setTimeout(async () => { 122 | console.log('Stopping the connection') 123 | try { 124 | await sdk.stopEndpoint({ 125 | connectionId: connection.connectionId, 126 | }) 127 | console.log('Connection stopped.') 128 | console.log('Summary Info:', connection.summaryInfo) 129 | console.log('Conversation ID:', connection.conversationId) 130 | } catch (err) {} 131 | }, 62 * 1000) 132 | } catch (e) {} 133 | })() 134 | -------------------------------------------------------------------------------- /examples/node/telephony/realtime-intent-detection/README.md: -------------------------------------------------------------------------------- 1 | # Realtime Intent Detection with PSTN DialIn using Voice SDK 2 | 3 | In this example let's walk through how to get live intent detection in a Telephone call. 4 | 5 | ## Getting started 6 | 7 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get 8 | APP_ID and APP_SECRET from 9 | [https://platform.symbl.ai](https://platform.symbl.ai) 10 | 11 | We will use `symbl-node` package. 12 | 13 | ```javascript 14 | require('dotenv').config() 15 | 16 | const {sdk} = require('symbl-node') 17 | ``` 18 | 19 | Let's start by initialising `symbl-node` sdk 20 | 21 | ```js 22 | await sdk.init({ 23 | appId: process.env.APP_ID, 24 | appSecret: process.env.APP_SECRET, 25 | basePath: 'https://api.symbl.ai', 26 | }) 27 | ``` 28 | 29 | Now let's start our connection: 30 | 31 | `const connection = await sdk.startEndpoint(endpointConfig)` 32 | 33 | First of all let's provide phone number and endpoint type: 34 | 35 | ```javascript 36 | endpoint: { 37 | type: 'pstn', 38 | phoneNumber: process.env.DEFAULT_PHONE_NUMBER, 39 | }, 40 | ``` 41 | 42 | In case you want to use `sip` connection, you can use `type: sip` and provide 43 | SIP URI to dial-in to. This should be unique for an active call/meeting in your 44 | system. You can also provide `dtmf` code if you have one. You can find this code 45 | on meeting platform invite. You can leave it blank if not connecting to meeting 46 | platform 47 | 48 | ```javascript 49 | dtmf: "", 50 | type: 'sip', 51 | uri: 'sip:124@domain.com' 52 | ``` 53 | 54 | You can also pass custom `audioConfig`. If not provided, it uses PCMU with 800 55 | sample rate. If you want to provide it, you can do it like so: 56 | 57 | ```js 58 | audioConfig: { 59 | encoding: 'OPUS', 60 | sampleRate: 48000 61 | }, 62 | ``` 63 | ### Intents 64 | Symbl provides various intents which can be detected in realtime. 65 | * An `intent` can also have a `subIntent` which indicates additional metadata about the intent. 66 | For e.g. the `answering_machine` intent will have subIntents which can either be `answered_by_human` or `answered_by_machine` 67 | 68 | * The `text` field in the `intent` returns the textual content at which the intent was finalised. 69 | 70 | * The `score` field in the `intent` returns a confidence score for the detected intent. 71 | 72 | * The `alternatives` is an array in the `intent` object which contains other possible intents detected if any, with their confidence `score` 73 | 74 | Refer to the below [section](#Getting the detected Intents in RealTime) for extracting the above structure from the response. 75 | 76 | In order to detect intents for a conversation, you can specify the below configuration: 77 | 78 | ```js 79 | intents: [ 80 | { 81 | intent: 'answering_machine' 82 | }, 83 | { 84 | intent: 'interested' 85 | }, 86 | { 87 | intent: 'not_interested' 88 | }, 89 | { 90 | intent: 'do_not_call' 91 | } 92 | ] 93 | ``` 94 | 95 | ### Actions 96 | 97 | You can specify different actions to happen during the call. We will define just 98 | one: 99 | 100 | ```javascript 101 | actions: [ 102 | { 103 | invokeOn: 'stop', 104 | name: 'sendSummaryEmail', 105 | parameters: { 106 | emails: [process.env.SUMMARY_EMAIL], // Add valid email addresses to received email 107 | }, 108 | }, 109 | ], 110 | ``` 111 | 112 | When our connection will be stopped, Symbl will send summary mail provided in 113 | `.env` file 114 | 115 | Let's also name our session by providing: 116 | 117 | ```js 118 | data: { 119 | session: { 120 | name: 'My Awesome Meet', 121 | }, 122 | }, 123 | ``` 124 | 125 | ### Getting connection Id. 126 | 127 | For subscribing to the data, we will need to use `connectionId` unique to each 128 | active connection. to get it you can simply retrieve it from connection 129 | response: 130 | 131 | ```js 132 | const connectionId = connection.connectionId 133 | ``` 134 | 135 | ### Getting the detected Intents in RealTime 136 | 137 | In order to get real time intents, we need to subscribe to the connection. We can 138 | do so by using 139 | 140 | ```js 141 | sdk.subscribeToConnection(connectionId, (data) => {}) 142 | ``` 143 | 144 | `data` has `type` field, so we will check for `intent_response`. 145 | In the nested object we will find the detected `intent` and it's metadata. 146 | 147 | ```js 148 | if (data.type === 'intent_response') { 149 | const { intent: intentData } = data; 150 | 151 | switch (intentData.intent) { 152 | case "answering_machine": 153 | let { subIntent } = intentData; 154 | console.log(`SubIntent identified: ${subIntent} for 'answering_machine'`); // subIntents supported under 'answering_machine' are [answered_by_human, answered_by_machine] 155 | case "interested": 156 | case "not_interested": 157 | case "do_not_call": 158 | let { score, text, alternatives } = intentData; 159 | console.log(`Score: ${score}`); // Score of the detected intent 160 | console.log(`Text: ${text}`); // Text at which the intent was detected 161 | console.log(`Alternatives: ${alternatives}`); // These represent other complementing intents if any were detected 162 | break; 163 | } 164 | } 165 | ``` 166 | 167 | As you can see with this data there is a wide array of implementations you can 168 | do. 169 | -------------------------------------------------------------------------------- /examples/node/telephony/realtime-intent-detection/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config(); 5 | 6 | const {sdk} = require('symbl-node'); 7 | 8 | const phoneNumber = process.env.DEFAULT_PHONE_NUMBER; // replace this with the phone number, or configure DEFAULT_PHONE_NUMBER in .env file. 9 | 10 | sdk.init({ 11 | appId: process.env.APP_ID, 12 | appSecret: process.env.APP_SECRET, 13 | basePath: process.env.BASE_PATH 14 | }).then(() => { 15 | sdk.startEndpoint({ 16 | endpoint: { 17 | type: "pstn", 18 | phoneNumber: phoneNumber, 19 | // dtmf: "" // you can find this on the meeting platform invite. Leave blank if not connecting to a meeting platform 20 | // audioConfig: { 21 | // encoding: 'OPUS', 22 | // sampleRate: 48000 23 | // }, 24 | // type: 'sip', 25 | // uri: 'sip:124@domain.com' 26 | }, 27 | intents: [{ 28 | intent: 'answering_machine' 29 | },{ 30 | intent: 'interested' 31 | },{ 32 | intent: 'not_interested' 33 | },{ 34 | intent: 'do_not_call' 35 | }], 36 | actions: [{ 37 | "invokeOn": "stop", 38 | "name": "sendSummaryEmail", 39 | "parameters": { 40 | "emails": [ 41 | "john@symbl.ai" 42 | ] 43 | } 44 | }], 45 | data: { 46 | session: { 47 | name: 'My Awesome Meet', 48 | users: [{ 49 | user: { 50 | name: 'John', 51 | userId: 'john@symbl.ai', 52 | role: 'organizer' 53 | } 54 | }] 55 | } 56 | } 57 | }).then(connection => { 58 | const connectionId = connection.connectionId; 59 | console.log('Successfully connected:', connectionId); 60 | 61 | // The function `subscribeToConnection` provides the live events as it receives them to the callback function passed 62 | sdk.subscribeToConnection(connectionId, (data) => { 63 | if (data.type === 'intent_response') { 64 | const { intent: intentData } = data; 65 | 66 | switch (intentData.intent) { 67 | case "answering_machine": 68 | let { subIntent } = intentData; 69 | console.log(`SubIntent identified: ${subIntent} for 'answering_machine'`); // subIntents supported under 'answering_machine' are [answered_by_human, answered_by_machine] 70 | case "interested": 71 | case "not_interested": 72 | case "do_not_call": 73 | let { score, text, alternatives } = intentData; 74 | console.log(`Score: ${score}`); // Score of the detected intent 75 | console.log(`Text: ${text}`); // Text at which the intent was detected 76 | console.log(`Alternatives: ${alternatives}`); // These represent other complementing intents if any were detected 77 | break; 78 | } 79 | } else if (data.type === 'transcript_response') { 80 | const { payload: { content }, isFinal } = data; 81 | // isFinal: false represents an on going iteration for the speech being transcribed. 82 | // isFinal: true represents final iteration the transcribed sentence processed util now. 83 | console.log(`Transcription: ${content}, isFinal: ${isFinal}`); 84 | } else if (data.type === 'insight_response') { 85 | const { insights } = data; 86 | insights.forEach(insight => { 87 | const { type, text, confidence, from } = insight; 88 | console.log(`Insight Type: ${type}`); // Insight Type can be one of [action_item, question] 89 | console.log(`Text: ${text}`); // Textual the part of transcript detected as an insight 90 | console.log(`Insight Score: ${confidence}`); // The confidence score for this insight 91 | console.log(`From:`, from); // The detected user who spoke this insight if any 92 | }); 93 | } 94 | }); 95 | 96 | setTimeout(() => { 97 | 98 | // Scheduling stop endpoint call after 30 seconds 99 | setTimeout(() => { 100 | console.log('Stopping connection ' + connection.connectionId); 101 | sdk.stopEndpoint({ 102 | connectionId 103 | }).then(() => { 104 | console.log('Stopped the connection'); 105 | }).catch(err => console.error('Error while stopping the connection:', err)); 106 | }, 30000); 107 | }, 1000); 108 | 109 | }).catch(err => console.error('Error while starting the connection', err)); 110 | 111 | }).catch(err => console.error('Error in SDK initialization.', err)); 112 | -------------------------------------------------------------------------------- /examples/node/telephony/speaker-events/README.md: -------------------------------------------------------------------------------- 1 | # PSTN Dial-in using Voice SDK 2 | 3 | In this example, it establishes a connection using a phone number through PSTN, 4 | to send speaker events, generate insights, and display a summary URL with the 5 | output. You can see how to initialize the Voice SDK, connect to the endpoint, 6 | push speaker events and get the summary URL. 7 | 8 | ## Getting started 9 | 10 | Open `.env` file and add your APP_ID, APP_SECRET, SUMMARY_EMAIL. You can get 11 | APP_ID and APP_SECRET from 12 | [https://platform.symbl.ai](https://platform.symbl.ai) 13 | 14 | Let's start by initializing `symbl-node` sdk 15 | 16 | ```js 17 | await sdk.init({ 18 | appId: process.env.APP_ID, 19 | appSecret: process.env.APP_SECRET, 20 | basePath: 'https://api.symbl.ai', 21 | }) 22 | ``` 23 | 24 | ## Connecting 25 | 26 | `const connection = await sdk.startEndpoint(endpointConfig)` 27 | 28 | First of all let's provide phone number and endpoint type to connect to 29 | a landline or cell number: 30 | 31 | ```javascript 32 | endpoint: { 33 | type: 'pstn', 34 | phoneNumber: process.env.DEFAULT_PHONE_NUMBER, 35 | }, 36 | ``` 37 | 38 | You can also provide `dtmf` code if you have one. You can often find this code 39 | on the meeting platform invite. For example, if your meeting id is 8349: 40 | 41 | ```javascript 42 | endpoint: { 43 | type: 'pstn', 44 | phoneNumber: process.env.DEFAULT_PHONE_NUMBER, 45 | dtmf: ',,8349#' # 8349 <# symbol> 46 | }, 47 | ``` 48 | 49 | In case you want to use `sip` connection, you can use `type: sip` and provide 50 | SIP URI to dial-in to. This should be unique for an active call/meeting in your 51 | system. 52 | 53 | ```javascript 54 | dtmf: "", 55 | type: 'sip', 56 | uri: 'sip:124@domain.com' 57 | ``` 58 | 59 | You can also pass custom `audioConfig`. If not provided, it uses PCMU with 800 60 | sample rate. If you want to provide it, you can do it like so: 61 | 62 | ```js 63 | audioConfig: { 64 | encoding: 'OPUS', 65 | sampleRate: 48000 66 | }, 67 | ``` 68 | 69 | ### Getting connection Id. 70 | 71 | To send speaker events we will need `connectionId` unique to each active 72 | connection. to get it you can simply retrieve it from connection response: 73 | 74 | ```js 75 | const connectionId = connection.connectionId 76 | ``` 77 | 78 | ## Sending speaker events. 79 | 80 | We can send different speaker events to our connection indicating that different 81 | speakers started speaking. That will give us more personalised insights and get 82 | better meeting summary 83 | 84 | In our example we will do it by calling helper `getScheduleEvent` function, that 85 | we will review in a bit. We pass SpeakerEvent type to it by using 86 | `SpeakerEvent.types` enum from `symbl-node`, passing user data and timestamp 87 | 88 | ```javascript 89 | const scheduleEvent = getScheduleEvent(sdk, connectionId) 90 | 91 | setTimeout(() => { 92 | // Schedule all the events to be sent. 93 | scheduleEvent(SpeakerEvent.types.startedSpeaking, users.john, 0) 94 | scheduleEvent(SpeakerEvent.types.stoppedSpeaking, users.john, 5) 95 | }, 1000) 96 | ``` 97 | 98 | We retrieve users just from the global array of users but in real world example 99 | that might be users data retrieved from database. 100 | 101 | ```js 102 | const users = { 103 | john: { 104 | userId: 'john@example.com', 105 | name: 'John', 106 | }, 107 | mary: { 108 | userId: 'mary@example.com', 109 | name: 'Mary', 110 | }, 111 | } 112 | ``` 113 | 114 | In order to push event to our connection we will create an event like so 115 | 116 | ```js 117 | const speakerEvent = new SpeakerEvent({ 118 | type: eventType, 119 | user, 120 | }) 121 | 122 | speakerEvent.timestamp = new Date().toISOString() 123 | ``` 124 | 125 | And push it using `pushEventOnConnection` function provided by SDK 126 | 127 | ```js 128 | sdk.pushEventOnConnection(connectionId, speakerEvent.toJSON(), (err) => { 129 | if (err) { 130 | console.error('Error during push event.', err) 131 | } else { 132 | console.log('Event pushed!') 133 | } 134 | }) 135 | ``` 136 | -------------------------------------------------------------------------------- /examples/node/telephony/speaker-events/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | require('dotenv').config() 5 | 6 | const {sdk, SpeakerEvent} = require('symbl-node') 7 | 8 | const phoneNumber = undefined // replace this with the phone number, or configure DEFAULT_PHONE_NUMBER in .env file. 9 | 10 | sdk 11 | .init({ 12 | appId: process.env.APP_ID, 13 | appSecret: process.env.APP_SECRET, 14 | basePath: 'https://api.symbl.ai', 15 | }) 16 | .then(() => { 17 | console.log('SDK Initialized') 18 | 19 | sdk 20 | .startEndpoint({ 21 | endpoint: { 22 | // type: 'sip', // Use this if you're trying to dial in to a SIP trunk. 23 | // uri: 'sip:username@domain.com', 24 | type: 'pstn', 25 | phoneNumber: phoneNumber || process.env.DEFAULT_PHONE_NUMBER //, 26 | //dtmf: '', // you can find this on the meeting platform invite. Omit or leave blank if not connecting to a meeting platform 27 | }, 28 | actions: [ 29 | { 30 | invokeOn: 'stop', 31 | name: 'sendSummaryEmail', 32 | parameters: { 33 | emails: [process.env.SUMMARY_EMAIL], // Add valid email addresses to received email 34 | }, 35 | }, 36 | ], 37 | }) 38 | .then((connection) => { 39 | const connectionId = connection.connectionId 40 | console.log('Successfully connected.', connectionId) 41 | 42 | const speakerEvent = new SpeakerEvent({ 43 | type: SpeakerEvent.types.startedSpeaking, 44 | user: { 45 | userId: 'john@example.com', 46 | name: 'John', 47 | }, 48 | }) 49 | 50 | setTimeout(() => { 51 | speakerEvent.timestamp = new Date().toISOString() 52 | sdk.pushEventOnConnection( 53 | connectionId, 54 | speakerEvent.toJSON(), 55 | (err) => { 56 | if (err) { 57 | console.error('Error during push event.', err) 58 | } else { 59 | console.log('Event pushed!') 60 | } 61 | }, 62 | ) 63 | }, 1000) 64 | 65 | setTimeout(() => { 66 | speakerEvent.type = SpeakerEvent.types.stoppedSpeaking 67 | speakerEvent.timestamp = new Date().toISOString() 68 | 69 | sdk.pushEventOnConnection( 70 | connectionId, 71 | speakerEvent.toJSON(), 72 | (err) => { 73 | if (err) { 74 | console.error('Error during push event.', err) 75 | } else { 76 | console.log('Event pushed!') 77 | } 78 | }, 79 | ) 80 | }, 12000) 81 | 82 | // Scheduling stop endpoint call after 60 seconds 83 | setTimeout(() => { 84 | sdk 85 | .stopEndpoint({ 86 | connectionId: connection.connectionId, 87 | }) 88 | .then(() => { 89 | console.log('Stopped the connection') 90 | console.log('Summary Info:', connection.summaryInfo) 91 | console.log('Conversation ID:', connection.conversationId) 92 | }) 93 | .catch((err) => 94 | console.error('Error while stopping the connection.', err), 95 | ) 96 | }, 10000) 97 | }) 98 | .catch((err) => console.error('Error while starting the connection', err)) 99 | }) 100 | .catch((err) => console.error('Error in SDK initialization.', err)) 101 | -------------------------------------------------------------------------------- /newPhonecall.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symblai/getting-started-samples/cc110998b763a241339622dd114351a561cfde28/newPhonecall.mp3 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "getting-started-voice-sdk", 3 | "version": "1.0.0", 4 | "description": "Quick code samples to get started and explore Symbl's APIs", 5 | "main": "examples/voice-sdk/index.js", 6 | "directories": { 7 | "example": "examples" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/symblai/getting-started-voice-sdk.git" 12 | }, 13 | "author": "", 14 | "license": "MIT", 15 | "bugs": { 16 | "url": "https://github.com/symblai/getting-started-samples/issues" 17 | }, 18 | "homepage": "https://github.com/symblai/getting-started-samples#readme", 19 | "dependencies": { 20 | "@symblai/symbl-js": "^1.4.8", 21 | "dotenv": "^8.2.0", 22 | "lodash": "^4.17.19", 23 | "mic": "^2.1.2", 24 | "node-audiorecorder": "^3.0.0", 25 | "node-fetch": "^2.6.7", 26 | "request": "^2.88.2", 27 | "symbl-node": "^1.0.11", 28 | "uuid": "^8.1.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /phoneNumber.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/symblai/getting-started-samples/cc110998b763a241339622dd114351a561cfde28/phoneNumber.mp3 -------------------------------------------------------------------------------- /run-example.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Symbl.ai contributors. All Rights Reserved. 4 | # SPDX-License-Identifier: MIT 5 | 6 | # set -o errexit 7 | set -o nounset 8 | set -o pipefail 9 | set -o xtrace 10 | 11 | set +x 12 | echo " " # formatting 13 | 14 | API_TYPE="${1:-""}" 15 | EXAMPLE_NAME="${2:-""}" 16 | SDK_LANG="${SDK_LANG:-""}" 17 | 18 | if [[ -z "${SDK_LANG}" ]]; then 19 | SDK_LANG="node" 20 | fi 21 | 22 | if [[ -z "${API_TYPE}" && -z "${EXAMPLE_NAME}" ]]; then 23 | echo "Syntax: run-example.sh [API_TYPE] " 24 | echo " " 25 | echo "Required Parameters:" 26 | echo "- API_TYPE (required): async-upload, async-url, streaming or telephony" 27 | echo " " 28 | echo "Optional parameters:" 29 | echo "- PROJECT_NAME (optional): if missing, will provide a list of projects" 30 | echo "- SDK_LANG (optional): environment variable to select the language. (Default: node)" 31 | echo "- (optional): some action require user input" 32 | echo " " 33 | echo "Examples:" 34 | echo "To list examples for streaming projects, run:" 35 | echo "run-example.sh realitime" 36 | echo " " 37 | echo "To the realtime tracker example, run:" 38 | echo "run-example.sh realitime tracker" 39 | echo " " 40 | exit 1 41 | fi 42 | 43 | FILENAME="${FILENAME:-""}" 44 | URL="${URL:-""}" 45 | TRACKER_ID="${TRACKER_ID:-""}" 46 | TRACKER_NAME="${TRACKER_NAME:-""}" 47 | TRACKER_VALUE="${TRACKER_VALUE:-""}" 48 | 49 | # handle params 50 | i=3; 51 | j=$#; 52 | while [ $i -le $j ] 53 | do 54 | key=$(echo "${3}" | cut -d "=" -f 1) 55 | value=$(echo "${3}" | cut -d "=" -f 2) 56 | 57 | case "${key}" in 58 | "FILENAME" | "filename") 59 | FILENAME="${value}" 60 | ;; 61 | "URL" | "url") 62 | URL="${value}" 63 | ;; 64 | "TRACKER_ID" | "TRACKERId" | "tracker_id" | "trackeid") 65 | TRACKER_ID="${value}" 66 | ;; 67 | "TRACKER_NAME" | "TRACKERNAME" | "tracker_name" | "trackename") 68 | TRACKER_NAME="${value}" 69 | ;; 70 | "TRACKER_VALUE" | "TRACKERVALUE" | "tracker_value" | "trackevalue") 71 | TRACKER_VALUE="${value}" 72 | ;; 73 | *) 74 | echo "Unknown parameter. Skipping." 75 | ;; 76 | esac 77 | 78 | i=$((i + 1)); 79 | shift 1; 80 | done 81 | 82 | if [[ "${SDK_LANG}" != "node" ]]; then 83 | echo "Currently the only language that is supported is nodejs." 84 | exit 1 85 | fi 86 | if [[ -z "$(command -v ${SDK_LANG})" ]]; then 87 | echo "Please make sure ${SDK_LANG} is installed." 88 | exit 1 89 | fi 90 | 91 | # checks 92 | case "${API_TYPE}" in 93 | "async-upload") 94 | if [[ -z "${FILENAME}" ]]; then 95 | echo "If you want to provide your own audio file, specify FILENAME=\"PATH_TO_FILE\"." 96 | echo "Otherwise, the default at the root of the repo will be provided." 97 | echo " " 98 | fi 99 | ;; 100 | "async-url") 101 | if [[ -z "${URL}" ]]; then 102 | echo "If you want to provide your own audio/video file, specify URL=\"HTTP URL\"." 103 | echo "Otherwise, the default at the root of the repo will be provided." 104 | echo " " 105 | fi 106 | ;; 107 | "management") 108 | if [[ "${EXAMPLE_NAME}" == "create" ]]; then 109 | if [[ -z "${TRACKER_NAME}" || -z "${TRACKER_VALUE}" ]]; then 110 | echo "The tracker name and/or value must be set." 111 | echo "Add TRACKER_NAME=\"myname\" or TRACKER_VALUE=\"myvalue\" if they are missing." 112 | exit 1 113 | fi 114 | elif [[ "${EXAMPLE_NAME}" == "delete" ]]; then 115 | if [[ -z "${TRACKER_ID}" ]]; then 116 | echo "To delete a tracker the ID must be set." 117 | echo "Add TRACKER_ID=\"id\" where id is the value of the Tracker ID." 118 | exit 1 119 | fi 120 | fi 121 | ;; 122 | "streaming" | "telephony") 123 | ;; 124 | *) 125 | echo "The only supported API examples are: async-upload, async-url, streaming, management or telephony." 126 | echo "To list examples using the Asychronous API with File Uploads, run the following command:" 127 | echo "./run-example.sh async-upload" 128 | echo " " 129 | echo "To run the Streaming API where all conversation insights are detected, run the following command:" 130 | echo "./run-example.sh streaming enable-all" 131 | exit 1 132 | ;; 133 | esac 134 | 135 | if [[ -z "${URL}" ]]; then 136 | URL="https://symbltestdata.s3.us-east-2.amazonaws.com/newPhonecall.mp3" 137 | fi 138 | if [[ -z "${FILENAME}" ]]; then 139 | if [[ "${EXAMPLE_NAME}" == "redaction" ]]; then 140 | FILENAME="phoneNumber.mp3" 141 | else 142 | FILENAME="newPhonecall.mp3" 143 | fi 144 | fi 145 | 146 | if [[ -z "${EXAMPLE_NAME}" ]]; then 147 | echo "Here is a list of examples using the ${API_TYPE} APIs:" 148 | find "./examples/node/${API_TYPE}" -type dir | grep "/${API_TYPE}/" | rev | cut -d '/' -f '1' | rev 149 | exit 1 150 | fi 151 | 152 | DIRECTORY="examples/${SDK_LANG}/${API_TYPE}/${EXAMPLE_NAME}" 153 | if [[ ! -d "${DIRECTORY}" ]]; then 154 | echo "Invalid project name. Here are the list that are available:" 155 | find "./examples/node/${API_TYPE}" -type dir | grep "/${API_TYPE}/" | rev | cut -d '/' -f '1' | rev 156 | exit 1 157 | fi 158 | 159 | # execute the example 160 | FILENAME="${FILENAME}" \ 161 | URL="${URL}" \ 162 | TRACKER_ID="${TRACKER_ID}" \ 163 | TRACKER_NAME="${TRACKER_NAME}" \ 164 | TRACKER_VALUE="${TRACKER_VALUE}" \ 165 | node "${DIRECTORY}/index.js" 166 | 167 | set -x 168 | -------------------------------------------------------------------------------- /tutorials/node/live-transcript-phone-call/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /tutorials/node/live-transcript-phone-call/README.md: -------------------------------------------------------------------------------- 1 | # Get a Live Transcription with a Simple Phone Call 2 | 3 | Get the live transcription in your Node.js application by making a simple call 4 | to a valid phone number. 5 | 6 | Making a simple phone call is also the quickest way to test the 7 | [Symbl’s Telephony API](https://docs.symbl.ai/?shell#telephony-api). It can make 8 | an outbound call to a phone number using a traditional public switched telephony 9 | network 10 | ([PSTN](https://en.wikipedia.org/wiki/Public_switched_telephone_network)) or any 11 | [SIP trunks](https://en.wikipedia.org/wiki/SIP_trunking) or SIP endpoints that 12 | can be accessed over the internet using a SIP URI. 13 | 14 | Live transcription can be used by calling let's say meeting number and getting 15 | live transcription of the whole meeting. Important to note, that there won't be 16 | any automated messages, so main use of this API is to get live transcription of 17 | meetings etc. 18 | 19 | ## Setup 20 | 21 | Make sure you have [your account credentials](https://platform.symbl.ai/#/home) 22 | and Node.js installed (> v8.x) on your machine. 23 | 24 | ### Install dependencies 25 | 26 | ```bash 27 | npm install 28 | ``` 29 | 30 | ## Update Code 31 | 32 | 1. Update your credentials in `init()` call. 33 | 34 | ```javascript 35 | sdk.init({ 36 | // Your appId and appSecret https://platform.symbl.ai 37 | appId: 'your_appId', 38 | appSecret: 'your_appSecret', 39 | }) 40 | ``` 41 | 42 | 2. Update your phone number (valid US/Canada number), with country code. 43 | 44 | ```javascript 45 | const connection = await sdk.startEndpoint({ 46 | endpoint: { 47 | type: 'pstn', // when making a regular phone call 48 | // Replace this with a real phone number 49 | phoneNumber: '1XXXXXXXXXX', // include country code, example - 19998887777 50 | }, 51 | }) 52 | ``` 53 | 54 | The above call will start the phone call to your phone, but in order to get 55 | actual live transcription and insights data from the call, you need to subscribe 56 | to connection like so. `sdk.subscribeToConnection` 57 | 58 | You can read more about that in the 59 | [docs](https://docs.symbl.ai/#get-live-transcription-phone-call-node-js-telephony) 60 | 61 | ## Run 62 | 63 | Run the code: 64 | 65 | ```bash 66 | node index.js 67 | ``` 68 | 69 | You should receive a phone call on the phone number you used in the 70 | startEndpoint call. Accept the Call. 71 | 72 | Start speaking - you should see the live transcription being printed on the 73 | console in real-time. 74 | 75 | The call should automatically end after 60 seconds. 76 | -------------------------------------------------------------------------------- /tutorials/node/live-transcript-phone-call/index.js: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Symbl.ai SDK contributors. All Rights Reserved. 2 | // SPDX-License-Identifier: MIT 3 | 4 | const {sdk, SpeakerEvent} = require("symbl-node"); 5 | 6 | sdk.init({ 7 | // Your appId and appSecret https://platform.symbl.ai 8 | appId: 'your_appId', 9 | appSecret: 'your_appSecret' 10 | }).then(async () => { 11 | console.log('SDK initialized.'); 12 | try { 13 | const connection = await sdk.startEndpoint({ 14 | endpoint: { 15 | type: 'pstn', // when making a regular phone call 16 | // Replace this with a real phone number 17 | phoneNumber: '1XXXXXXXXXX' // include country code, example - 19998887777 18 | } 19 | }); 20 | const {connectionId} = connection; 21 | console.log('Successfully connected. Connection Id: ', connectionId); 22 | 23 | // Subscribe to connection using connectionId. 24 | sdk.subscribeToConnection(connectionId, (data) => { 25 | const {type} = data; 26 | if (type === 'transcript_response') { 27 | const {payload} = data; 28 | 29 | // You get live transcription here!! 30 | process.stdout.write('Live: ' + payload && payload.content + '\r'); 31 | 32 | } else if (type === 'message_response') { 33 | const {messages} = data; 34 | 35 | // You get processed messages in the transcript here!!! Real-time but not live! :) 36 | messages.forEach(message => { 37 | process.stdout.write('Message: ' + message.payload.content + '\n'); 38 | }); 39 | } else if (type === 'insight_response') { 40 | const {insights} = data; 41 | // See for more details on Insights 42 | // You get any insights here!!! 43 | insights.forEach(insight => { 44 | process.stdout.write(`Insight: ${insight.type} - ${insight.text} \n\n`); 45 | }); 46 | } 47 | }); 48 | 49 | // Stop call after 60 seconds to automatically. 50 | setTimeout(async () => { 51 | await sdk.stopEndpoint({connectionId}); 52 | console.log('Stopped the connection'); 53 | console.log('Conversation ID:', connection.conversationId); 54 | }, 60000); // Change the 60000 with higher value if you want this to continue for more time. 55 | } catch (e) { 56 | console.error(e); 57 | } 58 | }).catch(err => console.error('Error in SDK initialization.', err)); 59 | -------------------------------------------------------------------------------- /tutorials/node/live-transcript-phone-call/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "live-transcript-phone-call", 3 | "version": "1.0.0", 4 | "description": "Get the live transcription in your Node.js application by making a simple call to a valid phone number.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "license": "MIT", 10 | "dependencies": { 11 | "symbl-node": "latest" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@symblai/api-client@^1.0.17": 6 | version "1.0.17" 7 | resolved "https://registry.npmjs.org/@symblai/api-client/-/api-client-1.0.17.tgz" 8 | dependencies: 9 | superagent "3.5.2" 10 | 11 | "@symblai/symbl-js@^1.4.8": 12 | version "1.4.8" 13 | resolved "https://registry.npmjs.org/@symblai/symbl-js/-/symbl-js-1.4.8.tgz" 14 | dependencies: 15 | "@symblai/api-client" "^1.0.17" 16 | detect-node "^2.1.0" 17 | loglevel "^1.6.1" 18 | mic "^2.1.2" 19 | p-queue "^6.4.0" 20 | uuid latest 21 | websocket "^1.0.28" 22 | 23 | ajv@^6.12.3: 24 | version "6.12.6" 25 | resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" 26 | dependencies: 27 | fast-deep-equal "^3.1.1" 28 | fast-json-stable-stringify "^2.0.0" 29 | json-schema-traverse "^0.4.1" 30 | uri-js "^4.2.2" 31 | 32 | asn1@~0.2.3: 33 | version "0.2.4" 34 | resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz" 35 | dependencies: 36 | safer-buffer "~2.1.0" 37 | 38 | assert-plus@1.0.0, assert-plus@^1.0.0: 39 | version "1.0.0" 40 | resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" 41 | 42 | asynckit@^0.4.0: 43 | version "0.4.0" 44 | resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" 45 | 46 | aws-sign2@~0.7.0: 47 | version "0.7.0" 48 | resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" 49 | 50 | aws4@^1.8.0: 51 | version "1.11.0" 52 | resolved "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz" 53 | 54 | bcrypt-pbkdf@^1.0.0: 55 | version "1.0.2" 56 | resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" 57 | dependencies: 58 | tweetnacl "^0.14.3" 59 | 60 | bufferutil@^4.0.1: 61 | version "4.0.2" 62 | resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.2.tgz" 63 | dependencies: 64 | node-gyp-build "^4.2.0" 65 | 66 | caseless@~0.12.0: 67 | version "0.12.0" 68 | resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" 69 | 70 | combined-stream@^1.0.6, combined-stream@~1.0.6: 71 | version "1.0.8" 72 | resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" 73 | dependencies: 74 | delayed-stream "~1.0.0" 75 | 76 | component-emitter@^1.2.0: 77 | version "1.3.0" 78 | resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" 79 | 80 | cookiejar@^2.0.6: 81 | version "2.1.4" 82 | resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" 83 | 84 | core-util-is@1.0.2, core-util-is@~1.0.0: 85 | version "1.0.2" 86 | resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" 87 | 88 | d@1, d@^1.0.1: 89 | version "1.0.1" 90 | resolved "https://registry.npmjs.org/d/-/d-1.0.1.tgz" 91 | dependencies: 92 | es5-ext "^0.10.50" 93 | type "^1.0.1" 94 | 95 | dashdash@^1.12.0: 96 | version "1.14.1" 97 | resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz" 98 | dependencies: 99 | assert-plus "^1.0.0" 100 | 101 | debug@^2.2.0: 102 | version "2.6.9" 103 | resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" 104 | dependencies: 105 | ms "2.0.0" 106 | 107 | delayed-stream@~1.0.0: 108 | version "1.0.0" 109 | resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" 110 | 111 | detect-node@^2.1.0: 112 | version "2.1.0" 113 | resolved "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz" 114 | 115 | dotenv@^8.2.0: 116 | version "8.2.0" 117 | resolved "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz" 118 | 119 | ecc-jsbn@~0.1.1: 120 | version "0.1.2" 121 | resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz" 122 | dependencies: 123 | jsbn "~0.1.0" 124 | safer-buffer "^2.1.0" 125 | 126 | es5-ext@^0.10.35, es5-ext@^0.10.50: 127 | version "0.10.53" 128 | resolved "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz" 129 | dependencies: 130 | es6-iterator "~2.0.3" 131 | es6-symbol "~3.1.3" 132 | next-tick "~1.0.0" 133 | 134 | es6-iterator@~2.0.3: 135 | version "2.0.3" 136 | resolved "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz" 137 | dependencies: 138 | d "1" 139 | es5-ext "^0.10.35" 140 | es6-symbol "^3.1.1" 141 | 142 | es6-symbol@^3.1.1, es6-symbol@~3.1.3: 143 | version "3.1.3" 144 | resolved "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz" 145 | dependencies: 146 | d "^1.0.1" 147 | ext "^1.1.2" 148 | 149 | eventemitter3@^4.0.4: 150 | version "4.0.7" 151 | resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" 152 | 153 | ext@^1.1.2: 154 | version "1.4.0" 155 | resolved "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz" 156 | dependencies: 157 | type "^2.0.0" 158 | 159 | extend@^3.0.0, extend@~3.0.2: 160 | version "3.0.2" 161 | resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" 162 | 163 | extsprintf@1.3.0, extsprintf@^1.2.0: 164 | version "1.3.0" 165 | resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" 166 | 167 | fast-deep-equal@^3.1.1: 168 | version "3.1.3" 169 | resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" 170 | 171 | fast-json-stable-stringify@^2.0.0: 172 | version "2.1.0" 173 | resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" 174 | 175 | forever-agent@~0.6.1: 176 | version "0.6.1" 177 | resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" 178 | 179 | form-data@^2.1.1, form-data@~2.3.2: 180 | version "2.3.3" 181 | resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz" 182 | dependencies: 183 | asynckit "^0.4.0" 184 | combined-stream "^1.0.6" 185 | mime-types "^2.1.12" 186 | 187 | formidable@^1.1.1, formidable@^1.2.0: 188 | version "1.2.2" 189 | resolved "https://registry.npmjs.org/formidable/-/formidable-1.2.2.tgz" 190 | 191 | getpass@^0.1.1: 192 | version "0.1.7" 193 | resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" 194 | dependencies: 195 | assert-plus "^1.0.0" 196 | 197 | har-schema@^2.0.0: 198 | version "2.0.0" 199 | resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" 200 | 201 | har-validator@~5.1.3: 202 | version "5.1.5" 203 | resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz" 204 | dependencies: 205 | ajv "^6.12.3" 206 | har-schema "^2.0.0" 207 | 208 | http-signature@~1.2.0: 209 | version "1.2.0" 210 | resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz" 211 | dependencies: 212 | assert-plus "^1.0.0" 213 | jsprim "^1.2.2" 214 | sshpk "^1.7.0" 215 | 216 | inherits@~2.0.3: 217 | version "2.0.4" 218 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" 219 | 220 | is-typedarray@^1.0.0, is-typedarray@~1.0.0: 221 | version "1.0.0" 222 | resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" 223 | 224 | isarray@~1.0.0: 225 | version "1.0.0" 226 | resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" 227 | 228 | isstream@~0.1.2: 229 | version "0.1.2" 230 | resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" 231 | 232 | jsbn@~0.1.0: 233 | version "0.1.1" 234 | resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" 235 | 236 | json-schema-traverse@^0.4.1: 237 | version "0.4.1" 238 | resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" 239 | 240 | json-schema@0.4.0: 241 | version "0.4.0" 242 | resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz" 243 | 244 | json-stringify-safe@~5.0.1: 245 | version "5.0.1" 246 | resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" 247 | 248 | jsprim@^1.2.2: 249 | version "1.4.2" 250 | resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz" 251 | dependencies: 252 | assert-plus "1.0.0" 253 | extsprintf "1.3.0" 254 | json-schema "0.4.0" 255 | verror "1.10.0" 256 | 257 | lodash@^4.17.19: 258 | version "4.17.21" 259 | resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" 260 | 261 | loglevel@^1.6.1: 262 | version "1.8.0" 263 | resolved "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz" 264 | 265 | methods@^1.1.1: 266 | version "1.1.2" 267 | resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" 268 | 269 | mic@^2.1.2: 270 | version "2.1.2" 271 | resolved "https://registry.npmjs.org/mic/-/mic-2.1.2.tgz" 272 | 273 | mime-db@1.44.0: 274 | version "1.44.0" 275 | resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz" 276 | 277 | mime-types@^2.1.12, mime-types@~2.1.19: 278 | version "2.1.27" 279 | resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz" 280 | dependencies: 281 | mime-db "1.44.0" 282 | 283 | mime@^1.3.4: 284 | version "1.6.0" 285 | resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" 286 | 287 | ms@2.0.0: 288 | version "2.0.0" 289 | resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" 290 | 291 | next-tick@~1.0.0: 292 | version "1.0.0" 293 | resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz" 294 | 295 | node-audiorecorder@^3.0.0: 296 | version "3.0.0" 297 | resolved "https://registry.npmjs.org/node-audiorecorder/-/node-audiorecorder-3.0.0.tgz" 298 | 299 | node-fetch@^2.6.7: 300 | version "2.6.7" 301 | resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" 302 | dependencies: 303 | whatwg-url "^5.0.0" 304 | 305 | node-gyp-build@^4.2.0: 306 | version "4.2.3" 307 | resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz" 308 | 309 | oauth-sign@~0.9.0: 310 | version "0.9.0" 311 | resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" 312 | 313 | p-finally@^1.0.0: 314 | version "1.0.0" 315 | resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" 316 | 317 | p-queue@^6.4.0: 318 | version "6.6.2" 319 | resolved "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz" 320 | dependencies: 321 | eventemitter3 "^4.0.4" 322 | p-timeout "^3.2.0" 323 | 324 | p-timeout@^3.2.0: 325 | version "3.2.0" 326 | resolved "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz" 327 | dependencies: 328 | p-finally "^1.0.0" 329 | 330 | performance-now@^2.1.0: 331 | version "2.1.0" 332 | resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" 333 | 334 | process-nextick-args@~2.0.0: 335 | version "2.0.1" 336 | resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" 337 | 338 | psl@^1.1.28: 339 | version "1.8.0" 340 | resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz" 341 | 342 | punycode@^2.1.0, punycode@^2.1.1: 343 | version "2.1.1" 344 | resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" 345 | 346 | qs@^6.1.0, qs@~6.5.2: 347 | version "6.5.3" 348 | resolved "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz" 349 | 350 | readable-stream@^2.0.5: 351 | version "2.3.7" 352 | resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" 353 | dependencies: 354 | core-util-is "~1.0.0" 355 | inherits "~2.0.3" 356 | isarray "~1.0.0" 357 | process-nextick-args "~2.0.0" 358 | safe-buffer "~5.1.1" 359 | string_decoder "~1.1.1" 360 | util-deprecate "~1.0.1" 361 | 362 | request@^2.88.2: 363 | version "2.88.2" 364 | resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz" 365 | dependencies: 366 | aws-sign2 "~0.7.0" 367 | aws4 "^1.8.0" 368 | caseless "~0.12.0" 369 | combined-stream "~1.0.6" 370 | extend "~3.0.2" 371 | forever-agent "~0.6.1" 372 | form-data "~2.3.2" 373 | har-validator "~5.1.3" 374 | http-signature "~1.2.0" 375 | is-typedarray "~1.0.0" 376 | isstream "~0.1.2" 377 | json-stringify-safe "~5.0.1" 378 | mime-types "~2.1.19" 379 | oauth-sign "~0.9.0" 380 | performance-now "^2.1.0" 381 | qs "~6.5.2" 382 | safe-buffer "^5.1.2" 383 | tough-cookie "~2.5.0" 384 | tunnel-agent "^0.6.0" 385 | uuid "^3.3.2" 386 | 387 | safe-buffer@^5.0.1, safe-buffer@^5.1.2: 388 | version "5.2.1" 389 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" 390 | 391 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 392 | version "5.1.2" 393 | resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" 394 | 395 | safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: 396 | version "2.1.2" 397 | resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" 398 | 399 | sshpk@^1.7.0: 400 | version "1.16.1" 401 | resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz" 402 | dependencies: 403 | asn1 "~0.2.3" 404 | assert-plus "^1.0.0" 405 | bcrypt-pbkdf "^1.0.0" 406 | dashdash "^1.12.0" 407 | ecc-jsbn "~0.1.1" 408 | getpass "^0.1.1" 409 | jsbn "~0.1.0" 410 | safer-buffer "^2.0.2" 411 | tweetnacl "~0.14.0" 412 | 413 | string_decoder@~1.1.1: 414 | version "1.1.1" 415 | resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" 416 | dependencies: 417 | safe-buffer "~5.1.0" 418 | 419 | superagent@3.5.2: 420 | version "3.5.2" 421 | resolved "https://registry.npmjs.org/superagent/-/superagent-3.5.2.tgz" 422 | dependencies: 423 | component-emitter "^1.2.0" 424 | cookiejar "^2.0.6" 425 | debug "^2.2.0" 426 | extend "^3.0.0" 427 | form-data "^2.1.1" 428 | formidable "^1.1.1" 429 | methods "^1.1.1" 430 | mime "^1.3.4" 431 | qs "^6.1.0" 432 | readable-stream "^2.0.5" 433 | 434 | symbl-node@^1.0.11: 435 | version "1.0.11" 436 | resolved "https://registry.npmjs.org/symbl-node/-/symbl-node-1.0.11.tgz" 437 | dependencies: 438 | formidable "^1.2.0" 439 | websocket "^1.0.26" 440 | 441 | tough-cookie@~2.5.0: 442 | version "2.5.0" 443 | resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" 444 | dependencies: 445 | psl "^1.1.28" 446 | punycode "^2.1.1" 447 | 448 | tr46@~0.0.3: 449 | version "0.0.3" 450 | resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" 451 | 452 | tunnel-agent@^0.6.0: 453 | version "0.6.0" 454 | resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" 455 | dependencies: 456 | safe-buffer "^5.0.1" 457 | 458 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 459 | version "0.14.5" 460 | resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" 461 | 462 | type@^1.0.1: 463 | version "1.2.0" 464 | resolved "https://registry.npmjs.org/type/-/type-1.2.0.tgz" 465 | 466 | type@^2.0.0: 467 | version "2.1.0" 468 | resolved "https://registry.npmjs.org/type/-/type-2.1.0.tgz" 469 | 470 | typedarray-to-buffer@^3.1.5: 471 | version "3.1.5" 472 | resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" 473 | dependencies: 474 | is-typedarray "^1.0.0" 475 | 476 | uri-js@^4.2.2: 477 | version "4.4.0" 478 | resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz" 479 | dependencies: 480 | punycode "^2.1.0" 481 | 482 | utf-8-validate@^5.0.2: 483 | version "5.0.3" 484 | resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.3.tgz" 485 | dependencies: 486 | node-gyp-build "^4.2.0" 487 | 488 | util-deprecate@~1.0.1: 489 | version "1.0.2" 490 | resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" 491 | 492 | uuid@^3.3.2: 493 | version "3.4.0" 494 | resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" 495 | 496 | uuid@^8.1.0: 497 | version "8.1.0" 498 | resolved "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz" 499 | 500 | uuid@latest: 501 | version "9.0.0" 502 | resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz" 503 | 504 | verror@1.10.0: 505 | version "1.10.0" 506 | resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" 507 | dependencies: 508 | assert-plus "^1.0.0" 509 | core-util-is "1.0.2" 510 | extsprintf "^1.2.0" 511 | 512 | webidl-conversions@^3.0.0: 513 | version "3.0.1" 514 | resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" 515 | 516 | websocket@^1.0.26, websocket@^1.0.28: 517 | version "1.0.32" 518 | resolved "https://registry.npmjs.org/websocket/-/websocket-1.0.32.tgz" 519 | dependencies: 520 | bufferutil "^4.0.1" 521 | debug "^2.2.0" 522 | es5-ext "^0.10.50" 523 | typedarray-to-buffer "^3.1.5" 524 | utf-8-validate "^5.0.2" 525 | yaeti "^0.0.6" 526 | 527 | whatwg-url@^5.0.0: 528 | version "5.0.0" 529 | resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" 530 | dependencies: 531 | tr46 "~0.0.3" 532 | webidl-conversions "^3.0.0" 533 | 534 | yaeti@^0.0.6: 535 | version "0.0.6" 536 | resolved "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz" 537 | --------------------------------------------------------------------------------