mirror of
https://github.com/jambonz/jambonz-webapp.git
synced 2026-01-25 02:08:19 +00:00
Compare commits
13 Commits
feature/up
...
v0.8.2-rc1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aba8b2be3a | ||
|
|
f4d7880ab7 | ||
|
|
7f93489580 | ||
|
|
19fafdc908 | ||
|
|
a165bfc4d6 | ||
|
|
e26d9b95cb | ||
|
|
e425d825bc | ||
|
|
a8d28da221 | ||
|
|
e3855e83f7 | ||
|
|
446b6e76e2 | ||
|
|
0b55cdcf85 | ||
|
|
f1743a9129 | ||
|
|
ec46121696 |
5
.env
5
.env
@@ -2,4 +2,7 @@ VITE_API_BASE_URL=http://127.0.0.1:3000/v1
|
||||
VITE_DEV_BASE_URL=http://127.0.0.1:3000/v1
|
||||
|
||||
## enables choosing units and lisenced account call limits
|
||||
# VITE_APP_ENABLE_ACCOUNT_LIMITS_ALL=true
|
||||
# VITE_APP_ENABLE_ACCOUNT_LIMITS_ALL=true
|
||||
|
||||
# disables controls for default application routing to carrier for SP and account level users
|
||||
#VITE_APP_DISABLE_DEFAULT_TRUNK_ROUTING=true
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:18.14.0-alpine3.16 as builder
|
||||
FROM node:18.14.1-alpine3.16 as builder
|
||||
RUN apk update && apk add --no-cache python3 make g++
|
||||
COPY . /opt/app
|
||||
WORKDIR /opt/app/
|
||||
@@ -6,7 +6,7 @@ RUN npm install
|
||||
RUN npm run build
|
||||
RUN npm prune
|
||||
|
||||
FROM node:18.9.0-alpine as webapp
|
||||
FROM node:18.14.1-alpine as webapp
|
||||
RUN apk add curl
|
||||
WORKDIR /opt/app
|
||||
COPY . /opt/app
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "jambonz-webapp",
|
||||
"version": "v1.0.0",
|
||||
"version": "v0.8.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "jambonz-webapp",
|
||||
"version": "v1.0.0",
|
||||
"version": "v0.8.2",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jambonz-webapp",
|
||||
"description": "A simple provisioning web app for jambonz",
|
||||
"version": "v1.0.0",
|
||||
"version": "v0.8.2",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
|
||||
@@ -28,6 +28,11 @@ export const API_BASE_URL =
|
||||
/** Serves mock API responses from a local dev API server */
|
||||
export const DEV_BASE_URL = import.meta.env.VITE_DEV_BASE_URL;
|
||||
|
||||
/** Disable custom speech vendor*/
|
||||
export const DISABLE_CUSTOM_SPEECH: boolean = JSON.parse(
|
||||
import.meta.env.VITE_DISABLE_CUSTOM_SPEECH || "false"
|
||||
);
|
||||
|
||||
/** TCP Max Port */
|
||||
export const TCP_MAX_PORT = 65535;
|
||||
|
||||
@@ -184,6 +189,7 @@ export const CRED_NOT_TESTED = "not tested";
|
||||
|
||||
/** API base paths */
|
||||
export const API_LOGIN = `${API_BASE_URL}/login`;
|
||||
export const API_LOGOUT = `${API_BASE_URL}/logout`;
|
||||
export const API_SBCS = `${API_BASE_URL}/Sbcs`;
|
||||
export const API_USERS = `${API_BASE_URL}/Users`;
|
||||
export const API_API_KEYS = `${API_BASE_URL}/ApiKeys`;
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
API_SIP_GATEWAY,
|
||||
API_PASSWORD_SETTINGS,
|
||||
USER_ACCOUNT,
|
||||
API_LOGOUT,
|
||||
} from "./constants";
|
||||
import { ROUTE_LOGIN } from "src/router/routes";
|
||||
import {
|
||||
@@ -233,6 +234,10 @@ export const postLogin = (payload: UserLoginPayload) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const postLogout = () => {
|
||||
return postFetch<undefined>(API_LOGOUT);
|
||||
};
|
||||
|
||||
/** Named wrappers for `postFetch` */
|
||||
|
||||
export const postServiceProviders = (payload: Partial<ServiceProvider>) => {
|
||||
|
||||
@@ -303,12 +303,17 @@ export interface SpeechCredential {
|
||||
custom_stt_endpoint: null | string;
|
||||
client_id: null | string;
|
||||
secret: null | string;
|
||||
nuance_tts_uri: null | string;
|
||||
nuance_stt_uri: null | string;
|
||||
tts_api_key: null | string;
|
||||
tts_region: null | string;
|
||||
stt_api_key: null | string;
|
||||
stt_region: null | string;
|
||||
instance_id: null | string;
|
||||
riva_server_uri: null | string;
|
||||
auth_token: null | string;
|
||||
custom_stt_url: null | string;
|
||||
custom_tts_url: null | string;
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
|
||||
@@ -418,11 +418,6 @@ export const AccountForm = ({ apps, limits, account }: AccountFormProps) => {
|
||||
username: e.target.value,
|
||||
});
|
||||
}}
|
||||
required={
|
||||
webhook.stateVal.password && !webhook.stateVal.username
|
||||
? true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
<label htmlFor={`${webhook.prefix}_password`}>
|
||||
Password
|
||||
@@ -438,11 +433,6 @@ export const AccountForm = ({ apps, limits, account }: AccountFormProps) => {
|
||||
password: e.target.value,
|
||||
});
|
||||
}}
|
||||
required={
|
||||
webhook.stateVal.username && !webhook.stateVal.password
|
||||
? true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
</Checkzone>
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,8 @@ import {
|
||||
VENDOR_WELLSAID,
|
||||
useSpeechVendors,
|
||||
VENDOR_DEEPGRAM,
|
||||
VENDOR_SONIOX,
|
||||
VENDOR_CUSTOM,
|
||||
} from "src/vendor";
|
||||
import {
|
||||
postApplication,
|
||||
@@ -39,6 +41,7 @@ import type {
|
||||
Voice,
|
||||
VoiceLanguage,
|
||||
Language,
|
||||
VendorOptions,
|
||||
} from "src/vendor/types";
|
||||
|
||||
import type {
|
||||
@@ -47,9 +50,10 @@ import type {
|
||||
Application,
|
||||
WebhookMethod,
|
||||
UseApiDataMap,
|
||||
SpeechCredential,
|
||||
} from "src/api/types";
|
||||
import { MSG_REQUIRED_FIELDS, MSG_WEBHOOK_FIELDS } from "src/constants";
|
||||
import { isUserAccountScope, useRedirect } from "src/utils";
|
||||
import { hasLength, isUserAccountScope, useRedirect } from "src/utils";
|
||||
import { setAccountFilter, setLocation } from "src/store/localStore";
|
||||
|
||||
type ApplicationFormProps = {
|
||||
@@ -68,11 +72,17 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
const [initialApplicationJson, setInitialApplicationJson] = useState(false);
|
||||
const [accountSid, setAccountSid] = useState("");
|
||||
const [callWebhook, setCallWebhook] = useState<WebHook>(DEFAULT_WEBHOOK);
|
||||
const [tmpCallWebhook, setTmpCallWebhook] =
|
||||
useState<WebHook>(DEFAULT_WEBHOOK);
|
||||
const [initialCallWebhook, setInitialCallWebhook] = useState(false);
|
||||
const [statusWebhook, setStatusWebhook] = useState<WebHook>(DEFAULT_WEBHOOK);
|
||||
const [tmpStatusWebhook, setTmpStatusWebhook] =
|
||||
useState<WebHook>(DEFAULT_WEBHOOK);
|
||||
const [initialStatusWebhook, setInitialStatusWebhook] = useState(false);
|
||||
const [messageWebhook, setMessageWebhook] =
|
||||
useState<WebHook>(DEFAULT_WEBHOOK);
|
||||
const [tmpMessageWebhook, setTmpMessageWebhook] =
|
||||
useState<WebHook>(DEFAULT_WEBHOOK);
|
||||
const [initialMessageWebhook, setInitialMessageWebhook] = useState(false);
|
||||
const [synthVendor, setSynthVendor] =
|
||||
useState<keyof SynthesisVendors>(VENDOR_GOOGLE);
|
||||
@@ -82,6 +92,10 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
useState<keyof RecognizerVendors>(VENDOR_GOOGLE);
|
||||
const [recogLang, setRecogLang] = useState(LANG_EN_US);
|
||||
const [message, setMessage] = useState("");
|
||||
const [apiUrl, setApiUrl] = useState("");
|
||||
const [credentials] = useApiData<SpeechCredential[]>(apiUrl);
|
||||
const [softTtsVendor, setSoftTtsVendor] = useState<VendorOptions[]>(vendors);
|
||||
const [softSttVendor, setSoftSttVendor] = useState<VendorOptions[]>(vendors);
|
||||
|
||||
/** This lets us map and render the same UI for each... */
|
||||
const webhooks = [
|
||||
@@ -89,7 +103,9 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
label: "Calling",
|
||||
prefix: "call_webhook",
|
||||
stateVal: callWebhook,
|
||||
tmpStateVal: tmpCallWebhook,
|
||||
stateSet: setCallWebhook,
|
||||
tmpStateSet: setTmpCallWebhook,
|
||||
initialCheck: initialCallWebhook,
|
||||
required: true,
|
||||
},
|
||||
@@ -97,7 +113,9 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
label: "Call status",
|
||||
prefix: "status_webhook",
|
||||
stateVal: statusWebhook,
|
||||
tmpStateVal: tmpStatusWebhook,
|
||||
stateSet: setStatusWebhook,
|
||||
tmpStateSet: setTmpStatusWebhook,
|
||||
initialCheck: initialStatusWebhook,
|
||||
required: true,
|
||||
},
|
||||
@@ -105,7 +123,9 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
label: "Messaging",
|
||||
prefix: "message_webhook",
|
||||
stateVal: messageWebhook,
|
||||
tmpStateVal: tmpMessageWebhook,
|
||||
stateSet: setMessageWebhook,
|
||||
tmpStateSet: setTmpMessageWebhook,
|
||||
initialCheck: initialMessageWebhook,
|
||||
required: false,
|
||||
},
|
||||
@@ -185,6 +205,40 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (credentials && hasLength(credentials)) {
|
||||
const v = credentials
|
||||
.filter((tv) => tv.vendor.startsWith(VENDOR_CUSTOM) && tv.use_for_tts)
|
||||
.map((tv) =>
|
||||
Object.assign({
|
||||
name:
|
||||
tv.vendor.substring(VENDOR_CUSTOM.length + 1) +
|
||||
` (${VENDOR_CUSTOM})`,
|
||||
value: tv.vendor,
|
||||
})
|
||||
);
|
||||
setSoftTtsVendor(vendors.concat(v));
|
||||
|
||||
const v2 = credentials
|
||||
.filter((tv) => tv.vendor.startsWith(VENDOR_CUSTOM) && tv.use_for_stt)
|
||||
.map((tv) =>
|
||||
Object.assign({
|
||||
name:
|
||||
tv.vendor.substring(VENDOR_CUSTOM.length + 1) +
|
||||
` (${VENDOR_CUSTOM})`,
|
||||
value: tv.vendor,
|
||||
})
|
||||
);
|
||||
setSoftSttVendor(vendors.concat(v2));
|
||||
}
|
||||
}, [credentials]);
|
||||
|
||||
useEffect(() => {
|
||||
if (accountSid) {
|
||||
setApiUrl(`Accounts/${accountSid}/SpeechCredentials`);
|
||||
}
|
||||
}, [accountSid]);
|
||||
|
||||
useEffect(() => {
|
||||
setLocation();
|
||||
if (application && application.data) {
|
||||
@@ -200,6 +254,7 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
|
||||
if (application.data.call_hook) {
|
||||
setCallWebhook(application.data.call_hook);
|
||||
setTmpCallWebhook(application.data.call_hook);
|
||||
|
||||
if (
|
||||
application.data.call_hook.username ||
|
||||
@@ -211,6 +266,7 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
|
||||
if (application.data.call_status_hook) {
|
||||
setStatusWebhook(application.data.call_status_hook);
|
||||
setTmpStatusWebhook(application.data.call_status_hook);
|
||||
|
||||
if (
|
||||
application.data.call_status_hook.username ||
|
||||
@@ -222,6 +278,7 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
|
||||
if (application.data.messaging_hook) {
|
||||
setMessageWebhook(application.data.messaging_hook);
|
||||
setTmpMessageWebhook(application.data.messaging_hook);
|
||||
|
||||
if (
|
||||
application.data.messaging_hook.username ||
|
||||
@@ -341,6 +398,18 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
name={webhook.prefix}
|
||||
label="Use HTTP basic authentication"
|
||||
initialCheck={webhook.initialCheck}
|
||||
handleChecked={(e) => {
|
||||
if (e.target.checked) {
|
||||
webhook.stateSet(webhook.tmpStateVal);
|
||||
} else {
|
||||
webhook.tmpStateSet(webhook.stateVal);
|
||||
webhook.stateSet({
|
||||
...webhook.stateVal,
|
||||
username: "",
|
||||
password: "",
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MS>{MSG_WEBHOOK_FIELDS}</MS>
|
||||
<label htmlFor={`${webhook.prefix}_username`}>Username</label>
|
||||
@@ -356,13 +425,6 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
username: e.target.value,
|
||||
});
|
||||
}}
|
||||
required={
|
||||
webhook.required &&
|
||||
!webhook.stateVal.username &&
|
||||
webhook.stateVal.password
|
||||
? true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
<label htmlFor={`${webhook.prefix}_password`}>Password</label>
|
||||
<Passwd
|
||||
@@ -376,13 +438,6 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
password: e.target.value,
|
||||
});
|
||||
}}
|
||||
required={
|
||||
webhook.required &&
|
||||
webhook.stateVal.username &&
|
||||
!webhook.stateVal.password
|
||||
? true
|
||||
: false
|
||||
}
|
||||
/>
|
||||
</Checkzone>
|
||||
</fieldset>
|
||||
@@ -395,13 +450,22 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
id="synthesis_vendor"
|
||||
name="synthesis_vendor"
|
||||
value={synthVendor}
|
||||
options={vendors.filter(
|
||||
(vendor) => vendor.value != VENDOR_DEEPGRAM
|
||||
options={softTtsVendor.filter(
|
||||
(vendor) =>
|
||||
vendor.value != VENDOR_DEEPGRAM &&
|
||||
vendor.value != VENDOR_SONIOX &&
|
||||
vendor.value !== VENDOR_CUSTOM
|
||||
)}
|
||||
onChange={(e) => {
|
||||
const vendor = e.target.value as keyof SynthesisVendors;
|
||||
setSynthVendor(vendor);
|
||||
|
||||
/** 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 &&
|
||||
@@ -430,55 +494,88 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
setSynthVoice(newLang!.voices[0].value);
|
||||
}}
|
||||
/>
|
||||
{synthVendor && synthLang && (
|
||||
<>
|
||||
<label htmlFor="synthesis_lang">Language</label>
|
||||
<Selector
|
||||
id="synthesis_lang"
|
||||
name="synthesis_lang"
|
||||
value={synthLang}
|
||||
options={synthesis[synthVendor as keyof SynthesisVendors].map(
|
||||
(lang: VoiceLanguage) => ({
|
||||
{synthVendor &&
|
||||
!synthVendor.toString().startsWith(VENDOR_CUSTOM) &&
|
||||
synthLang && (
|
||||
<>
|
||||
<label htmlFor="synthesis_lang">Language</label>
|
||||
<Selector
|
||||
id="synthesis_lang"
|
||||
name="synthesis_lang"
|
||||
value={synthLang}
|
||||
options={synthesis[
|
||||
synthVendor as keyof SynthesisVendors
|
||||
].map((lang: VoiceLanguage) => ({
|
||||
name: lang.name,
|
||||
value: lang.code,
|
||||
})
|
||||
)}
|
||||
onChange={(e) => {
|
||||
const language = e.target.value;
|
||||
setSynthLang(language);
|
||||
}))}
|
||||
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;
|
||||
/** 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>
|
||||
<Selector
|
||||
id="synthesis_voice"
|
||||
name="synthesis_voice"
|
||||
value={synthVoice}
|
||||
options={
|
||||
synthesis[synthVendor as keyof SynthesisVendors]
|
||||
.filter(
|
||||
(lang: VoiceLanguage) => lang.code === synthLang
|
||||
)
|
||||
.flatMap((lang: VoiceLanguage) =>
|
||||
lang.voices.map((voice: Voice) => ({
|
||||
name: voice.name,
|
||||
value: voice.value,
|
||||
}))
|
||||
) as Voice[]
|
||||
}
|
||||
|
||||
const newLang = synthesis[
|
||||
synthVendor as keyof SynthesisVendors
|
||||
].find((lang) => lang.code === language);
|
||||
|
||||
setSynthVoice(newLang!.voices[0].value);
|
||||
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="synthesis_voice">Voice</label>
|
||||
<Selector
|
||||
id="synthesis_voice"
|
||||
name="synthesis_voice"
|
||||
|
||||
<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}
|
||||
options={
|
||||
synthesis[synthVendor as keyof SynthesisVendors]
|
||||
.filter((lang: VoiceLanguage) => lang.code === synthLang)
|
||||
.flatMap((lang: VoiceLanguage) =>
|
||||
lang.voices.map((voice: Voice) => ({
|
||||
name: voice.name,
|
||||
value: voice.value,
|
||||
}))
|
||||
) as Voice[]
|
||||
}
|
||||
onChange={(e) => setSynthVoice(e.target.value)}
|
||||
onChange={(e) => {
|
||||
setSynthVoice(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
@@ -491,13 +588,18 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
id="recognizer_vendor"
|
||||
name="recognizer_vendor"
|
||||
value={recogVendor}
|
||||
options={vendors.filter(
|
||||
(vendor) => vendor.value != VENDOR_WELLSAID
|
||||
options={softSttVendor.filter(
|
||||
(vendor) =>
|
||||
vendor.value != VENDOR_WELLSAID &&
|
||||
vendor.value !== VENDOR_CUSTOM
|
||||
)}
|
||||
onChange={(e) => {
|
||||
const vendor = e.target.value as keyof RecognizerVendors;
|
||||
setRecogVendor(vendor);
|
||||
|
||||
/**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(
|
||||
@@ -512,19 +614,37 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{recogVendor && recogLang && (
|
||||
{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,
|
||||
}))}
|
||||
onChange={(e) => {
|
||||
setRecogLang(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{recogVendor.toString().startsWith(VENDOR_CUSTOM) && (
|
||||
<>
|
||||
<label htmlFor="recognizer_lang">Language</label>
|
||||
<Selector
|
||||
id="recognizer_lang"
|
||||
name="recognizer_lang"
|
||||
<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}
|
||||
options={recognizers[
|
||||
recogVendor as keyof RecognizerVendors
|
||||
].map((lang: Language) => ({
|
||||
name: lang.name,
|
||||
value: lang.code,
|
||||
}))}
|
||||
onChange={(e) => {
|
||||
setRecogLang(e.target.value);
|
||||
}}
|
||||
|
||||
@@ -45,6 +45,7 @@ import {
|
||||
isUserAccountScope,
|
||||
hasLength,
|
||||
isValidPort,
|
||||
disableDefaultTrunkRouting,
|
||||
} from "src/utils";
|
||||
|
||||
import type {
|
||||
@@ -725,18 +726,21 @@ export const CarrierForm = ({
|
||||
: false
|
||||
}
|
||||
/>
|
||||
{accountSid && hasLength(applications) && (
|
||||
<>
|
||||
<ApplicationSelect
|
||||
label="Default Application"
|
||||
defaultOption="None"
|
||||
application={[applicationSid, setApplicationSid]}
|
||||
applications={applications.filter(
|
||||
(application) => application.account_sid === accountSid
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{user &&
|
||||
disableDefaultTrunkRouting(user?.scope) &&
|
||||
accountSid &&
|
||||
hasLength(applications) && (
|
||||
<>
|
||||
<ApplicationSelect
|
||||
label="Default Application"
|
||||
defaultOption="None"
|
||||
application={[applicationSid, setApplicationSid]}
|
||||
applications={applications.filter(
|
||||
(application) => application.account_sid === accountSid
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<Checkzone
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import React, { Fragment, useEffect, useState } from "react";
|
||||
import { Button, ButtonGroup, MS } from "@jambonz/ui-kit";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
Selector,
|
||||
Passwd,
|
||||
AccountSelect,
|
||||
Checkzone,
|
||||
} from "src/components/forms";
|
||||
import { toastError, toastSuccess, useSelectState } from "src/store";
|
||||
import {
|
||||
@@ -27,6 +28,8 @@ import {
|
||||
VENDOR_DEEPGRAM,
|
||||
VENDOR_IBM,
|
||||
VENDOR_NVIDIA,
|
||||
VENDOR_SONIOX,
|
||||
VENDOR_CUSTOM,
|
||||
} from "src/vendor";
|
||||
import { MSG_REQUIRED_FIELDS } from "src/constants";
|
||||
import {
|
||||
@@ -40,6 +43,7 @@ import { CredentialStatus } from "./status";
|
||||
import type { RegionVendors, GoogleServiceKey, Vendor } from "src/vendor/types";
|
||||
import type { Account, SpeechCredential, UseApiDataMap } from "src/api/types";
|
||||
import { setAccountFilter, setLocation } from "src/store/localStore";
|
||||
import { DISABLE_CUSTOM_SPEECH } from "src/api/constants";
|
||||
|
||||
type SpeechServiceFormProps = {
|
||||
credential?: UseApiDataMap<SpeechCredential>;
|
||||
@@ -52,7 +56,9 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
const regions = useRegionVendors();
|
||||
const [accounts] = useServiceProviderData<Account[]>("Accounts");
|
||||
const [accountSid, setAccountSid] = useState("");
|
||||
const [initialTtsCheck, setInitialTtsCheck] = useState(false);
|
||||
const [ttsCheck, setTtsCheck] = useState(false);
|
||||
const [initialSttCheck, setInitialSttCheck] = useState(false);
|
||||
const [sttCheck, setSttCheck] = useState(false);
|
||||
const [vendor, setVendor] = useState<Lowercase<Vendor>>(
|
||||
"" as Lowercase<Vendor>
|
||||
@@ -77,6 +83,22 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
const [customSttEndpoint, setCustomSttEndpoint] = useState("");
|
||||
const [tmpCustomSttEndpoint, setTmpCustomSttEndpoint] = useState("");
|
||||
const [rivaServerUri, setRivaServerUri] = useState("");
|
||||
const [customVendorName, setCustomVendorName] = useState("");
|
||||
const [customVendorAuthToken, setCustomVendorAuthToken] = useState("");
|
||||
const [tmpCustomVendorTtsUrl, setTmpCustomVendorTtsUrl] = useState("");
|
||||
const [customVendorTtsUrl, setCustomVendorTtsUrl] = useState("");
|
||||
const [tmpCustomVendorSttUrl, setTmpCustomVendorSttUrl] = useState("");
|
||||
const [customVendorSttUrl, setCustomVendorSttUrl] = useState("");
|
||||
const [initialOnPremNuanceTtsCheck, setInitialOnPremNuanceTtsCheck] =
|
||||
useState(false);
|
||||
const [onPremNuanceTtsCheck, setOnPremNuanceTtsCheck] = useState(false);
|
||||
const [onPremNuanceTtsUrl, setOnPremNuanceTtsUrl] = useState("");
|
||||
const [tmpOnPremNuanceTtsUrl, setTmpOnPremNuanceTtsUrl] = useState("");
|
||||
const [initialOnPremNuanceSttCheck, setInitialOnPremNuanceSttCheck] =
|
||||
useState(false);
|
||||
const [onPremNuanceSttCheck, setOnPremNuanceSttCheck] = useState(false);
|
||||
const [tmpOnPremNuanceSttUrl, setTmpOnPremNuanceSttUrl] = useState("");
|
||||
const [onPremNuanceSttUrl, setOnPremNuanceSttUrl] = useState("");
|
||||
|
||||
const handleFile = (file: File) => {
|
||||
const handleError = () => {
|
||||
@@ -141,6 +163,20 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
...(vendor === VENDOR_NVIDIA && {
|
||||
riva_server_uri: rivaServerUri || null,
|
||||
}),
|
||||
...(vendor === VENDOR_CUSTOM && {
|
||||
vendor: (vendor + ":" + customVendorName) as Lowercase<Vendor>,
|
||||
use_for_tts: ttsCheck ? 1 : 0,
|
||||
use_for_stt: sttCheck ? 1 : 0,
|
||||
custom_tts_url: customVendorTtsUrl || null,
|
||||
custom_stt_url: customVendorSttUrl || null,
|
||||
auth_token: customVendorAuthToken || null,
|
||||
}),
|
||||
...(vendor === VENDOR_NUANCE && {
|
||||
client_id: clientId || null,
|
||||
secret: secretKey || null,
|
||||
nuance_tts_uri: onPremNuanceTtsUrl || null,
|
||||
nuance_stt_uri: onPremNuanceSttUrl || null,
|
||||
}),
|
||||
};
|
||||
|
||||
if (credential && credential.data) {
|
||||
@@ -173,11 +209,10 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
api_key:
|
||||
vendor === VENDOR_MICROSOFT ||
|
||||
vendor === VENDOR_WELLSAID ||
|
||||
vendor === VENDOR_DEEPGRAM
|
||||
vendor === VENDOR_DEEPGRAM ||
|
||||
vendor === VENDOR_SONIOX
|
||||
? apiKey
|
||||
: null,
|
||||
client_id: vendor === VENDOR_NUANCE ? clientId : null,
|
||||
secret: vendor === VENDOR_NUANCE ? secretKey : null,
|
||||
riva_server_uri: vendor == VENDOR_NVIDIA ? rivaServerUri : null,
|
||||
})
|
||||
.then(() => {
|
||||
@@ -196,7 +231,10 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
setLocation();
|
||||
if (credential && credential.data) {
|
||||
if (credential.data.vendor) {
|
||||
setVendor(credential.data.vendor);
|
||||
const v = credential.data.vendor.startsWith(VENDOR_CUSTOM)
|
||||
? VENDOR_CUSTOM
|
||||
: credential.data.vendor;
|
||||
setVendor(v);
|
||||
}
|
||||
|
||||
if (credential.data.account_sid) {
|
||||
@@ -205,14 +243,18 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
|
||||
if (credential.data.use_for_stt) {
|
||||
setSttCheck(true);
|
||||
setInitialSttCheck(true);
|
||||
} else {
|
||||
setSttCheck(false);
|
||||
setInitialSttCheck(false);
|
||||
}
|
||||
|
||||
if (credential.data.use_for_tts) {
|
||||
setTtsCheck(true);
|
||||
setInitialTtsCheck(true);
|
||||
} else {
|
||||
setTtsCheck(false);
|
||||
setInitialTtsCheck(false);
|
||||
}
|
||||
|
||||
if (credential.data.service_key) {
|
||||
@@ -247,6 +289,24 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
setSecretKey(credential.data.secret);
|
||||
}
|
||||
|
||||
if (credential.data.nuance_tts_uri) {
|
||||
setOnPremNuanceTtsUrl(credential.data.nuance_tts_uri);
|
||||
setInitialOnPremNuanceTtsCheck(true);
|
||||
setOnPremNuanceTtsCheck(true);
|
||||
} else {
|
||||
setInitialOnPremNuanceTtsCheck(false);
|
||||
setOnPremNuanceTtsCheck(false);
|
||||
}
|
||||
|
||||
if (credential.data.nuance_stt_uri) {
|
||||
setOnPremNuanceSttUrl(credential.data.nuance_stt_uri);
|
||||
setInitialOnPremNuanceSttCheck(true);
|
||||
setOnPremNuanceSttCheck(true);
|
||||
} else {
|
||||
setInitialOnPremNuanceSttCheck(false);
|
||||
setOnPremNuanceSttCheck(false);
|
||||
}
|
||||
|
||||
if (credential.data.tts_api_key) {
|
||||
setTtsApiKey(credential.data.tts_api_key);
|
||||
}
|
||||
@@ -277,6 +337,16 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
setCustomSttEndpoint(credential.data.custom_stt_endpoint || "");
|
||||
setTmpCustomTtsEndpoint(credential.data.custom_tts_endpoint || "");
|
||||
setTmpCustomSttEndpoint(credential.data.custom_stt_endpoint || "");
|
||||
setCustomVendorName(
|
||||
credential.data.vendor.startsWith(VENDOR_CUSTOM)
|
||||
? credential.data.vendor.substring(VENDOR_CUSTOM.length + 1)
|
||||
: credential.data.vendor
|
||||
);
|
||||
setCustomVendorAuthToken(credential.data.auth_token || "");
|
||||
setCustomVendorSttUrl(credential.data.custom_stt_url || "");
|
||||
setTmpCustomVendorSttUrl(credential.data.custom_stt_url || "");
|
||||
setCustomVendorTtsUrl(credential.data.custom_tts_url || "");
|
||||
setTmpCustomVendorTtsUrl(credential.data.custom_tts_url || "");
|
||||
}
|
||||
}, [credential]);
|
||||
|
||||
@@ -305,7 +375,11 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
name: "Select a vendor",
|
||||
value: "",
|
||||
},
|
||||
].concat(vendors)}
|
||||
]
|
||||
.concat(vendors)
|
||||
.filter(
|
||||
(v) => !DISABLE_CUSTOM_SPEECH || v.value !== VENDOR_CUSTOM
|
||||
)}
|
||||
onChange={(e) => {
|
||||
setVendor(e.target.value as Lowercase<Vendor>);
|
||||
setRegion("");
|
||||
@@ -315,6 +389,23 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
disabled={credential ? true : false}
|
||||
required
|
||||
/>
|
||||
{vendor === VENDOR_CUSTOM && (
|
||||
<>
|
||||
<label htmlFor="custom_vendor_name">
|
||||
Name<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="custom_vendor_name"
|
||||
required
|
||||
type="text"
|
||||
name="custom_vendor_name"
|
||||
placeholder="Vendor Name"
|
||||
value={customVendorName}
|
||||
onChange={(e) => setCustomVendorName(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<AccountSelect
|
||||
@@ -327,19 +418,21 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
</fieldset>
|
||||
{vendor && (
|
||||
<fieldset>
|
||||
{vendor !== VENDOR_DEEPGRAM && (
|
||||
<label htmlFor="use_for_tts" className="chk">
|
||||
<input
|
||||
id="use_for_tts"
|
||||
name="use_for_tts"
|
||||
type="checkbox"
|
||||
onChange={(e) => setTtsCheck(e.target.checked)}
|
||||
defaultChecked={ttsCheck}
|
||||
/>
|
||||
<div>Use for text-to-speech</div>
|
||||
</label>
|
||||
)}
|
||||
{vendor !== VENDOR_WELLSAID && (
|
||||
{vendor !== VENDOR_DEEPGRAM &&
|
||||
vendor !== VENDOR_SONIOX &&
|
||||
vendor != VENDOR_CUSTOM && (
|
||||
<label htmlFor="use_for_tts" className="chk">
|
||||
<input
|
||||
id="use_for_tts"
|
||||
name="use_for_tts"
|
||||
type="checkbox"
|
||||
onChange={(e) => setTtsCheck(e.target.checked)}
|
||||
defaultChecked={ttsCheck}
|
||||
/>
|
||||
<div>Use for text-to-speech</div>
|
||||
</label>
|
||||
)}
|
||||
{vendor !== VENDOR_WELLSAID && vendor !== VENDOR_CUSTOM && (
|
||||
<label htmlFor="use_for_stt" className="chk">
|
||||
<input
|
||||
id="use_for_stt"
|
||||
@@ -351,6 +444,87 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
<div>Use for speech-to-text</div>
|
||||
</label>
|
||||
)}
|
||||
{vendor === VENDOR_CUSTOM && (
|
||||
<Fragment>
|
||||
<Checkzone
|
||||
hidden
|
||||
name="custom_vendor_use_for_tts"
|
||||
label="Use for text-to-speech"
|
||||
initialCheck={initialTtsCheck}
|
||||
handleChecked={(e) => {
|
||||
setTtsCheck(e.target.checked);
|
||||
if (!e.target.checked) {
|
||||
setTmpCustomVendorTtsUrl(customVendorTtsUrl);
|
||||
setCustomVendorTtsUrl("");
|
||||
} else {
|
||||
setCustomVendorTtsUrl(tmpCustomVendorTtsUrl);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="custom_vendor_use_for_tts">
|
||||
TTS HTTP URL<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="custom_vendor_use_for_tts"
|
||||
type="text"
|
||||
name="custom_vendor_use_for_tts"
|
||||
placeholder="Required"
|
||||
required={ttsCheck}
|
||||
value={customVendorTtsUrl}
|
||||
onChange={(e) => {
|
||||
setCustomVendorTtsUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Checkzone>
|
||||
|
||||
<Checkzone
|
||||
hidden
|
||||
name="custom_vendor_use_for_stt"
|
||||
label="Use for speech-to-text"
|
||||
initialCheck={initialSttCheck}
|
||||
handleChecked={(e) => {
|
||||
setSttCheck(e.target.checked);
|
||||
if (!e.target.checked) {
|
||||
setTmpCustomVendorSttUrl(customVendorSttUrl);
|
||||
setCustomVendorSttUrl("");
|
||||
} else {
|
||||
setCustomVendorSttUrl(tmpCustomVendorSttUrl);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="custom_vendor_use_for_stt">
|
||||
STT websocket URL<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="custom_vendor_use_for_stt"
|
||||
type="text"
|
||||
name="custom_vendor_use_for_stt"
|
||||
placeholder="Required"
|
||||
required={sttCheck}
|
||||
value={customVendorSttUrl}
|
||||
onChange={(e) => {
|
||||
setCustomVendorSttUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Checkzone>
|
||||
</Fragment>
|
||||
)}
|
||||
</fieldset>
|
||||
)}
|
||||
{vendor === VENDOR_CUSTOM && (
|
||||
<fieldset>
|
||||
<label htmlFor="custom_vendor_auth_token">
|
||||
Authentication Token
|
||||
</label>
|
||||
<input
|
||||
id="custom_vendor_auth_token"
|
||||
type="text"
|
||||
name="custom_vendor_auth_token"
|
||||
placeholder="Authentication Token"
|
||||
value={customVendorAuthToken}
|
||||
onChange={(e) => setCustomVendorAuthToken(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
</fieldset>
|
||||
)}
|
||||
{vendor === VENDOR_GOOGLE && (
|
||||
@@ -385,33 +559,108 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
</>
|
||||
)}
|
||||
{vendor === VENDOR_NUANCE && (
|
||||
<fieldset>
|
||||
<label htmlFor="nuance_client_id">
|
||||
Client ID<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="nuance_client_id"
|
||||
required
|
||||
type="text"
|
||||
name="nuance_client_id"
|
||||
placeholder="Client ID"
|
||||
value={clientId}
|
||||
onChange={(e) => setClientId(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
<label htmlFor="nuance_secret">
|
||||
Secret<span>*</span>
|
||||
</label>
|
||||
<Passwd
|
||||
id="nuance_secret"
|
||||
required
|
||||
name="nuance_secret"
|
||||
placeholder="Secret Key"
|
||||
value={secretKey ? getObscuredSecret(secretKey) : secretKey}
|
||||
onChange={(e) => setSecretKey(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
</fieldset>
|
||||
<>
|
||||
<fieldset>
|
||||
<label htmlFor="nuance_client_id">
|
||||
Client ID
|
||||
{!onPremNuanceSttCheck && !onPremNuanceTtsCheck && (
|
||||
<span>*</span>
|
||||
)}
|
||||
</label>
|
||||
<input
|
||||
id="nuance_client_id"
|
||||
required={!onPremNuanceSttCheck && !onPremNuanceTtsCheck}
|
||||
type="text"
|
||||
name="nuance_client_id"
|
||||
placeholder="Client ID"
|
||||
value={clientId}
|
||||
onChange={(e) => setClientId(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
<label htmlFor="nuance_secret">
|
||||
Secret
|
||||
{!onPremNuanceSttCheck && !onPremNuanceTtsCheck && (
|
||||
<span>*</span>
|
||||
)}
|
||||
</label>
|
||||
<Passwd
|
||||
id="nuance_secret"
|
||||
required={!onPremNuanceSttCheck && !onPremNuanceTtsCheck}
|
||||
name="nuance_secret"
|
||||
placeholder="Secret Key"
|
||||
value={secretKey ? getObscuredSecret(secretKey) : secretKey}
|
||||
onChange={(e) => setSecretKey(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<>
|
||||
<Checkzone
|
||||
hidden
|
||||
name="on_prem_nuance_use_tts"
|
||||
label="Use on-prem TTS"
|
||||
initialCheck={initialOnPremNuanceTtsCheck}
|
||||
handleChecked={(e) => {
|
||||
setOnPremNuanceTtsCheck(e.target.checked);
|
||||
if (!e.target.checked) {
|
||||
setTmpOnPremNuanceTtsUrl(onPremNuanceTtsUrl);
|
||||
setOnPremNuanceTtsUrl("");
|
||||
} else {
|
||||
setOnPremNuanceTtsUrl(tmpOnPremNuanceTtsUrl);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="on_prem_nuance_use_tts">
|
||||
TTS URI<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="on_prem_nuance_use_tts"
|
||||
type="text"
|
||||
name="on_prem_nuance_use_tts"
|
||||
placeholder="ip:port"
|
||||
pattern="(.*):([0-9]{0,6}$)"
|
||||
required={onPremNuanceTtsCheck}
|
||||
value={onPremNuanceTtsUrl}
|
||||
onChange={(e) => {
|
||||
setOnPremNuanceTtsUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Checkzone>
|
||||
|
||||
<Checkzone
|
||||
hidden
|
||||
name="on_prem_nuance_use_stt"
|
||||
label="Use on-prem STT"
|
||||
initialCheck={initialOnPremNuanceSttCheck}
|
||||
handleChecked={(e) => {
|
||||
setOnPremNuanceSttCheck(e.target.checked);
|
||||
if (!e.target.checked) {
|
||||
setTmpOnPremNuanceSttUrl(onPremNuanceSttUrl);
|
||||
setOnPremNuanceSttUrl("");
|
||||
} else {
|
||||
setOnPremNuanceSttUrl(tmpOnPremNuanceSttUrl);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="on_prem_nuance_use_stt_lb">
|
||||
STT URI<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="on_prem_nuance_use_stt"
|
||||
type="text"
|
||||
name="on_prem_nuance_use_stt"
|
||||
placeholder="ip:port"
|
||||
pattern="(.*):([0-9]{0,6}$)"
|
||||
required={onPremNuanceSttCheck}
|
||||
value={onPremNuanceSttUrl}
|
||||
onChange={(e) => {
|
||||
setOnPremNuanceSttUrl(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</Checkzone>
|
||||
</>
|
||||
</fieldset>
|
||||
</>
|
||||
)}
|
||||
{vendor === VENDOR_AWS && (
|
||||
<fieldset>
|
||||
@@ -448,7 +697,8 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
)}
|
||||
{(vendor === VENDOR_MICROSOFT ||
|
||||
vendor === VENDOR_WELLSAID ||
|
||||
vendor === VENDOR_DEEPGRAM) && (
|
||||
vendor === VENDOR_DEEPGRAM ||
|
||||
vendor === VENDOR_SONIOX) && (
|
||||
<fieldset>
|
||||
<label htmlFor={`${vendor}_apikey`}>
|
||||
API key<span>*</span>
|
||||
|
||||
@@ -26,6 +26,7 @@ import type { SpeechCredential, Account } from "src/api/types";
|
||||
import { ScopedAccess } from "src/components/scoped-access";
|
||||
import { Scope } from "src/store/types";
|
||||
import { getAccountFilter, setLocation } from "src/store/localStore";
|
||||
import { VENDOR_CUSTOM } from "src/vendor";
|
||||
|
||||
export const SpeechServices = () => {
|
||||
const user = useSelectState("user");
|
||||
@@ -140,7 +141,14 @@ export const SpeechServices = () => {
|
||||
title="Edit application"
|
||||
className="i"
|
||||
>
|
||||
<strong>Vendor: {credential.vendor}</strong>
|
||||
<strong>
|
||||
Vendor:{" "}
|
||||
{credential.vendor.startsWith(VENDOR_CUSTOM)
|
||||
? credential.vendor.substring(
|
||||
VENDOR_CUSTOM.length + 1
|
||||
)
|
||||
: credential.vendor}
|
||||
</strong>
|
||||
<Icons.ArrowRight />
|
||||
</Link>
|
||||
</ScopedAccess>
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
import React, { useContext } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { postLogin } from "src/api";
|
||||
import { postLogin, postLogout } from "src/api";
|
||||
import { StatusCodes } from "src/api/types";
|
||||
import {
|
||||
ROUTE_LOGIN,
|
||||
ROUTE_CREATE_PASSWORD,
|
||||
ROUTE_INTERNAL_ACCOUNTS,
|
||||
ROUTE_INTERNAL_APPLICATIONS,
|
||||
ROUTE_LOGIN,
|
||||
} from "./routes";
|
||||
import {
|
||||
SESS_OLD_PASSWORD,
|
||||
@@ -136,10 +136,27 @@ export const useProvideAuth = (): AuthStateContext => {
|
||||
};
|
||||
|
||||
const signout = () => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
sessionStorage.setItem(SESS_FLASH_MSG, MSG_LOGGED_OUT);
|
||||
window.location.href = ROUTE_LOGIN;
|
||||
return new Promise((resolve, reject) => {
|
||||
postLogout()
|
||||
.then((response) => {
|
||||
if (response.status === StatusCodes.OK) {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
sessionStorage.setItem(SESS_FLASH_MSG, MSG_LOGGED_OUT);
|
||||
resolve(response.json);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
sessionStorage.setItem(SESS_FLASH_MSG, MSG_LOGGED_OUT);
|
||||
if (error) {
|
||||
reject(error);
|
||||
}
|
||||
reject(MSG_SOMETHING_WRONG);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -225,6 +225,17 @@ export const createFilterString = (filterValue: string, label: string) => {
|
||||
return filterString.join("/");
|
||||
};
|
||||
|
||||
export const disableDefaultTrunkRouting = (userScope: UserData["scope"]) => {
|
||||
if (import.meta.env.VITE_APP_DISABLE_DEFAULT_TRUNK_ROUTING) {
|
||||
if (userScope === USER_ADMIN) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
export {
|
||||
withSuspense,
|
||||
useMobileMedia,
|
||||
|
||||
13
src/vendor/index.tsx
vendored
13
src/vendor/index.tsx
vendored
@@ -17,6 +17,8 @@ export const VENDOR_NUANCE = "nuance";
|
||||
export const VENDOR_DEEPGRAM = "deepgram";
|
||||
export const VENDOR_IBM = "ibm";
|
||||
export const VENDOR_NVIDIA = "nvidia";
|
||||
export const VENDOR_SONIOX = "soniox";
|
||||
export const VENDOR_CUSTOM = "custom";
|
||||
|
||||
export const vendors: VendorOptions[] = [
|
||||
{
|
||||
@@ -51,6 +53,14 @@ export const vendors: VendorOptions[] = [
|
||||
name: "WellSaid",
|
||||
value: VENDOR_WELLSAID,
|
||||
},
|
||||
{
|
||||
name: "Soniox",
|
||||
value: VENDOR_SONIOX,
|
||||
},
|
||||
{
|
||||
name: "Custom",
|
||||
value: VENDOR_CUSTOM,
|
||||
},
|
||||
];
|
||||
|
||||
export const useRegionVendors = () => {
|
||||
@@ -104,6 +114,7 @@ export const useSpeechVendors = () => {
|
||||
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-synthesis/aws-speech-synthesis-lang"),
|
||||
import("./speech-synthesis/google-speech-synthesis-lang"),
|
||||
import("./speech-synthesis/ms-speech-synthesis-lang"),
|
||||
@@ -120,6 +131,7 @@ export const useSpeechVendors = () => {
|
||||
{ default: deepgramRecognizer },
|
||||
{ default: ibmRecognizer },
|
||||
{ default: nvidiaRecognizer },
|
||||
{ default: sonioxRecognizer },
|
||||
{ default: awsSynthesis },
|
||||
{ default: googleSynthesis },
|
||||
{ default: msSynthesis },
|
||||
@@ -147,6 +159,7 @@ export const useSpeechVendors = () => {
|
||||
deepgram: deepgramRecognizer,
|
||||
ibm: ibmRecognizer,
|
||||
nvidia: nvidiaRecognizer,
|
||||
soniox: sonioxRecognizer,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
10
src/vendor/speech-recognizer/soniox-speech-recognizer-lang.ts
vendored
Normal file
10
src/vendor/speech-recognizer/soniox-speech-recognizer-lang.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import type { Language } from "../types";
|
||||
|
||||
export const languages: Language[] = [
|
||||
{
|
||||
name: "English (United States)",
|
||||
code: "en-US",
|
||||
},
|
||||
];
|
||||
|
||||
export default languages;
|
||||
5
src/vendor/types.ts
vendored
5
src/vendor/types.ts
vendored
@@ -6,7 +6,9 @@ export type Vendor =
|
||||
| "Nuance"
|
||||
| "Deepgram"
|
||||
| "IBM"
|
||||
| "Nvidia";
|
||||
| "Nvidia"
|
||||
| "Soniox"
|
||||
| "Custom";
|
||||
|
||||
export interface VendorOptions {
|
||||
name: Vendor;
|
||||
@@ -62,6 +64,7 @@ export interface RecognizerVendors {
|
||||
deepgram: Language[];
|
||||
ibm: Language[];
|
||||
nvidia: Language[];
|
||||
soniox: Language[];
|
||||
}
|
||||
|
||||
export interface SynthesisVendors {
|
||||
|
||||
Reference in New Issue
Block a user