Compare commits

...

45 Commits

Author SHA1 Message Date
Hoan Luu Huu
e8355a1dd3 issue 409, shoud not get Invoices in self-hosted system (#412) 2024-03-19 07:23:10 -04:00
Hoan Luu Huu
8be61ddfad remove use_stream in elevenlabs and whisper speech (#406) 2024-02-20 08:01:12 -05:00
Dave Horton
05c1d9efaa prettier fix 2024-02-12 09:03:12 -05:00
Dave Horton
01a5476dfe update github actions 2024-02-12 08:57:49 -05:00
Hoan Luu Huu
9d2fee64e6 Support deepgram onprem (#398)
* Support deepgram onprem

* wip

* wip
2024-02-12 08:52:54 -05:00
Hoan Luu Huu
3a87f5f1c2 support use_streaming elevenlabs and whisper (#396) 2024-02-12 08:16:31 -05:00
Hoan Luu Huu
a991b56a4e Fix/speech selection after updating application (#395)
* fix speech selection show app languge and voice

* wip

* wip

* wip

* wip
2024-01-27 11:26:37 -05:00
Dave Horton
6e14207327 sync with change of property name to time_to_first_byte_ms (#394) 2024-01-25 13:16:42 -05:00
Hoan Luu Huu
8d8d46e76e draw tts region label to lower possition (#393) 2024-01-24 19:48:56 -05:00
Hoan Luu Huu
7f72d739cd Fix/tts region use tts_time_to_first_byte streaming api (#391)
* tts region tts_time_to_first_byte_ms

* wip
2024-01-24 10:19:46 -05:00
Hoan Luu Huu
c804d60664 wavesurfer region use s instead of sec (#390) 2024-01-24 08:44:31 -05:00
Hoan Luu Huu
df3fc8f2b7 playback latency region on wavesurfer (#387)
* playback latency region on wavesurfer

* remove start-audio region
2024-01-22 20:31:02 -05:00
Hoan Luu Huu
65e5b511c3 gather speech verb hook latency (#383)
* gather speech verb hook latency

* wip
2024-01-17 12:37:36 -05:00
Hoan Luu Huu
dc519bdef9 fix remove speech label, cause application save wrong label (#384)
* fix remove speech label, cause application save wrong label

* fix microsoft custom_tts input
2024-01-17 09:17:25 -05:00
Hoan Luu Huu
af1ba3a15c fix app cannot set elevenlab tts (#386) 2024-01-17 07:30:36 -05:00
Hoan Luu Huu
67b7792d04 tts options should change if language is changed (#381) 2024-01-14 21:48:43 -05:00
Hoan Luu Huu
c5e7eb0d23 fix stt/tts regoin on wrong position (#380)
* fix stt/tts regoin on wrong position

* wip

* fix speech credentials does not choose default model

* fix speech credentials does not choose default model
2024-01-13 11:08:07 -05:00
Hoan Luu Huu
6ddcb82adc update jambonz cloud free plan subscription (#379) 2024-01-12 09:24:10 -05:00
Hoan Luu Huu
8b9c7ca9c0 Feat/tts stt voices languages from api server (#376)
* support fetching tts/stt language and voice from api server

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip
2024-01-12 07:34:22 -05:00
Hoan Luu Huu
353c7cfff8 update google tts language (#375) 2024-01-05 07:18:39 -05:00
Hoan Luu Huu
7828dc3827 fix default value for elevenlab optimize_streaming_latency (#374) 2024-01-03 07:21:29 -05:00
Hoan Luu Huu
213267f682 fix, change synthLange does not update synthVoice (#372) 2023-12-27 09:37:19 -05:00
Hoan Luu Huu
cf056ae6f1 fix issue that when speech has label, save application should use the first label in the list (#371) 2023-12-27 09:33:44 -05:00
Hoan Luu Huu
1c16d707ca fix deepgram tts default model and update stt languages (#370) 2023-12-26 18:48:59 -05:00
Hoan Luu Huu
2f2e58e180 support deepgram (#369)
* support deepgram

* wip
2023-12-26 07:53:13 -05:00
Hoan Luu Huu
eae674b992 fix application is blank page if choosing custom speech vendor (#361) 2023-12-06 09:06:57 -05:00
Hoan Luu Huu
aa7889a0d8 tts latency feature (#359)
* tts latency feature

* fix review comment
2023-12-05 20:33:53 -05:00
Hoan Luu Huu
a892550b06 elevenlabs new model and options (#357)
* elevenlabs new model and options

* beautify

* fix review comments
2023-11-30 10:20:35 -05:00
Hoan Luu Huu
053f8e509f update azure voices (#356) 2023-11-24 09:18:06 -05:00
Hoan Luu Huu
fc40695828 fix carrier registration status (#354) 2023-11-23 22:01:37 -05:00
Hoan Luu Huu
42af4f6243 fix elevenlabs set voice (#353) 2023-11-21 08:27:47 -06:00
Hoan Luu Huu
7ec8065977 fix lcr create update generate too much request (#351)
* fix lcr create update generate too much request

* wip
2023-11-14 08:07:29 -05:00
Dave Horton
d8f05da6fd fix regression bug: not sending aws_region (#348) 2023-11-09 16:02:42 -05:00
Dave Horton
15c2b955ca 0.8.5 2023-11-09 12:37:59 -05:00
Hoan Luu Huu
87b3ca7e94 Support whisper TTS (#346)
* support tts whisper

* support tts whisper

* wip

* wip

* fix wrong language and voice
2023-11-09 09:50:38 -05:00
Hoan Luu Huu
adafff7ec3 disable update client username/password (#345)
* disable update client username/password

* fix application stt vendor for elevenlabs
2023-11-08 12:13:08 -05:00
Dave Horton
bc9a2464fd Fine tune speech latency (#344)
* divide speech into 10ms segments when evaluating peaks for speech latency

* minor

* minor

* minor change for clarity
2023-11-07 14:40:44 -05:00
Dave Horton
2a6f8c272c assemblyai is stt only (#343) 2023-11-06 12:34:26 -05:00
Dave Horton
f031c47228 changes to enable/disable direct calling from chrome extension (#342)
* changes to enable/disable direct calling from chrome extension

* wip

* wip

* wip

---------

Co-authored-by: Quan HL <quan.luuhoang8@gmail.com>
2023-11-06 09:34:33 -05:00
Hoan Luu Huu
2e9b86c0c4 feat calculate speech recognition latency (#341)
* feat calculate speech recognition latency

* fix review comments

* wip

* wip

* wip

* wip

* wip
2023-11-06 09:31:24 -05:00
Hoan Luu Huu
dd93bedd0e Feat/assemblyai (#340)
* feat assembly ai

* feat assembly ai
2023-11-01 08:03:24 -04:00
Hoan Luu Huu
e2157ce50e feat google custom voice (#338)
* feat google custom voice

* google custom voice

* wip

* wip

* wip
2023-10-30 20:28:34 -04:00
Dave Horton
a382f21f86 #335 - allow top level fqdn for outbound gateway (#336) 2023-10-21 11:22:18 +02:00
Hoan Luu Huu
a20e1513bc remove warning message if there is no device call application (#334) 2023-10-20 13:18:01 +02:00
Hoan Luu Huu
af8c09587c fix wrong css for filter on each component (#333) 2023-10-20 08:16:00 +02:00
53 changed files with 2188 additions and 8678 deletions

View File

@@ -12,18 +12,18 @@ jobs:
pr-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Cache node_modules
id: node-cache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: node_modules
key: node-modules-${{ hashFiles('package-lock.json') }}
- name: Cache cypress binary
id: cypress-cache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: /home/runner/.cache/Cypress
key: cypress-${{ hashFiles('package-lock.json') }}

513
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "jambonz-webapp",
"version": "0.8.4",
"version": "0.8.5",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "jambonz-webapp",
"version": "0.8.4",
"version": "0.8.5",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -77,17 +77,89 @@
}
},
"node_modules/@babel/code-frame": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
"integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.22.5"
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/code-frame/node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/code-frame/node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/code-frame/node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/@babel/code-frame/node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@babel/code-frame/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/code-frame/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/compat-data": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz",
@@ -128,12 +200,12 @@
}
},
"node_modules/@babel/generator": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
"integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz",
"integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5",
"@babel/types": "^7.23.3",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -202,22 +274,22 @@
"dev": true
},
"node_modules/@babel/helper-environment-visitor": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
"integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"dependencies": {
"@babel/template": "^7.22.5",
"@babel/types": "^7.22.5"
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
@@ -287,9 +359,9 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
"integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5"
@@ -308,9 +380,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@@ -340,13 +412,13 @@
}
},
"node_modules/@babel/highlight": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
"integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.22.5",
"chalk": "^2.0.0",
"@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@@ -425,9 +497,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
"integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz",
"integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -522,33 +594,33 @@
}
},
"node_modules/@babel/template": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
"integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.22.5",
"@babel/parser": "^7.22.5",
"@babel/types": "^7.22.5"
"@babel/code-frame": "^7.22.13",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
"integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz",
"integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.22.5",
"@babel/generator": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.3",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.5",
"@babel/parser": "^7.22.5",
"@babel/types": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.3",
"@babel/types": "^7.23.3",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -566,13 +638,13 @@
}
},
"node_modules/@babel/types": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
"integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz",
"integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==",
"dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -612,9 +684,9 @@
}
},
"node_modules/@cypress/request": {
"version": "2.88.10",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz",
"integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==",
"version": "2.88.12",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz",
"integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==",
"dev": true,
"dependencies": {
"aws-sign2": "~0.7.0",
@@ -630,9 +702,9 @@
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"qs": "~6.10.3",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tough-cookie": "^4.1.3",
"tunnel-agent": "^0.6.0",
"uuid": "^8.3.2"
},
@@ -652,15 +724,6 @@
"node": ">= 0.6"
}
},
"node_modules/@cypress/request/node_modules/qs": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
"dev": true,
"engines": {
"node": ">=0.6"
}
},
"node_modules/@cypress/xvfb": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz",
@@ -2433,9 +2496,9 @@
"license": "MIT"
},
"node_modules/cypress": {
"version": "10.8.0",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-10.8.0.tgz",
"integrity": "sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA==",
"version": "10.11.0",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-10.11.0.tgz",
"integrity": "sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -5437,7 +5500,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.14",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"funding": [
{
@@ -5447,11 +5512,14 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@@ -5460,10 +5528,16 @@
}
},
"node_modules/postcss/node_modules/nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -5572,6 +5646,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"dev": true
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"dev": true,
@@ -5856,6 +5936,12 @@
"node": ">=0.10.0"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true
},
"node_modules/resolve": {
"version": "1.22.1",
"dev": true,
@@ -6018,9 +6104,10 @@
}
},
"node_modules/semver": {
"version": "6.3.0",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
@@ -6498,16 +6585,27 @@
}
},
"node_modules/tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"dev": true,
"dependencies": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
},
"engines": {
"node": ">=0.8"
"node": ">=6"
}
},
"node_modules/tough-cookie/node_modules/universalify": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"dev": true,
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/ts-node": {
@@ -6758,6 +6856,16 @@
"punycode": "^2.1.0"
}
},
"node_modules/url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dev": true,
"dependencies": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
@@ -7031,12 +7139,71 @@
}
},
"@babel/code-frame": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
"integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"requires": {
"@babel/highlight": "^7.22.5"
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"@babel/compat-data": {
@@ -7069,12 +7236,12 @@
}
},
"@babel/generator": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz",
"integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz",
"integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==",
"dev": true,
"requires": {
"@babel/types": "^7.22.5",
"@babel/types": "^7.23.3",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -7131,19 +7298,19 @@
}
},
"@babel/helper-environment-visitor": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
"integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true
},
"@babel/helper-function-name": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
"integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"requires": {
"@babel/template": "^7.22.5",
"@babel/types": "^7.22.5"
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
@@ -7194,9 +7361,9 @@
}
},
"@babel/helper-split-export-declaration": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz",
"integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==",
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"requires": {
"@babel/types": "^7.22.5"
@@ -7209,9 +7376,9 @@
"dev": true
},
"@babel/helper-validator-identifier": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
"integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true
},
"@babel/helper-validator-option": {
@@ -7232,13 +7399,13 @@
}
},
"@babel/highlight": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
"integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.22.5",
"chalk": "^2.0.0",
"@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"dependencies": {
@@ -7301,9 +7468,9 @@
}
},
"@babel/parser": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz",
"integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz",
"integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==",
"dev": true
},
"@babel/plugin-syntax-jsx": {
@@ -7354,30 +7521,30 @@
}
},
"@babel/template": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
"integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.22.5",
"@babel/parser": "^7.22.5",
"@babel/types": "^7.22.5"
"@babel/code-frame": "^7.22.13",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15"
}
},
"@babel/traverse": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz",
"integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz",
"integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.22.5",
"@babel/generator": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.5",
"@babel/helper-function-name": "^7.22.5",
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.3",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.5",
"@babel/parser": "^7.22.5",
"@babel/types": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.3",
"@babel/types": "^7.23.3",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -7391,13 +7558,13 @@
}
},
"@babel/types": {
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz",
"integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==",
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz",
"integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==",
"dev": true,
"requires": {
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
@@ -7430,9 +7597,9 @@
}
},
"@cypress/request": {
"version": "2.88.10",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz",
"integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==",
"version": "2.88.12",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz",
"integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==",
"dev": true,
"requires": {
"aws-sign2": "~0.7.0",
@@ -7448,9 +7615,9 @@
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"qs": "~6.10.3",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tough-cookie": "^4.1.3",
"tunnel-agent": "^0.6.0",
"uuid": "^8.3.2"
},
@@ -7463,12 +7630,6 @@
"requires": {
"mime-db": "1.52.0"
}
},
"qs": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
"dev": true
}
}
},
@@ -8653,9 +8814,9 @@
"devOptional": true
},
"cypress": {
"version": "10.8.0",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-10.8.0.tgz",
"integrity": "sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA==",
"version": "10.11.0",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-10.11.0.tgz",
"integrity": "sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA==",
"dev": true,
"requires": {
"@cypress/request": "^2.88.10",
@@ -10716,18 +10877,20 @@
"dev": true
},
"postcss": {
"version": "8.4.14",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"requires": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"dependencies": {
"nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
"dev": true
}
}
@@ -10799,6 +10962,12 @@
"side-channel": "^1.0.4"
}
},
"querystringify": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
"dev": true
},
"queue-microtask": {
"version": "1.2.3",
"dev": true
@@ -10973,6 +11142,12 @@
"version": "2.0.2",
"dev": true
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
"dev": true
},
"resolve": {
"version": "1.22.1",
"dev": true,
@@ -11073,7 +11248,9 @@
}
},
"semver": {
"version": "6.3.0",
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true
},
"send": {
@@ -11409,13 +11586,23 @@
"dev": true
},
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"dev": true,
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
"psl": "^1.1.33",
"punycode": "^2.1.1",
"universalify": "^0.2.0",
"url-parse": "^1.5.3"
},
"dependencies": {
"universalify": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
"dev": true
}
}
},
"ts-node": {
@@ -11575,6 +11762,16 @@
"punycode": "^2.1.0"
}
},
"url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
"dev": true,
"requires": {
"querystringify": "^2.1.1",
"requires-port": "^1.0.0"
}
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",

View File

@@ -1,7 +1,7 @@
{
"name": "jambonz-webapp",
"description": "A simple provisioning web app for jambonz",
"version": "0.8.4",
"version": "0.8.5",
"license": "MIT",
"type": "module",
"engines": {

View File

@@ -1,5 +1,6 @@
import type {
Currency,
ElevenLabsOptions,
LimitField,
LimitUnitOption,
PasswordSettings,
@@ -200,11 +201,25 @@ export const AUDIO_FORMAT_OPTIONS = [
export const DEFAULT_ELEVENLABS_MODEL = "eleven_multilingual_v2";
export const ELEVENLABS_MODEL_OPTIONS = [
{ name: "Multilingual v2", value: "eleven_multilingual_v2" },
{ name: "Multilingual v1", value: "eleven_multilingual_v1" },
{ name: "English v1", value: "eleven_monolingual_v1" },
export const DEFAULT_WHISPER_MODEL = "tts-1";
// Google Custom Voice reported usage options
export const DEFAULT_GOOGLE_CUSTOM_VOICES_REPORTED_USAGE = "REALTIME";
export const GOOGLE_CUSTOM_VOICES_REPORTED_USAGE = [
{ name: "REPORTED_USAGE_UNSPECIFIED", value: "REPORTED_USAGE_UNSPECIFIED" },
{ name: "REALTIME", value: "REALTIME" },
{ name: "OFFLINE", value: "OFFLINE" },
];
// Eleven Labs options
export const DEFAULT_ELEVENLABS_OPTIONS: Partial<ElevenLabsOptions> = {
optimize_streaming_latency: 3,
voice_settings: {
stability: 0.5,
similarity_boost: 0.5,
use_speaker_boost: true,
},
};
/** Password Length options */
export const PASSWORD_MIN = 8;
@@ -352,3 +367,4 @@ export const API_PRICE = `${API_BASE_URL}/Prices`;
export const API_SUBSCRIPTIONS = `${API_BASE_URL}/Subscriptions`;
export const API_CHANGE_PASSWORD = `${API_BASE_URL}/change-password`;
export const API_SIGNIN = `${API_BASE_URL}/signin`;
export const API_GOOGLE_CUSTOM_VOICES = `${API_BASE_URL}/GoogleCustomVoices`;

View File

@@ -33,6 +33,7 @@ import {
API_SUBSCRIPTIONS,
API_CHANGE_PASSWORD,
API_SIGNIN,
API_GOOGLE_CUSTOM_VOICES,
} from "./constants";
import { ROUTE_LOGIN } from "src/router/routes";
import {
@@ -90,10 +91,9 @@ import type {
DeleteAccount,
ChangePassword,
SignIn,
GetVoices,
LanguageOption,
VoiceOption,
GetLanguages,
GoogleCustomVoice,
GoogleCustomVoicesQuery,
SpeechSupportedLanguagesAndVoices,
} from "./types";
import { Availability, StatusCodes } from "./types";
import { JaegerRoot } from "./jaeger-types";
@@ -333,32 +333,6 @@ export const postSpeechService = (
return postFetch<SidResponse, Partial<SpeechCredential>>(apiUrl, payload);
};
export const postSpeechServiceVoices = (
sid: string,
payload: Partial<GetVoices>
) => {
const userData = parseJwt(getToken());
const apiUrl =
userData.scope === USER_ACCOUNT
? `${API_ACCOUNTS}/${userData.account_sid}/SpeechCredentials/voices`
: `${API_SERVICE_PROVIDERS}/${sid}/SpeechCredentials/voices`;
return postFetch<VoiceOption[], Partial<GetVoices>>(apiUrl, payload);
};
export const postSpeechServiceLanguages = (
sid: string,
payload: Partial<GetLanguages>
) => {
const userData = parseJwt(getToken());
const apiUrl =
userData.scope === USER_ACCOUNT
? `${API_ACCOUNTS}/${userData.account_sid}/SpeechCredentials/languages`
: `${API_SERVICE_PROVIDERS}/${sid}/SpeechCredentials/languages`;
return postFetch<LanguageOption[], Partial<GetLanguages>>(apiUrl, payload);
};
export const postMsTeamsTentant = (payload: Partial<MSTeamsTenant>) => {
return postFetch<SidResponse, Partial<MSTeamsTenant>>(
API_MS_TEAMS_TENANTS,
@@ -454,6 +428,16 @@ export const postLcr = (payload: Partial<Lcr>) => {
return postFetch<SidResponse, Partial<Lcr>>(API_LCRS, payload);
};
export const postLcrCreateRoutes = (
sid: string,
payload: Partial<LcrRoute[]>
) => {
return postFetch<EmptyResponse, Partial<LcrRoute[]>>(
`${API_LCRS}/${sid}/Routes`,
payload
);
};
export const postLcrRoute = (payload: Partial<LcrRoute>) => {
return postFetch<SidResponse, Partial<LcrRoute>>(API_LCR_ROUTES, payload);
};
@@ -501,6 +485,13 @@ export const postChangepassword = (payload: Partial<ChangePassword>) => {
export const postSignIn = (payload: Partial<SignIn>) => {
return postFetch<SignIn, Partial<SignIn>>(API_SIGNIN, payload);
};
export const postGoogleCustomVoice = (payload: Partial<GoogleCustomVoice>) => {
return postFetch<SidResponse, Partial<GoogleCustomVoice>>(
API_GOOGLE_CUSTOM_VOICES,
payload
);
};
/** Named wrappers for `putFetch` */
export const putUser = (sid: string, payload: Partial<UserUpdatePayload>) => {
@@ -597,6 +588,16 @@ export const putLcr = (sid: string, payload: Partial<Lcr>) => {
return putFetch<EmptyResponse, Partial<Lcr>>(`${API_LCRS}/${sid}`, payload);
};
export const putLcrUpdateRoutes = (
sid: string,
payload: Partial<LcrRoute[]>
) => {
return putFetch<EmptyResponse, Partial<LcrRoute[]>>(
`${API_LCRS}/${sid}/Routes`,
payload
);
};
export const putLcrRoutes = (sid: string, payload: Partial<LcrRoute>) => {
return putFetch<EmptyResponse, Partial<LcrRoute>>(
`${API_LCR_ROUTES}/${sid}`,
@@ -630,6 +631,17 @@ export const putActivationCode = (
payload
);
};
export const putGoogleCustomVoice = (
sid: string,
payload: Partial<GoogleCustomVoice>
) => {
return putFetch<EmptyResponse, Partial<GoogleCustomVoice>>(
`${API_GOOGLE_CUSTOM_VOICES}/${sid}`,
payload
);
};
/** Named wrappers for `deleteFetch` */
export const deleteUser = (sid: string) => {
@@ -719,6 +731,10 @@ export const deleteClient = (sid: string) => {
export const deleteRecord = (url: string) => {
return deleteFetch<EmptyResponse>(url);
};
export const deleteGoogleCustomVoice = (sid: string) => {
return deleteFetch<EmptyResponse>(`${API_GOOGLE_CUSTOM_VOICES}/${sid}`);
};
/** Named wrappers for `getFetch` */
export const getUser = (sid: string) => {
@@ -771,6 +787,13 @@ export const getAvailability = (domain: string) => {
);
};
export const getGoogleCustomVoices = (
query: Partial<GoogleCustomVoicesQuery>
) => {
const qryStr = getQuery<Partial<GoogleCustomVoicesQuery>>(query);
return getFetch<GoogleCustomVoice[]>(`${API_GOOGLE_CUSTOM_VOICES}?${qryStr}`);
};
/** Wrappers for APIs that can have a mock dev server response */
export const getMe = () => {
@@ -848,6 +871,22 @@ export const getPrice = () => {
return getFetch<PriceInfo[]>(API_PRICE);
};
export const getSpeechSupportedLanguagesAndVoices = (
sid: string | undefined,
vendor: string,
label: string
) => {
const userData = parseJwt(getToken());
const apiUrl =
(userData.scope === USER_ACCOUNT
? `${API_ACCOUNTS}/${userData.account_sid}`
: `${API_SERVICE_PROVIDERS}/${sid}`) +
`/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=${vendor}${
label ? `&label=${label}` : ""
}`;
return getFetch<SpeechSupportedLanguagesAndVoices>(apiUrl);
};
/** Hooks for components to fetch data with refetch method */
/** :GET /{apiPath} -- this is generic for any fetch of data collections */

View File

@@ -42,6 +42,18 @@ export interface WaveSurferSttResult {
transcript: string;
confidence: number;
language_code: string;
latency?: number;
}
export interface WaveSurferTtsLatencyResult {
vendor: string;
latency: string;
isCached: string;
}
export interface WaveSurferGatherSpeechVerbHookLatencyResult {
statusCode: number;
latency: string;
}
export interface WaveSurferDtmfResult {

View File

@@ -1,4 +1,4 @@
import type { Vendor } from "src/vendor/types";
import type { Language, Model, Vendor, VoiceLanguage } from "src/vendor/types";
/** Simple types */
@@ -262,6 +262,7 @@ export interface Account {
plan_type?: string;
device_to_call_ratio?: number;
trial_end_date?: null | string;
is_active: boolean;
}
export interface Product {
@@ -372,6 +373,14 @@ export interface RecentCall {
recording_url?: string;
}
export interface GoogleCustomVoice {
google_custom_voice_sid?: string;
speech_credential_sid?: string;
name: string;
reported_usage: string;
model: string;
}
export interface SpeechCredential {
speech_credential_sid: string;
service_provider_sid: null | string;
@@ -408,6 +417,10 @@ export interface SpeechCredential {
label: null | string;
cobalt_server_uri: null | string;
model_id: null | string;
model: null | string;
options: null | string;
deepgram_stt_uri: null | string;
deepgram_stt_use_tls: number;
}
export interface Alert {
@@ -495,7 +508,7 @@ export interface LcrRoute {
lcr_route_sid?: null | string;
lcr_sid: null | string;
regex: null | string;
desciption?: null | string;
description?: null | string;
priority: number;
lcr_carrier_set_entries?: LcrCarrierSetEntry[];
}
@@ -514,6 +527,9 @@ export interface Client {
username: null | string;
password?: null | string;
is_active: boolean;
allow_direct_app_calling: boolean;
allow_direct_queue_calling: boolean;
allow_direct_user_calling: boolean;
}
export interface PageQuery {
@@ -528,6 +544,13 @@ export interface CallQuery extends PageQuery {
answered?: string;
}
export interface GoogleCustomVoicesQuery {
speech_credential_sid?: string;
label?: string;
account_sid?: string;
service_provider_sid: string;
}
export interface PagedResponse<Type> {
page_size: number;
total: number;
@@ -677,19 +700,23 @@ export interface SignIn {
account_sid?: null | string;
}
export interface GetVoices {
export interface GetLanguagesAndVoices {
vendor: string;
label: string;
}
export interface VoiceOption extends SelectorOptions {
[key: string]: unknown;
export interface SpeechSupportedLanguagesAndVoices {
tts: VoiceLanguage[];
stt: Language[];
models: Model[];
}
export interface GetLanguages extends GetVoices {
[key: string]: unknown;
}
export interface LanguageOption extends SelectorOptions {
[key: string]: unknown;
export interface ElevenLabsOptions {
optimize_streaming_latency: number;
voice_settings: Partial<{
similarity_boost: number;
stability: number;
style: number;
use_speaker_boost: boolean;
}>;
}

View File

@@ -11,6 +11,7 @@ type CheckzoneProps = {
hidden?: boolean;
children: React.ReactNode;
initialCheck: boolean;
disabled?: boolean;
handleChecked?: (e: React.ChangeEvent<HTMLInputElement>) => void;
};
@@ -28,6 +29,7 @@ export const Checkzone = forwardRef<CheckzoneRef, CheckzoneProps>(
children,
initialCheck,
handleChecked,
disabled = false,
}: CheckzoneProps,
ref
) => {
@@ -51,6 +53,7 @@ export const Checkzone = forwardRef<CheckzoneRef, CheckzoneProps>(
<label>
<div className="label-container">
<input
disabled={disabled}
ref={ref}
type="checkbox"
name={name}

View File

@@ -24,4 +24,3 @@ export const MSG_WEBHOOK_FIELDS = (
<span>password</span> fields are required.
</>
);
export const NOT_AVAILABLE_PREFIX = "NotAvalable";

View File

@@ -40,6 +40,7 @@ import {
PlanType,
USER_ACCOUNT,
WEBHOOK_METHODS,
STRIPE_PUBLISHABLE_KEY,
} from "src/api/constants";
import { MSG_REQUIRED_FIELDS, MSG_WEBHOOK_FIELDS } from "src/constants";
@@ -85,7 +86,10 @@ export const AccountForm = ({
const user = useSelectState("user");
const currentServiceProvider = useSelectState("currentServiceProvider");
const [accounts] = useApiData<Account[]>("Accounts");
const [invoice] = useApiData<Invoice>("Invoices");
// Dont get Invoices if the environment is self-hosted
const [invoice] = STRIPE_PUBLISHABLE_KEY
? useApiData<Invoice>("Invoices")
: [undefined];
const [userData] = useApiData<CurrentUserData>("Users/me");
const [userCarriers] = useApiData<Carrier[]>(`VoipCarriers`);
const [userSpeechs] = useApiData<SpeechCredential[]>(
@@ -579,7 +583,7 @@ export const AccountForm = ({
(userData.account.device_to_call_ratio || 0) *
(callSessionRecord.quantity || 0) +
(registeredDeviceRecord.quantity || 0);
const { trial_end_date } = userData.account || {};
const { trial_end_date, is_active } = userData.account || {};
switch (pType) {
case PlanType.TRIAL:
setSubscriptionDescription(
@@ -609,9 +613,15 @@ export const AccountForm = ({
break;
case PlanType.FREE:
setSubscriptionDescription(
`You are currently on the Free plan (trial period expired). You are limited to ${callSessionRecord.quantity} simultaneous calls and ${quantity} registered devices`
);
if (is_active) {
setSubscriptionDescription(
`You are currently on the Free plan (trial period expired). You are limited to ${callSessionRecord.quantity} simultaneous calls and ${quantity} registered devices`
);
} else {
setSubscriptionDescription(
"Your free trial has expired. Please upgrade your subscription to a paid plan to continue service"
);
}
break;
}
// Make sure Account page is alway scroll to top to see subscription
@@ -693,7 +703,9 @@ export const AccountForm = ({
{isDeleteAccount && (
<Section slim>
<form
className="form form--internal"
className={`form form--internal ${
!account?.data && account?.refetch ? "form--blur" : ""
}`}
onSubmit={handleDeleteAccount}
>
<fieldset>

View File

@@ -71,7 +71,7 @@ export const Accounts = () => {
</Icon>
</Link>
</section>
<section className="filters filters--spaced">
<section className="filters filters--multi">
<SearchFilter
placeholder="Filter accounts"
filter={[filter, setFilter]}

View File

@@ -16,7 +16,6 @@ import {
LANG_EN_US,
VENDOR_GOOGLE,
LANG_EN_US_STANDARD_C,
useSpeechVendors,
VENDOR_CUSTOM,
} from "src/vendor";
import {
@@ -61,8 +60,8 @@ type ApplicationFormProps = {
export const ApplicationForm = ({ application }: ApplicationFormProps) => {
const navigate = useNavigate();
const { synthesis, recognizers } = useSpeechVendors();
const user = useSelectState("user");
const currentServiceProvider = useSelectState("currentServiceProvider");
const [accounts] = useServiceProviderData<Account[]>("Accounts");
const [applications] = useApiData<Application[]>("Applications");
const [applicationName, setApplicationName] = useState("");
@@ -387,6 +386,53 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
}
}, [accountSid]);
useEffect(() => {
let label: string;
// Synthesis Label
label = application?.data?.speech_synthesis_label || "";
if (ttsLabelOptions && !ttsLabelOptions.find((l) => l.value === label)) {
label = ttsLabelOptions.length ? ttsLabelOptions[0].value : "";
}
setSynthLabel(label);
// fallback Synthesis Label
label = application?.data?.fallback_speech_synthesis_label || "";
if (
fallbackTtsLabelOptions &&
!fallbackTtsLabelOptions.find((l) => l.value === label)
) {
label = fallbackTtsLabelOptions.length
? fallbackTtsLabelOptions[0].value
: "";
}
setFallbackSpeechSynthsisLabel(label);
// regconizer label
label = application?.data?.speech_recognizer_label || "";
if (sttLabelOptions && !sttLabelOptions.find((l) => l.value === label)) {
label = sttLabelOptions.length ? sttLabelOptions[0].value : "";
}
setRecogLabel(label);
// fallback regconizer label
label = application?.data?.fallback_speech_recognizer_label || "";
if (
fallbackSttLabelOptions &&
!fallbackSttLabelOptions.find((l) => l.value === label)
) {
label = fallbackSttLabelOptions.length
? fallbackSttLabelOptions[0].value
: "";
}
setFallbackSpeechRecognizerLabel(label);
}, [
ttsLabelOptions,
sttLabelOptions,
fallbackTtsLabelOptions,
fallbackSttLabelOptions,
application,
]);
useEffect(() => {
setLocation();
if (application && application.data) {
@@ -463,12 +509,7 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
if (application.data.speech_recognizer_language)
setRecogLang(application.data.speech_recognizer_language);
if (application.data.speech_synthesis_label) {
setSynthLabel(application.data.speech_synthesis_label);
}
if (application.data.speech_recognizer_label) {
setRecogLabel(application.data.speech_recognizer_label);
}
if (application.data.use_for_fallback_speech) {
setUseForFallbackSpeech(application.data.use_for_fallback_speech > 0);
setInitalCheckFallbackSpeech(
@@ -486,11 +527,7 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
application.data.fallback_speech_recognizer_language
);
}
if (application.data.fallback_speech_recognizer_label) {
setFallbackSpeechRecognizerLabel(
application.data.fallback_speech_recognizer_label
);
}
if (application.data.fallback_speech_synthesis_vendor) {
setFallbackSpeechSynthsisVendor(
application.data
@@ -507,11 +544,6 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
application.data.fallback_speech_synthesis_voice
);
}
if (application.data.fallback_speech_synthesis_label) {
setFallbackSpeechSynthsisLabel(
application.data.fallback_speech_synthesis_label
);
}
}
}, [application]);
@@ -549,7 +581,12 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
return (
<Section slim>
<form className="form form--internal" onSubmit={handleSubmit}>
<form
className={`form form--internal ${
!application?.data && application?.refetch ? "form--blur" : ""
}`}
onSubmit={handleSubmit}
>
<fieldset>
<MS>{MSG_REQUIRED_FIELDS}</MS>
</fieldset>
@@ -674,15 +711,17 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
);
})}
<SpeechProviderSelection
serviceProviderSid={
currentServiceProvider?.service_provider_sid || ""
}
accountSid={accountSid}
credentials={credentials}
synthesis={synthesis}
ttsVendor={[synthVendor, setSynthVendor]}
ttsVendorOptions={ttsVendorOptions}
ttsVoice={[synthVoice, setSynthVoice]}
ttsLang={[synthLang, setSynthLang]}
ttsLabelOptions={ttsLabelOptions}
ttsLabel={[synthLabel, setSynthLabel]}
recognizers={recognizers}
sttVendor={[recogVendor, setRecogVendor]}
sttVendorOptions={sttVendorOptions}
sttLang={[recogLang, setRecogLang]}
@@ -701,8 +740,11 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
}}
>
<SpeechProviderSelection
serviceProviderSid={
currentServiceProvider?.service_provider_sid || ""
}
accountSid={accountSid}
credentials={credentials}
synthesis={synthesis}
ttsVendor={[
fallbackSpeechSynthsisVendor,
setFallbackSpeechSynthsisVendor,
@@ -721,7 +763,6 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
fallbackSpeechSynthsisLabel,
setFallbackSpeechSynthsisLabel,
]}
recognizers={recognizers}
sttVendor={[
fallbackSpeechRecognizerVendor,
setFallbackSpeechRecognizerVendor,

View File

@@ -96,7 +96,7 @@ export const Applications = () => {
</Link>
)}
</section>
<section className="filters filters--spaced">
<section className="filters filters--multi">
<SearchFilter
placeholder="Filter applications"
filter={[filter, setFilter]}

View File

@@ -1,9 +1,16 @@
import React, { useEffect, useState } from "react";
import { postSpeechServiceLanguages, postSpeechServiceVoices } from "src/api";
import { SpeechCredential } from "src/api/types";
import React, { useEffect, useRef, useState } from "react";
import {
getGoogleCustomVoices,
getSpeechSupportedLanguagesAndVoices,
} from "src/api";
import { USER_ADMIN } from "src/api/constants";
import {
SpeechCredential,
SpeechSupportedLanguagesAndVoices,
} from "src/api/types";
import { Selector } from "src/components/forms";
import { SelectorOption } from "src/components/forms/selector";
import { useSelectState } from "src/store";
import { toastError, useSelectState } from "src/store";
import { hasLength } from "src/utils";
import {
ELEVENLABS_LANG_EN,
@@ -14,24 +21,24 @@ import {
VENDOR_COBALT,
VENDOR_CUSTOM,
VENDOR_DEEPGRAM,
VENDOR_ASSEMBLYAI,
VENDOR_ELEVENLABS,
VENDOR_GOOGLE,
VENDOR_MICROSOFT,
VENDOR_SONIOX,
VENDOR_WELLSAID,
VENDOR_WHISPER,
} from "src/vendor";
import {
LabelOptions,
Language,
RecognizerVendors,
SynthesisVendors,
VendorOptions,
Voice,
VoiceLanguage,
} from "src/vendor/types";
type SpeechProviderSelectionProbs = {
accountSid: string;
serviceProviderSid: string;
credentials: SpeechCredential[] | undefined;
synthesis: SynthesisVendors | undefined;
ttsVendor: [
keyof SynthesisVendors,
React.Dispatch<React.SetStateAction<keyof SynthesisVendors>>
@@ -41,7 +48,6 @@ type SpeechProviderSelectionProbs = {
ttsLang: [string, React.Dispatch<React.SetStateAction<string>>];
ttsLabelOptions: LabelOptions[];
ttsLabel: [string, React.Dispatch<React.SetStateAction<string>>];
recognizers: RecognizerVendors | undefined;
sttVendor: [
keyof RecognizerVendors,
React.Dispatch<React.SetStateAction<keyof RecognizerVendors>>
@@ -53,21 +59,26 @@ type SpeechProviderSelectionProbs = {
};
export const SpeechProviderSelection = ({
accountSid,
serviceProviderSid,
credentials,
synthesis,
ttsVendor: [synthVendor, setSynthVendor],
ttsVendorOptions,
ttsVoice: [synthVoice, setSynthVoice],
ttsLang: [synthLang, setSynthLang],
ttsLabelOptions,
ttsLabel: [synthLabel, setSynthLabel],
recognizers,
sttVendor: [recogVendor, setRecogVendor],
sttVendorOptions,
sttLang: [recogLang, setRecogLang],
sttLabelOptions,
sttLabel: [recogLabel, setRecogLabel],
}: SpeechProviderSelectionProbs) => {
const user = useSelectState("user");
const [
synthesisSupportedLanguagesAndVoices,
setSynthesisSupportedLanguagesAndVoices,
] = useState<SpeechSupportedLanguagesAndVoices | null>();
const [selectedCredential, setSelectedCredential] = useState<
SpeechCredential | undefined
>();
@@ -77,333 +88,488 @@ export const SpeechProviderSelection = ({
const [synthesisLanguageOptions, setSynthesisLanguageOptions] = useState<
SelectorOption[]
>([]);
const [synthesisModelOptions, setSynthesisModelOptions] = useState<
SelectorOption[]
>([]);
const [
synthesisGoogleCustomVoiceOptions,
setSynthesisGoogleCustomVoiceOptions,
] = useState<SelectorOption[]>([]);
const [recogLanguageOptions, setRecogLanguageOptions] = useState<
SelectorOption[]
>([]);
const currentServiceProvider = useSelectState("currentServiceProvider");
const currentTtsVendor = useRef(synthVendor);
const currentSttVendor = useRef(recogVendor);
const shouldUpdateTtsVoice = useRef(false);
const shouldUpdateSttLanguage = useRef(false);
const ttsEffectTimer = useRef<number | null>(null);
const sttEffectTimer = useRef<number | null>(null);
// Get Synthesis languages and voices
useEffect(() => {
if (!synthesis) {
if (
!user ||
!synthVendor ||
(user?.scope === USER_ADMIN && !serviceProviderSid)
) {
return;
}
let options = synthesis[synthVendor as keyof SynthesisVendors]
.filter((lang: VoiceLanguage) => {
// ELEVENLABS has same voice for all lange, take voices from the 1st language
if (synthVendor === VENDOR_ELEVENLABS) {
return true;
}
return lang.code === synthLang;
})
.flatMap((lang: VoiceLanguage) =>
lang.voices.map((voice: Voice) => ({
name: voice.name,
value: voice.value,
}))
) as Voice[];
setSynthesisVoiceOptions(options);
options = synthesis[synthVendor as keyof SynthesisVendors].map(
(lang: VoiceLanguage) => ({
name: lang.name,
value: lang.code,
})
);
setSynthesisLanguageOptions(options);
if (synthVendor === VENDOR_ELEVENLABS) {
postSpeechServiceVoices(
currentServiceProvider
? currentServiceProvider.service_provider_sid
: "",
{
vendor: synthVendor,
label: synthLabel,
}
).then(({ json }) => {
if (json.length > 0) {
setSynthesisVoiceOptions(json);
}
});
postSpeechServiceLanguages(
currentServiceProvider
? currentServiceProvider.service_provider_sid
: "",
{
vendor: synthVendor,
label: synthLabel,
}
).then(({ json }) => {
if (json.length > 0) {
setSynthesisLanguageOptions(json);
}
});
currentTtsVendor.current = synthVendor;
/** When Custom Vendor is used, user you have to input the lange and voice. */
if (synthVendor.toString().startsWith(VENDOR_CUSTOM)) {
setSynthVoice("");
return;
}
}, [synthVendor, synthesis, synthLabel]);
// just execute last change
if (ttsEffectTimer.current) {
clearTimeout(ttsEffectTimer.current);
}
ttsEffectTimer.current = setTimeout(() => {
configSynthesis();
}, 200);
}, [synthVendor, synthLabel, serviceProviderSid]);
// Get Recognizer languages and voices
useEffect(() => {
/** When Custom Vendor is used, user you have to input the lange and voice. */
if (recogVendor.toString().startsWith(VENDOR_CUSTOM)) {
setRecogLang(LANG_EN_US);
return;
}
if (
!user ||
!recogVendor ||
(user?.scope === USER_ADMIN && !serviceProviderSid)
) {
return;
}
currentSttVendor.current = recogVendor;
// just execute last change
if (sttEffectTimer.current) {
clearTimeout(sttEffectTimer.current);
}
sttEffectTimer.current = setTimeout(() => {
configRecognizer();
}, 200);
}, [recogVendor, recogLabel, serviceProviderSid]);
useEffect(() => {
if (credentials) {
setSelectedCredential(
credentials.find(
(c) => c.vendor === synthVendor && c.label === synthLabel
(c) => c.vendor === synthVendor && (c.label || "") === synthLabel
)
);
}
}, [synthVendor, synthLabel, credentials]);
useEffect(() => {
if (!synthLabel && ttsLabelOptions?.length > 0) {
setSynthLabel(ttsLabelOptions[0].value);
}
if (!recogLabel && sttLabelOptions?.length > 0) {
setRecogLabel(sttLabelOptions[0].value);
}
}, [ttsLabelOptions, sttLabelOptions]);
useEffect(() => {
if (synthesisSupportedLanguagesAndVoices) {
// Extract Voice
const voicesOpts =
synthesisSupportedLanguagesAndVoices.tts?.find((lang) => {
if (synthVendor === VENDOR_ELEVENLABS && lang.voices.length > 0) {
return true;
}
return lang.value === synthLang;
})?.voices || [];
if (synthVendor === VENDOR_GOOGLE && synthesisGoogleCustomVoiceOptions) {
if (synthesisGoogleCustomVoiceOptions) {
setSynthesisVoiceOptions([
...synthesisGoogleCustomVoiceOptions,
...voicesOpts,
]);
} else {
setSynthesisVoiceOptions(voicesOpts);
}
if (synthesisGoogleCustomVoiceOptions.length > 0) {
updateTtsVoice(synthesisGoogleCustomVoiceOptions[0].value);
}
} else {
setSynthesisVoiceOptions(voicesOpts);
}
}
}, [
synthLang,
synthesisSupportedLanguagesAndVoices,
synthesisGoogleCustomVoiceOptions,
]);
const configSynthesis = () => {
getSpeechSupportedLanguagesAndVoices(
serviceProviderSid,
synthVendor,
synthLabel
)
.then(({ json }) => {
// while fetching data, user might change the vendor
if (currentTtsVendor.current !== synthVendor) {
return;
}
setSynthesisSupportedLanguagesAndVoices(json);
// Extract model
if (json.models && json.models.length) {
setSynthesisModelOptions(json.models);
if (synthVendor === VENDOR_DEEPGRAM) {
setSynthVoice(json.models[0].value);
return;
}
}
if (json.tts && json.tts.length) {
// Extract Language
const langOpts = json.tts.map((lang) => ({
name: lang.name,
value: lang.value,
}));
setSynthesisLanguageOptions(langOpts);
// Default setting
const googleLang = json.tts.find((lang) => lang.value === synthLang);
if (
synthVendor === VENDOR_GOOGLE &&
(!googleLang ||
!googleLang.voices.find((v) => v.value === synthVoice))
) {
setSynthLang(LANG_EN_US);
updateTtsVoice(LANG_EN_US_STANDARD_C);
return;
}
if (synthVendor === VENDOR_ELEVENLABS) {
// Samve Voices applied to all languages
// Voices are only available for the 1st language.
setSynthLang(ELEVENLABS_LANG_EN);
updateTtsVoice(json.tts[0].voices[0].value);
return;
}
if (synthVendor === VENDOR_WHISPER) {
const newLang = json.tts.find((lang) => lang.value === LANG_EN_US);
setSynthLang(LANG_EN_US);
updateTtsVoice(newLang!.voices[0].value);
return;
}
/** Google and AWS have different language lists */
/** If the new language doesn't map then default to "en-US" */
let newLang = json.tts.find((lang) => lang.value === synthLang);
if (newLang) {
updateTtsVoice(newLang.voices[0].value);
return;
}
newLang = json.tts.find((lang) => lang.value === LANG_EN_US);
setSynthLang(LANG_EN_US);
updateTtsVoice(newLang!.voices[0].value);
}
})
.catch((error) => {
toastError(error.msg);
});
if (synthVendor === VENDOR_GOOGLE) {
getGoogleCustomVoices({
...(synthLabel && { label: synthLabel }),
account_sid: accountSid,
service_provider_sid: serviceProviderSid,
}).then(({ json }) => {
// If after successfully fetching data, vendor is still good, then apply value
if (currentTtsVendor.current !== VENDOR_GOOGLE) {
return;
}
const customVOices = json.map((v) => ({
name: `${v.name} (Custom)`,
value: `custom_${v.google_custom_voice_sid}`,
}));
setSynthesisGoogleCustomVoiceOptions(customVOices);
});
}
};
const updateTtsVoice = (value: string) => {
if (shouldUpdateTtsVoice.current) {
setSynthVoice(value);
shouldUpdateTtsVoice.current = false;
}
};
const configRecognizer = () => {
getSpeechSupportedLanguagesAndVoices(
serviceProviderSid,
recogVendor,
recogLabel
)
.then(({ json }) => {
// while fetching data, the user might change the vendor
if (currentSttVendor.current !== recogVendor) {
return;
}
// Extract Language
const langOpts = json.stt.map((lang) => ({
name: lang.name,
value: lang.value,
}));
setRecogLanguageOptions(langOpts);
/**When vendor is custom, Language is input by user */
if (
recogVendor.toString() === VENDOR_CUSTOM ||
!shouldUpdateSttLanguage.current
)
return;
shouldUpdateSttLanguage.current = false;
/** Google and AWS have different language lists */
/** If the new language doesn't map then default to "en-US" */
const newLang = json.stt.find((lang) => lang.value === recogLang);
if (
(recogVendor === VENDOR_GOOGLE || recogVendor === VENDOR_AWS) &&
!newLang
) {
setRecogLang(LANG_EN_US);
} else if (recogVendor === VENDOR_COBALT && !newLang) {
setRecogLang(LANG_COBALT_EN_US);
} else if (langOpts.length && !newLang) {
setRecogLang(langOpts[0].value);
}
})
.catch((error) => {
toastError(error.msg);
});
};
return (
<>
{synthesis && (
<fieldset>
<label htmlFor="synthesis_vendor">Speech synthesis vendor</label>
<Selector
id="synthesis_vendor"
name="synthesis_vendor"
value={synthVendor}
options={ttsVendorOptions.filter(
(vendor) =>
vendor.value != VENDOR_DEEPGRAM &&
vendor.value != VENDOR_SONIOX &&
vendor.value !== VENDOR_CUSTOM &&
vendor.value !== VENDOR_COBALT
)}
onChange={(e) => {
const vendor = e.target.value as keyof SynthesisVendors;
setSynthVendor(vendor);
setSynthLabel("");
/** When Custom Vendor is used, user you have to input the lange and voice. */
if (vendor.toString().startsWith(VENDOR_CUSTOM)) {
setSynthVoice("");
return;
}
/** When using Google and en-US, ensure "Standard-C" is used as default */
if (
e.target.value === VENDOR_GOOGLE &&
synthLang === LANG_EN_US
) {
setSynthVoice(LANG_EN_US_STANDARD_C);
return;
}
if (vendor === VENDOR_ELEVENLABS) {
const newLang = synthesis[vendor].find(
(lang) => lang.code === ELEVENLABS_LANG_EN
);
setSynthLang(ELEVENLABS_LANG_EN);
setSynthVoice(newLang!.voices[0].value);
return;
}
/** Google and AWS have different language lists */
/** If the new language doesn't map then default to "en-US" */
let newLang = synthesis[vendor].find(
(lang) => lang.code === synthLang
);
if (newLang) {
setSynthVoice(newLang.voices[0].value);
return;
}
newLang = synthesis[vendor].find(
(lang) => lang.code === LANG_EN_US
);
setSynthLang(LANG_EN_US);
setSynthVoice(newLang!.voices[0].value);
}}
/>
{hasLength(ttsLabelOptions) && ttsLabelOptions.length > 1 && (
<>
<label htmlFor="synthesis_label">Label</label>
<Selector
id="systhesis_label"
name="systhesis_label"
value={synthLabel}
options={ttsLabelOptions}
onChange={(e) => {
setSynthLabel(e.target.value);
}}
/>
</>
<fieldset>
<label htmlFor="synthesis_vendor">Speech synthesis vendor</label>
<Selector
id="synthesis_vendor"
name="synthesis_vendor"
value={synthVendor}
options={ttsVendorOptions.filter(
(vendor) =>
vendor.value != VENDOR_ASSEMBLYAI &&
vendor.value != VENDOR_SONIOX &&
vendor.value !== VENDOR_CUSTOM &&
vendor.value !== VENDOR_COBALT
)}
{synthVendor &&
!synthVendor.toString().startsWith(VENDOR_CUSTOM) &&
synthLang && (
<>
<label htmlFor="synthesis_lang">Language</label>
<Selector
id="synthesis_lang"
name="synthesis_lang"
value={synthLang}
options={synthesisLanguageOptions}
onChange={(e) => {
const language = e.target.value;
setSynthLang(language);
/** When using Google and en-US, ensure "Standard-C" is used as default */
if (
synthVendor === VENDOR_GOOGLE &&
language === LANG_EN_US
) {
setSynthVoice(LANG_EN_US_STANDARD_C);
return;
}
const newLang = synthesis[
synthVendor as keyof SynthesisVendors
].find((lang) => lang.code === language);
setSynthVoice(newLang!.voices[0].value);
}}
/>
<label htmlFor="synthesis_voice">Voice</label>
{synthVendor === VENDOR_MICROSOFT &&
selectedCredential &&
selectedCredential.use_custom_tts ? (
<input
id="custom_microsoft_synthesis_voice"
type="text"
name="custom_microsoft_synthesis_voice"
placeholder="Required"
required
value={synthVoice}
onChange={(e) => {
setSynthVoice(e.target.value);
}}
/>
) : (
<Selector
id="synthesis_voice"
name="synthesis_voice"
value={synthVoice}
options={synthesisVoiceOptions}
onChange={(e) => setSynthVoice(e.target.value)}
/>
)}
</>
)}
{synthVendor.toString().startsWith(VENDOR_CUSTOM) && (
onChange={(e) => {
const vendor = e.target.value as keyof SynthesisVendors;
shouldUpdateTtsVoice.current = true;
setSynthVendor(vendor);
setSynthLabel("");
setSynthesisLanguageOptions([]);
setSynthesisVoiceOptions([]);
}}
/>
{hasLength(ttsLabelOptions) && (
<>
<label htmlFor="synthesis_label">Label</label>
<Selector
id="systhesis_label"
name="systhesis_label"
value={synthLabel}
options={ttsLabelOptions}
onChange={(e) => {
setSynthLabel(e.target.value);
}}
/>
</>
)}
{synthesisModelOptions && synthVendor === VENDOR_DEEPGRAM && (
<>
<label htmlFor="synthesis_lang">Model</label>
<Selector
id="synthesis_voice"
name="synthesis_voice"
value={synthVoice}
options={synthesisModelOptions}
onChange={(e) => setSynthVoice(e.target.value)}
/>
</>
)}
{synthVendor &&
!synthVendor.toString().startsWith(VENDOR_CUSTOM) &&
synthVendor !== VENDOR_DEEPGRAM &&
synthLang && (
<>
<label htmlFor="custom_vendor_synthesis_lang">Language</label>
<input
id="custom_vendor_synthesis_lang"
type="text"
name="custom_vendor_synthesis_lang"
placeholder="Required"
required
<label htmlFor="synthesis_lang">Language</label>
<Selector
id="synthesis_lang"
name="synthesis_lang"
value={synthLang}
options={synthesisLanguageOptions}
onChange={(e) => {
setSynthLang(e.target.value);
shouldUpdateTtsVoice.current = true;
const language = e.target.value;
setSynthLang(language);
/** When using Google and en-US, ensure "Standard-C" is used as default */
if (
synthVendor === VENDOR_GOOGLE &&
language === LANG_EN_US
) {
setSynthVoice(LANG_EN_US_STANDARD_C);
return;
}
const voices =
synthesisSupportedLanguagesAndVoices?.tts.find(
(lang) => lang.value === language
)?.voices || [];
if (
synthVendor === VENDOR_GOOGLE &&
synthesisGoogleCustomVoiceOptions &&
synthesisGoogleCustomVoiceOptions.length
) {
setSynthesisVoiceOptions([
...synthesisGoogleCustomVoiceOptions,
...voices,
]);
} else {
setSynthesisVoiceOptions(voices);
}
setSynthVoice(voices[0].value);
}}
/>
<label htmlFor="custom_vendor_synthesis_voice">Voice</label>
<input
id="custom_vendor_synthesis_voice"
type="text"
name="custom_vendor_synthesis_voice"
placeholder="Required"
required
value={synthVoice}
onChange={(e) => {
setSynthVoice(e.target.value);
}}
/>
</>
)}
</fieldset>
)}
{recognizers && (
<fieldset>
<label htmlFor="recognizer_vendor">Speech recognizer vendor</label>
<Selector
id="recognizer_vendor"
name="recognizer_vendor"
value={recogVendor}
options={sttVendorOptions.filter(
(vendor) =>
vendor.value != VENDOR_WELLSAID &&
vendor.value !== VENDOR_CUSTOM
)}
onChange={(e) => {
const vendor = e.target.value as keyof RecognizerVendors;
setRecogVendor(vendor);
setRecogLabel("");
/**When vendor is custom, Language is input by user */
if (vendor.toString() === VENDOR_CUSTOM) return;
/** Google and AWS have different language lists */
/** If the new language doesn't map then default to "en-US" */
const newLang = recognizers[vendor].find(
(lang: Language) => lang.code === recogLang
);
if (
(vendor === VENDOR_GOOGLE || vendor === VENDOR_AWS) &&
!newLang
) {
setRecogLang(LANG_EN_US);
}
// Default colbalt language
if (vendor === VENDOR_COBALT) {
setRecogLang(LANG_COBALT_EN_US);
}
}}
/>
{hasLength(sttLabelOptions) && sttLabelOptions.length > 1 && (
<>
<label htmlFor="recog_label">Label</label>
<Selector
id="recog_label"
name="recog_label"
value={recogLabel}
options={sttLabelOptions}
onChange={(e) => {
setRecogLabel(e.target.value);
}}
/>
</>
)}
{recogVendor &&
!recogVendor.toString().startsWith(VENDOR_CUSTOM) &&
recogLang && (
<>
<label htmlFor="recognizer_lang">Language</label>
<Selector
id="recognizer_lang"
name="recognizer_lang"
value={recogLang}
options={recognizers[
recogVendor as keyof RecognizerVendors
].map((lang: Language) => ({
name: lang.name,
value: lang.code,
}))}
<label htmlFor="synthesis_voice">Voice</label>
{synthVendor === VENDOR_MICROSOFT &&
selectedCredential &&
selectedCredential.use_custom_tts ? (
<input
id="custom_microsoft_synthesis_voice"
type="text"
name="custom_microsoft_synthesis_voice"
placeholder="Required"
required
value={synthVoice}
onChange={(e) => {
setRecogLang(e.target.value);
setSynthVoice(e.target.value);
}}
/>
</>
)}
{recogVendor.toString().startsWith(VENDOR_CUSTOM) && (
) : (
<Selector
id="synthesis_voice"
name="synthesis_voice"
value={synthVoice}
options={synthesisVoiceOptions}
onChange={(e) => setSynthVoice(e.target.value)}
/>
)}
</>
)}
{synthVendor.toString().startsWith(VENDOR_CUSTOM) && (
<>
<label htmlFor="custom_vendor_synthesis_lang">Language</label>
<input
id="custom_vendor_synthesis_lang"
type="text"
name="custom_vendor_synthesis_lang"
placeholder="Required"
required
value={synthLang}
onChange={(e) => {
setSynthLang(e.target.value);
}}
/>
<label htmlFor="custom_vendor_synthesis_voice">Voice</label>
<input
id="custom_vendor_synthesis_voice"
type="text"
name="custom_vendor_synthesis_voice"
placeholder="Required"
required
value={synthVoice}
onChange={(e) => {
setSynthVoice(e.target.value);
}}
/>
</>
)}
</fieldset>
<fieldset>
<label htmlFor="recognizer_vendor">Speech recognizer vendor</label>
<Selector
id="recognizer_vendor"
name="recognizer_vendor"
value={recogVendor}
options={sttVendorOptions.filter(
(vendor) =>
vendor.value != VENDOR_WELLSAID &&
vendor.value != VENDOR_ELEVENLABS &&
vendor.value != VENDOR_WHISPER &&
vendor.value !== VENDOR_CUSTOM
)}
onChange={(e) => {
const vendor = e.target.value as keyof RecognizerVendors;
shouldUpdateSttLanguage.current = true;
setRecogVendor(vendor);
setRecogLabel("");
setRecogLanguageOptions([]);
}}
/>
{hasLength(sttLabelOptions) && (
<>
<label htmlFor="recog_label">Label</label>
<Selector
id="recog_label"
name="recog_label"
value={recogLabel}
options={sttLabelOptions}
onChange={(e) => {
setRecogLabel(e.target.value);
}}
/>
</>
)}
{recogVendor &&
!recogVendor.toString().startsWith(VENDOR_CUSTOM) &&
recogLang && (
<>
<label htmlFor="custom_vendor_recognizer_voice">Language</label>
<input
id="custom_vendor_recognizer_voice"
type="text"
name="custom_vendor_recognizer_voice"
placeholder="Required"
required
<label htmlFor="recognizer_lang">Language</label>
<Selector
id="recognizer_lang"
name="recognizer_lang"
value={recogLang}
options={recogLanguageOptions}
onChange={(e) => {
setRecogLang(e.target.value);
}}
/>
</>
)}
</fieldset>
)}
{recogVendor.toString().startsWith(VENDOR_CUSTOM) && (
<>
<label htmlFor="custom_vendor_recognizer_voice">Language</label>
<input
id="custom_vendor_recognizer_voice"
type="text"
name="custom_vendor_recognizer_voice"
placeholder="Required"
required
value={recogLang}
onChange={(e) => {
setRecogLang(e.target.value);
}}
/>
</>
)}
</fieldset>
</>
);
};

View File

@@ -336,10 +336,13 @@ export const CarrierForm = ({
const gateway = sipGateways[i];
const type = getIpValidationType(gateway.ipv4);
/** DH: unclear why we had this restriction, removing for now
if (type === FQDN_TOP_LEVEL) {
refSipIp.current[i].focus();
return "When using an FQDN, you must use a subdomain (e.g. sip.example.com).";
} else if (type === FQDN && (!gateway.outbound || gateway.inbound)) {
*/
if (type === FQDN && (!gateway.outbound || gateway.inbound)) {
refSipIp.current[i].focus();
return "A fully qualified domain name may only be used for outbound calls.";
} else if (type === INVALID) {
@@ -636,7 +639,12 @@ export const CarrierForm = ({
return (
<Section slim>
<form className="form form--internal" onSubmit={handleSubmit}>
<form
className={`form form--internal ${
!carrier?.data && carrier?.refetch ? "form--blur" : ""
}`}
onSubmit={handleSubmit}
>
<fieldset>
<MS>{MSG_REQUIRED_FIELDS}</MS>
</fieldset>

View File

@@ -155,7 +155,7 @@ export const Carriers = () => {
</Icon>
</Link>
</section>
<section className="filters filters--spaced">
<section className="filters filters--multi">
<SearchFilter
placeholder="Filter carriers"
filter={[filter, setFilter]}

View File

@@ -10,6 +10,13 @@ type CarrierProps = {
};
export const RegisterStatus = ({ carrier }: CarrierProps) => {
const getReason = () => {
return carrier.register_status.reason
? typeof carrier.register_status.reason === "string"
? carrier.register_status.reason
: "Not Started"
: "Not Started";
};
const renderStatus = () => {
return (
<div
@@ -20,7 +27,7 @@ export const RegisterStatus = ({ carrier }: CarrierProps) => {
: "jam"
: "jean"
}`}
title={carrier.register_status.reason || "Not Started"}
title={getReason()}
>
{carrier.register_status.status === CARRIER_REG_OK ? (
<Icons.CheckCircle />
@@ -40,8 +47,7 @@ export const RegisterStatus = ({ carrier }: CarrierProps) => {
<details className={carrier.register_status.status || "not-tested"}>
<summary>{renderStatus()}</summary>
<MS>
<strong>Reason:</strong>{" "}
{carrier.register_status.reason || "Not Started"}
<strong>Reason:</strong> {getReason()}
</MS>
<PcapButton
accountSid={carrier.account_sid || ""}

View File

@@ -1,13 +1,15 @@
import { H1 } from "@jambonz/ui-kit";
import React, { useEffect } from "react";
import { useParams } from "react-router-dom";
import { useNavigate, useParams } from "react-router-dom";
import { useApiData } from "src/api";
import { Client } from "src/api/types";
import { toastError } from "src/store";
import ClientsForm from "./form";
import { ROUTE_INTERNAL_CLIENTS } from "src/router/routes";
export const ClientsEdit = () => {
const params = useParams();
const navigate = useNavigate();
const [data, refetch, error] = useApiData<Client>(
`Clients/${params.client_sid}`
);
@@ -16,6 +18,7 @@ export const ClientsEdit = () => {
useEffect(() => {
if (error) {
toastError(error.msg);
navigate(ROUTE_INTERNAL_CLIENTS);
}
}, [error]);

View File

@@ -9,7 +9,7 @@ import {
} from "src/api";
import { USER_ACCOUNT } from "src/api/constants";
import { Account, Client, UseApiDataMap } from "src/api/types";
import { Section } from "src/components";
import { Section, Tooltip } from "src/components";
import { AccountSelect, Message, Passwd } from "src/components/forms";
import { MSG_REQUIRED_FIELDS } from "src/constants";
import { ROUTE_INTERNAL_CLIENTS } from "src/router/routes";
@@ -30,7 +30,12 @@ export const ClientsForm = ({ client }: ClientsFormProps) => {
const [accountSid, setAccountSid] = useState("");
const [password, setPassword] = useState("");
const [username, setUsername] = useState("");
const [isActive, setIsActive] = useState(true);
const [isActive, setIsActive] = useState(
client ? client.data?.is_active : true
);
const [allowDirectAppCalling, setAllowDirectAppCalling] = useState(true);
const [allowDirectQueueCalling, setAllowDirectQueueCalling] = useState(true);
const [allowDirectUserCalling, setAllowDirectUserCalling] = useState(true);
const [modal, setModal] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const handleSubmit = (e: React.FormEvent) => {
@@ -42,6 +47,9 @@ export const ClientsForm = ({ client }: ClientsFormProps) => {
username: username,
password: password,
is_active: isActive,
allow_direct_app_calling: allowDirectAppCalling,
allow_direct_queue_calling: allowDirectQueueCalling,
allow_direct_user_calling: allowDirectUserCalling,
})
.then(() => {
toastSuccess("Client created successfully");
@@ -52,10 +60,10 @@ export const ClientsForm = ({ client }: ClientsFormProps) => {
});
} else {
putClient(client.data?.client_sid || "", {
account_sid: accountSid,
username: username,
...(password && { password: password }),
is_active: isActive,
allow_direct_app_calling: allowDirectAppCalling,
allow_direct_queue_calling: allowDirectQueueCalling,
allow_direct_user_calling: allowDirectUserCalling,
})
.then(() => {
toastSuccess("Client updated successfully");
@@ -99,6 +107,9 @@ export const ClientsForm = ({ client }: ClientsFormProps) => {
}
setIsActive(client.data.is_active);
setAllowDirectAppCalling(client.data.allow_direct_app_calling);
setAllowDirectQueueCalling(client.data.allow_direct_queue_calling);
setAllowDirectUserCalling(client.data.allow_direct_user_calling);
}
}, [client]);
@@ -107,8 +118,6 @@ export const ClientsForm = ({ client }: ClientsFormProps) => {
if (!accountSid || !accounts || !acc) return;
if (!acc?.sip_realm) {
setErrorMessage(`Sip realm is not set for the account.`);
} else if (!acc?.device_calling_application_sid) {
setErrorMessage(`Device calling application is not set for the account.`);
} else {
setErrorMessage("");
}
@@ -116,7 +125,12 @@ export const ClientsForm = ({ client }: ClientsFormProps) => {
return (
<>
<Section slim>
<form className="form form--internal" onSubmit={handleSubmit}>
<form
className={`form form--internal ${
!client?.data && client?.refetch ? "form--blur" : ""
}`}
onSubmit={handleSubmit}
>
<fieldset>
<MS>{MSG_REQUIRED_FIELDS}</MS>
{errorMessage && <Message message={errorMessage} />}
@@ -134,22 +148,12 @@ export const ClientsForm = ({ client }: ClientsFormProps) => {
placeholder="user name"
value={username}
required={true}
disabled={hasValue(client)}
autoComplete="off"
onChange={(e) => setUsername(e.target.value)}
/>
</div>
</div>
<label htmlFor="is_active" className="chk">
<input
id="is_active"
name="is_active"
type="checkbox"
checked={isActive}
onChange={(e) => setIsActive(e.target.checked)}
/>
<div>Active</div>
</label>
</fieldset>
<fieldset>
<label htmlFor="password">
Password{!hasValue(client) && <span>*</span>}
</label>
@@ -160,14 +164,67 @@ export const ClientsForm = ({ client }: ClientsFormProps) => {
value={password}
placeholder="Password"
setValue={setPassword}
disabled={hasValue(client)}
autoComplete="off"
/>
</fieldset>
<fieldset>
<label htmlFor="is_active" className="chk">
<input
id="is_active"
name="is_active"
type="checkbox"
checked={isActive}
onChange={(e) => setIsActive(e.target.checked)}
/>
<div>Active</div>
</label>
<label htmlFor="allow_direct_app_calling" className="chk">
<input
id="allow_direct_app_calling"
name="allow_direct_app_calling"
type="checkbox"
checked={allowDirectAppCalling}
onChange={(e) => setAllowDirectAppCalling(e.target.checked)}
/>
<div>Allow direct calling to applications</div>
<Tooltip text="Allow user to call applications without configuring an application for sip device calls.">
{" "}
</Tooltip>
</label>
<label htmlFor="allow_direct_queue_calling" className="chk">
<input
id="allow_direct_queue_calling"
name="allow_direct_queue_calling"
type="checkbox"
checked={allowDirectQueueCalling}
onChange={(e) => setAllowDirectQueueCalling(e.target.checked)}
/>
<div>Allow direct calling to queues</div>
<Tooltip text="Allow user to take calls from queues without configuring an application for sip device calls.">
{" "}
</Tooltip>
</label>
<label htmlFor="allow_direct_user_calling" className="chk">
<input
id="allow_direct_user_calling"
name="allow_direct_user_calling"
type="checkbox"
checked={allowDirectUserCalling}
onChange={(e) => setAllowDirectUserCalling(e.target.checked)}
/>
<div>Allow direct calling to other users</div>
<Tooltip text="Allow user to call other users without configuring an application for sip device calls.">
{" "}
</Tooltip>
</label>
</fieldset>
{user?.scope !== USER_ACCOUNT && (
<fieldset>
<AccountSelect
accounts={accounts}
account={[accountSid, setAccountSid]}
label="Used by"
label="Belongs to"
required={true}
defaultOption={false}
disabled={hasValue(client)}

View File

@@ -126,7 +126,7 @@ export const Clients = () => {
</Link>
</section>
<section className="filters filters--spaced">
<section className="filters filters--multi">
<SearchFilter
placeholder="Filter clients"
filter={[filter, setFilter]}

View File

@@ -6,7 +6,6 @@ import update from "immutability-helper";
import { deleteLcrRoute } from "src/api";
import { toastError, toastSuccess } from "src/store";
import { SelectorOption } from "src/components/forms/selector";
import { NOT_AVAILABLE_PREFIX } from "src/constants";
type ContainerProps = {
lcrRoute: [LcrRoute[], React.Dispatch<React.SetStateAction<LcrRoute[]>>];
@@ -61,11 +60,7 @@ export const Container = ({
};
const handleRouteDelete = (r: LcrRoute | undefined, index: number) => {
if (
r &&
r.lcr_route_sid &&
!r.lcr_route_sid.startsWith(NOT_AVAILABLE_PREFIX)
) {
if (r && r.lcr_route_sid) {
deleteLcrRoute(r.lcr_route_sid)
.then(() => {
toastSuccess("Least cost routing rule successfully deleted");
@@ -82,7 +77,7 @@ export const Container = ({
{hasLength(lcrRoutes) &&
lcrRoutes.map((lr, i) => (
<Card
key={lr.lcr_route_sid}
key={lr.lcr_route_sid || i}
lr={lr}
index={i}
moveCard={moveCard}

View File

@@ -8,37 +8,33 @@ import {
useDispatch,
useSelectState,
} from "src/store";
import { MSG_REQUIRED_FIELDS, NOT_AVAILABLE_PREFIX } from "src/constants";
import { MSG_REQUIRED_FIELDS } from "src/constants";
import { setLocation } from "src/store/localStore";
import { AccountSelect, Message, Selector } from "src/components/forms";
import type {
Account,
Carrier,
Lcr,
LcrCarrierSetEntry,
LcrRoute,
UseApiDataMap,
} from "src/api/types";
import { ROUTE_INTERNAL_LEST_COST_ROUTING } from "src/router/routes";
import {
deleteLcr,
postLcrCarrierSetEntry,
putLcrCarrierSetEntries,
putLcrRoutes,
putLcr,
postLcrCreateRoutes,
putLcrUpdateRoutes,
useApiData,
useServiceProviderData,
getLcrRoute,
} from "src/api";
import { USER_ACCOUNT, USER_ADMIN } from "src/api/constants";
import { postLcr } from "src/api";
import { postLcrRoute } from "src/api";
import DeleteLcr from "./delete";
import { Scope } from "src/store/types";
import { DndProvider } from "react-dnd";
import { HTML5Backend } from "react-dnd-html5-backend";
import Container from "./container";
import { v4 } from "uuid";
import { hasValue } from "src/utils";
type LcrFormProps = {
lcrDataMap?: UseApiDataMap<Lcr>;
@@ -47,7 +43,7 @@ type LcrFormProps = {
export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => {
const LCR_ROUTE_TEMPLATE: LcrRoute = {
lcr_route_sid: `${NOT_AVAILABLE_PREFIX}${v4()}`,
lcr_route_sid: "",
regex: "",
lcr_sid: "",
priority: 0,
@@ -68,7 +64,7 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => {
const [defaultLcrCarrier, setDefaultLcrCarrier] = useState("");
const [defaultLcrCarrierSetEntrySid, setDefaultLcrCarrierSetEntrySid] =
useState<string | null>();
const [defaultLcrRouteSid, setDefaultLcrRouteSid] = useState("");
const [defaultLcrRoute, setDefaultLcrRoute] = useState<LcrRoute | null>(null);
const [defaultCarrier, setDefaultCarrier] = useState("");
const [apiUrl, setApiUrl] = useState("");
const [accountSid, setAccountSid] = useState("");
@@ -136,44 +132,53 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => {
setPreviousLcr(lcrDataMap.data);
}
if (
lcrRouteDataMap &&
lcrRouteDataMap.data &&
lcrRouteDataMap.data !== previousLcrRoutes
) {
setPreviousLcrRoutes(lcrRouteDataMap.data);
// Find default carrier
lcrRouteDataMap.data.forEach((lr) => {
lr.lcr_carrier_set_entries?.forEach((entry) => {
if (
entry.lcr_carrier_set_entry_sid ===
lcrDataMap?.data?.default_carrier_set_entry_sid
) {
setDefaultLcrCarrier(entry.voip_carrier_sid || defaultCarrier);
setDefaultLcrCarrierSetEntrySid(
entry.lcr_carrier_set_entry_sid || null
);
setDefaultLcrRouteSid(entry.lcr_route_sid || "");
}
});
});
}
useMemo(() => {
let default_lcr_route_sid = "";
if (
lcrRouteDataMap &&
lcrRouteDataMap.data &&
lcrRouteDataMap.data !== previousLcrRoutes
) {
setPreviousLcrRoutes(lcrRouteDataMap.data);
// Find default carrier
lcrRouteDataMap.data.forEach((lr) => {
lr.lcr_carrier_set_entries?.forEach((entry) => {
if (
entry.lcr_carrier_set_entry_sid ===
lcrDataMap?.data?.default_carrier_set_entry_sid
) {
setDefaultLcrCarrier(entry.voip_carrier_sid || defaultCarrier);
setDefaultLcrCarrierSetEntrySid(
entry.lcr_carrier_set_entry_sid || null
);
default_lcr_route_sid = entry.lcr_route_sid || "";
setDefaultLcrRoute(lr);
}
});
});
}
if (lcrRouteDataMap && lcrRouteDataMap.data)
setLcrRoutes(
lcrRouteDataMap.data.filter(
(route) => route.lcr_route_sid !== defaultLcrRouteSid
(route) => route.lcr_route_sid !== default_lcr_route_sid
)
);
}, [defaultLcrRouteSid]);
}, [lcrRouteDataMap?.data]);
const addLcrRoutes = () => {
const newLcrRoute = LCR_ROUTE_TEMPLATE;
const ls = [
...lcrRoutes,
{
...LCR_ROUTE_TEMPLATE,
...newLcrRoute,
priority: lcrRoutes.length,
lcr_carrier_set_entries: newLcrRoute.lcr_carrier_set_entries?.map(
(r) => ({
...r,
voip_carrier_sid: defaultCarrier || carrierSelectorOptions[0].value,
})
),
},
];
setLcrRoutes(ls);
@@ -194,11 +199,48 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => {
const lcrPayload: Lcr = getLcrPayload();
postLcr(lcrPayload)
.then(({ json }) => {
Promise.all(
lcrRoutes.map((route, i) => handleLcrRoutePost(json.sid, route, i))
)
const lcrsPayload = lcrRoutes.map((l, i) => ({
...l,
lcr_carrier_set_entries: l.lcr_carrier_set_entries?.map((e) => ({
...e,
voip_carrier_sid:
e.voip_carrier_sid ||
defaultCarrier ||
carrierSelectorOptions[0]?.value,
})),
lcr_sid: json.sid,
priority: i,
}));
lcrsPayload.push({
lcr_sid: json.sid,
regex: ".*",
description: "System Default Route",
priority: 9999,
lcr_carrier_set_entries: [
{
lcr_route_sid: "",
voip_carrier_sid:
defaultLcrCarrier || carrierSelectorOptions[0]?.value,
priority: 0,
},
],
});
postLcrCreateRoutes(json.sid, lcrsPayload)
.then(() => {
handleLcrDefaultCarrierPost(json.sid);
if (lcrDataMap) {
toastSuccess("Least cost routing successfully updated");
} else {
toastSuccess("Least cost routing successfully created");
if (user?.access === Scope.admin) {
navigate(ROUTE_INTERNAL_LEST_COST_ROUTING);
} else {
navigate(
`${ROUTE_INTERNAL_LEST_COST_ROUTING}/${json.sid}/edit`
);
}
// Update global state
dispatch({ type: "lcr" });
}
})
.catch(({ msg }) => {
toastError(msg);
@@ -209,209 +251,38 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => {
});
};
const handleLcrDefaultCarrierPost = (lcr_sid: string) => {
const defaultRoute = {
lcr_sid: lcr_sid,
regex: ".*",
desciption: "System Default Route",
priority: 9999,
lcr_carrier_set_entries: [
{
lcr_route_sid: "",
voip_carrier_sid: defaultLcrCarrier,
priority: 0,
},
],
};
handleLcrRoutePost(lcr_sid, defaultRoute, 9999).then((lcr_route_sid) => {
// There is small hack here to wait the data commited in bd for lcr entries
new Promise(async (r) => setTimeout(() => r(0), 300)).then(() => {
getLcrRoute(lcr_route_sid).then(({ json }) => {
if (json.lcr_carrier_set_entries?.length) {
const lcr_carrier_set_entry_sid =
json.lcr_carrier_set_entries[0].lcr_carrier_set_entry_sid;
putLcr(lcr_sid, {
default_carrier_set_entry_sid: lcr_carrier_set_entry_sid,
})
.then(() => {
if (lcrDataMap) {
toastSuccess("Least cost routing successfully updated");
} else {
toastSuccess("Least cost routing successfully created");
if (user?.access === Scope.admin) {
navigate(ROUTE_INTERNAL_LEST_COST_ROUTING);
} else {
navigate(
`${ROUTE_INTERNAL_LEST_COST_ROUTING}/${lcr_sid}/edit`
);
}
// Update global state
dispatch({ type: "lcr" });
}
})
.catch((error) => {
toastError(error);
});
}
});
});
});
};
const handleLcrRoutePost = (
lcr_sid: string,
route: LcrRoute,
priority: number
): Promise<string> => {
return new Promise(async (resolve, reject) => {
const lcrRoutePayload: LcrRoute = {
lcr_sid,
regex: route.regex,
priority,
};
postLcrRoute(lcrRoutePayload)
.then(({ json }) => {
if (route.lcr_carrier_set_entries) {
Promise.all(
route.lcr_carrier_set_entries.map((entry) => {
handleLcrCarrierSetEntryPost(json.sid, entry);
})
)
.then(() => {
resolve(json.sid);
})
.catch((error) => {
reject(error);
});
}
})
.catch((error) => {
reject(error);
});
});
};
const handleLcrCarrierSetEntryPost = (
lcr_route_sid: string,
entry: LcrCarrierSetEntry
): Promise<string> => {
const lcrCarrierSetEntryPayload: LcrCarrierSetEntry = {
...entry,
voip_carrier_sid: entry.voip_carrier_sid || defaultCarrier,
lcr_route_sid,
};
return new Promise<string>(async (r, e) => {
postLcrCarrierSetEntry(lcrCarrierSetEntryPayload)
.then(({ json }) => r(json.sid))
.catch((error) => e(error));
});
};
const handleLcrPut = () => {
if (lcrDataMap && lcrDataMap.data && lcrDataMap.data.lcr_sid) {
// update LCR
const lcrPayload: Lcr = getLcrPayload();
putLcr(lcrDataMap.data.lcr_sid, lcrPayload).then(() => {
Promise.all(
lcrRoutes.map((route, i) => {
if (
route.lcr_route_sid &&
!route.lcr_route_sid?.startsWith(NOT_AVAILABLE_PREFIX)
) {
handleLcrRoutePut(
lcrDataMap.data?.lcr_sid || "",
route.lcr_route_sid,
route,
i
);
} else {
handleLcrRoutePost(lcrDataMap.data?.lcr_sid || "", route, i);
}
})
)
putLcrUpdateRoutes(lcrDataMap.data?.lcr_sid || "", [
...lcrRoutes.map((r, i) => ({
...r,
priority: i,
})),
...(hasValue(defaultLcrRoute)
? [
{
...defaultLcrRoute,
lcr_carrier_set_entries:
defaultLcrRoute.lcr_carrier_set_entries?.map((r) => ({
...r,
voip_carrier_sid:
defaultLcrCarrier ||
r.voip_carrier_sid ||
carrierSelectorOptions[0].value,
})),
},
]
: []),
])
.then(() => {
if (defaultLcrCarrierSetEntrySid) {
const defaultEntry: LcrCarrierSetEntry = {
lcr_route_sid: defaultLcrRouteSid,
voip_carrier_sid: defaultLcrCarrier,
priority: 0,
};
handleLcrCarrierEntryPut(
defaultLcrRouteSid,
defaultLcrCarrierSetEntrySid,
defaultEntry
).then(() => {
toastSuccess("Least cost routing rule successfully updated");
});
}
toastSuccess("Least cost routing rule successfully updated");
})
.catch((error) => toastError(error));
});
}
const handleLcrRoutePut = (
lcr_sid: string,
lcr_route_sid: string,
route: LcrRoute,
priority: number
): Promise<string> => {
return new Promise(async (resolve, reject) => {
const lcrRoutePayload: LcrRoute = {
lcr_sid,
regex: route.regex,
priority,
};
putLcrRoutes(lcr_route_sid, lcrRoutePayload).then(() => {
if (
route.lcr_carrier_set_entries &&
route.lcr_carrier_set_entries.length > 0
) {
Promise.all(
route.lcr_carrier_set_entries.map((entry) => {
if (entry.lcr_carrier_set_entry_sid) {
return handleLcrCarrierEntryPut(
entry.lcr_route_sid || lcr_route_sid,
entry.lcr_carrier_set_entry_sid,
entry
);
} else {
return handleLcrCarrierSetEntryPost(lcr_route_sid, entry);
}
})
)
.then(() => {
resolve("Least cost routing rule successfully updated");
})
.catch((error) => {
reject(error);
});
}
});
});
};
const handleLcrCarrierEntryPut = (
lcr_route_sid: string,
lcr_carrier_set_entry_sid: string,
entry: LcrCarrierSetEntry
): Promise<string> => {
const lcrCarrierSetEntryPayload: LcrCarrierSetEntry = {
lcr_route_sid,
workload: entry.workload,
voip_carrier_sid: entry.voip_carrier_sid || defaultCarrier,
priority: entry.priority,
};
return new Promise<string>(async (r, e) => {
putLcrCarrierSetEntries(
lcr_carrier_set_entry_sid,
lcrCarrierSetEntryPayload
)
.then(() => r("success"))
.catch((error) => e(error));
});
};
};
const handleSubmit = (e: React.FormEvent) => {
@@ -449,7 +320,12 @@ export const LcrForm = ({ lcrDataMap, lcrRouteDataMap }: LcrFormProps) => {
return (
<>
<Section slim>
<form className="form form--internal" onSubmit={handleSubmit}>
<form
className={`form form--internal ${
!lcrDataMap?.data && lcrDataMap?.refetch ? "form--blur" : ""
}`}
onSubmit={handleSubmit}
>
<fieldset>
<MS>{MSG_REQUIRED_FIELDS}</MS>
{errorMessage && <Message message={errorMessage} />}

View File

@@ -99,7 +99,7 @@ export const Lcrs = () => {
multiple carriers available.
</M>
</section>
<section className="filters filters--spaced">
<section className="filters filters--multi">
<SearchFilter placeholder="Filter lcrs" filter={[filter, setFilter]} />
<ScopedAccess user={user} scope={Scope.admin}>
<AccountFilter

View File

@@ -120,7 +120,12 @@ export const MsTeamsTenantForm = ({
return (
<Section slim>
<form className="form form--internal" onSubmit={handleSubmit}>
<form
className={`form form--internal ${
!msTeamsTenant?.data && msTeamsTenant?.refetch ? "form--blur" : ""
}`}
onSubmit={handleSubmit}
>
<fieldset>
<MS>{MSG_REQUIRED_FIELDS}</MS>
</fieldset>

View File

@@ -89,7 +89,7 @@ export const MSTeamsTenants = () => {
</Link>
)}
</section>
<section className="filters filters--spaced">
<section className="filters filters--multi">
<SearchFilter
placeholder="Filter ms teams tenants"
filter={[filter, setFilter]}

View File

@@ -141,7 +141,12 @@ export const PhoneNumberForm = ({ phoneNumber }: PhoneNumberFormProps) => {
return (
<>
<Section slim>
<form className="form form--internal" onSubmit={handleSubmit}>
<form
className={`form form--internal ${
!phoneNumber?.data && phoneNumber?.refetch ? "form--blur" : ""
}`}
onSubmit={handleSubmit}
>
<fieldset>
<MS>{MSG_REQUIRED_FIELDS}</MS>
</fieldset>

View File

@@ -129,7 +129,7 @@ export const PhoneNumbers = () => {
</Link>
)}
</section>
<section className="filters filters--spaced">
<section className="filters filters--multi">
<SearchFilter
placeholder="Filter phone numbers"
filter={[filter, setFilter]}

View File

@@ -13,11 +13,12 @@ import {
JaegerRoot,
JaegerSpan,
WaveSurferDtmfResult,
WaveSurferGatherSpeechVerbHookLatencyResult,
WaveSurferSttResult,
WaveSurferTtsLatencyResult,
} from "src/api/jaeger-types";
import {
getSpanAttributeByName,
getSpansByName,
getSpansByNameRegex,
getSpansFromJaegerRoot,
} from "./utils";
@@ -42,6 +43,14 @@ export const Player = ({ call }: PlayerProps) => {
useState<WaveSurferSttResult | null>();
const [waveSurferDtmfData, setWaveSurferDtmfData] =
useState<WaveSurferDtmfResult | null>();
const [waveSurferTtsLatencyData, setWaveSurferTtsLatencyData] =
useState<WaveSurferTtsLatencyResult | null>();
const [
waveSurferGatherSpeechVerbHookLatencyData,
setWaveSurferGatherSpeechVerbHookLatencyData,
] = useState<WaveSurferGatherSpeechVerbHookLatencyResult | null>();
const [regionChecked, setRegionChecked] = useState(false);
const wavesurferId = `wavesurfer--${call_sid}`;
@@ -112,6 +121,43 @@ export const Player = ({ call }: PlayerProps) => {
});
};
const PEAKS_WINDOW = 5; // require 30 ms of speech energy over threshold to trigger
const PEAK_THRESHOLD = 0.03;
const getSilenceStartTime = (
start: number,
end: number,
channel: number
): number => {
if (waveSurferRef.current) {
const duration = waveSurferRef.current.getDecodedData()?.duration;
if (duration && duration > 0) {
const maxLength = Math.round(duration * 8000) / 10; // evaluate speech energy every 10 ms
const peaks = waveSurferRef.current.exportPeaks({ maxLength });
if (peaks && peaks.length > channel) {
if (duration && duration > 0) {
const data = peaks[channel];
const startPeak = Math.ceil((start * data.length) / duration);
const endPeak = Math.ceil((end * data.length) / duration);
let count = 0;
for (let i = endPeak; i > startPeak; i--)
if (Math.abs(data[i]) > PEAK_THRESHOLD) {
count++;
if (count === PEAKS_WINDOW) {
return (
((i + PEAKS_WINDOW) * duration) / data.length + 0.02 // add 20 ms adjustment
);
}
} else {
count = 0;
}
}
}
}
}
return -1;
};
const drawSttRegionForSpan = (
s: JaegerSpan,
startPoint: JaegerSpan,
@@ -128,26 +174,42 @@ export const Player = ({ call }: PlayerProps) => {
const end =
(s.endTimeUnixNano - startPoint.startTimeUnixNano) / 1_000_000_000;
const region = waveSurferRegionsPluginRef.current.addRegion({
id: s.spanId,
start,
end,
color: "rgba(255, 0, 0, 0.15)",
drag: false,
resize: false,
});
const endSpeechTime = getSilenceStartTime(start, end, channel);
changeRegionMouseStyle(region, channel);
const [sttResult] = getSpanAttributeByName(s.attributes, "stt.result");
let att: WaveSurferSttResult;
if (sttResult) {
const data = JSON.parse(sttResult.value.stringValue);
att = {
vendor: data.vendor.name,
transcript: data.alternatives[0].transcript,
confidence: data.alternatives[0].confidence,
language_code: data.language_code,
...(endSpeechTime > 0 && { latency: end - endSpeechTime }),
};
const [sttResolve] = getSpanAttributeByName(
s.attributes,
"stt.resolve"
);
if (
endSpeechTime > 0 &&
sttResolve &&
sttResolve.value.stringValue === "speech"
) {
const latencyRegion = waveSurferRegionsPluginRef.current.addRegion({
id: s.spanId + "latency",
start: endSpeechTime,
end,
color: "rgba(255, 255, 0, 0.55)",
drag: false,
resize: false,
content: `${(end - endSpeechTime).toFixed(2)}s`,
});
changeRegionMouseStyle(latencyRegion, channel);
}
} else {
const [sttResolve] = getSpanAttributeByName(
s.attributes,
@@ -171,6 +233,17 @@ export const Player = ({ call }: PlayerProps) => {
}
}
const region = waveSurferRegionsPluginRef.current.addRegion({
id: s.spanId,
start,
end,
color: "rgba(255, 0, 0, 0.15)",
drag: false,
resize: false,
});
changeRegionMouseStyle(region, channel);
region.on("click", () => {
setWaveSurferRegionData(att);
});
@@ -178,10 +251,103 @@ export const Player = ({ call }: PlayerProps) => {
}
};
const drawTtsLatencyRegion = (s: JaegerSpan, startPoint: JaegerSpan) => {
if (waveSurferRegionsPluginRef.current) {
const r = waveSurferRegionsPluginRef.current
.getRegions()
.find((r) => r.id === s.spanId);
if (!r) {
const start =
(s.startTimeUnixNano - startPoint.startTimeUnixNano) / 1_000_000_000;
let end =
(s.endTimeUnixNano - startPoint.startTimeUnixNano) / 1_000_000_000;
const [ttsVendor] = getSpanAttributeByName(s.attributes, "tts.vendor");
const [ttsCache] = getSpanAttributeByName(s.attributes, "tts.cached");
const [streamLatency] = getSpanAttributeByName(
s.attributes,
"time_to_first_byte_ms"
);
if (streamLatency && streamLatency.value.stringValue) {
end = start + Number(streamLatency.value.stringValue) / 1_000;
}
if (ttsVendor && ttsCache && !Boolean(ttsCache.value.boolValue)) {
const latencyRegion = waveSurferRegionsPluginRef.current.addRegion({
id: s.spanId,
start: start,
end,
color: "rgba(255, 155, 0, 0.55)",
drag: false,
resize: false,
content: createMultiLineTextElement(`${(end - start).toFixed(2)}s`),
});
changeRegionMouseStyle(latencyRegion, 1);
latencyRegion.on("click", () => {
setWaveSurferTtsLatencyData({
vendor: ttsVendor.value.stringValue,
latency: `${(end - start).toFixed(2)}s`,
isCached: String(ttsCache.value.boolValue),
});
});
}
}
}
};
const drawVerbHookDelayRegion = (s: JaegerSpan, startPoint: JaegerSpan) => {
if (waveSurferRegionsPluginRef.current) {
const r = waveSurferRegionsPluginRef.current
.getRegions()
.find((r) => r.id === s.spanId);
if (!r) {
const start =
(s.startTimeUnixNano - startPoint.startTimeUnixNano) / 1_000_000_000;
const end =
(s.endTimeUnixNano - startPoint.startTimeUnixNano) / 1_000_000_000;
const tmpEnd = end - start < 0.05 ? start + 0.05 : end;
const latencyRegion = waveSurferRegionsPluginRef.current.addRegion({
id: s.spanId,
start: start,
end: tmpEnd,
color: "rgba(255, 3, 180, 0.55)",
drag: false,
resize: false,
content: createMultiLineTextElement(`${(end - start).toFixed(2)}s`),
});
const [statusCode] = getSpanAttributeByName(
s.attributes,
"http.statusCode"
);
changeRegionMouseStyle(latencyRegion, 0);
latencyRegion.on("click", () => {
setWaveSurferGatherSpeechVerbHookLatencyData({
statusCode: statusCode ? Number(statusCode.value.doubleValue) : 404,
latency: `${(end - start).toFixed(2)}s`,
});
});
}
}
};
function createMultiLineTextElement(text: string) {
const div = document.createElement("div");
div.style.paddingLeft = "10px";
div.style.paddingTop = "15px";
div.appendChild(document.createElement("br"));
div.appendChild(document.createTextNode(text));
return div;
}
const buildWavesurferRegion = () => {
if (jaegerRoot) {
const spans = getSpansFromJaegerRoot(jaegerRoot);
const [startPoint] = getSpansByName(spans, "background-listen:listen");
const start = getSpansByNameRegex(spans, /background-record:listen/);
const startPoint = start ? start[0] : null;
// there should be only one startPoint for background listen
if (startPoint) {
const gatherSpans = getSpansByNameRegex(spans, /:gather{/);
@@ -189,6 +355,7 @@ export const Player = ({ call }: PlayerProps) => {
drawSttRegionForSpan(s, startPoint);
});
// Trasscription
const transcribeSpans = getSpansByNameRegex(spans, /stt-listen:/);
transcribeSpans.forEach((cs) => {
// Channel start from 0
@@ -199,11 +366,35 @@ export const Player = ({ call }: PlayerProps) => {
channel > 0 ? channel - 1 : channel
);
});
// DTMF
const dtmfSpans = getSpansByNameRegex(spans, /dtmf:/);
dtmfSpans.forEach((ds) => {
drawDtmfRegionForSpan(ds, startPoint);
});
// TTS delay
const ttsSpans = getSpansByNameRegex(spans, /tts-generation/);
ttsSpans.forEach((tts) => {
drawTtsLatencyRegion(tts, startPoint);
});
// Gather verb hook delay
const verbHookSpans = getSpansByNameRegex(spans, /verb:hook/);
verbHookSpans
.filter((s) => {
const [httpBody] = getSpanAttributeByName(
s.attributes,
"http.body"
);
return (
httpBody.value.stringValue.includes(
'"reason":"speechDetected"'
) ||
httpBody.value.stringValue.includes('"reason":"dtmfDetected"')
);
})
.forEach((s) => {
drawVerbHookDelayRegion(s, startPoint);
});
}
}
};
@@ -423,7 +614,7 @@ export const Player = ({ call }: PlayerProps) => {
}
}}
/>
<div>Overlay STT and DTMF events</div>
<div>Show latencies</div>
</label>
</div>
{waveSurferRegionData && (
@@ -475,6 +666,16 @@ export const Player = ({ call }: PlayerProps) => {
</div>
</div>
)}
{waveSurferRegionData.latency && (
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Latency:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSurferRegionData.latency.toFixed(2)} seconds
</div>
</div>
)}
</div>
</div>
</ModalClose>
@@ -509,6 +710,77 @@ export const Player = ({ call }: PlayerProps) => {
</div>
</ModalClose>
)}
{waveSurferTtsLatencyData && (
<ModalClose handleClose={() => setWaveSurferTtsLatencyData(null)}>
<div className="spanDetailsWrapper__header">
<P>
<strong>Tts Latency</strong>
</P>
</div>
<div className="spanDetailsWrapper">
<div className="spanDetailsWrapper__detailsWrapper">
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Vendor:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSurferTtsLatencyData.vendor}
</div>
</div>
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Latency:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSurferTtsLatencyData.latency}
</div>
</div>
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>From Cache:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSurferTtsLatencyData.isCached}
</div>
</div>
</div>
</div>
</ModalClose>
)}
{waveSurferGatherSpeechVerbHookLatencyData && (
<ModalClose
handleClose={() => setWaveSurferGatherSpeechVerbHookLatencyData(null)}
>
<div className="spanDetailsWrapper__header">
<P>
<strong>Application Response Latency</strong>
</P>
</div>
<div className="spanDetailsWrapper">
<div className="spanDetailsWrapper__detailsWrapper">
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Status Code:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSurferGatherSpeechVerbHookLatencyData.statusCode}
</div>
</div>
<div className="spanDetailsWrapper__details">
<div className="spanDetailsWrapper__details_header">
<strong>Latency:</strong>
</div>
<div className="spanDetailsWrapper__details_body">
{waveSurferGatherSpeechVerbHookLatencyData.latency}
</div>
</div>
</div>
</div>
</ModalClose>
)}
{deleteRecordUrl && (
<Modal
handleCancel={() => setDeleteRecordUrl("")}

View File

@@ -1,19 +1,25 @@
import React, { Fragment, useEffect, useState } from "react";
import { Button, ButtonGroup, MS } from "@jambonz/ui-kit";
import { Button, ButtonGroup, Icon, MS, MXS } from "@jambonz/ui-kit";
import { Link, useNavigate } from "react-router-dom";
import { ROUTE_INTERNAL_SPEECH } from "src/router/routes";
import { Section, Tooltip } from "src/components";
import { Icons, Section, Tooltip } from "src/components";
import {
FileUpload,
Selector,
Passwd,
AccountSelect,
Checkzone,
Message,
} from "src/components/forms";
import { toastError, toastSuccess, useSelectState } from "src/store";
import {
deleteGoogleCustomVoice,
getGoogleCustomVoices,
getSpeechSupportedLanguagesAndVoices,
postGoogleCustomVoice,
postSpeechService,
putGoogleCustomVoice,
putSpeechService,
useServiceProviderData,
} from "src/api";
@@ -32,6 +38,8 @@ import {
VENDOR_CUSTOM,
VENDOR_COBALT,
VENDOR_ELEVENLABS,
VENDOR_ASSEMBLYAI,
VENDOR_WHISPER,
} from "src/vendor";
import { MSG_REQUIRED_FIELDS } from "src/constants";
import {
@@ -39,17 +47,30 @@ import {
getObscuredSecret,
isUserAccountScope,
isNotBlank,
hasLength,
hasValue,
} from "src/utils";
import { getObscuredGoogleServiceKey } from "./utils";
import { CredentialStatus } from "./status";
import type { RegionVendors, GoogleServiceKey, Vendor } from "src/vendor/types";
import type { Account, SpeechCredential, UseApiDataMap } from "src/api/types";
import type {
RegionVendors,
GoogleServiceKey,
Vendor,
Model,
} from "src/vendor/types";
import type {
Account,
GoogleCustomVoice,
SpeechCredential,
UseApiDataMap,
} from "src/api/types";
import { setAccountFilter, setLocation } from "src/store/localStore";
import {
DEFAULT_ELEVENLABS_MODEL,
DEFAULT_ELEVENLABS_OPTIONS,
DEFAULT_GOOGLE_CUSTOM_VOICES_REPORTED_USAGE,
DISABLE_CUSTOM_SPEECH,
ELEVENLABS_MODEL_OPTIONS,
GOOGLE_CUSTOM_VOICES_REPORTED_USAGE,
} from "src/api/constants";
type SpeechServiceFormProps = {
@@ -82,7 +103,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
const [sttApiKey, setSttApiKey] = useState("");
const [ttsRegion, setTtsRegion] = useState("");
const [ttsApiKey, setTtsApiKey] = useState("");
const [ttsModelId, setTtsModelId] = useState(DEFAULT_ELEVENLABS_MODEL);
const [ttsModelId, setTtsModelId] = useState("");
const [instanceId, setInstanceId] = useState("");
const [initialCheckCustomTts, setInitialCheckCustomTts] = useState(false);
const [initialCheckCustomStt, setInitialCheckCustomStt] = useState(false);
@@ -117,6 +138,20 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
const [onPremNuanceSttUrl, setOnPremNuanceSttUrl] = useState("");
const [cobaltServerUri, setCobaltServerUri] = useState("");
const [label, setLabel] = useState("");
const [useCustomVoicesCheck, setUseCustomVoicesCheck] = useState(false);
const [customVoices, setCustomVoices] = useState<GoogleCustomVoice[]>([]);
const [customVoicesMessage, setCustomVoicesMessage] = useState("");
const [ttsModels, setTtsModels] = useState<Model[]>([]);
const [optionsInitialChecked, setOptionsInitialChecked] = useState(false);
const [options, setOptions] = useState("");
const [tmpOptions, setTmpOptions] = useState("");
const [deepgramSttUri, setDeepgramSttUri] = useState("");
const [tmpDeepgramSttUri, setTmpDeepgramSttUri] = useState("");
const [deepgramSttUseTls, setDeepgramSttUseTls] = useState(false);
const [tmpDeepgramSttUseTls, setTmpDeepgramSttUseTls] = useState(false);
const [initialDeepgramOnpremCheck, setInitialDeepgramOnpremCheck] =
useState(false);
const [isDeepgramOnpremEnabled, setIsDeepgramOnpremEnabled] = useState(false);
const handleFile = (file: File) => {
const handleError = () => {
@@ -144,6 +179,62 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
});
};
const handlePutGoogleCustomVoices = () => {
if (!credential || !credential.data) {
return;
}
if (useCustomVoicesCheck) {
Promise.all(
customVoices.map((v) => {
if (v.google_custom_voice_sid) {
const sid = v.google_custom_voice_sid;
delete v.google_custom_voice_sid;
return putGoogleCustomVoice(sid, v);
} else {
return postGoogleCustomVoice({
...v,
speech_credential_sid: credential.data?.speech_credential_sid,
});
}
})
)
.then(() => {
toastSuccess("Speech credential updated successfully");
credential.refetch();
navigate(
`${ROUTE_INTERNAL_SPEECH}/${credential?.data?.speech_credential_sid}/edit`
);
})
.catch((error) => {
toastError(error.msg);
});
} else if (useCustomVoicesCheck && customVoices.length > 0) {
Promise.all(
customVoices.map((v) => {
if (v.google_custom_voice_sid) {
return deleteGoogleCustomVoice(v.google_custom_voice_sid);
}
})
)
.then(() => {
toastSuccess("Speech credential updated successfully");
credential.refetch();
navigate(
`${ROUTE_INTERNAL_SPEECH}/${credential?.data?.speech_credential_sid}/edit`
);
})
.catch((error) => {
toastError(error.msg);
});
} else {
toastSuccess("Speech credential updated successfully");
credential.refetch();
navigate(
`${ROUTE_INTERNAL_SPEECH}/${credential.data.speech_credential_sid}/edit`
);
}
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
@@ -203,9 +294,16 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
...(vendor === VENDOR_COBALT && {
cobalt_server_uri: cobaltServerUri || null,
}),
...(vendor === VENDOR_ELEVENLABS && {
...((vendor === VENDOR_ELEVENLABS || vendor === VENDOR_WHISPER) && {
model_id: ttsModelId || null,
}),
...(vendor === VENDOR_ELEVENLABS && {
options: options || null,
}),
...(vendor === VENDOR_DEEPGRAM && {
deepgram_stt_uri: deepgramSttUri || null,
deepgram_stt_use_tls: deepgramSttUseTls ? 1 : 0,
}),
};
if (credential && credential.data) {
@@ -218,11 +316,15 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
)
.then(() => {
if (credential && credential.data) {
toastSuccess("Speech credential updated successfully");
credential.refetch();
navigate(
`${ROUTE_INTERNAL_SPEECH}/${credential.data.speech_credential_sid}/edit`
);
if (credential.data.vendor === VENDOR_GOOGLE) {
handlePutGoogleCustomVoices();
} else {
toastSuccess("Speech credential updated successfully");
credential.refetch();
navigate(
`${ROUTE_INTERNAL_SPEECH}/${credential.data.speech_credential_sid}/edit`
);
}
}
})
.catch((error) => {
@@ -240,17 +342,34 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
vendor === VENDOR_MICROSOFT ||
vendor === VENDOR_WELLSAID ||
vendor === VENDOR_DEEPGRAM ||
vendor === VENDOR_ASSEMBLYAI ||
vendor === VENDOR_SONIOX ||
vendor === VENDOR_ELEVENLABS
vendor === VENDOR_ELEVENLABS ||
vendor === VENDOR_WHISPER
? apiKey
: null,
}),
riva_server_uri: vendor == VENDOR_NVIDIA ? rivaServerUri : null,
})
.then(() => {
toastSuccess("Speech credential created successfully");
navigate(ROUTE_INTERNAL_SPEECH);
setAccountFilter(accountSid);
.then(({ json }) => {
if (vendor === VENDOR_GOOGLE && useCustomVoicesCheck) {
Promise.all(
customVoices.map((v) =>
postGoogleCustomVoice({
...v,
speech_credential_sid: json.sid,
})
)
).then(() => {
toastSuccess("Speech credential created successfully");
navigate(ROUTE_INTERNAL_SPEECH);
setAccountFilter(accountSid);
});
} else {
toastSuccess("Speech credential created successfully");
navigate(ROUTE_INTERNAL_SPEECH);
setAccountFilter(accountSid);
}
})
.catch((error) => {
toastError(error.msg);
@@ -259,6 +378,28 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
}
};
useEffect(() => {
if (vendor === VENDOR_ELEVENLABS || vendor === VENDOR_WHISPER) {
getSpeechSupportedLanguagesAndVoices(
currentServiceProvider?.service_provider_sid,
vendor,
""
).then(({ json }) => {
if (json.models) {
setTtsModels(json.models);
if (
json.models.length > 0 &&
(vendor === VENDOR_ELEVENLABS || vendor === VENDOR_WHISPER)
) {
setTtsModelId(json.models[0].value);
}
}
});
} else {
setTtsModels([]);
}
}, [vendor]);
useEffect(() => {
setLocation();
if (credential && credential.data) {
@@ -402,11 +543,56 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
setTtsModelId(credential.data.model_id);
}
}
if (credential?.data?.options) {
setOptions(credential.data.options);
setOptionsInitialChecked(true);
}
if (credential?.data?.vendor === VENDOR_GOOGLE) {
// let try to check if there is custom voices
getGoogleCustomVoices({
speech_credential_sid: credential.data.speech_credential_sid,
}).then(({ json }) => {
setCustomVoices(json);
setUseCustomVoicesCheck(json.length > 0);
});
}
if (credential?.data?.deepgram_stt_uri) {
setDeepgramSttUri(credential.data.deepgram_stt_uri);
}
if (credential?.data?.deepgram_stt_use_tls) {
setDeepgramSttUseTls(
credential?.data?.deepgram_stt_use_tls > 0 ? true : false
);
}
setInitialDeepgramOnpremCheck(hasValue(credential?.data?.deepgram_stt_uri));
setIsDeepgramOnpremEnabled(hasValue(credential?.data?.deepgram_stt_uri));
}, [credential]);
const updateCustomVoices = (
index: number,
key: string,
value: typeof customVoices[number][keyof GoogleCustomVoice]
) => {
setCustomVoices((prev) =>
prev.map((g, i) =>
i === index
? {
...g,
[key]: value,
}
: g
)
);
};
return (
<Section slim>
<form className="form form--internal" onSubmit={handleSubmit}>
<form
className={`form form--internal ${
!credential?.data && credential?.refetch ? "form--blur" : ""
}`}
onSubmit={handleSubmit}
>
<fieldset>
<MS>{MSG_REQUIRED_FIELDS}</MS>
</fieldset>
@@ -488,7 +674,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
</fieldset>
{vendor && (
<fieldset>
{vendor !== VENDOR_DEEPGRAM &&
{vendor !== VENDOR_ASSEMBLYAI &&
vendor !== VENDOR_COBALT &&
vendor !== VENDOR_SONIOX &&
vendor != VENDOR_CUSTOM && (
@@ -505,6 +691,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
)}
{vendor !== VENDOR_WELLSAID &&
vendor !== VENDOR_CUSTOM &&
vendor !== VENDOR_WHISPER &&
vendor !== VENDOR_ELEVENLABS && (
<label htmlFor="use_for_stt" className="chk">
<input
@@ -647,6 +834,166 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
</pre>
</fieldset>
)}
{ttsCheck && vendor === VENDOR_GOOGLE && (
<fieldset>
<label htmlFor="use_custom_voice" className="chk">
<input
id="use_custom_voice"
name="use_custom_voice"
type="checkbox"
onChange={(e) => {
if (customVoices.length === 0) {
setCustomVoices([
{
name: "",
reported_usage:
DEFAULT_GOOGLE_CUSTOM_VOICES_REPORTED_USAGE,
model: "",
},
]);
}
setUseCustomVoicesCheck(e.target.checked);
}}
checked={useCustomVoicesCheck}
/>
<div>Use custom voices</div>
</label>
{useCustomVoicesCheck && (
<fieldset>
<label htmlFor="sip_gateways">Custom Voices</label>
<MXS>
<em>At least one Custom voice is required.</em>
</MXS>
{customVoicesMessage && (
<Message message={customVoicesMessage} />
)}
{hasLength(customVoices) &&
customVoices.map((v, i) => (
<div key={`custom_voice_${i}`} className="customVoice">
<div>
<div>
<label htmlFor="custom_voice_name">
Name / Reported Usage
</label>
</div>
</div>
<div>
<div>
<input
id={`sip_ip_${i}`}
name={`sip_ip_${i}`}
type="text"
placeholder="Assigned Name"
required
value={v.name}
onChange={(e) => {
updateCustomVoices(i, "name", e.target.value);
}}
/>
</div>
<div>
<Selector
id={"google_custom_voices_reported_usage"}
name={"google_custom_voices_reported_usage"}
value={v.reported_usage}
options={GOOGLE_CUSTOM_VOICES_REPORTED_USAGE}
onChange={(e) => {
updateCustomVoices(
i,
"reported_usage",
e.target.value
);
}}
/>
</div>
</div>
<div>
<div>
<label htmlFor="custom_voice_name">Model</label>
</div>
</div>
<div>
<div>
<input
id={`sip_ip_${i}`}
name={`sip_ip_${i}`}
type="text"
placeholder="Model"
required
value={v.model}
style={{ maxWidth: "100%" }}
onChange={(e) => {
updateCustomVoices(
i,
"model",
e.target.value
);
}}
/>
</div>
</div>
<button
className="btnty"
title="Delete custom voice"
type="button"
onClick={() => {
setCustomVoicesMessage("");
if (customVoices.length === 1) {
setCustomVoicesMessage(
"You must provide at least one custom voice."
);
return;
}
if (v.google_custom_voice_sid) {
deleteGoogleCustomVoice(
v.google_custom_voice_sid
).finally(() => {
credential?.refetch();
});
}
setCustomVoices((prev) =>
prev.filter((_, idx) => idx !== i)
);
}}
>
<Icon>
<Icons.Trash2 />
</Icon>
</button>
</div>
))}
<ButtonGroup left>
<button
className="btnty"
type="button"
title="Add Voice"
onClick={() => {
setCustomVoicesMessage("");
setCustomVoices((prev) => [
...prev,
{
name: "",
reported_usage:
DEFAULT_GOOGLE_CUSTOM_VOICES_REPORTED_USAGE,
model: "",
},
]);
}}
>
<Icon subStyle="teal">
<Icons.Plus />
</Icon>
</button>
</ButtonGroup>
</fieldset>
)}
</fieldset>
)}
</>
)}
{vendor === VENDOR_NUANCE && (
@@ -787,8 +1134,9 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
</fieldset>
)}
{(vendor === VENDOR_WELLSAID ||
vendor === VENDOR_DEEPGRAM ||
vendor === VENDOR_ASSEMBLYAI ||
vendor == VENDOR_ELEVENLABS ||
vendor === VENDOR_WHISPER ||
vendor === VENDOR_SONIOX) && (
<fieldset>
<label htmlFor={`${vendor}_apikey`}>
@@ -805,20 +1153,117 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
/>
</fieldset>
)}
{vendor == VENDOR_ELEVENLABS && (
{vendor === VENDOR_DEEPGRAM && (
<fieldset>
<label htmlFor={`${vendor}_apikey`}>Model</label>
<Selector
id={"audio_format"}
name={"audio_format"}
value={ttsModelId}
options={ELEVENLABS_MODEL_OPTIONS}
onChange={(e) => {
setTtsModelId(e.target.value);
}}
<label htmlFor={`${vendor}_apikey`}>
API key{!isDeepgramOnpremEnabled && <span>*</span>}
</label>
<Passwd
id={`${vendor}_apikey`}
required={!isDeepgramOnpremEnabled}
name={`${vendor}_apikey`}
placeholder="API key"
value={apiKey ? getObscuredSecret(apiKey) : apiKey}
onChange={(e) => setApiKey(e.target.value)}
disabled={credential ? true : false}
/>
</fieldset>
)}
{(vendor == VENDOR_ELEVENLABS || vendor == VENDOR_WHISPER) &&
ttsModels.length > 0 && (
<fieldset>
<label htmlFor={`${vendor}_tts_model_id`}>Model</label>
<Selector
id={"tts_model_id"}
name={"tts_model_id"}
value={ttsModelId}
options={ttsModels}
onChange={(e) => {
setTtsModelId(e.target.value);
}}
/>
</fieldset>
)}
{vendor === VENDOR_ELEVENLABS && (
<fieldset>
<Checkzone
hidden
name="cz_speech_credential_options"
label="Extra Options"
initialCheck={optionsInitialChecked}
handleChecked={(e) => {
if (e.target.checked) {
setOptions(
tmpOptions
? tmpOptions
: JSON.stringify(DEFAULT_ELEVENLABS_OPTIONS, null, 2)
);
}
if (!e.target.checked) {
setTmpOptions(options);
setOptions("");
}
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "flex-end",
}}
>
<div
style={{
display: "flex",
alignItems: "center", // Align items vertically in the center
}}
>
<a
href="https://elevenlabs.io/docs/api-reference/streaming"
target="_blank"
rel="noopener noreferrer"
style={{ marginRight: "10px", fontSize: "16px" }}
>
Docs
</a>
<button
onClick={(e) => {
e.preventDefault();
if (options) {
setOptions((prev) => {
try {
return JSON.stringify(JSON.parse(options), null, 2);
} catch (err) {
return prev;
}
});
}
}}
style={{
background: "none",
border: "none",
cursor: "pointer",
color: "green",
fontSize: "16px",
}}
>
Beautify
</button>
</div>
<textarea
id="input_speech_credential_options"
name="speech_credential_options"
rows={6}
cols={55}
placeholder="extra options in Json"
value={options}
onChange={(e) => setOptions(e.target.value)}
/>
</div>
</Checkzone>
</fieldset>
)}
{regions &&
regions[vendor as keyof RegionVendors] &&
vendor !== VENDOR_IBM &&
@@ -916,6 +1361,57 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
/>
</fieldset>
)}
{vendor === VENDOR_DEEPGRAM && (
<fieldset>
<Checkzone
disabled={hasValue(credential)}
hidden
name="use_hosted_deepgram_service"
label="Use on-prem Deepgram container"
initialCheck={initialDeepgramOnpremCheck}
handleChecked={(e) => {
// setInitialDeepgramOnpremCheck(!e.target.checked);
setIsDeepgramOnpremEnabled(e.target.checked);
if (e.target.checked) {
if (tmpDeepgramSttUri) {
setDeepgramSttUri(tmpDeepgramSttUri);
}
if (tmpDeepgramSttUseTls) {
setDeepgramSttUseTls(tmpDeepgramSttUseTls);
}
} else {
setTmpDeepgramSttUri(deepgramSttUri);
setDeepgramSttUri("");
setTmpDeepgramSttUseTls(deepgramSttUseTls);
setDeepgramSttUseTls(false);
}
}}
>
<label htmlFor="deepgram_uri_for_tts">
Container URI<span>*</span>
</label>
<input
id="deepgram_uri_for_tts"
required
type="text"
name="deepgram_uri_for_tts"
placeholder="Container URI for TTS"
value={deepgramSttUri}
onChange={(e) => setDeepgramSttUri(e.target.value)}
/>
<label htmlFor="deepgram_tts_use_tls" className="chk">
<input
id="deepgram_tts_use_tls"
name="deepgram_tts_use_tls"
type="checkbox"
onChange={(e) => setDeepgramSttUseTls(e.target.checked)}
defaultChecked={deepgramSttUseTls}
/>
<div>Use TLS</div>
</label>
</Checkzone>
</fieldset>
)}
{vendor === VENDOR_MICROSOFT && (
<React.Fragment>
<fieldset>

View File

@@ -112,7 +112,7 @@ export const SpeechServices = () => {
</Icon>
</Link>
</section>
<section className="filters filters--ender">
<section className="filters filters--multi">
<ScopedAccess user={user} scope={Scope.service_provider}>
<AccountFilter
account={[accountSid, setAccountSid]}

View File

@@ -183,7 +183,12 @@ export const UserForm = ({ user }: UserFormProps) => {
return (
<>
<Section slim>
<form className="form form--internal" onSubmit={handleSubmit}>
<form
className={`form form--internal ${
!user?.data && user?.refetch ? "form--blur" : ""
}`}
onSubmit={handleSubmit}
>
<fieldset>
<MS>{MSG_REQUIRED_FIELDS}</MS>
</fieldset>

View File

@@ -88,7 +88,7 @@ export const Users = () => {
</Icon>
</Link>
</section>
<section className="filters filters--mix">
<section className="filters filters--multi">
<section>
<SearchFilter
placeholder="Filter users"

View File

@@ -105,6 +105,10 @@ fieldset {
}
}
&--blur {
pointer-events: none;
}
label {
@include ui-mixins.m();
@include ui-mixins.font-medium();
@@ -294,3 +298,53 @@ fieldset {
.bucket_tag {
@extend .lcr;
}
.customVoice {
padding: ui-vars.$px02;
border-radius: ui-vars.$px01;
border: 2px solid ui-vars.$grey;
max-width: ui-vars.$width-mobile;
position: relative;
> div {
display: grid;
grid-gap: ui-vars.$px02;
align-items: center;
&:nth-child(1) {
grid-template-columns: [col] 100%;
}
&:nth-child(2) {
grid-template-columns: [col] calc(40% - #{ui-vars.$px02 * 2}) [col] 60%;
margin-top: ui-vars.$px02;
}
&:nth-child(3) {
grid-template-columns: [col] 100%;
margin-top: ui-vars.$px02;
}
&:nth-child(4) {
grid-template-columns: [col] 100%;
margin-top: ui-vars.$px02;
}
}
> button {
position: absolute;
right: 0;
bottom: 50%;
transform: translate3d(50%, 50%, 0);
@include mixins.small() {
top: auto;
bottom: auto;
transform: none;
position: relative;
margin-top: ui-vars.$px02;
display: flex;
margin-left: auto;
}
}
}

100
src/vendor/index.tsx vendored
View File

@@ -1,11 +1,6 @@
import { useEffect, useState } from "react";
import type {
VendorOptions,
SynthesisVendors,
RecognizerVendors,
RegionVendors,
} from "./types";
import type { VendorOptions, RegionVendors } from "./types";
export const LANG_EN_US = "en-US";
export const ELEVENLABS_LANG_EN = "en";
@@ -23,6 +18,8 @@ export const VENDOR_SONIOX = "soniox";
export const VENDOR_CUSTOM = "custom";
export const VENDOR_COBALT = "cobalt";
export const VENDOR_ELEVENLABS = "elevenlabs";
export const VENDOR_ASSEMBLYAI = "assemblyai";
export const VENDOR_WHISPER = "whisper";
export const vendors: VendorOptions[] = [
{
@@ -73,6 +70,14 @@ export const vendors: VendorOptions[] = [
name: "ElevenLabs",
value: VENDOR_ELEVENLABS,
},
{
name: "AssemblyAI",
value: VENDOR_ASSEMBLYAI,
},
{
name: "Whisper",
value: VENDOR_WHISPER,
},
].sort((a, b) => a.name.localeCompare(b.name)) as VendorOptions[];
export const useRegionVendors = () => {
@@ -108,86 +113,3 @@ export const useRegionVendors = () => {
return regions;
};
export const useSpeechVendors = () => {
const [speech, setSpeech] = useState<{
synthesis?: SynthesisVendors;
recognizers?: RecognizerVendors;
}>({});
useEffect(() => {
let ignore = false;
Promise.all([
import("./speech-recognizer/aws-speech-recognizer-lang"),
import("./speech-recognizer/google-speech-recognizer-lang"),
import("./speech-recognizer/ms-speech-recognizer-lang"),
import("./speech-recognizer/nuance-speech-recognizer-lang"),
import("./speech-recognizer/deepgram-speech-recognizer-lang"),
import("./speech-recognizer/ibm-speech-recognizer-lang"),
import("./speech-recognizer/nvidia-speech-recognizer-lang"),
import("./speech-recognizer/soniox-speech-recognizer-lang"),
import("./speech-recognizer/cobalt-speech-recognizer-lang"),
import("./speech-synthesis/aws-speech-synthesis-lang"),
import("./speech-synthesis/google-speech-synthesis-lang"),
import("./speech-synthesis/ms-speech-synthesis-lang"),
import("./speech-synthesis/wellsaid-speech-synthesis-lang"),
import("./speech-synthesis/nuance-speech-synthesis-lang"),
import("./speech-synthesis/ibm-speech-synthesis-lang"),
import("./speech-synthesis/nvidia-speech-synthesis-lang"),
import("./speech-synthesis/elevellabs-speech-synthesis-lang"),
]).then(
([
{ default: awsRecognizer },
{ default: googleRecognizer },
{ default: msRecognizer },
{ default: nuanceRecognizer },
{ default: deepgramRecognizer },
{ default: ibmRecognizer },
{ default: nvidiaRecognizer },
{ default: sonioxRecognizer },
{ default: cobaltRecognizer },
{ default: awsSynthesis },
{ default: googleSynthesis },
{ default: msSynthesis },
{ default: wellsaidSynthesis },
{ default: nuanceSynthesis },
{ default: ibmSynthesis },
{ default: nvidiaynthesis },
{ default: elevenLabsSynthesis },
]) => {
if (!ignore) {
setSpeech({
synthesis: {
aws: awsSynthesis,
google: googleSynthesis,
microsoft: msSynthesis,
wellsaid: wellsaidSynthesis,
nuance: nuanceSynthesis,
ibm: ibmSynthesis,
nvidia: nvidiaynthesis,
elevenlabs: elevenLabsSynthesis,
},
recognizers: {
aws: awsRecognizer,
google: googleRecognizer,
microsoft: msRecognizer,
nuance: nuanceRecognizer,
deepgram: deepgramRecognizer,
ibm: ibmRecognizer,
nvidia: nvidiaRecognizer,
soniox: sonioxRecognizer,
cobalt: cobaltRecognizer,
},
});
}
}
);
return function cleanup() {
ignore = true;
};
}, []);
return speech;
};

View File

@@ -1,14 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{ name: "Australian English", code: "en-AU" },
{ name: "British English", code: "en-GB" },
{ name: "US English", code: "en-US" },
{ name: "French", code: "fr-FR" },
{ name: "Canadian French", code: "fr-CA" },
{ name: "German", code: "de-DE" },
{ name: "Italian", code: "it-IT" },
{ name: "US Spanish", code: "es-US" },
];
export default languages;

View File

@@ -1,30 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{
name: "English US",
code: "en_US-8khz",
},
{
name: "English UK",
code: "en_UK-8khz",
},
{
name: "Spanish",
code: "es_xx-8khz",
},
{
name: "French",
code: "fr_fr-8khz",
},
{
name: "Russian",
code: "ru_ru-8khz",
},
{
name: "Portuguese",
code: "pt_br-8khz",
},
];
export default languages;

View File

@@ -1,126 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{
name: "Chinese - general",
code: "zh",
},
{
name: "Chinese (China)",
code: "zh-CN",
},
{
name: "Chinese (Taiwan)",
code: "zh-TW",
},
{
name: "Dutch - general",
code: "nl",
},
{
name: "English - general",
code: "en",
},
{
name: "English (Australia)",
code: "en-AU",
},
{
name: "English (United Kingdom)",
code: "en-GB",
},
{
name: "English (India)",
code: "en-IN",
},
{
name: "English (New Zealand)",
code: "en-NZ",
},
{
name: "English (United States)",
code: "en-US",
},
{
name: "French - general",
code: "fr",
},
{
name: "French (Canada)",
code: "fr-CA",
},
{
name: "German - general",
code: "de",
},
{
name: "Hindi - general",
code: "hi",
},
{
name: "Hindi (Roman Script)",
code: "hi-Latin",
},
{
name: "Indonesian - general",
code: "in",
},
{
name: "Italian - general",
code: "it",
},
{
name: "Japanese - general",
code: "ja",
},
{
name: "Korean - general",
code: "ko",
},
{
name: "Norwegian - general",
code: "no",
},
{
name: "Polish - general",
code: "pl",
},
{
name: "Portuguese - general",
code: "pt",
},
{
name: "Portuguese (Brazil)",
code: "pt-BR",
},
{
name: "Portuguese (Portugal)",
code: "pt-PT",
},
{
name: "Russian - general",
code: "ru",
},
{
name: "Spanish - general",
code: "es",
},
{
name: "Spanish (Latin America)",
code: "es-419",
},
{
name: "Swedish - general",
code: "sv",
},
{
name: "Turkish - general",
code: "tr",
},
{
name: "Ukrainian - general",
code: "uk",
},
];
export default languages;

View File

@@ -1,134 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{ name: "Afrikaans (South Africa)", code: "af-ZA" },
{ name: "Albanian (Albania)", code: "sq-AL" },
{ name: "Amharic (Ethiopia)", code: "am-ET" },
{ name: "Arabic (Algeria)", code: "ar-DZ" },
{ name: "Arabic (Bahrain)", code: "ar-BH" },
{ name: "Arabic (Egypt)", code: "ar-EG" },
{ name: "Arabic (Iraq)", code: "ar-IQ" },
{ name: "Arabic (Israel)", code: "ar-IL" },
{ name: "Arabic (Jordan)", code: "ar-JO" },
{ name: "Arabic (Kuwait)", code: "ar-KW" },
{ name: "Arabic (Lebanon)", code: "ar-LB" },
{ name: "Arabic (Morocco)", code: "ar-MA" },
{ name: "Arabic (Oman)", code: "ar-OM" },
{ name: "Arabic (Qatar)", code: "ar-QA" },
{ name: "Arabic (Saudi Arabia)", code: "ar-SA" },
{ name: "Arabic (State of Palestine)", code: "ar-PS" },
{ name: "Arabic (Tunisia)", code: "ar-TN" },
{ name: "Arabic (United Arab Emirates)", code: "ar-AE" },
{ name: "Armenian (Armenia)", code: "hy-AM" },
{ name: "Azerbaijani (Azerbaijan)", code: "az-AZ" },
{ name: "Basque (Spain)", code: "eu-ES" },
{ name: "Bengali (Bangladesh)", code: "bn-BD" },
{ name: "Bengali (India)", code: "bn-IN" },
{ name: "Bulgarian (Bulgaria)", code: "bg-BG" },
{ name: "Burmese (Myanmar)", code: "my-MM" },
{ name: "Catalan (Spain)", code: "ca-ES" },
{ name: "Chinese, Cantonese (Traditional, Hong Kong)", code: "yue-Hant-HK" },
{ name: "Chinese, Mandarin (Simplified, China)", code: "zh" },
{ name: "Chinese, Mandarin (Simplified, Hong Kong)", code: "zh-HK" },
{ name: "Chinese, Mandarin (Simplified, Taiwan)", code: "zh-TW" },
{ name: "Croatian (Croatia)", code: "hr-HR" },
{ name: "Czech (Czech Republic)", code: "cs-CZ" },
{ name: "Danish (Denmark)", code: "da-DK" },
{ name: "Dutch (Belgium)", code: "nl-BE" },
{ name: "Dutch (Netherlands)", code: "nl-NL" },
{ name: "English (Australia)", code: "en-AU" },
{ name: "English (Canada)", code: "en-CA" },
{ name: "English (Ghana)", code: "en-GH" },
{ name: "English (India)", code: "en-IN" },
{ name: "English (Ireland)", code: "en-IE" },
{ name: "English (Kenya)", code: "en-KE" },
{ name: "English (New Zealand)", code: "en-NZ" },
{ name: "English (Nigeria)", code: "en-NG" },
{ name: "English (Philippines)", code: "en-PH" },
{ name: "English (Singapore)", code: "en-SG" },
{ name: "English (South Africa)", code: "en-ZA" },
{ name: "English (Tanzania)", code: "en-TZ" },
{ name: "English (United Kingdom)", code: "en-GB" },
{ name: "English (United States)", code: "en-US" },
{ name: "Estonian (Estonia)", code: "et-EE" },
{ name: "Filipino (Philippines)", code: "fil-PH" },
{ name: "Finnish (Finland)", code: "fi-FI" },
{ name: "French (Canada)", code: "fr-CA" },
{ name: "French (France)", code: "fr-FR" },
{ name: "Galician (Spain)", code: "gl-ES" },
{ name: "Georgian (Georgia)", code: "ka-GE" },
{ name: "German (Germany)", code: "de-DE" },
{ name: "Greek (Greece)", code: "el-GR" },
{ name: "Gujarati (India)", code: "gu-IN" },
{ name: "Hebrew (Israel)", code: "he-IL" },
{ name: "Hindi (India)", code: "hi-IN" },
{ name: "Hungarian (Hungary)", code: "hu-HU" },
{ name: "Icelandic (Iceland)", code: "is-IS" },
{ name: "Indonesian (Indonesia)", code: "id-ID" },
{ name: "Italian (Italy)", code: "it-IT" },
{ name: "Japanese (Japan)", code: "ja-JP" },
{ name: "Javanese (Indonesia)", code: "jv-ID" },
{ name: "Kannada (India)", code: "kn-IN" },
{ name: "Khmer (Cambodia)", code: "km-KH" },
{ name: "Korean (South Korea)", code: "ko-KR" },
{ name: "Lao (Laos)", code: "lo-LA" },
{ name: "Latvian (Latvia)", code: "lv-LV" },
{ name: "Lithuanian (Lithuania)", code: "lt-LT" },
{ name: "Macedonian (North Macedonia)", code: "mk-MK" },
{ name: "Malay (Malaysia)", code: "ms-MY" },
{ name: "Malayalam (India)", code: "ml-IN" },
{ name: "Marathi (India)", code: "mr-IN" },
{ name: "Mongolian (Mongolia)", code: "mn-MN" },
{ name: "Nepali (Nepal)", code: "ne-NP" },
{ name: "Norwegian Bokmål (Norway)", code: "nb-NO" },
{ name: "Persian (Iran)", code: "fa-IR" },
{ name: "Polish (Poland)", code: "pl-PL" },
{ name: "Portuguese (Brazil)", code: "pt-BR" },
{ name: "Portuguese (Portugal)", code: "pt-PT" },
{ name: "Punjabi (Gurmukhi, India)", code: "pa-guru-IN" },
{ name: "Romanian (Romania)", code: "ro-RO" },
{ name: "Russian (Russia)", code: "ru-RU" },
{ name: "Serbian (Serbia)", code: "sr-RS" },
{ name: "Sinhala (Sri Lanka)", code: "si-LK" },
{ name: "Slovak (Slovakia)", code: "sk-SK" },
{ name: "Slovenian (Slovenia)", code: "sl-SI" },
{ name: "Spanish (Argentina)", code: "es-AR" },
{ name: "Spanish (Bolivia)", code: "es-BO" },
{ name: "Spanish (Chile)", code: "es-CL" },
{ name: "Spanish (Colombia)", code: "es-CO" },
{ name: "Spanish (Costa Rica)", code: "es-CR" },
{ name: "Spanish (Dominican Republic)", code: "es-DO" },
{ name: "Spanish (Ecuador)", code: "es-EC" },
{ name: "Spanish (El Salvador)", code: "es-SV" },
{ name: "Spanish (Guatemala)", code: "es-GT" },
{ name: "Spanish (Honduras)", code: "es-HN" },
{ name: "Spanish (Mexico)", code: "es-MX" },
{ name: "Spanish (Nicaragua)", code: "es-NI" },
{ name: "Spanish (Panama)", code: "es-PA" },
{ name: "Spanish (Paraguay)", code: "es-PY" },
{ name: "Spanish (Peru)", code: "es-PE" },
{ name: "Spanish (Puerto Rico)", code: "es-PR" },
{ name: "Spanish (Spain)", code: "es-ES" },
{ name: "Spanish (United States)", code: "es-US" },
{ name: "Spanish (Uruguay)", code: "es-UY" },
{ name: "Spanish (Venezuela)", code: "es-VE" },
{ name: "Sundanese (Indonesia)", code: "su-ID" },
{ name: "Swahili (Kenya)", code: "sw-KE" },
{ name: "Swahili (Tanzania)", code: "sw-TZ" },
{ name: "Swedish (Sweden)", code: "sv-SE" },
{ name: "Tamil (India)", code: "ta-IN" },
{ name: "Tamil (Malaysia)", code: "ta-MY" },
{ name: "Tamil (Singapore)", code: "ta-SG" },
{ name: "Tamil (Sri Lanka)", code: "ta-LK" },
{ name: "Telugu (India)", code: "te-IN" },
{ name: "Thai (Thailand)", code: "th-TH" },
{ name: "Turkish (Turkey)", code: "tr-TR" },
{ name: "Ukrainian (Ukraine)", code: "uk-UA" },
{ name: "Urdu (India)", code: "ur-IN" },
{ name: "Urdu (Pakistan)", code: "ur-PK" },
{ name: "Uzbek (Uzbekistan)", code: "uz-UZ" },
{ name: "Vietnamese (Vietnam)", code: "vi-VN" },
{ name: "Zulu (South Africa)", code: "zu-ZA" },
];
export default languages;

View File

@@ -1,86 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{
name: "Arabic (Modern Standard)",
code: "ar-MS_Telephony",
},
{
name: "Chinese (Mandarin)",
code: "zh-CN_Telephony",
},
{
name: "Czech ",
code: "cs-CZ_Telephony",
},
{
name: "Dutch (Belgian)",
code: "nl-BE_Telephony",
},
{
name: "Dutch (Netherlands)",
code: "nl-NL_Telephony",
},
{
name: "English (all supported dialects)",
code: "en-WW_Medical_Telephony",
},
{
name: "English (Australian)",
code: "en-AU_Telephony",
},
{
name: "English (Indian)",
code: "en-IN_Telephony",
},
{
name: "English (United Kingdom)",
code: "en-GB_Telephony",
},
{
name: "English (United States)",
code: "en-US_Telephony",
},
{
name: "French (Canadian)",
code: "fr-CA_Telephony",
},
{
name: "French (France)",
code: "fr-FR_Telephony",
},
{
name: "German",
code: "de-DE_Telephony",
},
{
name: "Hindi (Indian)",
code: "hi-IN_Telephony",
},
{
name: "Italian",
code: "it-IT_Telephony",
},
{
name: "Korean",
code: "ko-KR_Telephony",
},
{
name: "Portuguese (Brazilian)",
code: "pt-BR_Telephony",
},
{
name: "Spanish (Mexican)",
code: "es-LA_Telephony",
},
{
name: "Spanish (Castilian)",
code: "es-ES_Telephony",
},
{
name: "Swedish ",
code: "sv-SE_Telephony",
},
];
export default languages;

View File

@@ -1,494 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{
name: "Afrikaans (South Africa)",
code: "af-ZA",
},
{
name: "Amharic (Ethiopia)",
code: "am-ET",
},
{
name: "Arabic (Algeria)",
code: "ar-DZ",
},
{
name: "Arabic (Bahrain)",
code: "ar-BH",
},
{
name: "Arabic (Egypt)",
code: "ar-EG",
},
{
name: "Arabic (Iraq)",
code: "ar-IQ",
},
{
name: "Arabic (Israel)",
code: "ar-IL",
},
{
name: "Arabic (Jordan)",
code: "ar-JO",
},
{
name: "Arabic (Kuwait)",
code: "ar-KW",
},
{
name: "Arabic (Lebanon)",
code: "ar-LB",
},
{
name: "Arabic (Libya)",
code: "ar-LY",
},
{
name: "Arabic (Morocco)",
code: "ar-MA",
},
{
name: "Arabic (Oman)",
code: "ar-OM",
},
{
name: "Arabic (Qatar)",
code: "ar-QA",
},
{
name: "Arabic (Saudi Arabia)",
code: "ar-SA",
},
{
name: "Arabic (Palestinian Authority)",
code: "ar-PS",
},
{
name: "Arabic (Syria)",
code: "ar-SY",
},
{
name: "Arabic (Tunisia)",
code: "ar-TN",
},
{
name: "Arabic (United Arab Emirates)",
code: "ar-AE",
},
{
name: "Arabic (Yemen)",
code: "ar-YE",
},
{
name: "Bulgarian (Bulgaria)",
code: "bg-BG",
},
{
name: "Bengali (India)",
code: "bn-IN",
},
{
name: "Catalan (Spain)",
code: "ca-ES",
},
{
name: "Chinese (Cantonese, Traditional)",
code: "zh-HK",
},
{
name: "Chinese (Mandarin, Simplified)",
code: "zh-CN",
},
{
name: "Chinese (Taiwanese Mandarin)",
code: "zh-TW",
},
{
name: "Croatian (Croatia)",
code: "hr-HR",
},
{
name: "Czech (Czech)",
code: "cs-CZ",
},
{
name: "Danish (Denmark)",
code: "da-DK",
},
{
name: "Dutch (Netherlands)",
code: "nl-NL",
},
{
name: "Dutch (Belgium)",
code: "nl-BE",
},
{
name: "English (Australia)",
code: "en-AU",
},
{
name: "English (Canada)",
code: "en-CA",
},
{
name: "English (Ghana)",
code: "en-GH",
},
{
name: "English (Hong Kong)",
code: "en-HK",
},
{
name: "English (India)",
code: "en-IN",
},
{
name: "English (Ireland)",
code: "en-IE",
},
{
name: "English (Kenya)",
code: "en-KE",
},
{
name: "English (New Zealand)",
code: "en-NZ",
},
{
name: "English (Nigeria)",
code: "en-NG",
},
{
name: "English (Philippines)",
code: "en-PH",
},
{
name: "English (Singapore)",
code: "en-SG",
},
{
name: "English (South Africa)",
code: "en-ZA",
},
{
name: "English (Tanzania)",
code: "en-TZ",
},
{
name: "English (United Kingdom)",
code: "en-GB",
},
{
name: "English (United States)",
code: "en-US",
},
{
name: "Estonian(Estonia)",
code: "et-EE",
},
{
name: "Filipino (Philippines)",
code: "fil-PH",
},
{
name: "Finnish (Finland)",
code: "fi-FI",
},
{
name: "French (Belgium)",
code: "fr-BE",
},
{
name: "French (Canada)",
code: "fr-CA",
},
{
name: "French (France)",
code: "fr-FR",
},
{
name: "French (Switzerland)",
code: "fr-CH",
},
{
name: "German (Austria)",
code: "de-AT",
},
{
name: "German (Switzerland)",
code: "de-CH",
},
{
name: "German (Germany)",
code: "de-DE",
},
{
name: "Greek (Greece)",
code: "el-GR",
},
{
name: "Gujarati (Indian)",
code: "gu-IN",
},
{
name: "Hebrew (Israel)",
code: "he-IL",
},
{
name: "Hindi (India)",
code: "hi-IN",
},
{
name: "Hungarian (Hungary)",
code: "hu-HU",
},
{
name: "Indonesian (Indonesia)",
code: "id-ID",
},
{
name: "Icelandic (Iceland)",
code: "is-IS",
},
{
name: "Irish (Ireland)",
code: "ga-IE",
},
{
name: "Italian (Italy)",
code: "it-IT",
},
{
name: "Japanese (Japan)",
code: "ja-JP",
},
{
name: "Javanese (Indonesia)",
code: "jv-ID",
},
{
name: "Kannada (India)",
code: "kn-IN",
},
{
name: "Khmer (Cambodia)",
code: "km-KH",
},
{
name: "Korean (Korea)",
code: "ko-KR",
},
{
name: "Latvian (Latvia)",
code: "lv-LV",
},
{
name: "Lao (Laos)",
code: "lo-LA",
},
{
name: "Lithuanian (Lithuania)",
code: "lt-LT",
},
{
name: "Malay (Malaysia)",
code: "ms-MY",
},
{
name: "Macedonian (North Macedonia)",
code: "mk-MK",
},
{
name: "Maltese (Malta)",
code: "mt-MT",
},
{
name: "Marathi (India)",
code: "mr-IN",
},
{
name: "Burmese (Myanmar)",
code: "my-MM",
},
{
name: "Norwegian (Bokmål, Norway)",
code: "nb-NO",
},
{
name: "Persian (Iran)",
code: "fa-IR",
},
{
name: "Polish (Poland)",
code: "pl-PL",
},
{
name: "Portuguese (Brazil)",
code: "pt-BR",
},
{
name: "Portuguese (Portugal)",
code: "pt-PT",
},
{
name: "Romanian (Romania)",
code: "ro-RO",
},
{
name: "Russian (Russia)",
code: "ru-RU",
},
{
name: "Slovak (Slovakia)",
code: "sk-SK",
},
{
name: "Slovenian (Slovenia)",
code: "sl-SI",
},
{
name: "Spanish (Argentina)",
code: "es-AR",
},
{
name: "Spanish (Bolivia)",
code: "es-BO",
},
{
name: "Spanish (Chile)",
code: "es-CL",
},
{
name: "Spanish (Colombia)",
code: "es-CO",
},
{
name: "Spanish (Costa Rica)",
code: "es-CR",
},
{
name: "Spanish (Cuba)",
code: "es-CU",
},
{
name: "Spanish (Dominican Republic)",
code: "es-DO",
},
{
name: "Spanish (Ecuador)",
code: "es-EC",
},
{
name: "Spanish (El Salvador)",
code: "es-SV",
},
{
name: "Spanish (Equatorial Guinea)",
code: "es-GQ",
},
{
name: "Spanish (Guatemala)",
code: "es-GT",
},
{
name: "Spanish (Honduras)",
code: "es-HN",
},
{
name: "Spanish (Mexico)",
code: "es-MX",
},
{
name: "Spanish (Nicaragua)",
code: "es-NI",
},
{
name: "Spanish (Panama)",
code: "es-PA",
},
{
name: "Spanish (Paraguay)",
code: "es-PY",
},
{
name: "Spanish (Peru)",
code: "es-PE",
},
{
name: "Spanish (Puerto Rico)",
code: "es-PR",
},
{
name: "Spanish (Spain)",
code: "es-ES",
},
{
name: "Spanish (Uruguay)",
code: "es-UY",
},
{
name: "Spanish (USA)",
code: "es-US",
},
{
name: "Spanish (Venezuela)",
code: "es-VE",
},
{
name: "Swahili (Kenya)",
code: "sw-KE",
},
{
name: "Swahili (Tanzania)",
code: "sw-TZ",
},
{
name: "Sinhala (Sri Lanka)",
code: "si-LK",
},
{
name: "Swedish (Sweden)",
code: "sv-SE",
},
{
name: "Serbian (Serbia)",
code: "sr-RS",
},
{
name: "Tamil (India)",
code: "ta-IN",
},
{
name: "Telugu (India)",
code: "te-IN",
},
{
name: "Thai (Thailand)",
code: "th-TH",
},
{
name: "Turkish (Turkey)",
code: "tr-TR",
},
{
name: "Ukrainian (Ukraine)",
code: "uk-UA",
},
{
name: "Uzbek (Uzbekistan)",
code: "uz-UZ",
},
{
name: "Zulu (South Africa)",
code: "zu-ZA",
},
{
name: "Vietnamese (Vietnam)",
code: "vi-VN",
},
];
export default languages;

View File

@@ -1,211 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{
name: "Arabic (Worldwide)",
code: "ar-WW",
codeMix: "ara-XWW",
},
{
name: "Catalan (Spain)",
code: "ca-ES",
codeMix: "cat-ESP",
},
{
name: "Croatian (Croatia)",
code: "hr-HR",
codeMix: "hrv-HRV",
},
{
name: "Czech (Czech Republic)",
code: "cs-CZ",
codeMix: "ces-CZE",
},
{
name: "Danish (Denmark)",
code: "da-DK",
codeMix: "dan-DNK",
},
{
name: "Dutch (Netherlands)",
code: "nl-NL",
codeMix: "nld-NLD",
},
{
name: "English (Australia)",
code: "en-AU",
codeMix: "eng-AUS",
},
{
name: "English (United States)",
code: "en-US",
codeMix: "eng-USA",
},
{
name: "English (India)",
code: "en-IN",
codeMix: "eng-IND",
},
{
name: "English (United Kingdom)",
code: "en-GB",
codeMix: "eng-GBR",
},
{
name: "Finnish (Finland)",
code: "fi-FI",
codeMix: "fin-FIN",
},
{
name: "French (Canada)",
code: "fr-CA",
codeMix: "fra-CAN",
},
{
name: "French (France)",
code: "fr-FR",
codeMix: "fra-FRA",
},
{
name: "German (Germany)",
code: "de-DE",
codeMix: "deu-DEU",
},
{
name: "Greek (Greece)",
code: "el-GR",
codeMix: "ell-GRC",
},
{
name: "Hebrew (Israel)",
code: "he-IL",
codeMix: "heb-ISR",
},
{
name: "Hindi (India)",
code: "hi-IN",
codeMix: "hin-IND",
},
{
name: "Hungarian (Hungary)",
code: "hu-HU",
codeMix: "hun-HUN",
},
{
name: "Indonesian (Indonesia)",
code: "id-ID",
codeMix: "ind-IDN",
},
{
name: "Italian (Italy)",
code: "it-IT",
codeMix: "ita-ITA",
},
{
name: "Japanese (Japan)",
code: "ja-JP",
codeMix: "jpn-JPN",
},
{
name: "Korean (South Korea)",
code: "ko-KR",
codeMix: "kor-KOR",
},
{
name: "Malay (Malaysia)",
code: "ms-MY",
codeMix: "zlm-MYS",
},
{
name: "Norwegian (Norway)",
code: "no-NO",
codeMix: "nor-NOR",
},
{
name: "Polish (Poland)",
code: "pl-PL",
codeMix: "pol-POL",
},
{
name: "Portuguese (Brazil)",
code: "pt-BR",
codeMix: "por-BRA",
},
{
name: "Portuguese (Portugal)",
code: "pt-PT",
codeMix: "por-PRT",
},
{
name: "Romanian (Romania)",
code: "ro-RO",
codeMix: "ron-ROU",
},
{
name: "Russian (Russia)",
code: "ru-RU",
codeMix: "rus-RUS",
},
{
name: "Shanghainese (China)",
code: "zh-WU",
codeMix: "wuu-CHN",
},
{
name: "Mandarin (China)",
code: "zh-CN",
codeMix: "cmn-CHN",
},
{
name: "Slovak (Slovakia)",
code: "sk-SK",
codeMix: "slk-SVK",
},
{
name: "Spanish (Spain)",
code: "es-ES",
codeMix: "spa-ESP",
},
{
name: "Spanish (Latin America)",
code: "es-US",
codeMix: "spa-XLA",
},
{
name: "Swedish (Sweden)",
code: "sv-SE",
codeMix: "swe-SWE",
},
{
name: "Thai (Thailand)",
code: "th-TH",
codeMix: "tha-THA",
},
{
name: "Cantonese (Hong Kong)",
code: "cn-HK",
codeMix: "yue-CHS",
},
{
name: "Mandarin (Taiwan)",
code: "zh-TW",
codeMix: "cmn-TWN",
},
{
name: "Turkish (Turkey)",
code: "tr-TR",
codeMix: "tur-TUR",
},
{
name: "Ukrainian (Ukraine)",
code: "uk-UA",
codeMix: "ukr-UKR",
},
{
name: "Vietnamese (Vietnam)",
code: "vi-VN",
codeMix: "vie-VNM",
},
];
export default languages;

View File

@@ -1,62 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{
name: "Arabic",
code: "ar-AR",
},
{
name: "English",
code: "en-US",
},
{
name: "English - GB",
code: "en-GB",
},
{
name: "Spanish - US",
code: "es-US",
},
{
name: "Spanish",
code: "es-ES",
},
{
name: "German",
code: "de-DE",
},
{
name: "French",
code: "fr-FR",
},
{
name: "Hindi",
code: "hi-IN",
},
{
name: "Russian",
code: "ru-RU",
},
{
name: "Korean",
code: "ko-KR",
},
{
name: "Brazilian-Portuguese",
code: "pt-BR",
},
{
name: "Japanese",
code: "ja-JP",
},
{
name: "Italian",
code: "it-IT",
},
{
name: "Mandarin",
code: "zh-CN",
},
];
export default languages;

View File

@@ -1,10 +0,0 @@
import type { Language } from "../types";
export const languages: Language[] = [
{
name: "English (United States)",
code: "en-US",
},
];
export default languages;

View File

@@ -1,217 +0,0 @@
import type { VoiceLanguage } from "../types";
export const languages: VoiceLanguage[] = [
{
code: "arb",
name: "Arabic",
voices: [{ value: "Zeina", name: "Zeina (Female)" }],
},
{
code: "cmn-CN",
name: "Chinese, Mandarin",
voices: [{ value: "Zhiyu", name: "Zhiyu (Female)" }],
},
{
code: "da-DK",
name: "Danish",
voices: [
{ value: "Naja", name: "Naja (Female)" },
{ value: "Mads", name: "Mads (Male)" },
],
},
{
code: "nl-NL",
name: "Dutch",
voices: [
{ value: "Lotte", name: "Lotte (Female)" },
{ value: "Ruben", name: "Ruben (Male)" },
],
},
{
code: "en-AU",
name: "English (Australian)",
voices: [
{ value: "Nicole", name: "Nicole (Female)" },
{ value: "Russell", name: "Russell (Male)" },
],
},
{
code: "en-GB",
name: "English (British)",
voices: [
{ value: "Amy", name: "Amy (Female)" },
{ value: "Emma", name: "Emma (Female)" },
{ value: "Brian", name: "Brian (Male)" },
],
},
{
code: "en-IN",
name: "English (Indian)",
voices: [
{ value: "Aditi", name: "Aditi (Female)" },
{ value: "Raveena", name: "Raveena (Female)" },
],
},
{
code: "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)" },
],
},
{
code: "en-GB-WLS",
name: "English (Welsh)",
voices: [{ value: "Geraint", name: "Geraint (Male)" }],
},
{
code: "fr-FR",
name: "French",
voices: [
{ value: "Celine", name: "Céline (Female)" },
{ value: "Lea", name: "Léa (Female)" },
{ value: "Mathieu", name: "Mathieu (Male)" },
],
},
{
code: "fr-CA",
name: "French (Canadian)",
voices: [{ value: "Chantal", name: "Chantal (Female)" }],
},
{
code: "de-DE",
name: "German",
voices: [
{ value: "Marlene", name: "Marlene (Female)" },
{ value: "Vicki", name: "Vicki (Female)" },
{ value: "Hans", name: "Hans (Male)" },
],
},
{
code: "hi-IN",
name: "Hindi",
voices: [{ value: "Aditi", name: "Aditi (Female)" }],
},
{
code: "is-IS",
name: "Icelandic",
voices: [
{ value: "Dora", name: "Dóra (Female)" },
{ value: "Karl", name: "Karl (Male)" },
],
},
{
code: "it-IT",
name: "Italian",
voices: [
{ value: "Carla", name: "Carla (Female)" },
{ value: "Bianca", name: "Bianca (Female)" },
{ value: "Giorgio", name: "Giorgio (Male)" },
],
},
{
code: "ja-JP",
name: "Japanese",
voices: [
{ value: "Mizuki", name: "Mizuki (Female)" },
{ value: "Takumi", name: "Takumi (Male)" },
],
},
{
code: "ko-KR",
name: "Korean",
voices: [{ value: "Seoyeon", name: "Seoyeon (Female)" }],
},
{
code: "nb-NO",
name: "Norwegian",
voices: [{ value: "Liv", name: "Liv (Female)" }],
},
{
code: "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)" },
],
},
{
code: "pt-BR",
name: "Portuguese (Brazilian)",
voices: [
{ value: "Camila", name: "Camila (Female)" },
{ value: "Vitoria", name: "Vitória (Female)" },
{ value: "Ricardo", name: "Ricardo (Male)" },
],
},
{
code: "pt-PT",
name: "Portuguese (European)",
voices: [
{ value: "Ines", name: "Inês (Female)" },
{ value: "Cristiano", name: "Cristiano (Male)" },
],
},
{
code: "ro-RO",
name: "Romanian",
voices: [{ value: "Carmen", name: "Carmen (Female)" }],
},
{
code: "ru-RU",
name: "Russian",
voices: [
{ value: "Tatyana", name: "Tatyana (Female)" },
{ value: "Maxim", name: "Maxim (Male)" },
],
},
{
code: "es-ES",
name: "Spanish (European)",
voices: [
{ value: "Conchita", name: "Conchita (Female)" },
{ value: "Lucia", name: "Lucia (Female)" },
{ value: "Enrique", name: "Enrique (Male)" },
],
},
{
code: "es-MX",
name: "Spanish (Mexican)",
voices: [{ value: "Mia", name: "Mia (Female)" }],
},
{
code: "es-US",
name: "Spanish (US)",
voices: [
{ value: "Lupe", name: "Lupe (Female)" },
{ value: "Penelope", name: "Penélope (Female)" },
{ value: "Miguel", name: "Miguel (Male)" },
],
},
{
code: "sv-SE",
name: "Swedish",
voices: [{ value: "Astrid", name: "Astrid (Female)" }],
},
{
code: "tr-TR",
name: "Turkish",
voices: [{ value: "Filiz", name: "Filiz (Female)" }],
},
{
code: "cy-GB",
name: "Welsh",
voices: [{ value: "Gwyneth", name: "Gwyneth (Female)" }],
},
];
export default languages;

View File

@@ -1,196 +0,0 @@
import type { VoiceLanguage } from "../types";
export const languages: VoiceLanguage[] = [
{
code: "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",
},
],
},
{ code: "bg", name: "Bulgarian", voices: [] },
{ code: "zh", name: "Chinese", voices: [] },
{ code: "hr", name: "Croatian", voices: [] },
{ code: "cs", name: "Czech", voices: [] },
{ code: "da", name: "Danish", voices: [] },
{ code: "nl", name: "Dutch", voices: [] },
{ code: "en", name: "English", voices: [] },
{ code: "fil", name: "Filipino", voices: [] },
{ code: "fi", name: "Finnish", voices: [] },
{ code: "fr", name: "French", voices: [] },
{ code: "de", name: "German", voices: [] },
{ code: "el", name: "Greek", voices: [] },
{ code: "hi", name: "Hindi", voices: [] },
{ code: "id", name: "Indonesian", voices: [] },
{ code: "it", name: "Italian", voices: [] },
{ code: "ja", name: "Japanese", voices: [] },
{ code: "ko", name: "Korean", voices: [] },
{ code: "ms", name: "Malay", voices: [] },
{ code: "pl", name: "Polish", voices: [] },
{ code: "pt", name: "Portuguese", voices: [] },
{ code: "ro", name: "Romanian", voices: [] },
{ code: "ru", name: "Russian", voices: [] },
{ code: "sk", name: "Slovak", voices: [] },
{ code: "es", name: "Spanish", voices: [] },
{ code: "sv", name: "Swedish", voices: [] },
{ code: "ta", name: "Tamil", voices: [] },
{ code: "tr", name: "Turkish", voices: [] },
{ code: "uk", name: "Ukrainian", voices: [] },
];
export default languages;

View File

@@ -1,513 +0,0 @@
import type { VoiceLanguage } from "../types";
export const languages: VoiceLanguage[] = [
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "fi-FI",
name: "Finnish (Finland)",
voices: [
{ value: "fi-FI-Standard-A", name: "Standard-A (Female)" },
{ value: "fi-FI-Wavenet-A", name: "Wavenet-A (Female)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "el-GR",
name: "Greek (Greece)",
voices: [
{ value: "el-GR-Standard-A", name: "Standard-A (Female)" },
{ value: "el-GR-Wavenet-A", name: "Wavenet-A (Female)" },
],
},
{
code: "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)" },
],
},
{
code: "hu-HU",
name: "Hungarian (Hungary)",
voices: [
{ value: "hu-HU-Standard-A", name: "Standard-A (Female)" },
{ value: "hu-HU-Wavenet-A", name: "Wavenet-A (Female)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "sk-SK",
name: "Slovak (Slovakia)",
voices: [
{ value: "sk-SK-Standard-A", name: "Standard-A (Female)" },
{ value: "sk-SK-Wavenet-A", name: "Wavenet-A (Female)" },
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "sv-SE",
name: "Swedish (Sweden)",
voices: [
{ value: "sv-SE-Standard-A", name: "Standard-A (Female)" },
{ value: "sv-SE-Wavenet-A", name: "Wavenet-A (Female)" },
],
},
{
code: "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)" },
],
},
{
code: "uk-UA",
name: "Ukrainian (Ukraine)",
voices: [
{ value: "uk-UA-Standard-A", name: "Standard-A (Female)" },
{ value: "uk-UA-Wavenet-A", name: "Wavenet-A (Female)" },
],
},
{
code: "th-TH",
name: "Thai (Thailand)",
voices: [{ value: "th-TH-Neural2-C", name: "Neural2-C (Female)" }],
},
{
code: "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)" },
],
},
];
export default languages;

View File

@@ -1,171 +0,0 @@
import type { VoiceLanguage } from "../types";
export const languages: VoiceLanguage[] = [
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "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)" },
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "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)" },
],
},
{
code: "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)" },
],
},
{
code: "fr-CA",
name: "French (CA)",
voices: [{ value: "fr-CA_LouiseV3Voice", name: "Louise (Female)" }],
},
{
code: "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)" },
],
},
{
code: "pt-BR",
name: "Portuguese (Brazil)",
voices: [
{ value: "pt-BR_IsabelaVoice", name: "Isabela (Female)" },
{ value: "pt-BR_IsabelaV3Voice", name: "Isabela 2 (Female)" },
],
},
{
code: "ja-JP",
name: "Japanese",
voices: [
{ value: "ja-JP_EmiVoice", name: "Emi (Female)" },
{ value: "ja-JP_EmiV3Voice", name: "Emi 2 (Female)" },
],
},
];
export default languages;

View File

@@ -1,30 +0,0 @@
import { rawData } from "./ms-speech-synthesis-raw";
import type { VoiceLanguage } from "../types";
export const languages: VoiceLanguage[] = [];
rawData.forEach((data) => {
const lang = languages.find((l) => {
return l.code === data.Locale;
});
if (!lang) {
languages.push({
code: data.Locale,
name: data.LocaleName,
voices: rawData
.filter((d) => {
return d.Locale === data.Locale;
})
.map((d) => {
return {
value: d.ShortName,
name: `${d.DisplayName} (${d.Gender})`,
};
}),
});
}
});
export default languages;

File diff suppressed because it is too large Load Diff

View File

@@ -1,962 +0,0 @@
import type { VoiceLanguage } from "../types";
export const languages: VoiceLanguage[] = [
{
code: "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",
},
],
},
{
code: "eu-ES",
name: "Basque (Spain)",
voices: [{ value: "Miren", name: "Miren (standard)", model: "standard" }],
},
{
code: "bn-IN",
name: "Bengali (India)",
voices: [
{ value: "Paya - standard", name: "Paya (standard)", model: "standard" },
],
},
{
code: "bho-IN",
name: "Bhojpuri (India)",
voices: [
{ value: "Jaya - standard", name: "Jaya (standard)", model: "standard" },
],
},
{
code: "bg-BG",
name: "Bulgarian (Bulgaria)",
voices: [
{
value: "Daria - standard",
name: "Daria (standard)",
model: "standard",
},
],
},
{
code: "yue-HK",
name: "Cantonese (Hong Kong)",
voices: [
{
value: "Sinji-Ml - standard",
name: "Sinji-Ml (standard)",
model: "standard",
},
],
},
{
code: "ca-ES",
name: "Catalan (Spain)",
voices: [
{
value: "Jordi - standard",
name: "Jordi (standard)",
model: "standard",
},
{
value: "Montserrat - standard",
name: "Montserrat (standard)",
model: "enhanced",
},
],
},
{
code: "yue-HK",
name: "Croatian (Croatia)",
voices: [
{ value: "Lana - standard", name: "Lana (standard)", model: "standard" },
],
},
{
code: "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",
},
],
},
{
code: "da-DK",
name: "Danish (Denmark)",
voices: [
{
value: "Magnus - standard",
name: "Magnus (standard)",
model: "standard",
},
{ value: "Sara - standard", name: "Sara (standard)", model: "standard" },
],
},
{
code: "nl-BE",
name: "Dutch (Belgium)",
voices: [
{
value: "Ellen - standard",
name: "Ellen (standard)",
model: "standard",
},
],
},
{
code: "nl-NL",
name: "Dutch (Belgium)",
voices: [
{
value: "Claire-Ml - standard",
name: "Claire-Ml (standard)",
model: "standard",
},
{
value: "Xander - standard",
name: "Xander (standard)",
model: "standard",
},
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "en-IE",
name: "English (Ireland)",
voices: [
{
value: "Moira - standard",
name: "Moira (standard)",
model: "standard",
},
],
},
{
code: "en-SC",
name: "English (Scotland)",
voices: [
{
value: "Fiona - standard",
name: "Fiona (standard)",
model: "standard",
},
],
},
{
code: "en-ZA",
name: "English (South Africa)",
voices: [
{
value: "Tessa - standard",
name: "Tessa (standard)",
model: "standard",
},
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "fi-FI",
name: "Finnish (Finland)",
voices: [
{ value: "Onni - standard", name: "Onni (standard)", model: "standard" },
{ value: "Satu - standard", name: "Satu (standard)", model: "standard" },
],
},
{
code: "fr-BE",
name: "French (Belgium)",
voices: [
{ value: "Aude - standard", name: "Aude (standard)", model: "standard" },
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "gl-ES",
name: "Galician (Spain)",
voices: [
{
value: "Carmela - standard",
name: "Carmela (standard)",
model: "standard",
},
],
},
{
code: "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",
},
],
},
{
code: "el-GR",
name: "Greek (Greece)",
voices: [
{
value: "Melina - standard",
name: "Melina (standard)",
model: "standard",
},
{
value: "Nikos - standard",
name: "Nikos (standard)",
model: "standard",
},
],
},
{
code: "he-IL",
name: "Hebrew (Israel)",
voices: [
{
value: "Carmit - standard",
name: "Carmit (standard)",
model: "standard",
},
],
},
{
code: "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",
},
],
},
{
code: "hu-HU",
name: "Hungarian (Hungary)",
voices: [
{
value: "Mariska - standard",
name: "Mariska (standard)",
model: "standard",
},
],
},
{
code: "id-ID",
name: "Indonesian (Indonesia)",
voices: [
{
value: "Damayanti - standard",
name: "Damayanti (standard)",
model: "standard",
},
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "kn-IN",
name: "Kannada (India)",
voices: [
{
value: "Alpana - standard",
name: "Alpana (standard)",
model: "standard",
},
],
},
{
code: "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",
},
],
},
{
code: "zlm-MY",
name: "Malay (Malaysia)",
voices: [
{
value: "Amira - standard",
name: "Amira (standard)",
model: "standard",
},
],
},
{
code: "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",
},
],
},
{
code: "cmn-TW",
name: "Mandarin (Taiwan)",
voices: [
{
value: "Meijia-Ml - standard",
name: "Meijia-Ml (standard)",
model: "standard",
},
],
},
{
code: "mr-IN",
name: "Marathi (India)",
voices: [
{
value: "Ananya - standard",
name: "Ananya (standard)",
model: "standard",
},
],
},
{
code: "nb-NO",
name: "Norwegian Bokmål (Norway)",
voices: [
{
value: "Henrik - standard",
name: "Henrik (standard)",
model: "standard",
},
{ value: "Nora - standard", name: "Nora (standard)", model: "standard" },
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "ro-RO",
name: "Romanian (Romania)",
voices: [
{
value: "Ioana - standard",
name: "Ioana (standard)",
model: "standard",
},
],
},
{
code: "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" },
],
},
{
code: "sk-SK",
name: "Slovak (Slovakia)",
voices: [
{
value: "Laura - standard",
name: "Laura (standard)",
model: "standard",
},
],
},
{
code: "es-AR",
name: "Spanish (Argentina)",
voices: [
{
value: "Diego - standard",
name: "Diego (standard)",
model: "standard",
},
{
value: "Isabela - standard",
name: "Isabela (standard)",
model: "standard",
},
],
},
{
code: "es-CL",
name: "Spanish (Chile)",
voices: [
{
value: "Francisca - standard",
name: "Francisca (standard)",
model: "standard",
},
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "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",
},
],
},
{
code: "ta-IN",
name: "Tamil (India)",
voices: [
{ value: "Vani - standard", name: "Vani (standard)", model: "standard" },
],
},
{
code: "te-IN",
name: "Telugu (India)",
voices: [
{
value: "Geeta - standard",
name: "Geeta (standard)",
model: "standard",
},
],
},
{
code: "th-TH",
name: "Thai (Thailand)",
voices: [
{
value: "Kanya - enhanced",
name: "Kanya (enhanced)",
model: "enhanced",
},
{
value: "Narisa - standard",
name: "Narisa (standard)",
model: "standard",
},
],
},
{
code: "tr-TR",
name: "Turkish (Turkey)",
voices: [
{
value: "Cem-Ml - standard",
name: "Cem-Ml (standard)",
model: "standard",
},
{
value: "Yelda - standard",
name: "Yelda (standard)",
model: "standard",
},
],
},
{
code: "uk-UA",
name: "Ukrainian (Ukraine)",
voices: [
{
value: "Lesya - standard",
name: "Lesya (standard)",
model: "standard",
},
],
},
{
code: "va-ES",
name: "Valencian (Spain)",
voices: [
{
value: "Empar - standard",
name: "Empar (standard)",
model: "standard",
},
],
},
{
code: "vi-VN",
name: "Vietnamese (Vietnam)",
voices: [
{ value: "Linh - standard", name: "Linh (standard)", model: "standard" },
],
},
];
export default languages;

View File

@@ -1,20 +0,0 @@
import type { VoiceLanguage } from "../types";
export const languages: VoiceLanguage[] = [
{
code: "en-US",
name: "English",
voices: [
{
value: "English-US.Female-1",
name: "Female",
},
{
value: "English-US.Male-1",
name: "Male",
},
],
},
];
export default languages;

View File

@@ -1,43 +0,0 @@
import type { VoiceLanguage } from "../types";
export const languages: VoiceLanguage[] = [
{
code: "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)" },
],
},
];
export default languages;

21
src/vendor/types.ts vendored
View File

@@ -10,7 +10,9 @@ export type Vendor =
| "Soniox"
| "Cobalt"
| "Custom"
| "ElevenLabs";
| "ElevenLabs"
| "assemblyai"
| "whisper";
export interface VendorOptions {
name: Vendor;
@@ -27,6 +29,11 @@ export interface Region {
value: string;
}
export interface Model {
name: string;
value: string;
}
export interface Voice {
name: string;
value: string;
@@ -35,7 +42,7 @@ export interface Voice {
export interface Language {
name: string;
code: string;
value: string;
codeMix?: string;
}
@@ -63,6 +70,12 @@ export interface RegionVendors {
ibm: Region[];
}
export interface TtsModels {
elevenlabs: Model[];
whisper: Model[];
deepgram: Model[];
}
export interface RecognizerVendors {
aws: Language[];
google: Language[];
@@ -73,6 +86,7 @@ export interface RecognizerVendors {
nvidia: Language[];
soniox: Language[];
cobalt: Language[];
assemblyai: Language[];
}
export interface SynthesisVendors {
@@ -84,6 +98,8 @@ export interface SynthesisVendors {
ibm: VoiceLanguage[];
nvidia: VoiceLanguage[];
elevenlabs: VoiceLanguage[];
whisper: VoiceLanguage[];
deepgram: VoiceLanguage[];
}
export interface MSRawSpeech {
@@ -100,5 +116,6 @@ export interface MSRawSpeech {
StyleList?: string[];
RolePlayList?: string[];
WordPerMinute?: Record<string, unknown>;
WordsPerMinute?: string;
SecondaryLocaleList?: string[];
}