mirror of
https://github.com/jambonz/jambonz-webapp.git
synced 2026-02-08 04:59:37 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6c5a18c87 | ||
|
|
19742ab67e | ||
|
|
53d0c0b510 | ||
|
|
7a0eb71bae | ||
|
|
6aae8d9930 | ||
|
|
a70a1bf614 | ||
|
|
975a787f1e | ||
|
|
46e220f28b | ||
|
|
6836a99635 | ||
|
|
f7f4a2e7b1 | ||
|
|
f1f8a7d808 | ||
|
|
9dd9cf867a | ||
|
|
a372c09bc6 | ||
|
|
031e5e923e | ||
|
|
e02904f7f3 | ||
|
|
7eaf25d13f | ||
|
|
6e4d663337 | ||
|
|
c0a40dd784 | ||
|
|
536bf0f471 | ||
|
|
aaf1ede5c2 | ||
|
|
24d646f705 | ||
|
|
c648afcb1a | ||
|
|
4eca59d9bd |
2
.env
2
.env
@@ -1,4 +1,4 @@
|
||||
#VITE_API_BASE_URL=http://127.0.0.1:3000/v1
|
||||
# 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
|
||||
|
||||
3043
package-lock.json
generated
3043
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jambonz-webapp",
|
||||
"description": "A simple provisioning web app for jambonz",
|
||||
"version": "0.9.4",
|
||||
"version": "0.9.5",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
@@ -41,7 +41,7 @@
|
||||
"deploy": "npm i && npm run build && npm run pm2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@jambonz/ui-kit": "^0.0.21",
|
||||
"@jambonz/ui-kit": "^0.0.22",
|
||||
"@stripe/react-stripe-js": "^2.6.2",
|
||||
"@stripe/stripe-js": "^3.2.0",
|
||||
"dayjs": "^1.11.10",
|
||||
@@ -71,16 +71,16 @@
|
||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||
"eslint-plugin-react": "^7.34.1",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"express": "^4.19.2",
|
||||
"express": "^5.1.0",
|
||||
"husky": "^9.0.11",
|
||||
"lint-staged": "^15.2.2",
|
||||
"nanoid": "^5.0.7",
|
||||
"lint-staged": "^16.1.2",
|
||||
"nanoid": "^5.1.5",
|
||||
"prettier": "^3.2.5",
|
||||
"sass": "^1.74.1",
|
||||
"serve": "^14.2.1",
|
||||
"sass": "^1.89.2",
|
||||
"serve": "^14.2.4",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.4.4",
|
||||
"vite": "^5.2.8"
|
||||
"vite": "^6.0.1"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{ts,tsx}": "eslint --max-warnings=0",
|
||||
|
||||
@@ -3,6 +3,7 @@ import type {
|
||||
Currency,
|
||||
ElevenLabsOptions,
|
||||
GoogleCustomVoice,
|
||||
InworldOptions,
|
||||
LimitField,
|
||||
LimitUnitOption,
|
||||
PasswordSettings,
|
||||
@@ -130,7 +131,7 @@ export const DEFAULT_WEBHOOK: WebHook = {
|
||||
};
|
||||
|
||||
/** Default SIP/SMPP Gateways */
|
||||
export const DEFAULT_SIP_GATEWAY: SipGateway = {
|
||||
export const DEFAULT_SIP_INBOUND_GATEWAY: SipGateway = {
|
||||
voip_carrier_sid: "",
|
||||
ipv4: "",
|
||||
port: 5060,
|
||||
@@ -244,6 +245,14 @@ export const VERBIO_STT_MODELS = [
|
||||
|
||||
export const DEFAULT_VERBIO_MODEL = "V1";
|
||||
|
||||
// ASSEMBLYAI
|
||||
export const ASSEMBLYAI_STT_VERSIONS = [
|
||||
{ name: "V2", value: "v2" },
|
||||
{ name: "V3", value: "v3" },
|
||||
];
|
||||
|
||||
export const DEFAULT_ASSEMBLYAI_STT_VERSION = "v2";
|
||||
|
||||
export const ADDITIONAL_SPEECH_VENDORS: Lowercase<Vendor>[] = ["speechmatics"];
|
||||
|
||||
// Google Custom Voice reported usage options
|
||||
@@ -277,6 +286,14 @@ export const DEFAULT_RIMELABS_OPTIONS: Partial<RimelabsOptions> = {
|
||||
reduceLatency: true,
|
||||
};
|
||||
|
||||
export const DEFAULT_INWORLD_OPTIONS: Partial<InworldOptions> = {
|
||||
audioConfig: {
|
||||
pitch: 0.0,
|
||||
speakingRate: 1.0,
|
||||
},
|
||||
temperature: 0.8,
|
||||
};
|
||||
|
||||
// PlayHT options
|
||||
export const DEFAULT_PLAYHT_OPTIONS: Partial<PlayHTOptions> = {
|
||||
quality: "medium",
|
||||
@@ -331,6 +348,12 @@ export const DTMF_TYPE_SELECTION: SelectorOptions[] = [
|
||||
{ name: "Tones", value: "tones" },
|
||||
];
|
||||
|
||||
export const TRUNK_TYPE_SELECTION: SelectorOptions[] = [
|
||||
{ name: "IP Trunk", value: "static_ip" },
|
||||
{ name: "Auth Trunk", value: "auth" },
|
||||
{ name: "Registration Trunk", value: "reg" },
|
||||
];
|
||||
|
||||
/** Available webhook methods */
|
||||
export const WEBHOOK_METHODS: WebhookOption[] = [
|
||||
{
|
||||
@@ -401,6 +424,11 @@ export const CurrencySymbol: Currency = {
|
||||
usd: "$",
|
||||
};
|
||||
|
||||
export const DEEPGRAM_STT_ENPOINT = [
|
||||
{ name: "US (Default)", value: "" },
|
||||
{ name: "EU-hosted", value: "api.eu.deepgram.com" },
|
||||
];
|
||||
|
||||
/** User scope values values */
|
||||
export const USER_ADMIN = "admin";
|
||||
export const USER_SP = "service_provider";
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import type { Language, Model, Vendor, VoiceLanguage } from "src/vendor/types";
|
||||
import type {
|
||||
JambonzResourceOptions,
|
||||
Language,
|
||||
Model,
|
||||
Vendor,
|
||||
VoiceLanguage,
|
||||
} from "src/vendor/types";
|
||||
|
||||
/** Simple types */
|
||||
|
||||
@@ -413,6 +419,7 @@ export interface SpeechCredential {
|
||||
custom_stt_endpoint: null | string;
|
||||
client_id: null | string;
|
||||
client_secret: null | string;
|
||||
client_key: null | string;
|
||||
secret: null | string;
|
||||
nuance_tts_uri: null | string;
|
||||
nuance_stt_uri: null | string;
|
||||
@@ -429,8 +436,10 @@ export interface SpeechCredential {
|
||||
label: null | string;
|
||||
cobalt_server_uri: null | string;
|
||||
model_id: null | string;
|
||||
stt_model_id: null | string;
|
||||
voice_engine: null | string;
|
||||
engine_version: null | string;
|
||||
service_version: null | string;
|
||||
model: null | string;
|
||||
options: null | string;
|
||||
deepgram_stt_uri: null | string;
|
||||
@@ -438,6 +447,9 @@ export interface SpeechCredential {
|
||||
deepgram_stt_use_tls: number;
|
||||
speechmatics_stt_uri: null | string;
|
||||
playht_tts_uri: null | string;
|
||||
resemble_tts_uri: null | string;
|
||||
resemble_tts_use_tls: number;
|
||||
api_uri: null | string;
|
||||
}
|
||||
|
||||
export interface Alert {
|
||||
@@ -457,6 +469,8 @@ export interface CarrierRegisterStatus {
|
||||
|
||||
export type DtmfType = "rfc2833" | "tones" | "info";
|
||||
|
||||
export type TrunkType = "static_ip" | "auth" | "reg";
|
||||
|
||||
export interface Carrier {
|
||||
voip_carrier_sid: string;
|
||||
name: string;
|
||||
@@ -485,6 +499,7 @@ export interface Carrier {
|
||||
register_status: CarrierRegisterStatus;
|
||||
dtmf_type: DtmfType;
|
||||
outbound_sip_proxy: string | null;
|
||||
trunk_type: TrunkType;
|
||||
}
|
||||
|
||||
export interface PredefinedCarrier extends Carrier {
|
||||
@@ -780,6 +795,16 @@ export interface RimelabsOptions {
|
||||
reduceLatency: boolean;
|
||||
}
|
||||
|
||||
export interface InworldOptions {
|
||||
audioConfig: {
|
||||
bitRate?: number;
|
||||
sampleRateHertz?: number;
|
||||
pitch?: number;
|
||||
speakingRate?: number;
|
||||
};
|
||||
temperature?: number;
|
||||
}
|
||||
|
||||
export type CartesiaEmotions =
|
||||
| "anger:lowest"
|
||||
| "anger:low"
|
||||
@@ -811,6 +836,8 @@ export interface AppEnvProperty {
|
||||
obscure?: boolean;
|
||||
uiHint?: "input" | "textarea" | "filepicker";
|
||||
enum?: string[];
|
||||
jambonzResource?: "carriers";
|
||||
jambonzResourceOptions?: JambonzResourceOptions[];
|
||||
}
|
||||
|
||||
export interface AppEnv {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
}
|
||||
|
||||
select {
|
||||
@include ui-mixins.m();
|
||||
appearance: none;
|
||||
padding: ui-vars.$px01 ui-vars.$px02;
|
||||
border-radius: ui-vars.$px01;
|
||||
@@ -33,6 +32,7 @@
|
||||
background-color: ui-vars.$white;
|
||||
width: 100%;
|
||||
max-width: vars.$widthinput;
|
||||
@include ui-mixins.m();
|
||||
|
||||
&:focus {
|
||||
border-color: ui-vars.$dark;
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
}
|
||||
|
||||
@mixin typeahead-input {
|
||||
@include ui-mixins.m();
|
||||
appearance: none;
|
||||
padding: ui-vars.$px01 ui-vars.$px02;
|
||||
border-radius: ui-vars.$px01;
|
||||
@@ -37,6 +36,7 @@
|
||||
max-width: vars.$widthtypeaheadinput;
|
||||
transition: border-color 0.2s ease;
|
||||
font-family: inherit;
|
||||
@include ui-mixins.m();
|
||||
|
||||
&:focus {
|
||||
border-color: ui-vars.$dark;
|
||||
@@ -84,7 +84,6 @@
|
||||
}
|
||||
|
||||
@mixin typeahead-dropdown {
|
||||
@include ui-mixins.m();
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
@@ -93,6 +92,7 @@
|
||||
border: 1px solid ui-vars.$dark;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
@include ui-mixins.m();
|
||||
}
|
||||
|
||||
@mixin typeahead-option {
|
||||
@@ -126,8 +126,8 @@
|
||||
width: 100%;
|
||||
|
||||
input {
|
||||
@include typeahead-input();
|
||||
width: 100%;
|
||||
@include typeahead-input();
|
||||
}
|
||||
|
||||
span {
|
||||
@@ -135,8 +135,8 @@
|
||||
}
|
||||
|
||||
.typeahead-dropdown {
|
||||
@include typeahead-dropdown();
|
||||
z-index: 1000;
|
||||
@include typeahead-dropdown();
|
||||
}
|
||||
|
||||
.typeahead-option {
|
||||
@@ -149,10 +149,10 @@
|
||||
width: auto;
|
||||
|
||||
input {
|
||||
@include typeahead-input();
|
||||
height: 34px;
|
||||
min-width: 370px;
|
||||
font-size: var(--mxs-size);
|
||||
@include typeahead-input();
|
||||
}
|
||||
|
||||
span {
|
||||
@@ -160,13 +160,13 @@
|
||||
}
|
||||
|
||||
.typeahead-dropdown {
|
||||
@include typeahead-dropdown();
|
||||
width: 100%;
|
||||
@include typeahead-dropdown();
|
||||
}
|
||||
|
||||
.typeahead-option {
|
||||
@include typeahead-option();
|
||||
font-size: var(--mxs-size);
|
||||
@include typeahead-option();
|
||||
}
|
||||
|
||||
.pointerevents {
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
useServiceProviderData,
|
||||
useApiData,
|
||||
getAppEnvSchema,
|
||||
getSPVoipCarriers,
|
||||
} from "src/api";
|
||||
import {
|
||||
ROUTE_INTERNAL_ACCOUNTS,
|
||||
@@ -588,6 +589,51 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
setFallbackSpeechRecognizerLabel(tmp);
|
||||
};
|
||||
|
||||
const fetchAppEnvJambonzResources = async (appEnv: AppEnv) => {
|
||||
if (appEnv) {
|
||||
const promises = Object.entries(appEnv).map(async ([key, value]) => {
|
||||
const { jambonzResource } = value;
|
||||
switch (jambonzResource) {
|
||||
case "carriers":
|
||||
const carriers = await getSPVoipCarriers(
|
||||
currentServiceProvider?.service_provider_sid || "",
|
||||
{
|
||||
page: 1,
|
||||
page_size: 10000,
|
||||
...(user?.account_sid && {
|
||||
account_sid: user.account_sid,
|
||||
}),
|
||||
},
|
||||
);
|
||||
if (carriers.json.total) {
|
||||
return {
|
||||
key,
|
||||
jambonzResourceOptions: carriers.json.data.map((carrier) => ({
|
||||
name: carrier.name,
|
||||
value: carrier.name,
|
||||
})),
|
||||
};
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return { key, jambonzResourceOptions: null };
|
||||
});
|
||||
|
||||
const results = await Promise.all(promises);
|
||||
|
||||
// Merge the results back into appEnv
|
||||
results.forEach(({ key, jambonzResourceOptions }) => {
|
||||
if (jambonzResourceOptions) {
|
||||
appEnv[key].jambonzResourceOptions = jambonzResourceOptions;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return appEnv;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (callWebhook && callWebhook.url) {
|
||||
// Clear any existing timeout to prevent multiple requests
|
||||
@@ -599,19 +645,26 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
appEnvTimeoutRef.current = setTimeout(() => {
|
||||
getAppEnvSchema(callWebhook.url)
|
||||
.then(({ json }) => {
|
||||
setAppEnv(json);
|
||||
const defaultEnvVars = Object.keys(json).reduce((acc, key) => {
|
||||
const value = json[key];
|
||||
if (value?.default) {
|
||||
return { ...acc, [key]: value.default };
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
// fetch app env jambonz_resource
|
||||
fetchAppEnvJambonzResources(json).then((updatedEnv) => {
|
||||
setAppEnv(updatedEnv);
|
||||
const defaultEnvVars = Object.keys(updatedEnv).reduce(
|
||||
(acc, key) => {
|
||||
const value = updatedEnv[key];
|
||||
if (value?.default) {
|
||||
return { ...acc, [key]: value.default };
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
setEnvVars((prev) => ({
|
||||
...defaultEnvVars,
|
||||
...(prev || {}),
|
||||
}));
|
||||
setEnvVars((prev) => ({
|
||||
...defaultEnvVars,
|
||||
...(prev || {}),
|
||||
}));
|
||||
});
|
||||
// Default value
|
||||
})
|
||||
.catch((error) => {
|
||||
setMessage(error.msg);
|
||||
@@ -873,9 +926,13 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
};
|
||||
|
||||
const isDropdown =
|
||||
webhook.webhookEnv![key].type === "string" &&
|
||||
(webhook.webhookEnv![key].enum?.length || 0) >
|
||||
0;
|
||||
(webhook.webhookEnv![key].type === "string" &&
|
||||
(webhook.webhookEnv![key].enum?.length ||
|
||||
0) > 0) ||
|
||||
hasLength(
|
||||
webhook.webhookEnv![key]
|
||||
.jambonzResourceOptions,
|
||||
);
|
||||
|
||||
const textAreaSpecificProps = {
|
||||
rows: 6,
|
||||
@@ -888,15 +945,19 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
|
||||
? ObscureInput
|
||||
: webhook.webhookEnv![key].uiHint || "input";
|
||||
if (isDropdown) {
|
||||
const options =
|
||||
webhook.webhookEnv![key]
|
||||
.jambonzResourceOptions ||
|
||||
webhook.webhookEnv![key].enum!.map(
|
||||
(option) => ({
|
||||
name: option,
|
||||
value: option,
|
||||
}),
|
||||
);
|
||||
return (
|
||||
<Selector
|
||||
{...commonProps}
|
||||
options={webhook.webhookEnv![
|
||||
key
|
||||
].enum!.map((option) => ({
|
||||
name: option,
|
||||
value: option,
|
||||
}))}
|
||||
options={options}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ import {
|
||||
VENDOR_VOXIST,
|
||||
VENDOR_RIMELABS,
|
||||
VENDOR_OPENAI,
|
||||
VENDOR_INWORLD,
|
||||
VENDOR_DEEPGRAM_FLUX,
|
||||
VENDOR_RESEMBLE,
|
||||
VENDOR_HOUNDIFY,
|
||||
} from "src/vendor";
|
||||
import {
|
||||
LabelOptions,
|
||||
@@ -139,7 +143,12 @@ export const SpeechProviderSelection = ({
|
||||
ttsEffectTimer.current = setTimeout(() => {
|
||||
configSynthesis();
|
||||
}, 200);
|
||||
}, [synthVendor, synthLabel, serviceProviderSid]);
|
||||
}, [
|
||||
synthVendor,
|
||||
synthLabel,
|
||||
serviceProviderSid,
|
||||
application_speech_synthesis_voice,
|
||||
]);
|
||||
|
||||
// Get Recognizer languages and voices
|
||||
useEffect(() => {
|
||||
@@ -246,6 +255,15 @@ export const SpeechProviderSelection = ({
|
||||
// Extract model
|
||||
if (json.models && json.models.length) {
|
||||
setSynthesisModelOptions(json.models);
|
||||
if (
|
||||
synthVendor === VENDOR_DEEPGRAM &&
|
||||
(!application_speech_synthesis_voice ||
|
||||
!json.models.some(
|
||||
(m) => m.value === application_speech_synthesis_voice,
|
||||
))
|
||||
) {
|
||||
setSynthVoice(json.models[0].value);
|
||||
}
|
||||
}
|
||||
|
||||
if (json.tts && json.tts.length) {
|
||||
@@ -298,6 +316,15 @@ export const SpeechProviderSelection = ({
|
||||
updateTtsVoice(newLang!.value, newLang!.voices[0].value);
|
||||
return;
|
||||
}
|
||||
if (synthVendor === VENDOR_INWORLD) {
|
||||
let newLang = json.tts.find((lang) => lang.value === "en");
|
||||
// If the new language doesn't map then default to the first one
|
||||
if (!newLang) {
|
||||
newLang = json.tts[0];
|
||||
}
|
||||
updateTtsVoice(newLang!.value, 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);
|
||||
@@ -337,7 +364,6 @@ export const SpeechProviderSelection = ({
|
||||
|
||||
const updateTtsVoice = (language: string, voice: string) => {
|
||||
if (shouldUpdateTtsVoice.current) {
|
||||
console.log("xhoaluu");
|
||||
setSynthLang(language);
|
||||
setSynthVoice(voice);
|
||||
shouldUpdateTtsVoice.current = false;
|
||||
@@ -345,6 +371,9 @@ export const SpeechProviderSelection = ({
|
||||
};
|
||||
|
||||
const configRecognizer = () => {
|
||||
if (recogVendor === VENDOR_DEEPGRAM_FLUX) {
|
||||
return;
|
||||
}
|
||||
getSpeechSupportedLanguagesAndVoices(
|
||||
serviceProviderSid,
|
||||
recogVendor,
|
||||
@@ -389,19 +418,6 @@ export const SpeechProviderSelection = ({
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
synthVendor === VENDOR_DEEPGRAM &&
|
||||
synthesisModelOptions.length > 0 &&
|
||||
!synthesisModelOptions.some(
|
||||
(m) => m.value === application_speech_synthesis_voice,
|
||||
)
|
||||
) {
|
||||
setSynthVoice(synthesisModelOptions[0].value);
|
||||
} else {
|
||||
setSynthVoice(application_speech_synthesis_voice || "");
|
||||
}
|
||||
}, [synthesisModelOptions, application_speech_synthesis_voice]);
|
||||
return (
|
||||
<>
|
||||
<fieldset>
|
||||
@@ -418,6 +434,8 @@ export const SpeechProviderSelection = ({
|
||||
vendor.value !== VENDOR_SPEECHMATICS &&
|
||||
vendor.value !== VENDOR_CUSTOM &&
|
||||
vendor.value !== VENDOR_OPENAI &&
|
||||
vendor.value !== VENDOR_DEEPGRAM_FLUX &&
|
||||
vendor.value !== VENDOR_HOUNDIFY &&
|
||||
vendor.value !== VENDOR_COBALT,
|
||||
)}
|
||||
onChange={(e) => {
|
||||
@@ -572,6 +590,7 @@ export const SpeechProviderSelection = ({
|
||||
vendor.value != VENDOR_WELLSAID &&
|
||||
vendor.value != VENDOR_ELEVENLABS &&
|
||||
vendor.value != VENDOR_WHISPER &&
|
||||
vendor.value !== VENDOR_RESEMBLE &&
|
||||
vendor.value !== VENDOR_CUSTOM,
|
||||
)}
|
||||
onChange={(e) => {
|
||||
@@ -599,6 +618,7 @@ export const SpeechProviderSelection = ({
|
||||
)}
|
||||
{recogVendor &&
|
||||
!recogVendor.toString().startsWith(VENDOR_CUSTOM) &&
|
||||
recogVendor !== VENDOR_DEEPGRAM_FLUX &&
|
||||
recogLang && (
|
||||
<>
|
||||
<label htmlFor="recognizer_lang">Language</label>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { P } from "@jambonz/ui-kit";
|
||||
import { Modal, ModalClose } from "src/components";
|
||||
import { getFetch, getLcrRoutes, getLcrs } from "src/api";
|
||||
import { API_PHONE_NUMBERS } from "src/api/constants";
|
||||
import { formatPhoneNumber, hasLength } from "src/utils";
|
||||
import { formatPhoneNumber, hasLength, hasValue } from "src/utils";
|
||||
|
||||
import type { Carrier, Lcr, PhoneNumber } from "src/api/types";
|
||||
|
||||
@@ -63,7 +63,8 @@ export const DeleteCarrier = ({
|
||||
),
|
||||
);
|
||||
|
||||
setLcrs(fetchedLcrs);
|
||||
// Only set LCRs if they are not empty
|
||||
setLcrs(fetchedLcrs.filter((p) => hasValue(p)));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@
|
||||
|
||||
.barGroup {
|
||||
border-radius: ui-vars.$px01;
|
||||
@include mixins.code();
|
||||
text-align: left;
|
||||
padding: ui-vars.$px03;
|
||||
color: ui-vars.$pink;
|
||||
@@ -13,6 +12,7 @@
|
||||
margin-top: ui-vars.$px02;
|
||||
overflow-x: auto;
|
||||
overflow-y: scroll;
|
||||
@include mixins.code();
|
||||
|
||||
@media (max-width: 600px) {
|
||||
padding: 15px;
|
||||
@@ -72,7 +72,6 @@
|
||||
|
||||
.spanDetailsWrapper {
|
||||
border-radius: ui-vars.$px01;
|
||||
@include mixins.code();
|
||||
text-align: left;
|
||||
padding: ui-vars.$px01;
|
||||
background-color: ui-vars.$white;
|
||||
@@ -82,6 +81,7 @@
|
||||
max-width: ui-vars.$width-tablet-2;
|
||||
max-height: 500px;
|
||||
overflow-y: scroll;
|
||||
@include mixins.code();
|
||||
|
||||
&__detailsWrapper {
|
||||
height: 100%;
|
||||
|
||||
@@ -161,6 +161,7 @@ export const Player = ({ call }: PlayerProps) => {
|
||||
|
||||
const drawSttRegionForSpan = (
|
||||
s: JaegerSpan,
|
||||
allSpans: JaegerSpan[],
|
||||
startPoint: JaegerSpan,
|
||||
channel = 0,
|
||||
) => {
|
||||
@@ -175,7 +176,36 @@ export const Player = ({ call }: PlayerProps) => {
|
||||
const end =
|
||||
(s.endTimeUnixNano - startPoint.startTimeUnixNano) / 1_000_000_000;
|
||||
|
||||
const endSpeechTime = getSilenceStartTime(start, end, channel);
|
||||
const verbHookSpans = getSpansByNameRegex(allSpans, /verb:hook/);
|
||||
const verbHookSpan = verbHookSpans.find(
|
||||
(v) => v.parentSpanId === s.spanId,
|
||||
);
|
||||
|
||||
let verbHookDurantion = 0;
|
||||
let latency = 0;
|
||||
if (verbHookSpan) {
|
||||
verbHookDurantion =
|
||||
(verbHookSpan.endTimeUnixNano - verbHookSpan.startTimeUnixNano) /
|
||||
1_000_000_000;
|
||||
}
|
||||
|
||||
const [sttLatencyMs] = getSpanAttributeByName(
|
||||
s.attributes,
|
||||
"stt.latency_ms",
|
||||
);
|
||||
let endSpeechTime = 0;
|
||||
if (!sttLatencyMs) {
|
||||
endSpeechTime = getSilenceStartTime(start, end, channel);
|
||||
latency = Number(
|
||||
(end - endSpeechTime - verbHookDurantion).toFixed(2),
|
||||
);
|
||||
} else {
|
||||
endSpeechTime =
|
||||
end -
|
||||
Number(sttLatencyMs.value.stringValue) / 1_000 -
|
||||
verbHookDurantion;
|
||||
latency = Number(sttLatencyMs.value.stringValue) / 1_000;
|
||||
}
|
||||
|
||||
const [sttResult] = getSpanAttributeByName(s.attributes, "stt.result");
|
||||
let att: WaveSurferSttResult;
|
||||
@@ -187,7 +217,7 @@ export const Player = ({ call }: PlayerProps) => {
|
||||
transcript: data.alternatives[0].transcript,
|
||||
confidence: data.alternatives[0].confidence,
|
||||
language_code: data.language_code,
|
||||
...(endSpeechTime > 0 && { latency: end - endSpeechTime }),
|
||||
latency,
|
||||
};
|
||||
|
||||
const [sttResolve] = getSpanAttributeByName(
|
||||
@@ -206,7 +236,7 @@ export const Player = ({ call }: PlayerProps) => {
|
||||
color: "rgba(255, 255, 0, 0.55)",
|
||||
drag: false,
|
||||
resize: false,
|
||||
content: `${(end - endSpeechTime).toFixed(2)}s`,
|
||||
content: `${latency}s`,
|
||||
});
|
||||
|
||||
changeRegionMouseStyle(latencyRegion, channel);
|
||||
@@ -353,7 +383,7 @@ export const Player = ({ call }: PlayerProps) => {
|
||||
if (startPoint) {
|
||||
const gatherSpans = getSpansByNameRegex(spans, /:gather{/);
|
||||
gatherSpans.forEach((s) => {
|
||||
drawSttRegionForSpan(s, startPoint);
|
||||
drawSttRegionForSpan(s, spans, startPoint);
|
||||
});
|
||||
|
||||
// Trasscription
|
||||
@@ -363,6 +393,7 @@ export const Player = ({ call }: PlayerProps) => {
|
||||
const channel = Number(cs.name.split(":")[1]);
|
||||
drawSttRegionForSpan(
|
||||
cs,
|
||||
spans,
|
||||
startPoint,
|
||||
channel > 0 ? channel - 1 : channel,
|
||||
);
|
||||
|
||||
@@ -52,6 +52,11 @@ import {
|
||||
VENDOR_CARTESIA,
|
||||
VENDOR_VOXIST,
|
||||
VENDOR_OPENAI,
|
||||
VENDOR_INWORLD,
|
||||
VENDOR_DEEPGRAM_FLUX,
|
||||
VENDOR_RESEMBLE,
|
||||
VENDOR_HOUNDIFY,
|
||||
VENDOR_GLADIA,
|
||||
} from "src/vendor";
|
||||
import { MSG_REQUIRED_FIELDS } from "src/constants";
|
||||
import {
|
||||
@@ -80,9 +85,13 @@ import type {
|
||||
import { setAccountFilter, setLocation } from "src/store/localStore";
|
||||
import {
|
||||
ADDITIONAL_SPEECH_VENDORS,
|
||||
ASSEMBLYAI_STT_VERSIONS,
|
||||
DEEPGRAM_STT_ENPOINT,
|
||||
DEFAULT_ASSEMBLYAI_STT_VERSION,
|
||||
DEFAULT_CARTESIA_OPTIONS,
|
||||
DEFAULT_ELEVENLABS_OPTIONS,
|
||||
DEFAULT_GOOGLE_CUSTOM_VOICE,
|
||||
DEFAULT_INWORLD_OPTIONS,
|
||||
DEFAULT_PLAYHT_OPTIONS,
|
||||
DEFAULT_RIMELABS_OPTIONS,
|
||||
DEFAULT_VERBIO_MODEL,
|
||||
@@ -101,6 +110,13 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
const { toastError, toastSuccess } = useToast();
|
||||
const navigate = useNavigate();
|
||||
const user = useSelectState("user");
|
||||
|
||||
// ElevenLabs API URI options
|
||||
const ELEVENLABS_API_URI_OPTIONS = [
|
||||
{ name: "US", value: "api.elevenlabs.io" },
|
||||
{ name: "EU", value: "api.eu.residency.elevenlabs.io" },
|
||||
{ name: "IN", value: "api.in.residency.elevenlabs.io" },
|
||||
];
|
||||
const currentServiceProvider = useSelectState("currentServiceProvider");
|
||||
const regions = useRegionVendors();
|
||||
const [accounts] = useServiceProviderData<Account[]>("Accounts");
|
||||
@@ -114,11 +130,13 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
);
|
||||
const [region, setRegion] = useState("");
|
||||
const [apiKey, setApiKey] = useState("");
|
||||
const [apiUri, setApiUri] = useState("api.elevenlabs.io");
|
||||
const [userId, setUserId] = useState("");
|
||||
const [accessKeyId, setAccessKeyId] = useState("");
|
||||
const [secretAccessKey, setSecretAccessKey] = useState("");
|
||||
const [clientId, setClientId] = useState("");
|
||||
const [secretKey, setSecretKey] = useState("");
|
||||
const [clientKey, setClientKey] = useState("");
|
||||
const [clientSecret, setClientSecret] = useState("");
|
||||
const [googleServiceKey, setGoogleServiceKey] =
|
||||
useState<GoogleServiceKey | null>(null);
|
||||
@@ -129,6 +147,9 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
const [ttsModelId, setTtsModelId] = useState("");
|
||||
const [sttModelId, setSttModelId] = useState("");
|
||||
const [engineVersion, setEngineVersion] = useState(DEFAULT_VERBIO_MODEL);
|
||||
const [serviceVersion, setServiceVersion] = useState(
|
||||
DEFAULT_ASSEMBLYAI_STT_VERSION,
|
||||
);
|
||||
const [instanceId, setInstanceId] = useState("");
|
||||
const [initialCheckCustomTts, setInitialCheckCustomTts] = useState(false);
|
||||
const [initialCheckCustomStt, setInitialCheckCustomStt] = useState(false);
|
||||
@@ -198,6 +219,12 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
const [tmpPlayhtTtsUri, setTmpPlayhtTtsUri] = useState("");
|
||||
const [initialPlayhtOnpremCheck, setInitialPlayhtOnpremCheck] =
|
||||
useState(false);
|
||||
const [resembleTtsUri, setResembleTtsUri] = useState("");
|
||||
const [tmpResembleTtsUri, setTmpResembleTtsUri] = useState("");
|
||||
const [initialResembleOnpremCheck, setInitialResembleOnpremCheck] =
|
||||
useState(false);
|
||||
const [resembleTtsUseTls, setResembleTtsUseTls] = useState(false);
|
||||
const [tmpResembleTtsUseTls, setTmpResembleTtsUseTls] = useState(false);
|
||||
const handleFile = (file: File) => {
|
||||
const handleError = () => {
|
||||
setGoogleServiceKey(null);
|
||||
@@ -233,6 +260,8 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
return DEFAULT_PLAYHT_OPTIONS;
|
||||
case VENDOR_RIMELABS:
|
||||
return DEFAULT_RIMELABS_OPTIONS;
|
||||
case VENDOR_INWORLD:
|
||||
return DEFAULT_INWORLD_OPTIONS;
|
||||
case VENDOR_CARTESIA:
|
||||
return DEFAULT_CARTESIA_OPTIONS;
|
||||
}
|
||||
@@ -249,6 +278,8 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
return "https://docs.play.ht/reference/api-generate-tts-audio-stream";
|
||||
case VENDOR_RIMELABS:
|
||||
return "https://rimelabs.mintlify.app/api-reference/endpoint/streaming-mp3#variable-parameters";
|
||||
case VENDOR_INWORLD:
|
||||
return "https://docs.inworld.ai/api-reference/ttsAPI/texttospeech/synthesize-speech-stream";
|
||||
case VENDOR_CARTESIA:
|
||||
return "https://docs.cartesia.ai/api-reference/tts/bytes";
|
||||
}
|
||||
@@ -260,7 +291,19 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
switch (vendor) {
|
||||
case VENDOR_PLAYHT:
|
||||
return "Voice Engine";
|
||||
case VENDOR_DEEPGRAM:
|
||||
return "Model ID";
|
||||
case VENDOR_CARTESIA:
|
||||
return "TTS Model ID";
|
||||
default:
|
||||
return "Model";
|
||||
}
|
||||
};
|
||||
|
||||
const getSTTModelLabelByVendor = (vendor: Lowercase<Vendor>) => {
|
||||
switch (vendor) {
|
||||
case VENDOR_CARTESIA:
|
||||
return " STT Model ID";
|
||||
case VENDOR_DEEPGRAM:
|
||||
return "Model ID";
|
||||
default:
|
||||
@@ -397,6 +440,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
}),
|
||||
...(vendor === VENDOR_CARTESIA && {
|
||||
model_id: ttsModelId || null,
|
||||
stt_model_id: sttModelId || null,
|
||||
options: options || null,
|
||||
}),
|
||||
...(vendor === VENDOR_CUSTOM && {
|
||||
@@ -414,16 +458,26 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
nuance_tts_uri: onPremNuanceTtsUrl || null,
|
||||
nuance_stt_uri: onPremNuanceSttUrl || null,
|
||||
}),
|
||||
...(vendor === VENDOR_HOUNDIFY && {
|
||||
client_id: clientId || null,
|
||||
client_key: clientKey || null,
|
||||
user_id: userId || null,
|
||||
}),
|
||||
...(vendor === VENDOR_COBALT && {
|
||||
cobalt_server_uri: cobaltServerUri || null,
|
||||
}),
|
||||
...((vendor === VENDOR_ELEVENLABS ||
|
||||
vendor === VENDOR_WHISPER ||
|
||||
vendor === VENDOR_INWORLD ||
|
||||
vendor === VENDOR_RIMELABS) && {
|
||||
model_id: ttsModelId || null,
|
||||
}),
|
||||
...(vendor === VENDOR_ELEVENLABS && {
|
||||
api_uri: apiUri || null,
|
||||
}),
|
||||
...((vendor === VENDOR_ELEVENLABS ||
|
||||
vendor === VENDOR_PLAYHT ||
|
||||
vendor === VENDOR_INWORLD ||
|
||||
vendor === VENDOR_RIMELABS) && {
|
||||
options: options || null,
|
||||
}),
|
||||
@@ -447,9 +501,20 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
...(vendor === VENDOR_VERBIO && {
|
||||
engine_version: engineVersion,
|
||||
}),
|
||||
...(vendor === VENDOR_ASSEMBLYAI && {
|
||||
service_version: serviceVersion || null,
|
||||
}),
|
||||
...(vendor === VENDOR_PLAYHT && {
|
||||
playht_tts_uri: playhtTtsUri || null,
|
||||
}),
|
||||
...(vendor === VENDOR_RESEMBLE && {
|
||||
resemble_tts_uri: resembleTtsUri || null,
|
||||
resemble_tts_use_tls: resembleTtsUseTls ? 1 : 0,
|
||||
}),
|
||||
...(vendor === VENDOR_GLADIA && {
|
||||
api_key: apiKey || null,
|
||||
region: region || null,
|
||||
}),
|
||||
};
|
||||
|
||||
if (credential && credential.data) {
|
||||
@@ -496,9 +561,13 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
vendor === VENDOR_ELEVENLABS ||
|
||||
vendor === VENDOR_PLAYHT ||
|
||||
vendor === VENDOR_RIMELABS ||
|
||||
vendor === VENDOR_INWORLD ||
|
||||
vendor === VENDOR_WHISPER ||
|
||||
vendor === VENDOR_CARTESIA ||
|
||||
vendor === VENDOR_OPENAI
|
||||
vendor === VENDOR_OPENAI ||
|
||||
vendor === VENDOR_RESEMBLE ||
|
||||
vendor === VENDOR_DEEPGRAM_FLUX ||
|
||||
vendor === VENDOR_GLADIA
|
||||
? apiKey
|
||||
: null,
|
||||
}),
|
||||
@@ -565,6 +634,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
vendor === VENDOR_WHISPER ||
|
||||
vendor === VENDOR_PLAYHT ||
|
||||
vendor === VENDOR_RIMELABS ||
|
||||
vendor === VENDOR_INWORLD ||
|
||||
vendor === VENDOR_CARTESIA ||
|
||||
vendor === VENDOR_OPENAI ||
|
||||
vendor === VENDOR_DEEPGRAM
|
||||
@@ -651,6 +721,10 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
setApiKey(credential.data.api_key);
|
||||
}
|
||||
|
||||
if (credential.data.api_uri) {
|
||||
setApiUri(credential.data.api_uri);
|
||||
}
|
||||
|
||||
if (credential.data.region) {
|
||||
setRegion(credential.data.region);
|
||||
}
|
||||
@@ -662,6 +736,9 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
if (credential.data.client_id) {
|
||||
setClientId(credential.data.client_id);
|
||||
}
|
||||
if (credential.data.client_key) {
|
||||
setClientKey(credential.data.client_key);
|
||||
}
|
||||
|
||||
if (credential.data.secret) {
|
||||
setSecretKey(credential.data.secret);
|
||||
@@ -758,10 +835,15 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
(vendor === VENDOR_OPENAI || vendor === VENDOR_DEEPGRAM)
|
||||
) {
|
||||
setSttModelId(credential.data.model_id);
|
||||
} else if (credential.data.stt_model_id) {
|
||||
setSttModelId(credential.data.stt_model_id);
|
||||
}
|
||||
if (credential?.data?.playht_tts_uri) {
|
||||
setPlayhtTtsUri(credential.data.playht_tts_uri);
|
||||
}
|
||||
if (credential?.data?.resemble_tts_uri) {
|
||||
setResembleTtsUri(credential.data.resemble_tts_uri);
|
||||
}
|
||||
}
|
||||
if (credential?.data?.options) {
|
||||
setOptions(credential.data.options);
|
||||
@@ -776,9 +858,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
setUseCustomVoicesCheck(json.length > 0);
|
||||
});
|
||||
}
|
||||
if (credential?.data?.deepgram_stt_uri) {
|
||||
setDeepgramSttUri(credential.data.deepgram_stt_uri);
|
||||
}
|
||||
setDeepgramSttUri(credential?.data?.deepgram_stt_uri || "");
|
||||
if (credential?.data?.deepgram_tts_uri) {
|
||||
setDeepgramTtsUri(credential.data.deepgram_tts_uri);
|
||||
}
|
||||
@@ -787,7 +867,12 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
credential?.data?.deepgram_stt_use_tls > 0 ? true : false,
|
||||
);
|
||||
}
|
||||
setInitialDeepgramOnpremCheck(hasValue(credential?.data?.deepgram_stt_uri));
|
||||
setInitialDeepgramOnpremCheck(
|
||||
hasValue(credential?.data?.deepgram_stt_uri) &&
|
||||
!DEEPGRAM_STT_ENPOINT.map((e) => e.value).includes(
|
||||
credential?.data?.deepgram_stt_uri,
|
||||
),
|
||||
);
|
||||
|
||||
if (credential?.data?.user_id) {
|
||||
setUserId(credential.data.user_id);
|
||||
@@ -817,6 +902,9 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
if (credential?.data?.engine_version) {
|
||||
setEngineVersion(credential.data.engine_version);
|
||||
}
|
||||
if (credential?.data?.service_version) {
|
||||
setServiceVersion(credential.data.service_version);
|
||||
}
|
||||
|
||||
if (credential?.data?.speechmatics_stt_uri) {
|
||||
setInitialSpeechMaticsOnpremCheck(
|
||||
@@ -825,6 +913,15 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
setSpeechmaticsEndpoint(credential.data.speechmatics_stt_uri);
|
||||
}
|
||||
setInitialPlayhtOnpremCheck(hasValue(credential?.data?.playht_tts_uri));
|
||||
setInitialResembleOnpremCheck(hasValue(credential?.data?.resemble_tts_uri));
|
||||
if (credential?.data?.resemble_tts_use_tls) {
|
||||
setResembleTtsUseTls(
|
||||
credential?.data?.resemble_tts_use_tls > 0 ? true : false,
|
||||
);
|
||||
setTmpResembleTtsUseTls(
|
||||
credential?.data?.resemble_tts_use_tls > 0 ? true : false,
|
||||
);
|
||||
}
|
||||
}, [credential]);
|
||||
|
||||
const updateCustomVoices = (
|
||||
@@ -888,6 +985,9 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
setVendor(e.target.value as Lowercase<Vendor>);
|
||||
setRegion("");
|
||||
setApiKey("");
|
||||
setApiUri(
|
||||
e.target.value === VENDOR_ELEVENLABS ? "api.elevenlabs.io" : "",
|
||||
);
|
||||
setGoogleServiceKey(null);
|
||||
}}
|
||||
disabled={credential ? true : false}
|
||||
@@ -943,7 +1043,10 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
vendor !== VENDOR_COBALT &&
|
||||
vendor !== VENDOR_SONIOX &&
|
||||
vendor !== VENDOR_SPEECHMATICS &&
|
||||
vendor !== VENDOR_DEEPGRAM_FLUX &&
|
||||
vendor !== VENDOR_HOUNDIFY &&
|
||||
vendor !== VENDOR_OPENAI &&
|
||||
vendor !== VENDOR_GLADIA &&
|
||||
vendor != VENDOR_CUSTOM && (
|
||||
<label htmlFor="use_for_tts" className="chk">
|
||||
<input
|
||||
@@ -961,7 +1064,8 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
vendor !== VENDOR_WHISPER &&
|
||||
vendor !== VENDOR_PLAYHT &&
|
||||
vendor !== VENDOR_RIMELABS &&
|
||||
vendor !== VENDOR_CARTESIA &&
|
||||
vendor !== VENDOR_INWORLD &&
|
||||
vendor !== VENDOR_RESEMBLE &&
|
||||
vendor !== VENDOR_ELEVENLABS && (
|
||||
<label htmlFor="use_for_stt" className="chk">
|
||||
<input
|
||||
@@ -1341,6 +1445,47 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{vendor === VENDOR_HOUNDIFY && (
|
||||
<fieldset>
|
||||
<label htmlFor="houndify_client_id">
|
||||
Client ID
|
||||
{!onPremNuanceSttCheck && !onPremNuanceTtsCheck && <span>*</span>}
|
||||
</label>
|
||||
<input
|
||||
id="houndify_client_id"
|
||||
required={!onPremNuanceSttCheck && !onPremNuanceTtsCheck}
|
||||
type="text"
|
||||
name="houndify_client_id"
|
||||
placeholder="Client ID"
|
||||
value={clientId}
|
||||
onChange={(e) => setClientId(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
<label htmlFor="houndify_secret">
|
||||
Client Key
|
||||
{!onPremNuanceSttCheck && !onPremNuanceTtsCheck && <span>*</span>}
|
||||
</label>
|
||||
<Passwd
|
||||
id="houndify_secret"
|
||||
required={!onPremNuanceSttCheck && !onPremNuanceTtsCheck}
|
||||
name="houndify_secret"
|
||||
placeholder="Client Key"
|
||||
value={clientKey ? getObscuredSecret(clientKey) : clientKey}
|
||||
onChange={(e) => setClientKey(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
<label htmlFor="houndify_user_id">User ID</label>
|
||||
<input
|
||||
id="houndify_user_id"
|
||||
type="text"
|
||||
name="houndify_user_id"
|
||||
placeholder="User ID"
|
||||
value={userId}
|
||||
onChange={(e) => setUserId(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
</fieldset>
|
||||
)}
|
||||
{vendor === VENDOR_NUANCE && (
|
||||
<>
|
||||
<fieldset>
|
||||
@@ -1497,6 +1642,22 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
</fieldset>
|
||||
</>
|
||||
)}
|
||||
{vendor === VENDOR_ASSEMBLYAI && (
|
||||
<fieldset>
|
||||
<label htmlFor={`${vendor}_tts_model_id`}>
|
||||
Service version<span>*</span>
|
||||
</label>
|
||||
<Selector
|
||||
id={"assemblyai_service_version"}
|
||||
name={"assemblyai_service_version"}
|
||||
value={serviceVersion}
|
||||
options={ASSEMBLYAI_STT_VERSIONS}
|
||||
onChange={(e) => {
|
||||
setServiceVersion(e.target.value);
|
||||
}}
|
||||
/>
|
||||
</fieldset>
|
||||
)}
|
||||
{vendor === VENDOR_AWS && (
|
||||
<fieldset>
|
||||
<label htmlFor="vendor">
|
||||
@@ -1685,16 +1846,98 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
</fieldset>
|
||||
)}
|
||||
|
||||
{vendor === VENDOR_RESEMBLE && (
|
||||
<fieldset>
|
||||
<Checkzone
|
||||
disabled={hasValue(credential)}
|
||||
hidden
|
||||
name="use_on-prem_resemble_container"
|
||||
label="Use on-prem Resemble container"
|
||||
initialCheck={initialResembleOnpremCheck}
|
||||
handleChecked={(e) => {
|
||||
setInitialResembleOnpremCheck(e.target.checked);
|
||||
if (e.target.checked) {
|
||||
if (tmpResembleTtsUri) {
|
||||
setResembleTtsUri(tmpResembleTtsUri);
|
||||
}
|
||||
if (tmpResembleTtsUseTls) {
|
||||
setResembleTtsUseTls(tmpResembleTtsUseTls);
|
||||
}
|
||||
} else {
|
||||
setTmpResembleTtsUri(resembleTtsUri);
|
||||
setResembleTtsUri("");
|
||||
setTmpResembleTtsUseTls(resembleTtsUseTls);
|
||||
setResembleTtsUseTls(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<label htmlFor="resemble_uri_for_tts">
|
||||
TTS Container URI<span>*</span>
|
||||
</label>
|
||||
<input
|
||||
id="resemble_uri_for_tts"
|
||||
required
|
||||
type="text"
|
||||
name="resemble_uri_for_tts"
|
||||
placeholder=""
|
||||
value={resembleTtsUri}
|
||||
onChange={(e) => setResembleTtsUri(e.target.value)}
|
||||
/>
|
||||
<label htmlFor="resemble_stt_use_tls" className="chk">
|
||||
<input
|
||||
id="resemble_stt_use_tls"
|
||||
name="resemble_stt_use_tls"
|
||||
type="checkbox"
|
||||
onChange={(e) => setResembleTtsUseTls(e.target.checked)}
|
||||
defaultChecked={resembleTtsUseTls}
|
||||
/>
|
||||
<div>Use TLS</div>
|
||||
</label>
|
||||
</Checkzone>
|
||||
</fieldset>
|
||||
)}
|
||||
|
||||
{vendor === VENDOR_ELEVENLABS && (
|
||||
<fieldset>
|
||||
<label htmlFor="elevenlabs_api_uri">
|
||||
Data residency<span>*</span>
|
||||
</label>
|
||||
<Selector
|
||||
id="elevenlabs_api_uri"
|
||||
name="elevenlabs_api_uri"
|
||||
value={apiUri}
|
||||
options={ELEVENLABS_API_URI_OPTIONS}
|
||||
onChange={(e) => setApiUri(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<label htmlFor={`${vendor}_apikey`}>
|
||||
API key<span>*</span>
|
||||
</label>
|
||||
<Passwd
|
||||
id={`${vendor}_apikey`}
|
||||
required
|
||||
name={`${vendor}_apikey`}
|
||||
placeholder="API key"
|
||||
value={apiKey ? getObscuredSecret(apiKey) : apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
</fieldset>
|
||||
)}
|
||||
|
||||
{(vendor === VENDOR_WELLSAID ||
|
||||
vendor === VENDOR_ASSEMBLYAI ||
|
||||
vendor === VENDOR_VOXIST ||
|
||||
vendor == VENDOR_ELEVENLABS ||
|
||||
vendor === VENDOR_WHISPER ||
|
||||
vendor === VENDOR_RIMELABS ||
|
||||
vendor === VENDOR_INWORLD ||
|
||||
vendor === VENDOR_SONIOX ||
|
||||
vendor === VENDOR_CARTESIA ||
|
||||
vendor === VENDOR_OPENAI ||
|
||||
vendor === VENDOR_SPEECHMATICS) && (
|
||||
vendor === VENDOR_DEEPGRAM_FLUX ||
|
||||
vendor === VENDOR_RESEMBLE ||
|
||||
vendor === VENDOR_SPEECHMATICS ||
|
||||
vendor === VENDOR_GLADIA) && (
|
||||
<fieldset>
|
||||
<label htmlFor={`${vendor}_apikey`}>
|
||||
API key<span>*</span>
|
||||
@@ -1710,11 +1953,12 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
/>
|
||||
</fieldset>
|
||||
)}
|
||||
{(vendor == VENDOR_ELEVENLABS ||
|
||||
vendor == VENDOR_WHISPER ||
|
||||
vendor === VENDOR_CARTESIA ||
|
||||
{(vendor === VENDOR_ELEVENLABS ||
|
||||
vendor === VENDOR_WHISPER ||
|
||||
vendor === VENDOR_PLAYHT ||
|
||||
vendor == VENDOR_RIMELABS) &&
|
||||
vendor === VENDOR_RIMELABS ||
|
||||
vendor === VENDOR_INWORLD ||
|
||||
(ttsCheck && vendor === VENDOR_CARTESIA)) &&
|
||||
ttsModels.length > 0 && (
|
||||
<fieldset>
|
||||
<label htmlFor={`${vendor}_tts_model_id`}>
|
||||
@@ -1731,11 +1975,13 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
/>
|
||||
</fieldset>
|
||||
)}
|
||||
{(vendor == VENDOR_OPENAI || vendor === VENDOR_DEEPGRAM) &&
|
||||
{(vendor == VENDOR_OPENAI ||
|
||||
vendor === VENDOR_DEEPGRAM ||
|
||||
(sttCheck && vendor === VENDOR_CARTESIA)) &&
|
||||
sttModels.length > 0 && (
|
||||
<fieldset>
|
||||
<label htmlFor={`${vendor}_stt_model_id`}>
|
||||
{getModelLabelByVendor(vendor)}
|
||||
{getSTTModelLabelByVendor(vendor)}
|
||||
</label>
|
||||
<Selector
|
||||
id={"stt_model_id"}
|
||||
@@ -1751,7 +1997,8 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
{(vendor === VENDOR_ELEVENLABS ||
|
||||
vendor === VENDOR_PLAYHT ||
|
||||
vendor === VENDOR_CARTESIA ||
|
||||
vendor === VENDOR_RIMELABS) && (
|
||||
vendor === VENDOR_RIMELABS ||
|
||||
vendor === VENDOR_INWORLD) && (
|
||||
<fieldset>
|
||||
<Checkzone
|
||||
hidden
|
||||
@@ -1972,6 +2219,19 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
disabled={credential ? true : false}
|
||||
/>
|
||||
<label htmlFor={`${vendor}_deepgram_stt_enpoint`}>
|
||||
Deepgram STT Endpoint<span>*</span>
|
||||
</label>
|
||||
<Selector
|
||||
id={"deepgram_stt_enpoint"}
|
||||
name={"deepgram_stt_enpoint"}
|
||||
value={deepgramSttUri}
|
||||
options={DEEPGRAM_STT_ENPOINT}
|
||||
onChange={(e) => {
|
||||
setDeepgramSttUri(e.target.value);
|
||||
setDeepgramSttUseTls(hasValue(e.target.value));
|
||||
}}
|
||||
/>
|
||||
</Checkzone>
|
||||
<Checkzone
|
||||
disabled={hasValue(credential)}
|
||||
|
||||
@@ -7,12 +7,12 @@ input[type="text"],
|
||||
input[type="email"],
|
||||
input[type="number"],
|
||||
input[type="password"] {
|
||||
@include ui-mixins.m();
|
||||
padding: ui-vars.$px01 ui-vars.$px02;
|
||||
border-radius: ui-vars.$px01;
|
||||
border: 2px solid ui-vars.$grey;
|
||||
background-color: ui-vars.$white;
|
||||
color: inherit;
|
||||
@include ui-mixins.m();
|
||||
|
||||
&:focus {
|
||||
border-color: ui-vars.$dark;
|
||||
@@ -110,11 +110,11 @@ fieldset {
|
||||
}
|
||||
|
||||
label {
|
||||
@include ui-mixins.m();
|
||||
@include ui-mixins.font-medium();
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
@include ui-mixins.font-medium();
|
||||
@include ui-mixins.m();
|
||||
|
||||
span {
|
||||
color: ui-vars.$jambonz;
|
||||
@@ -218,7 +218,8 @@ fieldset {
|
||||
}
|
||||
}
|
||||
|
||||
.gateway {
|
||||
.gateway,
|
||||
.gateway-inbound {
|
||||
padding: ui-vars.$px02;
|
||||
border-radius: ui-vars.$px01;
|
||||
border: 2px solid ui-vars.$grey;
|
||||
@@ -284,6 +285,18 @@ fieldset {
|
||||
}
|
||||
}
|
||||
|
||||
.gateway-inbound {
|
||||
> div {
|
||||
&:nth-child(1) {
|
||||
grid-template-columns: [col] calc(70% - #{ui-vars.$px02 * 2}) [col] 30%;
|
||||
|
||||
@include mixins.small() {
|
||||
grid-template-columns: [col] 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lcr {
|
||||
@extend .gateway;
|
||||
|
||||
|
||||
@@ -21,10 +21,10 @@
|
||||
}
|
||||
|
||||
&__row {
|
||||
@include ui-mixins.m();
|
||||
display: grid;
|
||||
padding: ui-vars.$px03;
|
||||
align-items: center;
|
||||
@include ui-mixins.m();
|
||||
|
||||
@include mixins.small() {
|
||||
padding: ui-vars.$px02;
|
||||
|
||||
@@ -30,11 +30,11 @@
|
||||
}
|
||||
|
||||
&__title {
|
||||
@include ui-mixins.p();
|
||||
display: flex;
|
||||
align-items: center;
|
||||
grid-gap: ui-vars.$px02;
|
||||
color: ui-vars.$jambonz;
|
||||
@include ui-mixins.p();
|
||||
|
||||
+ .item__meta {
|
||||
@include mixins.small() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
@use "sass:color";
|
||||
@use "./forms";
|
||||
// @use "./cards";
|
||||
@use "./lists";
|
||||
@@ -68,7 +69,7 @@ details {
|
||||
&.ok {
|
||||
color: ui-vars.$teal;
|
||||
border: 2px solid ui-vars.$teal;
|
||||
background-color: mix(ui-vars.$white, ui-vars.$teal, 95%);
|
||||
background-color: color.mix(ui-vars.$white, ui-vars.$teal, 95%);
|
||||
}
|
||||
|
||||
&.not-tested {
|
||||
@@ -77,8 +78,8 @@ details {
|
||||
}
|
||||
|
||||
summary {
|
||||
@include ui-mixins.m();
|
||||
cursor: pointer;
|
||||
@include ui-mixins.m();
|
||||
|
||||
+ * {
|
||||
margin-top: ui-vars.$px02;
|
||||
@@ -160,7 +161,6 @@ details {
|
||||
|
||||
/** Used for recent-calls */
|
||||
.pre-grid {
|
||||
@include mixins.code();
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-row-gap: ui-vars.$px01;
|
||||
@@ -171,6 +171,7 @@ details {
|
||||
background-color: ui-vars.$dark;
|
||||
border-radius: ui-vars.$px01;
|
||||
margin-top: ui-vars.$px02;
|
||||
@include mixins.code();
|
||||
}
|
||||
|
||||
.pre-grid-white {
|
||||
|
||||
28
src/vendor/index.tsx
vendored
28
src/vendor/index.tsx
vendored
@@ -12,6 +12,7 @@ export const VENDOR_MICROSOFT = "microsoft";
|
||||
export const VENDOR_WELLSAID = "wellsaid";
|
||||
export const VENDOR_NUANCE = "nuance";
|
||||
export const VENDOR_DEEPGRAM = "deepgram";
|
||||
export const VENDOR_DEEPGRAM_FLUX = "deepgramflux";
|
||||
export const VENDOR_IBM = "ibm";
|
||||
export const VENDOR_NVIDIA = "nvidia";
|
||||
export const VENDOR_SONIOX = "soniox";
|
||||
@@ -24,9 +25,13 @@ export const VENDOR_VOXIST = "voxist";
|
||||
export const VENDOR_WHISPER = "whisper";
|
||||
export const VENDOR_PLAYHT = "playht";
|
||||
export const VENDOR_RIMELABS = "rimelabs";
|
||||
export const VENDOR_INWORLD = "inworld";
|
||||
export const VENDOR_VERBIO = "verbio";
|
||||
export const VENDOR_CARTESIA = "cartesia";
|
||||
export const VENDOR_OPENAI = "openai";
|
||||
export const VENDOR_RESEMBLE = "resemble";
|
||||
export const VENDOR_HOUNDIFY = "houndify";
|
||||
export const VENDOR_GLADIA = "gladia";
|
||||
|
||||
export const vendors: VendorOptions[] = [
|
||||
{
|
||||
@@ -41,6 +46,10 @@ export const vendors: VendorOptions[] = [
|
||||
name: "Deepgram",
|
||||
value: VENDOR_DEEPGRAM,
|
||||
},
|
||||
{
|
||||
name: "Deepgram Flux",
|
||||
value: VENDOR_DEEPGRAM_FLUX,
|
||||
},
|
||||
{
|
||||
name: "IBM",
|
||||
value: VENDOR_IBM,
|
||||
@@ -101,6 +110,10 @@ export const vendors: VendorOptions[] = [
|
||||
name: "RimeLabs",
|
||||
value: VENDOR_RIMELABS,
|
||||
},
|
||||
{
|
||||
name: "Inworld",
|
||||
value: VENDOR_INWORLD,
|
||||
},
|
||||
{
|
||||
name: "Verbio",
|
||||
value: VENDOR_VERBIO,
|
||||
@@ -113,6 +126,18 @@ export const vendors: VendorOptions[] = [
|
||||
name: "OpenAI",
|
||||
value: VENDOR_OPENAI,
|
||||
},
|
||||
{
|
||||
name: "Resemble",
|
||||
value: VENDOR_RESEMBLE,
|
||||
},
|
||||
{
|
||||
name: "SoundHound",
|
||||
value: VENDOR_HOUNDIFY,
|
||||
},
|
||||
{
|
||||
name: "Gladia",
|
||||
value: VENDOR_GLADIA,
|
||||
},
|
||||
].sort((a, b) => a.name.localeCompare(b.name)) as VendorOptions[];
|
||||
|
||||
export const AWS_CREDENTIAL_ACCESS_KEY = "access_key";
|
||||
@@ -145,12 +170,14 @@ export const useRegionVendors = () => {
|
||||
import("./regions/ms-azure-regions"),
|
||||
import("./regions/ibm-regions"),
|
||||
import("./regions/speechmatics-regions"),
|
||||
import("./regions/gladia-regions"),
|
||||
]).then(
|
||||
([
|
||||
{ default: awsRegions },
|
||||
{ default: msRegions },
|
||||
{ default: ibmRegions },
|
||||
{ default: speechmaticsRegions },
|
||||
{ default: gladiaRegions },
|
||||
]) => {
|
||||
if (!ignore) {
|
||||
setRegions({
|
||||
@@ -158,6 +185,7 @@ export const useRegionVendors = () => {
|
||||
microsoft: msRegions,
|
||||
ibm: ibmRegions,
|
||||
speechmatics: speechmaticsRegions,
|
||||
gladia: gladiaRegions,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
14
src/vendor/regions/gladia-regions.ts
vendored
Normal file
14
src/vendor/regions/gladia-regions.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import type { Region } from "../types";
|
||||
|
||||
export const regions: Region[] = [
|
||||
{
|
||||
name: "US West",
|
||||
value: "us-west",
|
||||
},
|
||||
{
|
||||
name: "EU West",
|
||||
value: "eu-west",
|
||||
},
|
||||
];
|
||||
|
||||
export default regions;
|
||||
15
src/vendor/types.ts
vendored
15
src/vendor/types.ts
vendored
@@ -5,6 +5,7 @@ export type Vendor =
|
||||
| "WellSaid"
|
||||
| "Nuance"
|
||||
| "Deepgram"
|
||||
| "DeepgramFlux"
|
||||
| "IBM"
|
||||
| "Nvidia"
|
||||
| "Soniox"
|
||||
@@ -17,9 +18,13 @@ export type Vendor =
|
||||
| "whisper"
|
||||
| "playht"
|
||||
| "rimelabs"
|
||||
| "inworld"
|
||||
| "verbio"
|
||||
| "openai"
|
||||
| "Cartesia";
|
||||
| "Cartesia"
|
||||
| "Resemble"
|
||||
| "Houndify"
|
||||
| "gladia";
|
||||
|
||||
export interface VendorOptions {
|
||||
name: Vendor;
|
||||
@@ -31,6 +36,11 @@ export interface LabelOptions {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface JambonzResourceOptions {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface Region {
|
||||
name: string;
|
||||
value: string;
|
||||
@@ -76,6 +86,7 @@ export interface RegionVendors {
|
||||
microsoft: Region[];
|
||||
ibm: Region[];
|
||||
speechmatics: Region[];
|
||||
gladia: Region[];
|
||||
}
|
||||
|
||||
export interface TtsModels {
|
||||
@@ -96,6 +107,7 @@ export interface RecognizerVendors {
|
||||
speechmatics: Language[];
|
||||
cobalt: Language[];
|
||||
assemblyai: Language[];
|
||||
deepgramflux: Language[];
|
||||
}
|
||||
|
||||
export interface SynthesisVendors {
|
||||
@@ -112,6 +124,7 @@ export interface SynthesisVendors {
|
||||
playht: VoiceLanguage[];
|
||||
cartesia: VoiceLanguage[];
|
||||
rimelabs: VoiceLanguage[];
|
||||
inworld: VoiceLanguage[];
|
||||
}
|
||||
|
||||
export interface MSRawSpeech {
|
||||
|
||||
@@ -15,6 +15,15 @@ export default defineConfig(() => {
|
||||
src: path.resolve(__dirname, "src"),
|
||||
},
|
||||
},
|
||||
|
||||
// Configure Sass to use the modern API
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
api: "modern-compiler",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return config;
|
||||
|
||||
Reference in New Issue
Block a user