mirror of
https://github.com/jambonz/jambonz-webapp.git
synced 2026-01-25 02:08:19 +00:00
Compare commits
7 Commits
feature/up
...
v0.8.2-rc7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -309,6 +309,9 @@ export interface SpeechCredential {
|
||||
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 = {
|
||||
@@ -82,6 +86,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 = [
|
||||
@@ -185,6 +193,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) {
|
||||
@@ -356,13 +398,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 +411,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 +423,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 +467,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 +561,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 +587,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,12 @@ 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 handleFile = (file: File) => {
|
||||
const handleError = () => {
|
||||
@@ -141,6 +153,14 @@ 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,
|
||||
}),
|
||||
};
|
||||
|
||||
if (credential && credential.data) {
|
||||
@@ -173,7 +193,8 @@ 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,
|
||||
@@ -196,7 +217,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
|
||||
: vendor;
|
||||
setVendor(v);
|
||||
}
|
||||
|
||||
if (credential.data.account_sid) {
|
||||
@@ -205,14 +229,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) {
|
||||
@@ -277,6 +305,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 +343,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 +357,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 +386,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 +412,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 && (
|
||||
@@ -448,7 +590,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>
|
||||
|
||||
@@ -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