mirror of
https://github.com/jambonz/jambonz-api-server.git
synced 2026-01-25 02:08:24 +00:00
Compare commits
1 Commits
v0.9.2-rc2
...
fix/admin_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cfd1eab7cd |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -7,21 +7,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install Docker Compose
|
||||
run: |
|
||||
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
docker-compose --version
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: lts/*
|
||||
- run: npm install
|
||||
- run: npm run jslint
|
||||
- name: Install Docker Compose
|
||||
run: |
|
||||
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
docker-compose --version
|
||||
- run: npm test
|
||||
|
||||
|
||||
|
||||
60
.github/workflows/docker-publish-dbcreate.yml
vendored
60
.github/workflows/docker-publish-dbcreate.yml
vendored
@@ -2,10 +2,16 @@ name: Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
# Publish `main` as Docker `latest` image.
|
||||
branches:
|
||||
- main
|
||||
|
||||
# Publish `v1.2.3` tags as releases.
|
||||
tags:
|
||||
- '*'
|
||||
- v*
|
||||
|
||||
env:
|
||||
IMAGE_NAME: db-create
|
||||
|
||||
jobs:
|
||||
push:
|
||||
@@ -14,42 +20,32 @@ jobs:
|
||||
if: github.event_name == 'push'
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: prepare tag
|
||||
id: prepare_tag
|
||||
- name: Build image
|
||||
run: docker build . --file Dockerfile.db-create --tag $IMAGE_NAME
|
||||
|
||||
- name: Log into registry
|
||||
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||
|
||||
- name: Push image
|
||||
run: |
|
||||
IMAGE_ID=jambonz/db-create
|
||||
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
|
||||
|
||||
# Strip git ref prefix from version
|
||||
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
|
||||
# Change all uppercase to lowercase
|
||||
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
|
||||
|
||||
# Strip "v" prefix from tag name
|
||||
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
|
||||
# Strip git ref prefix from version
|
||||
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
|
||||
|
||||
# Use Docker `latest` tag convention
|
||||
[ "$VERSION" == "main" ] && VERSION=latest
|
||||
# Strip "v" prefix from tag name
|
||||
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
|
||||
|
||||
echo IMAGE_ID=$IMAGE_ID
|
||||
echo VERSION=$VERSION
|
||||
# Use Docker `latest` tag convention
|
||||
[ "$VERSION" == "main" ] && VERSION=latest
|
||||
|
||||
echo "image_id=$IMAGE_ID" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo IMAGE_ID=$IMAGE_ID
|
||||
echo VERSION=$VERSION
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile.db-create
|
||||
push: true
|
||||
tags: ${{ steps.prepare_tag.outputs.image_id }}:${{ steps.prepare_tag.outputs.version }}
|
||||
build-args: |
|
||||
GITHUB_REPOSITORY=$GITHUB_REPOSITORY
|
||||
GITHUB_REF=$GITHUB_REF
|
||||
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
|
||||
docker push $IMAGE_ID:$VERSION
|
||||
4
.github/workflows/docker-publish.yml
vendored
4
.github/workflows/docker-publish.yml
vendored
@@ -2,8 +2,6 @@ name: Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
@@ -20,7 +18,7 @@ jobs:
|
||||
- name: prepare tag
|
||||
id: prepare_tag
|
||||
run: |
|
||||
IMAGE_ID=jambonz/api-server
|
||||
IMAGE_ID=$GITHUB_REPOSITORY
|
||||
|
||||
# Strip git ref prefix from version
|
||||
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2024 FirstFive8, Inc.
|
||||
Copyright (c) 2021 Drachtio Communications Services, LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -33,8 +33,6 @@ Configuration is provided via environment variables:
|
||||
|K8S| service running as kubernetes service |no|
|
||||
|K8S_FEATURE_SERVER_SERVICE_NAME| feature server name(required for K8S) |no|
|
||||
|K8S_FEATURE_SERVER_SERVICE_PORT| feature server port(required for K8S) |no|
|
||||
|JAMBONZ_RECORD_WS_USERNAME| recording websocket username|no|
|
||||
|JAMBONZ_RECORD_WS_PASSWORD| recording websocket password|no|
|
||||
|
||||
#### Database dependency
|
||||
A mysql database is used to store long-lived objects such as Accounts, Applications, etc. To create the database schema, use or review the scripts in the 'db' folder, particularly:
|
||||
|
||||
93
app.js
93
app.js
@@ -8,18 +8,12 @@ const rateLimit = require('express-rate-limit');
|
||||
const cors = require('cors');
|
||||
const passport = require('passport');
|
||||
const routes = require('./lib/routes');
|
||||
const Registrar = require('@jambonz/mw-registrar');
|
||||
|
||||
assert.ok(process.env.JAMBONES_MYSQL_HOST &&
|
||||
process.env.JAMBONES_MYSQL_USER &&
|
||||
process.env.JAMBONES_MYSQL_PASSWORD &&
|
||||
process.env.JAMBONES_MYSQL_DATABASE, 'missing JAMBONES_MYSQL_XXX env vars');
|
||||
if (process.env.JAMBONES_REDIS_SENTINELS) {
|
||||
assert.ok(process.env.JAMBONES_REDIS_SENTINEL_MASTER_NAME,
|
||||
'missing JAMBONES_REDIS_SENTINEL_MASTER_NAME env var, JAMBONES_REDIS_SENTINEL_PASSWORD env var is optional');
|
||||
} else {
|
||||
assert.ok(process.env.JAMBONES_REDIS_HOST, 'missing JAMBONES_REDIS_HOST env var');
|
||||
}
|
||||
assert.ok(process.env.JAMBONES_REDIS_HOST, 'missing JAMBONES_REDIS_HOST env var');
|
||||
assert.ok(process.env.JAMBONES_TIME_SERIES_HOST, 'missing JAMBONES_TIME_SERIES_HOST env var');
|
||||
assert.ok(process.env.ENCRYPTION_SECRET || process.env.JWT_SECRET, 'missing ENCRYPTION_SECRET env var');
|
||||
assert.ok(process.env.JWT_SECRET, 'missing JWT_SECRET env var');
|
||||
@@ -36,27 +30,23 @@ const {
|
||||
logger, process.env.JAMBONES_TIME_SERIES_HOST
|
||||
);
|
||||
const {
|
||||
client,
|
||||
retrieveCall,
|
||||
deleteCall,
|
||||
listCalls,
|
||||
listSortedSets,
|
||||
listQueues,
|
||||
purgeCalls,
|
||||
retrieveSet,
|
||||
addKey,
|
||||
retrieveKey,
|
||||
deleteKey,
|
||||
incrKey,
|
||||
listConferences
|
||||
incrKey
|
||||
} = require('./lib/helpers/realtimedb-helpers');
|
||||
const {
|
||||
getTtsVoices,
|
||||
getTtsSize,
|
||||
purgeTtsCache,
|
||||
getAwsAuthToken,
|
||||
getVerbioAccessToken,
|
||||
synthAudio
|
||||
} = require('@jambonz/speech-utils')({}, logger);
|
||||
getTtsVoices
|
||||
} = require('@jambonz/speech-utils')({
|
||||
host: process.env.JAMBONES_REDIS_HOST,
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
}, logger);
|
||||
const {
|
||||
lookupAppBySid,
|
||||
lookupAccountBySid,
|
||||
@@ -64,8 +54,7 @@ const {
|
||||
lookupAppByPhoneNumber,
|
||||
lookupCarrierBySid,
|
||||
lookupSipGatewayBySid,
|
||||
lookupSmppGatewayBySid,
|
||||
lookupClientByAccountAndUsername
|
||||
lookupSmppGatewayBySid
|
||||
} = require('@jambonz/db-helpers')({
|
||||
host: process.env.JAMBONES_MYSQL_HOST,
|
||||
user: process.env.JAMBONES_MYSQL_USER,
|
||||
@@ -77,20 +66,17 @@ const {
|
||||
const PORT = process.env.HTTP_PORT || 3000;
|
||||
const authStrategy = require('./lib/auth')(logger, retrieveKey);
|
||||
const {delayLoginMiddleware} = require('./lib/middleware');
|
||||
const Websocket = require('ws');
|
||||
|
||||
passport.use(authStrategy);
|
||||
|
||||
app.locals = app.locals || {};
|
||||
app.locals = {
|
||||
...app.locals,
|
||||
registrar: new Registrar(logger, client),
|
||||
logger,
|
||||
retrieveCall,
|
||||
deleteCall,
|
||||
listCalls,
|
||||
listSortedSets,
|
||||
listConferences,
|
||||
listQueues,
|
||||
purgeCalls,
|
||||
retrieveSet,
|
||||
addKey,
|
||||
@@ -98,11 +84,6 @@ app.locals = {
|
||||
retrieveKey,
|
||||
deleteKey,
|
||||
getTtsVoices,
|
||||
getTtsSize,
|
||||
getAwsAuthToken,
|
||||
getVerbioAccessToken,
|
||||
purgeTtsCache,
|
||||
synthAudio,
|
||||
lookupAppBySid,
|
||||
lookupAccountBySid,
|
||||
lookupAccountByPhoneNumber,
|
||||
@@ -110,7 +91,6 @@ app.locals = {
|
||||
lookupCarrierBySid,
|
||||
lookupSipGatewayBySid,
|
||||
lookupSmppGatewayBySid,
|
||||
lookupClientByAccountAndUsername,
|
||||
queryCdrs,
|
||||
queryCdrsSP,
|
||||
queryAlerts,
|
||||
@@ -134,12 +114,6 @@ const limiter = rateLimit({
|
||||
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
|
||||
});
|
||||
|
||||
// Setup websocket for recording audio
|
||||
const recordWsServer = require('./lib/record');
|
||||
const wsServer = new Websocket.Server({ noServer: true });
|
||||
wsServer.setMaxListeners(0);
|
||||
wsServer.on('connection', recordWsServer.bind(null, logger));
|
||||
|
||||
if (process.env.JAMBONES_TRUST_PROXY) {
|
||||
const proxyCount = parseInt(process.env.JAMBONES_TRUST_PROXY);
|
||||
if (!isNaN(proxyCount) && proxyCount > 0) {
|
||||
@@ -180,52 +154,7 @@ app.use((err, req, res, next) => {
|
||||
});
|
||||
});
|
||||
logger.info(`listening for HTTP traffic on port ${PORT}`);
|
||||
const server = app.listen(PORT);
|
||||
|
||||
|
||||
const isValidWsKey = (hdr) => {
|
||||
const username = process.env.JAMBONZ_RECORD_WS_USERNAME || process.env.JAMBONES_RECORD_WS_USERNAME;
|
||||
const password = process.env.JAMBONZ_RECORD_WS_PASSWORD || process.env.JAMBONES_RECORD_WS_PASSWORD;
|
||||
if (username && password) {
|
||||
if (!hdr) {
|
||||
// auth header is missing
|
||||
return false;
|
||||
}
|
||||
const token = Buffer.from(`${username}:${password}`).toString('base64');
|
||||
const arr = /^Basic (.*)$/.exec(hdr);
|
||||
if (!Array.isArray(arr)) {
|
||||
// malformed auth header
|
||||
return false;
|
||||
}
|
||||
return arr[1] === token;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
server.on('upgrade', (request, socket, head) => {
|
||||
logger.debug({
|
||||
url: request.url,
|
||||
headers: request.headers,
|
||||
}, 'received upgrade request');
|
||||
|
||||
/* verify the path starts with /transcribe */
|
||||
if (!request.url.includes('/record/')) {
|
||||
logger.info(`unhandled path: ${request.url}`);
|
||||
return socket.write('HTTP/1.1 404 Not Found \r\n\r\n', () => socket.destroy());
|
||||
}
|
||||
|
||||
/* verify the api key */
|
||||
if (!isValidWsKey(request.headers['authorization'])) {
|
||||
logger.info(`invalid auth header: ${request.headers['authorization'] || 'authorization header missing'}`);
|
||||
return socket.write('HTTP/1.1 403 Forbidden \r\n\r\n', () => socket.destroy());
|
||||
}
|
||||
|
||||
/* complete the upgrade */
|
||||
wsServer.handleUpgrade(request, socket, head, (ws) => {
|
||||
logger.info(`upgraded to websocket, url: ${request.url}`);
|
||||
wsServer.emit('connection', ws, request.url);
|
||||
});
|
||||
});
|
||||
app.listen(PORT);
|
||||
|
||||
// purge old calls from active call set every 10 mins
|
||||
async function purge() {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* SQLEditor (MySQL (2))*/
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
DROP TABLE IF EXISTS account_static_ips;
|
||||
@@ -14,8 +13,6 @@ DROP TABLE IF EXISTS beta_invite_codes;
|
||||
|
||||
DROP TABLE IF EXISTS call_routes;
|
||||
|
||||
DROP TABLE IF EXISTS clients;
|
||||
|
||||
DROP TABLE IF EXISTS dns_records;
|
||||
|
||||
DROP TABLE IF EXISTS lcr;
|
||||
@@ -54,8 +51,6 @@ DROP TABLE IF EXISTS signup_history;
|
||||
|
||||
DROP TABLE IF EXISTS smpp_addresses;
|
||||
|
||||
DROP TABLE IF EXISTS google_custom_voices;
|
||||
|
||||
DROP TABLE IF EXISTS speech_credentials;
|
||||
|
||||
DROP TABLE IF EXISTS system_information;
|
||||
@@ -132,19 +127,6 @@ application_sid CHAR(36) NOT NULL,
|
||||
PRIMARY KEY (call_route_sid)
|
||||
) COMMENT='a regex-based pattern match for call routing';
|
||||
|
||||
CREATE TABLE clients
|
||||
(
|
||||
client_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
account_sid CHAR(36) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT 1,
|
||||
username VARCHAR(64),
|
||||
password VARCHAR(1024),
|
||||
allow_direct_app_calling BOOLEAN NOT NULL DEFAULT 1,
|
||||
allow_direct_queue_calling BOOLEAN NOT NULL DEFAULT 1,
|
||||
allow_direct_user_calling BOOLEAN NOT NULL DEFAULT 1,
|
||||
PRIMARY KEY (client_sid)
|
||||
);
|
||||
|
||||
CREATE TABLE dns_records
|
||||
(
|
||||
dns_record_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
@@ -162,7 +144,7 @@ regex VARCHAR(32) NOT NULL COMMENT 'regex-based pattern match against dialed num
|
||||
description VARCHAR(1024),
|
||||
priority INTEGER NOT NULL COMMENT 'lower priority routes are attempted first',
|
||||
PRIMARY KEY (lcr_route_sid)
|
||||
) COMMENT='An ordered list of digit patterns in an LCR table. The pat';
|
||||
) COMMENT='An ordered list of digit patterns in an LCR table. The patterns are tested in sequence until one matches';
|
||||
|
||||
CREATE TABLE lcr
|
||||
(
|
||||
@@ -173,7 +155,7 @@ default_carrier_set_entry_sid CHAR(36) COMMENT 'default carrier/route to use whe
|
||||
service_provider_sid CHAR(36),
|
||||
account_sid CHAR(36),
|
||||
PRIMARY KEY (lcr_sid)
|
||||
) COMMENT='An LCR (least cost routing) table that is used by a service ';
|
||||
) COMMENT='An LCR (least cost routing) table that is used by a service provider or account to make decisions about routing outbound calls when multiple carriers are available.';
|
||||
|
||||
CREATE TABLE password_settings
|
||||
(
|
||||
@@ -340,26 +322,14 @@ last_tested DATETIME,
|
||||
tts_tested_ok BOOLEAN,
|
||||
stt_tested_ok BOOLEAN,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
label VARCHAR(64),
|
||||
PRIMARY KEY (speech_credential_sid)
|
||||
);
|
||||
|
||||
CREATE TABLE google_custom_voices
|
||||
(
|
||||
google_custom_voice_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
speech_credential_sid CHAR(36) NOT NULL,
|
||||
model VARCHAR(512) NOT NULL,
|
||||
reported_usage ENUM('REPORTED_USAGE_UNSPECIFIED','REALTIME','OFFLINE') DEFAULT 'REALTIME',
|
||||
name VARCHAR(64) NOT NULL,
|
||||
PRIMARY KEY (google_custom_voice_sid)
|
||||
);
|
||||
|
||||
CREATE TABLE system_information
|
||||
(
|
||||
domain_name VARCHAR(255),
|
||||
sip_domain_name VARCHAR(255),
|
||||
monitoring_domain_name VARCHAR(255),
|
||||
private_network_cidr VARCHAR(8192)
|
||||
monitoring_domain_name VARCHAR(255)
|
||||
);
|
||||
|
||||
CREATE TABLE users
|
||||
@@ -441,7 +411,7 @@ PRIMARY KEY (smpp_gateway_sid)
|
||||
CREATE TABLE phone_numbers
|
||||
(
|
||||
phone_number_sid CHAR(36) UNIQUE ,
|
||||
number VARCHAR(132) NOT NULL,
|
||||
number VARCHAR(132) NOT NULL UNIQUE ,
|
||||
voip_carrier_sid CHAR(36),
|
||||
account_sid CHAR(36),
|
||||
application_sid CHAR(36),
|
||||
@@ -454,14 +424,11 @@ CREATE TABLE sip_gateways
|
||||
sip_gateway_sid CHAR(36),
|
||||
ipv4 VARCHAR(128) NOT NULL COMMENT 'ip address or DNS name of the gateway. For gateways providing inbound calling service, ip address is required.',
|
||||
netmask INTEGER NOT NULL DEFAULT 32,
|
||||
port INTEGER COMMENT 'sip signaling port',
|
||||
port INTEGER NOT NULL DEFAULT 5060 COMMENT 'sip signaling port',
|
||||
inbound BOOLEAN NOT NULL COMMENT 'if true, whitelist this IP to allow inbound calls from the gateway',
|
||||
outbound BOOLEAN NOT NULL COMMENT 'if true, include in least-cost routing when placing calls to the PSTN',
|
||||
voip_carrier_sid CHAR(36) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT 1,
|
||||
send_options_ping BOOLEAN NOT NULL DEFAULT 0,
|
||||
use_sips_scheme BOOLEAN NOT NULL DEFAULT 0,
|
||||
pad_crypto BOOLEAN NOT NULL DEFAULT 0,
|
||||
protocol ENUM('udp','tcp','tls', 'tls/srtp') DEFAULT 'udp' COMMENT 'Outbound call protocol',
|
||||
PRIMARY KEY (sip_gateway_sid)
|
||||
) COMMENT='A whitelisted sip gateway used for origination/termination';
|
||||
@@ -498,21 +465,10 @@ messaging_hook_sid CHAR(36) COMMENT 'webhook to call for inbound SMS/MMS ',
|
||||
app_json TEXT,
|
||||
speech_synthesis_vendor VARCHAR(64) NOT NULL DEFAULT 'google',
|
||||
speech_synthesis_language VARCHAR(12) NOT NULL DEFAULT 'en-US',
|
||||
speech_synthesis_voice VARCHAR(256),
|
||||
speech_synthesis_label VARCHAR(64),
|
||||
speech_synthesis_voice VARCHAR(64),
|
||||
speech_recognizer_vendor VARCHAR(64) NOT NULL DEFAULT 'google',
|
||||
speech_recognizer_language VARCHAR(64) NOT NULL DEFAULT 'en-US',
|
||||
speech_recognizer_label VARCHAR(64),
|
||||
use_for_fallback_speech BOOLEAN DEFAULT false,
|
||||
fallback_speech_synthesis_vendor VARCHAR(64),
|
||||
fallback_speech_synthesis_language VARCHAR(12),
|
||||
fallback_speech_synthesis_voice VARCHAR(256),
|
||||
fallback_speech_synthesis_label VARCHAR(64),
|
||||
fallback_speech_recognizer_vendor VARCHAR(64),
|
||||
fallback_speech_recognizer_language VARCHAR(64),
|
||||
fallback_speech_recognizer_label VARCHAR(64),
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
record_all_calls BOOLEAN NOT NULL DEFAULT false,
|
||||
PRIMARY KEY (application_sid)
|
||||
) COMMENT='A defined set of behaviors to be applied to phone calls ';
|
||||
|
||||
@@ -550,9 +506,6 @@ subspace_client_secret VARCHAR(255),
|
||||
subspace_sip_teleport_id VARCHAR(255),
|
||||
subspace_sip_teleport_destinations VARCHAR(255),
|
||||
siprec_hook_sid CHAR(36),
|
||||
record_all_calls BOOLEAN NOT NULL DEFAULT false,
|
||||
record_format VARCHAR(16) NOT NULL DEFAULT 'mp3',
|
||||
bucket_credential VARCHAR(8192) COMMENT 'credential used to authenticate with storage service',
|
||||
PRIMARY KEY (account_sid)
|
||||
) COMMENT='An enterprise that uses the platform for comm services';
|
||||
|
||||
@@ -573,9 +526,6 @@ ALTER TABLE call_routes ADD FOREIGN KEY account_sid_idxfk_3 (account_sid) REFERE
|
||||
|
||||
ALTER TABLE call_routes ADD FOREIGN KEY application_sid_idxfk (application_sid) REFERENCES applications (application_sid);
|
||||
|
||||
CREATE INDEX client_sid_idx ON clients (client_sid);
|
||||
ALTER TABLE clients ADD CONSTRAINT account_sid_idxfk_13 FOREIGN KEY account_sid_idxfk_13 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
CREATE INDEX dns_record_sid_idx ON dns_records (dns_record_sid);
|
||||
ALTER TABLE dns_records ADD FOREIGN KEY account_sid_idxfk_4 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
@@ -640,6 +590,8 @@ CREATE INDEX smpp_address_sid_idx ON smpp_addresses (smpp_address_sid);
|
||||
CREATE INDEX service_provider_sid_idx ON smpp_addresses (service_provider_sid);
|
||||
ALTER TABLE smpp_addresses ADD FOREIGN KEY service_provider_sid_idxfk_4 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
|
||||
|
||||
CREATE UNIQUE INDEX speech_credentials_idx_1 ON speech_credentials (vendor,account_sid);
|
||||
|
||||
CREATE INDEX speech_credential_sid_idx ON speech_credentials (speech_credential_sid);
|
||||
CREATE INDEX service_provider_sid_idx ON speech_credentials (service_provider_sid);
|
||||
ALTER TABLE speech_credentials ADD FOREIGN KEY service_provider_sid_idxfk_5 (service_provider_sid) REFERENCES service_providers (service_provider_sid);
|
||||
@@ -647,10 +599,6 @@ ALTER TABLE speech_credentials ADD FOREIGN KEY service_provider_sid_idxfk_5 (ser
|
||||
CREATE INDEX account_sid_idx ON speech_credentials (account_sid);
|
||||
ALTER TABLE speech_credentials ADD FOREIGN KEY account_sid_idxfk_8 (account_sid) REFERENCES accounts (account_sid);
|
||||
|
||||
CREATE INDEX google_custom_voice_sid_idx ON google_custom_voices (google_custom_voice_sid);
|
||||
CREATE INDEX speech_credential_sid_idx ON google_custom_voices (speech_credential_sid);
|
||||
ALTER TABLE google_custom_voices ADD FOREIGN KEY speech_credential_sid_idxfk (speech_credential_sid) REFERENCES speech_credentials (speech_credential_sid) ON DELETE CASCADE;
|
||||
|
||||
CREATE INDEX user_sid_idx ON users (user_sid);
|
||||
CREATE INDEX email_idx ON users (email);
|
||||
CREATE INDEX phone_idx ON users (phone);
|
||||
@@ -680,8 +628,6 @@ CREATE INDEX smpp_gateway_sid_idx ON smpp_gateways (smpp_gateway_sid);
|
||||
CREATE INDEX voip_carrier_sid_idx ON smpp_gateways (voip_carrier_sid);
|
||||
ALTER TABLE smpp_gateways ADD FOREIGN KEY voip_carrier_sid_idxfk (voip_carrier_sid) REFERENCES voip_carriers (voip_carrier_sid);
|
||||
|
||||
CREATE UNIQUE INDEX phone_numbers_unique_idx_voip_carrier_number ON phone_numbers (number,voip_carrier_sid);
|
||||
|
||||
CREATE INDEX phone_number_sid_idx ON phone_numbers (phone_number_sid);
|
||||
CREATE INDEX number_idx ON phone_numbers (number);
|
||||
CREATE INDEX voip_carrier_sid_idx ON phone_numbers (voip_carrier_sid);
|
||||
|
||||
412
db/jambones.sqs
412
db/jambones.sqs
@@ -87,7 +87,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[49E56AF4-4E40-49B6-BA88-4E378F1E6C18]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[13]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[11]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[0507BD46-ACAC-48A3-841E-4DEC2FEDCB72]]></uid>
|
||||
</SQLTable>
|
||||
@@ -148,7 +148,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[6E651E52-F91E-4086-9A1E-FB3425476B2F]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[23]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[21]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[0A95311F-47FA-429F-BAF9-1442C6EE0C0E]]></uid>
|
||||
</SQLTable>
|
||||
@@ -225,7 +225,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[D1019218-F1FC-4BC5-A890-F8DBB7153375]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[16]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[14]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[0AC2FD20-B22F-48DB-8611-801CEF6BFA12]]></uid>
|
||||
</SQLTable>
|
||||
@@ -279,7 +279,7 @@
|
||||
<uid><![CDATA[755D10B0-F60D-4250-8971-C8E4FDB0E0CD]]></uid>
|
||||
<unique><![CDATA[1]]></unique>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[20]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[18]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[16B9E383-E044-4D71-AB46-FEB86A46A298]]></uid>
|
||||
</SQLTable>
|
||||
@@ -316,7 +316,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[C4EEBFF0-C3CB-4897-8720-12D14DBA93A5]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[7]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[5]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[1A80FB9B-419E-483A-86FF-B44A00A44D7F]]></uid>
|
||||
</SQLTable>
|
||||
@@ -471,7 +471,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[601FA05B-78A5-4E7E-9983-39BB0E6D18EB]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[27]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[25]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[2A735FAB-592C-42E5-9C8B-06B109314799]]></uid>
|
||||
</SQLTable>
|
||||
@@ -537,7 +537,7 @@
|
||||
<indexed><![CDATA[1]]></indexed>
|
||||
<uid><![CDATA[365FB018-429D-4DA4-AC33-D9D106EA97E5]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[12]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[10]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[311D99B2-DC8B-4C4A-A1FC-4AFAA1F450F3]]></uid>
|
||||
</SQLTable>
|
||||
@@ -737,7 +737,7 @@
|
||||
<type><![CDATA[VARCHAR(4096)]]></type>
|
||||
<uid><![CDATA[7C7DFE92-D7AC-4447-A1C2-E0F10C1EA26A]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[28]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[26]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[A Carrier or customer PBX that can send or receive calls]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[3D3136A7-AFC0-4A70-AEC3-68577955CA2E]]></uid>
|
||||
@@ -819,7 +819,7 @@
|
||||
<defaultValue><![CDATA[CURRENT_TIMESTAMP]]></defaultValue>
|
||||
<uid><![CDATA[C84C9B6A-80B5-4B0B-8C14-EB02F7421BBE]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[37]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[35]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[An authorization token that is used to access the REST api]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[3EDF89A0-FD38-4DF9-BB65-E0FCD0A678BE]]></uid>
|
||||
@@ -872,7 +872,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[EA4C1A7E-68ED-41D5-9EE9-345DD61F00C7]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[9]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[7]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[4893A0F0-BE1B-4322-9034-644528E802DE]]></uid>
|
||||
</SQLTable>
|
||||
@@ -884,7 +884,7 @@
|
||||
<y>958.00</y>
|
||||
</location>
|
||||
<size>
|
||||
<width>302.00</width>
|
||||
<width>368.00</width>
|
||||
<height>280.00</height>
|
||||
</size>
|
||||
<zorder>14</zorder>
|
||||
@@ -892,7 +892,6 @@
|
||||
<name><![CDATA[speech_credential_sid]]></name>
|
||||
<type><![CDATA[CHAR(36)]]></type>
|
||||
<primaryKey>1</primaryKey>
|
||||
<forcedUnique><![CDATA[1]]></forcedUnique>
|
||||
<indexed><![CDATA[1]]></indexed>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[A5B51E8C-D4F3-4D7A-953D-B3082D87A226]]></uid>
|
||||
@@ -982,12 +981,25 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[8860648C-4790-4A01-9E2E-60DC52A287FA]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[label]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<uid><![CDATA[0D42A22C-DF14-42A1-BDE2-A53AC8B0D8D6]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[22]]></labelWindowIndex>
|
||||
<SQLIndex>
|
||||
<name><![CDATA[speech_credentials_idx_1]]></name>
|
||||
<fieldName><![CDATA[vendor]]></fieldName>
|
||||
<fieldName><![CDATA[account_sid]]></fieldName>
|
||||
<SQLIndexEntry>
|
||||
<name><![CDATA[vendor]]></name>
|
||||
<prefixSize><![CDATA[]]></prefixSize>
|
||||
<fieldUid><![CDATA[9D8FCF55-D68E-44D3-90DF-27B5ABD1D0BE]]></fieldUid>
|
||||
</SQLIndexEntry>
|
||||
<SQLIndexEntry>
|
||||
<name><![CDATA[account_sid]]></name>
|
||||
<prefixSize><![CDATA[]]></prefixSize>
|
||||
<fieldUid><![CDATA[7E964ED2-EC2E-4BCB-8DEC-C455B87FAC07]]></fieldUid>
|
||||
</SQLIndexEntry>
|
||||
<indexNamePrefix><![CDATA[speech_credentials]]></indexNamePrefix>
|
||||
<indexType><![CDATA[UNIQUE]]></indexType>
|
||||
<uid><![CDATA[554ABEC2-3E1B-41B1-BF07-25F403D5E3B4]]></uid>
|
||||
</SQLIndex>
|
||||
<labelWindowIndex><![CDATA[20]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[49A68E1C-DEE2-446C-A4EB-9850E16155CC]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1008,7 +1020,7 @@
|
||||
<type><![CDATA[VARCHAR(16)]]></type>
|
||||
<uid><![CDATA[1EA572BD-FF6B-43CC-9EBB-33A735781429]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[10]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[8]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[518AC592-D3E6-4032-8A33-15A3DB72B060]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1069,7 +1081,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[6B2F726C-48A6-49D9-B7B1-8850DD6FB3EC]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[15]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[13]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[51A02EFE-AA51-46EF-8671-E8B2F1FC5F8D]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1121,7 +1133,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[2EA3A57F-7EF7-4958-B06B-62B0279BB87E]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[8]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[6]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[5784AC2F-BEBC-466F-9818-F9A7D227A5B5]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1171,7 +1183,7 @@
|
||||
<type><![CDATA[VARCHAR(255)]]></type>
|
||||
<uid><![CDATA[04BB457A-D532-4780-8A58-5900094171EC]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[29]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[27]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[An HTTP callback]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[64D64CB9-0990-4C68-BE71-F9FD43C2BE19]]></uid>
|
||||
@@ -1271,7 +1283,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[9A75A20B-1EFD-4E16-994A-5376C650EAB5]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[11]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[9]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[6511AF7D-91FD-40C7-9F73-B8E9E66DC249]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1340,7 +1352,7 @@
|
||||
<uid><![CDATA[9B4208B5-9E3B-4B76-B7F7-4E5D36B99BF2]]></uid>
|
||||
<unsigned><![CDATA[0]]></unsigned>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[36]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[34]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[a regex-based pattern match for call routing]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[78584D93-2CD7-4495-9C5E-893C7B869133]]></uid>
|
||||
@@ -1377,7 +1389,7 @@
|
||||
<noQuoteDefault><![CDATA[1]]></noQuoteDefault>
|
||||
<uid><![CDATA[4D2F7B02-F183-4239-8CE8-3E98206708AE]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[14]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[12]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[86FAB0AB-DC68-4ADF-8A08-BBAF61BA1840]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1415,7 +1427,7 @@
|
||||
<type><![CDATA[VARCHAR(255)]]></type>
|
||||
<uid><![CDATA[673137EA-B74C-4BA7-AD25-1B71360A2E26]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[6]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[4]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[87F254ED-D381-48E3-8E8F-C0F3D99CC01C]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1447,7 +1459,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[8998AAD6-A21C-4697-9660-8DC5005AED07]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[5]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[3]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[8E75DB2D-9078-40E6-88BF-7DDED5033362]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1524,7 +1536,7 @@
|
||||
<uid><![CDATA[1DDAD1A1-942D-4487-89C8-D496B7F82274]]></uid>
|
||||
<unique><![CDATA[1]]></unique>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[26]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[24]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[A Microsoft Teams customer tenant]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[92FD042A-5AEC-4D8F-AB94-C73C0F566F75]]></uid>
|
||||
@@ -1595,7 +1607,7 @@
|
||||
<objectComment><![CDATA[lower priority carriers are attempted first]]></objectComment>
|
||||
<uid><![CDATA[01F61C68-799B-49B0-9E6A-0E2162EE5A54]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[32]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[30]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[An entry in the LCR routing list]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[956025F5-0798-47F7-B76C-457814C7B52E]]></uid>
|
||||
@@ -1610,7 +1622,7 @@
|
||||
</location>
|
||||
<size>
|
||||
<width>318.00</width>
|
||||
<height>500.00</height>
|
||||
<height>440.00</height>
|
||||
</size>
|
||||
<zorder>4</zorder>
|
||||
<SQLField>
|
||||
@@ -1788,28 +1800,7 @@
|
||||
<referencesTableUID><![CDATA[E97EE4F0-7ED7-4E8C-862E-D98192D6EAE0]]></referencesTableUID>
|
||||
<uid><![CDATA[4B8283B4-5E16-4846-A79D-12C6B2E73C86]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[record_all_calls]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[false]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[F4154533-AE5B-48FE-9435-A37FA2632752]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[record_format]]></name>
|
||||
<type><![CDATA[VARCHAR(16)]]></type>
|
||||
<defaultValue><![CDATA[mp3]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[F03BFF28-69EA-4555-9E5E-B0CA7B095408]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[bucket_credential]]></name>
|
||||
<type><![CDATA[VARCHAR(8192)]]></type>
|
||||
<forcedUnique><![CDATA[0]]></forcedUnique>
|
||||
<objectComment><![CDATA[credential used to authenticate with storage service]]></objectComment>
|
||||
<uid><![CDATA[E81859C0-DCBD-4FF3-BEEF-FA575394326B]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[34]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[32]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[An enterprise that uses the platform for comm services]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[985D6997-B1A7-4AB3-80F4-4D59B45480C8]]></uid>
|
||||
@@ -1848,7 +1839,7 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[D0BF7D36-E40C-4385-9BA5-2099B49A1042]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[21]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[19]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[A8ED2178-3CC4-4174-A8FC-C2B58FD28214]]></uid>
|
||||
</SQLTable>
|
||||
@@ -1940,7 +1931,7 @@
|
||||
<type><![CDATA[VARCHAR(32)]]></type>
|
||||
<uid><![CDATA[CE2015BC-8538-4FB0-B4D9-454436FAB1D9]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[17]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[15]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[AF34726D-EDFD-414E-9B44-5243DA9D9497]]></uid>
|
||||
</SQLTable>
|
||||
@@ -2010,7 +2001,7 @@
|
||||
<indexed><![CDATA[1]]></indexed>
|
||||
<uid><![CDATA[EA936343-89D3-4E3F-BD92-9F8967DC27C4]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[4]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[2]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[An LCR (least cost routing) table that is used by a service provider or account to make decisions about routing outbound calls when multiple carriers are available.]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[AFD51FD4-44C8-4442-94C2-0DFA93CD48AE]]></uid>
|
||||
@@ -2019,8 +2010,8 @@
|
||||
<name><![CDATA[dns_records]]></name>
|
||||
<schema><![CDATA[]]></schema>
|
||||
<location>
|
||||
<x>1270.00</x>
|
||||
<y>1425.00</y>
|
||||
<x>960.00</x>
|
||||
<y>1155.00</y>
|
||||
</location>
|
||||
<size>
|
||||
<width>262.00</width>
|
||||
@@ -2062,72 +2053,10 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[73092A7A-9F3F-4C49-8478-39CE5DAF5ADD]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[19]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[17]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[B10C0DE3-03CD-4C5A-B1FB-F9F81ED14A40]]></uid>
|
||||
</SQLTable>
|
||||
<SQLTable>
|
||||
<name><![CDATA[google_custom_voices]]></name>
|
||||
<schema><![CDATA[]]></schema>
|
||||
<location>
|
||||
<x>1803.00</x>
|
||||
<y>1036.00</y>
|
||||
</location>
|
||||
<size>
|
||||
<width>521.00</width>
|
||||
<height>120.00</height>
|
||||
</size>
|
||||
<zorder>37</zorder>
|
||||
<SQLField>
|
||||
<name><![CDATA[google_custom_voice_sid]]></name>
|
||||
<type><![CDATA[CHAR(36)]]></type>
|
||||
<primaryKey>1</primaryKey>
|
||||
<indexed><![CDATA[1]]></indexed>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[D246DAFE-98AB-4DC6-A384-1DFE8E40573D]]></uid>
|
||||
<unique><![CDATA[1]]></unique>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[speech_credential_sid]]></name>
|
||||
<type><![CDATA[CHAR(36)]]></type>
|
||||
<referencesField>speech_credential_sid</referencesField>
|
||||
<referencesTable>speech_credentials</referencesTable>
|
||||
<deleteAction>1</deleteAction>
|
||||
<referencesField><![CDATA[speech_credential_sid]]></referencesField>
|
||||
<referencesTable><![CDATA[speech_credentials]]></referencesTable>
|
||||
<sourceCardinality>4</sourceCardinality>
|
||||
<destinationCardinality>1</destinationCardinality>
|
||||
<referencesFieldUID><![CDATA[A5B51E8C-D4F3-4D7A-953D-B3082D87A226]]></referencesFieldUID>
|
||||
<referencesTableUID><![CDATA[49A68E1C-DEE2-446C-A4EB-9850E16155CC]]></referencesTableUID>
|
||||
<forcedUnique><![CDATA[0]]></forcedUnique>
|
||||
<indexed><![CDATA[1]]></indexed>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[AB763F3E-8E49-46EE-BE99-5ED02A688E93]]></uid>
|
||||
<unique><![CDATA[0]]></unique>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[model]]></name>
|
||||
<type><![CDATA[VARCHAR(512)]]></type>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[CB4E2A6B-7C59-4C8F-B5F5-5F27200B971F]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[reported_usage]]></name>
|
||||
<type><![CDATA[ENUM('REPORTED_USAGE_UNSPECIFIED','REALTIME','OFFLINE')]]></type>
|
||||
<defaultValue><![CDATA[REALTIME]]></defaultValue>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[A17005D7-81E3-4E12-91EB-6DB23DEAA618]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[name]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[D22EED9A-3502-489E-BE0A-5609B76697A8]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[1]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[B83321B9-0B89-4E5F-95D4-864ADE2EC405]]></uid>
|
||||
</SQLTable>
|
||||
<SQLTable>
|
||||
<name><![CDATA[phone_numbers]]></name>
|
||||
<schema><![CDATA[]]></schema>
|
||||
@@ -2137,8 +2066,8 @@
|
||||
<y>1128.00</y>
|
||||
</location>
|
||||
<size>
|
||||
<width>522.00</width>
|
||||
<height>160.00</height>
|
||||
<width>265.00</width>
|
||||
<height>140.00</height>
|
||||
</size>
|
||||
<zorder>2</zorder>
|
||||
<SQLField>
|
||||
@@ -2158,7 +2087,7 @@
|
||||
<indexed><![CDATA[1]]></indexed>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[159B82ED-C6B0-4FC6-957B-5C354AF9E783]]></uid>
|
||||
<unique><![CDATA[0]]></unique>
|
||||
<unique><![CDATA[1]]></unique>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[voip_carrier_sid]]></name>
|
||||
@@ -2220,108 +2149,11 @@
|
||||
<objectComment><![CDATA[if not null, this number is a test number for the associated service provider]]></objectComment>
|
||||
<uid><![CDATA[D2D46B75-F9C7-42A5-8D8C-4A8412C75ECA]]></uid>
|
||||
</SQLField>
|
||||
<SQLIndex>
|
||||
<name><![CDATA[phone_numbers_unique_idx_voip_carrier_number]]></name>
|
||||
<fieldName><![CDATA[number]]></fieldName>
|
||||
<fieldName><![CDATA[voip_carrier_sid]]></fieldName>
|
||||
<SQLIndexEntry>
|
||||
<name><![CDATA[number]]></name>
|
||||
<prefixSize><![CDATA[]]></prefixSize>
|
||||
<fieldUid><![CDATA[159B82ED-C6B0-4FC6-957B-5C354AF9E783]]></fieldUid>
|
||||
</SQLIndexEntry>
|
||||
<SQLIndexEntry>
|
||||
<name><![CDATA[voip_carrier_sid]]></name>
|
||||
<prefixSize><![CDATA[]]></prefixSize>
|
||||
<fieldUid><![CDATA[58A047B9-C1C9-4697-9FE8-08E3BFF91660]]></fieldUid>
|
||||
</SQLIndexEntry>
|
||||
<indexNamePrefix><![CDATA[phone_numbers]]></indexNamePrefix>
|
||||
<indexType><![CDATA[UNIQUE]]></indexType>
|
||||
<uid><![CDATA[4E84523A-7F30-4A5D-A0A8-578652102BD0]]></uid>
|
||||
</SQLIndex>
|
||||
<labelWindowIndex><![CDATA[35]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[33]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[A phone number that has been assigned to an account]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[BA650DDC-AC7B-4DFE-A5E5-828C75607807]]></uid>
|
||||
</SQLTable>
|
||||
<SQLTable>
|
||||
<name><![CDATA[clients]]></name>
|
||||
<schema><![CDATA[]]></schema>
|
||||
<location>
|
||||
<x>974.00</x>
|
||||
<y>1496.00</y>
|
||||
</location>
|
||||
<size>
|
||||
<width>282.00</width>
|
||||
<height>180.00</height>
|
||||
</size>
|
||||
<zorder>36</zorder>
|
||||
<SQLField>
|
||||
<name><![CDATA[client_sid]]></name>
|
||||
<type><![CDATA[CHAR(36)]]></type>
|
||||
<primaryKey>1</primaryKey>
|
||||
<indexed><![CDATA[1]]></indexed>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[0CD7B8BF-0C4C-49CC-8A9B-27E03C70255D]]></uid>
|
||||
<unique><![CDATA[1]]></unique>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[account_sid]]></name>
|
||||
<type><![CDATA[CHAR(36)]]></type>
|
||||
<referencesField>account_sid</referencesField>
|
||||
<referencesTable>accounts</referencesTable>
|
||||
<referencesField><![CDATA[account_sid]]></referencesField>
|
||||
<referencesTable><![CDATA[accounts]]></referencesTable>
|
||||
<sourceCardinality>4</sourceCardinality>
|
||||
<destinationCardinality>1</destinationCardinality>
|
||||
<referencesFieldUID><![CDATA[1342FAFA-C15C-429B-809B-C6C55F9FA5B6]]></referencesFieldUID>
|
||||
<referencesTableUID><![CDATA[985D6997-B1A7-4AB3-80F4-4D59B45480C8]]></referencesTableUID>
|
||||
<foreignKeyName><![CDATA[account_sid_idxfk_13]]></foreignKeyName>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[AEB7E64F-A890-483D-946E-B0EFC640B017]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[is_active]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[1]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[EEE9DF14-8CA6-40BA-9737-C37D702FCB92]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[username]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<uid><![CDATA[9F6D877B-3985-4DF0-9E42-41FF87140C05]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[password]]></name>
|
||||
<type><![CDATA[VARCHAR(1024)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[2963DB28-7248-4D58-92E6-F21F2EB9E680]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[allow_direct_app_calling]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[1]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[EA252940-708B-4BD3-B211-5EC59AA540D3]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[allow_direct_queue_calling]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[1]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[76CE0DFC-7CC6-46EE-82C6-2CF16C7EAD4D]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[allow_direct_user_calling]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[1]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[206E169C-E5F6-4774-8D4A-5BECF25E49A3]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[2]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[C2CDB45C-3F50-40B3-B8CE-2F093EB0D517]]></uid>
|
||||
</SQLTable>
|
||||
<SQLTable>
|
||||
<name><![CDATA[sip_gateways]]></name>
|
||||
<schema><![CDATA[]]></schema>
|
||||
@@ -2332,7 +2164,7 @@
|
||||
</location>
|
||||
<size>
|
||||
<width>281.00</width>
|
||||
<height>280.00</height>
|
||||
<height>220.00</height>
|
||||
</size>
|
||||
<zorder>7</zorder>
|
||||
<SQLField>
|
||||
@@ -2358,7 +2190,8 @@
|
||||
<SQLField>
|
||||
<name><![CDATA[port]]></name>
|
||||
<type><![CDATA[INTEGER]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<defaultValue><![CDATA[5060]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<objectComment><![CDATA[sip signaling port]]></objectComment>
|
||||
<uid><![CDATA[26B20F1E-4DB0-48C0-90F7-CA90A06A1070]]></uid>
|
||||
</SQLField>
|
||||
@@ -2399,28 +2232,6 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[27D4A5BD-8093-4ADD-B5B5-D546844206F9]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[send_options_ping]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[0]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[E04C19A2-12BF-443F-AB61-96990224A18D]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[use_sips_scheme]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[0]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[5DCBDD48-913B-4580-B78C-9B06C939FEA8]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[pad_crypto]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[0]]></defaultValue>
|
||||
<forcedUnique><![CDATA[0]]></forcedUnique>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[C5C0043B-100A-4476-BF01-BE0777AE27C0]]></uid>
|
||||
</SQLField>
|
||||
<SQLIndex>
|
||||
<name><![CDATA[sip_gateway_idx_hostport]]></name>
|
||||
<fieldName><![CDATA[ipv4]]></fieldName>
|
||||
@@ -2445,7 +2256,7 @@
|
||||
<objectComment><![CDATA[Outbound call protocol]]></objectComment>
|
||||
<uid><![CDATA[30661D66-96EC-4B02-995C-5E7EB8A3BD70]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[31]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[29]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[A whitelisted sip gateway used for origination/termination]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[D8A564E2-DA41-4217-8ACE-06CF77E9BEC1]]></uid>
|
||||
@@ -2455,12 +2266,12 @@
|
||||
<schema><![CDATA[]]></schema>
|
||||
<comment><![CDATA[A defined set of behaviors to be applied to phone calls ]]></comment>
|
||||
<location>
|
||||
<x>840.00</x>
|
||||
<y>917.00</y>
|
||||
<x>841.00</x>
|
||||
<y>824.00</y>
|
||||
</location>
|
||||
<size>
|
||||
<width>345.00</width>
|
||||
<height>540.00</height>
|
||||
<height>320.00</height>
|
||||
</size>
|
||||
<zorder>0</zorder>
|
||||
<SQLField>
|
||||
@@ -2575,15 +2386,9 @@
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[speech_synthesis_voice]]></name>
|
||||
<type><![CDATA[VARCHAR(256)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[929D66F0-64B9-4D7C-AB4B-24F131E1178F]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[speech_synthesis_label]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[BFA24DF2-9CF5-47B0-848D-8B685B7C6750]]></uid>
|
||||
<uid><![CDATA[929D66F0-64B9-4D7C-AB4B-24F131E1178F]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[speech_recognizer_vendor]]></name>
|
||||
@@ -2599,76 +2404,14 @@
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[A03AFB7B-492F-48E3-AE3C-B1416D5B6B12]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[speech_recognizer_label]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[A247A784-CCD6-40B4-9D0A-2F0EF8F8AFD2]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[use_for_fallback_speech]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[false]]></defaultValue>
|
||||
<uid><![CDATA[DDA48DD6-4B0F-4AD5-9B32-D508BBA1A8EE]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[fallback_speech_synthesis_vendor]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[26BBDEEF-E179-4280-9917-6F2BD6367459]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[fallback_speech_synthesis_language]]></name>
|
||||
<type><![CDATA[VARCHAR(12)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[E008D6D7-9BB7-4372-8B46-F92C0EB15082]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[fallback_speech_synthesis_voice]]></name>
|
||||
<type><![CDATA[VARCHAR(256)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[6A0E92C9-32B9-4179-A893-3DADF5DD7728]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[fallback_speech_synthesis_label]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[8576DEF6-D81A-4D4D-8980-00580779D164]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[fallback_speech_recognizer_vendor]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[14ECF5EA-81C5-4EAE-9575-9785CEB672E6]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[fallback_speech_recognizer_language]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[EC792500-6B2B-4E54-AA89-43E7A0FD8642]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[fallback_speech_recognizer_label]]></name>
|
||||
<type><![CDATA[VARCHAR(64)]]></type>
|
||||
<notNull><![CDATA[0]]></notNull>
|
||||
<uid><![CDATA[65AA5173-6523-49F7-9D95-78C4B3A7C7E6]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[created_at]]></name>
|
||||
<type><![CDATA[DATETIME]]></type>
|
||||
<defaultValue><![CDATA[CURRENT_TIMESTAMP]]></defaultValue>
|
||||
<forcedUnique><![CDATA[0]]></forcedUnique>
|
||||
<noQuoteDefault><![CDATA[1]]></noQuoteDefault>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[C09B1BDB-8390-4B8A-B70A-642EC5E12899]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[record_all_calls]]></name>
|
||||
<type><![CDATA[BOOLEAN]]></type>
|
||||
<defaultValue><![CDATA[false]]></defaultValue>
|
||||
<notNull><![CDATA[1]]></notNull>
|
||||
<uid><![CDATA[0AAA3997-9E40-47CC-976D-5EC1B82AD290]]></uid>
|
||||
</SQLField>
|
||||
<SQLIndex>
|
||||
<name><![CDATA[applications_idx_name]]></name>
|
||||
<fieldName><![CDATA[account_sid]]></fieldName>
|
||||
@@ -2687,7 +2430,7 @@
|
||||
<indexType><![CDATA[UNIQUE]]></indexType>
|
||||
<uid><![CDATA[3FDDDF3B-375D-4DE4-B759-514438845F7D]]></uid>
|
||||
</SQLIndex>
|
||||
<labelWindowIndex><![CDATA[33]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[31]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[A defined set of behaviors to be applied to phone calls ]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[E97EE4F0-7ED7-4E8C-862E-D98192D6EAE0]]></uid>
|
||||
@@ -2795,7 +2538,7 @@
|
||||
<type><![CDATA[VARBINARY(52)]]></type>
|
||||
<uid><![CDATA[B4793720-635C-4E25-A306-62E7416541C4]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[18]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[16]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[EB4BC5F9-CC10-4C8C-AB31-6D942256AEFB]]></uid>
|
||||
</SQLTable>
|
||||
@@ -2808,7 +2551,7 @@
|
||||
</location>
|
||||
<size>
|
||||
<width>266.00</width>
|
||||
<height>100.00</height>
|
||||
<height>80.00</height>
|
||||
</size>
|
||||
<zorder>35</zorder>
|
||||
<SQLField>
|
||||
@@ -2826,12 +2569,7 @@
|
||||
<type><![CDATA[VARCHAR(255)]]></type>
|
||||
<uid><![CDATA[0A8DB34E-76C9-4D40-9E31-786E0228DCEE]]></uid>
|
||||
</SQLField>
|
||||
<SQLField>
|
||||
<name><![CDATA[private_network_cidr]]></name>
|
||||
<type><![CDATA[VARCHAR(8192)]]></type>
|
||||
<uid><![CDATA[45A2CE92-0BA7-4156-AE05-750D63F386F3]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[3]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[1]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[F0C2DC80-CBA7-4BE7-8856-D10B062A7B17]]></uid>
|
||||
</SQLTable>
|
||||
@@ -2916,7 +2654,7 @@
|
||||
<type><![CDATA[DATETIME]]></type>
|
||||
<uid><![CDATA[CD43B91B-F34E-4422-9C0F-A4B92E2E7B95]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[25]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[23]]></labelWindowIndex>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[F0EE651E-DBF6-4CAC-A517-AC85BCC2D3AF]]></uid>
|
||||
</SQLTable>
|
||||
@@ -2976,7 +2714,7 @@
|
||||
<uid><![CDATA[B73773BA-AB1B-47AA-B995-2D2FE006198F]]></uid>
|
||||
<unique><![CDATA[0]]></unique>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[30]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[28]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[An ordered list of digit patterns in an LCR table. The patterns are tested in sequence until one matches]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[F283D572-F670-4571-91FD-A665A9D3E15D]]></uid>
|
||||
@@ -3043,7 +2781,7 @@
|
||||
<type><![CDATA[VARCHAR(255)]]></type>
|
||||
<uid><![CDATA[FA39B463-61C7-4654-BE9C-D1AC39AB1B97]]></uid>
|
||||
</SQLField>
|
||||
<labelWindowIndex><![CDATA[24]]></labelWindowIndex>
|
||||
<labelWindowIndex><![CDATA[22]]></labelWindowIndex>
|
||||
<objectComment><![CDATA[A partition of the platform used by one service provider]]></objectComment>
|
||||
<ui.treeExpanded><![CDATA[1]]></ui.treeExpanded>
|
||||
<uid><![CDATA[F294B51E-F867-47CA-BC1F-F70BDF8170FF]]></uid>
|
||||
@@ -3117,17 +2855,17 @@
|
||||
<overviewPanelHidden><![CDATA[0]]></overviewPanelHidden>
|
||||
<pageBoundariesVisible><![CDATA[0]]></pageBoundariesVisible>
|
||||
<PageGridVisible><![CDATA[0]]></PageGridVisible>
|
||||
<RightSidebarWidth><![CDATA[1235.000000]]></RightSidebarWidth>
|
||||
<RightSidebarWidth><![CDATA[1873.000000]]></RightSidebarWidth>
|
||||
<sidebarIndex><![CDATA[2]]></sidebarIndex>
|
||||
<snapToGrid><![CDATA[0]]></snapToGrid>
|
||||
<SourceSidebarWidth><![CDATA[0.000000]]></SourceSidebarWidth>
|
||||
<SourceSidebarWidth><![CDATA[312.000000]]></SourceSidebarWidth>
|
||||
<SQLEditorFileFormatVersion><![CDATA[4]]></SQLEditorFileFormatVersion>
|
||||
<uid><![CDATA[58C99A00-06C9-478C-A667-C63842E088F3]]></uid>
|
||||
<windowHeight><![CDATA[873.000000]]></windowHeight>
|
||||
<windowLocationX><![CDATA[0.000000]]></windowLocationX>
|
||||
<windowLocationY><![CDATA[71.000000]]></windowLocationY>
|
||||
<windowScrollOrigin><![CDATA[{1674.5, 0}]]></windowScrollOrigin>
|
||||
<windowWidth><![CDATA[1512.000000]]></windowWidth>
|
||||
<windowHeight><![CDATA[1055.000000]]></windowHeight>
|
||||
<windowLocationX><![CDATA[1728.000000]]></windowLocationX>
|
||||
<windowLocationY><![CDATA[37.000000]]></windowLocationY>
|
||||
<windowScrollOrigin><![CDATA[{0, 0}]]></windowScrollOrigin>
|
||||
<windowWidth><![CDATA[1874.000000]]></windowWidth>
|
||||
</SQLDocumentInfo>
|
||||
<AllowsIndexRenamingOnInsert><![CDATA[1]]></AllowsIndexRenamingOnInsert>
|
||||
<defaultLabelExpanded><![CDATA[1]]></defaultLabelExpanded>
|
||||
|
||||
@@ -22,7 +22,7 @@ values ('3f35518f-5a0d-4c2e-90a5-2407bb3b36f0', '38700987-c7a4-4685-a5bb-af378f9
|
||||
|
||||
-- create one service provider and one account
|
||||
insert into service_providers (service_provider_sid, name, root_domain)
|
||||
values ('2708b1b3-2736-40ea-b502-c53d8396247f', 'default service provider', 'sip.jambonz.cloud');
|
||||
values ('2708b1b3-2736-40ea-b502-c53d8396247f', 'default service provider', 'sip.jambonz.us');
|
||||
|
||||
insert into accounts (account_sid, service_provider_sid, name, webhook_secret)
|
||||
values ('9351f46a-678c-43f5-b8a6-d4eb58d131af','2708b1b3-2736-40ea-b502-c53d8396247f', 'default account', 'wh_secret_cJqgtMDPzDhhnjmaJH6Mtk');
|
||||
@@ -38,9 +38,9 @@ values ('3f35518f-5a0d-4c2e-90a5-2407bb3b36fs', '38700987-c7a4-4685-a5bb-af378f9
|
||||
-- create two applications
|
||||
insert into webhooks(webhook_sid, url, method)
|
||||
values
|
||||
('84e3db00-b172-4e46-b54b-a503fdb19e4a', 'https://public-apps.jambonz.cloud/call-status', 'POST'),
|
||||
('d31568d0-b193-4a05-8ff6-778369bc6efe', 'https://public-apps.jambonz.cloud/hello-world', 'POST'),
|
||||
('81844b05-714d-4295-8bf3-3b0640a4bf02', 'https://public-apps.jambonz.cloud/dial-time', 'POST');
|
||||
('84e3db00-b172-4e46-b54b-a503fdb19e4a', 'https://public-apps.jambonz.us/call-status', 'POST'),
|
||||
('d31568d0-b193-4a05-8ff6-778369bc6efe', 'https://public-apps.jambonz.us/hello-world', 'POST'),
|
||||
('81844b05-714d-4295-8bf3-3b0640a4bf02', 'https://public-apps.jambonz.us/dial-time', 'POST');
|
||||
|
||||
insert into applications (application_sid, account_sid, name, call_hook_sid, call_status_hook_sid, speech_synthesis_vendor, speech_synthesis_language, speech_synthesis_voice, speech_recognizer_vendor, speech_recognizer_language)
|
||||
VALUES
|
||||
|
||||
@@ -24,9 +24,10 @@ values ('09e92f3c-9d73-4303-b63f-3668574862ce', '1cf2f4f4-64c4-4249-9a3e-5bb4cb5
|
||||
-- create two applications
|
||||
insert into webhooks(webhook_sid, url, method)
|
||||
values
|
||||
('84e3db00-b172-4e46-b54b-a503fdb19e4a', 'https://public-apps.jambonz.cloud/call-status', 'POST'),
|
||||
('d31568d0-b193-4a05-8ff6-778369bc6efe', 'https://public-apps.jambonz.cloud/hello-world', 'POST'),
|
||||
('81844b05-714d-4295-8bf3-3b0640a4bf02', 'https://public-apps.jambonz.cloud/dial-time', 'POST');
|
||||
('84e3db00-b172-4e46-b54b-a503fdb19e4a', 'https://public-apps.jambonz.us/call-status', 'POST'),
|
||||
('d31568d0-b193-4a05-8ff6-778369bc6efe', 'https://public-apps.jambonz.us/hello-world', 'POST'),
|
||||
('81844b05-714d-4295-8bf3-3b0640a4bf02', 'https://public-apps.jambonz.us/dial-time', 'POST');
|
||||
|
||||
insert into applications (application_sid, account_sid, name, call_hook_sid, call_status_hook_sid, speech_synthesis_vendor, speech_synthesis_language, speech_synthesis_voice, speech_recognizer_vendor, speech_recognizer_language)
|
||||
VALUES
|
||||
('7087fe50-8acb-4f3b-b820-97b573723aab', '9351f46a-678c-43f5-b8a6-d4eb58d131af', 'hello world', 'd31568d0-b193-4a05-8ff6-778369bc6efe', '84e3db00-b172-4e46-b54b-a503fdb19e4a', 'google', 'en-US', 'en-US-Wavenet-C', 'google', 'en-US'),
|
||||
@@ -67,6 +68,9 @@ VALUES
|
||||
('d2ccfcb1-9198-4fe9-a0ca-6e49395837c4', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '54.172.60.0', 30, 5060, 1, 0),
|
||||
('6b1d0032-4430-41f1-87c6-f22233d394ef', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '54.244.51.0', 30, 5060, 1, 0),
|
||||
('0de40217-8bd5-4aa8-a9fd-1994282953c6', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '54.171.127.192', 30, 5060, 1, 0),
|
||||
('48b108e3-1ce7-4f18-a4cb-e41e63688bdf', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '54.171.127.193', 30, 5060, 1, 0),
|
||||
('d9131a69-fe44-4c2a-ba82-4adc81f628dd', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '54.171.127.194', 30, 5060, 1, 0),
|
||||
('34a6a311-4bd6-49ca-aa77-edd3cb92c6e1', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '54.171.127.195', 30, 5060, 1, 0),
|
||||
('37bc0b20-b53c-4c31-95a6-f82b1c3713e3', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '35.156.191.128', 30, 5060, 1, 0),
|
||||
('39791f4e-b612-4882-a37e-e92711a39f3f', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '54.65.63.192', 30, 5060, 1, 0),
|
||||
('81a0c8cb-a33e-42da-8f20-99083da6f02f', '7d509a18-bbff-4c5d-b21e-b99bf8f8c49a', '54.252.254.64', 30, 5060, 1, 0),
|
||||
|
||||
@@ -88,7 +88,7 @@ const sql = {
|
||||
'ALTER TABLE user_permissions ADD FOREIGN KEY permission_sid_idxfk (permission_sid) REFERENCES permissions (permission_sid)',
|
||||
'ALTER TABLE `users` ADD COLUMN `is_active` BOOLEAN NOT NULL default true',
|
||||
],
|
||||
'8003': [
|
||||
8003: [
|
||||
'SET FOREIGN_KEY_CHECKS=0',
|
||||
'ALTER TABLE `voip_carriers` ADD COLUMN `register_status` VARCHAR(4096)',
|
||||
'ALTER TABLE `sbc_addresses` ADD COLUMN `last_updated` DATETIME',
|
||||
@@ -138,68 +138,6 @@ const sql = {
|
||||
'CREATE INDEX account_sid_idx ON lcr (account_sid)',
|
||||
'ALTER TABLE lcr_carrier_set_entry ADD FOREIGN KEY lcr_route_sid_idxfk (lcr_route_sid) REFERENCES lcr_routes (lcr_route_sid)',
|
||||
'ALTER TABLE lcr_carrier_set_entry ADD FOREIGN KEY voip_carrier_sid_idxfk_3 (voip_carrier_sid) REFERENCES voip_carriers (voip_carrier_sid)',
|
||||
'SET FOREIGN_KEY_CHECKS=1',
|
||||
],
|
||||
'8004': [
|
||||
'alter table accounts add column record_all_calls BOOLEAN NOT NULL DEFAULT false',
|
||||
'alter table accounts add column bucket_credential VARCHAR(8192)',
|
||||
'alter table accounts add column record_format VARCHAR(16) NOT NULL DEFAULT \'mp3\'',
|
||||
'alter table applications add column record_all_calls BOOLEAN NOT NULL DEFAULT false',
|
||||
'alter table phone_numbers DROP INDEX number',
|
||||
'create unique index phone_numbers_unique_idx_voip_carrier_number ON phone_numbers (number,voip_carrier_sid)',
|
||||
`CREATE TABLE clients
|
||||
(
|
||||
client_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
account_sid CHAR(36) NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT 1,
|
||||
username VARCHAR(64),
|
||||
password VARCHAR(1024),
|
||||
PRIMARY KEY (client_sid)
|
||||
)`,
|
||||
'CREATE INDEX client_sid_idx ON clients (client_sid)',
|
||||
'ALTER TABLE clients ADD CONSTRAINT account_sid_idxfk_13 FOREIGN KEY account_sid_idxfk_13 (account_sid) REFERENCES accounts (account_sid)',
|
||||
'ALTER TABLE sip_gateways ADD COLUMN protocol ENUM(\'udp\',\'tcp\',\'tls\', \'tls/srtp\') DEFAULT \'udp\''
|
||||
],
|
||||
'8005': [
|
||||
'DROP INDEX speech_credentials_idx_1 ON speech_credentials',
|
||||
'ALTER TABLE speech_credentials ADD COLUMN label VARCHAR(64)',
|
||||
'ALTER TABLE applications ADD COLUMN speech_synthesis_label VARCHAR(64)',
|
||||
'ALTER TABLE applications ADD COLUMN speech_recognizer_label VARCHAR(64)',
|
||||
'ALTER TABLE applications ADD COLUMN use_for_fallback_speech BOOLEAN DEFAULT false',
|
||||
'ALTER TABLE applications ADD COLUMN fallback_speech_synthesis_vendor VARCHAR(64)',
|
||||
'ALTER TABLE applications ADD COLUMN fallback_speech_synthesis_language VARCHAR(12)',
|
||||
'ALTER TABLE applications ADD COLUMN fallback_speech_synthesis_voice VARCHAR(64)',
|
||||
'ALTER TABLE applications ADD COLUMN fallback_speech_synthesis_label VARCHAR(64)',
|
||||
'ALTER TABLE applications ADD COLUMN fallback_speech_recognizer_vendor VARCHAR(64)',
|
||||
'ALTER TABLE applications ADD COLUMN fallback_speech_recognizer_language VARCHAR(64)',
|
||||
'ALTER TABLE applications ADD COLUMN fallback_speech_recognizer_label VARCHAR(64)',
|
||||
'ALTER TABLE sip_gateways ADD COLUMN pad_crypto BOOLEAN NOT NULL DEFAULT 0',
|
||||
'ALTER TABLE sip_gateways MODIFY port INTEGER',
|
||||
`CREATE TABLE google_custom_voices
|
||||
(
|
||||
google_custom_voice_sid CHAR(36) NOT NULL UNIQUE ,
|
||||
speech_credential_sid CHAR(36) NOT NULL,
|
||||
model VARCHAR(512) NOT NULL,
|
||||
reported_usage ENUM('REPORTED_USAGE_UNSPECIFIED','REALTIME','OFFLINE') DEFAULT 'REALTIME',
|
||||
name VARCHAR(64) NOT NULL,
|
||||
PRIMARY KEY (google_custom_voice_sid)
|
||||
)
|
||||
`,
|
||||
'CREATE INDEX google_custom_voice_sid_idx ON google_custom_voices (google_custom_voice_sid)',
|
||||
'CREATE INDEX speech_credential_sid_idx ON google_custom_voices (speech_credential_sid)',
|
||||
'ALTER TABLE google_custom_voices ADD FOREIGN KEY speech_credential_sid_idxfk (speech_credential_sid) REFERENCES speech_credentials (speech_credential_sid) ON DELETE CASCADE',
|
||||
'ALTER TABLE clients ADD COLUMN allow_direct_queue_calling BOOLEAN NOT NULL DEFAULT 1',
|
||||
'ALTER TABLE clients ADD COLUMN allow_direct_user_calling BOOLEAN NOT NULL DEFAULT 1',
|
||||
'ALTER TABLE clients ADD COLUMN allow_direct_app_calling BOOLEAN NOT NULL DEFAULT 1',
|
||||
],
|
||||
9000: [
|
||||
'ALTER TABLE sip_gateways ADD COLUMN send_options_ping BOOLEAN NOT NULL DEFAULT 0',
|
||||
'ALTER TABLE applications MODIFY COLUMN speech_synthesis_voice VARCHAR(256)',
|
||||
'ALTER TABLE applications MODIFY COLUMN fallback_speech_synthesis_voice VARCHAR(256)',
|
||||
'ALTER TABLE sip_gateways ADD COLUMN use_sips_scheme BOOLEAN NOT NULL DEFAULT 0',
|
||||
],
|
||||
9002: [
|
||||
'ALTER TABLE system_information ADD COLUMN private_network_cidr VARCHAR(8192)',
|
||||
]
|
||||
};
|
||||
|
||||
@@ -230,10 +168,6 @@ const doIt = async() => {
|
||||
if (val < 7007) upgrades.push(...sql['7007']);
|
||||
if (val < 8000) upgrades.push(...sql['8000']);
|
||||
if (val < 8003) upgrades.push(...sql['8003']);
|
||||
if (val < 8004) upgrades.push(...sql['8004']);
|
||||
if (val < 8005) upgrades.push(...sql['8005']);
|
||||
if (val < 9000) upgrades.push(...sql['9000']);
|
||||
if (val < 9002) upgrades.push(...sql['9002']);
|
||||
|
||||
// perform all upgrades
|
||||
logger.info({upgrades}, 'applying schema upgrades..');
|
||||
|
||||
@@ -2,7 +2,7 @@ SET FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
-- create one service provider
|
||||
insert into service_providers (service_provider_sid, name, description, root_domain)
|
||||
values ('2708b1b3-2736-40ea-b502-c53d8396247f', 'jambonz.cloud', 'jambonz.cloud service provider', 'sip.yakeeda.com');
|
||||
values ('2708b1b3-2736-40ea-b502-c53d8396247f', 'jambonz.us', 'jambonz.us service provider', 'sip.yakeeda.com');
|
||||
insert into api_keys (api_key_sid, token)
|
||||
values ('3f35518f-5a0d-4c2e-90a5-2407bb3b36f0', '38700987-c7a4-4685-a5bb-af378f9734de');
|
||||
|
||||
@@ -19,8 +19,8 @@ insert into sip_gateways (sip_gateway_sid, voip_carrier_sid, ipv4, port, inbound
|
||||
values ('46b727eb-c7dc-44fa-b063-96e48d408e4a', '5145b436-2f38-4029-8d4c-fd8c67831c7a', '3.3.3.3', 5060, 1, 1, 1);
|
||||
|
||||
-- create the test application and test phone number
|
||||
insert into webhooks (webhook_sid, url, method) values ('d9c205c6-a129-443e-a9c0-d1bb437d4bb7', 'https://flows.jambonz.cloud/testCall', 'POST');
|
||||
insert into webhooks (webhook_sid, url, method) values ('6ac36aeb-6bd0-428a-80a1-aed95640a296', 'https://flows.jambonz.cloud/callStatus', 'POST');
|
||||
insert into webhooks (webhook_sid, url, method) values ('d9c205c6-a129-443e-a9c0-d1bb437d4bb7', 'https://flows.jambonz.us/testCall', 'POST');
|
||||
insert into webhooks (webhook_sid, url, method) values ('6ac36aeb-6bd0-428a-80a1-aed95640a296', 'https://flows.jambonz.us/callStatus', 'POST');
|
||||
insert into applications (application_sid, name, service_provider_sid, call_hook_sid, call_status_hook_sid,
|
||||
speech_synthesis_vendor, speech_synthesis_language, speech_synthesis_voice, speech_recognizer_vendor, speech_recognizer_language)
|
||||
values ('7a489343-02ed-471e-8df0-fc5e1b98ce8f', 'Test application', '2708b1b3-2736-40ea-b502-c53d8396247f',
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
const logger = require('../logger');
|
||||
|
||||
const {
|
||||
client,
|
||||
retrieveCall,
|
||||
deleteCall,
|
||||
listCalls,
|
||||
listSortedSets,
|
||||
listQueues,
|
||||
purgeCalls,
|
||||
retrieveSet,
|
||||
addKey,
|
||||
@@ -13,21 +12,21 @@ const {
|
||||
deleteKey,
|
||||
incrKey,
|
||||
client: redisClient,
|
||||
listConferences
|
||||
} = require('@jambonz/realtimedb-helpers')({}, logger);
|
||||
} = require('@jambonz/realtimedb-helpers')({
|
||||
host: process.env.JAMBONES_REDIS_HOST || 'localhost',
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
}, logger);
|
||||
|
||||
module.exports = {
|
||||
client,
|
||||
retrieveCall,
|
||||
deleteCall,
|
||||
listCalls,
|
||||
listSortedSets,
|
||||
listQueues,
|
||||
purgeCalls,
|
||||
retrieveSet,
|
||||
addKey,
|
||||
retrieveKey,
|
||||
deleteKey,
|
||||
redisClient,
|
||||
incrKey,
|
||||
listConferences
|
||||
incrKey
|
||||
};
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
const opts = {
|
||||
const opts = Object.assign({
|
||||
timestamp: () => {
|
||||
return `, "time": "${new Date().toISOString()}"`;
|
||||
}
|
||||
}, {
|
||||
level: process.env.JAMBONES_LOGLEVEL || 'info'
|
||||
};
|
||||
const pino = require('pino');
|
||||
const logger = pino(opts, pino.destination(1, {sync: false}));
|
||||
});
|
||||
|
||||
const logger = require('pino')(opts);
|
||||
|
||||
module.exports = logger;
|
||||
|
||||
@@ -4,7 +4,7 @@ const {getMysqlConnection} = require('../db');
|
||||
const {promisePool} = require('../db');
|
||||
const { v4: uuid } = require('uuid');
|
||||
|
||||
const {encrypt, decrypt} = require('../utils/encrypt-decrypt');
|
||||
const {encrypt} = require('../utils/encrypt-decrypt');
|
||||
|
||||
const retrieveSql = `SELECT * from accounts acc
|
||||
LEFT JOIN webhooks AS rh
|
||||
@@ -34,7 +34,7 @@ AND effective_end_date IS NULL
|
||||
AND pending=0`;
|
||||
|
||||
const updatePaymentInfoSql = `UPDATE account_subscriptions
|
||||
SET last4 = ?, stripe_payment_method_id=?, exp_month = ?, exp_year = ?, card_type = ?
|
||||
SET last4 = ?, exp_month = ?, exp_year = ?, card_type = ?
|
||||
WHERE account_sid = ?
|
||||
AND effective_end_date IS NULL`;
|
||||
|
||||
@@ -55,13 +55,6 @@ WHERE account_sid = ?
|
||||
AND effective_end_date IS NULL
|
||||
AND pending = 0`;
|
||||
|
||||
const extractBucketCredential = (obj) => {
|
||||
const {bucket_credential} = obj;
|
||||
if (bucket_credential) {
|
||||
obj.bucket_credential = JSON.parse(decrypt(bucket_credential));
|
||||
}
|
||||
};
|
||||
|
||||
function transmogrifyResults(results) {
|
||||
return results.map((row) => {
|
||||
const obj = row.acc;
|
||||
@@ -82,8 +75,6 @@ function transmogrifyResults(results) {
|
||||
else obj.queue_event_hook = null;
|
||||
delete obj.queue_event_hook_sid;
|
||||
|
||||
extractBucketCredential(obj);
|
||||
|
||||
return obj;
|
||||
});
|
||||
}
|
||||
@@ -199,18 +190,17 @@ class Account extends Model {
|
||||
debug(r3, 'Account.activateSubscription - replaced old subscription');
|
||||
|
||||
/* update account.plan to paid, if it isnt already */
|
||||
/* update account.is_active to 1, if account is deactivated */
|
||||
await promisePool.execute(
|
||||
'UPDATE accounts SET plan_type = \'paid\', is_active = 1 WHERE account_sid = ?',
|
||||
'UPDATE accounts SET plan_type = \'paid\' WHERE account_sid = ?',
|
||||
[account_sid]);
|
||||
return true;
|
||||
}
|
||||
|
||||
static async updatePaymentInfo(logger, account_sid, pm) {
|
||||
const {id, card} = pm;
|
||||
const {card} = pm;
|
||||
const last4_encrypted = encrypt(card.last4);
|
||||
await promisePool.execute(updatePaymentInfoSql,
|
||||
[last4_encrypted, id, card.exp_month, card.exp_year, card.brand, account_sid]);
|
||||
[last4_encrypted, card.exp_month, card.exp_year, card.brand, account_sid]);
|
||||
}
|
||||
|
||||
static async provisionPendingSubscription(logger, account_sid, products, payment_method, subscription_id) {
|
||||
@@ -248,6 +238,7 @@ class Account extends Model {
|
||||
}));
|
||||
return account_subscription_sid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Account.table = 'accounts';
|
||||
@@ -328,15 +319,7 @@ Account.fields = [
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'record_all_calls',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'record_format',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
name: 'bucket_credential',
|
||||
name: 'lcr_sid',
|
||||
type: 'string'
|
||||
}
|
||||
];
|
||||
|
||||
@@ -120,10 +120,6 @@ Application.fields = [
|
||||
{
|
||||
name: 'messaging_hook_sid',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'record_all_calls',
|
||||
type: 'number',
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
const Model = require('./model');
|
||||
const {promisePool} = require('../db');
|
||||
|
||||
class Client extends Model {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
static async retrieveAllByAccountSid(account_sid) {
|
||||
const sql = `SELECT * FROM ${this.table} WHERE account_sid = ?`;
|
||||
const [rows] = await promisePool.query(sql, account_sid);
|
||||
return rows;
|
||||
}
|
||||
|
||||
static async retrieveAllByServiceProviderSid(service_provider_sid) {
|
||||
const sql = `SELECT c.client_sid, c.account_sid, c.is_active, c.username, c.hashed_password
|
||||
FROM ${this.table} AS c LEFT JOIN accounts AS acc ON c.account_sid = acc.account_sid
|
||||
LEFT JOIN service_providers AS sp ON sp.service_provider_sid = accs.service_provider_sid
|
||||
WHERE sp.service_provider_sid = ?`;
|
||||
const [rows] = await promisePool.query(sql, service_provider_sid);
|
||||
return rows;
|
||||
}
|
||||
|
||||
static async retrieveByAccountSidAndUserName(account_sid, username) {
|
||||
const sql = `SELECT * FROM ${this.table} WHERE account_sid = ? AND username = ?`;
|
||||
const [rows] = await promisePool.query(sql, [account_sid, username]);
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
Client.table = 'clients';
|
||||
Client.fields = [
|
||||
{
|
||||
name: 'client_sid',
|
||||
type: 'string',
|
||||
primaryKey: true
|
||||
},
|
||||
{
|
||||
name: 'account_sid',
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'is_active',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'username',
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'password',
|
||||
type: 'string'
|
||||
},
|
||||
{
|
||||
name: 'allow_direct_app_calling',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'allow_direct_queue_calling',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'allow_direct_user_calling',
|
||||
type: 'number'
|
||||
}
|
||||
];
|
||||
|
||||
module.exports = Client;
|
||||
@@ -1,61 +0,0 @@
|
||||
const Model = require('./model');
|
||||
const {promisePool} = require('../db');
|
||||
|
||||
class GoogleCustomVoice extends Model {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
static async retrieveAllBySpeechCredentialSid(speech_credential_sid) {
|
||||
const sql = `SELECT * FROM ${this.table} WHERE speech_credential_sid = ?`;
|
||||
const [rows] = await promisePool.query(sql, speech_credential_sid);
|
||||
return rows;
|
||||
}
|
||||
|
||||
static async deleteAllBySpeechCredentialSid(speech_credential_sid) {
|
||||
const sql = `DELETE FROM ${this.table} WHERE speech_credential_sid = ?`;
|
||||
const [rows] = await promisePool.query(sql, speech_credential_sid);
|
||||
return rows;
|
||||
}
|
||||
|
||||
static async retrieveAllByLabel(service_provider_sid, account_sid, label) {
|
||||
let sql;
|
||||
if (account_sid) {
|
||||
sql = `SELECT gcv.* FROM ${this.table} gcv
|
||||
LEFT JOIN speech_credentials sc ON gcv.speech_credential_sid = sc.speech_credential_sid
|
||||
WHERE sc.account_sid = ? OR (sc.account_sid is NULL && sc.service_provider_sid = ?)
|
||||
${label ? 'AND label = ?' : 'AND label is NULL'}`;
|
||||
} else {
|
||||
sql = `SELECT gcv.* FROM ${this.table} gcv
|
||||
LEFT JOIN speech_credentials sc ON gcv.speech_credential_sid = sc.speech_credential_sid
|
||||
WHERE sc.service_provider_sid = ? ${label ? 'AND label = ?' : 'AND label is NULL'}`;
|
||||
}
|
||||
const [rows] = await promisePool.query(sql, [...(account_sid ?
|
||||
[account_sid, service_provider_sid] : [service_provider_sid]), label]);
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
GoogleCustomVoice.table = 'google_custom_voices';
|
||||
GoogleCustomVoice.fields = [
|
||||
{
|
||||
name: 'google_custom_voice_sid',
|
||||
type: 'string',
|
||||
primaryKey: true
|
||||
},
|
||||
{
|
||||
name: 'model',
|
||||
type: 'string',
|
||||
required: true
|
||||
},
|
||||
{
|
||||
name: 'reported_usage',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'name',
|
||||
type: 'string',
|
||||
required: true
|
||||
}
|
||||
];
|
||||
|
||||
module.exports = GoogleCustomVoice;
|
||||
@@ -1,7 +1,6 @@
|
||||
const Model = require('./model');
|
||||
const {promisePool} = require('../db');
|
||||
const sqlRetrieveAll = 'SELECT * from phone_numbers WHERE account_sid = ? ORDER BY number';
|
||||
const sqlRetrieveOne = 'SELECT * from phone_numbers WHERE phone_number_sid = ? AND account_sid = ? ORDER BY number';
|
||||
const sql = 'SELECT * from phone_numbers WHERE account_sid = ?';
|
||||
const sqlSP = `SELECT *
|
||||
FROM phone_numbers
|
||||
WHERE account_sid IN
|
||||
@@ -9,7 +8,7 @@ WHERE account_sid IN
|
||||
SELECT account_sid
|
||||
FROM accounts
|
||||
WHERE service_provider_sid = ?
|
||||
) ORDER BY number`;
|
||||
)`;
|
||||
|
||||
class PhoneNumber extends Model {
|
||||
constructor() {
|
||||
@@ -17,8 +16,8 @@ class PhoneNumber extends Model {
|
||||
}
|
||||
|
||||
static async retrieveAll(account_sid) {
|
||||
if (!account_sid) return await super.retrieveAll();
|
||||
const [rows] = await promisePool.query(sqlRetrieveAll, account_sid);
|
||||
if (!account_sid) return super.retrieveAll();
|
||||
const [rows] = await promisePool.query(sql, account_sid);
|
||||
return rows;
|
||||
}
|
||||
static async retrieveAllForSP(service_provider_sid) {
|
||||
@@ -31,7 +30,7 @@ class PhoneNumber extends Model {
|
||||
*/
|
||||
static async retrieve(sid, account_sid) {
|
||||
if (!account_sid) return super.retrieve(sid);
|
||||
const [rows] = await promisePool.query(sqlRetrieveOne, [sid, account_sid]);
|
||||
const [rows] = await promisePool.query(`${sql} AND phone_number_sid = ?`, [account_sid, sid]);
|
||||
return rows;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,10 +51,6 @@ SipGateway.fields = [
|
||||
name: 'is_active',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'pad_crypto',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'account_sid',
|
||||
type: 'string'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const Model = require('./model');
|
||||
const {promisePool} = require('../db');
|
||||
const retrieveSql = 'SELECT * from speech_credentials WHERE account_sid = ?';
|
||||
const retrieveSqlForSP = 'SELECT * from speech_credentials WHERE service_provider_sid = ? and account_sid is null';
|
||||
const retrieveSqlForSP = 'SELECT * from speech_credentials WHERE service_provider_sid = ?';
|
||||
|
||||
class SpeechCredential extends Model {
|
||||
constructor() {
|
||||
@@ -20,19 +20,6 @@ class SpeechCredential extends Model {
|
||||
return rows;
|
||||
}
|
||||
|
||||
static async getSpeechCredentialsByVendorAndLabel(service_provider_sid, account_sid, vendor, label) {
|
||||
let sql;
|
||||
if (account_sid) {
|
||||
sql = `SELECT * FROM speech_credentials WHERE account_sid = ? AND vendor = ?
|
||||
AND label ${label ? '= ?' : 'is NULL'}`;
|
||||
} else {
|
||||
sql = `SELECT * FROM speech_credentials WHERE service_provider_sid = ? AND vendor = ?
|
||||
AND label ${label ? '= ?' : 'is NULL'}`;
|
||||
}
|
||||
const [rows] = await promisePool.query(sql, [account_sid ? account_sid : service_provider_sid, vendor, label]);
|
||||
return rows;
|
||||
}
|
||||
|
||||
static async disableStt(account_sid) {
|
||||
await promisePool.execute('UPDATE speech_credentials SET use_for_stt = 0 WHERE account_sid = ?', [account_sid]);
|
||||
}
|
||||
@@ -99,10 +86,6 @@ SpeechCredential.fields = [
|
||||
{
|
||||
name: 'last_tested',
|
||||
type: 'date'
|
||||
},
|
||||
{
|
||||
name: 'label',
|
||||
type: 'string'
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -33,10 +33,6 @@ SystemInformation.fields = [
|
||||
name: 'monitoring_domain_name',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'private_network_cidr',
|
||||
type: 'string',
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = SystemInformation;
|
||||
|
||||
@@ -61,10 +61,6 @@ VoipCarrier.fields = [
|
||||
name: 'requires_register',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'register_use_tls',
|
||||
type: 'number'
|
||||
},
|
||||
{
|
||||
name: 'register_username',
|
||||
type: 'string'
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
const { Writable } = require('stream');
|
||||
const { BlobServiceClient } = require('@azure/storage-blob');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const streamBuffers = require('stream-buffers');
|
||||
|
||||
class AzureStorageUploadStream extends Writable {
|
||||
constructor(logger, opts) {
|
||||
super(opts);
|
||||
const blobServiceClient = BlobServiceClient.fromConnectionString(opts.connection_string);
|
||||
this.blockBlobClient = blobServiceClient.getContainerClient(opts.bucketName).getBlockBlobClient(opts.Key);
|
||||
|
||||
this.metadata = opts.metadata;
|
||||
this.blocks = [];
|
||||
|
||||
this.bufferSize = 2 * 1024 * 1024; // Buffer size set to 2MB
|
||||
this.buffer = new streamBuffers.WritableStreamBuffer({
|
||||
initialSize: this.bufferSize,
|
||||
incrementAmount: this.bufferSize
|
||||
});
|
||||
}
|
||||
|
||||
async _write(chunk, encoding, callback) {
|
||||
this.buffer.write(chunk, encoding);
|
||||
|
||||
if (this.buffer.size() >= this.bufferSize) {
|
||||
const blockID = uuidv4().replace(/-/g, '');
|
||||
this.blocks.push(blockID);
|
||||
|
||||
try {
|
||||
const dataToWrite = this.buffer.getContents();
|
||||
await this.blockBlobClient.stageBlock(blockID, dataToWrite, dataToWrite.length);
|
||||
callback();
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
}
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
async _final(callback) {
|
||||
// Write any remaining data in buffer
|
||||
if (this.buffer.size() > 0) {
|
||||
const remainingData = this.buffer.getContents();
|
||||
const blockID = uuidv4().replace(/-/g, '');
|
||||
this.blocks.push(blockID);
|
||||
|
||||
try {
|
||||
await this.blockBlobClient.stageBlock(blockID, remainingData, remainingData.length);
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this.blockBlobClient.commitBlockList(this.blocks);
|
||||
// remove all null/undefined props
|
||||
const filteredObj = Object.entries(this.metadata).reduce((acc, [key, val]) => {
|
||||
if (val !== undefined && val !== null) acc[key] = val;
|
||||
return acc;
|
||||
}, {});
|
||||
await this.blockBlobClient.setMetadata(filteredObj);
|
||||
callback();
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AzureStorageUploadStream;
|
||||
@@ -1,61 +0,0 @@
|
||||
const { Transform } = require('stream');
|
||||
const lamejs = require('@jambonz/lamejs');
|
||||
|
||||
class PCMToMP3Encoder extends Transform {
|
||||
constructor(options, logger) {
|
||||
super(options);
|
||||
|
||||
const channels = options.channels || 1;
|
||||
const sampleRate = options.sampleRate || 8000;
|
||||
const bitRate = options.bitRate || 128;
|
||||
|
||||
this.encoder = new lamejs.Mp3Encoder(channels, sampleRate, bitRate);
|
||||
this.channels = channels;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
_transform(chunk, encoding, callback) {
|
||||
try {
|
||||
// Convert chunk buffer into Int16Array for lamejs
|
||||
const samples = new Int16Array(chunk.buffer, chunk.byteOffset, chunk.length / 2);
|
||||
|
||||
// Split input samples into left and right channel arrays if stereo
|
||||
let leftChannel, rightChannel;
|
||||
if (this.channels === 2) {
|
||||
leftChannel = new Int16Array(samples.length / 2);
|
||||
rightChannel = new Int16Array(samples.length / 2);
|
||||
|
||||
for (let i = 0; i < samples.length; i += 2) {
|
||||
leftChannel[i / 2] = samples[i];
|
||||
rightChannel[i / 2] = samples[i + 1];
|
||||
}
|
||||
} else {
|
||||
leftChannel = samples;
|
||||
}
|
||||
|
||||
// Encode the input data
|
||||
const mp3Data = this.encoder.encodeBuffer(leftChannel, rightChannel);
|
||||
|
||||
if (mp3Data.length > 0) {
|
||||
this.push(Buffer.from(mp3Data));
|
||||
}
|
||||
callback();
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
{ err },
|
||||
'Error while mp3 transform');
|
||||
}
|
||||
}
|
||||
|
||||
_flush(callback) {
|
||||
// Finalize encoding and flush the internal buffers
|
||||
const mp3Data = this.encoder.flush();
|
||||
|
||||
if (mp3Data.length > 0) {
|
||||
this.push(Buffer.from(mp3Data));
|
||||
}
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PCMToMP3Encoder;
|
||||
@@ -1,62 +0,0 @@
|
||||
const { Storage } = require('@google-cloud/storage');
|
||||
const { Writable } = require('stream');
|
||||
const streamBuffers = require('stream-buffers');
|
||||
|
||||
class GoogleStorageUploadStream extends Writable {
|
||||
|
||||
constructor(logger, opts) {
|
||||
super(opts);
|
||||
this.logger = logger;
|
||||
this.metadata = opts.metadata;
|
||||
|
||||
const storage = new Storage(opts.bucketCredential);
|
||||
this.gcsFile = storage.bucket(opts.bucketName).file(opts.Key);
|
||||
this.writeStream = this.gcsFile.createWriteStream();
|
||||
|
||||
this.bufferSize = 2 * 1024 * 1024; // Buffer size set to 2MB
|
||||
this.buffer = new streamBuffers.WritableStreamBuffer({
|
||||
initialSize: this.bufferSize,
|
||||
incrementAmount: this.bufferSize
|
||||
});
|
||||
|
||||
this.writeStream.on('error', (err) => this.logger.error(err));
|
||||
this.writeStream.on('finish', () => {
|
||||
this.logger.info('Google storage Upload completed.');
|
||||
this._addMetadata();
|
||||
});
|
||||
}
|
||||
|
||||
_write(chunk, encoding, callback) {
|
||||
this.buffer.write(chunk, encoding);
|
||||
|
||||
// Write to GCS when buffer reaches desired size
|
||||
if (this.buffer.size() >= this.bufferSize) {
|
||||
const dataToWrite = this.buffer.getContents();
|
||||
this.writeStream.write(dataToWrite, callback);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
_final(callback) {
|
||||
// Write any remaining data in the buffer to GCS
|
||||
if (this.buffer.size() > 0) {
|
||||
const remainingData = this.buffer.getContents();
|
||||
this.writeStream.write(remainingData);
|
||||
}
|
||||
|
||||
this.writeStream.end();
|
||||
this.writeStream.once('finish', callback);
|
||||
}
|
||||
|
||||
async _addMetadata() {
|
||||
try {
|
||||
await this.gcsFile.setMetadata({metadata: this.metadata});
|
||||
this.logger.info('Google storage Upload and metadata setting completed.');
|
||||
} catch (err) {
|
||||
this.logger.error(err, 'Google storage An error occurred while setting metadata');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GoogleStorageUploadStream;
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
async function record(logger, socket) {
|
||||
return require('./upload')(logger, socket);
|
||||
}
|
||||
|
||||
module.exports = record;
|
||||
@@ -1,103 +0,0 @@
|
||||
const { Writable } = require('stream');
|
||||
const {
|
||||
S3Client,
|
||||
CreateMultipartUploadCommand,
|
||||
UploadPartCommand,
|
||||
CompleteMultipartUploadCommand,
|
||||
} = require('@aws-sdk/client-s3');
|
||||
|
||||
class S3MultipartUploadStream extends Writable {
|
||||
constructor(logger, opts) {
|
||||
super(opts);
|
||||
this.logger = logger;
|
||||
this.bucketName = opts.bucketName;
|
||||
this.objectKey = opts.Key;
|
||||
this.uploadId = null;
|
||||
this.partNumber = 1;
|
||||
this.multipartETags = [];
|
||||
this.buffer = Buffer.alloc(0);
|
||||
this.minPartSize = 5 * 1024 * 1024; // 5 MB
|
||||
this.s3 = new S3Client(opts.bucketCredential);
|
||||
this.metadata = opts.metadata;
|
||||
}
|
||||
|
||||
async _initMultipartUpload() {
|
||||
const command = new CreateMultipartUploadCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: this.objectKey,
|
||||
Metadata: this.metadata
|
||||
});
|
||||
const response = await this.s3.send(command);
|
||||
return response.UploadId;
|
||||
}
|
||||
|
||||
async _uploadBuffer() {
|
||||
const uploadPartCommand = new UploadPartCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: this.objectKey,
|
||||
PartNumber: this.partNumber,
|
||||
UploadId: this.uploadId,
|
||||
Body: this.buffer,
|
||||
});
|
||||
|
||||
const uploadPartResponse = await this.s3.send(uploadPartCommand);
|
||||
this.multipartETags.push({
|
||||
ETag: uploadPartResponse.ETag,
|
||||
PartNumber: this.partNumber,
|
||||
});
|
||||
this.partNumber += 1;
|
||||
}
|
||||
|
||||
async _write(chunk, encoding, callback) {
|
||||
try {
|
||||
if (!this.uploadId) {
|
||||
this.uploadId = await this._initMultipartUpload();
|
||||
}
|
||||
|
||||
this.buffer = Buffer.concat([this.buffer, chunk]);
|
||||
|
||||
if (this.buffer.length >= this.minPartSize) {
|
||||
await this._uploadBuffer();
|
||||
this.buffer = Buffer.alloc(0);
|
||||
}
|
||||
|
||||
callback(null);
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
}
|
||||
}
|
||||
|
||||
async _finalize(err) {
|
||||
try {
|
||||
if (this.buffer.length > 0) {
|
||||
await this._uploadBuffer();
|
||||
}
|
||||
|
||||
const completeMultipartUploadCommand = new CompleteMultipartUploadCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: this.objectKey,
|
||||
MultipartUpload: {
|
||||
Parts: this.multipartETags.sort((a, b) => a.PartNumber - b.PartNumber),
|
||||
},
|
||||
UploadId: this.uploadId,
|
||||
});
|
||||
|
||||
await this.s3.send(completeMultipartUploadCommand);
|
||||
this.logger.info('Finished upload to S3');
|
||||
} catch (error) {
|
||||
this.logger.error('Error completing multipart upload:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async _final(callback) {
|
||||
try {
|
||||
await this._finalize();
|
||||
callback(null);
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = S3MultipartUploadStream;
|
||||
@@ -1,97 +0,0 @@
|
||||
const Account = require('../models/account');
|
||||
const Websocket = require('ws');
|
||||
const PCMToMP3Encoder = require('./encoder');
|
||||
const wav = require('wav');
|
||||
const { getUploader } = require('./utils');
|
||||
const { pipeline } = require('stream');
|
||||
|
||||
async function upload(logger, socket) {
|
||||
socket._recvInitialMetadata = false;
|
||||
socket.on('message', async function(data, isBinary) {
|
||||
try {
|
||||
if (!isBinary && !socket._recvInitialMetadata) {
|
||||
socket._recvInitialMetadata = true;
|
||||
logger.debug(`initial metadata: ${data}`);
|
||||
const obj = JSON.parse(data.toString());
|
||||
logger.info({ obj }, 'received JSON message from jambonz');
|
||||
const { sampleRate, accountSid, callSid, direction, from, to,
|
||||
callId, applicationSid, originatingSipIp, originatingSipTrunkName } = obj;
|
||||
const account = await Account.retrieve(accountSid);
|
||||
if (account && account.length && account[0].bucket_credential) {
|
||||
const obj = account[0].bucket_credential;
|
||||
// add tags to metadata
|
||||
const metadata = {
|
||||
accountSid,
|
||||
callSid,
|
||||
direction,
|
||||
from,
|
||||
to,
|
||||
callId,
|
||||
applicationSid,
|
||||
originatingSipIp,
|
||||
originatingSipTrunkName,
|
||||
sampleRate: `${sampleRate}`
|
||||
};
|
||||
if (obj.tags && obj.tags.length) {
|
||||
obj.tags.forEach((tag) => {
|
||||
metadata[tag.Key] = tag.Value;
|
||||
});
|
||||
}
|
||||
// create S3 path
|
||||
const day = new Date();
|
||||
let key = `${day.getFullYear()}/${(day.getMonth() + 1).toString().padStart(2, '0')}`;
|
||||
key += `/${day.getDate().toString().padStart(2, '0')}/${callSid}.${account[0].record_format}`;
|
||||
|
||||
// Uploader
|
||||
const uploadStream = getUploader(key, metadata, obj, logger);
|
||||
if (!uploadStream) {
|
||||
logger.info('There is no available record uploader, close the socket.');
|
||||
socket.close();
|
||||
}
|
||||
|
||||
/**encoder */
|
||||
let encoder;
|
||||
if (account[0].record_format === 'wav') {
|
||||
encoder = new wav.Writer({ channels: 2, sampleRate, bitDepth: 16 });
|
||||
} else {
|
||||
// default is mp3
|
||||
encoder = new PCMToMP3Encoder({
|
||||
channels: 2,
|
||||
sampleRate: sampleRate,
|
||||
bitrate: 128
|
||||
}, logger);
|
||||
}
|
||||
|
||||
/* start streaming data */
|
||||
pipeline(
|
||||
Websocket.createWebSocketStream(socket),
|
||||
encoder,
|
||||
uploadStream,
|
||||
(error) => {
|
||||
if (error) {
|
||||
logger.error({ error }, 'pipeline error, cannot upload data to storage');
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
logger.info(`account ${accountSid} does not have any bucket credential, close the socket`);
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error({ err, data }, 'error parsing message during connection');
|
||||
}
|
||||
});
|
||||
socket.on('error', function(err) {
|
||||
logger.error({ err }, 'record upload: error');
|
||||
});
|
||||
socket.on('close', (data) => {
|
||||
logger.info({ data }, 'record upload: close');
|
||||
});
|
||||
socket.on('end', function(err) {
|
||||
logger.error({ err }, 'record upload: socket closed from jambonz');
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = upload;
|
||||
@@ -1,58 +0,0 @@
|
||||
const AzureStorageUploadStream = require('./azure-storage');
|
||||
const GoogleStorageUploadStream = require('./google-storage');
|
||||
const S3MultipartUploadStream = require('./s3-multipart-upload-stream');
|
||||
|
||||
const getUploader = (key, metadata, bucket_credential, logger) => {
|
||||
const uploaderOpts = {
|
||||
bucketName: bucket_credential.name,
|
||||
Key: key,
|
||||
metadata
|
||||
};
|
||||
try {
|
||||
switch (bucket_credential.vendor) {
|
||||
case 'aws_s3':
|
||||
uploaderOpts.bucketCredential = {
|
||||
credentials: {
|
||||
accessKeyId: bucket_credential.access_key_id,
|
||||
secretAccessKey: bucket_credential.secret_access_key,
|
||||
},
|
||||
region: bucket_credential.region || 'us-east-1'
|
||||
};
|
||||
return new S3MultipartUploadStream(logger, uploaderOpts);
|
||||
case 's3_compatible':
|
||||
uploaderOpts.bucketCredential = {
|
||||
endpoint: bucket_credential.endpoint,
|
||||
credentials: {
|
||||
accessKeyId: bucket_credential.access_key_id,
|
||||
secretAccessKey: bucket_credential.secret_access_key,
|
||||
},
|
||||
region: 'us-east-1',
|
||||
forcePathStyle: true
|
||||
};
|
||||
return new S3MultipartUploadStream(logger, uploaderOpts);
|
||||
case 'google':
|
||||
const serviceKey = JSON.parse(bucket_credential.service_key);
|
||||
uploaderOpts.bucketCredential = {
|
||||
projectId: serviceKey.project_id,
|
||||
credentials: {
|
||||
client_email: serviceKey.client_email,
|
||||
private_key: serviceKey.private_key
|
||||
}
|
||||
};
|
||||
return new GoogleStorageUploadStream(logger, uploaderOpts);
|
||||
case 'azure':
|
||||
uploaderOpts.connection_string = bucket_credential.connection_string;
|
||||
return new AzureStorageUploadStream(logger, uploaderOpts);
|
||||
default:
|
||||
logger.error(`unknown bucket vendor: ${bucket_credential.vendor}`);
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error(`Error creating uploader, vendor: ${bucket_credential.vendor}, reason: ${err.message}`);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getUploader
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
const router = require('express').Router();
|
||||
const assert = require('assert');
|
||||
const request = require('request');
|
||||
const {DbErrorBadRequest, DbErrorForbidden, DbErrorUnprocessableRequest} = require('../../utils/errors');
|
||||
const Account = require('../../models/account');
|
||||
@@ -23,8 +22,6 @@ const {
|
||||
} = require('./utils');
|
||||
const short = require('short-uuid');
|
||||
const VoipCarrier = require('../../models/voip-carrier');
|
||||
const { encrypt } = require('../../utils/encrypt-decrypt');
|
||||
const { testS3Storage, testGoogleStorage, testAzureStorage } = require('../../utils/storage-utils');
|
||||
const translator = short();
|
||||
|
||||
let idx = 0;
|
||||
@@ -41,14 +38,20 @@ const getFsUrl = async(logger, retrieveSet, setName) => {
|
||||
logger.info('No available feature servers to handle createCall API request');
|
||||
return ;
|
||||
}
|
||||
const f = fs[idx++ % fs.length];
|
||||
logger.info({fs}, `feature servers available for createCall API request, selecting ${f}`);
|
||||
return `${f}/v1/createCall`;
|
||||
const ip = stripPort(fs[idx++ % fs.length]);
|
||||
logger.info({fs}, `feature servers available for createCall API request, selecting ${ip}`);
|
||||
return `http://${ip}:3000/v1/createCall`;
|
||||
} catch (err) {
|
||||
logger.error({err}, 'getFsUrl: error retreving feature servers from redis');
|
||||
}
|
||||
};
|
||||
|
||||
const stripPort = (hostport) => {
|
||||
const arr = /^(.*):(.*)$/.exec(hostport);
|
||||
if (arr) return arr[1];
|
||||
return hostport;
|
||||
};
|
||||
|
||||
const validateRequest = async(req, account_sid) => {
|
||||
try {
|
||||
if (req.user.hasScope('admin')) {
|
||||
@@ -86,7 +89,6 @@ router.use('/:sid/Charges', hasAccountPermissions, require('./charges'));
|
||||
router.use('/:sid/SipRealms', hasAccountPermissions, require('./sip-realm'));
|
||||
router.use('/:sid/PredefinedCarriers', hasAccountPermissions, require('./add-from-predefined-carrier'));
|
||||
router.use('/:sid/Limits', hasAccountPermissions, require('./limits'));
|
||||
router.use('/:sid/TtsCache', hasAccountPermissions, require('./tts-cache'));
|
||||
router.get('/:sid/Applications', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
@@ -146,88 +148,6 @@ router.post('/:sid/VoipCarriers', async(req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:sid/RegisteredSipUsers', async(req, res) => {
|
||||
const {logger, registrar} = req.app.locals;
|
||||
try {
|
||||
const account_sid = parseAccountSid(req);
|
||||
await validateRequest(req, account_sid);
|
||||
const result = await Account.retrieve(account_sid);
|
||||
if (!result || result.length === 0) {
|
||||
throw new DbErrorBadRequest(`account not found for sid ${account_sid}`);
|
||||
}
|
||||
if (!result[0].sip_realm) {
|
||||
throw new DbErrorBadRequest('account does not have sip_realm configuration');
|
||||
}
|
||||
const users = await registrar.getRegisteredUsersForRealm(result[0].sip_realm);
|
||||
res.status(200).json(users.map((u) => `${u}@${result[0].sip_realm}`));
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/:sid/RegisteredSipUsers', async(req, res) => {
|
||||
const {logger, registrar} = req.app.locals;
|
||||
const users = req.body;
|
||||
try {
|
||||
const account_sid = parseAccountSid(req);
|
||||
await validateRequest(req, account_sid);
|
||||
const result = await Account.retrieve(account_sid);
|
||||
if (!result || result.length === 0) {
|
||||
throw new DbErrorBadRequest(`account not found for sid ${account_sid}`);
|
||||
}
|
||||
if (!result[0].sip_realm) {
|
||||
throw new DbErrorBadRequest('account does not have sip_realm configuration');
|
||||
}
|
||||
if (!users || !Array.isArray(users) || users.length === 0) {
|
||||
return res.status(200).json(await registrar.getRegisteredUsersDetailsForRealm(result[0].sip_realm));
|
||||
}
|
||||
const ret = [];
|
||||
for (const u of users) {
|
||||
const user = await registrar.query(`${u}@${result[0].sip_realm}`) || {
|
||||
name: u,
|
||||
contact: null,
|
||||
expiryTime: 0,
|
||||
protocol: null
|
||||
};
|
||||
ret.push({
|
||||
name: u,
|
||||
...user,
|
||||
registered_status: user.expiryTime > 0 ? 'active' : 'inactive',
|
||||
});
|
||||
}
|
||||
res.status(200).json(ret);
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:sid/RegisteredSipUsers/:client', async(req, res) => {
|
||||
const {logger, registrar, lookupClientByAccountAndUsername} = req.app.locals;
|
||||
const client = req.params.client;
|
||||
try {
|
||||
const account_sid = parseAccountSid(req);
|
||||
await validateRequest(req, account_sid);
|
||||
const result = await Account.retrieve(account_sid);
|
||||
if (!result || result.length === 0) {
|
||||
throw new DbErrorBadRequest(`account not found for sid ${account_sid}`);
|
||||
}
|
||||
const user = await registrar.query(`${client}@${result[0].sip_realm}`);
|
||||
const [clientDb] = await lookupClientByAccountAndUsername(account_sid, client);
|
||||
res.status(200).json({
|
||||
name: client,
|
||||
contact: user ? user.contact : null,
|
||||
expiryTime: user ? user.expiryTime : 0,
|
||||
protocol: user ? user.protocol : null,
|
||||
allow_direct_app_calling: clientDb ? clientDb.allow_direct_app_calling : 0,
|
||||
allow_direct_queue_calling: clientDb ? clientDb.allow_direct_queue_calling : 0,
|
||||
allow_direct_user_calling: clientDb ? clientDb.allow_direct_user_calling : 0,
|
||||
registered_status: user ? 'active' : 'inactive'
|
||||
});
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
function coerceNumbers(callInfo) {
|
||||
if (Array.isArray(callInfo)) {
|
||||
return callInfo.map((ci) => {
|
||||
@@ -258,15 +178,11 @@ function validateUpdateCall(opts) {
|
||||
'child_call_hook',
|
||||
'call_status',
|
||||
'listen_status',
|
||||
'transcribe_status',
|
||||
'conf_hold_status',
|
||||
'conf_mute_status',
|
||||
'mute_status',
|
||||
'sip_request',
|
||||
'record',
|
||||
'tag',
|
||||
'dtmf',
|
||||
'conferenceParticipantAction'
|
||||
'record'
|
||||
]
|
||||
.reduce((acc, prop) => (opts[prop] ? ++acc : acc), 0);
|
||||
|
||||
@@ -302,34 +218,15 @@ function validateUpdateCall(opts) {
|
||||
throw new DbErrorBadRequest('invalid conf_mute_status');
|
||||
}
|
||||
if (opts.sip_request &&
|
||||
(!opts.sip_request.method || !opts.sip_request.content_type || !opts.sip_request.content)) {
|
||||
throw new DbErrorBadRequest('sip_request requires method, content_type and content properties');
|
||||
(!opts.sip_request.method && !opts.sip_request.content_type || !opts.sip_request.content_type)) {
|
||||
throw new DbErrorBadRequest('sip_request requires content_type and content properties');
|
||||
}
|
||||
if (opts.record && !opts.record.action) {
|
||||
throw new DbErrorBadRequest('record requires action property');
|
||||
}
|
||||
if (opts.dtmf && !opts.dtmf.digit) {
|
||||
throw new DbErrorBadRequest('invalid dtmf');
|
||||
}
|
||||
if ('startCallRecording' === opts.record?.action && !opts.record.siprecServerURL) {
|
||||
throw new DbErrorBadRequest('record requires siprecServerURL property when starting recording');
|
||||
}
|
||||
if (opts.tag && (typeof opts.tag !== 'object' || Array.isArray(opts.tag) || opts.tag === null)) {
|
||||
throw new DbErrorBadRequest('invalid tag data');
|
||||
}
|
||||
if (opts.conferenceParticipantAction) {
|
||||
if (!['tag', 'untag', 'coach', 'uncoach', 'mute', 'unmute', 'hold', 'unhold']
|
||||
.includes(opts.conferenceParticipantAction.action)) {
|
||||
throw new DbErrorBadRequest(
|
||||
`conferenceParticipantAction invalid action property ${opts.conferenceParticipantAction.action}`);
|
||||
}
|
||||
if ('tag' == opts.conferenceParticipantAction.action && !opts.conferenceParticipantAction.tag) {
|
||||
throw new DbErrorBadRequest('conferenceParticipantAction requires tag property when action is \'tag\'');
|
||||
}
|
||||
if ('coach' == opts.conferenceParticipantAction.action && !opts.conferenceParticipantAction.tag) {
|
||||
throw new DbErrorBadRequest('conferenceParticipantAction requires tag property when action is \'coach\'');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateTo(to) {
|
||||
@@ -366,7 +263,6 @@ async function validateCreateCall(logger, sid, req) {
|
||||
const application = await lookupAppBySid(obj.application_sid);
|
||||
Object.assign(obj, {
|
||||
call_hook: application.call_hook,
|
||||
app_json: application.app_json,
|
||||
call_status_hook: application.call_status_hook,
|
||||
speech_synthesis_vendor: application.speech_synthesis_vendor,
|
||||
speech_synthesis_language: application.speech_synthesis_language,
|
||||
@@ -553,6 +449,7 @@ router.get('/:sid', async(req, res) => {
|
||||
try {
|
||||
const account_sid = parseAccountSid(req);
|
||||
await validateRequest(req, account_sid);
|
||||
|
||||
const service_provider_sid = req.user.hasServiceProviderAuth ? req.user.service_provider_sid : null;
|
||||
const results = await Account.retrieve(account_sid, service_provider_sid);
|
||||
if (results.length === 0) return res.status(404).end();
|
||||
@@ -638,58 +535,6 @@ router.delete('/:sid/SubspaceTeleport', async(req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
function encryptBucketCredential(obj) {
|
||||
if (!obj.bucket_credential) return;
|
||||
const {
|
||||
vendor,
|
||||
region,
|
||||
name,
|
||||
access_key_id,
|
||||
secret_access_key,
|
||||
tags,
|
||||
service_key,
|
||||
connection_string,
|
||||
endpoint
|
||||
} = obj.bucket_credential;
|
||||
|
||||
switch (vendor) {
|
||||
case 'aws_s3':
|
||||
assert(access_key_id, 'invalid aws S3 bucket credential: access_key_id is required');
|
||||
assert(secret_access_key, 'invalid aws S3 bucket credential: secret_access_key is required');
|
||||
assert(name, 'invalid aws bucket name: name is required');
|
||||
assert(region, 'invalid aws bucket region: region is required');
|
||||
const awsData = JSON.stringify({vendor, region, name, access_key_id,
|
||||
secret_access_key, tags});
|
||||
obj.bucket_credential = encrypt(awsData);
|
||||
break;
|
||||
case 's3_compatible':
|
||||
assert(access_key_id, 'invalid aws S3 bucket credential: access_key_id is required');
|
||||
assert(secret_access_key, 'invalid aws S3 bucket credential: secret_access_key is required');
|
||||
assert(name, 'invalid aws bucket name: name is required');
|
||||
assert(endpoint, 'invalid endpoint uri: endpoint is required');
|
||||
const s3Data = JSON.stringify({vendor, endpoint, name, access_key_id,
|
||||
secret_access_key, tags});
|
||||
obj.bucket_credential = encrypt(s3Data);
|
||||
break;
|
||||
case 'google':
|
||||
assert(service_key, 'invalid google cloud storage credential: service_key is required');
|
||||
const googleData = JSON.stringify({vendor, name, service_key, tags});
|
||||
obj.bucket_credential = encrypt(googleData);
|
||||
break;
|
||||
case 'azure':
|
||||
assert(name, 'invalid azure container name: name is required');
|
||||
assert(connection_string, 'invalid azure cloud storage credential: connection_string is required');
|
||||
const azureData = JSON.stringify({vendor, name, connection_string, tags});
|
||||
obj.bucket_credential = encrypt(azureData);
|
||||
break;
|
||||
case 'none':
|
||||
obj.bucket_credential = null;
|
||||
break;
|
||||
default:
|
||||
throw new DbErrorBadRequest(`unknown storage vendor: ${vendor}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update
|
||||
*/
|
||||
@@ -736,8 +581,6 @@ router.put('/:sid', async(req, res) => {
|
||||
delete obj.registration_hook;
|
||||
delete obj.queue_event_hook;
|
||||
|
||||
encryptBucketCredential(obj);
|
||||
|
||||
const rowsAffected = await Account.update(sid, obj);
|
||||
if (rowsAffected === 0) {
|
||||
return res.status(404).end();
|
||||
@@ -830,44 +673,6 @@ account_subscriptions WHERE account_sid = ?)
|
||||
}
|
||||
});
|
||||
|
||||
/* Test Bucket credential Keys */
|
||||
router.post('/:sid/BucketCredentialTest', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
const account_sid = parseAccountSid(req);
|
||||
await validateRequest(req, account_sid);
|
||||
const {vendor, name, region, access_key_id, secret_access_key, service_key, connection_string, endpoint} = req.body;
|
||||
const ret = {
|
||||
status: 'not tested'
|
||||
};
|
||||
|
||||
switch (vendor) {
|
||||
case 'aws_s3':
|
||||
await testS3Storage(logger, {vendor, name, region, access_key_id, secret_access_key});
|
||||
ret.status = 'ok';
|
||||
break;
|
||||
case 's3_compatible':
|
||||
await testS3Storage(logger, {vendor, name, endpoint, access_key_id, secret_access_key});
|
||||
ret.status = 'ok';
|
||||
break;
|
||||
case 'google':
|
||||
await testGoogleStorage(logger, {vendor, name, service_key});
|
||||
ret.status = 'ok';
|
||||
break;
|
||||
case 'azure':
|
||||
await testAzureStorage(logger, {vendor, name, connection_string});
|
||||
ret.status = 'ok';
|
||||
break;
|
||||
default:
|
||||
throw new DbErrorBadRequest(`Does not support test for ${vendor}`);
|
||||
}
|
||||
return res.status(200).json(ret);
|
||||
}
|
||||
catch (err) {
|
||||
return res.status(200).json({status: 'failed', reason: err.message});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* retrieve account level api keys
|
||||
*/
|
||||
@@ -891,7 +696,7 @@ router.get('/:sid/ApiKeys', async(req, res) => {
|
||||
*/
|
||||
router.post('/:sid/Calls', async(req, res) => {
|
||||
const {retrieveSet, logger} = req.app.locals;
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:fs-service-url`;
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
|
||||
const serviceUrl = await getFsUrl(logger, retrieveSet, setName);
|
||||
|
||||
if (!serviceUrl) {
|
||||
@@ -1052,7 +857,7 @@ router.post('/:sid/Messages', async(req, res) => {
|
||||
const account_sid = parseAccountSid(req);
|
||||
await validateRequest(req, account_sid);
|
||||
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:fs-service-url`;
|
||||
const setName = `${(process.env.JAMBONES_CLUSTER_ID || 'default')}:active-fs`;
|
||||
const serviceUrl = await getFsUrl(logger, retrieveSet, setName);
|
||||
if (!serviceUrl) res.json({msg: 'no available feature servers at this time'}).status(480);
|
||||
await validateCreateMessage(logger, account_sid, req);
|
||||
@@ -1089,12 +894,12 @@ router.post('/:sid/Messages', async(req, res) => {
|
||||
* retrieve info for a group of queues under an account
|
||||
*/
|
||||
router.get('/:sid/Queues', async(req, res) => {
|
||||
const {logger, listSortedSets} = req.app.locals;
|
||||
const {logger, listQueues} = req.app.locals;
|
||||
const { search } = req.query || {};
|
||||
try {
|
||||
const accountSid = parseAccountSid(req);
|
||||
await validateRequest(req, accountSid);
|
||||
const queues = search ? await listSortedSets(accountSid, search) : await listSortedSets(accountSid);
|
||||
const queues = search ? await listQueues(accountSid, search) : await listQueues(accountSid);
|
||||
logger.debug(`retrieved ${queues.length} queues for account sid ${accountSid}`);
|
||||
res.status(200).json(queues);
|
||||
updateLastUsed(logger, accountSid, req).catch((err) => {});
|
||||
@@ -1103,21 +908,4 @@ router.get('/:sid/Queues', async(req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* retrieve info for a list of conferences under an account
|
||||
*/
|
||||
router.get('/:sid/Conferences', async(req, res) => {
|
||||
const {logger, listConferences} = req.app.locals;
|
||||
try {
|
||||
const accountSid = parseAccountSid(req);
|
||||
await validateRequest(req, accountSid);
|
||||
const conferences = await listConferences(accountSid);
|
||||
logger.debug(`retrieved ${conferences.length} queues for account sid ${accountSid}`);
|
||||
res.status(200).json(conferences.map((c) => c.split(':').pop()));
|
||||
updateLastUsed(logger, accountSid, req).catch((err) => {});
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
const router = require('express').Router();
|
||||
const decorate = require('./decorate');
|
||||
const sysError = require('../error');
|
||||
const Client = require('../../models/client');
|
||||
const Account = require('../../models/account');
|
||||
const { DbErrorBadRequest, DbErrorForbidden } = require('../../utils/errors');
|
||||
const { encrypt, decrypt, obscureKey } = require('../../utils/encrypt-decrypt');
|
||||
|
||||
const commonCheck = async(req) => {
|
||||
if (req.user.hasAccountAuth) {
|
||||
req.body.account_sid = req.user.account_sid;
|
||||
} else if (req.user.hasServiceProviderAuth && req.body.account_sid) {
|
||||
const accounts = await Account.retrieve(req.body.account_sid, req.user.service_provider_sid);
|
||||
if (accounts.length === 0) {
|
||||
throw new DbErrorForbidden('insufficient permissions');
|
||||
}
|
||||
}
|
||||
|
||||
if (req.body.password) {
|
||||
req.body.password = encrypt(req.body.password);
|
||||
}
|
||||
};
|
||||
|
||||
const validateAdd = async(req) => {
|
||||
await commonCheck(req);
|
||||
|
||||
const clients = await Client.retrieveByAccountSidAndUserName(req.body.account_sid, req.body.username);
|
||||
if (clients.length) {
|
||||
throw new DbErrorBadRequest('the client\'s username already exists');
|
||||
}
|
||||
};
|
||||
|
||||
const validateUpdate = async(req, sid) => {
|
||||
await commonCheck(req);
|
||||
|
||||
const clients = await Client.retrieveByAccountSidAndUserName(req.body.account_sid, req.body.username);
|
||||
if (clients.length && clients[0].client_sid !== sid) {
|
||||
throw new DbErrorBadRequest('the client\'s username already exists');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const preconditions = {
|
||||
add: validateAdd,
|
||||
update: validateUpdate,
|
||||
};
|
||||
|
||||
decorate(router, Client, ['add', 'update', 'delete'], preconditions);
|
||||
|
||||
router.get('/', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
const results = req.user.hasAdminAuth ?
|
||||
await Client.retrieveAll() : req.user.hasAccountAuth ?
|
||||
await Client.retrieveAllByAccountSid(req.user.hasAccountAuth ? req.user.account_sid : null) :
|
||||
await Client.retrieveAllByServiceProviderSid(req.user.service_provider_sid);
|
||||
const ret = results.map((c) => {
|
||||
c.password = obscureKey(decrypt(c.password), 1);
|
||||
return c;
|
||||
});
|
||||
res.status(200).json(ret);
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:sid', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
const results = await Client.retrieve(req.params.sid);
|
||||
if (results.length === 0) return res.sendStatus(404);
|
||||
const client = results[0];
|
||||
client.password = obscureKey(decrypt(client.password), 1);
|
||||
if (req.user.hasAccountAuth && client.account_sid !== req.user.account_sid) {
|
||||
return res.sendStatus(404);
|
||||
} else if (req.user.hasServiceProviderAuth) {
|
||||
const accounts = await Account.retrieve(client.account_sid, req.user.service_provider_sid);
|
||||
if (!accounts.length) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
}
|
||||
return res.status(200).json(client);
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -6,7 +6,6 @@ const {validateEmail, emailSimpleText} = require('../../utils/email-utils');
|
||||
const {promisePool} = require('../../db');
|
||||
const {cacheClient} = require('../../helpers');
|
||||
const sysError = require('../error');
|
||||
const assert = require('assert');
|
||||
const sql = `SELECT * from users user
|
||||
LEFT JOIN accounts AS acc
|
||||
ON acc.account_sid = user.account_sid
|
||||
@@ -27,8 +26,7 @@ function createOauthEmailText(provider) {
|
||||
}
|
||||
|
||||
function createResetEmailText(link) {
|
||||
assert(process.env.JAMBONZ_BASE_URL, 'process.env.JAMBONZ_BASE_URL is missing');
|
||||
const baseUrl = process.env.JAMBONZ_BASE_URL;
|
||||
const baseUrl = 'http://localhost:3001';
|
||||
|
||||
return `Hi there!
|
||||
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
const router = require('express').Router();
|
||||
const GoogleCustomVoice = require('../../models/google-custom-voice');
|
||||
const SpeechCredential = require('../../models/speech-credential');
|
||||
const decorate = require('./decorate');
|
||||
const {DbErrorBadRequest, DbErrorForbidden} = require('../../utils/errors');
|
||||
const sysError = require('../error');
|
||||
|
||||
const validateCredentialPermission = async(req) => {
|
||||
const credential = await SpeechCredential.retrieve(req.body.speech_credential_sid);
|
||||
if (!credential || credential.length === 0) {
|
||||
throw new DbErrorBadRequest('Invalid speech_credential_sid');
|
||||
}
|
||||
const cred = credential[0];
|
||||
|
||||
if (req.user.hasServiceProviderAuth && cred.service_provider_sid !== req.user.service_provider_sid) {
|
||||
throw new DbErrorForbidden('Insufficient privileges');
|
||||
}
|
||||
if (req.user.hasAccountAuth && cred.account_sid !== req.user.account_sid) {
|
||||
throw new DbErrorForbidden('Insufficient privileges');
|
||||
}
|
||||
};
|
||||
|
||||
const validateAdd = async(req) => {
|
||||
if (!req.body.speech_credential_sid) {
|
||||
throw new DbErrorBadRequest('missing speech_credential_sid');
|
||||
}
|
||||
|
||||
await validateCredentialPermission(req);
|
||||
};
|
||||
|
||||
const validateUpdate = async(req) => {
|
||||
if (req.body.speech_credential_sid) {
|
||||
await validateCredentialPermission(req);
|
||||
}
|
||||
};
|
||||
|
||||
const preconditions = {
|
||||
add: validateAdd,
|
||||
update: validateUpdate,
|
||||
};
|
||||
|
||||
decorate(router, GoogleCustomVoice, ['add', 'retrieve', 'update', 'delete'], preconditions);
|
||||
|
||||
router.get('/', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
const account_sid = req.user.account_sid || req.query.account_sid;
|
||||
const service_provider_sid = req.user.service_provider_sid || req.query.service_provider_sid;
|
||||
const speech_credential_sid = req.query.speech_credential_sid;
|
||||
const label = req.query.label;
|
||||
try {
|
||||
let results = [];
|
||||
if (speech_credential_sid) {
|
||||
const [cred] = await SpeechCredential.retrieve(speech_credential_sid);
|
||||
if (!cred) {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
if (account_sid && cred.account_sid && cred.account_sid !== account_sid) {
|
||||
throw new DbErrorForbidden('Insufficient privileges');
|
||||
}
|
||||
if (service_provider_sid && cred.service_provider_sid && cred.service_provider_sid !== service_provider_sid) {
|
||||
throw new DbErrorForbidden('Insufficient privileges');
|
||||
}
|
||||
results = await GoogleCustomVoice.retrieveAllBySpeechCredentialSid(speech_credential_sid);
|
||||
} else {
|
||||
if (!account_sid && !service_provider_sid) {
|
||||
throw new DbErrorBadRequest('missing account_sid or service_provider_sid in query parameters');
|
||||
}
|
||||
results = await GoogleCustomVoice.retrieveAllByLabel(service_provider_sid, account_sid, label);
|
||||
}
|
||||
res.status(200).json(results);
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
module.exports = router;
|
||||
@@ -17,7 +17,6 @@ const isAdminScope = (req, res, next) => {
|
||||
|
||||
api.use('/BetaInviteCodes', isAdminScope, require('./beta-invite-codes'));
|
||||
api.use('/SystemInformation', isAdminScope, require('./system-information'));
|
||||
api.use('/TtsCache', isAdminScope, require('./tts-cache'));
|
||||
api.use('/ServiceProviders', require('./service-providers'));
|
||||
api.use('/VoipCarriers', require('./voip-carriers'));
|
||||
api.use('/Webhooks', require('./webhooks'));
|
||||
@@ -51,9 +50,6 @@ api.use('/PasswordSettings', require('./password-settings'));
|
||||
api.use('/Lcrs', require('./lcrs'));
|
||||
api.use('/LcrRoutes', require('./lcr-routes'));
|
||||
api.use('/LcrCarrierSetEntries', require('./lcr-carrier-set-entries'));
|
||||
api.use('/Clients', require('./clients'));
|
||||
// Google Custom Voices
|
||||
api.use('/GoogleCustomVoices', require('./google-custom-voices'));
|
||||
|
||||
// messaging
|
||||
api.use('/Smpps', require('./smpps')); // our smpp server info
|
||||
|
||||
@@ -100,93 +100,6 @@ const preconditions = {
|
||||
|
||||
decorate(router, Lcr, ['add', 'update', 'delete'], preconditions);
|
||||
|
||||
const validateLcrBatchAdd = async(lcr_sid, body, lookupCarrierBySid) => {
|
||||
for (const lcr_route of body) {
|
||||
lcr_route.lcr_sid = lcr_sid;
|
||||
if (!lcr_route.lcr_carrier_set_entries || lcr_route.lcr_carrier_set_entries.length === 0) {
|
||||
throw new DbErrorBadRequest('Lcr Route batch process require lcr_carrier_set_entries');
|
||||
}
|
||||
for (const entry of lcr_route.lcr_carrier_set_entries) {
|
||||
// check voip_carrier_sid is exist
|
||||
if (!entry.voip_carrier_sid) {
|
||||
throw new DbErrorBadRequest('One of lcr_carrier_set_entries is missing voip_carrier_sid');
|
||||
}
|
||||
const carrier = await lookupCarrierBySid(entry.voip_carrier_sid);
|
||||
if (!carrier) {
|
||||
throw new DbErrorBadRequest('unknown voip_carrier_sid');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const addNewLcrRoute = async(lcr_route) => {
|
||||
const lcr_sid = lcr_route.lcr_sid;
|
||||
const lcr_carrier_set_entries = lcr_route.lcr_carrier_set_entries;
|
||||
delete lcr_route.lcr_carrier_set_entries;
|
||||
const lcr_route_sid = await LcrRoutes.make(lcr_route);
|
||||
for (const entry of lcr_carrier_set_entries) {
|
||||
entry.lcr_route_sid = lcr_route_sid;
|
||||
const lcr_carrier_set_entry_sid = await LcrCarrierSetEntry.make(entry);
|
||||
if (lcr_route.priority === 9999) {
|
||||
// this is default lcr set entry
|
||||
const [lcr] = await Lcr.retrieve(lcr_sid);
|
||||
if (lcr) {
|
||||
lcr.default_carrier_set_entry_sid = lcr_carrier_set_entry_sid;
|
||||
delete lcr.lcr_sid;
|
||||
await Lcr.update(lcr_sid, lcr);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
router.post('/:sid/Routes', async(req, res) => {
|
||||
const results = await Lcr.retrieve(req.params.sid);
|
||||
if (results.length === 0) return res.sendStatus(404);
|
||||
const {logger, lookupCarrierBySid} = req.app.locals;
|
||||
try {
|
||||
const body = req.body;
|
||||
await validateLcrBatchAdd(req.params.sid, body, lookupCarrierBySid);
|
||||
for (const lcr_route of body) {
|
||||
await addNewLcrRoute(lcr_route, lookupCarrierBySid);
|
||||
}
|
||||
res.sendStatus(204);
|
||||
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:sid/Routes', async(req, res) => {
|
||||
const results = await Lcr.retrieve(req.params.sid);
|
||||
if (results.length === 0) return res.sendStatus(404);
|
||||
const {logger, lookupCarrierBySid} = req.app.locals;
|
||||
try {
|
||||
const body = req.body;
|
||||
await validateLcrBatchAdd(req.params.sid, body, lookupCarrierBySid);
|
||||
for (const lcr_route of body) {
|
||||
if (lcr_route.lcr_route_sid) {
|
||||
const lcr_route_sid = lcr_route.lcr_route_sid;
|
||||
delete lcr_route.lcr_route_sid;
|
||||
const lcr_carrier_set_entries = lcr_route.lcr_carrier_set_entries;
|
||||
delete lcr_route.lcr_carrier_set_entries;
|
||||
await LcrRoutes.update(lcr_route_sid, lcr_route);
|
||||
for (const entry of lcr_carrier_set_entries) {
|
||||
const lcr_carrier_set_entry_sid = entry.lcr_carrier_set_entry_sid;
|
||||
delete entry.lcr_carrier_set_entry_sid;
|
||||
await LcrCarrierSetEntry.update(lcr_carrier_set_entry_sid, entry);
|
||||
}
|
||||
} else {
|
||||
// Route is not available yet, let create it now
|
||||
await addNewLcrRoute(lcr_route, lookupCarrierBySid);
|
||||
}
|
||||
}
|
||||
res.sendStatus(204);
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
|
||||
@@ -13,6 +13,8 @@ WHERE up.permission_sid = p.permission_sid
|
||||
AND up.user_sid = ?
|
||||
`;
|
||||
const retrieveSql = 'SELECT * from users where name = ?';
|
||||
const tokenSql = 'SELECT token from api_keys where account_sid IS NULL AND service_provider_sid IS NULL';
|
||||
|
||||
|
||||
router.post('/', async(req, res) => {
|
||||
const {logger, incrKey, retrieveKey} = req.app.locals;
|
||||
@@ -52,6 +54,11 @@ router.post('/', async(req, res) => {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
const force_change = !!r[0].force_change;
|
||||
const [t] = await promisePool.query(tokenSql);
|
||||
if (t.length === 0) {
|
||||
logger.error('Database has no admin token provisioned...run reset_admin_password');
|
||||
return res.sendStatus(500);
|
||||
}
|
||||
|
||||
const [p] = await promisePool.query(retrievePemissionsSql, r[0].user_sid);
|
||||
const permissions = p.map((x) => x.name);
|
||||
|
||||
@@ -94,9 +94,9 @@ decorate(router, PhoneNumber, ['add', 'update', 'delete'], preconditions);
|
||||
router.get('/', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
const results = req.user.hasServiceProviderAuth ?
|
||||
await PhoneNumber.retrieveAllForSP(req.user.service_provider_sid) :
|
||||
await PhoneNumber.retrieveAll(req.user.hasAccountAuth ? req.user.account_sid : null);
|
||||
const results = req.user.hasAdminAuth ?
|
||||
await PhoneNumber.retrieveAll(req.user.hasAccountAuth ? req.user.account_sid : null) :
|
||||
await PhoneNumber.retrieveAllForSP(req.user.service_provider_sid);
|
||||
res.status(200).json(results);
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
@@ -120,9 +120,6 @@ router.get('/:sid', async(req, res) => {
|
||||
throw new DbErrorBadRequest('insufficient privileges');
|
||||
}
|
||||
}
|
||||
if (req.user.hasAccountAuth && results.length > 1) {
|
||||
return res.status(200).json(results.filter((r) => r.phone_number_sid === sid)[0]);
|
||||
}
|
||||
return res.status(200).json(results[0]);
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
@@ -3,15 +3,6 @@ const sysError = require('../error');
|
||||
const {DbErrorBadRequest} = require('../../utils/errors');
|
||||
const {getHomerApiKey, getHomerSipTrace, getHomerPcap} = require('../../utils/homer-utils');
|
||||
const {getJaegerTrace} = require('../../utils/jaeger-utils');
|
||||
const Account = require('../../models/account');
|
||||
const {
|
||||
getS3Object,
|
||||
getGoogleStorageObject,
|
||||
getAzureStorageObject,
|
||||
deleteS3Object,
|
||||
deleteGoogleStorageObject,
|
||||
deleteAzureStorageObject
|
||||
} = require('../../utils/storage-utils');
|
||||
|
||||
const parseAccountSid = (url) => {
|
||||
const arr = /Accounts\/([^\/]*)/.exec(url);
|
||||
@@ -29,7 +20,7 @@ router.get('/', async(req, res) => {
|
||||
logger.debug({opts: req.query}, 'GET /RecentCalls');
|
||||
const account_sid = parseAccountSid(req.originalUrl);
|
||||
const service_provider_sid = account_sid ? null : parseServiceProviderSid(req.originalUrl);
|
||||
const {page, count, trunk, direction, days, answered, start, end, filter} = req.query || {};
|
||||
const {page, count, trunk, direction, days, answered, start, end} = req.query || {};
|
||||
if (!page || page < 1) throw new DbErrorBadRequest('missing or invalid "page" query arg');
|
||||
if (!count || count < 25 || count > 500) throw new DbErrorBadRequest('missing or invalid "count" query arg');
|
||||
|
||||
@@ -44,7 +35,6 @@ router.get('/', async(req, res) => {
|
||||
answered,
|
||||
start: days ? undefined : start,
|
||||
end: days ? undefined : end,
|
||||
filter
|
||||
});
|
||||
res.status(200).json(data);
|
||||
}
|
||||
@@ -59,7 +49,6 @@ router.get('/', async(req, res) => {
|
||||
answered,
|
||||
start: days ? undefined : start,
|
||||
end: days ? undefined : end,
|
||||
filter
|
||||
});
|
||||
res.status(200).json(data);
|
||||
}
|
||||
@@ -85,12 +74,12 @@ router.get('/:call_id', async(req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:call_id/:method/pcap', async(req, res) => {
|
||||
router.get('/:call_id/pcap', async(req, res) => {
|
||||
const {logger} = req.app.locals;
|
||||
try {
|
||||
const token = await getHomerApiKey(logger);
|
||||
if (!token) return res.sendStatus(400, {msg: 'getHomerApiKey: Failed to get Homer API token; check server config'});
|
||||
const stream = await getHomerPcap(logger, token, [req.params.call_id], req.params.method);
|
||||
const stream = await getHomerPcap(logger, token, [req.params.call_id]);
|
||||
if (!stream) {
|
||||
logger.info(`getHomerApiKey: unable to get sip traces from Homer for ${req.params.call_id}`);
|
||||
return res.sendStatus(404);
|
||||
@@ -122,84 +111,4 @@ router.get('/trace/:trace_id', async(req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/:call_sid/record/:year/:month/:day/:format', async(req, res) => {
|
||||
const {logger} = req.app.locals;
|
||||
const {call_sid, year, month, day, format} = req.params;
|
||||
|
||||
try {
|
||||
const account_sid = parseAccountSid(req.originalUrl);
|
||||
const r = await Account.retrieve(account_sid);
|
||||
if (r.length === 0 || !r[0].bucket_credential) return res.sendStatus(404);
|
||||
const {bucket_credential} = r[0];
|
||||
const getOptions = {
|
||||
...bucket_credential,
|
||||
key: `${year}/${month}/${day}/${call_sid}.${format || 'mp3'}`
|
||||
};
|
||||
let stream;
|
||||
switch (bucket_credential.vendor) {
|
||||
case 'aws_s3':
|
||||
case 's3_compatible':
|
||||
stream = await getS3Object(logger, getOptions);
|
||||
break;
|
||||
case 'google':
|
||||
stream = await getGoogleStorageObject(logger, getOptions);
|
||||
break;
|
||||
case 'azure':
|
||||
stream = await getAzureStorageObject(logger, getOptions);
|
||||
break;
|
||||
default:
|
||||
logger.error(`There is no handler for fetching record from ${bucket_credential.vendor}`);
|
||||
return res.sendStatus(500);
|
||||
}
|
||||
res.set({
|
||||
'Content-Type': `audio/${format || 'mp3'}`
|
||||
});
|
||||
if (stream) {
|
||||
stream.pipe(res);
|
||||
} else {
|
||||
return res.sendStatus(404);
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error({err}, ` error retrieving recording ${call_sid}`);
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:call_sid/record/:year/:month/:day/:format', async(req, res) => {
|
||||
const {logger} = req.app.locals;
|
||||
const {call_sid, year, month, day, format} = req.params;
|
||||
|
||||
try {
|
||||
const account_sid = parseAccountSid(req.originalUrl);
|
||||
const r = await Account.retrieve(account_sid);
|
||||
if (r.length === 0 || !r[0].bucket_credential) return res.sendStatus(404);
|
||||
const {bucket_credential} = r[0];
|
||||
|
||||
const deleteOptions = {
|
||||
...bucket_credential,
|
||||
key: `${year}/${month}/${day}/${call_sid}.${format || 'mp3'}`
|
||||
};
|
||||
|
||||
switch (bucket_credential.vendor) {
|
||||
case 'aws_s3':
|
||||
case 's3_compatible':
|
||||
await deleteS3Object(logger, deleteOptions);
|
||||
break;
|
||||
case 'google':
|
||||
await deleteGoogleStorageObject(logger, deleteOptions);
|
||||
break;
|
||||
case 'azure':
|
||||
await deleteAzureStorageObject(logger, deleteOptions);
|
||||
break;
|
||||
default:
|
||||
logger.error(`There is no handler for deleting record from ${bucket_credential.vendor}`);
|
||||
return res.sendStatus(500);
|
||||
}
|
||||
res.sendStatus(204);
|
||||
} catch (err) {
|
||||
logger.error({err}, ` error deleting recording ${call_sid}`);
|
||||
res.sendStatus(404);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -16,9 +16,8 @@ const insertUserSql = `INSERT into users
|
||||
(user_sid, account_sid, name, email, provider, provider_userid, email_validated)
|
||||
values (?, ?, ?, ?, ?, ?, 1)`;
|
||||
const insertUserLocalSql = `INSERT into users
|
||||
(user_sid, account_sid, name, email, email_activation_code, email_validated, provider,
|
||||
hashed_password, service_provider_sid)
|
||||
values (?, ?, ?, ?, ?, 0, 'local', ?, ?)`;
|
||||
(user_sid, account_sid, name, email, email_activation_code, email_validated, provider, hashed_password)
|
||||
values (?, ?, ?, ?, ?, 0, 'local', ?)`;
|
||||
const insertAccountSql = `INSERT into accounts
|
||||
(account_sid, service_provider_sid, name, is_active, webhook_secret, trial_end_date)
|
||||
values (?, ?, ?, ?, ?, CURDATE() + INTERVAL 21 DAY)`;
|
||||
@@ -37,7 +36,7 @@ const insertSignupHistorySql = `INSERT into signup_history
|
||||
values (?, ?)`;
|
||||
|
||||
const addLocalUser = async(logger, user_sid, account_sid,
|
||||
name, email, email_activation_code, passwordHash, service_provider_sid) => {
|
||||
name, email, email_activation_code, passwordHash) => {
|
||||
const [r] = await promisePool.execute(insertUserLocalSql,
|
||||
[
|
||||
user_sid,
|
||||
@@ -45,8 +44,7 @@ const addLocalUser = async(logger, user_sid, account_sid,
|
||||
name,
|
||||
email,
|
||||
email_activation_code,
|
||||
passwordHash,
|
||||
service_provider_sid
|
||||
passwordHash
|
||||
]);
|
||||
debug({r}, 'Result from adding user');
|
||||
};
|
||||
@@ -147,7 +145,7 @@ router.post('/', async(req, res) => {
|
||||
const user = await doGithubAuth(logger, req.body);
|
||||
logger.info({user}, 'retrieved user details from github');
|
||||
Object.assign(userProfile, {
|
||||
name: user.email,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
email_validated: user.email_validated,
|
||||
avatar_url: user.avatar_url,
|
||||
@@ -159,7 +157,7 @@ router.post('/', async(req, res) => {
|
||||
const user = await doGoogleAuth(logger, req.body);
|
||||
logger.info({user}, 'retrieved user details from google');
|
||||
Object.assign(userProfile, {
|
||||
name: user.email || user.email,
|
||||
name: user.name || user.email,
|
||||
email: user.email,
|
||||
email_validated: user.verified_email,
|
||||
picture: user.picture,
|
||||
@@ -172,7 +170,7 @@ router.post('/', async(req, res) => {
|
||||
logger.info({user}, 'retrieved user details for local provider');
|
||||
debug({user}, 'retrieved user details for local provider');
|
||||
Object.assign(userProfile, {
|
||||
name: user.email,
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
provider: 'local',
|
||||
email_activation_code: user.email_activation_code
|
||||
@@ -282,8 +280,7 @@ router.post('/', async(req, res) => {
|
||||
const passwordHash = await generateHashedPassword(req.body.password);
|
||||
debug(`hashed password: ${passwordHash}`);
|
||||
await addLocalUser(logger, userProfile.user_sid, userProfile.account_sid,
|
||||
userProfile.name, userProfile.email, userProfile.email_activation_code,
|
||||
passwordHash, req.body.service_provider_sid);
|
||||
userProfile.name, userProfile.email, userProfile.email_activation_code, passwordHash);
|
||||
debug('added local user');
|
||||
}
|
||||
else {
|
||||
@@ -296,25 +293,17 @@ router.post('/', async(req, res) => {
|
||||
const callStatusSid = uuid();
|
||||
const helloWordSid = uuid();
|
||||
const dialTimeSid = uuid();
|
||||
const echoSid = uuid();
|
||||
|
||||
/* 4 webhooks */
|
||||
await promisePool.execute(insertWebookSql,
|
||||
[callStatusSid, 'https://public-apps.jambonz.cloud/call-status', 'POST']);
|
||||
await promisePool.execute(insertWebookSql,
|
||||
[helloWordSid, 'https://public-apps.jambonz.cloud/hello-world', 'POST']);
|
||||
await promisePool.execute(insertWebookSql,
|
||||
[dialTimeSid, 'https://public-apps.jambonz.cloud/dial-time', 'POST']);
|
||||
await promisePool.execute(insertWebookSql,
|
||||
[echoSid, 'https://public-apps.jambonz.cloud/echo', 'POST']);
|
||||
/* 3 webhooks */
|
||||
await promisePool.execute(insertWebookSql, [callStatusSid, 'https://public-apps.jambonz.us/call-status', 'POST']);
|
||||
await promisePool.execute(insertWebookSql, [helloWordSid, 'https://public-apps.jambonz.us/hello-world', 'POST']);
|
||||
await promisePool.execute(insertWebookSql, [dialTimeSid, 'https://public-apps.jambonz.us/dial-time', 'POST']);
|
||||
|
||||
/* 2 applications */
|
||||
await promisePool.execute(insertApplicationSql, [uuid(), userProfile.account_sid, 'hello world',
|
||||
helloWordSid, callStatusSid, 'google', 'en-US', 'en-US-Wavenet-C', 'google', 'en-US']);
|
||||
await promisePool.execute(insertApplicationSql, [uuid(), userProfile.account_sid, 'dial time clock',
|
||||
dialTimeSid, callStatusSid, 'google', 'en-US', 'en-US-Wavenet-C', 'google', 'en-US']);
|
||||
await promisePool.execute(insertApplicationSql, [uuid(), userProfile.account_sid, 'simple echo test',
|
||||
echoSid, callStatusSid, 'google', 'en-US', 'en-US-Wavenet-C', 'google', 'en-US']);
|
||||
|
||||
Object.assign(userProfile, {
|
||||
pristine: true,
|
||||
@@ -338,7 +327,7 @@ router.post('/', async(req, res) => {
|
||||
|
||||
await addLocalUser(logger, userProfile.user_sid, userProfile.account_sid,
|
||||
userProfile.name, userProfile.email, userProfile.email_activation_code,
|
||||
passwordHash, req.body.service_provider_sid);
|
||||
passwordHash);
|
||||
|
||||
/* note: we deactivate the old user once the new email is validated */
|
||||
}
|
||||
@@ -360,8 +349,6 @@ router.post('/', async(req, res) => {
|
||||
const token = jwt.sign({
|
||||
user_sid: userProfile.user_sid,
|
||||
account_sid: userProfile.account_sid,
|
||||
service_provider_sid: req.body.service_provider_sid,
|
||||
scope: 'account',
|
||||
email: userProfile.email,
|
||||
name: userProfile.name
|
||||
}, process.env.JWT_SECRET, { expiresIn });
|
||||
|
||||
@@ -28,13 +28,20 @@ router.get('/', async(req, res) => {
|
||||
|
||||
if (req.user.hasAccountAuth) {
|
||||
const [r] = await promisePool.query('SELECT * from accounts WHERE account_sid = ?', req.user.account_sid);
|
||||
if (0 === r.length) throw new DbErrorBadRequest('invalid account_sid');
|
||||
if (0 === r.length) throw new Error('invalid account_sid');
|
||||
|
||||
service_provider_sid = r[0].service_provider_sid;
|
||||
}
|
||||
|
||||
if (req.user.hasServiceProviderAuth) {
|
||||
service_provider_sid = req.user.service_provider_sid;
|
||||
const [r] = await promisePool.query(
|
||||
'SELECT * from service_providers where service_provider_sid = ?',
|
||||
service_provider_sid);
|
||||
if (0 === r.length) throw new Error('invalid account_sid');
|
||||
|
||||
service_provider_sid = r[0].service_provider_sid;
|
||||
|
||||
if (!service_provider_sid) throw new DbErrorBadRequest('missing service_provider_sid in query');
|
||||
}
|
||||
|
||||
/** generally, we have a global set of SBCs that all accounts use.
|
||||
|
||||
@@ -41,7 +41,6 @@ const checkUserScope = async(req, voip_carrier_sid) => {
|
||||
|
||||
const validate = async(req, sid) => {
|
||||
const {lookupSipGatewayBySid} = req.app.locals;
|
||||
const {netmask} = req.body;
|
||||
let voip_carrier_sid;
|
||||
|
||||
if (sid) {
|
||||
@@ -53,12 +52,6 @@ const validate = async(req, sid) => {
|
||||
voip_carrier_sid = req.body.voip_carrier_sid;
|
||||
if (!voip_carrier_sid) throw new DbErrorBadRequest('missing voip_carrier_sid');
|
||||
}
|
||||
if (netmask &&
|
||||
process.env.JAMBONZ_MIN_GATEWAY_NETMASK &&
|
||||
parseInt(netmask) < process.env.JAMBONZ_MIN_GATEWAY_NETMASK) {
|
||||
throw new DbErrorBadRequest(
|
||||
`netmask required to have value equal or greater than ${process.env.JAMBONZ_MIN_GATEWAY_NETMASK}`);
|
||||
}
|
||||
await checkUserScope(req, voip_carrier_sid);
|
||||
};
|
||||
|
||||
|
||||
@@ -31,7 +31,6 @@ router.post('/:sip_realm', async(req, res) => {
|
||||
const [sbcs] = await promisePool.query('SELECT ipv4 from sbc_addresses');
|
||||
if (sbcs.length === 0) throw new Error('no SBC addresses provisioned in the database!');
|
||||
const ips = sbcs.map((s) => s.ipv4);
|
||||
const uniqueIps = [...new Set(ips)];
|
||||
|
||||
/* retrieve existing dns records */
|
||||
const [old_recs] = await promisePool.query('SELECT record_id from dns_records WHERE account_sid = ?',
|
||||
@@ -49,7 +48,7 @@ router.post('/:sip_realm', async(req, res) => {
|
||||
}
|
||||
|
||||
/* add the dns records */
|
||||
const records = await createDnsRecords(logger, domain, subdomain, uniqueIps);
|
||||
const records = await createDnsRecords(logger, domain, subdomain, ips);
|
||||
if (!records) throw new Error(`failure updating dns records for ${sip_realm}`);
|
||||
const values = records.map((r) => {
|
||||
return `('${uuid()}', '${account_sid}', '${r.type}', ${r.id})`;
|
||||
|
||||
@@ -14,14 +14,20 @@ const getFsUrl = async(logger, retrieveSet, setName, provider) => {
|
||||
logger.info('No available feature servers to handle createCall API request');
|
||||
return ;
|
||||
}
|
||||
const f = fs[idx++ % fs.length];
|
||||
logger.info({fs}, `feature servers available for createCall API request, selecting ${f}`);
|
||||
return `${f}/v1/messaging/${provider}`;
|
||||
const ip = stripPort(fs[idx++ % fs.length]);
|
||||
logger.info({fs}, `feature servers available for createCall API request, selecting ${ip}`);
|
||||
return `http://${ip}:3000/v1/messaging/${provider}`;
|
||||
} catch (err) {
|
||||
logger.error({err}, 'getFsUrl: error retreving feature servers from redis');
|
||||
}
|
||||
};
|
||||
|
||||
const stripPort = (hostport) => {
|
||||
const arr = /^(.*):(.*)$/.exec(hostport);
|
||||
if (arr) return arr[1];
|
||||
return hostport;
|
||||
};
|
||||
|
||||
const doSendResponse = async(res, respondFn, body) => {
|
||||
if (typeof respondFn === 'number') res.sendStatus(respondFn);
|
||||
else if (typeof respondFn !== 'function') res.sendStatus(200);
|
||||
@@ -38,7 +44,7 @@ router.post('/:provider', async(req, res) => {
|
||||
lookupAppByPhoneNumber,
|
||||
logger
|
||||
} = req.app.locals;
|
||||
const setName = `${process.env.JAMBONES_CLUSTER_ID || 'default'}:fs-service-url`;
|
||||
const setName = `${process.env.JAMBONES_CLUSTER_ID || 'default'}:active-fs`;
|
||||
logger.debug({path: req.path, body: req.body}, 'incomingSMS from carrier');
|
||||
|
||||
// search for provider module
|
||||
|
||||
@@ -5,13 +5,7 @@ const SpeechCredential = require('../../models/speech-credential');
|
||||
const sysError = require('../error');
|
||||
const {decrypt, encrypt} = require('../../utils/encrypt-decrypt');
|
||||
const {parseAccountSid, parseServiceProviderSid, parseSpeechCredentialSid} = require('./utils');
|
||||
const {decryptCredential, testWhisper, testDeepgramTTS,
|
||||
getLanguagesAndVoicesForVendor,
|
||||
testPlayHT,
|
||||
testRimelabs,
|
||||
testVerbioTts,
|
||||
testVerbioStt} = require('../../utils/speech-utils');
|
||||
const {DbErrorUnprocessableRequest, DbErrorForbidden, DbErrorBadRequest} = require('../../utils/errors');
|
||||
const {DbErrorUnprocessableRequest, DbErrorForbidden} = require('../../utils/errors');
|
||||
const {
|
||||
testGoogleTts,
|
||||
testGoogleStt,
|
||||
@@ -25,9 +19,7 @@ const {
|
||||
testDeepgramStt,
|
||||
testSonioxStt,
|
||||
testIbmTts,
|
||||
testIbmStt,
|
||||
testElevenlabs,
|
||||
testAssemblyStt
|
||||
testIbmStt
|
||||
} = require('../../utils/speech-utils');
|
||||
const {promisePool} = require('../../db');
|
||||
|
||||
@@ -107,6 +99,17 @@ const validateTest = async(req, speech_credentials) => {
|
||||
}
|
||||
};
|
||||
|
||||
const obscureKey = (key) => {
|
||||
const key_spoiler_length = 6;
|
||||
const key_spoiler_char = 'X';
|
||||
|
||||
if (key.length <= key_spoiler_length) {
|
||||
return key;
|
||||
}
|
||||
|
||||
return `${key.slice(0, key_spoiler_length)}${key_spoiler_char.repeat(key.length - key_spoiler_length)}`;
|
||||
};
|
||||
|
||||
const encryptCredential = (obj) => {
|
||||
const {
|
||||
vendor,
|
||||
@@ -115,22 +118,15 @@ const encryptCredential = (obj) => {
|
||||
secret_access_key,
|
||||
aws_region,
|
||||
api_key,
|
||||
role_arn,
|
||||
region,
|
||||
client_id,
|
||||
client_secret,
|
||||
secret,
|
||||
nuance_tts_uri,
|
||||
nuance_stt_uri,
|
||||
deepgram_stt_uri,
|
||||
deepgram_stt_use_tls,
|
||||
deepgram_tts_uri,
|
||||
use_custom_tts,
|
||||
custom_tts_endpoint,
|
||||
custom_tts_endpoint_url,
|
||||
use_custom_stt,
|
||||
custom_stt_endpoint,
|
||||
custom_stt_endpoint_url,
|
||||
tts_api_key,
|
||||
tts_region,
|
||||
stt_api_key,
|
||||
@@ -139,13 +135,7 @@ const encryptCredential = (obj) => {
|
||||
instance_id,
|
||||
custom_stt_url,
|
||||
custom_tts_url,
|
||||
auth_token = '',
|
||||
cobalt_server_uri,
|
||||
model_id,
|
||||
user_id,
|
||||
voice_engine,
|
||||
engine_version,
|
||||
options
|
||||
auth_token = ''
|
||||
} = obj;
|
||||
|
||||
switch (vendor) {
|
||||
@@ -161,33 +151,22 @@ const encryptCredential = (obj) => {
|
||||
return encrypt(service_key);
|
||||
|
||||
case 'aws':
|
||||
// AWS polly can work for 3 types of credentials:
|
||||
// 1/ access_key_id and secret_access_key
|
||||
// 2/ RoleArn Assume role
|
||||
// 3/ RoleArn assigned to instance profile where will run this application
|
||||
const awsData = JSON.stringify(
|
||||
{
|
||||
aws_region,
|
||||
...(access_key_id && {access_key_id}),
|
||||
...(secret_access_key && {secret_access_key}),
|
||||
...(role_arn && {role_arn}),
|
||||
});
|
||||
assert(access_key_id, 'invalid aws speech credential: access_key_id is required');
|
||||
assert(secret_access_key, 'invalid aws speech credential: secret_access_key is required');
|
||||
assert(aws_region, 'invalid aws speech credential: aws_region is required');
|
||||
const awsData = JSON.stringify({aws_region, access_key_id, secret_access_key});
|
||||
return encrypt(awsData);
|
||||
|
||||
case 'microsoft':
|
||||
if (!custom_tts_endpoint_url && !custom_stt_endpoint_url) {
|
||||
assert(region, 'invalid azure speech credential: region is required');
|
||||
assert(api_key, 'invalid azure speech credential: api_key is required');
|
||||
}
|
||||
assert(region, 'invalid azure speech credential: region is required');
|
||||
assert(api_key, 'invalid azure speech credential: api_key is required');
|
||||
const azureData = JSON.stringify({
|
||||
...(region && {region}),
|
||||
...(api_key && {api_key}),
|
||||
region,
|
||||
api_key,
|
||||
use_custom_tts,
|
||||
custom_tts_endpoint,
|
||||
custom_tts_endpoint_url,
|
||||
use_custom_stt,
|
||||
custom_stt_endpoint,
|
||||
custom_stt_endpoint_url
|
||||
custom_stt_endpoint
|
||||
});
|
||||
return encrypt(azureData);
|
||||
|
||||
@@ -204,11 +183,8 @@ const encryptCredential = (obj) => {
|
||||
return encrypt(nuanceData);
|
||||
|
||||
case 'deepgram':
|
||||
// API key is optional if onprem
|
||||
if (!deepgram_stt_uri || !deepgram_tts_uri) {
|
||||
assert(api_key, 'invalid deepgram speech credential: api_key is required');
|
||||
}
|
||||
const deepgramData = JSON.stringify({api_key, deepgram_stt_uri, deepgram_stt_use_tls, deepgram_tts_uri});
|
||||
assert(api_key, 'invalid deepgram speech credential: api_key is required');
|
||||
const deepgramData = JSON.stringify({api_key});
|
||||
return encrypt(deepgramData);
|
||||
|
||||
case 'ibm':
|
||||
@@ -225,48 +201,6 @@ const encryptCredential = (obj) => {
|
||||
const sonioxData = JSON.stringify({api_key});
|
||||
return encrypt(sonioxData);
|
||||
|
||||
case 'cobalt':
|
||||
assert(cobalt_server_uri, 'invalid cobalt speech credential: cobalt_server_uri is required');
|
||||
const cobaltData = JSON.stringify({cobalt_server_uri});
|
||||
return encrypt(cobaltData);
|
||||
|
||||
case 'elevenlabs':
|
||||
assert(api_key, 'invalid elevenLabs speech credential: api_key is required');
|
||||
assert(model_id, 'invalid elevenLabs speech credential: model_id is required');
|
||||
const elevenlabsData = JSON.stringify({api_key, model_id, options});
|
||||
return encrypt(elevenlabsData);
|
||||
|
||||
case 'playht':
|
||||
assert(api_key, 'invalid playht speech credential: api_key is required');
|
||||
assert(user_id, 'invalid playht speech credential: user_id is required');
|
||||
assert(voice_engine, 'invalid voice_engine speech credential: voice_engine is required');
|
||||
const playhtData = JSON.stringify({api_key, user_id, voice_engine, options});
|
||||
return encrypt(playhtData);
|
||||
|
||||
case 'rimelabs':
|
||||
assert(api_key, 'invalid rimelabs speech credential: api_key is required');
|
||||
assert(model_id, 'invalid rimelabs speech credential: model_id is required');
|
||||
const rimelabsData = JSON.stringify({api_key, model_id, options});
|
||||
return encrypt(rimelabsData);
|
||||
|
||||
case 'assemblyai':
|
||||
assert(api_key, 'invalid assemblyai speech credential: api_key is required');
|
||||
const assemblyaiData = JSON.stringify({api_key});
|
||||
return encrypt(assemblyaiData);
|
||||
|
||||
case 'whisper':
|
||||
assert(api_key, 'invalid whisper speech credential: api_key is required');
|
||||
assert(model_id, 'invalid whisper speech credential: model_id is required');
|
||||
const whisperData = JSON.stringify({api_key, model_id});
|
||||
return encrypt(whisperData);
|
||||
|
||||
case 'verbio':
|
||||
assert(engine_version, 'invalid verbio speech credential: client_id is required');
|
||||
assert(client_id, 'invalid verbio speech credential: client_id is required');
|
||||
assert(client_secret, 'invalid verbio speech credential: secret is required');
|
||||
const verbioData = JSON.stringify({client_id, client_secret, engine_version});
|
||||
return encrypt(verbioData);
|
||||
|
||||
default:
|
||||
if (vendor.startsWith('custom:')) {
|
||||
const customData = JSON.stringify({auth_token, custom_stt_url, custom_tts_url});
|
||||
@@ -284,7 +218,6 @@ router.post('/', async(req, res) => {
|
||||
use_for_stt,
|
||||
use_for_tts,
|
||||
vendor,
|
||||
label
|
||||
} = req.body;
|
||||
const account_sid = req.user.account_sid || req.body.account_sid;
|
||||
const service_provider_sid = req.user.service_provider_sid ||
|
||||
@@ -299,21 +232,11 @@ router.post('/', async(req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if vendor and label is already used for account or SP
|
||||
if (label) {
|
||||
const existingSpeech = await SpeechCredential.getSpeechCredentialsByVendorAndLabel(
|
||||
service_provider_sid, account_sid, vendor, label);
|
||||
if (existingSpeech.length > 0) {
|
||||
throw new DbErrorUnprocessableRequest(`Label ${label} is already in use for another speech credential`);
|
||||
}
|
||||
}
|
||||
|
||||
const encrypted_credential = encryptCredential(req.body);
|
||||
const uuid = await SpeechCredential.make({
|
||||
account_sid,
|
||||
service_provider_sid,
|
||||
vendor,
|
||||
label,
|
||||
use_for_tts,
|
||||
use_for_stt,
|
||||
credential: encrypted_credential
|
||||
@@ -350,7 +273,66 @@ router.get('/', async(req, res) => {
|
||||
res.status(200).json(creds.map((c) => {
|
||||
const {credential, ...obj} = c;
|
||||
|
||||
decryptCredential(obj, credential, logger);
|
||||
if ('google' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
const key_header = '-----BEGIN PRIVATE KEY-----\n';
|
||||
const obscured = {
|
||||
...o,
|
||||
private_key: `${key_header}${obscureKey(o.private_key.slice(key_header.length, o.private_key.length))}`
|
||||
};
|
||||
obj.service_key = obscured;
|
||||
}
|
||||
else if ('aws' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.access_key_id = o.access_key_id;
|
||||
obj.secret_access_key = obscureKey(o.secret_access_key);
|
||||
obj.aws_region = o.aws_region;
|
||||
logger.info({obj, o}, 'retrieving aws speech credential');
|
||||
}
|
||||
else if ('microsoft' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = obscureKey(o.api_key);
|
||||
obj.region = o.region;
|
||||
obj.use_custom_tts = o.use_custom_tts;
|
||||
obj.custom_tts_endpoint = o.custom_tts_endpoint;
|
||||
obj.use_custom_stt = o.use_custom_stt;
|
||||
obj.custom_stt_endpoint = o.custom_stt_endpoint;
|
||||
logger.info({obj, o}, 'retrieving azure speech credential');
|
||||
}
|
||||
else if ('wellsaid' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = obscureKey(o.api_key);
|
||||
}
|
||||
else if ('nuance' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.client_id = o.client_id;
|
||||
obj.secret = o.secret ? obscureKey(o.secret) : null;
|
||||
}
|
||||
else if ('deepgram' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = obscureKey(o.api_key);
|
||||
}
|
||||
else if ('ibm' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.tts_api_key = obscureKey(o.tts_api_key);
|
||||
obj.tts_region = o.tts_region;
|
||||
obj.stt_api_key = obscureKey(o.stt_api_key);
|
||||
obj.stt_region = o.stt_region;
|
||||
obj.instance_id = o.instance_id;
|
||||
} else if ('nvidia' == obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.riva_server_uri = o.riva_server_uri;
|
||||
}
|
||||
else if ('soniox' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = obscureKey(o.api_key);
|
||||
}
|
||||
else if (obj.vendor.startsWith('custom:')) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.auth_token = obscureKey(o.auth_token);
|
||||
obj.custom_stt_url = o.custom_stt_url;
|
||||
obj.custom_tts_url = o.custom_tts_url;
|
||||
}
|
||||
|
||||
if (req.user.hasAccountAuth && obj.account_sid === null) {
|
||||
delete obj.api_key;
|
||||
@@ -380,7 +362,66 @@ router.get('/:sid', async(req, res) => {
|
||||
await validateRetrieveUpdateDelete(req, cred);
|
||||
|
||||
const {credential, ...obj} = cred[0];
|
||||
decryptCredential(obj, credential, logger);
|
||||
if ('google' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
const key_header = '-----BEGIN PRIVATE KEY-----\n';
|
||||
const obscured = {
|
||||
...o,
|
||||
private_key: `${key_header}${obscureKey(o.private_key.slice(key_header.length, o.private_key.length))}`
|
||||
};
|
||||
obj.service_key = JSON.stringify(obscured);
|
||||
}
|
||||
else if ('aws' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.access_key_id = o.access_key_id;
|
||||
obj.secret_access_key = obscureKey(o.secret_access_key);
|
||||
obj.aws_region = o.aws_region;
|
||||
}
|
||||
else if ('microsoft' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = obscureKey(o.api_key);
|
||||
obj.region = o.region;
|
||||
obj.use_custom_tts = o.use_custom_tts;
|
||||
obj.custom_tts_endpoint = o.custom_tts_endpoint;
|
||||
obj.use_custom_stt = o.use_custom_stt;
|
||||
obj.custom_stt_endpoint = o.custom_stt_endpoint;
|
||||
}
|
||||
else if ('wellsaid' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = obscureKey(o.api_key);
|
||||
}
|
||||
else if ('nuance' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.client_id = o.client_id;
|
||||
obj.secret = o.secret ? obscureKey(o.secret) : null;
|
||||
obj.nuance_tts_uri = o.nuance_tts_uri;
|
||||
obj.nuance_stt_uri = o.nuance_stt_uri;
|
||||
}
|
||||
else if ('deepgram' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = obscureKey(o.api_key);
|
||||
}
|
||||
else if ('ibm' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.tts_api_key = obscureKey(o.tts_api_key);
|
||||
obj.tts_region = o.tts_region;
|
||||
obj.stt_api_key = obscureKey(o.stt_api_key);
|
||||
obj.stt_region = o.stt_region;
|
||||
obj.instance_id = o.instance_id;
|
||||
} else if ('nvidia' == obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.riva_server_uri = o.riva_server_uri;
|
||||
}
|
||||
else if ('soniox' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = obscureKey(o.api_key);
|
||||
}
|
||||
else if (obj.vendor.startsWith('custom:')) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.auth_token = obscureKey(o.auth_token);
|
||||
obj.custom_stt_url = o.custom_stt_url;
|
||||
obj.custom_tts_url = o.custom_tts_url;
|
||||
}
|
||||
|
||||
if (req.user.hasAccountAuth && obj.account_sid === null) {
|
||||
delete obj.api_key;
|
||||
@@ -447,20 +488,8 @@ router.put('/:sid', async(req, res) => {
|
||||
const {
|
||||
use_custom_tts,
|
||||
custom_tts_endpoint,
|
||||
custom_tts_endpoint_url,
|
||||
use_custom_stt,
|
||||
custom_stt_endpoint,
|
||||
custom_stt_endpoint_url,
|
||||
custom_stt_url,
|
||||
custom_tts_url,
|
||||
cobalt_server_uri,
|
||||
model_id,
|
||||
voice_engine,
|
||||
options,
|
||||
deepgram_stt_uri,
|
||||
deepgram_stt_use_tls,
|
||||
deepgram_tts_uri,
|
||||
engine_version
|
||||
custom_stt_endpoint
|
||||
} = req.body;
|
||||
|
||||
const newCred = {
|
||||
@@ -470,25 +499,13 @@ router.put('/:sid', async(req, res) => {
|
||||
aws_region,
|
||||
use_custom_tts,
|
||||
custom_tts_endpoint,
|
||||
custom_tts_endpoint_url,
|
||||
use_custom_stt,
|
||||
custom_stt_endpoint,
|
||||
custom_stt_endpoint_url,
|
||||
stt_region,
|
||||
tts_region,
|
||||
riva_server_uri,
|
||||
nuance_stt_uri,
|
||||
nuance_tts_uri,
|
||||
custom_stt_url,
|
||||
custom_tts_url,
|
||||
cobalt_server_uri,
|
||||
model_id,
|
||||
voice_engine,
|
||||
options,
|
||||
deepgram_stt_uri,
|
||||
deepgram_stt_use_tls,
|
||||
deepgram_tts_uri,
|
||||
engine_version
|
||||
nuance_tts_uri
|
||||
};
|
||||
logger.info({o, newCred}, 'updating speech credential with this new credential');
|
||||
obj.credential = encryptCredential(newCred);
|
||||
@@ -517,7 +534,7 @@ router.put('/:sid', async(req, res) => {
|
||||
* Test a credential
|
||||
*/
|
||||
router.get('/:sid/test', async(req, res) => {
|
||||
const {logger, synthAudio, getVerbioAccessToken} = req.app.locals;
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
const sid = parseSpeechCredentialSid(req);
|
||||
const creds = await SpeechCredential.retrieve(sid);
|
||||
@@ -565,13 +582,12 @@ router.get('/:sid/test', async(req, res) => {
|
||||
}
|
||||
}
|
||||
else if (cred.vendor === 'aws') {
|
||||
const {getTtsVoices, getAwsAuthToken} = req.app.locals;
|
||||
if (cred.use_for_tts) {
|
||||
const {getTtsVoices} = req.app.locals;
|
||||
try {
|
||||
await testAwsTts(logger, getTtsVoices, {
|
||||
accessKeyId: credential.access_key_id,
|
||||
secretAccessKey: credential.secret_access_key,
|
||||
roleArn: credential.role_arn,
|
||||
region: credential.aws_region || process.env.AWS_REGION
|
||||
});
|
||||
results.tts.status = 'ok';
|
||||
@@ -583,10 +599,9 @@ router.get('/:sid/test', async(req, res) => {
|
||||
}
|
||||
if (cred.use_for_stt) {
|
||||
try {
|
||||
await testAwsStt(logger, getAwsAuthToken, {
|
||||
await testAwsStt(logger, {
|
||||
accessKeyId: credential.access_key_id,
|
||||
secretAccessKey: credential.secret_access_key,
|
||||
roleArn: credential.role_arn,
|
||||
region: credential.aws_region || process.env.AWS_REGION
|
||||
});
|
||||
results.stt.status = 'ok';
|
||||
@@ -603,22 +618,18 @@ router.get('/:sid/test', async(req, res) => {
|
||||
region,
|
||||
use_custom_tts,
|
||||
custom_tts_endpoint,
|
||||
custom_tts_endpoint_url,
|
||||
use_custom_stt,
|
||||
custom_stt_endpoint,
|
||||
custom_stt_endpoint_url
|
||||
custom_stt_endpoint
|
||||
} = credential;
|
||||
if (cred.use_for_tts) {
|
||||
try {
|
||||
await testMicrosoftTts(logger, synthAudio, {
|
||||
await testMicrosoftTts(logger, {
|
||||
api_key,
|
||||
region,
|
||||
use_custom_tts,
|
||||
custom_tts_endpoint,
|
||||
custom_tts_endpoint_url,
|
||||
use_custom_stt,
|
||||
custom_stt_endpoint,
|
||||
custom_stt_endpoint_url
|
||||
custom_stt_endpoint
|
||||
});
|
||||
results.tts.status = 'ok';
|
||||
SpeechCredential.ttsTestResult(sid, true);
|
||||
@@ -629,7 +640,7 @@ router.get('/:sid/test', async(req, res) => {
|
||||
}
|
||||
if (cred.use_for_stt) {
|
||||
try {
|
||||
await testMicrosoftStt(logger, {api_key, region, use_custom_stt, custom_stt_endpoint_url});
|
||||
await testMicrosoftStt(logger, {api_key, region});
|
||||
results.stt.status = 'ok';
|
||||
SpeechCredential.sttTestResult(sid, true);
|
||||
} catch (err) {
|
||||
@@ -688,19 +699,10 @@ router.get('/:sid/test', async(req, res) => {
|
||||
SpeechCredential.sttTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
} else if (cred.vendor === 'deepgram') {
|
||||
}
|
||||
else if (cred.vendor === 'deepgram') {
|
||||
const {api_key} = credential;
|
||||
if (cred.use_for_tts) {
|
||||
try {
|
||||
await testDeepgramTTS(logger, synthAudio, credential);
|
||||
results.tts.status = 'ok';
|
||||
SpeechCredential.ttsTestResult(sid, true);
|
||||
} catch (err) {
|
||||
results.tts = {status: 'fail', reason: err.message};
|
||||
SpeechCredential.ttsTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
if (cred.use_for_stt && api_key) {
|
||||
if (cred.use_for_stt) {
|
||||
try {
|
||||
await testDeepgramStt(logger, {api_key});
|
||||
results.stt.status = 'ok';
|
||||
@@ -756,89 +758,6 @@ router.get('/:sid/test', async(req, res) => {
|
||||
SpeechCredential.sttTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
} else if (cred.vendor === 'elevenlabs') {
|
||||
const {api_key, model_id} = credential;
|
||||
if (cred.use_for_tts) {
|
||||
try {
|
||||
await testElevenlabs(logger, {api_key, model_id});
|
||||
results.tts.status = 'ok';
|
||||
SpeechCredential.ttsTestResult(sid, true);
|
||||
} catch (err) {
|
||||
results.tts = {status: 'fail', reason: err.message};
|
||||
SpeechCredential.ttsTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
} else if (cred.vendor === 'playht') {
|
||||
if (cred.use_for_tts) {
|
||||
try {
|
||||
await testPlayHT(logger, synthAudio, credential);
|
||||
results.tts.status = 'ok';
|
||||
SpeechCredential.ttsTestResult(sid, true);
|
||||
} catch (err) {
|
||||
let reason = err.message;
|
||||
// if error is from bent, let get the body
|
||||
try {
|
||||
reason = await err.text();
|
||||
} catch {}
|
||||
results.tts = {status: 'fail', reason};
|
||||
SpeechCredential.ttsTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
} else if (cred.vendor === 'rimelabs') {
|
||||
if (cred.use_for_tts) {
|
||||
try {
|
||||
await testRimelabs(logger, synthAudio, credential);
|
||||
results.tts.status = 'ok';
|
||||
SpeechCredential.ttsTestResult(sid, true);
|
||||
} catch (err) {
|
||||
results.tts = {status: 'fail', reason: err.message};
|
||||
SpeechCredential.ttsTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
} else if (cred.vendor === 'assemblyai') {
|
||||
const {api_key} = credential;
|
||||
if (cred.use_for_stt) {
|
||||
try {
|
||||
await testAssemblyStt(logger, {api_key});
|
||||
results.stt.status = 'ok';
|
||||
SpeechCredential.sttTestResult(sid, true);
|
||||
} catch (err) {
|
||||
results.stt = {status: 'fail', reason: err.message};
|
||||
SpeechCredential.sttTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
} else if (cred.vendor === 'whisper') {
|
||||
if (cred.use_for_tts) {
|
||||
try {
|
||||
await testWhisper(logger, synthAudio, credential);
|
||||
results.tts.status = 'ok';
|
||||
SpeechCredential.ttsTestResult(sid, true);
|
||||
} catch (err) {
|
||||
results.tts = {status: 'fail', reason: err.message};
|
||||
SpeechCredential.ttsTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
} else if (cred.vendor === 'verbio') {
|
||||
if (cred.use_for_tts) {
|
||||
try {
|
||||
await testVerbioTts(logger, synthAudio, credential);
|
||||
results.tts.status = 'ok';
|
||||
SpeechCredential.ttsTestResult(sid, true);
|
||||
} catch (err) {
|
||||
results.tts = {status: 'fail', reason: err.message};
|
||||
SpeechCredential.ttsTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
if (cred.use_for_stt) {
|
||||
try {
|
||||
await testVerbioStt(logger, getVerbioAccessToken, credential);
|
||||
results.stt.status = 'ok';
|
||||
SpeechCredential.sttTestResult(sid, true);
|
||||
} catch (err) {
|
||||
results.stt = {status: 'fail', reason: err.message};
|
||||
SpeechCredential.sttTestResult(sid, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.status(200).json(results);
|
||||
@@ -848,34 +767,4 @@ router.get('/:sid/test', async(req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Fetch speech voices and languages
|
||||
*/
|
||||
|
||||
router.get('/speech/supportedLanguagesAndVoices', async(req, res) => {
|
||||
const {logger, getTtsVoices} = req.app.locals;
|
||||
try {
|
||||
const {vendor, label} = req.query;
|
||||
if (!vendor) {
|
||||
throw new DbErrorBadRequest('vendor is required');
|
||||
}
|
||||
const account_sid = req.user.account_sid || req.body.account_sid;
|
||||
const service_provider_sid = req.user.service_provider_sid ||
|
||||
req.body.service_provider_sid || parseServiceProviderSid(req);
|
||||
|
||||
const credentials = await SpeechCredential.getSpeechCredentialsByVendorAndLabel(
|
||||
service_provider_sid, account_sid, vendor, label);
|
||||
const tmp = credentials && credentials.length > 0 ? credentials[0] : null;
|
||||
const cred = tmp ? JSON.parse(decrypt(tmp.credential)) : null;
|
||||
try {
|
||||
const data = await getLanguagesAndVoicesForVendor(logger, vendor, cred, getTtsVoices);
|
||||
res.status(200).json(data);
|
||||
} catch (err) {
|
||||
throw new DbErrorUnprocessableRequest(err.message);
|
||||
}
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
const router = require('express').Router();
|
||||
const {
|
||||
parseAccountSid
|
||||
} = require('./utils');
|
||||
const SpeechCredential = require('../../models/speech-credential');
|
||||
const fs = require('fs');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const {DbErrorBadRequest} = require('../../utils/errors');
|
||||
const Account = require('../../models/account');
|
||||
const sysError = require('../error');
|
||||
const { getSpeechCredential, decryptCredential } = require('../../utils/speech-utils');
|
||||
const PCMToMP3Encoder = require('../../record/encoder');
|
||||
const { pipeline } = require('stream');
|
||||
|
||||
router.delete('/', async(req, res) => {
|
||||
const {purgeTtsCache} = req.app.locals;
|
||||
const account_sid = parseAccountSid(req);
|
||||
if (account_sid) {
|
||||
await purgeTtsCache({account_sid});
|
||||
} else {
|
||||
await purgeTtsCache();
|
||||
}
|
||||
res.sendStatus(204);
|
||||
});
|
||||
|
||||
router.get('/', async(req, res) => {
|
||||
const {getTtsSize} = req.app.locals;
|
||||
const account_sid = parseAccountSid(req);
|
||||
let size = 0;
|
||||
if (account_sid) {
|
||||
size = await getTtsSize(`tts:${account_sid}:*`);
|
||||
} else {
|
||||
size = await getTtsSize();
|
||||
}
|
||||
res.status(200).json({size});
|
||||
});
|
||||
|
||||
router.post('/Synthesize', async(req, res) => {
|
||||
const {logger, synthAudio} = req.app.locals;
|
||||
try {
|
||||
const accountSid = parseAccountSid(req);
|
||||
const body = req.body;
|
||||
const encodingMp3 = req.body.encodingMp3 || false;
|
||||
if (!body.speech_credential_sid || !body.text || !body.language || !body.voice) {
|
||||
throw new DbErrorBadRequest('speech_credential_sid, text, language, voice are all required');
|
||||
}
|
||||
|
||||
const result = await Account.retrieve(accountSid);
|
||||
if (!result || result.length === 0 || !result[0].is_active) {
|
||||
throw new DbErrorBadRequest(`Account not found for sid ${accountSid}`);
|
||||
}
|
||||
const credentials = await SpeechCredential.retrieve(body.speech_credential_sid);
|
||||
if (!credentials || credentials.length === 0) {
|
||||
throw new
|
||||
DbErrorBadRequest(`There is no available speech credential for ${body.speech_credential_sid}`);
|
||||
}
|
||||
const {credential, ...obj} = credentials[0];
|
||||
|
||||
decryptCredential(obj, credential, logger, false);
|
||||
const cred = getSpeechCredential(obj, logger);
|
||||
|
||||
const { text, language, engine = 'standard' } = body;
|
||||
const salt = uuidv4();
|
||||
/* parse Nuance voices into name and model */
|
||||
let voice = body.voice;
|
||||
let model;
|
||||
if (cred.vendor === 'nuance' && voice) {
|
||||
const arr = /([A-Za-z-]*)\s+-\s+(enhanced|standard)/.exec(voice);
|
||||
if (arr) {
|
||||
voice = arr[1];
|
||||
model = arr[2];
|
||||
}
|
||||
} else if (cred.vendor === 'deepgram') {
|
||||
model = voice;
|
||||
}
|
||||
const stats = {
|
||||
histogram: () => {},
|
||||
increment: () => {},
|
||||
};
|
||||
const { filePath } = await synthAudio(stats, {
|
||||
account_sid: accountSid,
|
||||
text,
|
||||
vendor: cred.vendor,
|
||||
language,
|
||||
voice,
|
||||
engine,
|
||||
model,
|
||||
salt,
|
||||
credentials: cred,
|
||||
disableTtsCache: false,
|
||||
disableTtsStreaming: true
|
||||
});
|
||||
|
||||
let contentType = 'audio/mpeg';
|
||||
|
||||
let readStream = fs.createReadStream(filePath);
|
||||
if (['nuance', 'nvidia'].includes(cred.vendor) ||
|
||||
(
|
||||
process.env.JAMBONES_TTS_TRIM_SILENCE &&
|
||||
['microsoft', 'azure'].includes(cred.vendor)
|
||||
)
|
||||
) {
|
||||
if (encodingMp3) {
|
||||
readStream = readStream
|
||||
.pipe(new PCMToMP3Encoder({
|
||||
channels: 1,
|
||||
sampleRate: 8000,
|
||||
bitRate: 128
|
||||
}, logger));
|
||||
} else {
|
||||
contentType = 'application/octet-stream';
|
||||
}
|
||||
}
|
||||
res.writeHead(200, {
|
||||
'Content-Type': contentType,
|
||||
});
|
||||
|
||||
pipeline(readStream, res, (err) => {
|
||||
if (err) {
|
||||
logger.error('ttscache/Synthesize failed:', err);
|
||||
if (!res.headersSent) {
|
||||
res.status(500).end('Server error');
|
||||
}
|
||||
}
|
||||
|
||||
fs.unlink(filePath, (unlinkErr) => {
|
||||
if (unlinkErr) throw unlinkErr;
|
||||
logger.info(`${filePath} was deleted`);
|
||||
});
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -338,8 +338,8 @@ router.put('/:user_sid', async(req, res) => {
|
||||
//if (req.user.user_sid && req.user.user_sid !== user_sid) return res.sendStatus(403);
|
||||
|
||||
if (!hasAdminAuth &&
|
||||
!(hasAccountAuth && user[0] && req.user.account_sid === user[0].account_sid) &&
|
||||
!(hasServiceProviderAuth && user[0] && req.user.service_provider_sid === user[0].service_provider_sid) &&
|
||||
!(hasAccountAuth && req.user.account_sid === user[0].account_sid) &&
|
||||
!(hasServiceProviderAuth && req.user.service_provider_sid === user[0].service_provider_sid) &&
|
||||
(req.user.user_sid && req.user.user_sid !== user_sid)) {
|
||||
return res.sendStatus(403);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,8 @@ router.post('/', express.raw({type: 'application/json'}), async(req, res) => {
|
||||
}
|
||||
|
||||
/* process event */
|
||||
if (evt?.type?.startsWith('invoice.')) handleInvoiceEvents(logger, evt);
|
||||
logger.info(`received webhook: ${evt.type}`);
|
||||
if (evt.type.startsWith('invoice.')) handleInvoiceEvents(logger, evt);
|
||||
else {
|
||||
logger.debug(evt, 'unhandled stripe webook');
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: Jambonz REST API
|
||||
description: Jambonz REST API specification
|
||||
title: jambonz REST API
|
||||
description: jambonz REST API
|
||||
contact:
|
||||
email: daveh@drachtio.org
|
||||
license:
|
||||
@@ -44,8 +44,6 @@ tags:
|
||||
description: Least Cost Routing Routes operations
|
||||
- name: LcrCarrierSetEntries
|
||||
description: Least Cost Routing Carrier Set Entries operation
|
||||
- name: GoogleCustomVoices
|
||||
description: Google Custom voices operation
|
||||
paths:
|
||||
/BetaInviteCodes:
|
||||
post:
|
||||
@@ -382,35 +380,11 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/login:
|
||||
post:
|
||||
tags:
|
||||
- Authentication
|
||||
summary: login and retrieve a JWT
|
||||
operationId: login
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Login'
|
||||
responses:
|
||||
200:
|
||||
description: user logged in
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SuccessfulLogin'
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/logout:
|
||||
post:
|
||||
tags:
|
||||
- Authentication
|
||||
summary: log out and deactivate the JWT
|
||||
summary: log out and deactivate jwt
|
||||
operationId: logoutUser
|
||||
responses:
|
||||
204:
|
||||
@@ -608,9 +582,10 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
type:
|
||||
array
|
||||
items:
|
||||
$ref: '#/components/schemas/UserList'
|
||||
$ref: '#/components/schemas/Users'
|
||||
403:
|
||||
description: unauthorized
|
||||
500:
|
||||
@@ -633,13 +608,27 @@ paths:
|
||||
- Users
|
||||
summary: retrieve user information
|
||||
operationId: getUser
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
is_active:
|
||||
type: boolean
|
||||
force_change:
|
||||
type: boolean
|
||||
scope:
|
||||
type: string
|
||||
permissions:
|
||||
type: array
|
||||
responses:
|
||||
200:
|
||||
204:
|
||||
description: user information
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserProfile'
|
||||
403:
|
||||
description: user information
|
||||
content:
|
||||
@@ -683,8 +672,6 @@ paths:
|
||||
type: string
|
||||
permissions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
responses:
|
||||
204:
|
||||
description: user updated
|
||||
@@ -723,8 +710,6 @@ paths:
|
||||
type: string
|
||||
permissions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
old_password:
|
||||
type: string
|
||||
description: existing password, which is to be replaced
|
||||
@@ -801,7 +786,7 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: mycorp.sip.jambonz.cloud
|
||||
example: mycorp.sip.jambonz.us
|
||||
responses:
|
||||
200:
|
||||
description: indicates whether value is already in use
|
||||
@@ -1011,7 +996,7 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/AccountTest/{ServiceProviderSid}:
|
||||
/AccountTest/:ServiceProviderSid:
|
||||
parameters:
|
||||
- name: ServiceProviderSid
|
||||
in: path
|
||||
@@ -1108,9 +1093,6 @@ paths:
|
||||
requires_register:
|
||||
type: boolean
|
||||
description: wehther this provider requires us to send a REGISTER to them in order to receive calls
|
||||
register_use_tls:
|
||||
type: boolean
|
||||
description: wehther this provider requires us to send a REGISTER use TLS protocol
|
||||
register_username:
|
||||
type: string
|
||||
description: sip username to authenticate with, if registration is required
|
||||
@@ -1987,7 +1969,7 @@ paths:
|
||||
tags:
|
||||
- Service Providers
|
||||
summary: add a VoiPCarrier to a service provider based on PredefinedCarrier template
|
||||
operationId: createVoipCarrierFromTemplateBySP
|
||||
operationId: createVoipCarrierFromTemplate
|
||||
responses:
|
||||
201:
|
||||
description: voip carrier successfully created
|
||||
@@ -2088,41 +2070,6 @@ paths:
|
||||
description: credential successfully deleted
|
||||
404:
|
||||
description: credential not found
|
||||
/ServiceProviders/{ServiceProviderSid}/SpeechCredentials/speech/supportedLanguagesAndVoices:
|
||||
get:
|
||||
tags:
|
||||
- Service Providers
|
||||
summary: get supported languages, voices and models
|
||||
operationId: supportedLanguagesAndVoices
|
||||
parameters:
|
||||
- name: ServiceProviderSid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- name: vendor
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: label
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: get supported languages, voices and models
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SpeechLanguagesVoices'
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/ServiceProviders/{ServiceProviderSid}/SpeechCredentials/{SpeechCredentialSid}/test:
|
||||
get:
|
||||
tags:
|
||||
@@ -2942,7 +2889,7 @@ paths:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: get a specific speech credential
|
||||
operationId: getSpeechCredentialByAccount
|
||||
operationId: getSpeechCredential
|
||||
responses:
|
||||
200:
|
||||
description: retrieve speech credentials for a specified account
|
||||
@@ -2956,7 +2903,7 @@ paths:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: update a speech credential
|
||||
operationId: updateSpeechCredentialByAccount
|
||||
operationId: updateSpeechCredential
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
@@ -2977,53 +2924,18 @@ paths:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: delete a speech credential
|
||||
operationId: deleteSpeechCredentialByAccount
|
||||
operationId: deleteSpeechCredential
|
||||
responses:
|
||||
204:
|
||||
description: credential successfully deleted
|
||||
404:
|
||||
description: credential not found
|
||||
/Accounts/{AccountSid}/SpeechCredentials/speech/supportedLanguagesAndVoices:
|
||||
get:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: get supported languages, voices and models
|
||||
operationId: supportedLanguagesAndVoicesByAccount
|
||||
parameters:
|
||||
- name: AccountSid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- name: vendor
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: label
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: get supported languages, voices and models
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SpeechLanguagesVoices'
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/Accounts/{AccountSid}/SpeechCredentials/{SpeechCredentialSid}/test:
|
||||
get:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: test a speech credential
|
||||
operationId: testSpeechCredentialByAccount
|
||||
operationId: testSpeechCredential
|
||||
parameters:
|
||||
- name: AccountSid
|
||||
in: path
|
||||
@@ -3134,12 +3046,6 @@ paths:
|
||||
enum:
|
||||
- inbound
|
||||
- outbound
|
||||
- in: query
|
||||
name: filter
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: Filter value can be caller ID, callee ID or call Sid
|
||||
get:
|
||||
tags:
|
||||
- Accounts
|
||||
@@ -3269,7 +3175,7 @@ paths:
|
||||
tags:
|
||||
- Service Providers
|
||||
summary: retrieve pcap for a call
|
||||
operationId: getRecentCallTraceBySP
|
||||
operationId: getRecentCallTrace
|
||||
responses:
|
||||
200:
|
||||
description: retrieve sip trace data
|
||||
@@ -3339,23 +3245,11 @@ paths:
|
||||
enum:
|
||||
- inbound
|
||||
- outbound
|
||||
- in: query
|
||||
name: from
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: calling number to retrieve
|
||||
- in: query
|
||||
name: to
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: called number to retrieve
|
||||
get:
|
||||
tags:
|
||||
- Service Providers
|
||||
summary: retrieve recent calls for an account
|
||||
operationId: listRecentCallsBySP
|
||||
operationId: listRecentCalls
|
||||
responses:
|
||||
200:
|
||||
description: retrieve recent call records for a specified account
|
||||
@@ -3456,7 +3350,7 @@ paths:
|
||||
tags:
|
||||
- Service Providers
|
||||
summary: retrieve sip trace detail for a call
|
||||
operationId: getRecentCallTraceByCallId
|
||||
operationId: getRecentCallTrace
|
||||
responses:
|
||||
200:
|
||||
description: retrieve sip trace data
|
||||
@@ -3483,7 +3377,7 @@ paths:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: retrieve pcap for a call
|
||||
operationId: getRecentCallTraceByAccount
|
||||
operationId: getRecentCallTrace
|
||||
responses:
|
||||
200:
|
||||
description: retrieve sip trace data
|
||||
@@ -3669,7 +3563,7 @@ paths:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: retrieve alerts for an account
|
||||
operationId: listAlertsByAccount
|
||||
operationId: listAlerts
|
||||
responses:
|
||||
200:
|
||||
description: retrieve alerts for a specified account
|
||||
@@ -3882,38 +3776,10 @@ paths:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
|
||||
|
||||
/Accounts/{AccountSid}/Conferences:
|
||||
get:
|
||||
tags:
|
||||
- Conferences
|
||||
summary: list conferences
|
||||
operationId: listConferences
|
||||
parameters:
|
||||
- name: AccountSid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: list of conferences for a specified account
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
|
||||
/Accounts/{AccountSid}/Calls:
|
||||
post:
|
||||
tags:
|
||||
- Accounts
|
||||
- Accounts
|
||||
summary: create a call
|
||||
operationId: createCall
|
||||
parameters:
|
||||
@@ -3972,10 +3838,6 @@ paths:
|
||||
type: object
|
||||
description: The customer SIP headers to associate with the call
|
||||
example: {"X-Custom-Header": "Hello"}
|
||||
sipRequestWithinDialogHook:
|
||||
type: string
|
||||
description: The sip indialog hook to receive session messages
|
||||
example: '/customHook'
|
||||
responses:
|
||||
201:
|
||||
description: call successfully created
|
||||
@@ -4180,22 +4042,6 @@ paths:
|
||||
type: string
|
||||
siprecServerURL:
|
||||
type: string
|
||||
conferenceParticipantAction:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum:
|
||||
- tag
|
||||
- untag
|
||||
- coach
|
||||
- uncoach
|
||||
- mute
|
||||
- unmute
|
||||
- hold
|
||||
- unhold
|
||||
tag:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: Accepted
|
||||
@@ -4300,146 +4146,6 @@ paths:
|
||||
type: string
|
||||
length:
|
||||
type: string
|
||||
/Accounts/{AccountSid}/RegisteredSipUsers:
|
||||
parameters:
|
||||
- name: AccountSid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
get:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: retrieve online sip users for an account
|
||||
operationId: listRegisteredSipUsers
|
||||
responses:
|
||||
200:
|
||||
description: retrieve online sip users for an account
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
post:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: retrieve online sip users for an account by list of sip username
|
||||
operationId: listRegisteredSipUsersByUsername
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
responses:
|
||||
200:
|
||||
description: retrieve online sip users for an account
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/RegisteredClient'
|
||||
/Accounts/{AccountSid}/RegisteredSipUsers/{Client}:
|
||||
parameters:
|
||||
- name: AccountSid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
- name: Client
|
||||
in: path
|
||||
required: true
|
||||
style: simple
|
||||
explode: false
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: retrieve registered client registration
|
||||
operationId: getRegisteredClient
|
||||
responses:
|
||||
200:
|
||||
description: registered client found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RegisteredClient'
|
||||
/Accounts/{AccountSid}/TtsCache/Synthesize:
|
||||
parameters:
|
||||
- name: AccountSid
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
post:
|
||||
tags:
|
||||
- Accounts
|
||||
summary: get TTS from provider
|
||||
operationId: Synthesize
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
speech_credential_sid:
|
||||
type: string
|
||||
description: Speech credential Sid
|
||||
example: 553b4b6b-8918-4394-a46d-1e3c5a3c717b
|
||||
text:
|
||||
type: string
|
||||
description: the text to convert to audio
|
||||
example: Hello How are you
|
||||
language:
|
||||
type: string
|
||||
description: language is used in text
|
||||
example: en-US
|
||||
voice:
|
||||
type: string
|
||||
description: voice ID
|
||||
example: en-US-Standard-C
|
||||
encodingMp3:
|
||||
type: boolean
|
||||
description: convert audio to mp3.
|
||||
example: true
|
||||
required:
|
||||
- speech_credential_sid
|
||||
- text
|
||||
- language
|
||||
- voice
|
||||
responses:
|
||||
200:
|
||||
description: Audio is created
|
||||
content:
|
||||
audio/mpeg:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
400:
|
||||
description: bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
422:
|
||||
description: unprocessable entity
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/Lcrs:
|
||||
post:
|
||||
tags:
|
||||
@@ -4587,69 +4293,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/Lcrs/{LcrSid}/Routes:
|
||||
parameters:
|
||||
- name: LcrSid
|
||||
in: path
|
||||
required: true
|
||||
style: simple
|
||||
explode: false
|
||||
schema:
|
||||
type: string
|
||||
post:
|
||||
tags:
|
||||
- Lcrs
|
||||
summary: Create least cost routing routes and carrier set entries
|
||||
operationId: createLeastCostRoutingRoutesAndCarrierEntries
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LcrRoutes'
|
||||
responses:
|
||||
204:
|
||||
description: least cost routing routes and carrier set entries created
|
||||
400:
|
||||
description: bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
404:
|
||||
description: least cost routing not found
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
put:
|
||||
tags:
|
||||
- Lcrs
|
||||
summary: update least cost routing routes and carrier set entries
|
||||
operationId: updateLeastCostRoutingRoutesAndCarrierEntries
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LcrRoutes'
|
||||
responses:
|
||||
204:
|
||||
description: least cost routing ruoutes and carrier entries updated
|
||||
400:
|
||||
description: bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
404:
|
||||
description: least cost routing not found
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/LcrRoutes:
|
||||
post:
|
||||
tags:
|
||||
@@ -4942,173 +4585,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/GoogleCustomVoices:
|
||||
post:
|
||||
tags:
|
||||
- GoogleCustomVoices
|
||||
summary: create a Google custom voice
|
||||
operationId: createGoogleCustomVoice
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/GoogleCustomVoice'
|
||||
required:
|
||||
- speech_credential_sid
|
||||
- name
|
||||
- reported_usage
|
||||
- model
|
||||
responses:
|
||||
201:
|
||||
description: Least Cost Routing Carrier Set Entry successfully created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SuccessfulAdd'
|
||||
400:
|
||||
description: bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
422:
|
||||
description: unprocessable entity
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
get:
|
||||
tags:
|
||||
- GoogleCustomVoices
|
||||
parameters:
|
||||
- in: query
|
||||
name: service_provider_sid
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: return only the google voice custom operated belong to this service provider
|
||||
- in: query
|
||||
name: account_sid
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: return only the google voice custom operated belong to this account_sid
|
||||
|
||||
- in: query
|
||||
name: speech_credential_sid
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: return only the google voice custom operated belong to this speech credential
|
||||
summary: list google custom voices
|
||||
operationId: listGoogleCustomVoices
|
||||
responses:
|
||||
200:
|
||||
description: list oflist google custom voices
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/GoogleCustomVoice'
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
/GoogleCustomVoices/{GoogleCustomVoiceSid}:
|
||||
parameters:
|
||||
- name: GoogleCustomVoiceSid
|
||||
in: path
|
||||
required: true
|
||||
style: simple
|
||||
explode: false
|
||||
schema:
|
||||
type: string
|
||||
delete:
|
||||
tags:
|
||||
- GoogleCustomVoices
|
||||
summary: delete a google custom voice
|
||||
operationId: deleteGoogleCustomVoice
|
||||
responses:
|
||||
204:
|
||||
description: google custom voice successfully deleted
|
||||
404:
|
||||
description: google custom voice not found
|
||||
422:
|
||||
description: unprocessable entity
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
example:
|
||||
msg: a service provider with active accounts can not be deleted
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
get:
|
||||
tags:
|
||||
- GoogleCustomVoices
|
||||
summary: retrieve google custom voice
|
||||
operationId: getGoogleCustomVoice
|
||||
responses:
|
||||
200:
|
||||
description: google custom voice found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleCustomVoice'
|
||||
404:
|
||||
description: google custom voice not found
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
put:
|
||||
tags:
|
||||
- GoogleCustomVoices
|
||||
summary: update google custom voice
|
||||
operationId: updateGoogleCustomVoice
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleCustomVoice'
|
||||
responses:
|
||||
204:
|
||||
description: google custom voice updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GoogleCustomVoice'
|
||||
400:
|
||||
description: bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
404:
|
||||
description: least cost routing carrier set entry not found
|
||||
500:
|
||||
description: system error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
components:
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
@@ -5116,32 +4592,17 @@ components:
|
||||
scheme: bearer
|
||||
bearerFormat: token
|
||||
schemas:
|
||||
SuccessfulLogin:
|
||||
type: object
|
||||
required:
|
||||
- username
|
||||
- password
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
user_sid:
|
||||
type: string
|
||||
scope:
|
||||
type: string
|
||||
force_change:
|
||||
type: boolean
|
||||
|
||||
Login:
|
||||
type: object
|
||||
properties:
|
||||
username:
|
||||
user_sid:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
api_token:
|
||||
type: string
|
||||
change_password:
|
||||
type: boolean
|
||||
required:
|
||||
- username
|
||||
- password
|
||||
|
||||
- user_sid
|
||||
SuccessfulApiKeyAdd:
|
||||
type: object
|
||||
required:
|
||||
@@ -6082,137 +5543,6 @@ components:
|
||||
- lcr_route_sid
|
||||
- voip_carrier_sid
|
||||
- priority
|
||||
LcrRouteAndCarrierEntries:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/LcrRoute'
|
||||
- type: object
|
||||
properties:
|
||||
lcr_carrier_set_entries:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/LcrCarrierSetEntry'
|
||||
LcrRoutes:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/LcrRouteAndCarrierEntries'
|
||||
GoogleCustomVoice:
|
||||
type: object
|
||||
properties:
|
||||
speech_credential_sid:
|
||||
type: string
|
||||
example: 3fa85f64-5717-4562-b3fc-2c963f66afa6
|
||||
name:
|
||||
type: string
|
||||
example: Sally
|
||||
reported_usage:
|
||||
type: string
|
||||
example: REALTIME
|
||||
model:
|
||||
type: string
|
||||
example: projects/12412312/locations/global/models/2134124123-2dbf-43be-9593-12314123
|
||||
required:
|
||||
- speech_credential_sid
|
||||
- name
|
||||
- reported_usage
|
||||
- model
|
||||
RegisteredClient:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: xhoaluu
|
||||
contact:
|
||||
type: string
|
||||
example: sip:0dluqjt6@od41sl9jfc9m.invalid;transport=ws
|
||||
expiryTime:
|
||||
type: number
|
||||
example: 1698981449173
|
||||
protocol:
|
||||
type: string
|
||||
example: wss
|
||||
allow_direct_app_calling:
|
||||
type: number
|
||||
example: 1
|
||||
allow_direct_queue_calling:
|
||||
type: number
|
||||
example: 1
|
||||
allow_direct_user_calling:
|
||||
type: number
|
||||
example: 1
|
||||
registered_status:
|
||||
type: string
|
||||
enum:
|
||||
- active
|
||||
- inactive
|
||||
required:
|
||||
- speech_credential_sid
|
||||
- name
|
||||
- reported_usage
|
||||
- model
|
||||
TtsModel:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: Turbo v2
|
||||
value:
|
||||
type: string
|
||||
example: eleven_turbo_v2
|
||||
LanguageVoice:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: Standard-A (Female)
|
||||
value:
|
||||
type: string
|
||||
example: ar-XA-Standard-A
|
||||
LanguageVoices:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: English (US)
|
||||
value:
|
||||
type: string
|
||||
example: en-US
|
||||
voices:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/LanguageVoice'
|
||||
|
||||
SpeechLanguagesVoices:
|
||||
type: object
|
||||
properties:
|
||||
tts:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/LanguageVoices'
|
||||
stt:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/LanguageVoice'
|
||||
ttsModel:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TtsModel'
|
||||
UserList:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
is_active:
|
||||
type: boolean
|
||||
force_change:
|
||||
type: boolean
|
||||
scope:
|
||||
type: string
|
||||
permissions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -89,12 +89,7 @@ const createDnsRecords = async(logger, domain, name, value, ttl = 3600) => {
|
||||
const str = await res.text();
|
||||
return JSON.parse(str);
|
||||
}
|
||||
let body;
|
||||
try {
|
||||
body = await res.json();
|
||||
} catch (err) {
|
||||
}
|
||||
logger.error({headers: res.headers, body}, `Error creating records, status ${res.statusCode}`);
|
||||
logger.error({res}, 'Error creating records');
|
||||
} catch (err) {
|
||||
logger.error({err}, 'Error retrieving domains');
|
||||
}
|
||||
|
||||
@@ -47,14 +47,12 @@ const sendEmailByCustomVendor = async(logger, from, to, subject, text) => {
|
||||
};
|
||||
|
||||
const sendEmailByMailgun = async(logger, from, to, subject, text) => {
|
||||
if (!process.env.MAILGUN_API_KEY) throw new Error('MAILGUN_API_KEY env variable is not defined!');
|
||||
if (!process.env.MAILGUN_DOMAIN) throw new Error('MAILGUN_DOMAIN env variable is not defined!');
|
||||
|
||||
const mg = mailgun.client({
|
||||
username: 'api',
|
||||
key: process.env.MAILGUN_API_KEY,
|
||||
...(process.env.MAILGUN_URL && {url: process.env.MAILGUN_URL})
|
||||
key: process.env.MAILGUN_API_KEY
|
||||
});
|
||||
if (!process.env.MAILGUN_API_KEY) throw new Error('MAILGUN_API_KEY env variable is not defined!');
|
||||
if (!process.env.MAILGUN_DOMAIN) throw new Error('MAILGUN_DOMAIN env variable is not defined!');
|
||||
|
||||
try {
|
||||
const res = await mg.messages.create(process.env.MAILGUN_DOMAIN, {
|
||||
|
||||
@@ -23,18 +23,7 @@ const decrypt = (data) => {
|
||||
return decrpyted.toString();
|
||||
};
|
||||
|
||||
const obscureKey = (key, key_spoiler_length = 6) => {
|
||||
const key_spoiler_char = 'X';
|
||||
|
||||
if (!key || key.length <= key_spoiler_length) {
|
||||
return key;
|
||||
}
|
||||
|
||||
return `${key.slice(0, key_spoiler_length)}${key_spoiler_char.repeat(key.length - key_spoiler_length)}`;
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
encrypt,
|
||||
decrypt,
|
||||
obscureKey
|
||||
decrypt
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"trial": [
|
||||
{
|
||||
"category": "voice_call_session",
|
||||
"quantity": 5
|
||||
"quantity": 20
|
||||
},
|
||||
{
|
||||
"category": "device",
|
||||
|
||||
@@ -64,7 +64,7 @@ const getHomerSipTrace = async(logger, apiKey, callId) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getHomerPcap = async(logger, apiKey, callIds, method) => {
|
||||
const getHomerPcap = async(logger, apiKey, callIds) => {
|
||||
if (!process.env.HOMER_BASE_URL || !process.env.HOMER_USERNAME || !process.env.HOMER_PASSWORD) {
|
||||
logger.debug('getHomerPcap: Homer integration not installed');
|
||||
}
|
||||
@@ -73,23 +73,18 @@ const getHomerPcap = async(logger, apiKey, callIds, method) => {
|
||||
const stream = await postPcap('/api/v3/export/call/messages/pcap', {
|
||||
param: {
|
||||
transaction: {
|
||||
call: method === 'invite',
|
||||
registration: method === 'register',
|
||||
call: true,
|
||||
registration: true,
|
||||
rest: false
|
||||
},
|
||||
orlogic: true,
|
||||
search: {
|
||||
...(method === 'invite' && {
|
||||
'1_call': {
|
||||
callid: callIds
|
||||
}
|
||||
})
|
||||
,
|
||||
...(method === 'register' && {
|
||||
'1_registration': {
|
||||
callid: callIds
|
||||
}
|
||||
})
|
||||
'1_call': {
|
||||
callid: callIds
|
||||
},
|
||||
'1_registration': {
|
||||
callid: callIds
|
||||
}
|
||||
},
|
||||
},
|
||||
timestamp: {
|
||||
|
||||
@@ -9,8 +9,7 @@ const getJaegerTrace = async(logger, traceId) => {
|
||||
try {
|
||||
return await getJSON(`/api/v3/traces/${traceId}`);
|
||||
} catch (err) {
|
||||
const url = `${process.env.JAEGER_BASE_URL}/api/traces/${traceId}`;
|
||||
logger.error({err, traceId}, `getJaegerTrace: Error retrieving spans from ${url}`);
|
||||
logger.error({err}, `getJaegerTrace: Error retrieving spans for traceId ${traceId}`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Hello From Jambonz. This file was created because Record all call bucket credential test.
|
||||
@@ -1,22 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'Global English', value: 'en' },
|
||||
{ name: 'Australian English', value: 'en_au' },
|
||||
{ name: 'British English', value: 'en_uk' },
|
||||
{ name: 'US English', value: 'en_us' },
|
||||
{ name: 'Spanish', value: 'es' },
|
||||
{ name: 'French', value: 'fr' },
|
||||
{ name: 'German', value: 'de' },
|
||||
{ name: 'Italian', value: 'it' },
|
||||
{ name: 'Portuguese', value: 'pt' },
|
||||
{ name: 'Dutch', value: 'nl' },
|
||||
{ name: 'Hindi', value: 'hi' },
|
||||
{ name: 'Japanese', value: 'ja' },
|
||||
{ name: 'Chinese', value: 'zh' },
|
||||
{ name: 'Finnish', value: 'fi' },
|
||||
{ name: 'Korean', value: 'ko' },
|
||||
{ name: 'Polish', value: 'pl' },
|
||||
{ name: 'Russian', value: 'ru' },
|
||||
{ name: 'Turkish', value: 'tr' },
|
||||
{ name: 'Ukrainian', value: 'uk' },
|
||||
{ name: 'Vietnamese', value: 'vi' },
|
||||
];
|
||||
@@ -1,10 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'Australian English', value: 'en-AU' },
|
||||
{ name: 'British English', value: 'en-GB' },
|
||||
{ name: 'US English', value: 'en-US' },
|
||||
{ name: 'French', value: 'fr-FR' },
|
||||
{ name: 'Canadian French', value: 'fr-CA' },
|
||||
{ name: 'German', value: 'de-DE' },
|
||||
{ name: 'Italian', value: 'it-IT' },
|
||||
{ name: 'US Spanish', value: 'es-US' },
|
||||
];
|
||||
@@ -1,26 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'English US',
|
||||
value: 'en_US-8khz',
|
||||
},
|
||||
{
|
||||
name: 'English UK',
|
||||
value: 'en_UK-8khz',
|
||||
},
|
||||
{
|
||||
name: 'Spanish',
|
||||
value: 'es_xx-8khz',
|
||||
},
|
||||
{
|
||||
name: 'French',
|
||||
value: 'fr_fr-8khz',
|
||||
},
|
||||
{
|
||||
name: 'Russian',
|
||||
value: 'ru_ru-8khz',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese',
|
||||
value: 'pt_br-8khz',
|
||||
},
|
||||
];
|
||||
@@ -1,138 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'Chinese - general',
|
||||
value: 'zh',
|
||||
},
|
||||
{
|
||||
name: 'Chinese (China)',
|
||||
value: 'zh-CN',
|
||||
},
|
||||
{
|
||||
name: 'Chinese (Taiwan)',
|
||||
value: 'zh-TW',
|
||||
},
|
||||
{
|
||||
name: 'Dutch - general',
|
||||
value: 'nl',
|
||||
},
|
||||
{
|
||||
name: 'English - general',
|
||||
value: 'en',
|
||||
},
|
||||
{
|
||||
name: 'English (Australia)',
|
||||
value: 'en-AU',
|
||||
},
|
||||
{
|
||||
name: 'English (United Kingdom)',
|
||||
value: 'en-GB',
|
||||
},
|
||||
{
|
||||
name: 'English (India)',
|
||||
value: 'en-IN',
|
||||
},
|
||||
{
|
||||
name: 'English (New Zealand)',
|
||||
value: 'en-NZ',
|
||||
},
|
||||
{
|
||||
name: 'English (United States)',
|
||||
value: 'en-US',
|
||||
},
|
||||
{
|
||||
name: 'French - general',
|
||||
value: 'fr',
|
||||
},
|
||||
{
|
||||
name: 'French (Canada)',
|
||||
value: 'fr-CA',
|
||||
},
|
||||
{
|
||||
name: 'German - general',
|
||||
value: 'de',
|
||||
},
|
||||
{
|
||||
name: 'Hindi - general',
|
||||
value: 'hi',
|
||||
},
|
||||
{
|
||||
name: 'Hindi (Roman Script)',
|
||||
value: 'hi-Latin',
|
||||
},
|
||||
{
|
||||
name: 'Indonesian - general',
|
||||
value: 'in',
|
||||
},
|
||||
{
|
||||
name: 'Italian - general',
|
||||
value: 'it',
|
||||
},
|
||||
{
|
||||
name: 'Japanese - general',
|
||||
value: 'ja',
|
||||
},
|
||||
{
|
||||
name: 'Korean - general',
|
||||
value: 'ko',
|
||||
},
|
||||
{
|
||||
name: 'Norwegian - general',
|
||||
value: 'no',
|
||||
},
|
||||
{
|
||||
name: 'Polish - general',
|
||||
value: 'pl',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese - general',
|
||||
value: 'pt',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese (Brazil)',
|
||||
value: 'pt-BR',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese (Portugal)',
|
||||
value: 'pt-PT',
|
||||
},
|
||||
{
|
||||
name: 'Russian - general',
|
||||
value: 'ru',
|
||||
},
|
||||
{
|
||||
name: 'Spanish - general',
|
||||
value: 'es',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Latin America)',
|
||||
value: 'es-419',
|
||||
},
|
||||
{
|
||||
name: 'Swedish - general',
|
||||
value: 'sv',
|
||||
},
|
||||
{
|
||||
name: 'Turkish - general',
|
||||
value: 'tr',
|
||||
},
|
||||
{
|
||||
name: 'Ukrainian - general',
|
||||
value: 'uk',
|
||||
},
|
||||
{
|
||||
name: 'Flemish - general',
|
||||
value: 'nl-BE',
|
||||
},
|
||||
{
|
||||
name: 'Danish - general',
|
||||
value: 'da',
|
||||
},
|
||||
{
|
||||
name: 'Tamil - general',
|
||||
value: 'ta',
|
||||
},
|
||||
{
|
||||
name: 'Tamasheq - general',
|
||||
value: 'taq',
|
||||
},
|
||||
];
|
||||
@@ -1,130 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'Afrikaans (South Africa)', value: 'af-ZA' },
|
||||
{ name: 'Albanian (Albania)', value: 'sq-AL' },
|
||||
{ name: 'Amharic (Ethiopia)', value: 'am-ET' },
|
||||
{ name: 'Arabic (Algeria)', value: 'ar-DZ' },
|
||||
{ name: 'Arabic (Bahrain)', value: 'ar-BH' },
|
||||
{ name: 'Arabic (Egypt)', value: 'ar-EG' },
|
||||
{ name: 'Arabic (Iraq)', value: 'ar-IQ' },
|
||||
{ name: 'Arabic (Israel)', value: 'ar-IL' },
|
||||
{ name: 'Arabic (Jordan)', value: 'ar-JO' },
|
||||
{ name: 'Arabic (Kuwait)', value: 'ar-KW' },
|
||||
{ name: 'Arabic (Lebanon)', value: 'ar-LB' },
|
||||
{ name: 'Arabic (Morocco)', value: 'ar-MA' },
|
||||
{ name: 'Arabic (Oman)', value: 'ar-OM' },
|
||||
{ name: 'Arabic (Qatar)', value: 'ar-QA' },
|
||||
{ name: 'Arabic (Saudi Arabia)', value: 'ar-SA' },
|
||||
{ name: 'Arabic (State of Palestine)', value: 'ar-PS' },
|
||||
{ name: 'Arabic (Tunisia)', value: 'ar-TN' },
|
||||
{ name: 'Arabic (United Arab Emirates)', value: 'ar-AE' },
|
||||
{ name: 'Armenian (Armenia)', value: 'hy-AM' },
|
||||
{ name: 'Azerbaijani (Azerbaijan)', value: 'az-AZ' },
|
||||
{ name: 'Basque (Spain)', value: 'eu-ES' },
|
||||
{ name: 'Bengali (Bangladesh)', value: 'bn-BD' },
|
||||
{ name: 'Bengali (India)', value: 'bn-IN' },
|
||||
{ name: 'Bulgarian (Bulgaria)', value: 'bg-BG' },
|
||||
{ name: 'Burmese (Myanmar)', value: 'my-MM' },
|
||||
{ name: 'Catalan (Spain)', value: 'ca-ES' },
|
||||
{ name: 'Chinese, Cantonese (Traditional, Hong Kong)', value: 'yue-Hant-HK' },
|
||||
{ name: 'Chinese, Mandarin (Simplified, China)', value: 'zh' },
|
||||
{ name: 'Chinese, Mandarin (Simplified, Hong Kong)', value: 'zh-HK' },
|
||||
{ name: 'Chinese, Mandarin (Simplified, Taiwan)', value: 'zh-TW' },
|
||||
{ name: 'Croatian (Croatia)', value: 'hr-HR' },
|
||||
{ name: 'Czech (Czech Republic)', value: 'cs-CZ' },
|
||||
{ name: 'Danish (Denmark)', value: 'da-DK' },
|
||||
{ name: 'Dutch (Belgium)', value: 'nl-BE' },
|
||||
{ name: 'Dutch (Netherlands)', value: 'nl-NL' },
|
||||
{ name: 'English (Australia)', value: 'en-AU' },
|
||||
{ name: 'English (Canada)', value: 'en-CA' },
|
||||
{ name: 'English (Ghana)', value: 'en-GH' },
|
||||
{ name: 'English (India)', value: 'en-IN' },
|
||||
{ name: 'English (Ireland)', value: 'en-IE' },
|
||||
{ name: 'English (Kenya)', value: 'en-KE' },
|
||||
{ name: 'English (New Zealand)', value: 'en-NZ' },
|
||||
{ name: 'English (Nigeria)', value: 'en-NG' },
|
||||
{ name: 'English (Philippines)', value: 'en-PH' },
|
||||
{ name: 'English (Singapore)', value: 'en-SG' },
|
||||
{ name: 'English (South Africa)', value: 'en-ZA' },
|
||||
{ name: 'English (Tanzania)', value: 'en-TZ' },
|
||||
{ name: 'English (United Kingdom)', value: 'en-GB' },
|
||||
{ name: 'English (United States)', value: 'en-US' },
|
||||
{ name: 'Estonian (Estonia)', value: 'et-EE' },
|
||||
{ name: 'Filipino (Philippines)', value: 'fil-PH' },
|
||||
{ name: 'Finnish (Finland)', value: 'fi-FI' },
|
||||
{ name: 'French (Canada)', value: 'fr-CA' },
|
||||
{ name: 'French (France)', value: 'fr-FR' },
|
||||
{ name: 'Galician (Spain)', value: 'gl-ES' },
|
||||
{ name: 'Georgian (Georgia)', value: 'ka-GE' },
|
||||
{ name: 'German (Germany)', value: 'de-DE' },
|
||||
{ name: 'Greek (Greece)', value: 'el-GR' },
|
||||
{ name: 'Gujarati (India)', value: 'gu-IN' },
|
||||
{ name: 'Hebrew (Israel)', value: 'he-IL' },
|
||||
{ name: 'Hindi (India)', value: 'hi-IN' },
|
||||
{ name: 'Hungarian (Hungary)', value: 'hu-HU' },
|
||||
{ name: 'Icelandic (Iceland)', value: 'is-IS' },
|
||||
{ name: 'Indonesian (Indonesia)', value: 'id-ID' },
|
||||
{ name: 'Italian (Italy)', value: 'it-IT' },
|
||||
{ name: 'Japanese (Japan)', value: 'ja-JP' },
|
||||
{ name: 'Javanese (Indonesia)', value: 'jv-ID' },
|
||||
{ name: 'Kannada (India)', value: 'kn-IN' },
|
||||
{ name: 'Khmer (Cambodia)', value: 'km-KH' },
|
||||
{ name: 'Korean (South Korea)', value: 'ko-KR' },
|
||||
{ name: 'Lao (Laos)', value: 'lo-LA' },
|
||||
{ name: 'Latvian (Latvia)', value: 'lv-LV' },
|
||||
{ name: 'Lithuanian (Lithuania)', value: 'lt-LT' },
|
||||
{ name: 'Macedonian (North Macedonia)', value: 'mk-MK' },
|
||||
{ name: 'Malay (Malaysia)', value: 'ms-MY' },
|
||||
{ name: 'Malayalam (India)', value: 'ml-IN' },
|
||||
{ name: 'Marathi (India)', value: 'mr-IN' },
|
||||
{ name: 'Mongolian (Mongolia)', value: 'mn-MN' },
|
||||
{ name: 'Nepali (Nepal)', value: 'ne-NP' },
|
||||
{ name: 'Norwegian Bokmål (Norway)', value: 'nb-NO' },
|
||||
{ name: 'Persian (Iran)', value: 'fa-IR' },
|
||||
{ name: 'Polish (Poland)', value: 'pl-PL' },
|
||||
{ name: 'Portuguese (Brazil)', value: 'pt-BR' },
|
||||
{ name: 'Portuguese (Portugal)', value: 'pt-PT' },
|
||||
{ name: 'Punjabi (Gurmukhi, India)', value: 'pa-guru-IN' },
|
||||
{ name: 'Romanian (Romania)', value: 'ro-RO' },
|
||||
{ name: 'Russian (Russia)', value: 'ru-RU' },
|
||||
{ name: 'Serbian (Serbia)', value: 'sr-RS' },
|
||||
{ name: 'Sinhala (Sri Lanka)', value: 'si-LK' },
|
||||
{ name: 'Slovak (Slovakia)', value: 'sk-SK' },
|
||||
{ name: 'Slovenian (Slovenia)', value: 'sl-SI' },
|
||||
{ name: 'Spanish (Argentina)', value: 'es-AR' },
|
||||
{ name: 'Spanish (Bolivia)', value: 'es-BO' },
|
||||
{ name: 'Spanish (Chile)', value: 'es-CL' },
|
||||
{ name: 'Spanish (Colombia)', value: 'es-CO' },
|
||||
{ name: 'Spanish (Costa Rica)', value: 'es-CR' },
|
||||
{ name: 'Spanish (Dominican Republic)', value: 'es-DO' },
|
||||
{ name: 'Spanish (Ecuador)', value: 'es-EC' },
|
||||
{ name: 'Spanish (El Salvador)', value: 'es-SV' },
|
||||
{ name: 'Spanish (Guatemala)', value: 'es-GT' },
|
||||
{ name: 'Spanish (Honduras)', value: 'es-HN' },
|
||||
{ name: 'Spanish (Mexico)', value: 'es-MX' },
|
||||
{ name: 'Spanish (Nicaragua)', value: 'es-NI' },
|
||||
{ name: 'Spanish (Panama)', value: 'es-PA' },
|
||||
{ name: 'Spanish (Paraguay)', value: 'es-PY' },
|
||||
{ name: 'Spanish (Peru)', value: 'es-PE' },
|
||||
{ name: 'Spanish (Puerto Rico)', value: 'es-PR' },
|
||||
{ name: 'Spanish (Spain)', value: 'es-ES' },
|
||||
{ name: 'Spanish (United States)', value: 'es-US' },
|
||||
{ name: 'Spanish (Uruguay)', value: 'es-UY' },
|
||||
{ name: 'Spanish (Venezuela)', value: 'es-VE' },
|
||||
{ name: 'Sundanese (Indonesia)', value: 'su-ID' },
|
||||
{ name: 'Swahili (Kenya)', value: 'sw-KE' },
|
||||
{ name: 'Swahili (Tanzania)', value: 'sw-TZ' },
|
||||
{ name: 'Swedish (Sweden)', value: 'sv-SE' },
|
||||
{ name: 'Tamil (India)', value: 'ta-IN' },
|
||||
{ name: 'Tamil (Malaysia)', value: 'ta-MY' },
|
||||
{ name: 'Tamil (Singapore)', value: 'ta-SG' },
|
||||
{ name: 'Tamil (Sri Lanka)', value: 'ta-LK' },
|
||||
{ name: 'Telugu (India)', value: 'te-IN' },
|
||||
{ name: 'Thai (Thailand)', value: 'th-TH' },
|
||||
{ name: 'Turkish (Turkey)', value: 'tr-TR' },
|
||||
{ name: 'Ukrainian (Ukraine)', value: 'uk-UA' },
|
||||
{ name: 'Urdu (India)', value: 'ur-IN' },
|
||||
{ name: 'Urdu (Pakistan)', value: 'ur-PK' },
|
||||
{ name: 'Uzbek (Uzbekistan)', value: 'uz-UZ' },
|
||||
{ name: 'Vietnamese (Vietnam)', value: 'vi-VN' },
|
||||
{ name: 'Zulu (South Africa)', value: 'zu-ZA' },
|
||||
];
|
||||
@@ -1,82 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'Arabic (Modern Standard)',
|
||||
value: 'ar-MS_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Chinese (Mandarin)',
|
||||
value: 'zh-CN_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Czech ',
|
||||
value: 'cs-CZ_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Dutch (Belgian)',
|
||||
value: 'nl-BE_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Dutch (Netherlands)',
|
||||
value: 'nl-NL_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'English (all supported dialects)',
|
||||
value: 'en-WW_Medical_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'English (Australian)',
|
||||
value: 'en-AU_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'English (Indian)',
|
||||
value: 'en-IN_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'English (United Kingdom)',
|
||||
value: 'en-GB_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'English (United States)',
|
||||
value: 'en-US_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'French (Canadian)',
|
||||
value: 'fr-CA_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'French (France)',
|
||||
value: 'fr-FR_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'German',
|
||||
value: 'de-DE_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Hindi (Indian)',
|
||||
value: 'hi-IN_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Italian',
|
||||
value: 'it-IT_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Korean',
|
||||
value: 'ko-KR_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese (Brazilian)',
|
||||
value: 'pt-BR_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Mexican)',
|
||||
value: 'es-LA_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Castilian)',
|
||||
value: 'es-ES_Telephony',
|
||||
},
|
||||
{
|
||||
name: 'Swedish ',
|
||||
value: 'sv-SE_Telephony',
|
||||
},
|
||||
];
|
||||
@@ -1,490 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'Afrikaans (South Africa)',
|
||||
value: 'af-ZA',
|
||||
},
|
||||
{
|
||||
name: 'Amharic (Ethiopia)',
|
||||
value: 'am-ET',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Algeria)',
|
||||
value: 'ar-DZ',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Bahrain)',
|
||||
value: 'ar-BH',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Egypt)',
|
||||
value: 'ar-EG',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Iraq)',
|
||||
value: 'ar-IQ',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Israel)',
|
||||
value: 'ar-IL',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Jordan)',
|
||||
value: 'ar-JO',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Kuwait)',
|
||||
value: 'ar-KW',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Lebanon)',
|
||||
value: 'ar-LB',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Libya)',
|
||||
value: 'ar-LY',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Morocco)',
|
||||
value: 'ar-MA',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Oman)',
|
||||
value: 'ar-OM',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Qatar)',
|
||||
value: 'ar-QA',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Saudi Arabia)',
|
||||
value: 'ar-SA',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Palestinian Authority)',
|
||||
value: 'ar-PS',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Syria)',
|
||||
value: 'ar-SY',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Tunisia)',
|
||||
value: 'ar-TN',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (United Arab Emirates)',
|
||||
value: 'ar-AE',
|
||||
},
|
||||
{
|
||||
name: 'Arabic (Yemen)',
|
||||
value: 'ar-YE',
|
||||
},
|
||||
{
|
||||
name: 'Bulgarian (Bulgaria)',
|
||||
value: 'bg-BG',
|
||||
},
|
||||
{
|
||||
name: 'Bengali (India)',
|
||||
value: 'bn-IN',
|
||||
},
|
||||
{
|
||||
name: 'Catalan (Spain)',
|
||||
value: 'ca-ES',
|
||||
},
|
||||
{
|
||||
name: 'Chinese (Cantonese, Traditional)',
|
||||
value: 'zh-HK',
|
||||
},
|
||||
{
|
||||
name: 'Chinese (Mandarin, Simplified)',
|
||||
value: 'zh-CN',
|
||||
},
|
||||
{
|
||||
name: 'Chinese (Taiwanese Mandarin)',
|
||||
value: 'zh-TW',
|
||||
},
|
||||
{
|
||||
name: 'Croatian (Croatia)',
|
||||
value: 'hr-HR',
|
||||
},
|
||||
{
|
||||
name: 'Czech (Czech)',
|
||||
value: 'cs-CZ',
|
||||
},
|
||||
{
|
||||
name: 'Danish (Denmark)',
|
||||
value: 'da-DK',
|
||||
},
|
||||
{
|
||||
name: 'Dutch (Netherlands)',
|
||||
value: 'nl-NL',
|
||||
},
|
||||
{
|
||||
name: 'Dutch (Belgium)',
|
||||
value: 'nl-BE',
|
||||
},
|
||||
{
|
||||
name: 'English (Australia)',
|
||||
value: 'en-AU',
|
||||
},
|
||||
{
|
||||
name: 'English (Canada)',
|
||||
value: 'en-CA',
|
||||
},
|
||||
{
|
||||
name: 'English (Ghana)',
|
||||
value: 'en-GH',
|
||||
},
|
||||
{
|
||||
name: 'English (Hong Kong)',
|
||||
value: 'en-HK',
|
||||
},
|
||||
{
|
||||
name: 'English (India)',
|
||||
value: 'en-IN',
|
||||
},
|
||||
{
|
||||
name: 'English (Ireland)',
|
||||
value: 'en-IE',
|
||||
},
|
||||
{
|
||||
name: 'English (Kenya)',
|
||||
value: 'en-KE',
|
||||
},
|
||||
{
|
||||
name: 'English (New Zealand)',
|
||||
value: 'en-NZ',
|
||||
},
|
||||
{
|
||||
name: 'English (Nigeria)',
|
||||
value: 'en-NG',
|
||||
},
|
||||
{
|
||||
name: 'English (Philippines)',
|
||||
value: 'en-PH',
|
||||
},
|
||||
{
|
||||
name: 'English (Singapore)',
|
||||
value: 'en-SG',
|
||||
},
|
||||
{
|
||||
name: 'English (South Africa)',
|
||||
value: 'en-ZA',
|
||||
},
|
||||
{
|
||||
name: 'English (Tanzania)',
|
||||
value: 'en-TZ',
|
||||
},
|
||||
{
|
||||
name: 'English (United Kingdom)',
|
||||
value: 'en-GB',
|
||||
},
|
||||
{
|
||||
name: 'English (United States)',
|
||||
value: 'en-US',
|
||||
},
|
||||
{
|
||||
name: 'Estonian(Estonia)',
|
||||
value: 'et-EE',
|
||||
},
|
||||
{
|
||||
name: 'Filipino (Philippines)',
|
||||
value: 'fil-PH',
|
||||
},
|
||||
{
|
||||
name: 'Finnish (Finland)',
|
||||
value: 'fi-FI',
|
||||
},
|
||||
{
|
||||
name: 'French (Belgium)',
|
||||
value: 'fr-BE',
|
||||
},
|
||||
{
|
||||
name: 'French (Canada)',
|
||||
value: 'fr-CA',
|
||||
},
|
||||
{
|
||||
name: 'French (France)',
|
||||
value: 'fr-FR',
|
||||
},
|
||||
{
|
||||
name: 'French (Switzerland)',
|
||||
value: 'fr-CH',
|
||||
},
|
||||
{
|
||||
name: 'German (Austria)',
|
||||
value: 'de-AT',
|
||||
},
|
||||
{
|
||||
name: 'German (Switzerland)',
|
||||
value: 'de-CH',
|
||||
},
|
||||
{
|
||||
name: 'German (Germany)',
|
||||
value: 'de-DE',
|
||||
},
|
||||
{
|
||||
name: 'Greek (Greece)',
|
||||
value: 'el-GR',
|
||||
},
|
||||
{
|
||||
name: 'Gujarati (Indian)',
|
||||
value: 'gu-IN',
|
||||
},
|
||||
{
|
||||
name: 'Hebrew (Israel)',
|
||||
value: 'he-IL',
|
||||
},
|
||||
{
|
||||
name: 'Hindi (India)',
|
||||
value: 'hi-IN',
|
||||
},
|
||||
{
|
||||
name: 'Hungarian (Hungary)',
|
||||
value: 'hu-HU',
|
||||
},
|
||||
{
|
||||
name: 'Indonesian (Indonesia)',
|
||||
value: 'id-ID',
|
||||
},
|
||||
{
|
||||
name: 'Icelandic (Iceland)',
|
||||
value: 'is-IS',
|
||||
},
|
||||
{
|
||||
name: 'Irish (Ireland)',
|
||||
value: 'ga-IE',
|
||||
},
|
||||
{
|
||||
name: 'Italian (Italy)',
|
||||
value: 'it-IT',
|
||||
},
|
||||
{
|
||||
name: 'Japanese (Japan)',
|
||||
value: 'ja-JP',
|
||||
},
|
||||
{
|
||||
name: 'Javanese (Indonesia)',
|
||||
value: 'jv-ID',
|
||||
},
|
||||
{
|
||||
name: 'Kannada (India)',
|
||||
value: 'kn-IN',
|
||||
},
|
||||
{
|
||||
name: 'Khmer (Cambodia)',
|
||||
value: 'km-KH',
|
||||
},
|
||||
{
|
||||
name: 'Korean (Korea)',
|
||||
value: 'ko-KR',
|
||||
},
|
||||
{
|
||||
name: 'Latvian (Latvia)',
|
||||
value: 'lv-LV',
|
||||
},
|
||||
{
|
||||
name: 'Lao (Laos)',
|
||||
value: 'lo-LA',
|
||||
},
|
||||
{
|
||||
name: 'Lithuanian (Lithuania)',
|
||||
value: 'lt-LT',
|
||||
},
|
||||
{
|
||||
name: 'Malay (Malaysia)',
|
||||
value: 'ms-MY',
|
||||
},
|
||||
{
|
||||
name: 'Macedonian (North Macedonia)',
|
||||
value: 'mk-MK',
|
||||
},
|
||||
{
|
||||
name: 'Maltese (Malta)',
|
||||
value: 'mt-MT',
|
||||
},
|
||||
{
|
||||
name: 'Marathi (India)',
|
||||
value: 'mr-IN',
|
||||
},
|
||||
{
|
||||
name: 'Burmese (Myanmar)',
|
||||
value: 'my-MM',
|
||||
},
|
||||
{
|
||||
name: 'Norwegian (Bokmål, Norway)',
|
||||
value: 'nb-NO',
|
||||
},
|
||||
{
|
||||
name: 'Persian (Iran)',
|
||||
value: 'fa-IR',
|
||||
},
|
||||
{
|
||||
name: 'Polish (Poland)',
|
||||
value: 'pl-PL',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese (Brazil)',
|
||||
value: 'pt-BR',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese (Portugal)',
|
||||
value: 'pt-PT',
|
||||
},
|
||||
{
|
||||
name: 'Romanian (Romania)',
|
||||
value: 'ro-RO',
|
||||
},
|
||||
{
|
||||
name: 'Russian (Russia)',
|
||||
value: 'ru-RU',
|
||||
},
|
||||
{
|
||||
name: 'Slovak (Slovakia)',
|
||||
value: 'sk-SK',
|
||||
},
|
||||
{
|
||||
name: 'Slovenian (Slovenia)',
|
||||
value: 'sl-SI',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Argentina)',
|
||||
value: 'es-AR',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Bolivia)',
|
||||
value: 'es-BO',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Chile)',
|
||||
value: 'es-CL',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Colombia)',
|
||||
value: 'es-CO',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Costa Rica)',
|
||||
value: 'es-CR',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Cuba)',
|
||||
value: 'es-CU',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Dominican Republic)',
|
||||
value: 'es-DO',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Ecuador)',
|
||||
value: 'es-EC',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (El Salvador)',
|
||||
value: 'es-SV',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Equatorial Guinea)',
|
||||
value: 'es-GQ',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Guatemala)',
|
||||
value: 'es-GT',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Honduras)',
|
||||
value: 'es-HN',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Mexico)',
|
||||
value: 'es-MX',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Nicaragua)',
|
||||
value: 'es-NI',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Panama)',
|
||||
value: 'es-PA',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Paraguay)',
|
||||
value: 'es-PY',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Peru)',
|
||||
value: 'es-PE',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Puerto Rico)',
|
||||
value: 'es-PR',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Spain)',
|
||||
value: 'es-ES',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Uruguay)',
|
||||
value: 'es-UY',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (USA)',
|
||||
value: 'es-US',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Venezuela)',
|
||||
value: 'es-VE',
|
||||
},
|
||||
{
|
||||
name: 'Swahili (Kenya)',
|
||||
value: 'sw-KE',
|
||||
},
|
||||
{
|
||||
name: 'Swahili (Tanzania)',
|
||||
value: 'sw-TZ',
|
||||
},
|
||||
{
|
||||
name: 'Sinhala (Sri Lanka)',
|
||||
value: 'si-LK',
|
||||
},
|
||||
{
|
||||
name: 'Swedish (Sweden)',
|
||||
value: 'sv-SE',
|
||||
},
|
||||
{
|
||||
name: 'Serbian (Serbia)',
|
||||
value: 'sr-RS',
|
||||
},
|
||||
{
|
||||
name: 'Tamil (India)',
|
||||
value: 'ta-IN',
|
||||
},
|
||||
{
|
||||
name: 'Telugu (India)',
|
||||
value: 'te-IN',
|
||||
},
|
||||
{
|
||||
name: 'Thai (Thailand)',
|
||||
value: 'th-TH',
|
||||
},
|
||||
{
|
||||
name: 'Turkish (Turkey)',
|
||||
value: 'tr-TR',
|
||||
},
|
||||
{
|
||||
name: 'Ukrainian (Ukraine)',
|
||||
value: 'uk-UA',
|
||||
},
|
||||
{
|
||||
name: 'Uzbek (Uzbekistan)',
|
||||
value: 'uz-UZ',
|
||||
},
|
||||
{
|
||||
name: 'Zulu (South Africa)',
|
||||
value: 'zu-ZA',
|
||||
},
|
||||
{
|
||||
name: 'Vietnamese (Vietnam)',
|
||||
value: 'vi-VN',
|
||||
},
|
||||
];
|
||||
@@ -1,207 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'Arabic (Worldwide)',
|
||||
value: 'ar-WW',
|
||||
valueMix: 'ara-XWW',
|
||||
},
|
||||
{
|
||||
name: 'Catalan (Spain)',
|
||||
value: 'ca-ES',
|
||||
valueMix: 'cat-ESP',
|
||||
},
|
||||
{
|
||||
name: 'Croatian (Croatia)',
|
||||
value: 'hr-HR',
|
||||
valueMix: 'hrv-HRV',
|
||||
},
|
||||
{
|
||||
name: 'Czech (Czech Republic)',
|
||||
value: 'cs-CZ',
|
||||
valueMix: 'ces-CZE',
|
||||
},
|
||||
{
|
||||
name: 'Danish (Denmark)',
|
||||
value: 'da-DK',
|
||||
valueMix: 'dan-DNK',
|
||||
},
|
||||
{
|
||||
name: 'Dutch (Netherlands)',
|
||||
value: 'nl-NL',
|
||||
valueMix: 'nld-NLD',
|
||||
},
|
||||
{
|
||||
name: 'English (Australia)',
|
||||
value: 'en-AU',
|
||||
valueMix: 'eng-AUS',
|
||||
},
|
||||
{
|
||||
name: 'English (United States)',
|
||||
value: 'en-US',
|
||||
valueMix: 'eng-USA',
|
||||
},
|
||||
{
|
||||
name: 'English (India)',
|
||||
value: 'en-IN',
|
||||
valueMix: 'eng-IND',
|
||||
},
|
||||
{
|
||||
name: 'English (United Kingdom)',
|
||||
value: 'en-GB',
|
||||
valueMix: 'eng-GBR',
|
||||
},
|
||||
{
|
||||
name: 'Finnish (Finland)',
|
||||
value: 'fi-FI',
|
||||
valueMix: 'fin-FIN',
|
||||
},
|
||||
{
|
||||
name: 'French (Canada)',
|
||||
value: 'fr-CA',
|
||||
valueMix: 'fra-CAN',
|
||||
},
|
||||
{
|
||||
name: 'French (France)',
|
||||
value: 'fr-FR',
|
||||
valueMix: 'fra-FRA',
|
||||
},
|
||||
{
|
||||
name: 'German (Germany)',
|
||||
value: 'de-DE',
|
||||
valueMix: 'deu-DEU',
|
||||
},
|
||||
{
|
||||
name: 'Greek (Greece)',
|
||||
value: 'el-GR',
|
||||
valueMix: 'ell-GRC',
|
||||
},
|
||||
{
|
||||
name: 'Hebrew (Israel)',
|
||||
value: 'he-IL',
|
||||
valueMix: 'heb-ISR',
|
||||
},
|
||||
{
|
||||
name: 'Hindi (India)',
|
||||
value: 'hi-IN',
|
||||
valueMix: 'hin-IND',
|
||||
},
|
||||
{
|
||||
name: 'Hungarian (Hungary)',
|
||||
value: 'hu-HU',
|
||||
valueMix: 'hun-HUN',
|
||||
},
|
||||
{
|
||||
name: 'Indonesian (Indonesia)',
|
||||
value: 'id-ID',
|
||||
valueMix: 'ind-IDN',
|
||||
},
|
||||
{
|
||||
name: 'Italian (Italy)',
|
||||
value: 'it-IT',
|
||||
valueMix: 'ita-ITA',
|
||||
},
|
||||
{
|
||||
name: 'Japanese (Japan)',
|
||||
value: 'ja-JP',
|
||||
valueMix: 'jpn-JPN',
|
||||
},
|
||||
{
|
||||
name: 'Korean (South Korea)',
|
||||
value: 'ko-KR',
|
||||
valueMix: 'kor-KOR',
|
||||
},
|
||||
{
|
||||
name: 'Malay (Malaysia)',
|
||||
value: 'ms-MY',
|
||||
valueMix: 'zlm-MYS',
|
||||
},
|
||||
{
|
||||
name: 'Norwegian (Norway)',
|
||||
value: 'no-NO',
|
||||
valueMix: 'nor-NOR',
|
||||
},
|
||||
{
|
||||
name: 'Polish (Poland)',
|
||||
value: 'pl-PL',
|
||||
valueMix: 'pol-POL',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese (Brazil)',
|
||||
value: 'pt-BR',
|
||||
valueMix: 'por-BRA',
|
||||
},
|
||||
{
|
||||
name: 'Portuguese (Portugal)',
|
||||
value: 'pt-PT',
|
||||
valueMix: 'por-PRT',
|
||||
},
|
||||
{
|
||||
name: 'Romanian (Romania)',
|
||||
value: 'ro-RO',
|
||||
valueMix: 'ron-ROU',
|
||||
},
|
||||
{
|
||||
name: 'Russian (Russia)',
|
||||
value: 'ru-RU',
|
||||
valueMix: 'rus-RUS',
|
||||
},
|
||||
{
|
||||
name: 'Shanghainese (China)',
|
||||
value: 'zh-WU',
|
||||
valueMix: 'wuu-CHN',
|
||||
},
|
||||
{
|
||||
name: 'Mandarin (China)',
|
||||
value: 'zh-CN',
|
||||
valueMix: 'cmn-CHN',
|
||||
},
|
||||
{
|
||||
name: 'Slovak (Slovakia)',
|
||||
value: 'sk-SK',
|
||||
valueMix: 'slk-SVK',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Spain)',
|
||||
value: 'es-ES',
|
||||
valueMix: 'spa-ESP',
|
||||
},
|
||||
{
|
||||
name: 'Spanish (Latin America)',
|
||||
value: 'es-US',
|
||||
valueMix: 'spa-XLA',
|
||||
},
|
||||
{
|
||||
name: 'Swedish (Sweden)',
|
||||
value: 'sv-SE',
|
||||
valueMix: 'swe-SWE',
|
||||
},
|
||||
{
|
||||
name: 'Thai (Thailand)',
|
||||
value: 'th-TH',
|
||||
valueMix: 'tha-THA',
|
||||
},
|
||||
{
|
||||
name: 'Cantonese (Hong Kong)',
|
||||
value: 'cn-HK',
|
||||
valueMix: 'yue-CHS',
|
||||
},
|
||||
{
|
||||
name: 'Mandarin (Taiwan)',
|
||||
value: 'zh-TW',
|
||||
valueMix: 'cmn-TWN',
|
||||
},
|
||||
{
|
||||
name: 'Turkish (Turkey)',
|
||||
value: 'tr-TR',
|
||||
valueMix: 'tur-TUR',
|
||||
},
|
||||
{
|
||||
name: 'Ukrainian (Ukraine)',
|
||||
value: 'uk-UA',
|
||||
valueMix: 'ukr-UKR',
|
||||
},
|
||||
{
|
||||
name: 'Vietnamese (Vietnam)',
|
||||
value: 'vi-VN',
|
||||
valueMix: 'vie-VNM',
|
||||
},
|
||||
];
|
||||
@@ -1,58 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'Arabic',
|
||||
value: 'ar-AR',
|
||||
},
|
||||
{
|
||||
name: 'English',
|
||||
value: 'en-US',
|
||||
},
|
||||
{
|
||||
name: 'English - GB',
|
||||
value: 'en-GB',
|
||||
},
|
||||
{
|
||||
name: 'Spanish - US',
|
||||
value: 'es-US',
|
||||
},
|
||||
{
|
||||
name: 'Spanish',
|
||||
value: 'es-ES',
|
||||
},
|
||||
{
|
||||
name: 'German',
|
||||
value: 'de-DE',
|
||||
},
|
||||
{
|
||||
name: 'French',
|
||||
value: 'fr-FR',
|
||||
},
|
||||
{
|
||||
name: 'Hindi',
|
||||
value: 'hi-IN',
|
||||
},
|
||||
{
|
||||
name: 'Russian',
|
||||
value: 'ru-RU',
|
||||
},
|
||||
{
|
||||
name: 'Korean',
|
||||
value: 'ko-KR',
|
||||
},
|
||||
{
|
||||
name: 'Brazilian-Portuguese',
|
||||
value: 'pt-BR',
|
||||
},
|
||||
{
|
||||
name: 'Japanese',
|
||||
value: 'ja-JP',
|
||||
},
|
||||
{
|
||||
name: 'Italian',
|
||||
value: 'it-IT',
|
||||
},
|
||||
{
|
||||
name: 'Mandarin',
|
||||
value: 'zh-CN',
|
||||
},
|
||||
];
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
name: 'English (United States)',
|
||||
value: 'en-US',
|
||||
},
|
||||
];
|
||||
@@ -1,14 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'US English', value: 'en-US' },
|
||||
{ name: 'British English', value: 'en-GB' },
|
||||
{ name: 'LATAM Spanish', value: 'en-USes-419' },
|
||||
{ name: 'Spanish', value: 'es' },
|
||||
{ name: 'Catalan', value: 'ca-ES', version: 'v2' },
|
||||
{ name: 'Brazilian Portuguese', value: 'pt-BR' },
|
||||
{ name: 'French', value: 'fr', version: 'v1' },
|
||||
{ name: 'Canadian French', value: 'fr-CA', version: 'v1' },
|
||||
{ name: 'German', value: 'de', version: 'v1' },
|
||||
{ name: 'Italian', value: 'it', version: 'v1' },
|
||||
{ name: 'Turkish', value: 'tr', version: 'v1' },
|
||||
{ name: 'Japanese', value: 'ja', version: 'v1' },
|
||||
];
|
||||
@@ -1,213 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'arb',
|
||||
name: 'Arabic',
|
||||
voices: [{ value: 'Zeina', name: 'Zeina (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'cmn-CN',
|
||||
name: 'Chinese, Mandarin',
|
||||
voices: [{ value: 'Zhiyu', name: 'Zhiyu (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'da-DK',
|
||||
name: 'Danish',
|
||||
voices: [
|
||||
{ value: 'Naja', name: 'Naja (Female)' },
|
||||
{ value: 'Mads', name: 'Mads (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'nl-NL',
|
||||
name: 'Dutch',
|
||||
voices: [
|
||||
{ value: 'Lotte', name: 'Lotte (Female)' },
|
||||
{ value: 'Ruben', name: 'Ruben (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-AU',
|
||||
name: 'English (Australian)',
|
||||
voices: [
|
||||
{ value: 'Nicole', name: 'Nicole (Female)' },
|
||||
{ value: 'Russell', name: 'Russell (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-GB',
|
||||
name: 'English (British)',
|
||||
voices: [
|
||||
{ value: 'Amy', name: 'Amy (Female)' },
|
||||
{ value: 'Emma', name: 'Emma (Female)' },
|
||||
{ value: 'Brian', name: 'Brian (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-IN',
|
||||
name: 'English (Indian)',
|
||||
voices: [
|
||||
{ value: 'Aditi', name: 'Aditi (Female)' },
|
||||
{ value: 'Raveena', name: 'Raveena (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English (US)',
|
||||
voices: [
|
||||
{ value: 'Joanna', name: 'Joanna (Female)' },
|
||||
{ value: 'Kendra', name: 'Kendra (Female)' },
|
||||
{ value: 'Kimberly', name: 'Kimberly (Female)' },
|
||||
{ value: 'Ivy', name: 'Ivy (Female child)' },
|
||||
{ value: 'Salli', name: 'Salli (Female)' },
|
||||
{ value: 'Joey', name: 'Joey (Male)' },
|
||||
{ value: 'Matthew', name: 'Matthew (Male)' },
|
||||
{ value: 'Justin', name: 'Justin (Male child)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-GB-WLS',
|
||||
name: 'English (Welsh)',
|
||||
voices: [{ value: 'Geraint', name: 'Geraint (Male)' }],
|
||||
},
|
||||
{
|
||||
value: 'fr-FR',
|
||||
name: 'French',
|
||||
voices: [
|
||||
{ value: 'Celine', name: 'Céline (Female)' },
|
||||
{ value: 'Lea', name: 'Léa (Female)' },
|
||||
{ value: 'Mathieu', name: 'Mathieu (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fr-CA',
|
||||
name: 'French (Canadian)',
|
||||
voices: [{ value: 'Chantal', name: 'Chantal (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'de-DE',
|
||||
name: 'German',
|
||||
voices: [
|
||||
{ value: 'Marlene', name: 'Marlene (Female)' },
|
||||
{ value: 'Vicki', name: 'Vicki (Female)' },
|
||||
{ value: 'Hans', name: 'Hans (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'hi-IN',
|
||||
name: 'Hindi',
|
||||
voices: [{ value: 'Aditi', name: 'Aditi (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'is-IS',
|
||||
name: 'Icelandic',
|
||||
voices: [
|
||||
{ value: 'Dora', name: 'Dóra (Female)' },
|
||||
{ value: 'Karl', name: 'Karl (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'it-IT',
|
||||
name: 'Italian',
|
||||
voices: [
|
||||
{ value: 'Carla', name: 'Carla (Female)' },
|
||||
{ value: 'Bianca', name: 'Bianca (Female)' },
|
||||
{ value: 'Giorgio', name: 'Giorgio (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ja-JP',
|
||||
name: 'Japanese',
|
||||
voices: [
|
||||
{ value: 'Mizuki', name: 'Mizuki (Female)' },
|
||||
{ value: 'Takumi', name: 'Takumi (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ko-KR',
|
||||
name: 'Korean',
|
||||
voices: [{ value: 'Seoyeon', name: 'Seoyeon (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'nb-NO',
|
||||
name: 'Norwegian',
|
||||
voices: [{ value: 'Liv', name: 'Liv (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'pl-PL',
|
||||
name: 'Polish',
|
||||
voices: [
|
||||
{ value: 'Ewa', name: 'Ewa (Female)' },
|
||||
{ value: 'Maja', name: 'Maja (Female)' },
|
||||
{ value: 'Jacek', name: 'Jacek (Male)' },
|
||||
{ value: 'Jan', name: 'Jan (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'pt-BR',
|
||||
name: 'Portuguese (Brazilian)',
|
||||
voices: [
|
||||
{ value: 'Camila', name: 'Camila (Female)' },
|
||||
{ value: 'Vitoria', name: 'Vitória (Female)' },
|
||||
{ value: 'Ricardo', name: 'Ricardo (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'pt-PT',
|
||||
name: 'Portuguese (European)',
|
||||
voices: [
|
||||
{ value: 'Ines', name: 'Inês (Female)' },
|
||||
{ value: 'Cristiano', name: 'Cristiano (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ro-RO',
|
||||
name: 'Romanian',
|
||||
voices: [{ value: 'Carmen', name: 'Carmen (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'ru-RU',
|
||||
name: 'Russian',
|
||||
voices: [
|
||||
{ value: 'Tatyana', name: 'Tatyana (Female)' },
|
||||
{ value: 'Maxim', name: 'Maxim (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-ES',
|
||||
name: 'Spanish (European)',
|
||||
voices: [
|
||||
{ value: 'Conchita', name: 'Conchita (Female)' },
|
||||
{ value: 'Lucia', name: 'Lucia (Female)' },
|
||||
{ value: 'Enrique', name: 'Enrique (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-MX',
|
||||
name: 'Spanish (Mexican)',
|
||||
voices: [{ value: 'Mia', name: 'Mia (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'es-US',
|
||||
name: 'Spanish (US)',
|
||||
voices: [
|
||||
{ value: 'Lupe', name: 'Lupe (Female)' },
|
||||
{ value: 'Penelope', name: 'Penélope (Female)' },
|
||||
{ value: 'Miguel', name: 'Miguel (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'sv-SE',
|
||||
name: 'Swedish',
|
||||
voices: [{ value: 'Astrid', name: 'Astrid (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'tr-TR',
|
||||
name: 'Turkish',
|
||||
voices: [{ value: 'Filiz', name: 'Filiz (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'cy-GB',
|
||||
name: 'Welsh',
|
||||
voices: [{ value: 'Gwyneth', name: 'Gwyneth (Female)' }],
|
||||
},
|
||||
];
|
||||
@@ -1,192 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'ar',
|
||||
name: 'Arabic',
|
||||
voices: [
|
||||
{
|
||||
value: 'pNInz6obpgDQGcFmaJgB',
|
||||
name: 'Adam - american, deep, middle aged, male, narration',
|
||||
},
|
||||
{
|
||||
value: 'ErXwobaYiN019PkySvjV',
|
||||
name: 'Antoni - american, well-rounded, young, male, narration',
|
||||
},
|
||||
{
|
||||
value: 'VR6AewLTigWG4xSOukaG',
|
||||
name: 'Arnold - american, crisp, middle aged, male, narration',
|
||||
},
|
||||
{
|
||||
value: 'EXAVITQu4vr4xnSDxMaL',
|
||||
name: 'Bella - american, soft, young, female, narration',
|
||||
},
|
||||
{
|
||||
value: 'N2lVS1w4EtoT3dr4eOWO',
|
||||
name: 'Callum - american, hoarse, middle aged, male, video games',
|
||||
},
|
||||
{
|
||||
value: 'IKne3meq5aSn9XLyUdCD',
|
||||
name: 'Charlie - australian, casual, middle aged, male, conversational',
|
||||
},
|
||||
{
|
||||
value: 'XB0fDUnXU5powFXDhCwa',
|
||||
name: 'Charlotte - english-swedish, seductive, middle aged, female, video games',
|
||||
},
|
||||
{
|
||||
value: '2EiwWnXFnvU5JabPnv8n',
|
||||
name: 'Clyde - american, war veteran, middle aged, male, video games',
|
||||
},
|
||||
{
|
||||
value: 'onwK4e9ZLuTAKqWW03F9',
|
||||
name: 'Daniel - british, deep, middle aged, male, news presenter',
|
||||
},
|
||||
{
|
||||
value: 'CYw3kZ02Hs0563khs1Fj',
|
||||
name: 'Dave - british-essex, conversational, young, male, video games',
|
||||
},
|
||||
{
|
||||
value: 'AZnzlk1XvdvUeBnXmlld',
|
||||
name: 'Domi - american, strong, young, female, narration',
|
||||
},
|
||||
{
|
||||
value: 'ThT5KcBeYPX3keUQqHPh',
|
||||
name: "Dorothy - british, pleasant, young, female, children's stories",
|
||||
},
|
||||
{
|
||||
value: 'MF3mGyEYCl7XYWbV9V6O',
|
||||
name: 'Elli - american, emotional, young, female, narration',
|
||||
},
|
||||
{
|
||||
value: 'LcfcDJNUP1GQjkzn1xUU',
|
||||
name: 'Emily - american, calm, young, female, meditation',
|
||||
},
|
||||
{
|
||||
value: 'g5CIjZEefAph4nQFvHAz',
|
||||
name: 'Ethan - american, undefined, young, male, ASMR',
|
||||
},
|
||||
{
|
||||
value: 'D38z5RcWu1voky8WS1ja',
|
||||
name: 'Fin - irish, sailor, old, male, video games',
|
||||
},
|
||||
{
|
||||
value: 'jsCqWAovK2LkecY7zXl4',
|
||||
name: 'Freya - american, undefined, young, female, undefined',
|
||||
},
|
||||
{
|
||||
value: 'jBpfuIE2acCO8z3wKNLl',
|
||||
name: 'Gigi - american, childlish, young, female, animation',
|
||||
},
|
||||
{
|
||||
value: 'zcAOhNBS3c14rBihAFp1',
|
||||
name: 'Giovanni - english-italian, foreigner, young, male, audiobook',
|
||||
},
|
||||
{
|
||||
value: 'z9fAnlkpzviPz146aGWa',
|
||||
name: 'Glinda - american, witch, middle aged, female, video games',
|
||||
},
|
||||
{
|
||||
value: 'oWAxZDx7w5VEj9dCyTzz',
|
||||
name: 'Grace - american-southern, undefined, young, female, audiobook ',
|
||||
},
|
||||
{
|
||||
value: 'SOYHLrjzK2X1ezoPC6cr',
|
||||
name: 'Harry - american, anxious, young, male, video games',
|
||||
},
|
||||
{
|
||||
value: 'ZQe5CZNOzWyzPSCn5a3c',
|
||||
name: 'James - australian, calm , old, male, news',
|
||||
},
|
||||
{
|
||||
value: 'bVMeCyTHy58xNoL34h3p',
|
||||
name: 'Jeremy - american-irish, excited, young, male, narration',
|
||||
},
|
||||
{
|
||||
value: 't0jbNlBVZ17f02VDIeMI',
|
||||
name: 'Jessie - american, raspy , old, male, video games',
|
||||
},
|
||||
{
|
||||
value: 'Zlb1dXrM653N07WRdFW3',
|
||||
name: 'Joseph - british, undefined, middle aged, male, news',
|
||||
},
|
||||
{
|
||||
value: 'TxGEqnHWrfWFTfGW9XjX',
|
||||
name: 'Josh - american, deep, young, male, narration',
|
||||
},
|
||||
{
|
||||
value: 'TX3LPaxmHKxFdv7VOQHJ',
|
||||
name: 'Liam - american, undefined, young, male, narration',
|
||||
},
|
||||
{
|
||||
value: 'XrExE9yKIg1WjnnlVkGX',
|
||||
name: 'Matilda - american, warm, young, female, audiobook',
|
||||
},
|
||||
{
|
||||
value: 'Yko7PKHZNXotIFUBG7I9',
|
||||
name: 'Matthew - british, undefined, middle aged, male, audiobook',
|
||||
},
|
||||
{
|
||||
value: 'flq6f7yk4E4fJM5XTYuZ',
|
||||
name: 'Michael - american, undefined, old, male, audiobook',
|
||||
},
|
||||
{
|
||||
value: 'zrHiDhphv9ZnVXBqCLjz',
|
||||
name: 'Mimi - english-swedish, childish, young, female, animation',
|
||||
},
|
||||
{
|
||||
value: 'piTKgcLEGmPE4e6mEKli',
|
||||
name: 'Nicole - american, whisper, young, female, audiobook',
|
||||
},
|
||||
{
|
||||
value: 'ODq5zmih8GrVes37Dizd',
|
||||
name: 'Patrick - american, shouty, middle aged, male, video games',
|
||||
},
|
||||
{
|
||||
value: '21m00Tcm4TlvDq8ikWAM',
|
||||
name: 'Rachel - american, calm, young, female, narration',
|
||||
},
|
||||
{
|
||||
value: 'wViXBPUzp2ZZixB1xQuM',
|
||||
name: 'Ryan - american, soldier, middle aged, male, audiobook',
|
||||
},
|
||||
{
|
||||
value: 'yoZ06aMxZJJ28mfd3POQ',
|
||||
name: 'Sam - american, raspy, young, male, narration',
|
||||
},
|
||||
{
|
||||
value: 'pMsXgVXv3BLzUgSXRplE',
|
||||
name: 'Serena - american, pleasant, middle aged, female, interactive',
|
||||
},
|
||||
{
|
||||
value: 'GBv7mTt0atIp3Br8iCZE',
|
||||
name: 'Thomas - american, calm, young, male, meditation',
|
||||
},
|
||||
],
|
||||
},
|
||||
{ value: 'bg', name: 'Bulgarian', voices: [] },
|
||||
{ value: 'zh', name: 'Chinese', voices: [] },
|
||||
{ value: 'hr', name: 'Croatian', voices: [] },
|
||||
{ value: 'cs', name: 'Czech', voices: [] },
|
||||
{ value: 'da', name: 'Danish', voices: [] },
|
||||
{ value: 'nl', name: 'Dutch', voices: [] },
|
||||
{ value: 'en', name: 'English', voices: [] },
|
||||
{ value: 'fil', name: 'Filipino', voices: [] },
|
||||
{ value: 'fi', name: 'Finnish', voices: [] },
|
||||
{ value: 'fr', name: 'French', voices: [] },
|
||||
{ value: 'de', name: 'German', voices: [] },
|
||||
{ value: 'el', name: 'Greek', voices: [] },
|
||||
{ value: 'hi', name: 'Hindi', voices: [] },
|
||||
{ value: 'id', name: 'Indonesian', voices: [] },
|
||||
{ value: 'it', name: 'Italian', voices: [] },
|
||||
{ value: 'ja', name: 'Japanese', voices: [] },
|
||||
{ value: 'ko', name: 'Korean', voices: [] },
|
||||
{ value: 'ms', name: 'Malay', voices: [] },
|
||||
{ value: 'pl', name: 'Polish', voices: [] },
|
||||
{ value: 'pt', name: 'Portuguese', voices: [] },
|
||||
{ value: 'ro', name: 'Romanian', voices: [] },
|
||||
{ value: 'ru', name: 'Russian', voices: [] },
|
||||
{ value: 'sk', name: 'Slovak', voices: [] },
|
||||
{ value: 'es', name: 'Spanish', voices: [] },
|
||||
{ value: 'sv', name: 'Swedish', voices: [] },
|
||||
{ value: 'ta', name: 'Tamil', voices: [] },
|
||||
{ value: 'tr', name: 'Turkish', voices: [] },
|
||||
{ value: 'uk', name: 'Ukrainian', voices: [] },
|
||||
];
|
||||
@@ -1,796 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'ar-XA',
|
||||
name: 'Arabic',
|
||||
voices: [
|
||||
{ value: 'ar-XA-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'ar-XA-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'ar-XA-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'ar-XA-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'ar-XA-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'ar-XA-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'ar-XA-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'ar-XA-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'af-ZA',
|
||||
name: 'Afrikaans (South Africa)',
|
||||
voices: [{ value: 'af-ZA-Standard-A', name: 'Standard-A (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'bn-IN',
|
||||
name: 'Bengali (India)',
|
||||
voices: [
|
||||
{ value: 'bn-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'bn-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'bn-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'bn-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'bg-BG',
|
||||
name: 'Bulgarian (Bulgaria)',
|
||||
voices: [{ value: 'bg-BG-Standard-A', name: 'Standard-A (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'ca-ES',
|
||||
name: 'Catalan (Spain)',
|
||||
voices: [{ value: 'ca-ES-Standard-A', name: 'Standard-A (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'cs-CZ',
|
||||
name: 'Czech (Czech Republic)',
|
||||
voices: [
|
||||
{ value: 'cs-CZ-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'cs-CZ-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'da-DK',
|
||||
name: 'Danish (Denmark)',
|
||||
voices: [
|
||||
{ value: 'da-DK-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'da-DK-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'da-DK-Neural2-D', name: 'Neural2-D (Female)' },
|
||||
{ value: 'da-DK-Neural2-F', name: 'Neural2-F (Male)' },
|
||||
|
||||
{ value: 'da-DK-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'da-DK-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'da-DK-Standard-E', name: 'Standard-E (Female)' },
|
||||
{ value: 'da-DK-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'da-DK-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
{ value: 'da-DK-Wavenet-E', name: 'Wavenet-E (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'eu-ES',
|
||||
name: 'Basque (Spain)',
|
||||
voices: [{ value: 'eu-ES-Standard-A', name: 'Standard-A (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'nl-NL',
|
||||
name: 'Dutch (Netherlands)',
|
||||
voices: [
|
||||
{ value: 'nl-NL-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'nl-NL-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'nl-NL-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'nl-NL-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'nl-NL-Standard-E', name: 'Standard-E (Female)' },
|
||||
{ value: 'nl-NL-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'nl-NL-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'nl-NL-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'nl-NL-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
{ value: 'nl-NL-Wavenet-E', name: 'Wavenet-E (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-AU',
|
||||
name: 'English (Australia)',
|
||||
voices: [
|
||||
{ value: 'en-AU-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'en-AU-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'en-AU-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'en-AU-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'en-AU-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'en-AU-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'en-AU-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'en-AU-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'en-AU-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'en-AU-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'en-AU-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
{ value: 'en-AU-Neural2-D', name: 'Neural2-D (Male)' },
|
||||
{ value: 'en-AU-Polyglot-1', name: 'Polyglot-1 (Male)' },
|
||||
{ value: 'en-AU-News-E', name: 'News-E (Female)' },
|
||||
{ value: 'en-AU-News-F', name: 'News-F (Female)' },
|
||||
{ value: 'en-AU-News-G', name: 'News-G (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-IN',
|
||||
name: 'English (India)',
|
||||
voices: [
|
||||
{ value: 'en-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'en-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'en-IN-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'en-IN-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'en-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'en-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'en-IN-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'en-IN-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
|
||||
{ value: 'en-IN-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'en-IN-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'en-IN-Neural2-C', name: 'Neural2-C (Male)' },
|
||||
{ value: 'en-IN-Neural2-D', name: 'Neural2-D (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-GB',
|
||||
name: 'English (UK)',
|
||||
voices: [
|
||||
{ value: 'en-GB-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'en-GB-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'en-GB-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'en-GB-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'en-GB-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'en-GB-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'en-GB-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'en-GB-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'en-GB-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'en-GB-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'en-GB-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
{ value: 'en-GB-Neural2-D', name: 'Neural2-D (Male)' },
|
||||
{ value: 'en-GB-Neural2-F', name: 'Neural2-F (Female)' },
|
||||
{ value: 'en-GB-News-G', name: 'News-G (Female)' },
|
||||
{ value: 'en-GB-News-H', name: 'News-H (Female)' },
|
||||
{ value: 'en-GB-News-I', name: 'News-I (Female)' },
|
||||
{ value: 'en-GB-News-J', name: 'News-J (Male)' },
|
||||
{ value: 'en-GB-News-K', name: 'News-K (Male)' },
|
||||
{ value: 'en-GB-News-L', name: 'News-L (Male)' },
|
||||
{ value: 'en-GB-News-M', name: 'News-M (Male)' },
|
||||
|
||||
{ value: 'en-GB-Studio-B', name: 'Studio-B (Male)' },
|
||||
{ value: 'en-GB-Studio-C', name: 'Studio-C (Female)' },
|
||||
{ value: 'en-GB-Wavenet-F', name: 'Wavenet-F (Female)' },
|
||||
{ value: 'en-GB-Standard-F', name: 'Standard-F (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English (US)',
|
||||
voices: [
|
||||
{ value: 'en-US-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'en-US-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'en-US-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'en-US-Standard-E', name: 'Standard-E (Female)' },
|
||||
{ value: 'en-US-Wavenet-A', name: 'Wavenet-A (Male)' },
|
||||
{ value: 'en-US-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'en-US-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'en-US-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'en-US-Wavenet-E', name: 'Wavenet-E (Female)' },
|
||||
{ value: 'en-US-Wavenet-F', name: 'Wavenet-F (Female)' },
|
||||
{ value: 'en-US-Neural2-A', name: 'Neural2-A (Male)' },
|
||||
{ value: 'en-US-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
{ value: 'en-US-Neural2-D', name: 'Neural2-D (Male)' },
|
||||
{ value: 'en-US-Neural2-E', name: 'Neural2-E (Female)' },
|
||||
{ value: 'en-US-Neural2-F', name: 'Neural2-F (Female)' },
|
||||
{ value: 'en-US-Neural2-G', name: 'Neural2-G (Female)' },
|
||||
{ value: 'en-US-Neural2-H', name: 'Neural2-H (Female)' },
|
||||
{ value: 'en-US-Neural2-I', name: 'Neural2-I (Male)' },
|
||||
{ value: 'en-US-Neural2-J', name: 'Neural2-J (Male)' },
|
||||
{ value: 'en-US-Studio-M', name: 'Studio-M (Male)' },
|
||||
{ value: 'en-US-Studio-O', name: 'Studio-M (Female)' },
|
||||
{ value: 'en-US-Polyglot-1', name: 'Polyglot-1 (Male)' },
|
||||
{ value: 'en-US-News-K', name: 'News-K (Female)' },
|
||||
{ value: 'en-US-News-L', name: 'News-L (Female)' },
|
||||
{ value: 'en-US-News-M', name: 'News-M (Male)' },
|
||||
{ value: 'en-US-News-N', name: 'News-N (Male)' },
|
||||
|
||||
{ value: 'en-US-Standard-A', name: 'Standard-A (Male)' },
|
||||
{ value: 'en-US-Standard-F', name: 'Standard-F (Female)' },
|
||||
{ value: 'en-US-Standard-G', name: 'Standard-G (Female)' },
|
||||
{ value: 'en-US-Standard-H', name: 'Standard-H (Female)' },
|
||||
{ value: 'en-US-Standard-I', name: 'Standard-I (Male)' },
|
||||
{ value: 'en-US-Standard-J', name: 'Standard-J (Male)' },
|
||||
{ value: 'en-US-Wavenet-G', name: 'Wavenet-G (Female)' },
|
||||
{ value: 'en-US-Wavenet-H', name: 'Wavenet-H (Female)' },
|
||||
{ value: 'en-US-Wavenet-I', name: 'Wavenet-I (Male)' },
|
||||
{ value: 'en-US-Wavenet-J', name: 'Wavenet-J (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fil-PH',
|
||||
name: 'Filipino (Philippines)',
|
||||
voices: [
|
||||
{ value: 'fil-PH-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'fil-PH-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'fil-ph-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'fil-ph-Neural2-D', name: 'Neural2-A (Male)' },
|
||||
|
||||
{ value: 'fil-PH-Standard-B', name: 'Standard-B (Female)' },
|
||||
{ value: 'fil-PH-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'fil-PH-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'fil-PH-Wavenet-B', name: 'Wavenet-B (Female)' },
|
||||
{ value: 'fil-PH-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'fil-PH-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fi-FI',
|
||||
name: 'Finnish (Finland)',
|
||||
voices: [
|
||||
{ value: 'fi-FI-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'fi-FI-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fr-CA',
|
||||
name: 'French (Canada)',
|
||||
voices: [
|
||||
{ value: 'fr-CA-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'fr-CA-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'fr-CA-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'fr-CA-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'fr-CA-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'fr-CA-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'fr-CA-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'fr-CA-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'fr-CA-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'fr-CA-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'fr-CA-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
{ value: 'fr-CA-Neural2-D', name: 'Neural2-D (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fr-FR',
|
||||
name: 'French (France)',
|
||||
voices: [
|
||||
{ value: 'fr-FR-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'fr-FR-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'fr-FR-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'fr-FR-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'fr-FR-Standard-E', name: 'Standard-E (Female)' },
|
||||
{ value: 'fr-FR-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'fr-FR-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'fr-FR-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'fr-FR-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'fr-FR-Wavenet-E', name: 'Wavenet-E (Female)' },
|
||||
{ value: 'fr-FR-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'fr-FR-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'fr-FR-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
{ value: 'fr-FR-Neural2-D', name: 'Neural2-D (Male)' },
|
||||
{ value: 'fr-FR-Neural2-E', name: 'Neural2-E (Female)' },
|
||||
{ value: 'fr-FR-Polyglot-1', name: 'Polyglot-1 (Male)' },
|
||||
|
||||
{ value: 'fr-FR-Studio-A', name: 'Studio-A (Female)' },
|
||||
{ value: 'fr-FR-Studio-D', name: 'Studio-D (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'de-DE',
|
||||
name: 'German (Germany)',
|
||||
voices: [
|
||||
{ value: 'de-DE-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'de-DE-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'de-DE-Standard-E', name: 'Standard-E (Male)' },
|
||||
{ value: 'de-DE-Standard-F', name: 'Standard-F (Female)' },
|
||||
{ value: 'de-DE-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'de-DE-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'de-DE-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'de-DE-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'de-DE-Wavenet-E', name: 'Wavenet-E (Male)' },
|
||||
{ value: 'de-DE-Wavenet-F', name: 'Wavenet-F (Female)' },
|
||||
{ value: 'de-DE-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'de-DE-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
{ value: 'de-DE-Neural2-D', name: 'Neural2-D (Male)' },
|
||||
{ value: 'de-DE-Neural2-F', name: 'Neural2-F (Female)' },
|
||||
{ value: 'de-DE-Polyglot-1', name: 'Polyglot-1 (Male)' },
|
||||
|
||||
{ value: 'de-DE-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'de-DE-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'de-DE-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'de-DE-Studio-B', name: 'Studio-B (Male)' },
|
||||
{ value: 'de-DE-Studio-C', name: 'Studio-C (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'el-GR',
|
||||
name: 'Greek (Greece)',
|
||||
voices: [
|
||||
{ value: 'el-GR-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'el-GR-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'gl-ES',
|
||||
name: 'Galician (Spain)',
|
||||
voices: [{ value: 'gl-ES-Standard-A', name: 'Standard-A (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'gu-IN',
|
||||
name: 'Gujarati (India)',
|
||||
voices: [
|
||||
{ value: 'gu-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'gu-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'gu-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'gu-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'he-IL',
|
||||
name: 'Hebrew (Israel)',
|
||||
voices: [
|
||||
{ value: 'he-IL-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'he-IL-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'he-IL-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'he-IL-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'he-IL-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'he-IL-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'he-IL-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'he-IL-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'hi-IN',
|
||||
name: 'Hindi (India)',
|
||||
voices: [
|
||||
{ value: 'hi-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'hi-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'hi-IN-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'hi-IN-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'hi-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'hi-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'hi-IN-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'hi-IN-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
{ value: 'hi-IN-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'hi-IN-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'hi-IN-Neural2-C', name: 'Neural2-C (Male)' },
|
||||
{ value: 'hi-IN-Neural2-D', name: 'Neural2-D (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'hu-HU',
|
||||
name: 'Hungarian (Hungary)',
|
||||
voices: [
|
||||
{ value: 'hu-HU-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'hu-HU-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'is-IS',
|
||||
name: 'Icelandic (Iceland)',
|
||||
voices: [{ value: 'is-IS-Standard-A', name: 'Standard-A (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'id-ID',
|
||||
name: 'Indonesian (Indonesia)',
|
||||
voices: [
|
||||
{ value: 'id-ID-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'id-ID-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'id-ID-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'id-ID-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'id-ID-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'id-ID-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'id-ID-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'id-ID-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'it-IT',
|
||||
name: 'Italian (Italy)',
|
||||
voices: [
|
||||
{ value: 'it-IT-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'it-IT-Standard-B', name: 'Standard-B (Female)' },
|
||||
{ value: 'it-IT-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'it-IT-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'it-IT-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'it-IT-Wavenet-B', name: 'Wavenet-B (Female)' },
|
||||
{ value: 'it-IT-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'it-IT-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'it-IT-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'it-IT-Neural2-C', name: 'Neural2-C (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ja-JP',
|
||||
name: 'Japanese (Japan)',
|
||||
voices: [
|
||||
{ value: 'ja-JP-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'ja-JP-Standard-B', name: 'Standard-B (Female)' },
|
||||
{ value: 'ja-JP-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'ja-JP-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'ja-JP-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'ja-JP-Wavenet-B', name: 'Wavenet-B (Female)' },
|
||||
{ value: 'ja-JP-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'ja-JP-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'ja-JP-Neural2-B', name: 'Neural2-B (Female)' },
|
||||
{ value: 'ja-JP-Neural2-C', name: 'Neural2-C (Male)' },
|
||||
{ value: 'ja-JP-Neural2-D', name: 'Neural2-D (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'kn-IN',
|
||||
name: 'Kannada (India)',
|
||||
voices: [
|
||||
{ value: 'kn-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'kn-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'kn-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'kn-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ko-KR',
|
||||
name: 'Korean (South Korea)',
|
||||
voices: [
|
||||
{ value: 'ko-KR-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'ko-KR-Standard-B', name: 'Standard-B (Female)' },
|
||||
{ value: 'ko-KR-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'ko-KR-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'ko-KR-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'ko-KR-Wavenet-B', name: 'Wavenet-B (Female)' },
|
||||
{ value: 'ko-KR-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'ko-KR-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'ko-KR-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'ko-KR-Neural2-B', name: 'Neural2-B (Female)' },
|
||||
{ value: 'ko-KR-Neural2-C', name: 'Neural2-C (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'lv-LV',
|
||||
name: 'Latvian (Latvia)',
|
||||
voices: [{ value: 'lv-LV-Standard-A', name: 'Standard-A (Male)' }],
|
||||
},
|
||||
{
|
||||
value: 'lt-LT',
|
||||
name: 'Lithuanian (Lithuania)',
|
||||
voices: [{ value: 'lt-LT-Standard-A', name: 'Standard-A (Male)' }],
|
||||
},
|
||||
{
|
||||
value: 'cmn-CN',
|
||||
name: 'Mandarin Chinese',
|
||||
voices: [
|
||||
{ value: 'cmn-CN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'cmn-CN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'cmn-CN-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'cmn-CN-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'cmn-CN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'cmn-CN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'cmn-CN-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'cmn-CN-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'cmn-TW',
|
||||
name: 'Mandarin Chinese (Traditional)',
|
||||
voices: [
|
||||
{ value: 'cmn-TW-Standard-A-Alpha', name: 'Standard-A-Alpha (Female)' },
|
||||
{ value: 'cmn-TW-Standard-B-Alpha', name: 'Standard-B-Alpha (Male)' },
|
||||
{ value: 'cmn-TW-Standard-C-Alpha', name: 'Standard-C-Alpha (Male)' },
|
||||
{ value: 'cmn-TW-Wavenet-A-Alpha', name: 'Wavenet-A-Alpha (Female)' },
|
||||
{ value: 'cmn-TW-Wavenet-B-Alpha', name: 'Wavenet-B-Alpha (Male)' },
|
||||
{ value: 'cmn-TW-Wavenet-C-Alpha', name: 'Wavenet-C-Alpha (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ms-MY',
|
||||
name: 'Malay (Malaysia)',
|
||||
voices: [
|
||||
{ value: 'ms-MY-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'ms-MY-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'ms-MY-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'ms-MY-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'ms-MY-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'ms-MY-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'ms-MY-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'ms-MY-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'ml-IN',
|
||||
name: 'Malayalam (India)',
|
||||
voices: [
|
||||
{ value: 'ml-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'ml-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'ml-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'ml-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'ml-IN-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'ml-IN-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'mr-IN',
|
||||
name: 'Marathi (India)',
|
||||
voices: [
|
||||
{ value: 'mr-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'mr-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'mr-IN-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'mr-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'mr-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'mr-IN-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'nb-NO',
|
||||
name: 'Norwegian (Norway)',
|
||||
voices: [
|
||||
{ value: 'nb-NO-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'nb-NO-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'nb-NO-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'nb-NO-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'nb-no-Standard-E', name: 'Standard-E (Female)' },
|
||||
{ value: 'nb-NO-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'nb-NO-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'nb-NO-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'nb-NO-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'nb-no-Wavenet-E', name: 'Wavenet-E (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'nl-BE',
|
||||
name: 'Dutch (Belgium)',
|
||||
voices: [
|
||||
{ value: 'nl-BE-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'nl-BE-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'nl-BE-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'nl-BE-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'pl-PL',
|
||||
name: 'Polish (Poland)',
|
||||
voices: [
|
||||
{ value: 'pl-PL-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'pl-PL-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'pl-PL-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'pl-PL-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'pl-PL-Standard-E', name: 'Standard-E (Female)' },
|
||||
{ value: 'pl-PL-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'pl-PL-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'pl-PL-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'pl-PL-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
{ value: 'pl-PL-Wavenet-E', name: 'Wavenet-E (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'pa-IN',
|
||||
name: 'Punjabi (India)',
|
||||
voices: [
|
||||
{ value: 'pa-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'pa-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'pa-IN-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'pa-IN-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'pa-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'pa-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'pa-IN-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'pa-IN-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'pt-BR',
|
||||
name: 'Portuguese (Brazil)',
|
||||
voices: [
|
||||
{ value: 'pt-BR-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'pt-BR-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'pt-BR-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'pt-BR-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'pt-BR-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
|
||||
{ value: 'pt-BR-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'pt-BR-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'pt-BR-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'pt-BR-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'pt-PT',
|
||||
name: 'Portuguese (Portugal)',
|
||||
voices: [
|
||||
{ value: 'pt-PT-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'pt-PT-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'pt-PT-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'pt-PT-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'pt-PT-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'pt-PT-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'pt-PT-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'pt-PT-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'ro-RO',
|
||||
name: 'Romanian (Romania)',
|
||||
voices: [
|
||||
{ value: 'ro-RO-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'ro-RO-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'ru-RU',
|
||||
name: 'Russian (Russia)',
|
||||
voices: [
|
||||
{ value: 'ru-RU-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'ru-RU-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'ru-RU-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'ru-RU-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'ru-RU-Standard-E', name: 'Standard-E (Female)' },
|
||||
{ value: 'ru-RU-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'ru-RU-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'ru-RU-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'ru-RU-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'ru-RU-Wavenet-E', name: 'Wavenet-E (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'sk-SK',
|
||||
name: 'Slovak (Slovakia)',
|
||||
voices: [
|
||||
{ value: 'sk-SK-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'sk-SK-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'sr-RS',
|
||||
name: 'Serbian (Cyrillic)',
|
||||
voices: [{ value: 'sr-RS-Standard-A', name: 'Standard-A (Female)' }],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'es-ES',
|
||||
name: 'Spanish (Spain)',
|
||||
voices: [
|
||||
{ value: 'es-ES-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'es-ES-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'es-ES-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'es-ES-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
{ value: 'es-ES-Neural2-D', name: 'Neural2-D (Female)' },
|
||||
{ value: 'es-ES-Neural2-E', name: 'Neural2-E (Female)' },
|
||||
{ value: 'es-ES-Neural2-F', name: 'Neural2-F (Male)' },
|
||||
{ value: 'es-ES-Polyglot-1', name: 'Polyglot-1 (Male)' },
|
||||
|
||||
{ value: 'es-ES-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'es-ES-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'es-ES-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'es-ES-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'es-ES-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'es-ES-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-US',
|
||||
name: 'Spanish (US)',
|
||||
voices: [
|
||||
{ value: 'es-US-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'es-US-Neural2-B', name: 'Neural2-B (Male)' },
|
||||
{ value: 'es-US-Neural2-C', name: 'Neural2-C (Male)' },
|
||||
{ value: 'es-US-Studio-B', name: 'Studio-B (Male)' },
|
||||
{ value: 'es-US-Polyglot-1', name: 'Polyglot-1 (Male)' },
|
||||
{ value: 'es-US-News-D', name: 'News-D (Male)' },
|
||||
{ value: 'es-US-News-E', name: 'News-E (Male)' },
|
||||
{ value: 'es-US-News-F', name: 'News-F (Female)' },
|
||||
{ value: 'es-US-News-G', name: 'News-G (Female)' },
|
||||
|
||||
{ value: 'es-US-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'es-US-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'es-US-Standard-C', name: 'Standard-C (Male)' },
|
||||
{ value: 'es-US-Studio-B', name: 'Studio-B (Male)' },
|
||||
{ value: 'es-US-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'es-US-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'es-US-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'sv-SE',
|
||||
name: 'Swedish (Sweden)',
|
||||
voices: [
|
||||
{ value: 'sv-SE-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'sv-SE-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
|
||||
{ value: 'sv-SE-Standard-B', name: 'Standard-B (Female)' },
|
||||
{ value: 'sv-SE-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'sv-SE-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'sv-SE-Standard-E', name: 'Standard-E (Male)' },
|
||||
{ value: 'sv-SE-Wavenet-B', name: 'Wavenet-B (Female)' },
|
||||
{ value: 'sv-SE-Wavenet-C', name: 'Wavenet-C (Male)' },
|
||||
{ value: 'sv-SE-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
{ value: 'sv-SE-Wavenet-E', name: 'Wavenet-E (Male)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'ta-IN',
|
||||
name: 'Tamil (India)',
|
||||
voices: [
|
||||
{ value: 'ta-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'ta-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'ta-IN-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'ta-IN-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'ta-IN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'ta-IN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'ta-IN-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'ta-IN-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'te-IN',
|
||||
name: 'Telugu (India)',
|
||||
voices: [
|
||||
{ value: 'te-IN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'te-IN-Standard-B', name: 'Standard-B (Male)' },
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
value: 'tr-TR',
|
||||
name: 'Turkish (Turkey)',
|
||||
voices: [
|
||||
{ value: 'tr-TR-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'tr-TR-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'tr-TR-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'tr-TR-Standard-D', name: 'Standard-D (Female)' },
|
||||
{ value: 'tr-TR-Standard-E', name: 'Standard-E (Male)' },
|
||||
{ value: 'tr-TR-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'tr-TR-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'tr-TR-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'tr-TR-Wavenet-D', name: 'Wavenet-D (Female)' },
|
||||
{ value: 'tr-TR-Wavenet-E', name: 'Wavenet-E (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'uk-UA',
|
||||
name: 'Ukrainian (Ukraine)',
|
||||
voices: [
|
||||
{ value: 'uk-UA-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'uk-UA-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'th-TH',
|
||||
name: 'Thai (Thailand)',
|
||||
voices: [
|
||||
{ value: 'th-TH-Neural2-C', name: 'Neural2-C (Female)' },
|
||||
|
||||
{ value: 'th-TH-Standard-A', name: 'Standard-A (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'vi-VN',
|
||||
name: 'Vietnamese (Vietnam)',
|
||||
voices: [
|
||||
{ value: 'vi-VN-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'vi-VN-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'vi-VN-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'vi-VN-Standard-D', name: 'Standard-D (Male)' },
|
||||
{ value: 'vi-VN-Wavenet-A', name: 'Wavenet-A (Female)' },
|
||||
{ value: 'vi-VN-Wavenet-B', name: 'Wavenet-B (Male)' },
|
||||
{ value: 'vi-VN-Wavenet-C', name: 'Wavenet-C (Female)' },
|
||||
{ value: 'vi-VN-Wavenet-D', name: 'Wavenet-D (Male)' },
|
||||
{ value: 'vi-VN-Neural2-A', name: 'Neural2-A (Female)' },
|
||||
{ value: 'vi-VN-Neural2-D', name: 'Neural2-D (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'yue-HK',
|
||||
name: 'Chinese (Hong Kong)',
|
||||
voices: [
|
||||
{ value: 'yue-HK-Standard-A', name: 'Standard-A (Female)' },
|
||||
{ value: 'yue-HK-Standard-B', name: 'Standard-B (Male)' },
|
||||
{ value: 'yue-HK-Standard-C', name: 'Standard-C (Female)' },
|
||||
{ value: 'yue-HK-Standard-D', name: 'Standard-D (Male)' },
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -1,167 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'de-DE',
|
||||
name: 'German (Germany)',
|
||||
voices: [
|
||||
{ value: 'de-DE_DieterVoice', name: 'Dieter (Male): Standard German' },
|
||||
{
|
||||
value: 'de-DE_DieterV2Voice',
|
||||
name: 'Dieter 2 (Male): Standard German',
|
||||
},
|
||||
{
|
||||
value: 'de-DE_DieterV3Voice',
|
||||
name: 'Dieter 3 (Male): Standard German',
|
||||
},
|
||||
{ value: 'de-DE_ErikaV3Voice', name: 'Erika (Female): Standard German' },
|
||||
{ value: 'de-DE_BirgitVoice', name: 'Brigit (Female): Standard German' },
|
||||
{
|
||||
value: 'de-DE_BirgitV2Voice',
|
||||
name: 'Brigit 2 (Female): Standard German',
|
||||
},
|
||||
{
|
||||
value: 'de-DE_BirgitV3Voice',
|
||||
name: 'Brigit 3 (Female): Standard German',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English (US)',
|
||||
voices: [
|
||||
{
|
||||
value: 'en-US_MichaelExpressive',
|
||||
name: 'Michael (Male): American English - Expressive',
|
||||
},
|
||||
{ value: 'en-US_MichaelVoice', name: 'Michael (Male): American English' },
|
||||
{
|
||||
value: 'en-US_MichaelV2Voice',
|
||||
name: 'Michael 2 (Male): American English',
|
||||
},
|
||||
{
|
||||
value: 'en-US_MichaelV3Voice',
|
||||
name: 'Michael 3 (Male): American English',
|
||||
},
|
||||
{ value: 'en-US_HenryV3Voice', name: 'Henry (Male): American English' },
|
||||
{ value: 'en-US_EmilyV3Voice', name: 'Emily (Female): American English' },
|
||||
{
|
||||
value: 'en-US_OliviaV3Voice',
|
||||
name: 'Olivia (Female): American English',
|
||||
},
|
||||
{
|
||||
value: 'en-US_AllisonExpressive',
|
||||
name: 'Allison (Female): American English - Expressive',
|
||||
},
|
||||
{
|
||||
value: 'en-US_AllisonVoice',
|
||||
name: 'Allison (Female): American English',
|
||||
},
|
||||
{
|
||||
value: 'en-US_AllisonV2Voice',
|
||||
name: 'Allison 2 (Female): American English',
|
||||
},
|
||||
{
|
||||
value: 'en-US_AllisonV3Voice',
|
||||
name: 'Allison 3 (Female): American English',
|
||||
},
|
||||
{
|
||||
value: 'en-US_LisaExpressive',
|
||||
name: 'Lisa (Female): American English - Expressive',
|
||||
},
|
||||
{ value: 'en-US_LisaVoice', name: 'Lisa (Female): American English' },
|
||||
{ value: 'en-US_LisaV2Voice', name: 'Lisa 2 (Female): American English' },
|
||||
{ value: 'en-US_LisaV3Voice', name: 'Lisa 3 (Female): American English' },
|
||||
{ value: 'en-US_KevinV3Voice', name: 'Kevin (Male): American English' },
|
||||
{
|
||||
value: 'en-US_EmmaExpressive',
|
||||
name: 'Emma (Female): American English - Expressive',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-GB',
|
||||
name: 'English (GB)',
|
||||
voices: [
|
||||
{ value: 'en-GB_JamesV3Voice', name: 'James (Male)' },
|
||||
{ value: 'en-GB_KateVoice', name: 'Kate (Female)' },
|
||||
{ value: 'en-GB_KateV3Voice', name: 'Kate 2 (Female)' },
|
||||
{ value: 'en-GB_CharlotteV3Voice', name: 'Charlotte (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-US',
|
||||
name: 'Spanish (North America)',
|
||||
voices: [
|
||||
{
|
||||
value: 'es-US_SofiaVoice',
|
||||
name: 'Sofia (Female): North American Spanish',
|
||||
},
|
||||
{
|
||||
value: 'es-US_SofiaV3Voice',
|
||||
name: 'Sofia 2 (Female): North American Spanish',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-LA',
|
||||
name: 'Spanish (Latin America)',
|
||||
voices: [
|
||||
{
|
||||
value: 'es-LA_SofiaVoice',
|
||||
name: 'Sofia (Female): Latin American Spanish',
|
||||
},
|
||||
{
|
||||
value: 'es-LA_SofiaV3Voice',
|
||||
name: 'Sofia 2 (Female): Latin American Spanish',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-ES',
|
||||
name: 'Spanish (Castilian)',
|
||||
voices: [
|
||||
{ value: 'es-ES_LauraVoice', name: 'Laura (Female)' },
|
||||
{ value: 'es-ES_LauraV3Voice', name: 'Laura 2 (Female)' },
|
||||
{ value: 'es-ES_EnriqueVoice', name: 'Enrique (Male)' },
|
||||
{ value: 'es-ES_EnriqueV3Voice', name: 'Enrique 2 (Male)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fr-FR',
|
||||
name: 'French (FR)',
|
||||
voices: [
|
||||
{ value: 'fr-FR_NicolasV3Voice', name: 'Nicolas (Male)' },
|
||||
{ value: 'fr-FR_ReneeVoice', name: 'Renee (Female)' },
|
||||
{ value: 'fr-FR_ReneeV3Voice', name: 'Renee 2 (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fr-CA',
|
||||
name: 'French (CA)',
|
||||
voices: [{ value: 'fr-CA_LouiseV3Voice', name: 'Louise (Female)' }],
|
||||
},
|
||||
{
|
||||
value: 'it-IT',
|
||||
name: 'Italian',
|
||||
voices: [
|
||||
{ value: 'it-IT_FrancescaVoice', name: 'Francesca (Female)' },
|
||||
{ value: 'it-IT_FrancescaV2Voice', name: 'Francesca 2 (Female)' },
|
||||
{ value: 'it-IT_FrancescaV3Voice', name: 'Francesca 3 (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'pt-BR',
|
||||
name: 'Portuguese (Brazil)',
|
||||
voices: [
|
||||
{ value: 'pt-BR_IsabelaVoice', name: 'Isabela (Female)' },
|
||||
{ value: 'pt-BR_IsabelaV3Voice', name: 'Isabela 2 (Female)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ja-JP',
|
||||
name: 'Japanese',
|
||||
voices: [
|
||||
{ value: 'ja-JP_EmiVoice', name: 'Emi (Female)' },
|
||||
{ value: 'ja-JP_EmiV3Voice', name: 'Emi 2 (Female)' },
|
||||
],
|
||||
},
|
||||
];
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,28 +0,0 @@
|
||||
const TtsAwsLanguagesVoiceRaw = require('./tts-microsoft-raw');
|
||||
|
||||
const languagesVoices = [];
|
||||
|
||||
TtsAwsLanguagesVoiceRaw.forEach((data) => {
|
||||
const lang = languagesVoices.find((l) => {
|
||||
return l.value === data.Locale;
|
||||
});
|
||||
|
||||
if (!lang) {
|
||||
languagesVoices.push({
|
||||
value: data.Locale,
|
||||
name: data.LocaleName,
|
||||
voices: TtsAwsLanguagesVoiceRaw
|
||||
.filter((d) => {
|
||||
return d.Locale === data.Locale;
|
||||
})
|
||||
.map((d) => {
|
||||
return {
|
||||
value: d.ShortName,
|
||||
name: `${d.DisplayName} (${d.Gender})`,
|
||||
};
|
||||
}),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = languagesVoices;
|
||||
@@ -1,14 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'Asteria English (US) Female', value: 'aura-asteria-en' },
|
||||
{ name: 'Luna English (US) Female', value: 'aura-luna-en' },
|
||||
{ name: 'Stella English (US) Female', value: 'aura-stella-en' },
|
||||
{ name: 'Stella English (UK) Female', value: 'aura-athena-en' },
|
||||
{ name: 'Hera English (US) Female', value: 'aura-hera-en' },
|
||||
{ name: 'Orion English (US) Male', value: 'aura-orion-en' },
|
||||
{ name: 'Arcas English (US) Male', value: 'aura-arcas-en' },
|
||||
{ name: 'Perseus English (US) Male', value: 'aura-perseus-en' },
|
||||
{ name: 'Angus English (Ireland) Male', value: 'aura-angus-en' },
|
||||
{ name: 'Orpheus English (US) Male', value: 'aura-orpheus-en' },
|
||||
{ name: 'Helios English (UK) Male', value: 'aura-helios-en' },
|
||||
{ name: 'Zeus English (US) Male', value: 'aura-zeus-en' },
|
||||
];
|
||||
@@ -1,9 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'Turbo v2', value: 'eleven_turbo_v2' },
|
||||
{ name: 'Turbo v2.5', value: 'eleven_turbo_v2_5' },
|
||||
{ name: 'Multilingual v2', value: 'eleven_multilingual_v2' },
|
||||
{ name: 'Multilingual v1', value: 'eleven_multilingual_v1' },
|
||||
{ name: 'English v1', value: 'eleven_monolingual_v1' },
|
||||
{ name: 'English v2', value: 'eleven_english_sts_v2' },
|
||||
];
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'PlayHT2.0-turbo', value: 'PlayHT2.0-turbo' },
|
||||
{ name: 'PlayHT2.0', value: 'PlayHT2.0' },
|
||||
{ name: 'PlayHT1.0', value: 'PlayHT1.0' },
|
||||
];
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'Mist', value: 'mist' },
|
||||
{ name: 'V1', value: 'v1' },
|
||||
];
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = [
|
||||
{ name: 'TTS-1', value: 'tts-1' },
|
||||
{ name: 'TTS-1-HD', value: 'tts-1-hd' },
|
||||
];
|
||||
|
||||
@@ -1,958 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'ar-WW',
|
||||
name: 'Arabic (Worldwide)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Laila - standard',
|
||||
name: 'Laila (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Tarik - standard',
|
||||
name: 'Tarik (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Miriam - standard',
|
||||
name: 'Miriam (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'eu-ES',
|
||||
name: 'Basque (Spain)',
|
||||
voices: [{ value: 'Miren', name: 'Miren (standard)', model: 'standard' }],
|
||||
},
|
||||
{
|
||||
value: 'bn-IN',
|
||||
name: 'Bengali (India)',
|
||||
voices: [
|
||||
{ value: 'Paya - standard', name: 'Paya (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'bho-IN',
|
||||
name: 'Bhojpuri (India)',
|
||||
voices: [
|
||||
{ value: 'Jaya - standard', name: 'Jaya (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'bg-BG',
|
||||
name: 'Bulgarian (Bulgaria)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Daria - standard',
|
||||
name: 'Daria (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'yue-HK',
|
||||
name: 'Cantonese (Hong Kong)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Sinji-Ml - standard',
|
||||
name: 'Sinji-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ca-ES',
|
||||
name: 'Catalan (Spain)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Jordi - standard',
|
||||
name: 'Jordi (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Montserrat - standard',
|
||||
name: 'Montserrat (standard)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'yue-HK',
|
||||
name: 'Croatian (Croatia)',
|
||||
voices: [
|
||||
{ value: 'Lana - standard', name: 'Lana (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'cs-CZ',
|
||||
name: 'Czech (Czech Republic)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Iveta - standard',
|
||||
name: 'Iveta (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Zuzana - standard',
|
||||
name: 'Zuzana (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Zuzana-ml - enhanced',
|
||||
name: 'Zuzana (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'da-DK',
|
||||
name: 'Danish (Denmark)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Magnus - standard',
|
||||
name: 'Magnus (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'Sara - standard', name: 'Sara (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'nl-BE',
|
||||
name: 'Dutch (Belgium)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Ellen - standard',
|
||||
name: 'Ellen (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'nl-NL',
|
||||
name: 'Dutch (Belgium)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Claire-Ml - standard',
|
||||
name: 'Claire-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Xander - standard',
|
||||
name: 'Xander (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-AU',
|
||||
name: 'English (Australia)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Karen - standard',
|
||||
name: 'Karen (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'Lee - standard', name: 'Lee (standard)', model: 'standard' },
|
||||
{
|
||||
value: 'Matilda - enhanced',
|
||||
name: 'Matilda (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-IN',
|
||||
name: 'English (India)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Isha-Ml - enhanced',
|
||||
name: 'Isha-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Rishi - standard',
|
||||
name: 'Rishi (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Rishi-Ml - standard',
|
||||
name: 'Rishi-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Sangeeta - standard',
|
||||
name: 'Sangeeta (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Veena - standard',
|
||||
name: 'Veena (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-IE',
|
||||
name: 'English (Ireland)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Moira - standard',
|
||||
name: 'Moira (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-SC',
|
||||
name: 'English (Scotland)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Fiona - standard',
|
||||
name: 'Fiona (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-ZA',
|
||||
name: 'English (South Africa)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Tessa - standard',
|
||||
name: 'Tessa (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-GB',
|
||||
name: 'English (United Kingdom)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Daniel - standard',
|
||||
name: 'Daniel (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'Kate - standard', name: 'Kate (standard)', model: 'standard' },
|
||||
{
|
||||
value: 'Malcolm - standard',
|
||||
name: 'Malcolm (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Oliver - standard',
|
||||
name: 'Oliver (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Serena - enhanced',
|
||||
name: 'Serena (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Simon - standard',
|
||||
name: 'Simon (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Stephanie - standard',
|
||||
name: 'Stephanie (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English (United States)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Allison - standard',
|
||||
name: 'Allison (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Ava-Ml - enhanced',
|
||||
name: 'Ava-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Chloe - standard',
|
||||
name: 'Chloe (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'Evan - enhanced', name: 'Evan (enhanced)', model: 'enhanced' },
|
||||
{
|
||||
value: 'Nathan - enhanced',
|
||||
name: 'Nathan (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Evelyn - standard',
|
||||
name: 'Evelyn (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Nolan - standard',
|
||||
name: 'Nolan (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Samantha - standard',
|
||||
name: 'Samantha (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Susan - standard',
|
||||
name: 'Susan (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'Tom - standard', name: 'Tom (standard)', model: 'standard' },
|
||||
{
|
||||
value: 'Zoe-Ml - enhanced',
|
||||
name: 'Zoe-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fi-FI',
|
||||
name: 'Finnish (Finland)',
|
||||
voices: [
|
||||
{ value: 'Onni - standard', name: 'Onni (standard)', model: 'standard' },
|
||||
{ value: 'Satu - standard', name: 'Satu (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fr-BE',
|
||||
name: 'French (Belgium)',
|
||||
voices: [
|
||||
{ value: 'Aude - standard', name: 'Aude (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fr-CA',
|
||||
name: 'French (Canada)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Amelie-Ml - enhanced',
|
||||
name: 'Amelie-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Chantal - standard',
|
||||
name: 'Chantal (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Nicolas - standard',
|
||||
name: 'Nicolas (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'fr-FR',
|
||||
name: 'French (France)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Audrey-Ml - enhanced',
|
||||
name: 'Audrey-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Aurelie - standard',
|
||||
name: 'Aurelie (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Thomas - standard',
|
||||
name: 'Thomas (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'gl-ES',
|
||||
name: 'Galician (Spain)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Carmela - standard',
|
||||
name: 'Carmela (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'de-DE',
|
||||
name: 'German (Germany)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Anna-Ml - enhanced',
|
||||
name: 'Anna-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Markus - standard',
|
||||
name: 'Markus (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Petra-Ml - enhanced',
|
||||
name: 'Petra-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Viktor - standard',
|
||||
name: 'Viktor (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Yannick - standard',
|
||||
name: 'Yannick (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'el-GR',
|
||||
name: 'Greek (Greece)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Melina - standard',
|
||||
name: 'Melina (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Nikos - standard',
|
||||
name: 'Nikos (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'he-IL',
|
||||
name: 'Hebrew (Israel)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Carmit - standard',
|
||||
name: 'Carmit (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'hi-IN',
|
||||
name: 'Hindi (India)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Kiyara-Ml - enhanced',
|
||||
name: 'Kiyara-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Lekha - standard',
|
||||
name: 'Lekha (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'neel - standard', name: 'Neel (standard)', model: 'standard' },
|
||||
{
|
||||
value: 'Neel-Ml - standard',
|
||||
name: 'Neel-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'hu-HU',
|
||||
name: 'Hungarian (Hungary)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Mariska - standard',
|
||||
name: 'Mariska (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'id-ID',
|
||||
name: 'Indonesian (Indonesia)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Damayanti - standard',
|
||||
name: 'Damayanti (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'it-IT',
|
||||
name: 'Italian (Italy)',
|
||||
voices: [
|
||||
{ value: 'Emma - enhanced', name: 'Emma (enhanced)', model: 'enhanced' },
|
||||
{
|
||||
value: 'Federica-Ml - standard',
|
||||
name: 'Federica-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'Luca - standard', name: 'Luca (standard)', model: 'standard' },
|
||||
{
|
||||
value: 'Neel-Ml - standard',
|
||||
name: 'Neel-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Paola - standard',
|
||||
name: 'Paola (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ja-JP',
|
||||
name: 'Japanese (Japan)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Ayane - standard',
|
||||
name: 'Ayane (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Daisuke - standard',
|
||||
name: 'Daisuke (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Ichiro - standard',
|
||||
name: 'Ichiro (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Koharu - standard',
|
||||
name: 'Koharu (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Kyoko - standard',
|
||||
name: 'Kyoko (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Mizuki - standard',
|
||||
name: 'Mizuki (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Otoya - standard',
|
||||
name: 'Otoya (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Sakura - standard',
|
||||
name: 'Sakura (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Seiji - standard',
|
||||
name: 'Seiji (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'kn-IN',
|
||||
name: 'Kannada (India)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Alpana - standard',
|
||||
name: 'Alpana (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ko-KR',
|
||||
name: 'Korean (South Korea)',
|
||||
voices: [
|
||||
{ value: 'Jina - enhanced', name: 'Jina (enhanced)', model: 'enhanced' },
|
||||
{ value: 'Sora - standard', name: 'Sora (standard)', model: 'standard' },
|
||||
{ value: 'Yuna - standard', name: 'Yuna (standard)', model: 'standard' },
|
||||
{
|
||||
value: 'Yuna-Ml - enhanced',
|
||||
name: 'Yuna-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'zlm-MY',
|
||||
name: 'Malay (Malaysia)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Amira - standard',
|
||||
name: 'Amira (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'zh-CN',
|
||||
name: 'Mandarin (China)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Lili-Ml - enhanced',
|
||||
name: 'Lili-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Binbin-Ml - standard',
|
||||
name: 'Binbin-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Lilian-Ml - standard',
|
||||
name: 'Lilian-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Lisheng-Ml - standard',
|
||||
name: 'Lisheng-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Tiantian-Ml - standard',
|
||||
name: 'Tiantian-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Tingting-Ml - standard',
|
||||
name: 'Tingting-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'cmn-TW',
|
||||
name: 'Mandarin (Taiwan)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Meijia-Ml - standard',
|
||||
name: 'Meijia-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'mr-IN',
|
||||
name: 'Marathi (India)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Ananya - standard',
|
||||
name: 'Ananya (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'nb-NO',
|
||||
name: 'Norwegian Bokmål (Norway)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Henrik - standard',
|
||||
name: 'Henrik (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'Nora - standard', name: 'Nora (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'pl-PL',
|
||||
name: 'Polish (Poland)',
|
||||
voices: [
|
||||
{ value: 'Ewa - enhanced', name: 'Ewa (enhanced)', model: 'enhanced' },
|
||||
{
|
||||
value: 'Krzysztof - standard',
|
||||
name: 'Krzysztof (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Zosia - standard',
|
||||
name: 'Zosia (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'pt-BR',
|
||||
name: 'Portuguese (Brazil)',
|
||||
voices: [
|
||||
{
|
||||
value: 'luciana - enhanced',
|
||||
name: 'Luciana (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Fernanda - standard',
|
||||
name: 'Fernanda (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Felipe - standard',
|
||||
name: 'Felipe (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'pt-PT',
|
||||
name: 'Portuguese (Portugal)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Catarina - standard',
|
||||
name: 'Catarina (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Joana - standard',
|
||||
name: 'Joana (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Joaquim - standard',
|
||||
name: 'Joaquim (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ro-RO',
|
||||
name: 'Romanian (Romania)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Ioana - standard',
|
||||
name: 'Ioana (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ru-RU',
|
||||
name: 'Russian (Russia)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Katya - standard',
|
||||
name: 'Katya (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Katya-Ml - standard',
|
||||
name: 'Katya-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Milena - standard',
|
||||
name: 'Milena (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'yuri - standard', name: 'Yuri (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'sk-SK',
|
||||
name: 'Slovak (Slovakia)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Laura - standard',
|
||||
name: 'Laura (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-AR',
|
||||
name: 'Spanish (Argentina)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Diego - standard',
|
||||
name: 'Diego (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Isabela - standard',
|
||||
name: 'Isabela (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-CL',
|
||||
name: 'Spanish (Chile)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Francisca - standard',
|
||||
name: 'Francisca (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-CO',
|
||||
name: 'Spanish (Colombia)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Carlos - standard',
|
||||
name: 'Carlos (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Soledad - standard',
|
||||
name: 'Soledad (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Ximena - standard',
|
||||
name: 'Ximena (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-MX',
|
||||
name: 'Spanish (Mexico)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Angelica - standard',
|
||||
name: 'Angelica (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Javier - standard',
|
||||
name: 'Javier (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{ value: 'Juan - standard', name: 'Juan (standard)', model: 'standard' },
|
||||
{
|
||||
value: 'Paulina-Ml - enhanced',
|
||||
name: 'Paulina-Ml (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-ES',
|
||||
name: 'Spanish (Spain)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Jorge - standard',
|
||||
name: 'Jorge (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Marisol-Ml - standard',
|
||||
name: 'Marisol-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Monica-Ml - standard',
|
||||
name: 'Monica-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'sv-SE',
|
||||
name: 'Swedish (Sweden)',
|
||||
voices: [
|
||||
{ value: 'Alva - standard', name: 'Alva (standard)', model: 'standard' },
|
||||
{
|
||||
value: 'Klara - standard',
|
||||
name: 'Klara (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Oskar - standard',
|
||||
name: 'Oskar (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ta-IN',
|
||||
name: 'Tamil (India)',
|
||||
voices: [
|
||||
{ value: 'Vani - standard', name: 'Vani (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'te-IN',
|
||||
name: 'Telugu (India)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Geeta - standard',
|
||||
name: 'Geeta (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'th-TH',
|
||||
name: 'Thai (Thailand)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Kanya - enhanced',
|
||||
name: 'Kanya (enhanced)',
|
||||
model: 'enhanced',
|
||||
},
|
||||
{
|
||||
value: 'Narisa - standard',
|
||||
name: 'Narisa (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'tr-TR',
|
||||
name: 'Turkish (Turkey)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Cem-Ml - standard',
|
||||
name: 'Cem-Ml (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
{
|
||||
value: 'Yelda - standard',
|
||||
name: 'Yelda (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'uk-UA',
|
||||
name: 'Ukrainian (Ukraine)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Lesya - standard',
|
||||
name: 'Lesya (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'va-ES',
|
||||
name: 'Valencian (Spain)',
|
||||
voices: [
|
||||
{
|
||||
value: 'Empar - standard',
|
||||
name: 'Empar (standard)',
|
||||
model: 'standard',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'vi-VN',
|
||||
name: 'Vietnamese (Vietnam)',
|
||||
voices: [
|
||||
{ value: 'Linh - standard', name: 'Linh (standard)', model: 'standard' },
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -1,16 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English',
|
||||
voices: [
|
||||
{
|
||||
value: 'English-US.Female-1',
|
||||
name: 'Female',
|
||||
},
|
||||
{
|
||||
value: 'English-US.Male-1',
|
||||
name: 'Male',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -1,710 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English (US)',
|
||||
voices: [
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/abigail_vo_6661b91f-4012-44e3-ad12-589fbdee9948/voices/speaker/manifest.json',
|
||||
name: 'Abigail - american, female, narrative, smooth',
|
||||
},
|
||||
{
|
||||
value: 'abram',
|
||||
name: 'Abram - british, old, male, low, narrative, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'adolfo',
|
||||
name: 'Adolfo - american, adult, male, neutral, narrative, fast, thick',
|
||||
},
|
||||
{
|
||||
value: 'adrian',
|
||||
name: 'Adrian - american, old, male, neutral, narrative, fast, thick',
|
||||
},
|
||||
{
|
||||
value: 'ahmed',
|
||||
name: 'Logan - british, old, male, neutral, narrative, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 'alex',
|
||||
name: 'Alex - british, adult, male, high, narrative, slow, thick',
|
||||
},
|
||||
{
|
||||
value: 'alexander',
|
||||
name: 'Alexander - british, old, male, high, narrative, fast, thick',
|
||||
},
|
||||
{
|
||||
value: 'alfonso',
|
||||
name: 'Alfonso - american, adult, male, neutral, videos, neutral, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'alphonso',
|
||||
name: 'Alphonso - american, adult, female, low, videos, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'amado',
|
||||
name: 'Amado - american, old, male, low, narrative, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 'anny',
|
||||
name: 'Anny - american, youth, female, neutral, narrative, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 'anthony',
|
||||
name: 'Anthony - american, adult, male, neutral, training, slow, thick',
|
||||
},
|
||||
{
|
||||
value: 'spencer',
|
||||
name: 'April - british, adult, female, neutral, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'victor',
|
||||
name: 'Ariana - american, youth, female, high, videos, fast, thick',
|
||||
},
|
||||
{
|
||||
value: 'arthur',
|
||||
name: 'Arthur - british, adult, male, neutral, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'aubrey',
|
||||
name: 'Aubrey - british, adult, male, neutral, videos, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'hipolito',
|
||||
name: 'Audrey - american, adult, female, low, narrative, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'aurora',
|
||||
name: 'Aurora - british, adult, female, low, training, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'axel',
|
||||
name: 'Axel - american, adult, male, neutral, narrative, fast, thick',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/ayla_vo_commercials_d66900d5-69f5-476f-9bd6-8eab2936dda3/voices/speaker/manifest.json',
|
||||
name: 'Ayla (Advertising) - american, female, advertising',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/ayla_vo_expressive_16095e08-b9e8-429b-947c-47a75e41053b/voices/speaker/manifest.json',
|
||||
name: 'Ayla (Expressive) - american, female, narrative',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/ayla_vo_meditation_d11dd9da-b5f1-4709-95a6-e6d5dc77614a/voices/speaker/manifest.json',
|
||||
name: 'Ayla (Meditation) - american, female, meditation',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/ayla_vo_narrative_d8199dfd-b50f-40c7-9d99-e203ba5f4152/voices/speaker/manifest.json',
|
||||
name: 'Ayla (Narrative) - american, female, narrative',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/ayla_vo_training_e6751ca5-e47c-4c4b-ad05-d3a194417600/voices/speaker/manifest.json',
|
||||
name: 'Ayla (Training) - american, female, training',
|
||||
},
|
||||
{
|
||||
value: 'benton',
|
||||
name: 'Benton - american, old, male, high, videos, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 'bertram',
|
||||
name: 'Bertram - british, adult, male, low, narrative, neutral, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'bill',
|
||||
name: 'Harper - american, adult, female, high, videos, fast, smooth',
|
||||
},
|
||||
{
|
||||
// eslint-disable-next-line max-len
|
||||
value:'s3://mockingbird-prod/nathan_drake_carmelo_pampillonio_7d540ad6-7d32-41f6-8d53-2584901aa03d/voices/speaker/manifest.json',
|
||||
name: 'Billy - american, male, gaming',
|
||||
},
|
||||
{
|
||||
value: 'blaine',
|
||||
name: 'Blaine - british, adult, male, high, narrative, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 'booker',
|
||||
name: 'Booker - british, youth, male, neutral, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'bret',
|
||||
name: 'Bret - american, adult, female, neutral, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'bruce',
|
||||
name: 'Bruce - british, adult, male, high, training, fast, thick',
|
||||
},
|
||||
{
|
||||
value: 'bryan',
|
||||
name: 'Bryan - american, adult, male, low, videos, fast, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'carlo',
|
||||
name: 'Carlo - british, adult, male, neutral, advertising, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'carter',
|
||||
name: 'Carter - american, adult, male, neutral, narrative, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 'charles',
|
||||
name: 'Charles - american, adult, male, neutral, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'charlotte',
|
||||
name: 'Charlotte - canadian, adult, female, low, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/028a32d4-6a79-4ca3-a303-d6559843114b/chris/manifest.json',
|
||||
name: 'Chris - american, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 'chuck',
|
||||
name: 'Chuck - british, adult, male, neutral, videos, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'clark',
|
||||
name: 'Clark - british, old, male, neutral, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'clifton',
|
||||
name: 'Clifton - american, old, male, high, narrative, neutral, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'hayden',
|
||||
name: 'Cooper - american, adult, male, neutral, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'daisy',
|
||||
name: 'Daisy - british, adult, female, low, narrative, neutral, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'dane',
|
||||
name: 'Dane - american, adult, male, neutral, videos, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'daniel',
|
||||
name: 'Daniel - canadian, adult, male, low, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'darnell',
|
||||
name: 'Darnell - american, youth, male, neutral, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'daron',
|
||||
name: 'Daron - american, old, male, low, narrative, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'darrell',
|
||||
name: 'Darrell - british, adult, male, neutral, advertising, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/a10/manifest.json',
|
||||
name: 'Davis - american, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 'ignacio',
|
||||
name: 'Delilah - american, adult, female, neutral, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'denis',
|
||||
name: 'Eleanor - british, adult, female, neutral, advertising, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'dick',
|
||||
name: 'Dick - american, adult, male, neutral, training, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 'domenic',
|
||||
name: 'Domenic - british, adult, male, high, videos, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/donna_meditation_saad/manifest.json',
|
||||
name: 'Donna (Meditation) - american, female, meditation',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/donna_parrot_saad/manifest.json',
|
||||
name: 'Donna (Narrative) - american, female, narrative',
|
||||
},
|
||||
{
|
||||
value: 'donovan',
|
||||
name: 'Donovan - american, adult, male, low, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'dudley',
|
||||
name: 'Dudley - american, old, male, low, narrative, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 'dylan',
|
||||
name: 'Dylan - british, old, male, high, gaming, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'earle',
|
||||
name: 'Earle - british, adult, male, high, narrative, neutral, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'efren',
|
||||
name: 'Efren - american, adult, male, neutral, training, slow, thick',
|
||||
},
|
||||
{
|
||||
value: 'denis',
|
||||
name: 'Eleanor - british, adult, female, neutral, advertising, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'elijah',
|
||||
name: 'Elijah - american, old, male, neutral, training, neutral, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'ellie',
|
||||
name: 'Ellie - american, adult, female, low, training, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'erasmo',
|
||||
name: 'Erasmo - american, old, male, low, training, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/evelyn 2 saad parrot/manifest.json',
|
||||
name: 'Evelyn - american, adult, female, low, videos, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'fletcher',
|
||||
name: 'Fletcher - british, adult, male, neutral, narrative, fast, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'florencio',
|
||||
name: 'Madison - british, old, female, neutral, narrative, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'flynn',
|
||||
name: 'Flynn - british, adult, male, neutral, narrative, fast, round',
|
||||
},
|
||||
{
|
||||
value: 'gabriel',
|
||||
name: 'Samantha - american, old, female, neutral, narrative, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 'greg',
|
||||
name: 'Greg - british, adult, male, high, narrative, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'harold',
|
||||
name: 'Harold - american, adult, male, neutral, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'bill',
|
||||
name: 'Harper - american, adult, female, high, videos, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 'harris',
|
||||
name: 'Harris - british, adult, male, low, narrative, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 'harrison',
|
||||
name: 'Harrison - american, adult, male, neutral, narrative, fast, round',
|
||||
},
|
||||
{
|
||||
value: 'hayden',
|
||||
name: 'Cooper - american, adult, male, neutral, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'hipolito',
|
||||
name: 'Audrey - american, adult, female, low, narrative, slow, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/hook_1_chico_a3e5e83f-08ae-4a9f-825c-7e48d32d2fd8/voices/speaker/manifest.json',
|
||||
name: 'Hook - american, male, gaming',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/hudson saad parrot/manifest.json',
|
||||
name: 'Hudson - american, adult, male, neutral, videos, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 'hunter',
|
||||
name: 'Hunter - british, old, male, high, narrative, fast, round',
|
||||
},
|
||||
{
|
||||
value: 'ignacio',
|
||||
name: 'Delilah - american, adult, female, neutral, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/mel28/manifest.json',
|
||||
name: 'Jack - american, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 'jarrett',
|
||||
name: 'Jarrett - american, adult, male, low, advertising, slow, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/801a663f-efd0-4254-98d0-5c175514c3e8/jennifer/manifest.json',
|
||||
name: 'Jennifer - american, adult, female,',
|
||||
},
|
||||
{
|
||||
value: 'jerrell',
|
||||
name: 'Jerrell - american, adult, male, low, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'jordan',
|
||||
name: 'Jordan - american, adult, male, neutral, training, slow, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/dc23bb38-f568-4323-b6fb-7d64f685b97a/joseph/manifest.json',
|
||||
name: 'Joseph - american, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 'judson',
|
||||
name: 'Judson - american, adult, male, low, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'lance',
|
||||
name: 'Lance - british, adult, male, low, videos, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'larry',
|
||||
name: 'Larry - american, adult, male, neutral, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/larry_ads3_parrot_saad/manifest.json',
|
||||
name: 'Larry (Advertising) - american, adult, male, neutral, advertising, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/larry_vo_narrative_4bd5c1bd-f662-4a38-b5b9-76563f7b92ec/voices/speaker/manifest.json',
|
||||
name: 'Larry (Narrative) - american, adult, male, neutral, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'lillian',
|
||||
name: 'Lillian - british, old, female, neutral, training, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'ahmed',
|
||||
name: 'Logan - british, old, male, neutral, narrative, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 'lottie',
|
||||
name: 'Lottie - british, adult, female, low, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'lucius',
|
||||
name: 'Lucius - british, adult, male, low, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'mickey',
|
||||
name: 'Madelyn - british, adult, female, neutral, videos, fast, thick',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/09b5c0cc-a8f4-4450-aaab-3657b9965d0b/podcaster/manifest.json',
|
||||
name: 'Matt - american, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/mel21/manifest.json',
|
||||
name: 'Melissa - american, adult, female,',
|
||||
},
|
||||
{
|
||||
value: 'micah',
|
||||
name: 'Micah - british, adult, female, neutral, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/7c339a9d-370f-4643-adf5-4134e3ec9886/mlae02/manifest.json',
|
||||
name: 'Michael - american, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 'mickey',
|
||||
name: 'Madelyn - british, adult, female, neutral, videos, fast, thick',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/7c38b588-14e8-42b9-bacd-e03d1d673c3c/nicole/manifest.json',
|
||||
name: 'Nicole - american, adult, female,',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/nolan saad parrot/manifest.json',
|
||||
name: 'Nolan - british, adult, male, high, videos, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'nova',
|
||||
name: 'Nova - american, adult, female, whisper, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'oliver',
|
||||
name: 'Oliver - british, adult, male, high, videos, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'oscar',
|
||||
name: 'Oscar - british, adult, male, neutral, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'owen',
|
||||
name: 'Owen - american, youth, male, high, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'pedro',
|
||||
name: 'Pedro - american, adult, male, neutral, narrative, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'phoebe',
|
||||
name: 'Phoebe - british, adult, female, high, videos, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 'randall',
|
||||
name: 'Randall - british, adult, male, high, narrative, fast, thick',
|
||||
},
|
||||
{
|
||||
value: 'reynaldo',
|
||||
name: 'Reynaldo - british, old, male, low, narrative, fast, smooth',
|
||||
},
|
||||
{
|
||||
value: 'rodrick',
|
||||
name: 'Rodrick - american, adult, male, neutral, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'gabriel',
|
||||
name: 'Samantha - american, old, female, neutral, narrative, neutral, thick',
|
||||
},
|
||||
{
|
||||
value: 'samuel',
|
||||
name: 'Samuel - american, old, male, high, narrative, slow, gravelly',
|
||||
},
|
||||
{
|
||||
value:
|
||||
// eslint-disable-next-line max-len
|
||||
's3://mockingbird-prod/agent_47_carmelo_pampillonio_58e796e1-0b87-4f3e-8b36-7def6d65ce66/voices/speaker/manifest.json',
|
||||
name: 'Sarge - american, male, gaming',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/1f44b3e7-22ea-4c2e-87d0-b4d9c8f1d47d/sophia/manifest.json',
|
||||
name: 'Sophia - american, adult, female,',
|
||||
},
|
||||
{
|
||||
value: 'spencer',
|
||||
name: 'April - british, adult, female, neutral, narrative, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 'stella',
|
||||
name: 'Stella - british, old, female, neutral, training, slow, round',
|
||||
},
|
||||
{
|
||||
value: 'susan',
|
||||
name: 'Susan - american, adult, female, high, videos, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
// eslint-disable-next-line max-len
|
||||
's3://mockingbird-prod/susan_vo_commercials_0f4fa663-6eba-4582-be1e-2d5bde798f1c/voices/speaker/manifest.json',
|
||||
name: 'Susan (Advertising) - american, adult, female, high, advertising, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/susan_vo_narrative_73051c90-460b-4e54-adab-9235f45c5e5f/voices/speaker/manifest.json',
|
||||
name: 'Susan (Narrative) - american, adult, female, high, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/susan_vo_training_46ffcc60-d630-42f6-acfe-4affd003ae7a/voices/speaker/manifest.json',
|
||||
name: 'Susan (Training) - american, adult, female, high, training, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'theodore',
|
||||
name: 'Theodore - american, old, male, neutral, narrative, neutral, gravelly',
|
||||
},
|
||||
{
|
||||
value: 'victor',
|
||||
name: 'Ariana - american, youth, female, high, videos, fast, thick',
|
||||
},
|
||||
{
|
||||
value: 'wilbert',
|
||||
name: 'Wilbert - british, adult, male, neutral, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value: 'wilbur',
|
||||
name: 'Wilbur - american, youth, male, neutral, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value: 'wilfred',
|
||||
name: 'Wilfred - american, old, male, low, training, slow, smooth',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/mel22/manifest.json',
|
||||
name: 'Will - american, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 'william',
|
||||
name: 'William - american, adult, male, neutral, videos, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
// eslint-disable-next-line max-len
|
||||
's3://mockingbird-prod/william_vo_narrative_0eacdff5-6243-4e26-8b3b-66e03458c1d1/voices/speaker/manifest.json',
|
||||
name: 'William (Narrative) - american, adult, male, neutral, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/william_vo_training_1b939b71-14fa-41f0-b1db-7d94f194ad0a/voices/speaker/manifest.json',
|
||||
name: 'William (Training) - american, adult, male, neutral, training, neutral, round',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-GB',
|
||||
name: 'English (GB)',
|
||||
voices: [
|
||||
{
|
||||
value: 's3://peregrine-voices/arthur ads parrot saad/manifest.json',
|
||||
name: 'Arthur (Advertising) - british, adult, male, neutral, advertising, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
// eslint-disable-next-line max-len
|
||||
's3://mockingbird-prod/arthur_vo_meditatoin_211f702d-b185-4115-b8b4-801f8130a38d/voices/speaker/manifest.json',
|
||||
name: 'Arthur (Meditation) - british, adult, male, neutral, meditation, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/arthur_vo_narrative_a33fd610-73a9-4401-9a78-6b8219c68a9e/voices/speaker/manifest.json',
|
||||
name: 'Arthur (Narrative) - british, adult, male, neutral, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/arthur_vo_training_9281c8fd-c7f0-4445-a148-466292d3d329/voices/speaker/manifest.json',
|
||||
name: 'Arthur (Training) - british, adult, male, neutral, training, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/eileen_vo_5d7b2bcc-d635-4301-97e8-d97c13768514/voices/speaker/manifest.json',
|
||||
name: 'Eileen - british, female, narrative',
|
||||
},
|
||||
{
|
||||
value: 'frankie',
|
||||
name: 'Frankie - british, old, male, neutral, training, neutral, thick',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/418a94fa-2395-4487-81d8-22daf107781f/george/manifest.json',
|
||||
name: 'George - british, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 'julian',
|
||||
name: 'Julian - british, adult, male, neutral, videos, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/0b5b2e4b-5103-425e-8aa0-510dd35226e2/mark/manifest.json',
|
||||
name: 'Mark - british, adult, male,',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/oliver_ads2_parrot_saad/manifest.json',
|
||||
name: 'Oliver (Advertising) - british, adult, male, high, advertising, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://peregrine-voices/oliver_narrative2_parrot_saad/manifest.json',
|
||||
name: 'Oliver (Narrative) - british, adult, male, high, narrative, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/oliver_vo_training_6e3f604a-5605-4542-948d-347b0d7546fc/voices/speaker/manifest.json',
|
||||
name: 'Oliver (Training) - british, adult, male, high, training, neutral, round',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/820da3d2-3a3b-42e7-844d-e68db835a206/sarah/manifest.json',
|
||||
name: 'Sarah - british, adult, female,',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-AU',
|
||||
name: 'English (AU)',
|
||||
voices: [
|
||||
{
|
||||
value: 's3://peregrine-voices/barry ads parrot saad/manifest.json',
|
||||
name: 'Barry (Advertising) - australian, male, advertising',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://peregrine-voices/barry narrative parrot saad/manifest.json',
|
||||
name: 'Barry (Narrative) - australian, male, narrative',
|
||||
},
|
||||
{
|
||||
value: 'frederick',
|
||||
name: 'Frederick - australian, adult, male, low, narrative, slow, thick',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/russell2_parrot_saad/manifest.json',
|
||||
name: 'Russell - australian, male,',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-CA',
|
||||
name: 'English (CA)',
|
||||
voices: [
|
||||
{
|
||||
value: 's3://peregrine-voices/charlotte ads parrot saad/manifest.json',
|
||||
name: 'Charlotte (Advertising) - canadian, adult, female, low, advertising, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://peregrine-voices/charlotte meditation 2 parrot saad/manifest.json',
|
||||
name: 'Charlotte (Meditation) - canadian, adult, female, low, meditation, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
// eslint-disable-next-line max-len
|
||||
's3://mockingbird-prod/charlotte_vo_narrative_9290be17-ccea-4700-a7fd-a8fe5c49fb20/voices/speaker/manifest.json',
|
||||
name: 'Charlotte (Narrative) - canadian, adult, female, low, narrative, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://peregrine-voices/charlotte_training_parrot_saad/manifest.json',
|
||||
name: 'Charlotte (Training) - canadian, adult, female, low, training, neutral, smooth',
|
||||
},
|
||||
{
|
||||
value:
|
||||
// eslint-disable-next-line max-len
|
||||
's3://mockingbird-prod/olivia_vo_commercials_6e3c384f-15d6-4fe7-b9a4-0cb1d69daeba/voices/speaker/manifest.json',
|
||||
name: 'Olivia (Advertising) - canadian, female, advertising',
|
||||
},
|
||||
{
|
||||
value: 's3://peregrine-voices/olivia_ads3_parrot_saad/manifest.json',
|
||||
name: 'Olivia (Narrative) - canadian, female, narrative',
|
||||
},
|
||||
{
|
||||
value:
|
||||
's3://mockingbird-prod/olivia_vo_training_4376204f-a411-4e5d-a5c0-ce6cc3908052/voices/speaker/manifest.json',
|
||||
name: 'Olivia (Training) - canadian, female, training',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-IE',
|
||||
name: 'English (IE)',
|
||||
voices: [
|
||||
{
|
||||
value: 'florencio',
|
||||
name: 'Madison - irish, old, female, neutral, narrative, slow, round',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'en-NZ',
|
||||
name: 'English (NZ)',
|
||||
voices: [
|
||||
{
|
||||
value:
|
||||
's3://voice-cloning-zero-shot/d9ff78ba-d016-47f6-b0ef-dd630f59414e/female-cs/manifest.json',
|
||||
name: 'Ruby - australian, adult, female,',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -1,62 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'US English',
|
||||
voices: [
|
||||
{
|
||||
value: 'tommy_en_us',
|
||||
name: 'Tommy-Male',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-ES',
|
||||
name: 'Castilian Spanish',
|
||||
voices: [
|
||||
{
|
||||
value: 'david_es_es',
|
||||
name: 'David-Male',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-PE',
|
||||
name: 'Peruvian Spanish',
|
||||
voices: [
|
||||
{
|
||||
value: 'miguel_es_pe',
|
||||
name: 'Miguel-Male',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'es-PE',
|
||||
name: 'Peruvian Spanish',
|
||||
voices: [
|
||||
{
|
||||
value: 'luz_es_pe',
|
||||
name: 'Luz-Female',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'pt-BR',
|
||||
name: 'Brazilian Portuguese',
|
||||
voices: [
|
||||
{
|
||||
value: 'bel_pt_br',
|
||||
name: 'Bel-Female',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
value: 'ca-ES',
|
||||
name: 'Catalan',
|
||||
voices: [
|
||||
{
|
||||
value: 'anna_ca',
|
||||
name: 'Anna-Female',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -1,39 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English (US)',
|
||||
voices: [
|
||||
{ value: '3', name: 'Alana B.' },
|
||||
{ value: '4', name: 'Ramona J.' },
|
||||
{ value: '5', name: 'Ramona J. (promo)' },
|
||||
{ value: '7', name: 'Wade C.' },
|
||||
{ value: '8', name: 'Sofia H.' },
|
||||
{ value: '9', name: 'David D.' },
|
||||
{ value: '11', name: 'Isabel V.' },
|
||||
{ value: '12', name: 'Ava H.' },
|
||||
{ value: '13', name: 'Jeremy G.' },
|
||||
{ value: '14', name: 'Nicole L.' },
|
||||
{ value: '15', name: 'Paige L.' },
|
||||
{ value: '16', name: 'Tobin A.' },
|
||||
{ value: '17', name: 'Kai M.' },
|
||||
{ value: '18', name: 'Tristan F.' },
|
||||
{ value: '19', name: 'Patrick K.' },
|
||||
{ value: '20', name: 'Soifia H. (promo)' },
|
||||
{ value: '21', name: 'Damian P. (promo)' },
|
||||
{ value: '22', name: 'Jodi P. (promo)' },
|
||||
{ value: '23', name: 'Lee M. (promo)' },
|
||||
{ value: '24', name: 'Selene R. (promo)' },
|
||||
{ value: '26', name: 'Wade C. (promo)' },
|
||||
{ value: '27', name: 'Joe F.' },
|
||||
{ value: '28', name: 'Joe F. (promo)' },
|
||||
{ value: '29', name: 'Garry J. (character)' },
|
||||
{ value: '33', name: 'Jude D.' },
|
||||
{ value: '34', name: 'Eric S. (promo)' },
|
||||
{ value: '35', name: 'Chase J.' },
|
||||
{ value: '37', name: 'Steve B. (promo)' },
|
||||
{ value: '38', name: 'Bella B. (promo)' },
|
||||
{ value: '39', name: 'Tilda C. (promo)' },
|
||||
{ value: '41', name: 'Paul B. (promo)' },
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -1,14 +0,0 @@
|
||||
module.exports = [
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English',
|
||||
voices: [
|
||||
{ value: 'alloy', name: 'Alloy' },
|
||||
{ value: 'echo', name: 'Echo' },
|
||||
{ value: 'fable', name: 'Fable' },
|
||||
{ value: 'onyx', name: 'Onyx' },
|
||||
{ value: 'nova', name: 'Nova' },
|
||||
{ value: 'shimmer', name: 'Shimmer' },
|
||||
],
|
||||
},
|
||||
];
|
||||
@@ -5,38 +5,7 @@ const sdk = require('microsoft-cognitiveservices-speech-sdk');
|
||||
const { SpeechClient } = require('@soniox/soniox-node');
|
||||
const bent = require('bent');
|
||||
const fs = require('fs');
|
||||
const { AssemblyAI } = require('assemblyai');
|
||||
const {decrypt, obscureKey} = require('./encrypt-decrypt');
|
||||
|
||||
const TtsGoogleLanguagesVoices = require('./speech-data/tts-google');
|
||||
const TtsAwsLanguagesVoices = require('./speech-data/tts-aws');
|
||||
const TtsMicrosoftLanguagesVoices = require('./speech-data/tts-microsoft');
|
||||
const TtsWellsaidLanguagesVoices = require('./speech-data/tts-wellsaid');
|
||||
const TtsNuanceLanguagesVoices = require('./speech-data/tts-nuance');
|
||||
const TtsIbmLanguagesVoices = require('./speech-data/tts-ibm');
|
||||
const TtsNvidiaLanguagesVoices = require('./speech-data/tts-nvidia');
|
||||
const TtsElevenlabsLanguagesVoices = require('./speech-data/tts-elevenlabs');
|
||||
const TtsWhisperLanguagesVoices = require('./speech-data/tts-whisper');
|
||||
const TtsPlayHtLanguagesVoices = require('./speech-data/tts-playht');
|
||||
const TtsVerbioLanguagesVoices = require('./speech-data/tts-verbio');
|
||||
|
||||
const TtsModelDeepgram = require('./speech-data/tts-model-deepgram');
|
||||
const TtsModelElevenLabs = require('./speech-data/tts-model-elevenlabs');
|
||||
const TtsModelWhisper = require('./speech-data/tts-model-whisper');
|
||||
const TtsModelPlayHT = require('./speech-data/tts-model-playht');
|
||||
const TtsModelRimelabs = require('./speech-data/tts-model-rimelabs');
|
||||
|
||||
const SttGoogleLanguagesVoices = require('./speech-data/stt-google');
|
||||
const SttAwsLanguagesVoices = require('./speech-data/stt-aws');
|
||||
const SttMicrosoftLanguagesVoices = require('./speech-data/stt-microsoft');
|
||||
const SttNuanceLanguagesVoices = require('./speech-data/stt-nuance');
|
||||
const SttDeepgramLanguagesVoices = require('./speech-data/stt-deepgram');
|
||||
const SttIbmLanguagesVoices = require('./speech-data/stt-ibm');
|
||||
const SttNvidiaLanguagesVoices = require('./speech-data/stt-nvidia');
|
||||
const SttCobaltLanguagesVoices = require('./speech-data/stt-cobalt');
|
||||
const SttSonioxLanguagesVoices = require('./speech-data/stt-soniox');
|
||||
const SttAssemblyaiLanguagesVoices = require('./speech-data/stt-assemblyai');
|
||||
const SttVerbioLanguagesVoices = require('./speech-data/stt-verbio');
|
||||
|
||||
const testSonioxStt = async(logger, credentials) => {
|
||||
const api_key = credentials;
|
||||
@@ -92,8 +61,8 @@ const testGoogleStt = async(logger, credentials) => {
|
||||
};
|
||||
|
||||
const testDeepgramStt = async(logger, credentials) => {
|
||||
const {api_key, deepgram_stt_uri, deepgram_stt_use_tls} = credentials;
|
||||
const deepgram = new Deepgram(api_key, deepgram_stt_uri, deepgram_stt_uri && deepgram_stt_use_tls);
|
||||
const {api_key} = credentials;
|
||||
const deepgram = new Deepgram(api_key);
|
||||
|
||||
const mimetype = 'audio/wav';
|
||||
const source = {
|
||||
@@ -119,19 +88,11 @@ const testDeepgramStt = async(logger, credentials) => {
|
||||
};
|
||||
|
||||
const testMicrosoftStt = async(logger, credentials) => {
|
||||
const {api_key, region, use_custom_stt, custom_stt_endpoint_url} = credentials;
|
||||
const speechConfig = use_custom_stt ? sdk.SpeechConfig.fromEndpoint(
|
||||
new URL(custom_stt_endpoint_url), api_key) :
|
||||
sdk.SpeechConfig.fromSubscription(api_key, region);
|
||||
const {api_key, region} = credentials;
|
||||
|
||||
const speechConfig = sdk.SpeechConfig.fromSubscription(api_key, region);
|
||||
const audioConfig = sdk.AudioConfig.fromWavFileInput(fs.readFileSync(`${__dirname}/../../data/test_audio.wav`));
|
||||
speechConfig.speechRecognitionLanguage = 'en-US';
|
||||
|
||||
if (process.env.JAMBONES_HTTP_PROXY_IP && process.env.JAMBONES_HTTP_PROXY_PORT) {
|
||||
logger.debug(
|
||||
`testMicrosoftStt: using proxy ${process.env.JAMBONES_HTTP_PROXY_IP}:${process.env.JAMBONES_HTTP_PROXY_PORT}`);
|
||||
speechConfig.setProxy(process.env.JAMBONES_HTTP_PROXY_IP, process.env.JAMBONES_HTTP_PROXY_PORT);
|
||||
}
|
||||
|
||||
const speechRecognizer = new sdk.SpeechRecognizer(speechConfig, audioConfig);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -168,52 +129,57 @@ const testAwsTts = async(logger, getTtsVoices, credentials) => {
|
||||
}
|
||||
};
|
||||
|
||||
const testAwsStt = async(logger, getAwsAuthToken, credentials) => {
|
||||
const testAwsStt = async(logger, credentials) => {
|
||||
try {
|
||||
const {region, accessKeyId, secretAccessKey, roleArn} = credentials;
|
||||
let client = null;
|
||||
if (accessKeyId && secretAccessKey) {
|
||||
client = new TranscribeClient({
|
||||
region,
|
||||
credentials: {
|
||||
accessKeyId,
|
||||
secretAccessKey
|
||||
}
|
||||
});
|
||||
} else if (roleArn) {
|
||||
client = new TranscribeClient({
|
||||
region,
|
||||
credentials: await getAwsAuthToken({
|
||||
region,
|
||||
roleArn
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
client = new TranscribeClient({region});
|
||||
}
|
||||
const {region, accessKeyId, secretAccessKey} = credentials;
|
||||
const client = new TranscribeClient({
|
||||
region,
|
||||
credentials: {
|
||||
accessKeyId,
|
||||
secretAccessKey
|
||||
}
|
||||
});
|
||||
const command = new ListVocabulariesCommand({});
|
||||
const response = await client.send(command);
|
||||
return response;
|
||||
} catch (err) {
|
||||
logger.info({err}, 'testAwsStt - failed to list voices for region ${region}');
|
||||
logger.info({err}, 'testMicrosoftTts - failed to list voices for region ${region}');
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const testMicrosoftTts = async(logger, synthAudio, credentials) => {
|
||||
const testMicrosoftTts = async(logger, credentials) => {
|
||||
const {
|
||||
api_key,
|
||||
region,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
use_custom_tts,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
custom_tts_endpoint,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
use_custom_stt,
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
custom_stt_endpoint
|
||||
} = credentials;
|
||||
|
||||
logger.info({
|
||||
api_key,
|
||||
region,
|
||||
use_custom_tts,
|
||||
custom_tts_endpoint,
|
||||
use_custom_stt,
|
||||
custom_stt_endpoint
|
||||
}, 'testing microsoft tts');
|
||||
if (!api_key) throw new Error('testMicrosoftTts: credentials are missing api_key');
|
||||
if (!region) throw new Error('testMicrosoftTts: credentials are missing region');
|
||||
try {
|
||||
await synthAudio({increment: () => {}, histogram: () => {}},
|
||||
{
|
||||
vendor: 'microsoft',
|
||||
credentials,
|
||||
language: 'en-US',
|
||||
voice: 'en-US-JennyMultilingualNeural',
|
||||
text: 'Hi there and welcome to jambones!',
|
||||
renderForCaching: true
|
||||
}
|
||||
);
|
||||
const getJSON = bent('json', {
|
||||
'Ocp-Apim-Subscription-Key': api_key
|
||||
});
|
||||
const response = await getJSON(`https://${region}.tts.speech.microsoft.com/cognitiveservices/voices/list`);
|
||||
return response;
|
||||
} catch (err) {
|
||||
logger.info({err}, 'testMicrosoftTts returned error');
|
||||
logger.info({err}, `testMicrosoftTts - failed to list voices for region ${region}`);
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
@@ -237,110 +203,6 @@ const testWellSaidTts = async(logger, credentials) => {
|
||||
}
|
||||
};
|
||||
|
||||
const testElevenlabs = async(logger, credentials) => {
|
||||
const {api_key, model_id} = credentials;
|
||||
try {
|
||||
const post = bent('https://api.elevenlabs.io', 'POST', 'buffer', {
|
||||
'xi-api-key': api_key,
|
||||
'Accept': 'audio/mpeg',
|
||||
'Content-Type': 'application/json'
|
||||
});
|
||||
const mp3 = await post('/v1/text-to-speech/21m00Tcm4TlvDq8ikWAM', {
|
||||
text: 'Hello',
|
||||
model_id,
|
||||
voice_settings: {
|
||||
stability: 0.5,
|
||||
similarity_boost: 0.5
|
||||
}
|
||||
});
|
||||
return mp3;
|
||||
} catch (err) {
|
||||
logger.info({err}, 'synthEvenlabs returned error');
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const testPlayHT = async(logger, synthAudio, credentials) => {
|
||||
try {
|
||||
await synthAudio(
|
||||
{
|
||||
increment: () => {},
|
||||
histogram: () => {}
|
||||
},
|
||||
{
|
||||
vendor: 'playht',
|
||||
credentials,
|
||||
language: 'en-US',
|
||||
voice: 's3://voice-cloning-zero-shot/d9ff78ba-d016-47f6-b0ef-dd630f59414e/female-cs/manifest.json',
|
||||
text: 'Hi there and welcome to jambones!',
|
||||
renderForCaching: true
|
||||
}
|
||||
);
|
||||
// Test if playHT can fetch voices
|
||||
await fetchLayHTVoices(credentials);
|
||||
} catch (err) {
|
||||
logger.info({err}, 'synth Playht returned error');
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const testRimelabs = async(logger, synthAudio, credentials) => {
|
||||
try {
|
||||
await synthAudio(
|
||||
{
|
||||
increment: () => {},
|
||||
histogram: () => {}
|
||||
},
|
||||
{
|
||||
vendor: 'rimelabs',
|
||||
credentials,
|
||||
language: 'en-US',
|
||||
voice: 'amber',
|
||||
text: 'Hi there and welcome to jambones!',
|
||||
renderForCaching: true
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
logger.info({err}, 'synth Playht returned error');
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const testWhisper = async(logger, synthAudio, credentials) => {
|
||||
try {
|
||||
await synthAudio({increment: () => {}, histogram: () => {}},
|
||||
{
|
||||
vendor: 'whisper',
|
||||
credentials,
|
||||
language: 'en-US',
|
||||
voice: 'alloy',
|
||||
text: 'Hi there and welcome to jambones!',
|
||||
renderForCaching: true
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
logger.info({err}, 'synthEvenlabs returned error');
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const testDeepgramTTS = async(logger, synthAudio, credentials) => {
|
||||
try {
|
||||
await synthAudio({increment: () => {}, histogram: () => {}},
|
||||
{
|
||||
vendor: 'deepgram',
|
||||
credentials,
|
||||
model: 'aura-asteria-en',
|
||||
text: 'Hi there and welcome to jambones!',
|
||||
renderForCaching: true
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
logger.info({err}, 'testDeepgramTTS returned error');
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const testIbmTts = async(logger, getTtsVoices, credentials) => {
|
||||
const {tts_api_key, tts_region} = credentials;
|
||||
const voices = await getTtsVoices({vendor: 'ibm', credentials: {tts_api_key, tts_region}});
|
||||
@@ -375,669 +237,6 @@ const testWellSaidStt = async(logger, credentials) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const testVerbioTts = async(logger, synthAudio, credentials) => {
|
||||
try {
|
||||
await synthAudio(
|
||||
{
|
||||
increment: () => {},
|
||||
histogram: () => {}
|
||||
},
|
||||
{
|
||||
vendor: 'verbio',
|
||||
credentials,
|
||||
language: 'en-US',
|
||||
voice: 'tommy_en-us',
|
||||
text: 'Hi there and welcome to jambones!',
|
||||
renderForCaching: true
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
logger.info({err}, 'synth Verbio returned error');
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
const testVerbioStt = async(logger, getVerbioAccessToken, credentials) => {
|
||||
const token = await getVerbioAccessToken(credentials);
|
||||
try {
|
||||
const post = bent('https://us.rest.speechcenter.verbio.com', 'POST', 'json', {
|
||||
'Authorization': `Bearer ${token.access_token}`,
|
||||
'User-Agent': 'jambonz',
|
||||
'Content-Type': 'audio/wav'
|
||||
});
|
||||
const json = await post('/api/v1/recognize?language=en-US&version=V1',
|
||||
fs.readFileSync(`${__dirname}/../../data/test_audio.wav`));
|
||||
logger.debug({json}, 'successfully speech to text from verbio');
|
||||
} catch (err) {
|
||||
logger.info({err}, 'testWellSaidTts returned error');
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const testAssemblyStt = async(logger, credentials) => {
|
||||
const {api_key} = credentials;
|
||||
|
||||
const assemblyai = new AssemblyAI({
|
||||
apiKey: api_key
|
||||
});
|
||||
|
||||
const audioUrl = `${__dirname}/../../data/test_audio.wav`;
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
assemblyai.transcripts
|
||||
.create({ audio_url: audioUrl })
|
||||
.then((transcript) => {
|
||||
logger.debug({transcript}, 'got transcription from AssemblyAi');
|
||||
if (transcript.status === 'error') {
|
||||
return reject({message: transcript.error});
|
||||
}
|
||||
return resolve(transcript.text);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.info({err}, 'failed to get assemblyAI transcription');
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const getSpeechCredential = (credential, logger) => {
|
||||
const {vendor} = credential;
|
||||
logger.info(
|
||||
`Speech vendor: ${credential.vendor} ${credential.label ? `, label: ${credential.label}` : ''} selected`);
|
||||
if ('google' === vendor) {
|
||||
try {
|
||||
const cred = JSON.parse(credential.service_key.replace(/\n/g, '\\n'));
|
||||
return {
|
||||
...credential,
|
||||
credentials: cred
|
||||
};
|
||||
} catch (err) {
|
||||
logger.info({err}, `malformed google service_key provisioned for account ${credential.speech_credential_sid}`);
|
||||
}
|
||||
}
|
||||
else if (['aws', 'polly'].includes(vendor)) {
|
||||
return {
|
||||
...credential,
|
||||
accessKeyId: credential.access_key_id,
|
||||
secretAccessKey: credential.secret_access_key,
|
||||
roleArn: credential.role_arn,
|
||||
region: credential.aws_region || 'us-east-1'
|
||||
};
|
||||
}
|
||||
return credential;
|
||||
};
|
||||
|
||||
function decryptCredential(obj, credential, logger, isObscureKey = true) {
|
||||
if ('google' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
const key_header = '-----BEGIN PRIVATE KEY-----\n';
|
||||
const obscured = {
|
||||
...o,
|
||||
private_key: `${key_header}${isObscureKey ?
|
||||
obscureKey(o.private_key.slice(key_header.length, o.private_key.length)) :
|
||||
o.private_key.slice(key_header.length, o.private_key.length)}`
|
||||
};
|
||||
obj.service_key = JSON.stringify(obscured);
|
||||
}
|
||||
else if ('aws' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.access_key_id = o.access_key_id;
|
||||
obj.role_arn = o.role_arn;
|
||||
obj.secret_access_key = isObscureKey ? obscureKey(o.secret_access_key) : o.secret_access_key;
|
||||
obj.aws_region = o.aws_region;
|
||||
logger.info({obj, o}, 'retrieving aws speech credential');
|
||||
}
|
||||
else if ('microsoft' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
obj.region = o.region;
|
||||
obj.use_custom_tts = o.use_custom_tts;
|
||||
obj.custom_tts_endpoint = o.custom_tts_endpoint;
|
||||
obj.custom_tts_endpoint_url = o.custom_tts_endpoint_url;
|
||||
obj.use_custom_stt = o.use_custom_stt;
|
||||
obj.custom_stt_endpoint = o.custom_stt_endpoint;
|
||||
obj.custom_stt_endpoint_url = o.custom_stt_endpoint_url;
|
||||
logger.info({obj, o}, 'retrieving azure speech credential');
|
||||
}
|
||||
else if ('wellsaid' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
}
|
||||
else if ('nuance' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.client_id = o.client_id;
|
||||
obj.secret = o.secret ? (isObscureKey ? obscureKey(o.secret) : o.secret) : null;
|
||||
obj.nuance_tts_uri = o.nuance_tts_uri;
|
||||
obj.nuance_stt_uri = o.nuance_stt_uri;
|
||||
}
|
||||
else if ('deepgram' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
obj.deepgram_stt_uri = o.deepgram_stt_uri;
|
||||
obj.deepgram_stt_use_tls = o.deepgram_stt_use_tls;
|
||||
obj.deepgram_tts_uri = o.deepgram_tts_uri;
|
||||
}
|
||||
else if ('ibm' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.tts_api_key = isObscureKey ? obscureKey(o.tts_api_key) : o.tts_api_key;
|
||||
obj.tts_region = o.tts_region;
|
||||
obj.stt_api_key = isObscureKey ? obscureKey(o.stt_api_key) : o.stt_api_key;
|
||||
obj.stt_region = o.stt_region;
|
||||
obj.instance_id = o.instance_id;
|
||||
} else if ('nvidia' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.riva_server_uri = o.riva_server_uri;
|
||||
} else if ('cobalt' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.cobalt_server_uri = o.cobalt_server_uri;
|
||||
} else if ('soniox' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
} else if ('elevenlabs' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
obj.model_id = o.model_id;
|
||||
obj.options = o.options;
|
||||
} else if ('playht' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
obj.user_id = o.user_id;
|
||||
obj.voice_engine = o.voice_engine;
|
||||
obj.options = o.options;
|
||||
} else if ('rimelabs' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
obj.model_id = o.model_id;
|
||||
obj.options = o.options;
|
||||
} else if (obj.vendor.startsWith('custom:')) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.auth_token = isObscureKey ? obscureKey(o.auth_token) : o.auth_token;
|
||||
obj.custom_stt_url = o.custom_stt_url;
|
||||
obj.custom_tts_url = o.custom_tts_url;
|
||||
} else if ('assemblyai' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
} else if ('whisper' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.api_key = isObscureKey ? obscureKey(o.api_key) : o.api_key;
|
||||
obj.model_id = o.model_id;
|
||||
} else if ('verbio' === obj.vendor) {
|
||||
const o = JSON.parse(decrypt(credential));
|
||||
obj.client_id = o.client_id;
|
||||
obj.client_secret = isObscureKey ? obscureKey(o.client_secret) : o.client_secret;
|
||||
obj.engine_version = o.engine_version;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} logger logger
|
||||
* @param {*} vendor vendor
|
||||
* @param {*} credential STT/TTS vendor credential, can be null
|
||||
* @returns List of language and coresponding voices for specific vendor follow below format
|
||||
* {
|
||||
"tts": [
|
||||
{
|
||||
code: "ar-XA",
|
||||
name: "Arabic",
|
||||
voices: [
|
||||
{ value: "ar-XA-Standard-A", name: "Standard-A (Female)" },
|
||||
]
|
||||
}
|
||||
],
|
||||
"stt": [
|
||||
{ name: "Afrikaans (South Africa)", code: "af-ZA" },
|
||||
]
|
||||
}
|
||||
*/
|
||||
async function getLanguagesAndVoicesForVendor(logger, vendor, credential, getTtsVoices) {
|
||||
switch (vendor) {
|
||||
case 'google':
|
||||
return await getLanguagesVoicesForGoogle(credential, getTtsVoices, logger);
|
||||
case 'aws':
|
||||
return await getLanguagesVoicesForAws(credential, getTtsVoices, logger);
|
||||
case 'microsoft':
|
||||
return await getLanguagesVoicesForMicrosoft(credential, getTtsVoices, logger);
|
||||
case 'wellsaid':
|
||||
return await getLanguagesVoicesForWellsaid(credential, getTtsVoices, logger);
|
||||
case 'nuance':
|
||||
return await getLanguagesVoicesForNuane(credential, getTtsVoices, logger);
|
||||
case 'deepgram':
|
||||
return await getLanguagesVoicesForDeepgram(credential, getTtsVoices, logger);
|
||||
case 'ibm':
|
||||
return await getLanguagesVoicesForIbm(credential, getTtsVoices, logger);
|
||||
case 'nvidia':
|
||||
return await getLanguagesVoicesForNvida(credential, getTtsVoices, logger);
|
||||
case 'cobalt':
|
||||
return await getLanguagesVoicesForCobalt(credential, getTtsVoices, logger);
|
||||
case 'soniox':
|
||||
return await getLanguagesVoicesForSoniox(credential, getTtsVoices, logger);
|
||||
case 'elevenlabs':
|
||||
return await getLanguagesVoicesForElevenlabs(credential, getTtsVoices, logger);
|
||||
case 'playht':
|
||||
return await getLanguagesVoicesForPlayHT(credential, getTtsVoices, logger);
|
||||
case 'rimelabs':
|
||||
return await getLanguagesVoicesForRimelabs(credential, getTtsVoices, logger);
|
||||
case 'assemblyai':
|
||||
return await getLanguagesVoicesForAssemblyAI(credential, getTtsVoices, logger);
|
||||
case 'whisper':
|
||||
return await getLanguagesVoicesForWhisper(credential, getTtsVoices, logger);
|
||||
case 'verbio':
|
||||
return await getLanguagesVoicesForVerbio(credential, getTtsVoices, logger);
|
||||
default:
|
||||
logger.info(`invalid vendor ${vendor}, return empty result`);
|
||||
throw new Error(`Invalid vendor ${vendor}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForGoogle(credential, getTtsVoices, logger) {
|
||||
if (credential) {
|
||||
try {
|
||||
const [result] = await getTtsVoices({
|
||||
vendor: 'google',
|
||||
credentials: credential
|
||||
});
|
||||
const tts = parseGooglelanguagesVoices(result.voices);
|
||||
return tranform(tts, SttGoogleLanguagesVoices);
|
||||
} catch (err) {
|
||||
logger.info('Error while fetching google languages, voices, return predefined values', err);
|
||||
}
|
||||
}
|
||||
return tranform(TtsGoogleLanguagesVoices, SttGoogleLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForAws(credential, getTtsVoices, logger) {
|
||||
if (credential) {
|
||||
try {
|
||||
const result = await getTtsVoices({
|
||||
vendor: 'aws',
|
||||
credentials: {
|
||||
accessKeyId: credential.access_key_id,
|
||||
secretAccessKey: credential.secret_access_key,
|
||||
roleArn: credential.role_arn,
|
||||
region: credential.aws_region || process.env.AWS_REGION
|
||||
}
|
||||
});
|
||||
const tts = parseAwsLanguagesVoices(result.Voices);
|
||||
return tranform(tts, SttAwsLanguagesVoices);
|
||||
} catch (err) {
|
||||
logger.info('Error while fetching AWS languages, voices, return predefined values', err);
|
||||
}
|
||||
}
|
||||
return tranform(TtsAwsLanguagesVoices, SttAwsLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForMicrosoft(credential, getTtsVoices, logger) {
|
||||
if (credential) {
|
||||
try {
|
||||
const get = bent('https://westus.tts.speech.microsoft.com', 'GET', 'json', {
|
||||
'Ocp-Apim-Subscription-Key' : credential.api_key
|
||||
});
|
||||
|
||||
const voices = await get('/cognitiveservices/voices/list');
|
||||
const tts = parseMicrosoftLanguagesVoices(voices);
|
||||
return tranform(tts, SttMicrosoftLanguagesVoices);
|
||||
} catch (err) {
|
||||
logger.info('Error while fetching Microsoft languages, voices, return predefined values', err);
|
||||
}
|
||||
}
|
||||
return tranform(TtsMicrosoftLanguagesVoices, SttMicrosoftLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForWellsaid(credential) {
|
||||
return tranform(TtsWellsaidLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForNuane(credential, getTtsVoices, logger) {
|
||||
if (credential) {
|
||||
try {
|
||||
const result = await getTtsVoices({
|
||||
vendor: 'nuance',
|
||||
credentials: credential
|
||||
});
|
||||
const tts = parseNuanceLanguagesVoices(result.result.voices);
|
||||
return tranform(tts, SttNuanceLanguagesVoices);
|
||||
} catch (err) {
|
||||
logger.info('Error while fetching IBM languages, voices, return predefined values', err);
|
||||
}
|
||||
}
|
||||
return tranform(TtsNuanceLanguagesVoices, SttNuanceLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForDeepgram(credential) {
|
||||
return tranform(undefined, SttDeepgramLanguagesVoices, TtsModelDeepgram);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForIbm(credential, getTtsVoices, logger) {
|
||||
if (credential) {
|
||||
try {
|
||||
const result = await getTtsVoices({
|
||||
vendor: 'ibm',
|
||||
credentials: credential
|
||||
});
|
||||
const tts = parseIBMLanguagesVoices(result.result.voices);
|
||||
return tranform(tts, SttIbmLanguagesVoices);
|
||||
} catch (err) {
|
||||
logger.info('Error while fetching IBM languages, voices, return predefined values', err);
|
||||
}
|
||||
}
|
||||
return tranform(TtsIbmLanguagesVoices, SttIbmLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForNvida(credential) {
|
||||
return tranform(TtsNvidiaLanguagesVoices, SttNvidiaLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForCobalt(credential) {
|
||||
return tranform(undefined, SttCobaltLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForSoniox(credential) {
|
||||
return tranform(undefined, SttSonioxLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForElevenlabs(credential) {
|
||||
if (credential) {
|
||||
const get = bent('https://api.elevenlabs.io', 'GET', 'json', {
|
||||
'xi-api-key' : credential.api_key
|
||||
});
|
||||
|
||||
const [langResp, voiceResp] = await Promise.all([get('/v1/models'), get('/v1/voices')]);
|
||||
|
||||
const model = langResp.find((m) => m.model_id === credential.model_id);
|
||||
const languages = model ? model.languages.map((l) => {
|
||||
return {
|
||||
value: l.language_id,
|
||||
name: l.name
|
||||
};
|
||||
}).sort((a, b) => a.name.localeCompare(b.name)) : [];
|
||||
|
||||
if (languages && languages.length > 0) {
|
||||
const voices = voiceResp ? voiceResp.voices.map((v) => {
|
||||
let name = `${v.name}${v.category !== 'premade' ? ` (${v.category})` : ''} -
|
||||
${v.labels.accent ? ` ${v.labels.accent},` : ''}
|
||||
${v.labels.description ? ` ${v.labels.description},` : ''}
|
||||
${v.labels.age ? ` ${v.labels.age},` : ''}
|
||||
${v.labels.gender ? ` ${v.labels.gender},` : ''}
|
||||
${v.labels['use case'] ? ` ${v.labels['use case']},` : ''}
|
||||
`;
|
||||
const lastIndex = name.lastIndexOf(',');
|
||||
if (lastIndex !== -1) {
|
||||
name = name.substring(0, lastIndex);
|
||||
}
|
||||
return {
|
||||
value: v.voice_id,
|
||||
name
|
||||
};
|
||||
}).sort((a, b) => a.name.localeCompare(b.name)) : [];
|
||||
languages[0].voices = voices;
|
||||
}
|
||||
return tranform(languages, undefined, TtsModelElevenLabs);
|
||||
} else {
|
||||
return tranform(TtsElevenlabsLanguagesVoices, undefined, TtsModelElevenLabs);
|
||||
}
|
||||
}
|
||||
|
||||
const concat = (a) => {
|
||||
return a ? ` ${a},` : '';
|
||||
};
|
||||
|
||||
const fetchLayHTVoices = async(credential) => {
|
||||
if (credential) {
|
||||
const get = bent('https://api.play.ht', 'GET', 'json', {
|
||||
'AUTHORIZATION' : credential.api_key,
|
||||
'X-USER-ID': credential.user_id,
|
||||
'Accept': 'application/json'
|
||||
});
|
||||
|
||||
const voices = await get('/api/v2/voices');
|
||||
let clone_voices = [];
|
||||
try {
|
||||
// try if the account has permission to cloned voice
|
||||
//otherwise ignore this.
|
||||
clone_voices = await get('/api/v2/cloned-voices');
|
||||
} catch {}
|
||||
return [clone_voices, voices];
|
||||
}
|
||||
};
|
||||
|
||||
async function getLanguagesVoicesForPlayHT(credential) {
|
||||
if (credential) {
|
||||
const [cloned_voice, voices] = await fetchLayHTVoices(credential);
|
||||
const list_voices = [...cloned_voice, ...voices];
|
||||
|
||||
const buildVoice = (d) => {
|
||||
let name = `${d.name} -${concat(d.accent)}${concat(d.age)}${concat(d.gender)}${concat(d.loudness)}` +
|
||||
`${concat(d.style)}${concat(d.tempo)}${concat(d.texture)}` ;
|
||||
name = name.endsWith(',') ? name.trim().slice(0, -1) : name;
|
||||
return {
|
||||
value: `${d.id}`,
|
||||
name
|
||||
};
|
||||
};
|
||||
|
||||
const ttsVoices = list_voices.reduce((acc, voice) => {
|
||||
if (!credential.voice_engine.includes(voice.voice_engine)) {
|
||||
return acc;
|
||||
}
|
||||
const languageCode = voice.language_code;
|
||||
// custom voice does not have language code
|
||||
if (!languageCode) {
|
||||
voice.language_code = 'en';
|
||||
voice.language = 'Custom-English';
|
||||
}
|
||||
const existingLanguage = acc.find((lang) => lang.value === languageCode);
|
||||
if (existingLanguage) {
|
||||
existingLanguage.voices.push(buildVoice(voice));
|
||||
} else {
|
||||
acc.push({
|
||||
value: voice.language_code,
|
||||
name: voice.language,
|
||||
voices: [buildVoice(voice)]
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
return tranform(ttsVoices, undefined, TtsModelPlayHT);
|
||||
}
|
||||
return tranform(TtsPlayHtLanguagesVoices, undefined, TtsModelPlayHT);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForRimelabs(credential) {
|
||||
const model_id = credential ? credential.model_id : null;
|
||||
const get = bent('https://users.rime.ai', 'GET', 'json', {
|
||||
'Accept': 'application/json'
|
||||
});
|
||||
const voices = await get('/data/voices/all.json');
|
||||
let selectedVoices = model_id ? voices[model_id] : Object.values(voices).reduce((acc, val) => [...acc, ...val], []);
|
||||
selectedVoices = selectedVoices.map((v) => ({
|
||||
name: v.charAt(0).toUpperCase() + v.slice(1),
|
||||
value: v
|
||||
}));
|
||||
const ttsVoices = [
|
||||
{
|
||||
value: 'en-US',
|
||||
name: 'English (US)',
|
||||
voices: selectedVoices
|
||||
}
|
||||
];
|
||||
return tranform(ttsVoices, undefined, TtsModelRimelabs);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForAssemblyAI(credential) {
|
||||
return tranform(undefined, SttAssemblyaiLanguagesVoices);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForWhisper(credential) {
|
||||
return tranform(TtsWhisperLanguagesVoices, undefined, TtsModelWhisper);
|
||||
}
|
||||
|
||||
async function getLanguagesVoicesForVerbio(credentials, getTtsVoices, logger) {
|
||||
const stt = SttVerbioLanguagesVoices.reduce((acc, v) => {
|
||||
if (!v.version || credentials.engine_version === v.version) {
|
||||
acc.push(v);
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
try {
|
||||
const data = await getTtsVoices({vendor: 'verbio', credentials});
|
||||
const voices = parseVerbioLanguagesVoices(data);
|
||||
return tranform(voices, stt, undefined);
|
||||
} catch (err) {
|
||||
logger.info({err}, 'there is error while fetching verbio speech voices');
|
||||
return tranform(TtsVerbioLanguagesVoices, stt, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function tranform(tts, stt, models) {
|
||||
return {
|
||||
...(tts && {tts}),
|
||||
...(stt && {stt}),
|
||||
...(models && {models})
|
||||
};
|
||||
}
|
||||
|
||||
function parseGooglelanguagesVoices(data) {
|
||||
return data.reduce((acc, voice) => {
|
||||
const languageCode = voice.languageCodes[0];
|
||||
const existingLanguage = acc.find((lang) => lang.value === languageCode);
|
||||
|
||||
if (existingLanguage) {
|
||||
existingLanguage.voices.push({
|
||||
value: voice.name,
|
||||
name: `${voice.name.substring(languageCode.length + 1, voice.name.length)} (${voice.ssmlGender})`
|
||||
});
|
||||
} else {
|
||||
acc.push({
|
||||
value: languageCode,
|
||||
name: SttGoogleLanguagesVoices.find((lang) => lang.value === languageCode)?.name || languageCode,
|
||||
voices: [{
|
||||
value: voice.name,
|
||||
name: `${voice.name.substring(languageCode.length + 1, voice.name.length)} (${voice.ssmlGender})`
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function parseIBMLanguagesVoices(data) {
|
||||
return data.reduce((acc, voice) => {
|
||||
const languageCode = voice.language;
|
||||
const existingLanguage = acc.find((lang) => lang.value === languageCode);
|
||||
if (existingLanguage) {
|
||||
existingLanguage.voices.push({
|
||||
value: voice.name,
|
||||
name: `(${voice.gender}) ${voice.description}`
|
||||
});
|
||||
} else {
|
||||
acc.push({
|
||||
value: languageCode,
|
||||
name: SttGoogleLanguagesVoices.find((lang) => lang.value === languageCode)?.name || languageCode,
|
||||
voices: [{
|
||||
value: voice.name,
|
||||
name: `(${voice.gender}) ${voice.description}`
|
||||
}]
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function parseAwsLanguagesVoices(data) {
|
||||
return data.reduce((acc, voice) => {
|
||||
const languageCode = voice.LanguageCode;
|
||||
const existingLanguage = acc.find((lang) => lang.value === languageCode);
|
||||
if (existingLanguage) {
|
||||
existingLanguage.voices.push({
|
||||
value: voice.Id,
|
||||
name: `(${voice.Gender}) ${voice.Name}`
|
||||
});
|
||||
} else {
|
||||
acc.push({
|
||||
value: languageCode,
|
||||
name: voice.LanguageName,
|
||||
voices: [{
|
||||
value: voice.Id,
|
||||
name: `(${voice.Gender}) ${voice.Name}`
|
||||
}]
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function parseNuanceLanguagesVoices(data) {
|
||||
return data.reduce((acc, voice) => {
|
||||
const languageCode = voice.language;
|
||||
const existingLanguage = acc.find((lang) => lang.value === languageCode);
|
||||
if (existingLanguage) {
|
||||
existingLanguage.voices.push({
|
||||
value: voice.name,
|
||||
name: voice.name,
|
||||
model: voice.model
|
||||
});
|
||||
} else {
|
||||
acc.push({
|
||||
value: languageCode,
|
||||
name: SttGoogleLanguagesVoices.find((lang) => lang.value === languageCode)?.name || languageCode,
|
||||
voices: [{
|
||||
value: voice.name,
|
||||
name: voice.name,
|
||||
model: voice.model
|
||||
}]
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function parseMicrosoftLanguagesVoices(data) {
|
||||
return data.reduce((acc, voice) => {
|
||||
const languageCode = voice.Locale;
|
||||
const existingLanguage = acc.find((lang) => lang.value === languageCode);
|
||||
if (existingLanguage) {
|
||||
existingLanguage.voices.push({
|
||||
value: voice.ShortName,
|
||||
name: `${voice.DisplayName} (${voice.Gender})`,
|
||||
});
|
||||
} else {
|
||||
acc.push({
|
||||
value: voice.Locale,
|
||||
name: voice.LocaleName,
|
||||
voices: [{
|
||||
value: voice.ShortName,
|
||||
name: `${voice.DisplayName} (${voice.Gender})`,
|
||||
}]
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function parseVerbioLanguagesVoices(data) {
|
||||
return data.reduce((acc, voice) => {
|
||||
const languageCode = voice.language;
|
||||
const existingLanguage = acc.find((lang) => lang.value === languageCode);
|
||||
if (existingLanguage) {
|
||||
existingLanguage.voices.push({
|
||||
value: voice.voice_id,
|
||||
name: voice.name,
|
||||
});
|
||||
} else {
|
||||
acc.push({
|
||||
value: voice.language,
|
||||
name: voice.language,
|
||||
voices: [{
|
||||
value: voice.voice_id,
|
||||
name: voice.name,
|
||||
}]
|
||||
});
|
||||
}
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
testGoogleTts,
|
||||
testGoogleStt,
|
||||
@@ -1052,16 +251,5 @@ module.exports = {
|
||||
testDeepgramStt,
|
||||
testIbmTts,
|
||||
testIbmStt,
|
||||
testSonioxStt,
|
||||
testElevenlabs,
|
||||
testPlayHT,
|
||||
testRimelabs,
|
||||
testAssemblyStt,
|
||||
testDeepgramTTS,
|
||||
getSpeechCredential,
|
||||
decryptCredential,
|
||||
testWhisper,
|
||||
testVerbioTts,
|
||||
testVerbioStt,
|
||||
getLanguagesAndVoicesForVendor
|
||||
testSonioxStt
|
||||
};
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
const { S3Client, PutObjectCommand, GetObjectCommand, DeleteObjectCommand } = require('@aws-sdk/client-s3');
|
||||
const {Storage} = require('@google-cloud/storage');
|
||||
const fs = require('fs');
|
||||
const { BlobServiceClient } = require('@azure/storage-blob');
|
||||
|
||||
// Azure
|
||||
|
||||
async function testAzureStorage(logger, opts) {
|
||||
const blobServiceClient = BlobServiceClient.fromConnectionString(opts.connection_string);
|
||||
const containerClient = blobServiceClient.getContainerClient(opts.name);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient('jambonz-sample.text');
|
||||
|
||||
await blockBlobClient.uploadFile(`${__dirname}/jambonz-sample.text`);
|
||||
}
|
||||
|
||||
async function getAzureStorageObject(logger, opts) {
|
||||
const blobServiceClient = BlobServiceClient.fromConnectionString(opts.connection_string);
|
||||
const containerClient = blobServiceClient.getContainerClient(opts.name);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(opts.key);
|
||||
const response = await blockBlobClient.download(0);
|
||||
return response.readableStreamBody;
|
||||
}
|
||||
|
||||
async function deleteAzureStorageObject(logger, opts) {
|
||||
const blobServiceClient = BlobServiceClient.fromConnectionString(opts.connection_string);
|
||||
const containerClient = blobServiceClient.getContainerClient(opts.name);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(opts.key);
|
||||
await blockBlobClient.delete();
|
||||
}
|
||||
|
||||
// Google
|
||||
|
||||
function _initGoogleClient(opts) {
|
||||
const serviceKey = JSON.parse(opts.service_key);
|
||||
return new Storage({
|
||||
projectId: serviceKey.project_id,
|
||||
credentials: {
|
||||
client_email: serviceKey.client_email,
|
||||
private_key: serviceKey.private_key
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function testGoogleStorage(logger, opts) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const storage = _initGoogleClient(opts);
|
||||
|
||||
const blob = storage.bucket(opts.name).file('jambonz-sample.text');
|
||||
|
||||
fs.createReadStream(`${__dirname}/jambonz-sample.text`)
|
||||
.pipe(blob.createWriteStream())
|
||||
.on('error', (err) => reject(err))
|
||||
.on('finish', () => resolve());
|
||||
});
|
||||
}
|
||||
|
||||
async function getGoogleStorageObject(logger, opts) {
|
||||
const storage = _initGoogleClient(opts);
|
||||
|
||||
const bucket = storage.bucket(opts.name);
|
||||
const file = bucket.file(opts.key);
|
||||
const [exists] = await file.exists();
|
||||
if (exists) {
|
||||
return file.createReadStream();
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteGoogleStorageObject(logger, opts) {
|
||||
const storage = _initGoogleClient(opts);
|
||||
|
||||
const bucket = storage.bucket(opts.name);
|
||||
const file = bucket.file(opts.key);
|
||||
|
||||
await file.delete();
|
||||
}
|
||||
|
||||
// S3
|
||||
|
||||
function _initS3Client(opts) {
|
||||
return new S3Client({
|
||||
credentials: {
|
||||
accessKeyId: opts.access_key_id,
|
||||
secretAccessKey: opts.secret_access_key,
|
||||
},
|
||||
region: opts.region || 'us-east-1',
|
||||
...(opts.vendor === 's3_compatible' && { endpoint: opts.endpoint, forcePathStyle: true })
|
||||
});
|
||||
}
|
||||
|
||||
async function testS3Storage(logger, opts) {
|
||||
const s3 = _initS3Client(opts);
|
||||
const input = {
|
||||
'Body': 'Hello From Jambonz',
|
||||
'Bucket': opts.name,
|
||||
'Key': 'jambonz-sample.text'
|
||||
};
|
||||
const command = new PutObjectCommand(input);
|
||||
await s3.send(command);
|
||||
}
|
||||
|
||||
async function getS3Object(logger, opts) {
|
||||
const s3 = _initS3Client(opts);
|
||||
const command = new GetObjectCommand(
|
||||
{
|
||||
Bucket: opts.name,
|
||||
Key: opts.key
|
||||
}
|
||||
);
|
||||
const res = await s3.send(command);
|
||||
return res.Body;
|
||||
}
|
||||
|
||||
async function deleteS3Object(logger, opts) {
|
||||
const s3 = _initS3Client(opts);
|
||||
const command = new DeleteObjectCommand(
|
||||
{
|
||||
Bucket: opts.name,
|
||||
Key: opts.key
|
||||
}
|
||||
);
|
||||
await s3.send(command);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
testS3Storage,
|
||||
getS3Object,
|
||||
deleteS3Object,
|
||||
testGoogleStorage,
|
||||
getGoogleStorageObject,
|
||||
deleteGoogleStorageObject,
|
||||
testAzureStorage,
|
||||
getAzureStorageObject,
|
||||
deleteAzureStorageObject
|
||||
};
|
||||
13679
package-lock.json
generated
13679
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
67
package.json
67
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jambonz-api-server",
|
||||
"version": "0.9.2",
|
||||
"version": "0.8.3",
|
||||
"description": "",
|
||||
"main": "app.js",
|
||||
"scripts": {
|
||||
@@ -19,54 +19,45 @@
|
||||
"url": "https://github.com/jambonz/jambonz-api-server.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.550.0",
|
||||
"@aws-sdk/client-transcribe": "^3.549.0",
|
||||
"@azure/storage-blob": "^12.17.0",
|
||||
"@deepgram/sdk": "^1.21.0",
|
||||
"@google-cloud/speech": "^6.5.0",
|
||||
"@google-cloud/storage": "^7.9.0",
|
||||
"@jambonz/db-helpers": "^0.9.3",
|
||||
"@jambonz/lamejs": "^1.2.2",
|
||||
"@jambonz/mw-registrar": "^0.2.7",
|
||||
"@jambonz/realtimedb-helpers": "^0.8.9",
|
||||
"@jambonz/speech-utils": "^0.1.13",
|
||||
"@jambonz/time-series": "^0.2.8",
|
||||
"@jambonz/verb-specifications": "^0.0.72",
|
||||
"@soniox/soniox-node": "^1.2.2",
|
||||
"argon2": "^0.40.1",
|
||||
"assemblyai": "^4.3.4",
|
||||
"@aws-sdk/client-transcribe": "^3.290.0",
|
||||
"@deepgram/sdk": "^1.10.2",
|
||||
"@google-cloud/speech": "^5.1.0",
|
||||
"@jambonz/db-helpers": "^0.7.9",
|
||||
"@jambonz/realtimedb-helpers": "^0.7.2",
|
||||
"@jambonz/speech-utils": "^0.0.12",
|
||||
"@jambonz/time-series": "^0.2.5",
|
||||
"@jambonz/verb-specifications": "^0.0.21",
|
||||
"@soniox/soniox-node": "^1.1.0",
|
||||
"argon2": "^0.30.3",
|
||||
"bent": "^7.3.12",
|
||||
"cors": "^2.8.5",
|
||||
"debug": "^4.3.4",
|
||||
"express": "^4.19.2",
|
||||
"express-rate-limit": "^7.2.0",
|
||||
"form-data": "^4.0.0",
|
||||
"helmet": "^7.1.0",
|
||||
"ibm-watson": "^9.0.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mailgun.js": "^10.2.1",
|
||||
"microsoft-cognitiveservices-speech-sdk": "1.36.0",
|
||||
"mysql2": "^3.11.0",
|
||||
"nocache": "4.0.0",
|
||||
"passport": "^0.7.0",
|
||||
"express": "^4.18.1",
|
||||
"express-rate-limit": "^6.4.0",
|
||||
"form-data": "^2.5.1",
|
||||
"helmet": "^5.1.0",
|
||||
"ibm-watson": "^7.1.2",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"mailgun.js": "^3.7.3",
|
||||
"microsoft-cognitiveservices-speech-sdk": "^1.24.1",
|
||||
"mysql2": "^2.3.3",
|
||||
"nocache": "3.0.4",
|
||||
"passport": "^0.6.0",
|
||||
"passport-http-bearer": "^1.0.1",
|
||||
"pino": "^8.20.0",
|
||||
"short-uuid": "^4.2.2",
|
||||
"stream-buffers": "^3.0.2",
|
||||
"stripe": "^14.24.0",
|
||||
"swagger-ui-express": "^5.0.0",
|
||||
"uuid": "^9.0.1",
|
||||
"wav": "^1.0.2",
|
||||
"ws": "^8.16.0",
|
||||
"pino": "^5.17.0",
|
||||
"short-uuid": "^4.1.0",
|
||||
"stripe": "^8.222.0",
|
||||
"swagger-ui-express": "^4.4.0",
|
||||
"uuid": "^8.3.2",
|
||||
"yamljs": "^0.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8.39.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"husky": "9.0.11",
|
||||
"husky": "7.0.4",
|
||||
"nyc": "^15.1.0",
|
||||
"request": "^2.88.2",
|
||||
"request-promise-native": "^1.0.9",
|
||||
"tape": "^5.7.5"
|
||||
"tape": "^5.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ const {
|
||||
createPhoneNumber,
|
||||
deleteObjectBySid} = require('./utils');
|
||||
const logger = require('../lib/logger');
|
||||
const { addToSortedSet, createHash } = require('@jambonz/realtimedb-helpers')({
|
||||
const { pushBack } = require('@jambonz/realtimedb-helpers')({
|
||||
host: process.env.JAMBONES_REDIS_HOST,
|
||||
port: process.env.JAMBONES_REDIS_PORT || 6379
|
||||
}, logger);
|
||||
@@ -168,33 +168,11 @@ test('account tests', async(t) => {
|
||||
queue_event_hook: {
|
||||
url: 'http://example.com/q',
|
||||
method: 'post'
|
||||
},
|
||||
record_all_calls: true,
|
||||
record_format: 'wav',
|
||||
bucket_credential: {
|
||||
vendor: 'aws_s3',
|
||||
region: 'us-east-1',
|
||||
name: 'recordings',
|
||||
access_key_id: 'access_key_id',
|
||||
secret_access_key: 'secret access key'
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully updated account using account level token');
|
||||
|
||||
/* verify that bucket credential is updated*/
|
||||
result = await request.get(`/Accounts/${sid}`, {
|
||||
auth: {bearer: accountLevelToken},
|
||||
json: true,
|
||||
});
|
||||
|
||||
t.ok(result.bucket_credential.vendor === 'aws_s3', 'bucket_vendor was updated');
|
||||
t.ok(result.bucket_credential.name === 'recordings', 'bucket_name was updated');
|
||||
t.ok(result.bucket_credential.access_key_id === 'access_key_id', 'bucket_access_key_id was updated');
|
||||
t.ok(result.record_all_calls === 1, 'record_all_calls was updated');
|
||||
t.ok(result.record_format === 'wav', 'record_format was updated');
|
||||
|
||||
/* verify that account level api key last_used was updated*/
|
||||
result = await request.get(`/Accounts/${sid}/ApiKeys`, {
|
||||
auth: {bearer: accountLevelToken},
|
||||
@@ -290,8 +268,8 @@ test('account tests', async(t) => {
|
||||
t.ok(result.statusCode === 204, 'successfully deleted a call session limit for an account');
|
||||
|
||||
/* query account queues */
|
||||
await addToSortedSet(`queue:${sid}:test`, 'url1');
|
||||
await addToSortedSet(`queue:${sid}:dummy`, 'url2');
|
||||
await pushBack(`queue:${sid}:test`, 'url1');
|
||||
await pushBack(`queue:${sid}:dummy`, 'url2');
|
||||
|
||||
result = await request.get(`/Accounts/${sid}/Queues`, {
|
||||
auth: authAdmin,
|
||||
@@ -314,19 +292,6 @@ test('account tests', async(t) => {
|
||||
});
|
||||
t.ok(result.statusCode === 200 && result.body.length === 0, 'successfully queried account queue info with for an invalid account');
|
||||
|
||||
// query conferences
|
||||
await createHash(`conf:${sid}:conf1`, 'url1');
|
||||
await createHash(`conf:${sid}:conf2`, 'url2');
|
||||
await createHash(`conf:${sid}:conf3`, 'url3');
|
||||
await createHash(`conf:${sid}:conf4`, 'url4');
|
||||
|
||||
result = await request.get(`/Accounts/${sid}/Conferences`, {
|
||||
auth: authAdmin,
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.statusCode === 200 && result.body.length === 4, 'successfully queried account conferences info for an account');
|
||||
|
||||
/* delete account */
|
||||
result = await request.delete(`/Accounts/${sid}`, {
|
||||
auth: authAdmin,
|
||||
|
||||
@@ -53,7 +53,7 @@ test('application tests', async(t) => {
|
||||
]'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 400, 'Cant create application with invalid app_json');
|
||||
t.ok(result.statusCode === 400, 'Cant create application with invalid app_josn');
|
||||
|
||||
/* add an application */
|
||||
result = await request.post('/Applications', {
|
||||
@@ -81,15 +81,7 @@ test('application tests', async(t) => {
|
||||
"seekOffset": 8000,\
|
||||
"actionHook": "/play/action"\
|
||||
}\
|
||||
]',
|
||||
use_for_fallback_speech: 1,
|
||||
fallback_speech_synthesis_vendor: 'google',
|
||||
fallback_speech_synthesis_language: 'en-US',
|
||||
fallback_speech_synthesis_voice: 'man',
|
||||
fallback_speech_synthesis_label: 'label1',
|
||||
fallback_speech_recognizer_vendor: 'google',
|
||||
fallback_speech_recognizer_language: 'en-US',
|
||||
fallback_speech_recognizer_label: 'label1'
|
||||
]'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created application');
|
||||
@@ -110,14 +102,6 @@ test('application tests', async(t) => {
|
||||
});
|
||||
t.ok(result.name === 'daveh' , 'successfully retrieved application by sid');
|
||||
t.ok(result.messaging_hook.url === 'http://example.com/sms' , 'successfully retrieved messaging_hook from application');
|
||||
t.ok(result.use_for_fallback_speech === 1, 'successfully create use_for_fallback_speech');
|
||||
t.ok(result.fallback_speech_synthesis_vendor === 'google', 'successfully create fallback_speech_synthesis_vendor');
|
||||
t.ok(result.fallback_speech_synthesis_language === 'en-US', 'successfully create fallback_speech_synthesis_language');
|
||||
t.ok(result.fallback_speech_synthesis_voice === 'man', 'successfully create fallback_speech_synthesis_voice');
|
||||
t.ok(result.fallback_speech_synthesis_label === 'label1', 'successfully create fallback_speech_synthesis_label');
|
||||
t.ok(result.fallback_speech_recognizer_vendor === 'google', 'successfully create fallback_speech_recognizer_vendor');
|
||||
t.ok(result.fallback_speech_recognizer_language === 'en-US', 'successfully create fallback_speech_recognizer_language');
|
||||
t.ok(result.fallback_speech_recognizer_label === 'label1', 'successfully create fallback_speech_recognizer_label');
|
||||
let app_json = JSON.parse(result.app_json);
|
||||
t.ok(app_json[0].verb === 'play', 'successfully retrieved app_json from application')
|
||||
|
||||
@@ -141,16 +125,7 @@ test('application tests', async(t) => {
|
||||
"X-Reason" : "maximum call duration exceeded"\
|
||||
}\
|
||||
}\
|
||||
]',
|
||||
record_all_calls: true,
|
||||
use_for_fallback_speech: 0,
|
||||
fallback_speech_synthesis_vendor: 'microsoft',
|
||||
fallback_speech_synthesis_language: 'en-US',
|
||||
fallback_speech_synthesis_voice: 'woman',
|
||||
fallback_speech_synthesis_label: 'label2',
|
||||
fallback_speech_recognizer_vendor: 'microsoft',
|
||||
fallback_speech_recognizer_language: 'en-US',
|
||||
fallback_speech_recognizer_label: 'label2'
|
||||
]'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully updated application');
|
||||
@@ -163,15 +138,6 @@ test('application tests', async(t) => {
|
||||
t.ok(result.messaging_hook.url === 'http://example2.com/mms' , 'successfully updated messaging_hook');
|
||||
app_json = JSON.parse(result.app_json);
|
||||
t.ok(app_json[0].verb === 'hangup', 'successfully updated app_json from application')
|
||||
t.ok(result.record_all_calls === 1, 'successfully updated record_all_calls from application')
|
||||
t.ok(result.use_for_fallback_speech === 0, 'successfully update use_for_fallback_speech');
|
||||
t.ok(result.fallback_speech_synthesis_vendor === 'microsoft', 'successfully update fallback_speech_synthesis_vendor');
|
||||
t.ok(result.fallback_speech_synthesis_language === 'en-US', 'successfully update fallback_speech_synthesis_language');
|
||||
t.ok(result.fallback_speech_synthesis_voice === 'woman', 'successfully update fallback_speech_synthesis_voice');
|
||||
t.ok(result.fallback_speech_synthesis_label === 'label2', 'successfully update fallback_speech_synthesis_label');
|
||||
t.ok(result.fallback_speech_recognizer_vendor === 'microsoft', 'successfully update fallback_speech_recognizer_vendor');
|
||||
t.ok(result.fallback_speech_recognizer_language === 'en-US', 'successfully update fallback_speech_recognizer_language');
|
||||
t.ok(result.fallback_speech_recognizer_label === 'label2', 'successfully update fallback_speech_recognizer_label');
|
||||
|
||||
/* remove applications app_json*/
|
||||
result = await request.put(`/Applications/${sid}`, {
|
||||
|
||||
@@ -31,8 +31,8 @@ test('Create Call Success With Synthesizer in Payload', async (t) => {
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
call_hook: "https://public-apps.jambonz.cloud/hello-world",
|
||||
call_status_hook: "https://public-apps.jambonz.cloud/call-status",
|
||||
call_hook: "https://public-apps.jambonz.us/hello-world",
|
||||
call_status_hook: "https://public-apps.jambonz.us/call-status",
|
||||
from: "15083778299",
|
||||
to: {
|
||||
type: "phone",
|
||||
@@ -73,8 +73,8 @@ test('Create Call Success Without Synthesizer in Payload', async (t) => {
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
call_hook: "https://public-apps.jambonz.cloud/hello-world",
|
||||
call_status_hook: "https://public-apps.jambonz.cloud/call-status",
|
||||
call_hook: "https://public-apps.jambonz.us/hello-world",
|
||||
call_status_hook: "https://public-apps.jambonz.us/call-status",
|
||||
from: "15083778299",
|
||||
to: {
|
||||
type: "phone",
|
||||
@@ -83,74 +83,4 @@ test('Create Call Success Without Synthesizer in Payload', async (t) => {
|
||||
}
|
||||
}).then(data => { t.ok(false, 'Create Call should not be success') })
|
||||
.catch(error => { t.ok(error.response.statusCode === 400, 'Call failed for no synthesizer') });
|
||||
});
|
||||
|
||||
test("Create call with application sid and app_json", async(t) => {
|
||||
const app = require('../app');
|
||||
|
||||
const service_provider_sid = await createServiceProvider(request, 'account3_has_synthesizer');
|
||||
const account_sid = await createAccount(request, service_provider_sid, 'account3_has_synthesizer');
|
||||
|
||||
const token = jwt.sign({
|
||||
account_sid,
|
||||
scope: "account",
|
||||
permissions: ["PROVISION_USERS", "PROVISION_SERVICES", "VIEW_ONLY"]
|
||||
}, process.env.JWT_SECRET, { expiresIn: '1h' });
|
||||
const authUser = { bearer: token };
|
||||
const speech_sid = await createGoogleSpeechCredentials(request, account_sid, null, authUser, true, true);
|
||||
|
||||
// GIVEN
|
||||
/* add an application */
|
||||
|
||||
const app_json = '[\
|
||||
{\
|
||||
"verb": "play",\
|
||||
"url": "https://example.com/example.mp3",\
|
||||
"timeoutSecs": 10,\
|
||||
"seekOffset": 8000,\
|
||||
"actionHook": "/play/action"\
|
||||
}\
|
||||
]';
|
||||
let result = await request.post('/Applications', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
name: 'daveh',
|
||||
account_sid,
|
||||
call_hook: {
|
||||
url: 'http://example.com'
|
||||
},
|
||||
call_status_hook: {
|
||||
url: 'http://example.com/status',
|
||||
method: 'POST'
|
||||
},
|
||||
messaging_hook: {
|
||||
url: 'http://example.com/sms'
|
||||
},
|
||||
app_json
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created application');
|
||||
const sid = result.body.sid;
|
||||
|
||||
// WHEN
|
||||
result = await request.post(`/Accounts/${account_sid}/Calls`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
application_sid: sid,
|
||||
from: "15083778299",
|
||||
to: {
|
||||
type: "phone",
|
||||
number: "15089084809"
|
||||
},
|
||||
}
|
||||
});
|
||||
// THEN
|
||||
t.ok(result.statusCode === 201, 'successfully created Call without Synthesizer && application_sid');
|
||||
const fs_request = await getLastRequestFromFeatureServer('15083778299_createCall');
|
||||
const obj = JSON.parse(fs_request);
|
||||
t.ok(obj.body.app_json == app_json, 'app_json successfully added')
|
||||
});
|
||||
163
test/clients.js
163
test/clients.js
@@ -1,163 +0,0 @@
|
||||
const test = require('tape') ;
|
||||
const ADMIN_TOKEN = '38700987-c7a4-4685-a5bb-af378f9734de';
|
||||
const authAdmin = {bearer: ADMIN_TOKEN};
|
||||
const request = require('request-promise-native').defaults({
|
||||
baseUrl: 'http://127.0.0.1:3000/v1'
|
||||
});
|
||||
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
});
|
||||
|
||||
test('client test', async(t) => {
|
||||
const app = require('../app');
|
||||
const {registrar} = app.locals;
|
||||
|
||||
try {
|
||||
let result;
|
||||
/* add a service provider */
|
||||
result = await request.post('/ServiceProviders', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
body: {
|
||||
name: 'client_sp',
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created client service provider');
|
||||
const sp_sid = result.body.sid;
|
||||
|
||||
/* add an account */
|
||||
result = await request.post('/Accounts', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
body: {
|
||||
name: 'sample_account',
|
||||
service_provider_sid: sp_sid,
|
||||
sip_realm: 'drachtio.org',
|
||||
registration_hook: {
|
||||
url: 'http://example.com/reg',
|
||||
method: 'get'
|
||||
},
|
||||
webhook_secret: 'foobar'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created account');
|
||||
const account_sid = result.body.sid;
|
||||
|
||||
/* add new entity */
|
||||
result = await request.post('/Clients', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
body: {
|
||||
account_sid,
|
||||
username: 'client1',
|
||||
password: 'sdf12412',
|
||||
is_active: 1,
|
||||
allow_direct_app_calling: 0,
|
||||
allow_direct_queue_calling: 1,
|
||||
allow_direct_user_calling: 1,
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created Client');
|
||||
const sid = result.body.sid;
|
||||
|
||||
/* register the client */
|
||||
const r = await registrar.add(
|
||||
"dhorton@drachtio.org",
|
||||
{
|
||||
contact: "10.10.1.1",
|
||||
sbcAddress: "192.168.1.1",
|
||||
protocol: "udp",
|
||||
},
|
||||
5
|
||||
);
|
||||
t.ok(r, 'successfully registered Client');
|
||||
|
||||
/* query all registered clients */
|
||||
result = await request.get(`/Accounts/${account_sid}/RegisteredSipUsers`, {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.length === 1 && result[0] === 'dhorton@drachtio.org',
|
||||
'successfully queried all registered clients');
|
||||
|
||||
result = await request.post(`/Accounts/${account_sid}/RegisteredSipUsers`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
body: ['dhorton']
|
||||
});
|
||||
t.ok(result.body.length === 1 && result.body[0].name === 'dhorton',
|
||||
'successfully queried all registered clients');
|
||||
|
||||
result = await request.post(`/Accounts/${account_sid}/RegisteredSipUsers`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
body: []
|
||||
});
|
||||
t.ok(result.body.length === 1 && result.body[0].name === 'dhorton',
|
||||
'successfully queried all registered clients');
|
||||
|
||||
/* query all entity */
|
||||
result = await request.get('/Clients', {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.length === 1 , 'successfully queried all Clients');
|
||||
|
||||
/* query one entity */
|
||||
result = await request.get(`/Clients/${sid}`, {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.account_sid === account_sid , 'successfully retrieved Client by sid');
|
||||
t.ok(result.client_sid, 'successfully retrieved Client by sid');
|
||||
t.ok(result.username === 'client1', 'successfully retrieved Client by sid');
|
||||
t.ok(result.is_active === 1 , 'successfully retrieved Client by sid');
|
||||
t.ok(result.password === 'sXXXXXXX' , 'successfully retrieved Client by sid');
|
||||
t.ok(result.allow_direct_app_calling === 0 , 'successfully retrieved Client by sid');
|
||||
|
||||
/* update the entity */
|
||||
result = await request.put(`/Clients/${sid}`, {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
resolveWithFullResponse: true,
|
||||
body: {
|
||||
is_active: 0
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully updated Client');
|
||||
/* query one entity */
|
||||
result = await request.get(`/Clients/${sid}`, {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.is_active === 0 , 'successfully updated Client');
|
||||
t.ok(result.password === 'sXXXXXXX' , 'successfully retrieved Client by sid');
|
||||
|
||||
/* delete Client */
|
||||
result = await request.delete(`/Clients/${sid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
json: true,
|
||||
auth: authAdmin
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted Clients');
|
||||
|
||||
/* query all entity */
|
||||
result = await request.get('/Clients', {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.length === 0 , 'successfully queried all Clients');
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
t.end(err);
|
||||
}
|
||||
})
|
||||
@@ -10,7 +10,7 @@ networks:
|
||||
|
||||
services:
|
||||
mysql:
|
||||
# platform: linux/x86_64
|
||||
platform: linux/x86_64
|
||||
image: mysql:5.7
|
||||
ports:
|
||||
- "3360:3306"
|
||||
@@ -36,7 +36,7 @@ services:
|
||||
ipv4_address: 172.58.0.3
|
||||
|
||||
influxdb:
|
||||
# platform: linux/x86_64
|
||||
platform: linux/x86_64
|
||||
image: influxdb:1.8
|
||||
ports:
|
||||
- "8086:8086"
|
||||
|
||||
@@ -23,6 +23,4 @@ require('./system-information');
|
||||
require('./lcr-carriers-set-entries');
|
||||
require('./lcr-routes');
|
||||
require('./lcrs');
|
||||
require('./tts-cache');
|
||||
require('./clients');
|
||||
require('./docker_stop');
|
||||
|
||||
@@ -7,7 +7,7 @@ const test = async() => {
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env.GH_CODE}`,
|
||||
Accept: 'application/json',
|
||||
'User-Agent': 'jambonz.cloud'
|
||||
'User-Agent': 'jambonz.us'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
if (err) console.log(error);
|
||||
|
||||
@@ -75,29 +75,8 @@ test('recent calls tests', async(t) => {
|
||||
auth: authUser,
|
||||
json: true,
|
||||
});
|
||||
console.log(JSON.stringify(result));
|
||||
t.ok(result.data.length === 5, 'retrieved 5 recent calls by account');
|
||||
|
||||
result = await request.get(`/Accounts/${account_sid}/RecentCalls?page=1&count=25&filter=1508`, {
|
||||
auth: authUser,
|
||||
json: true,
|
||||
});
|
||||
console.log(JSON.stringify(result));
|
||||
t.ok(result.data.length === 5, 'retrieved 5 recent calls by account and from');
|
||||
|
||||
result = await request.get(`/Accounts/${account_sid}/RecentCalls?page=1&count=25&filter=15080`, {
|
||||
auth: authUser,
|
||||
json: true,
|
||||
});
|
||||
console.log(JSON.stringify(result));
|
||||
t.ok(result.data.length === 0, 'retrieved 0 recent calls by account and non-matching from');
|
||||
|
||||
result = await request.get(`/Accounts/${account_sid}/RecentCalls?page=1&count=25&filter=1888`, {
|
||||
auth: authUser,
|
||||
json: true,
|
||||
});
|
||||
console.log(JSON.stringify(result));
|
||||
t.ok(result.data.length === 5, 'retrieved 5 recent calls by account and to');
|
||||
//console.log({data: result.data}, 'Account recent calls');
|
||||
|
||||
/* query last 7 days by service provider */
|
||||
result = await request.get(`/ServiceProviders/${service_provider_sid}/RecentCalls?page=1&count=25`, {
|
||||
@@ -105,19 +84,6 @@ test('recent calls tests', async(t) => {
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.data.length === 5, 'retrieved 5 recent calls by service provider');
|
||||
|
||||
result = await request.get(`/ServiceProviders/${service_provider_sid}/RecentCalls?page=1&count=25&filter=1508`, {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.data.length === 5, 'retrieved 5 recent calls by service provider and from');
|
||||
|
||||
result = await request.get(`/ServiceProviders/${service_provider_sid}/RecentCalls?page=1&count=25&filter=1888`, {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.data.length === 5, 'retrieved 5 recent calls by service provider and to');
|
||||
|
||||
//console.log({data: result.data}, 'SP recent calls');
|
||||
|
||||
/* pull sip traces and pcap from homer */
|
||||
|
||||
45
test/sbcs.js
45
test/sbcs.js
@@ -17,37 +17,6 @@ test('sbc_addresses tests', async(t) => {
|
||||
let result;
|
||||
const service_provider_sid = await createServiceProvider(request);
|
||||
|
||||
/* add service_provider user */
|
||||
const sp_name = 'sbc_service_provider';
|
||||
const sp_password = 'password';
|
||||
result = await request.post(`/Users`, {
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
auth: authAdmin,
|
||||
body: {
|
||||
name: sp_name,
|
||||
email: 'sbc_sp@jambonz.com',
|
||||
is_active: true,
|
||||
force_change: false,
|
||||
initial_password: sp_password,
|
||||
service_provider_sid,
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201 && result.body.user_sid, 'SBC service_provider scope user created');
|
||||
const sbc_sp_user_sid = result.body.user_sid;
|
||||
|
||||
result = await request.post('/login', {
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
body: {
|
||||
username: sp_name,
|
||||
password: sp_password,
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 200 && result.body.token, 'successfully logged in as sbc user');
|
||||
const authSbcSp = {bearer: result.body.token};
|
||||
|
||||
|
||||
/* add a service provider sbc */
|
||||
result = await request.post('/Sbcs', {
|
||||
resolveWithFullResponse: true,
|
||||
@@ -69,20 +38,6 @@ test('sbc_addresses tests', async(t) => {
|
||||
//console.log(result.body)
|
||||
t.ok(result.body.length === 1 && result.body[0].ipv4 === '192.168.1.4', 'successfully retrieved service provider sbc');
|
||||
|
||||
result = await request.get('/Sbcs', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authSbcSp,
|
||||
json: true
|
||||
});
|
||||
//console.log(result.body)
|
||||
t.ok(result.body.length === 1 && result.body[0].ipv4 === '192.168.1.4', 'successfully retrieved service provider sbc');
|
||||
|
||||
await request.delete(`/Users/${sbc_sp_user_sid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
json: true,
|
||||
auth: authAdmin,
|
||||
});
|
||||
|
||||
await deleteObjectBySid(request, '/Sbcs', sid);
|
||||
await deleteObjectBySid(request, '/ServiceProviders', service_provider_sid);
|
||||
|
||||
|
||||
@@ -17,53 +17,6 @@ test('sip gateway tests', async(t) => {
|
||||
let result;
|
||||
const voip_carrier_sid = await createVoipCarrier(request);
|
||||
|
||||
/* add a invalid sip gateway */
|
||||
const STORED_JAMBONZ_MIN_GATEWAY_NETMASK = process.env.JAMBONZ_MIN_GATEWAY_NETMASK;
|
||||
process.env.JAMBONZ_MIN_GATEWAY_NETMASK = 24;
|
||||
|
||||
result = await request.post('/SipGateways', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
simple: false,
|
||||
body: {
|
||||
voip_carrier_sid,
|
||||
ipv4: '1.2.3.4',
|
||||
netmask: 1,
|
||||
inbound: true,
|
||||
outbound: true,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 400, 'successfully created sip gateway ');
|
||||
|
||||
result = await request.post('/SipGateways', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
body: {
|
||||
voip_carrier_sid,
|
||||
ipv4: '1.2.3.4',
|
||||
netmask: 24,
|
||||
inbound: true,
|
||||
outbound: true,
|
||||
protocol: 'tcp'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created sip gateway ');
|
||||
|
||||
process.env.JAMBONZ_MIN_GATEWAY_NETMASK = STORED_JAMBONZ_MIN_GATEWAY_NETMASK;
|
||||
|
||||
/* delete sip gateways */
|
||||
result = await request.delete(`/SipGateways/${result.body.sid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
json: true,
|
||||
auth: authAdmin
|
||||
});
|
||||
//console.log(`result: ${JSON.stringify(result)}`);
|
||||
t.ok(result.statusCode === 204, 'successfully deleted sip gateway');
|
||||
|
||||
/* add a sip gateway */
|
||||
result = await request.post('/SipGateways', {
|
||||
resolveWithFullResponse: true,
|
||||
@@ -122,44 +75,6 @@ test('sip gateway tests', async(t) => {
|
||||
});
|
||||
//console.log(`result: ${JSON.stringify(result)}`);
|
||||
t.ok(result.statusCode === 204, 'successfully deleted sip gateway');
|
||||
|
||||
/* add a sip gateway */
|
||||
result = await request.post('/SipGateways', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
body: {
|
||||
voip_carrier_sid,
|
||||
ipv4: '192.168.1.2',
|
||||
netmask: 32,
|
||||
inbound: true,
|
||||
outbound: true,
|
||||
protocol: 'tls',
|
||||
use_sips_scheme: true
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created sip gateway ');
|
||||
const sipsSid = result.body.sid;
|
||||
|
||||
/* query one sip gateway */
|
||||
result = await request.get(`/SipGateways/${sipsSid}`, {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
//console.log(`result: ${JSON.stringify(result)}`);
|
||||
t.ok(result.ipv4 === '192.168.1.2' , 'successfully retrieved voip carrier by sid');
|
||||
t.ok(result.protocol === 'tls' , 'successfully retrieved voip carrier by sid');
|
||||
t.ok(result.use_sips_scheme, 'successfully retrieved voip carrier by sid');
|
||||
|
||||
/* delete sip gateways */
|
||||
result = await request.delete(`/SipGateways/${sipsSid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
json: true,
|
||||
auth: authAdmin
|
||||
});
|
||||
//console.log(`result: ${JSON.stringify(result)}`);
|
||||
t.ok(result.statusCode === 204, 'successfully deleted sip gateway');
|
||||
|
||||
await deleteObjectBySid(request, '/VoipCarriers', voip_carrier_sid);
|
||||
|
||||
|
||||
@@ -84,7 +84,6 @@ test('speech credentials tests', async(t) => {
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'google',
|
||||
label: 'label1',
|
||||
service_key: jsonKey,
|
||||
use_for_tts: true,
|
||||
use_for_stt: true
|
||||
@@ -112,7 +111,6 @@ test('speech credentials tests', async(t) => {
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.vendor === 'google' , 'successfully retrieved speech credential by sid');
|
||||
t.ok(result.label === 'label1' , 'label is successfully created');
|
||||
|
||||
/* query all credentials */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
@@ -170,20 +168,6 @@ test('speech credentials tests', async(t) => {
|
||||
//console.log(JSON.stringify(result));
|
||||
t.ok(result.statusCode === 200 && result.body.tts.status === 'ok', 'successfully tested speech credential for google tts');
|
||||
t.ok(result.statusCode === 200 && result.body.stt.status === 'ok', 'successfully tested speech credential for google stt');
|
||||
|
||||
result = await request.post(`/Accounts/${account_sid}/TtsCache/Synthesize`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
speech_credential_sid: ms_sid,
|
||||
text: "Hello How are you",
|
||||
language: "en-US",
|
||||
voice: "en-US-Standard-C"
|
||||
}
|
||||
});
|
||||
|
||||
t.ok(result.statusCode === 200, 'successfully google tested synthesize');
|
||||
}
|
||||
|
||||
/* add / test a credential for microsoft */
|
||||
@@ -212,20 +196,6 @@ test('speech credentials tests', async(t) => {
|
||||
//console.log(JSON.stringify(result));
|
||||
t.ok(result.statusCode === 200 && result.body.tts.status === 'ok', 'successfully tested speech credential for microsoft tts');
|
||||
t.ok(result.statusCode === 200 && result.body.stt.status === 'ok', 'successfully tested speech credential for microsoft stt');
|
||||
|
||||
result = await request.post(`/Accounts/${account_sid}/TtsCache/Synthesize`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
speech_credential_sid: ms_sid,
|
||||
text: "Hello How are you",
|
||||
language: "en-US",
|
||||
voice: "en-US-AvaMultilingualNeural"
|
||||
}
|
||||
});
|
||||
|
||||
t.ok(result.statusCode === 200, 'successfully microsoft tested synthesize');
|
||||
}
|
||||
|
||||
/* add / test a credential for AWS */
|
||||
@@ -255,20 +225,6 @@ test('speech credentials tests', async(t) => {
|
||||
//console.log(JSON.stringify(result));
|
||||
t.ok(result.statusCode === 200 && result.body.tts.status === 'ok', 'successfully tested speech credential for AWS tts');
|
||||
t.ok(result.statusCode === 200 && result.body.stt.status === 'ok', 'successfully tested speech credential for AWS stt');
|
||||
|
||||
result = await request.post(`/Accounts/${account_sid}/TtsCache/Synthesize`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
speech_credential_sid: ms_sid,
|
||||
text: "Hello How are you",
|
||||
language: "en-US",
|
||||
voice: "Joanna"
|
||||
}
|
||||
});
|
||||
|
||||
t.ok(result.statusCode === 200, 'successfully AWS tested synthesize');
|
||||
}
|
||||
|
||||
/* add a credential for wellsaid */
|
||||
@@ -295,20 +251,6 @@ test('speech credentials tests', async(t) => {
|
||||
//console.log(JSON.stringify(result));
|
||||
t.ok(result.statusCode === 200 && result.body.tts.status === 'ok', 'successfully tested speech credential for wellsaid');
|
||||
|
||||
result = await request.post(`/Accounts/${account_sid}/TtsCache/Synthesize`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
speech_credential_sid: ms_sid,
|
||||
text: "Hello How are you",
|
||||
language: "en-US",
|
||||
voice: "3"
|
||||
}
|
||||
});
|
||||
|
||||
t.ok(result.statusCode === 200, 'successfully Wellsaid tested synthesize');
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${ms_sid}`, {
|
||||
auth: authUser,
|
||||
@@ -341,20 +283,6 @@ test('speech credentials tests', async(t) => {
|
||||
//console.log(JSON.stringify(result));
|
||||
t.ok(result.statusCode === 200 && result.body.stt.status === 'ok', 'successfully tested speech credential for deepgram');
|
||||
|
||||
result = await request.post(`/Accounts/${account_sid}/TtsCache/Synthesize`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
speech_credential_sid: ms_sid,
|
||||
text: "Hello How are you",
|
||||
language: "en-US",
|
||||
voice: "aura-asteria-en"
|
||||
}
|
||||
});
|
||||
|
||||
t.ok(result.statusCode === 200, 'successfully deepgram tested synthesize');
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${ms_sid}`, {
|
||||
auth: authUser,
|
||||
@@ -362,64 +290,6 @@ test('speech credentials tests', async(t) => {
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential');
|
||||
}
|
||||
// test create deepgram onprem
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'deepgram',
|
||||
use_for_stt: true,
|
||||
deepgram_stt_uri: "127.0.0.1:50002",
|
||||
deepgram_stt_use_tls: true,
|
||||
deepgram_tts_uri: 'https://server.com'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for deepgram');
|
||||
const dg_sid = result.body.sid;
|
||||
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/${dg_sid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
});
|
||||
//console.log(JSON.stringify(result));
|
||||
t.ok(result.statusCode === 200, 'successfully get speech credential for deepgram');
|
||||
t.ok(result.body.deepgram_stt_uri === '127.0.0.1:50002', "deepgram_stt_uri is correct for deepgram");
|
||||
t.ok(result.body.deepgram_stt_use_tls === true, "deepgram_stt_use_tls is correct for deepgram");
|
||||
t.ok(result.body.deepgram_tts_uri === 'https://server.com', "deepgram_tts_uri is correct for deepgram")
|
||||
|
||||
result = await request.put(`/Accounts/${account_sid}/SpeechCredentials/${dg_sid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'deepgram',
|
||||
use_for_stt: true,
|
||||
deepgram_stt_uri: "127.0.0.2:50002",
|
||||
deepgram_stt_use_tls: false,
|
||||
deepgram_tts_uri: 'https://server2.com'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully updated speech credential for deepgram onprem');
|
||||
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/${dg_sid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
});
|
||||
//console.log(JSON.stringify(result));
|
||||
t.ok(result.statusCode === 200, 'successfully get speech credential for deepgram onprem');
|
||||
t.ok(result.body.deepgram_stt_uri === '127.0.0.2:50002', "deepgram_stt_uri is correct for deepgram onprem");
|
||||
t.ok(result.body.deepgram_stt_use_tls === false, "deepgram_stt_use_tls is correct for deepgram onprem");
|
||||
t.ok(result.body.deepgram_tts_uri === 'https://server2.com', "deepgram_tts_uri is correct for deepgram onprem");
|
||||
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${dg_sid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential for deepgram onprem');
|
||||
|
||||
/* add a credential for ibm tts */
|
||||
if (process.env.IBM_TTS_API_KEY && process.env.IBM_TTS_REGION) {
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
@@ -478,20 +348,6 @@ test('speech credentials tests', async(t) => {
|
||||
//console.log(JSON.stringify(result));
|
||||
t.ok(result.statusCode === 200 && result.body.stt.status === 'ok', 'successfully tested speech credential for ibm stt');
|
||||
|
||||
result = await request.post(`/Accounts/${account_sid}/TtsCache/Synthesize`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
speech_credential_sid: ms_sid,
|
||||
text: "Hello How are you",
|
||||
language: "en-US",
|
||||
voice: "en-US_MichaelExpressive"
|
||||
}
|
||||
});
|
||||
|
||||
t.ok(result.statusCode === 200, 'successfully IBM tested synthesize');
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${ms_sid}`, {
|
||||
auth: authUser,
|
||||
@@ -589,366 +445,6 @@ test('speech credentials tests', async(t) => {
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential');
|
||||
|
||||
/* add a credential for cobalt */
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'cobalt',
|
||||
use_for_stt: true,
|
||||
use_for_tts: false,
|
||||
cobalt_server_uri: '32.32.32.32:2727',
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for Cobalt');
|
||||
const cobalt_sid = result.body.sid;
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${cobalt_sid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential for Cobalt');
|
||||
|
||||
/* add a credential for elevenlabs */
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'elevenlabs',
|
||||
use_for_stt: true,
|
||||
use_for_tts: false,
|
||||
api_key: 'asdasdasdasddsadasda',
|
||||
model_id: 'eleven_multilingual_v2'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for elevenlabs');
|
||||
const elevenlabs_sid = result.body.sid;
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${elevenlabs_sid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential for elevenlabs');
|
||||
|
||||
/* add a credential for playht */
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'playht',
|
||||
use_for_stt: false,
|
||||
use_for_tts: true,
|
||||
api_key: 'asdasdasdasddsadasda',
|
||||
user_id: 'user_id',
|
||||
voice_engine: 'PlayHT2.0-turbo'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for playht');
|
||||
const playht_sid = result.body.sid;
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${playht_sid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential for playht');
|
||||
|
||||
/* add a credential for rimelabs */
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'rimelabs',
|
||||
use_for_stt: false,
|
||||
use_for_tts: true,
|
||||
api_key: 'asdasdasdasddsadasda',
|
||||
model_id: 'mist',
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for rimelabs');
|
||||
const rimelabs_sid = result.body.sid;
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${rimelabs_sid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential for rimelabs');
|
||||
|
||||
|
||||
/* add a credential for custom voices google */
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'google',
|
||||
use_for_stt: true,
|
||||
use_for_tts: false,
|
||||
service_key: jsonKey
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for custom voice google');
|
||||
const customvoice_google_speech_credential_sid = result.body.sid;
|
||||
|
||||
result = await request.post(`/GoogleCustomVoices`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
speech_credential_sid: customvoice_google_speech_credential_sid,
|
||||
name: "Sally",
|
||||
reported_usage: 'REALTIME',
|
||||
model: "path/to/modelId"
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added custom voice google');
|
||||
const customvoice_google_sid = result.body.sid;
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/GoogleCustomVoices/${customvoice_google_sid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted custom voice google');
|
||||
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${customvoice_google_speech_credential_sid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential for custom voice google');
|
||||
|
||||
/* add a credential for assemblyAI */
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'assemblyai',
|
||||
use_for_stt: true,
|
||||
api_key: "APIKEY"
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for assemblyai');
|
||||
const assemblyAiSid = result.body.sid;
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${assemblyAiSid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential');
|
||||
|
||||
/* add a credential for aws polly by roleArn */
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'aws',
|
||||
label: 'aws_polly_with_arn',
|
||||
use_for_tts: true,
|
||||
use_for_stt: false,
|
||||
role_arn: 'Arn::aws::role',
|
||||
aws_region: 'us-east-1'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for AWS Polly By RoleArn');
|
||||
const awsPollySid = result.body.sid;
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${awsPollySid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential');
|
||||
|
||||
/* add a credential for verbio */
|
||||
result = await request.post(`/Accounts/${account_sid}/SpeechCredentials`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
vendor: 'verbio',
|
||||
use_for_tts: true,
|
||||
use_for_stt: true,
|
||||
client_id: 'client:id',
|
||||
client_secret: 'client:secret',
|
||||
engine_version: 'V1'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully added speech credential for Verbio');
|
||||
const verbioSid = result.body.sid;
|
||||
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/${verbioSid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.engine_version === "V1", 'successfully get verbio speech credential');
|
||||
|
||||
result = await request.put(`/Accounts/${account_sid}/SpeechCredentials/${verbioSid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
auth: authUser,
|
||||
json: true,
|
||||
body: {
|
||||
use_for_tts: true,
|
||||
use_for_stt: true,
|
||||
engine_version: 'V2'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully updated speech credential for verbio');
|
||||
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/${verbioSid}`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.engine_version === "V2", 'successfully Updated verbio speech credential');
|
||||
|
||||
/* delete the credential */
|
||||
result = await request.delete(`/Accounts/${account_sid}/SpeechCredentials/${verbioSid}`, {
|
||||
auth: authUser,
|
||||
resolveWithFullResponse: true,
|
||||
});
|
||||
t.ok(result.statusCode === 204, 'successfully deleted speech credential');
|
||||
|
||||
/* Check google supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=google`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get google supported languages and voices');
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get google supported languages and voices');
|
||||
|
||||
/* Check aws supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=aws`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get aws supported languages and voices');
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get aws supported languages and voices');
|
||||
|
||||
/* Check microsoft supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=microsoft`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get microsoft supported languages and voices');
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get microsoft supported languages and voices');
|
||||
|
||||
/* Check wellsaid supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=wellsaid`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get wellsaid supported languages and voices');
|
||||
|
||||
/* Check nuance supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=nuance`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get nuance supported languages and voices');
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get nuance supported languages and voices');
|
||||
|
||||
/* Check deepgram supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=deepgram`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get deepgram supported languages and voices');
|
||||
t.ok(result.body.models.length !== 0, 'successfully get deepgram supported languages and voices');
|
||||
|
||||
/* Check ibm supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=ibm`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get ibm supported languages and voices');
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get ibm supported languages and voices');
|
||||
|
||||
/* Check ibm supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=nvidia`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get nvidia supported languages and voices');
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get nvidia supported languages and voices');
|
||||
|
||||
/* Check cobalt supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=cobalt`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get cobalt supported languages and voices');
|
||||
|
||||
/* Check soniox supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=soniox`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get soniox supported languages and voices');
|
||||
|
||||
/* Check elevenlabs supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=elevenlabs`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get elevenlabs supported languages and voices');
|
||||
t.ok(result.body.models.length !== 0, 'successfully get elevenlabs supported languages and voices');
|
||||
|
||||
/* Check assemblyai supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=assemblyai`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.stt.length !== 0, 'successfully get assemblyai supported languages and voices');
|
||||
|
||||
/* Check whisper supportedLanguagesAndVoices */
|
||||
result = await request.get(`/Accounts/${account_sid}/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=whisper`, {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.body.tts.length !== 0, 'successfully get whisper supported languages and voices');
|
||||
t.ok(result.body.models.length !== 0, 'successfully get whisper supported languages and voices');
|
||||
|
||||
await deleteObjectBySid(request, '/Accounts', account_sid);
|
||||
await deleteObjectBySid(request, '/ServiceProviders', service_provider_sid);
|
||||
t.end();
|
||||
|
||||
@@ -16,8 +16,7 @@ test('system information test', async(t) => {
|
||||
body: {
|
||||
domain_name: 'test.com',
|
||||
sip_domain_name: 'sip.test.com',
|
||||
monitoring_domain_name: 'monitor.test.com',
|
||||
private_network_cidr: '192.168.1.0/24, 10.10.100.1'
|
||||
monitoring_domain_name: 'monitor.test.com'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created system information ');
|
||||
@@ -25,7 +24,6 @@ test('system information test', async(t) => {
|
||||
t.ok(body.domain_name === 'test.com', 'added domain_name ok');
|
||||
t.ok(body.sip_domain_name === 'sip.test.com', 'added sip_domain_name ok');
|
||||
t.ok(body.monitoring_domain_name === 'monitor.test.com', 'added monitoring_domain_name ok');
|
||||
t.ok(body.private_network_cidr === '192.168.1.0/24, 10.10.100.1', 'added private_network_cidr ok');
|
||||
|
||||
result = await request.get('/SystemInformation', {
|
||||
auth: authAdmin,
|
||||
@@ -34,7 +32,6 @@ test('system information test', async(t) => {
|
||||
t.ok(result.domain_name === 'test.com', 'get domain_name ok');
|
||||
t.ok(result.sip_domain_name === 'sip.test.com', 'get sip_domain_name ok');
|
||||
t.ok(result.monitoring_domain_name === 'monitor.test.com', 'get monitoring_domain_name ok');
|
||||
t.ok(result.private_network_cidr === '192.168.1.0/24, 10.10.100.1', 'get private_network_cidr ok');
|
||||
|
||||
result = await request.post('/SystemInformation', {
|
||||
resolveWithFullResponse: true,
|
||||
@@ -43,8 +40,7 @@ test('system information test', async(t) => {
|
||||
body: {
|
||||
domain_name: 'test1.com',
|
||||
sip_domain_name: 'sip1.test.com',
|
||||
monitoring_domain_name: 'monitor1.test.com',
|
||||
private_network_cidr: ''
|
||||
monitoring_domain_name: 'monitor1.test.com'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully updated system information ');
|
||||
@@ -52,7 +48,6 @@ test('system information test', async(t) => {
|
||||
t.ok(body.domain_name === 'test1.com', 'updated domain_name ok');
|
||||
t.ok(body.sip_domain_name === 'sip1.test.com', 'updated sip_domain_name ok');
|
||||
t.ok(body.monitoring_domain_name === 'monitor1.test.com', 'updated monitoring_domain_name ok');
|
||||
t.ok(body.private_network_cidr === '', 'updated private_network_cidr ok');
|
||||
|
||||
result = await request.get('/SystemInformation', {
|
||||
auth: authAdmin,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user