feat support multiple speech credential with different labels but same vendor (#305)

* feat support multiple speech credential with different labels but same vendor

* fix

* fix review comment

* fix review comment

* fix label tooltip

* fixed
This commit is contained in:
Hoan Luu Huu
2023-08-15 20:00:00 +07:00
committed by GitHub
parent 27f02c2bb3
commit 843d1eda1e
7 changed files with 133 additions and 6 deletions
+3
View File
@@ -318,8 +318,10 @@ export interface Application {
speech_synthesis_voice: null | string;
speech_synthesis_vendor: null | Lowercase<Vendor>;
speech_synthesis_language: null | string;
speech_synthesis_label: null | string;
speech_recognizer_vendor: null | Lowercase<Vendor>;
speech_recognizer_language: null | string;
speech_recognizer_label: null | string;
record_all_calls: number;
}
@@ -391,6 +393,7 @@ export interface SpeechCredential {
auth_token: null | string;
custom_stt_url: null | string;
custom_tts_url: null | string;
label: null | string;
}
export interface Alert {
+2
View File
@@ -50,6 +50,7 @@ import {
Smartphone,
Youtube,
Mail,
Tag,
} from "react-feather";
import type { Icon } from "react-feather";
@@ -110,4 +111,5 @@ export const Icons: IconMap = {
Smartphone,
Youtube,
Mail,
Tag,
};
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useMemo, useState } from "react";
import { Button, ButtonGroup, MS } from "@jambonz/ui-kit";
import { Link, useNavigate } from "react-router-dom";
@@ -46,6 +46,7 @@ import type {
VoiceLanguage,
Language,
VendorOptions,
LabelOptions,
} from "src/vendor/types";
import type {
@@ -100,6 +101,10 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
const [credentials] = useApiData<SpeechCredential[]>(apiUrl);
const [softTtsVendor, setSoftTtsVendor] = useState<VendorOptions[]>(vendors);
const [softSttVendor, setSoftSttVendor] = useState<VendorOptions[]>(vendors);
const [recogLabel, setRecogLabel] = useState("");
const [ttsLabelOptions, setTtsLabelOptions] = useState<LabelOptions[]>([]);
const [sttLabelOptions, setSttLabelOptions] = useState<LabelOptions[]>([]);
const [synthLabel, setSynthLabel] = useState("");
const [recordAllCalls, setRecordAllCalls] = useState(false);
/** This lets us map and render the same UI for each... */
@@ -180,9 +185,11 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
call_status_hook: statusWebhook || null,
speech_synthesis_vendor: synthVendor || null,
speech_synthesis_language: synthLang || null,
speech_synthesis_label: synthLabel || null,
speech_synthesis_voice: synthVoice || null,
speech_recognizer_vendor: recogVendor || null,
speech_recognizer_language: recogLang || null,
speech_recognizer_label: recogLabel || null,
record_all_calls: recordAllCalls ? 1 : 0,
};
@@ -211,7 +218,7 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
}
};
useEffect(() => {
useMemo(() => {
if (credentials && hasLength(credentials)) {
const v = credentials
.filter((tv) => tv.vendor.startsWith(VENDOR_CUSTOM) && tv.use_for_tts)
@@ -236,8 +243,47 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
})
);
setSoftSttVendor(vendors.concat(v2));
const noneLabelObject = {
name: "None",
value: null,
};
let labels = credentials
.filter(
(c) =>
c.label &&
c.vendor === synthVendor &&
c.account_sid === accountSid &&
c.use_for_tts
)
.map((c) =>
Object.assign({
name: c.label,
value: c.label,
})
);
setTtsLabelOptions([noneLabelObject, ...labels]);
labels = credentials
.filter(
(c) =>
c.label &&
c.vendor === recogVendor &&
c.account_sid === accountSid &&
c.use_for_stt
)
.map((c) =>
Object.assign({
name: c.label,
value: c.label,
})
);
setSttLabelOptions([noneLabelObject, ...labels]);
}
}, [credentials]);
}, [credentials, synthVendor, recogVendor]);
useEffect(() => {
if (accountSid) {
@@ -321,6 +367,12 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
if (application.data.speech_recognizer_language)
setRecogLang(application.data.speech_recognizer_language);
if (application.data.speech_synthesis_label) {
setSynthLabel(application.data.speech_synthesis_label);
}
if (application.data.speech_recognizer_label) {
setRecogLabel(application.data.speech_recognizer_label);
}
}
}, [application]);
@@ -501,6 +553,20 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
setSynthVoice(newLang!.voices[0].value);
}}
/>
{hasLength(ttsLabelOptions) && ttsLabelOptions.length > 1 && (
<>
<label htmlFor="synthesis_label">Label</label>
<Selector
id="systhesis_label"
name="systhesis_label"
value={synthLabel}
options={ttsLabelOptions}
onChange={(e) => {
setSynthLabel(e.target.value);
}}
/>
</>
)}
{synthVendor &&
!synthVendor.toString().startsWith(VENDOR_CUSTOM) &&
synthLang && (
@@ -621,6 +687,20 @@ export const ApplicationForm = ({ application }: ApplicationFormProps) => {
}
}}
/>
{hasLength(sttLabelOptions) && sttLabelOptions.length > 1 && (
<>
<label htmlFor="recog_label">Label</label>
<Selector
id="recog_label"
name="recog_label"
value={recogLabel}
options={sttLabelOptions}
onChange={(e) => {
setRecogLabel(e.target.value);
}}
/>
</>
)}
{recogVendor &&
!recogVendor.toString().startsWith(VENDOR_CUSTOM) &&
recogLang && (
@@ -19,7 +19,11 @@ export const DeleteSpeechService = ({
return (
<Modal handleCancel={handleCancel} handleSubmit={handleSubmit}>
<P>
Are you sure you want to delete the <strong>{credential.vendor}</strong>{" "}
Are you sure you want to delete the{" "}
<strong>
{credential.vendor}
{credential.label ? ` (${credential.label})` : ""}
</strong>{" "}
speech service?
</P>
</Modal>
@@ -3,7 +3,7 @@ import { Button, ButtonGroup, MS } from "@jambonz/ui-kit";
import { Link, useNavigate } from "react-router-dom";
import { ROUTE_INTERNAL_SPEECH } from "src/router/routes";
import { Section } from "src/components";
import { Section, Tooltip } from "src/components";
import {
FileUpload,
Selector,
@@ -99,6 +99,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
const [onPremNuanceSttCheck, setOnPremNuanceSttCheck] = useState(false);
const [tmpOnPremNuanceSttUrl, setTmpOnPremNuanceSttUrl] = useState("");
const [onPremNuanceSttUrl, setOnPremNuanceSttUrl] = useState("");
const [label, setLabel] = useState("");
const handleFile = (file: File) => {
const handleError = () => {
@@ -143,6 +144,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
service_provider_sid: currentServiceProvider.service_provider_sid,
use_for_tts: ttsCheck ? 1 : 0,
use_for_stt: sttCheck ? 1 : 0,
label: label || null,
...(vendor === VENDOR_AWS && {
aws_region: region || null,
}),
@@ -347,6 +349,9 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
setTmpCustomVendorSttUrl(credential.data.custom_stt_url || "");
setCustomVendorTtsUrl(credential.data.custom_tts_url || "");
setTmpCustomVendorTtsUrl(credential.data.custom_tts_url || "");
if (credential.data.label) {
setLabel(credential.data.label);
}
}
}, [credential]);
@@ -416,6 +421,22 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
disabled={credential ? true : false}
/>
</fieldset>
<fieldset>
<label htmlFor="speech_label">
Label
<Tooltip text="Assign a label only if you need to create multiple speech services from the same vendor. Then use the label in your application to specify which service to use.">
{" "}
</Tooltip>
</label>
<input
id="speech_label"
type="text"
name="speech_label"
value={label}
disabled={credential ? true : false}
onChange={(e) => setLabel(e.target.value)}
/>
</fieldset>
{vendor && (
<fieldset>
{vendor !== VENDOR_DEEPGRAM &&
@@ -76,7 +76,11 @@ export const SpeechServices = () => {
refetch();
toastSuccess(
<>
Deleted speech service <strong>{credential.vendor}</strong>
Deleted speech service{" "}
<strong>
{credential.vendor}
{credential.label ? ` (${credential.label})` : ""}
</strong>{" "}
</>
);
})
@@ -195,6 +199,14 @@ export const SpeechServices = () => {
<div>
<CredentialStatus cred={credential} />
</div>
{credential.label && (
<div>
<div className="i txt--teal">
<Icons.Tag />
<span>{credential.label}</span>
</div>
</div>
)}
</div>
</div>
<ScopedAccess
+5
View File
@@ -15,6 +15,11 @@ export interface VendorOptions {
value: Lowercase<Vendor>;
}
export interface LabelOptions {
name: string;
value: string;
}
export interface Region {
name: string;
value: string;