Compare commits

...

5 Commits

Author SHA1 Message Date
Hoan Luu Huu
2c390715d8 Feat/rid of env (#443)
* Get rid of VITE_API_BASE_URL

* wip

* wip
2024-07-15 08:58:22 -04:00
Hoan Luu Huu
dcdc2c0808 add use sips scheme to outbound tls gateway (#439)
* add use sips scheme to outbound tls gateway

* update license
2024-06-15 09:13:04 -04:00
Hoan Luu Huu
a3c48e7efb support verbio speech (#434) 2024-05-29 07:57:05 -04:00
Hoan Luu Huu
6b9167e6b8 support speech aws polly by roleArn (#428)
* support speech aws polly by roleArn

* add 3 types of aws poly credential

* wip
2024-05-02 07:58:02 -04:00
Hoan Luu Huu
e7889e1ad3 fix send OPTIONS ping mess the layout (#431) 2024-04-30 07:43:44 -04:00
9 changed files with 230 additions and 32 deletions

4
.env
View File

@@ -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_API_BASE_URL=http://127.0.0.1:3000/v1
#VITE_DEV_BASE_URL=http://127.0.0.1:3000/v1
## enables choosing units and lisenced account call limits
# VITE_APP_ENABLE_ACCOUNT_LIMITS_ALL=true

View File

@@ -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.

View File

@@ -1,3 +1,4 @@
import { hasValue } from "src/utils";
import type {
Currency,
ElevenLabsOptions,
@@ -37,8 +38,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;
@@ -205,6 +209,14 @@ 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";
// Google Custom Voice reported usage options
export const DEFAULT_GOOGLE_CUSTOM_VOICES_REPORTED_USAGE = "REALTIME";

View File

@@ -390,6 +390,7 @@ export interface SpeechCredential {
region: null | string;
aws_region: null | string;
api_key: null | string;
role_arn: null | string;
user_id: null | string;
access_key_id: null | string;
secret_access_key: null | string;
@@ -401,6 +402,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;
@@ -417,6 +419,7 @@ 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;
@@ -486,6 +489,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 {

View File

@@ -1142,6 +1142,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

View File

@@ -42,6 +42,11 @@ import {
VENDOR_WHISPER,
VENDOR_PLAYHT,
VENDOR_RIMELABS,
AWS_CREDENTIAL_TYPES,
AWS_CREDENTIAL_IAM_ASSUME_ROLE,
AWS_CREDENTIAL_ACCESS_KEY,
AWS_INSTANCE_PROFILE,
VENDOR_VERBIO,
} from "src/vendor";
import { MSG_REQUIRED_FIELDS } from "src/constants";
import {
@@ -73,8 +78,10 @@ import {
DEFAULT_GOOGLE_CUSTOM_VOICES_REPORTED_USAGE,
DEFAULT_PLAYHT_OPTIONS,
DEFAULT_RIMELABS_OPTIONS,
DEFAULT_VERBIO_MODEL,
DISABLE_CUSTOM_SPEECH,
GOOGLE_CUSTOM_VOICES_REPORTED_USAGE,
VERBIO_STT_MODELS,
} from "src/api/constants";
type SpeechServiceFormProps = {
@@ -102,6 +109,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("");
@@ -109,6 +117,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);
@@ -157,6 +166,10 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
const [initialDeepgramOnpremCheck, setInitialDeepgramOnpremCheck] =
useState(false);
const [isDeepgramOnpremEnabled, setIsDeepgramOnpremEnabled] = useState(false);
const [awsCredentialType, setAwsCredentialType] = useState(
AWS_CREDENTIAL_ACCESS_KEY,
);
const [roleArn, setRoleArn] = useState("");
const handleFile = (file: File) => {
const handleError = () => {
@@ -345,6 +358,9 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
deepgram_stt_uri: deepgramSttUri || null,
deepgram_stt_use_tls: deepgramSttUseTls ? 1 : 0,
}),
...(vendor === VENDOR_VERBIO && {
engine_version: engineVersion,
}),
};
if (credential && credential.data) {
@@ -378,6 +394,7 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
vendor === VENDOR_GOOGLE ? JSON.stringify(googleServiceKey) : null,
access_key_id: vendor === VENDOR_AWS ? accessKeyId : null,
secret_access_key: vendor === VENDOR_AWS ? secretAccessKey : null,
role_arn: vendor === VENDOR_AWS ? roleArn : null,
...(apiKey && {
api_key:
vendor === VENDOR_MICROSOFT ||
@@ -396,6 +413,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 }) => {
@@ -626,6 +647,27 @@ export const SpeechServiceForm = ({ credential }: SpeechServiceFormProps) => {
if (credential?.data?.voice_engine) {
setTtsModelId(credential.data.voice_engine);
}
if (credential?.data?.role_arn) {
setRoleArn(credential.data.role_arn);
}
if (credential) {
setAwsCredentialType(
credential?.data?.access_key_id
? AWS_CREDENTIAL_ACCESS_KEY
: credential?.data?.role_arn
? AWS_CREDENTIAL_IAM_ASSUME_ROLE
: 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);
}
}, [credential]);
const updateCustomVoices = (
@@ -1162,37 +1204,128 @@ 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="aws_access_key">
Access key ID<span>*</span>
<label htmlFor="vendor">
Credential type<span>*</span>
</label>
<input
id="aws_access_key"
required
type="text"
name="aws_access_key"
placeholder="Access Key ID"
value={accessKeyId}
onChange={(e) => setAccessKeyId(e.target.value)}
<Selector
id="aws_credential_type"
name="aws_credential_type"
value={awsCredentialType}
options={AWS_CREDENTIAL_TYPES}
onChange={(e) => {
setAccessKeyId("");
setSecretAccessKey("");
setRoleArn("");
setAwsCredentialType(e.target.value);
}}
disabled={credential ? true : false}
/>
<label htmlFor="aws_secret_key">
Secret access key<span>*</span>
</label>
<Passwd
id="aws_secret_key"
required
name="aws_secret_key"
placeholder="Secret Access Key"
value={
secretAccessKey
? getObscuredSecret(secretAccessKey)
: secretAccessKey
}
onChange={(e) => setSecretAccessKey(e.target.value)}
disabled={credential ? true : false}
/>
{awsCredentialType === AWS_CREDENTIAL_ACCESS_KEY ? (
<>
<label htmlFor="aws_access_key">
Access key ID<span>*</span>
</label>
<input
id="aws_access_key"
required
type="text"
name="aws_access_key"
placeholder="Access Key ID"
value={accessKeyId}
onChange={(e) => setAccessKeyId(e.target.value)}
disabled={credential ? true : false}
/>
<label htmlFor="aws_secret_key">
Secret access key<span>*</span>
</label>
<Passwd
id="aws_secret_key"
required
name="aws_secret_key"
placeholder="Secret Access Key"
value={
secretAccessKey
? getObscuredSecret(secretAccessKey)
: secretAccessKey
}
onChange={(e) => setSecretAccessKey(e.target.value)}
disabled={credential ? true : false}
/>
</>
) : awsCredentialType === AWS_CREDENTIAL_IAM_ASSUME_ROLE ? (
<>
<label htmlFor="aws_access_key">
RoleArn<span>*</span>
</label>
<input
id="aws_role_arn"
required
type="text"
name="aws_role_arn"
placeholder="RoleArn"
value={roleArn}
onChange={(e) => setRoleArn(e.target.value)}
disabled={credential ? true : false}
/>
</>
) : (
<></>
)}
</fieldset>
)}

View File

@@ -231,7 +231,7 @@ fieldset {
}
&:nth-child(2) {
grid-template-columns: repeat(4, 1fr);
grid-template-columns: repeat(3, 1fr);
margin-top: ui-vars.$px02;
> div:last-child {

24
src/vendor/index.tsx vendored
View File

@@ -22,6 +22,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[] = [
{
@@ -88,8 +89,31 @@ 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";
export const AWS_CREDENTIAL_IAM_ASSUME_ROLE = "assume_role";
export const AWS_INSTANCE_PROFILE = "instance_profile";
export const AWS_CREDENTIAL_TYPES = [
{
name: "AWS access key",
value: AWS_CREDENTIAL_ACCESS_KEY,
},
{
name: "AWS assume role",
value: AWS_CREDENTIAL_IAM_ASSUME_ROLE,
},
{
name: "AWS instance profile",
value: AWS_INSTANCE_PROFILE,
},
];
export const useRegionVendors = () => {
const [regions, setRegions] = useState<RegionVendors>();

3
src/vendor/types.ts vendored
View File

@@ -14,7 +14,8 @@ export type Vendor =
| "assemblyai"
| "whisper"
| "playht"
| "rimelabs";
| "rimelabs"
| "verbio";
export interface VendorOptions {
name: Vendor;