mirror of
https://github.com/jambonz/jambonz-webapp.git
synced 2026-01-25 02:08:19 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a586771ea6 | ||
|
|
7aaea04d3c | ||
|
|
f1d2ed8abd | ||
|
|
d7d61a769d | ||
|
|
c9da7946f3 | ||
|
|
5755cd8886 | ||
|
|
786327a0b9 | ||
|
|
2c390715d8 | ||
|
|
dcdc2c0808 | ||
|
|
a3c48e7efb |
6
.env
6
.env
@@ -1,5 +1,5 @@
|
||||
VITE_API_BASE_URL=http://127.0.0.1:3000/v1
|
||||
VITE_DEV_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
|
||||
@@ -25,4 +25,6 @@ VITE_DEV_BASE_URL=http://127.0.0.1:3000/v1
|
||||
## Base url for jambomz webapp
|
||||
#VITE_APP_BASE_URL="http://jambonz.one"
|
||||
## Strip publishable key
|
||||
#VITE_APP_STRIPE_PUBLISHABLE_KEY="pk_test_EChRaX9Tjk8csZZVSeoGqNvu00lsJzjaU1"
|
||||
#VITE_APP_STRIPE_PUBLISHABLE_KEY="pk_test_EChRaX9Tjk8csZZVSeoGqNvu00lsJzjaU1"
|
||||
## ignore some specific speech vendors, defined by ADDITIONAL_SPEECH_VENDORS constant
|
||||
# VITE_APP_DISABLE_ADDITIONAL_SPEECH_VENDORS=true
|
||||
4
LICENSE
4
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Drachtio Communications Services, LLC
|
||||
Copyright (c) 2018-2024 FirstFive8, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { hasValue } from "src/utils";
|
||||
import type {
|
||||
Currency,
|
||||
ElevenLabsOptions,
|
||||
@@ -12,6 +13,7 @@ import type {
|
||||
WebHook,
|
||||
WebhookOption,
|
||||
} from "./types";
|
||||
import { Vendor } from "src/vendor/types";
|
||||
|
||||
/** This window object is serialized and injected at docker runtime */
|
||||
/** The API url is constructed with the docker containers `ip:port` */
|
||||
@@ -28,6 +30,7 @@ interface JambonzWindowObject {
|
||||
BASE_URL: string;
|
||||
DEFAULT_SERVICE_PROVIDER_SID: string;
|
||||
STRIPE_PUBLISHABLE_KEY: string;
|
||||
DISABLE_ADDITIONAL_SPEECH_VENDORS: string;
|
||||
}
|
||||
|
||||
declare global {
|
||||
@@ -37,8 +40,11 @@ declare global {
|
||||
}
|
||||
|
||||
/** https://vitejs.dev/guide/env-and-mode.html#env-files */
|
||||
export const API_BASE_URL =
|
||||
const CONFIGURED_API_BASE_URL =
|
||||
window.JAMBONZ?.API_BASE_URL || import.meta.env.VITE_API_BASE_URL;
|
||||
export const API_BASE_URL = hasValue(CONFIGURED_API_BASE_URL)
|
||||
? CONFIGURED_API_BASE_URL
|
||||
: `${window.location.protocol}//${window.location.hostname}/api/v1`;
|
||||
|
||||
/** Serves mock API responses from a local dev API server */
|
||||
export const DEV_BASE_URL = import.meta.env.VITE_DEV_BASE_URL;
|
||||
@@ -72,6 +78,13 @@ export const DISABLE_CALL_RECORDING: boolean =
|
||||
window.JAMBONZ?.DISABLE_CALL_RECORDING === "true" ||
|
||||
JSON.parse(import.meta.env.VITE_APP_DISABLE_CALL_RECORDING || "false");
|
||||
|
||||
/** Disable additional speech vendors */
|
||||
export const DISABLE_ADDITIONAL_SPEECH_VENDORS: boolean =
|
||||
window.JAMBONZ?.DISABLE_ADDITIONAL_SPEECH_VENDORS === "true" ||
|
||||
JSON.parse(
|
||||
import.meta.env.VITE_APP_DISABLE_ADDITIONAL_SPEECH_VENDORS || "false",
|
||||
);
|
||||
|
||||
export const DEFAULT_SERVICE_PROVIDER_SID: string =
|
||||
window.JAMBONZ?.DEFAULT_SERVICE_PROVIDER_SID ||
|
||||
import.meta.env.VITE_APP_DEFAULT_SERVICE_PROVIDER_SID;
|
||||
@@ -201,10 +214,31 @@ export const AUDIO_FORMAT_OPTIONS = [
|
||||
},
|
||||
];
|
||||
|
||||
export const LOG_LEVEL_OPTIONS = [
|
||||
{
|
||||
name: "Info",
|
||||
value: "info",
|
||||
},
|
||||
{
|
||||
name: "Debug",
|
||||
value: "debug",
|
||||
},
|
||||
];
|
||||
|
||||
export const DEFAULT_ELEVENLABS_MODEL = "eleven_multilingual_v2";
|
||||
|
||||
export const DEFAULT_WHISPER_MODEL = "tts-1";
|
||||
|
||||
// VERBIO
|
||||
export const VERBIO_STT_MODELS = [
|
||||
{ name: "V1", value: "V1" },
|
||||
{ name: "V2", value: "V2" },
|
||||
];
|
||||
|
||||
export const DEFAULT_VERBIO_MODEL = "V1";
|
||||
|
||||
export const ADDITIONAL_SPEECH_VENDORS: Lowercase<Vendor>[] = ["speechmatics"];
|
||||
|
||||
// Google Custom Voice reported usage options
|
||||
|
||||
export const DEFAULT_GOOGLE_CUSTOM_VOICES_REPORTED_USAGE = "REALTIME";
|
||||
|
||||
@@ -875,6 +875,7 @@ export const getSpeechSupportedLanguagesAndVoices = (
|
||||
sid: string | undefined,
|
||||
vendor: string,
|
||||
label: string,
|
||||
create_new: boolean = false,
|
||||
) => {
|
||||
const userData = parseJwt(getToken());
|
||||
const apiUrl =
|
||||
@@ -883,7 +884,7 @@ export const getSpeechSupportedLanguagesAndVoices = (
|
||||
: `${API_SERVICE_PROVIDERS}/${sid}`) +
|
||||
`/SpeechCredentials/speech/supportedLanguagesAndVoices?vendor=${vendor}${
|
||||
label ? `&label=${label}` : ""
|
||||
}`;
|
||||
}${create_new ? "&create_new=true" : ""}`;
|
||||
return getFetch<SpeechSupportedLanguagesAndVoices>(apiUrl);
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ export interface LimitUnitOption {
|
||||
/** User roles / permissions */
|
||||
export type UserScopes = "admin" | "service_provider" | "account";
|
||||
|
||||
export type LogLevel = "info" | "debug";
|
||||
|
||||
export type UserPermissions =
|
||||
| "VIEW_ONLY"
|
||||
| "PROVISION_SERVICES"
|
||||
@@ -122,9 +124,11 @@ export interface ForgotPassword {
|
||||
}
|
||||
|
||||
export interface SystemInformation {
|
||||
domain_name: string;
|
||||
sip_domain_name: string;
|
||||
monitoring_domain_name: string;
|
||||
domain_name: null | string;
|
||||
sip_domain_name: null | string;
|
||||
monitoring_domain_name: null | string;
|
||||
private_network_cidr: null | string;
|
||||
log_level: LogLevel;
|
||||
}
|
||||
|
||||
export interface TtsCache {
|
||||
@@ -261,6 +265,7 @@ export interface Account {
|
||||
device_to_call_ratio?: number;
|
||||
trial_end_date?: null | string;
|
||||
is_active: boolean;
|
||||
enable_debug_log: boolean;
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
@@ -402,6 +407,7 @@ export interface SpeechCredential {
|
||||
custom_stt_endpoint_url: null | string;
|
||||
custom_stt_endpoint: null | string;
|
||||
client_id: null | string;
|
||||
client_secret: null | string;
|
||||
secret: null | string;
|
||||
nuance_tts_uri: null | string;
|
||||
nuance_stt_uri: null | string;
|
||||
@@ -418,10 +424,13 @@ export interface SpeechCredential {
|
||||
cobalt_server_uri: null | string;
|
||||
model_id: null | string;
|
||||
voice_engine: null | string;
|
||||
engine_version: null | string;
|
||||
model: null | string;
|
||||
options: null | string;
|
||||
deepgram_stt_uri: null | string;
|
||||
deepgram_tts_uri: null | string;
|
||||
deepgram_stt_use_tls: number;
|
||||
speechmatics_stt_uri: null | string;
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
@@ -487,6 +496,7 @@ export interface SipGateway extends Gateway {
|
||||
port: number | null;
|
||||
pad_crypto?: boolean;
|
||||
send_options_ping?: boolean;
|
||||
use_sips_scheme?: boolean;
|
||||
}
|
||||
|
||||
export interface SmppGateway extends Gateway {
|
||||
|
||||
@@ -14,7 +14,14 @@ import {
|
||||
postAccountBucketCredentialTest,
|
||||
deleteAccount,
|
||||
} from "src/api";
|
||||
import { ClipBoard, Icons, Modal, Section, Tooltip } from "src/components";
|
||||
import {
|
||||
ClipBoard,
|
||||
Icons,
|
||||
Modal,
|
||||
ScopedAccess,
|
||||
Section,
|
||||
Tooltip,
|
||||
} from "src/components";
|
||||
import {
|
||||
Selector,
|
||||
Checkzone,
|
||||
@@ -67,6 +74,7 @@ import dayjs from "dayjs";
|
||||
import { EditBoard } from "src/components/editboard";
|
||||
import { ModalLoader } from "src/components/modal";
|
||||
import { useAuth } from "src/router/auth";
|
||||
import { Scope } from "src/store/types";
|
||||
|
||||
type AccountFormProps = {
|
||||
apps?: Application[];
|
||||
@@ -137,6 +145,7 @@ export const AccountForm = ({
|
||||
const [isShowModalLoader, setIsShowModalLoader] = useState(false);
|
||||
const [azureConnectionString, setAzureConnectionString] = useState("");
|
||||
const [endpoint, setEndpoint] = useState("");
|
||||
const [enableDebugLog, setEnableDebugLog] = useState(false);
|
||||
|
||||
/** This lets us map and render the same UI for each... */
|
||||
const webhooks = [
|
||||
@@ -381,6 +390,7 @@ export const AccountForm = ({
|
||||
if (account && account.data) {
|
||||
putAccount(account.data.account_sid, {
|
||||
name,
|
||||
enable_debug_log: enableDebugLog,
|
||||
...(!ENABLE_HOSTED_SYSTEM && { sip_realm: realm || null }),
|
||||
webhook_secret: account.data.webhook_secret,
|
||||
siprec_hook_sid: recId || null,
|
||||
@@ -450,6 +460,7 @@ export const AccountForm = ({
|
||||
queue_event_hook: queueHook || null,
|
||||
registration_hook: regHook || null,
|
||||
service_provider_sid: currentServiceProvider.service_provider_sid,
|
||||
enable_debug_log: enableDebugLog,
|
||||
})
|
||||
.then(({ json }) => {
|
||||
toastSuccess("Account created successfully");
|
||||
@@ -465,6 +476,7 @@ export const AccountForm = ({
|
||||
/** Set current account data values if applicable -- e.g. "edit mode" */
|
||||
useEffect(() => {
|
||||
if (account && account.data) {
|
||||
setEnableDebugLog(account.data.enable_debug_log);
|
||||
setName(account.data.name);
|
||||
|
||||
if (account.data.sip_realm) {
|
||||
@@ -1021,6 +1033,22 @@ export const AccountForm = ({
|
||||
} cached TTS prompts`}</MS>
|
||||
</fieldset>
|
||||
)}
|
||||
<ScopedAccess scope={Scope.admin} user={user}>
|
||||
<fieldset>
|
||||
<label htmlFor="enable_debug_log" className="chk">
|
||||
<input
|
||||
id="enable_debug_log"
|
||||
name="enable_debug_log"
|
||||
type="checkbox"
|
||||
onChange={(e) => setEnableDebugLog(e.target.checked)}
|
||||
checked={enableDebugLog}
|
||||
/>
|
||||
<Tooltip text="You can enable debug log for calls only to this account">
|
||||
Enable debug log for this account
|
||||
</Tooltip>
|
||||
</label>
|
||||
</fieldset>
|
||||
</ScopedAccess>
|
||||
{!DISABLE_CALL_RECORDING && (
|
||||
<>
|
||||
<fieldset>
|
||||
|
||||
@@ -113,59 +113,62 @@ export const Applications = () => {
|
||||
{!hasValue(applications) && hasLength(accounts) ? (
|
||||
<Spinner />
|
||||
) : hasLength(filteredApplications) ? (
|
||||
filteredApplications.map((application) => {
|
||||
return (
|
||||
<div className="item" key={application.application_sid}>
|
||||
<div className="item__info">
|
||||
<div className="item__title">
|
||||
<Link
|
||||
to={`${ROUTE_INTERNAL_APPLICATIONS}/${application.application_sid}/edit`}
|
||||
title="Edit application"
|
||||
className="i"
|
||||
>
|
||||
<strong>{application.name}</strong>
|
||||
<Icons.ArrowRight />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="item__meta">
|
||||
<div>
|
||||
<div
|
||||
className={`i txt--${
|
||||
application.account_sid ? "teal" : "grey"
|
||||
}`}
|
||||
filteredApplications
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((application) => {
|
||||
return (
|
||||
<div className="item" key={application.application_sid}>
|
||||
<div className="item__info">
|
||||
<div className="item__title">
|
||||
<Link
|
||||
to={`${ROUTE_INTERNAL_APPLICATIONS}/${application.application_sid}/edit`}
|
||||
title="Edit application"
|
||||
className="i"
|
||||
>
|
||||
<Icons.Activity />
|
||||
<span>
|
||||
{
|
||||
accounts?.find(
|
||||
(acct) =>
|
||||
acct.account_sid === application.account_sid,
|
||||
)?.name
|
||||
}
|
||||
</span>
|
||||
<strong>{application.name}</strong>
|
||||
<Icons.ArrowRight />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="item__meta">
|
||||
<div>
|
||||
<div
|
||||
className={`i txt--${
|
||||
application.account_sid ? "teal" : "grey"
|
||||
}`}
|
||||
>
|
||||
<Icons.Activity />
|
||||
<span>
|
||||
{
|
||||
accounts?.find(
|
||||
(acct) =>
|
||||
acct.account_sid ===
|
||||
application.account_sid,
|
||||
)?.name
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="item__actions">
|
||||
<Link
|
||||
to={`${ROUTE_INTERNAL_APPLICATIONS}/${application.application_sid}/edit`}
|
||||
title="Edit application"
|
||||
>
|
||||
<Icons.Edit3 />
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
title="Delete application"
|
||||
onClick={() => setApplication(application)}
|
||||
className="btnty"
|
||||
>
|
||||
<Icons.Trash />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="item__actions">
|
||||
<Link
|
||||
to={`${ROUTE_INTERNAL_APPLICATIONS}/${application.application_sid}/edit`}
|
||||
title="Edit application"
|
||||
>
|
||||
<Icons.Edit3 />
|
||||
</Link>
|
||||
<button
|
||||
type="button"
|
||||
title="Delete application"
|
||||
onClick={() => setApplication(application)}
|
||||
className="btnty"
|
||||
>
|
||||
<Icons.Trash />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
) : accountSid ? (
|
||||
<M>No applications.</M>
|
||||
) : (
|
||||
|
||||
@@ -28,6 +28,8 @@ import {
|
||||
VENDOR_SONIOX,
|
||||
VENDOR_WELLSAID,
|
||||
VENDOR_WHISPER,
|
||||
VENDOR_SPEECHMATICS,
|
||||
VENDOR_PLAYHT,
|
||||
} from "src/vendor";
|
||||
import {
|
||||
LabelOptions,
|
||||
@@ -198,6 +200,19 @@ export const SpeechProviderSelection = ({
|
||||
if (synthesisGoogleCustomVoiceOptions.length > 0) {
|
||||
updateTtsVoice(synthesisGoogleCustomVoiceOptions[0].value);
|
||||
}
|
||||
}
|
||||
// PlayHT3.0 all voices are listed under english language, all voices can be used for multiple languages
|
||||
else if (
|
||||
synthVendor === VENDOR_PLAYHT &&
|
||||
synthesisSupportedLanguagesAndVoices.tts.some(
|
||||
(l) => l.value === "english",
|
||||
)
|
||||
) {
|
||||
setSynthesisVoiceOptions(
|
||||
synthesisSupportedLanguagesAndVoices.tts.find(
|
||||
(tts) => tts.value === "english",
|
||||
)!.voices,
|
||||
);
|
||||
} else {
|
||||
setSynthesisVoiceOptions(voicesOpts);
|
||||
}
|
||||
@@ -261,6 +276,14 @@ export const SpeechProviderSelection = ({
|
||||
updateTtsVoice(newLang!.voices[0].value);
|
||||
return;
|
||||
}
|
||||
if (synthVendor === VENDOR_PLAYHT) {
|
||||
const newLang = json.tts.find(
|
||||
(lang) => lang.value === LANG_EN_US || lang.value === "english",
|
||||
);
|
||||
setSynthLang(newLang!.value);
|
||||
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);
|
||||
@@ -360,8 +383,9 @@ export const SpeechProviderSelection = ({
|
||||
value={synthVendor}
|
||||
options={ttsVendorOptions.filter(
|
||||
(vendor) =>
|
||||
vendor.value != VENDOR_ASSEMBLYAI &&
|
||||
vendor.value != VENDOR_SONIOX &&
|
||||
vendor.value !== VENDOR_ASSEMBLYAI &&
|
||||
vendor.value !== VENDOR_SONIOX &&
|
||||
vendor.value !== VENDOR_SPEECHMATICS &&
|
||||
vendor.value !== VENDOR_CUSTOM &&
|
||||
vendor.value !== VENDOR_COBALT,
|
||||
)}
|
||||
@@ -383,6 +407,7 @@ export const SpeechProviderSelection = ({
|
||||
value={synthLabel}
|
||||
options={ttsLabelOptions}
|
||||
onChange={(e) => {
|
||||
shouldUpdateTtsVoice.current = true;
|
||||
setSynthLabel(e.target.value);
|
||||
}}
|
||||
/>
|
||||
@@ -410,7 +435,9 @@ export const SpeechProviderSelection = ({
|
||||
id="synthesis_lang"
|
||||
name="synthesis_lang"
|
||||
value={synthLang}
|
||||
options={synthesisLanguageOptions}
|
||||
options={synthesisLanguageOptions.sort((a, b) =>
|
||||
a.name.localeCompare(b.name),
|
||||
)}
|
||||
onChange={(e) => {
|
||||
shouldUpdateTtsVoice.current = true;
|
||||
const language = e.target.value;
|
||||
@@ -465,7 +492,9 @@ export const SpeechProviderSelection = ({
|
||||
id="synthesis_voice"
|
||||
name="synthesis_voice"
|
||||
value={synthVoice}
|
||||
options={synthesisVoiceOptions}
|
||||
options={synthesisVoiceOptions.sort((a, b) =>
|
||||
a.name.localeCompare(b.name),
|
||||
)}
|
||||
onChange={(e) => setSynthVoice(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1096,29 +1096,24 @@ export const CarrierForm = ({
|
||||
<div>Outbound</div>
|
||||
</label>
|
||||
</div>
|
||||
{g.outbound > 0 && g.protocol === "tls/srtp" && (
|
||||
<div>
|
||||
<label
|
||||
htmlFor={`sip_pad_crypto_${i}`}
|
||||
className="chk"
|
||||
>
|
||||
<input
|
||||
id={`sip_pad_crypto_${i}`}
|
||||
name={`sip_pad_crypto_${i}`}
|
||||
type="checkbox"
|
||||
checked={g.pad_crypto ? true : false}
|
||||
onChange={(e) => {
|
||||
updateSipGateways(
|
||||
i,
|
||||
"pad_crypto",
|
||||
e.target.checked,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<div>Pad crypto</div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<label htmlFor={`sip_pad_crypto_${i}`} className="chk">
|
||||
<input
|
||||
id={`sip_pad_crypto_${i}`}
|
||||
name={`sip_pad_crypto_${i}`}
|
||||
type="checkbox"
|
||||
checked={g.pad_crypto ? true : false}
|
||||
onChange={(e) => {
|
||||
updateSipGateways(
|
||||
i,
|
||||
"pad_crypto",
|
||||
e.target.checked,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<div>Pad crypto</div>
|
||||
</label>
|
||||
</div>
|
||||
{Boolean(g.outbound) && (
|
||||
<div>
|
||||
<label
|
||||
@@ -1142,6 +1137,30 @@ export const CarrierForm = ({
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{Boolean(g.outbound) &&
|
||||
(g.protocol === "tls" || g.protocol === "tls/srtp") && (
|
||||
<div>
|
||||
<label
|
||||
htmlFor={`use_sips_scheme_${i}`}
|
||||
className="chk"
|
||||
>
|
||||
<input
|
||||
id={`use_sips_scheme_${i}`}
|
||||
name={`use_sips_scheme_${i}`}
|
||||
type="checkbox"
|
||||
checked={g.use_sips_scheme ? true : false}
|
||||
onChange={(e) => {
|
||||
updateSipGateways(
|
||||
i,
|
||||
"use_sips_scheme",
|
||||
e.target.checked,
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<div>Use sips scheme</div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
|
||||
@@ -200,9 +200,11 @@ export const PhoneNumberForm = ({ phoneNumber }: PhoneNumberFormProps) => {
|
||||
application={[applicationSid, setApplicationSid]}
|
||||
applications={
|
||||
applications
|
||||
? applications.filter(
|
||||
(application) => application.account_sid === accountSid,
|
||||
)
|
||||
? applications
|
||||
.filter(
|
||||
(application) => application.account_sid === accountSid,
|
||||
)
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
: []
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -7,11 +7,20 @@ import {
|
||||
postSystemInformation,
|
||||
deleteTtsCache,
|
||||
} from "src/api";
|
||||
import { PasswordSettings, SystemInformation, TtsCache } from "src/api/types";
|
||||
import {
|
||||
LogLevel,
|
||||
PasswordSettings,
|
||||
SystemInformation,
|
||||
TtsCache,
|
||||
} from "src/api/types";
|
||||
import { toastError, toastSuccess } from "src/store";
|
||||
import { Selector } from "src/components/forms";
|
||||
import { hasValue } from "src/utils";
|
||||
import { PASSWORD_LENGTHS_OPTIONS, PASSWORD_MIN } from "src/api/constants";
|
||||
import { hasValue, isvalidIpv4OrCidr } from "src/utils";
|
||||
import {
|
||||
LOG_LEVEL_OPTIONS,
|
||||
PASSWORD_LENGTHS_OPTIONS,
|
||||
PASSWORD_MIN,
|
||||
} from "src/api/constants";
|
||||
import { Modal } from "src/components";
|
||||
|
||||
export const AdminSettings = () => {
|
||||
@@ -25,9 +34,11 @@ export const AdminSettings = () => {
|
||||
const [requireDigit, setRequireDigit] = useState(false);
|
||||
const [requireSpecialCharacter, setRequireSpecialCharacter] = useState(false);
|
||||
const [domainName, setDomainName] = useState("");
|
||||
const [privateNetworkCidr, setPrivateNetworkCidr] = useState("");
|
||||
const [sipDomainName, setSipDomainName] = useState("");
|
||||
const [monitoringDomainName, setMonitoringDomainName] = useState("");
|
||||
const [clearTtsCacheFlag, setClearTtsCacheFlag] = useState(false);
|
||||
const [logLevel, setLogLevel] = useState<LogLevel>("info");
|
||||
|
||||
const handleClearCache = () => {
|
||||
deleteTtsCache()
|
||||
@@ -44,10 +55,22 @@ export const AdminSettings = () => {
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (privateNetworkCidr) {
|
||||
const cidrs = privateNetworkCidr.split(",");
|
||||
for (const cidr of cidrs) {
|
||||
if (cidr && !isvalidIpv4OrCidr(cidr)) {
|
||||
toastError(`Invalid private network CIDR "${cidr}"`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const systemInformationPayload: Partial<SystemInformation> = {
|
||||
domain_name: domainName,
|
||||
sip_domain_name: sipDomainName,
|
||||
monitoring_domain_name: monitoringDomainName,
|
||||
domain_name: domainName || null,
|
||||
sip_domain_name: sipDomainName || null,
|
||||
monitoring_domain_name: monitoringDomainName || null,
|
||||
private_network_cidr: privateNetworkCidr || null,
|
||||
log_level: logLevel,
|
||||
};
|
||||
const passwordSettingsPayload: Partial<PasswordSettings> = {
|
||||
min_password_length: minPasswordLength,
|
||||
@@ -61,7 +84,7 @@ export const AdminSettings = () => {
|
||||
.then(() => {
|
||||
passwordSettingsFetcher();
|
||||
systemInformationFetcher();
|
||||
toastSuccess("Password settings successfully updated");
|
||||
toastSuccess("Admin settings updated successfully");
|
||||
})
|
||||
.catch((error) => {
|
||||
toastError(error.msg);
|
||||
@@ -78,11 +101,21 @@ export const AdminSettings = () => {
|
||||
setMinPasswordLength(passwordSettings.min_password_length);
|
||||
}
|
||||
}
|
||||
if (hasValue(systemInformation)) {
|
||||
if (systemInformation?.domain_name) {
|
||||
setDomainName(systemInformation.domain_name);
|
||||
}
|
||||
if (systemInformation?.sip_domain_name) {
|
||||
setSipDomainName(systemInformation.sip_domain_name);
|
||||
}
|
||||
if (systemInformation?.monitoring_domain_name) {
|
||||
setMonitoringDomainName(systemInformation.monitoring_domain_name);
|
||||
}
|
||||
if (systemInformation?.private_network_cidr) {
|
||||
setPrivateNetworkCidr(systemInformation.private_network_cidr);
|
||||
}
|
||||
if (systemInformation?.log_level) {
|
||||
setLogLevel(systemInformation.log_level);
|
||||
}
|
||||
}, [passwordSettings, systemInformation]);
|
||||
|
||||
return (
|
||||
@@ -107,6 +140,15 @@ export const AdminSettings = () => {
|
||||
value={sipDomainName}
|
||||
onChange={(e) => setSipDomainName(e.target.value)}
|
||||
/>
|
||||
<label htmlFor="name">Private Network CIDR</label>
|
||||
<input
|
||||
id="private_network_cidr"
|
||||
type="text"
|
||||
name="private_network_cidr"
|
||||
placeholder="Private network CIDR"
|
||||
value={privateNetworkCidr}
|
||||
onChange={(e) => setPrivateNetworkCidr(e.target.value)}
|
||||
/>
|
||||
<label htmlFor="name">Monitoring Domain Name</label>
|
||||
<input
|
||||
id="monitor_domain_name"
|
||||
@@ -116,6 +158,17 @@ export const AdminSettings = () => {
|
||||
value={monitoringDomainName}
|
||||
onChange={(e) => setMonitoringDomainName(e.target.value)}
|
||||
/>
|
||||
|
||||
<label htmlFor="audio_format">Log Level</label>
|
||||
<Selector
|
||||
id={"audio_format"}
|
||||
name={"audio_format"}
|
||||
value={logLevel}
|
||||
options={LOG_LEVEL_OPTIONS}
|
||||
onChange={(e) => {
|
||||
setLogLevel(e.target.value as LogLevel);
|
||||
}}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label htmlFor="min_password_length">Min password length</label>
|
||||
|
||||
@@ -46,6 +46,8 @@ import {
|
||||
AWS_CREDENTIAL_IAM_ASSUME_ROLE,
|
||||
AWS_CREDENTIAL_ACCESS_KEY,
|
||||
AWS_INSTANCE_PROFILE,
|
||||
VENDOR_VERBIO,
|
||||
VENDOR_SPEECHMATICS,
|
||||
} from "src/vendor";
|
||||
import { MSG_REQUIRED_FIELDS } from "src/constants";
|
||||
import {
|
||||
@@ -73,12 +75,16 @@ import type {
|
||||
} from "src/api/types";
|
||||
import { setAccountFilter, setLocation } from "src/store/localStore";
|
||||
import {
|
||||
ADDITIONAL_SPEECH_VENDORS,
|
||||
DEFAULT_ELEVENLABS_OPTIONS,
|
||||
DEFAULT_GOOGLE_CUSTOM_VOICES_REPORTED_USAGE,
|
||||
DEFAULT_PLAYHT_OPTIONS,
|
||||
DEFAULT_RIMELABS_OPTIONS,
|
||||
DEFAULT_VERBIO_MODEL,
|
||||
DISABLE_ADDITIONAL_SPEECH_VENDORS,
|
||||
DISABLE_CUSTOM_SPEECH,
|
||||
GOOGLE_CUSTOM_VOICES_REPORTED_USAGE,
|
||||
VERBIO_STT_MODELS,
|
||||
} from "src/api/constants";
|
||||
|
||||
type SpeechServiceFormProps = {
|
||||
@@ -106,6 +112,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
const [secretAccessKey, setSecretAccessKey] = useState("");
|
||||
const [clientId, setClientId] = useState("");
|
||||
const [secretKey, setSecretKey] = useState("");
|
||||
const [clientSecret, setClientSecret] = useState("");
|
||||
const [googleServiceKey, setGoogleServiceKey] =
|
||||
useState<GoogleServiceKey | null>(null);
|
||||
const [sttRegion, setSttRegion] = useState("");
|
||||
@@ -113,6 +120,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
const [ttsRegion, setTtsRegion] = useState("");
|
||||
const [ttsApiKey, setTtsApiKey] = useState("");
|
||||
const [ttsModelId, setTtsModelId] = useState("");
|
||||
const [engineVersion, setEngineVersion] = useState(DEFAULT_VERBIO_MODEL);
|
||||
const [instanceId, setInstanceId] = useState("");
|
||||
const [initialCheckCustomTts, setInitialCheckCustomTts] = useState(false);
|
||||
const [initialCheckCustomStt, setInitialCheckCustomStt] = useState(false);
|
||||
@@ -155,12 +163,20 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
const [options, setOptions] = useState("");
|
||||
const [tmpOptions, setTmpOptions] = useState("");
|
||||
const [deepgramSttUri, setDeepgramSttUri] = useState("");
|
||||
const [deepgramTtsUri, setDeepgramTtsUri] = useState("");
|
||||
const [tmpDeepgramSttUri, setTmpDeepgramSttUri] = useState("");
|
||||
const [tmpDeepgramTtsUri, setTmpDeepgramTtsUri] = useState("");
|
||||
const [deepgramSttUseTls, setDeepgramSttUseTls] = useState(false);
|
||||
const [tmpDeepgramSttUseTls, setTmpDeepgramSttUseTls] = useState(false);
|
||||
const [initialDeepgramOnpremCheck, setInitialDeepgramOnpremCheck] =
|
||||
useState(false);
|
||||
const [isDeepgramOnpremEnabled, setIsDeepgramOnpremEnabled] = useState(false);
|
||||
const [initialSpeechmaticsOnpremCheck, setInitialSpeechMaticsOnpremCheck] =
|
||||
useState(false);
|
||||
const [speechmaticsEndpoint, setSpeechmaticsEndpoint] = useState("");
|
||||
const [tmpHostedSpeechmaticsEndpoint, setTmpHostedSpeechmaticsEndpoint] =
|
||||
useState("");
|
||||
const [tmpOnpremSpeechmaticsEndpoint, setTmpOnpremSpeechmaticsEndpoint] =
|
||||
useState("");
|
||||
const [awsCredentialType, setAwsCredentialType] = useState(
|
||||
AWS_CREDENTIAL_ACCESS_KEY,
|
||||
);
|
||||
@@ -351,8 +367,15 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
}),
|
||||
...(vendor === VENDOR_DEEPGRAM && {
|
||||
deepgram_stt_uri: deepgramSttUri || null,
|
||||
deepgram_tts_uri: deepgramTtsUri || null,
|
||||
deepgram_stt_use_tls: deepgramSttUseTls ? 1 : 0,
|
||||
}),
|
||||
...(vendor === VENDOR_SPEECHMATICS && {
|
||||
speechmatics_stt_uri: speechmaticsEndpoint || null,
|
||||
}),
|
||||
...(vendor === VENDOR_VERBIO && {
|
||||
engine_version: engineVersion,
|
||||
}),
|
||||
};
|
||||
|
||||
if (credential && credential.data) {
|
||||
@@ -394,6 +417,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
vendor === VENDOR_DEEPGRAM ||
|
||||
vendor === VENDOR_ASSEMBLYAI ||
|
||||
vendor === VENDOR_SONIOX ||
|
||||
vendor === VENDOR_SPEECHMATICS ||
|
||||
vendor === VENDOR_ELEVENLABS ||
|
||||
vendor === VENDOR_PLAYHT ||
|
||||
vendor === VENDOR_RIMELABS ||
|
||||
@@ -405,6 +429,10 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
userId && {
|
||||
user_id: userId,
|
||||
}),
|
||||
...(vendor === VENDOR_VERBIO && {
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
}),
|
||||
riva_server_uri: vendor == VENDOR_NVIDIA ? rivaServerUri : null,
|
||||
})
|
||||
.then(({ json }) => {
|
||||
@@ -445,6 +473,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
currentServiceProvider?.service_provider_sid,
|
||||
vendor,
|
||||
"",
|
||||
credential ? false : true,
|
||||
).then(({ json }) => {
|
||||
if (json.models) {
|
||||
setTtsModels(json.models);
|
||||
@@ -620,13 +649,15 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
if (credential?.data?.deepgram_stt_uri) {
|
||||
setDeepgramSttUri(credential.data.deepgram_stt_uri);
|
||||
}
|
||||
if (credential?.data?.deepgram_tts_uri) {
|
||||
setDeepgramTtsUri(credential.data.deepgram_tts_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));
|
||||
|
||||
if (credential?.data?.user_id) {
|
||||
setUserId(credential.data.user_id);
|
||||
@@ -647,6 +678,22 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
: AWS_INSTANCE_PROFILE,
|
||||
);
|
||||
}
|
||||
if (credential?.data?.client_id) {
|
||||
setClientId(credential.data.client_id);
|
||||
}
|
||||
if (credential?.data?.client_secret) {
|
||||
setClientSecret(credential.data.client_secret);
|
||||
}
|
||||
if (credential?.data?.engine_version) {
|
||||
setEngineVersion(credential.data.engine_version);
|
||||
}
|
||||
|
||||
if (credential?.data?.speechmatics_stt_uri) {
|
||||
setInitialSpeechMaticsOnpremCheck(
|
||||
!credential.data.speechmatics_stt_uri?.includes("speechmatics.com"),
|
||||
);
|
||||
setSpeechmaticsEndpoint(credential.data.speechmatics_stt_uri);
|
||||
}
|
||||
}, [credential]);
|
||||
|
||||
const updateCustomVoices = (
|
||||
@@ -699,7 +746,12 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
]
|
||||
.concat(vendors)
|
||||
.filter(
|
||||
(v) => !DISABLE_CUSTOM_SPEECH || v.value !== VENDOR_CUSTOM,
|
||||
(v) =>
|
||||
(!DISABLE_CUSTOM_SPEECH || v.value !== VENDOR_CUSTOM) &&
|
||||
(!DISABLE_ADDITIONAL_SPEECH_VENDORS ||
|
||||
!ADDITIONAL_SPEECH_VENDORS.includes(
|
||||
v.value as Lowercase<Vendor>,
|
||||
)),
|
||||
)}
|
||||
onChange={(e) => {
|
||||
setVendor(e.target.value as Lowercase<Vendor>);
|
||||
@@ -758,6 +810,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
{vendor !== VENDOR_ASSEMBLYAI &&
|
||||
vendor !== VENDOR_COBALT &&
|
||||
vendor !== VENDOR_SONIOX &&
|
||||
vendor !== VENDOR_SPEECHMATICS &&
|
||||
vendor != VENDOR_CUSTOM && (
|
||||
<label htmlFor="use_for_tts" className="chk">
|
||||
<input
|
||||
@@ -1183,6 +1236,58 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
</fieldset>
|
||||
</>
|
||||
)}
|
||||
{vendor === VENDOR_VERBIO && (
|
||||
<>
|
||||
<fieldset>
|
||||
<label htmlFor="verbio_client_id">
|
||||
Client ID
|
||||
{!onPremNuanceSttCheck && !onPremNuanceTtsCheck && (
|
||||
<span>*</span>
|
||||
)}
|
||||
</label>
|
||||
<input
|
||||
id="verbio_client_id"
|
||||
required
|
||||
type="text"
|
||||
name="verbio_client_id"
|
||||
placeholder="Client ID"
|
||||
value={clientId}
|
||||
onChange={(e) => setClientId(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
<label htmlFor="verbio_client_secret">
|
||||
Client secret
|
||||
{!onPremNuanceSttCheck && !onPremNuanceTtsCheck && (
|
||||
<span>*</span>
|
||||
)}
|
||||
</label>
|
||||
<input
|
||||
id="verbio_client_secret"
|
||||
required
|
||||
type="text"
|
||||
name="verbio_client_secret"
|
||||
placeholder="Client secret"
|
||||
value={clientSecret}
|
||||
onChange={(e) => setClientSecret(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label htmlFor={`${vendor}_tts_model_id`}>
|
||||
Engine version<span>*</span>
|
||||
</label>
|
||||
<Selector
|
||||
id={"verbio_engine_version"}
|
||||
name={"verbio_engine_version"}
|
||||
value={engineVersion}
|
||||
options={VERBIO_STT_MODELS}
|
||||
onChange={(e) => {
|
||||
setEngineVersion(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</fieldset>
|
||||
</>
|
||||
)}
|
||||
{vendor === VENDOR_AWS && (
|
||||
<fieldset>
|
||||
<label htmlFor="vendor">
|
||||
@@ -1262,7 +1367,8 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
vendor === VENDOR_WHISPER ||
|
||||
vendor === VENDOR_PLAYHT ||
|
||||
vendor === VENDOR_RIMELABS ||
|
||||
vendor === VENDOR_SONIOX) && (
|
||||
vendor === VENDOR_SONIOX ||
|
||||
vendor === VENDOR_SPEECHMATICS) && (
|
||||
<fieldset>
|
||||
{vendor === VENDOR_PLAYHT && (
|
||||
<>
|
||||
@@ -1311,22 +1417,6 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
/>
|
||||
</fieldset>
|
||||
)}
|
||||
{vendor === VENDOR_DEEPGRAM && (
|
||||
<fieldset>
|
||||
<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 ||
|
||||
vendor == VENDOR_RIMELABS) &&
|
||||
@@ -1429,6 +1519,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
{regions &&
|
||||
regions[vendor as keyof RegionVendors] &&
|
||||
vendor !== VENDOR_IBM &&
|
||||
vendor !== VENDOR_SPEECHMATICS &&
|
||||
vendor !== VENDOR_MICROSOFT && (
|
||||
<fieldset>
|
||||
<label htmlFor="region">
|
||||
@@ -1529,11 +1620,52 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
disabled={hasValue(credential)}
|
||||
hidden
|
||||
name="use_hosted_deepgram_service"
|
||||
label="Use hosted Deepgram Service"
|
||||
initialCheck={!initialDeepgramOnpremCheck}
|
||||
handleChecked={(e) => {
|
||||
setInitialDeepgramOnpremCheck(!e.target.checked);
|
||||
|
||||
if (e.target.checked) {
|
||||
setTmpDeepgramSttUri(deepgramSttUri);
|
||||
setDeepgramSttUri("");
|
||||
setTmpDeepgramSttUseTls(deepgramSttUseTls);
|
||||
setDeepgramSttUseTls(false);
|
||||
setTmpDeepgramTtsUri(deepgramTtsUri);
|
||||
setDeepgramTtsUri("");
|
||||
} else {
|
||||
if (tmpDeepgramSttUri) {
|
||||
setDeepgramSttUri(tmpDeepgramSttUri);
|
||||
}
|
||||
if (tmpDeepgramSttUseTls) {
|
||||
setDeepgramSttUseTls(tmpDeepgramSttUseTls);
|
||||
}
|
||||
if (tmpDeepgramTtsUri) {
|
||||
setDeepgramTtsUri(tmpDeepgramTtsUri);
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor={`${vendor}_apikey`}>
|
||||
API key<span>*</span>
|
||||
</label>
|
||||
<Passwd
|
||||
id={`${vendor}_apikey`}
|
||||
required
|
||||
name={`${vendor}_apikey`}
|
||||
placeholder="API key"
|
||||
value={credential ? getObscuredSecret(apiKey) : apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
</Checkzone>
|
||||
<Checkzone
|
||||
disabled={hasValue(credential)}
|
||||
hidden
|
||||
name="use_on-prem_deepgram_container"
|
||||
label="Use on-prem Deepgram container"
|
||||
initialCheck={initialDeepgramOnpremCheck}
|
||||
handleChecked={(e) => {
|
||||
// setInitialDeepgramOnpremCheck(!e.target.checked);
|
||||
setIsDeepgramOnpremEnabled(e.target.checked);
|
||||
setInitialDeepgramOnpremCheck(e.target.checked);
|
||||
if (e.target.checked) {
|
||||
if (tmpDeepgramSttUri) {
|
||||
setDeepgramSttUri(tmpDeepgramSttUri);
|
||||
@@ -1541,36 +1673,63 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
if (tmpDeepgramSttUseTls) {
|
||||
setDeepgramSttUseTls(tmpDeepgramSttUseTls);
|
||||
}
|
||||
if (tmpDeepgramTtsUri) {
|
||||
setDeepgramTtsUri(tmpDeepgramTtsUri);
|
||||
}
|
||||
} else {
|
||||
setTmpDeepgramSttUri(deepgramSttUri);
|
||||
setDeepgramSttUri("");
|
||||
setTmpDeepgramSttUseTls(deepgramSttUseTls);
|
||||
setDeepgramSttUseTls(false);
|
||||
setTmpDeepgramTtsUri(deepgramTtsUri);
|
||||
setDeepgramTtsUri("");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="deepgram_uri_for_stt">
|
||||
STT Container URI<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="deepgram_uri_for_stt"
|
||||
required
|
||||
type="text"
|
||||
name="deepgram_uri_for_stt"
|
||||
placeholder="Container URI for STT"
|
||||
value={deepgramSttUri}
|
||||
onChange={(e) => setDeepgramSttUri(e.target.value)}
|
||||
/>
|
||||
<label htmlFor="deepgram_stt_use_tls" className="chk">
|
||||
<input
|
||||
id="deepgram_stt_use_tls"
|
||||
name="deepgram_stt_use_tls"
|
||||
type="checkbox"
|
||||
onChange={(e) => setDeepgramSttUseTls(e.target.checked)}
|
||||
defaultChecked={deepgramSttUseTls}
|
||||
/>
|
||||
<div>Use TLS for STT</div>
|
||||
</label>
|
||||
|
||||
<label htmlFor="deepgram_uri_for_tts">
|
||||
Container URI<span>*</span>
|
||||
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)}
|
||||
placeholder="http://"
|
||||
value={deepgramTtsUri}
|
||||
onChange={(e) => setDeepgramTtsUri(e.target.value)}
|
||||
/>
|
||||
<label htmlFor={`${vendor}_apikey`}>Api key (if required)</label>
|
||||
<Passwd
|
||||
id={`${vendor}_apikey`}
|
||||
name={`${vendor}_apikey`}
|
||||
placeholder="API key"
|
||||
value={credential ? getObscuredSecret(apiKey) : apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
<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>
|
||||
)}
|
||||
@@ -1775,6 +1934,73 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
</fieldset>
|
||||
</React.Fragment>
|
||||
)}
|
||||
{vendor === VENDOR_SPEECHMATICS &&
|
||||
regions &&
|
||||
regions[vendor as keyof RegionVendors] && (
|
||||
<fieldset>
|
||||
<Checkzone
|
||||
disabled={hasValue(credential)}
|
||||
hidden
|
||||
name="use_hosted_speechmatics_service"
|
||||
label="Use hosted Speechmatics Service"
|
||||
initialCheck={!initialSpeechmaticsOnpremCheck}
|
||||
handleChecked={(e) => {
|
||||
setInitialSpeechMaticsOnpremCheck(!e.target.checked);
|
||||
if (e.target.checked) {
|
||||
setTmpOnpremSpeechmaticsEndpoint(speechmaticsEndpoint);
|
||||
setSpeechmaticsEndpoint(tmpHostedSpeechmaticsEndpoint);
|
||||
setTmpHostedSpeechmaticsEndpoint("");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="speechmatics_endpoint">
|
||||
Endpoint {sttCheck && <span>*</span>}
|
||||
</label>
|
||||
<Selector
|
||||
id="speechmatics_endpoint"
|
||||
name="speechmatics_endpoint"
|
||||
value={speechmaticsEndpoint}
|
||||
required
|
||||
options={[
|
||||
{
|
||||
name: "Select a endpoint",
|
||||
value: "",
|
||||
},
|
||||
].concat(regions[vendor as keyof RegionVendors])}
|
||||
onChange={(e) => setSpeechmaticsEndpoint(e.target.value)}
|
||||
/>
|
||||
</Checkzone>
|
||||
|
||||
<Checkzone
|
||||
disabled={hasValue(credential)}
|
||||
hidden
|
||||
name="use_on-prem_speechmatics_container"
|
||||
label="Use on-prem Speechmatics container"
|
||||
initialCheck={initialSpeechmaticsOnpremCheck}
|
||||
handleChecked={(e) => {
|
||||
setInitialSpeechMaticsOnpremCheck(e.target.checked);
|
||||
if (e.target.checked) {
|
||||
setTmpHostedSpeechmaticsEndpoint(speechmaticsEndpoint);
|
||||
setSpeechmaticsEndpoint(tmpOnpremSpeechmaticsEndpoint);
|
||||
setTmpOnpremSpeechmaticsEndpoint("");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="speechmatics_uri_for_stt">
|
||||
Endpoint URI<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="speechmatics_uri_for_stt"
|
||||
required
|
||||
type="text"
|
||||
name="speechmatics_uri_for_stt"
|
||||
placeholder="Speechmatics URI for STT"
|
||||
value={speechmaticsEndpoint}
|
||||
onChange={(e) => setSpeechmaticsEndpoint(e.target.value)}
|
||||
/>
|
||||
</Checkzone>
|
||||
</fieldset>
|
||||
)}
|
||||
|
||||
<fieldset>
|
||||
<ButtonGroup left>
|
||||
|
||||
@@ -89,6 +89,22 @@ export const getIpValidationType = (ipv4: string): IpType => {
|
||||
return type;
|
||||
};
|
||||
|
||||
function isValidIPV4(ip: string): boolean {
|
||||
const ipv4Pattern =
|
||||
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
|
||||
return ipv4Pattern.test(ip);
|
||||
}
|
||||
|
||||
function isValidCIDR(cidr: string): boolean {
|
||||
const cidrPattern =
|
||||
/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))(\/([0-9]|[1-2][0-9]|3[0-2]))$/;
|
||||
return cidrPattern.test(cidr);
|
||||
}
|
||||
|
||||
export function isvalidIpv4OrCidr(input: string): boolean {
|
||||
return isValidIPV4(input) || isValidCIDR(input);
|
||||
}
|
||||
|
||||
export const getObscured = (str: string, sub = 4, char = "*") => {
|
||||
const len = str.length - sub;
|
||||
const obscured = str.substring(0, len).replace(/[a-zA-Z0-9]/g, char);
|
||||
|
||||
13
src/vendor/index.tsx
vendored
13
src/vendor/index.tsx
vendored
@@ -15,6 +15,7 @@ export const VENDOR_DEEPGRAM = "deepgram";
|
||||
export const VENDOR_IBM = "ibm";
|
||||
export const VENDOR_NVIDIA = "nvidia";
|
||||
export const VENDOR_SONIOX = "soniox";
|
||||
export const VENDOR_SPEECHMATICS = "speechmatics";
|
||||
export const VENDOR_CUSTOM = "custom";
|
||||
export const VENDOR_COBALT = "cobalt";
|
||||
export const VENDOR_ELEVENLABS = "elevenlabs";
|
||||
@@ -22,6 +23,7 @@ export const VENDOR_ASSEMBLYAI = "assemblyai";
|
||||
export const VENDOR_WHISPER = "whisper";
|
||||
export const VENDOR_PLAYHT = "playht";
|
||||
export const VENDOR_RIMELABS = "rimelabs";
|
||||
export const VENDOR_VERBIO = "verbio";
|
||||
|
||||
export const vendors: VendorOptions[] = [
|
||||
{
|
||||
@@ -60,6 +62,10 @@ export const vendors: VendorOptions[] = [
|
||||
name: "Soniox",
|
||||
value: VENDOR_SONIOX,
|
||||
},
|
||||
{
|
||||
name: "Speechmatics",
|
||||
value: VENDOR_SPEECHMATICS,
|
||||
},
|
||||
{
|
||||
name: "Custom",
|
||||
value: VENDOR_CUSTOM,
|
||||
@@ -88,6 +94,10 @@ export const vendors: VendorOptions[] = [
|
||||
name: "RimeLabs",
|
||||
value: VENDOR_RIMELABS,
|
||||
},
|
||||
{
|
||||
name: "Verbio",
|
||||
value: VENDOR_VERBIO,
|
||||
},
|
||||
].sort((a, b) => a.name.localeCompare(b.name)) as VendorOptions[];
|
||||
|
||||
export const AWS_CREDENTIAL_ACCESS_KEY = "access_key";
|
||||
@@ -119,17 +129,20 @@ export const useRegionVendors = () => {
|
||||
import("./regions/aws-regions"),
|
||||
import("./regions/ms-azure-regions"),
|
||||
import("./regions/ibm-regions"),
|
||||
import("./regions/speechmatics-regions"),
|
||||
]).then(
|
||||
([
|
||||
{ default: awsRegions },
|
||||
{ default: msRegions },
|
||||
{ default: ibmRegions },
|
||||
{ default: speechmaticsRegions },
|
||||
]) => {
|
||||
if (!ignore) {
|
||||
setRegions({
|
||||
aws: awsRegions,
|
||||
microsoft: msRegions,
|
||||
ibm: ibmRegions,
|
||||
speechmatics: speechmaticsRegions,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
18
src/vendor/regions/speechmatics-regions.ts
vendored
Normal file
18
src/vendor/regions/speechmatics-regions.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { Region } from "../types";
|
||||
|
||||
export const regions: Region[] = [
|
||||
{
|
||||
name: "EU (EU2 - On-demand)",
|
||||
value: "eu2.rt.speechmatics.com",
|
||||
},
|
||||
{
|
||||
name: "EU (EU1 - Enterprise)",
|
||||
value: "neu.rt.speechmatics.com",
|
||||
},
|
||||
{
|
||||
name: "US (US1 - Enterprise)",
|
||||
value: "wus.rt.speechmatics.com",
|
||||
},
|
||||
];
|
||||
|
||||
export default regions;
|
||||
7
src/vendor/types.ts
vendored
7
src/vendor/types.ts
vendored
@@ -8,13 +8,15 @@ export type Vendor =
|
||||
| "IBM"
|
||||
| "Nvidia"
|
||||
| "Soniox"
|
||||
| "Speechmatics"
|
||||
| "Cobalt"
|
||||
| "Custom"
|
||||
| "ElevenLabs"
|
||||
| "assemblyai"
|
||||
| "whisper"
|
||||
| "playht"
|
||||
| "rimelabs";
|
||||
| "rimelabs"
|
||||
| "verbio";
|
||||
|
||||
export interface VendorOptions {
|
||||
name: Vendor;
|
||||
@@ -70,6 +72,7 @@ export interface RegionVendors {
|
||||
aws: Region[];
|
||||
microsoft: Region[];
|
||||
ibm: Region[];
|
||||
speechmatics: Region[];
|
||||
}
|
||||
|
||||
export interface TtsModels {
|
||||
@@ -87,6 +90,7 @@ export interface RecognizerVendors {
|
||||
ibm: Language[];
|
||||
nvidia: Language[];
|
||||
soniox: Language[];
|
||||
speechmatics: Language[];
|
||||
cobalt: Language[];
|
||||
assemblyai: Language[];
|
||||
}
|
||||
@@ -102,6 +106,7 @@ export interface SynthesisVendors {
|
||||
elevenlabs: VoiceLanguage[];
|
||||
whisper: VoiceLanguage[];
|
||||
deepgram: VoiceLanguage[];
|
||||
playht: VoiceLanguage[];
|
||||
}
|
||||
|
||||
export interface MSRawSpeech {
|
||||
|
||||
Reference in New Issue
Block a user