@myscheme/voice-navigation-sdk 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +130 -17
- package/dist/actions.d.ts +1 -0
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +51 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +158 -1
- package/dist/languages.d.ts +17 -0
- package/dist/languages.d.ts.map +1 -0
- package/dist/languages.js +86 -0
- package/dist/microphone-handler.d.ts +8 -2
- package/dist/microphone-handler.d.ts.map +1 -1
- package/dist/microphone-handler.js +89 -2
- package/dist/navigation-controller.d.ts +2 -0
- package/dist/navigation-controller.d.ts.map +1 -1
- package/dist/navigation-controller.js +58 -22
- package/dist/server/azure-speech-handler.d.ts +3 -2
- package/dist/server/azure-speech-handler.d.ts.map +1 -1
- package/dist/server/azure-speech-handler.js +26 -2
- package/dist/server/bedrock-embedding-handler.d.ts +2 -1
- package/dist/server/bedrock-embedding-handler.d.ts.map +1 -1
- package/dist/server/bedrock-embedding-handler.js +73 -19
- package/dist/server/bedrock-handler.d.ts +2 -1
- package/dist/server/bedrock-handler.d.ts.map +1 -1
- package/dist/server/bedrock-handler.js +124 -19
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -0
- package/dist/server/opensearch-env-handler.d.ts +2 -1
- package/dist/server/opensearch-env-handler.d.ts.map +1 -1
- package/dist/server/opensearch-env-handler.js +23 -53
- package/dist/server/sarvam-stt-relay.d.ts +8 -0
- package/dist/server/sarvam-stt-relay.d.ts.map +1 -0
- package/dist/server/sarvam-stt-relay.js +111 -0
- package/dist/server/security.d.ts +26 -0
- package/dist/server/security.d.ts.map +1 -0
- package/dist/server/security.js +89 -0
- package/dist/services/bedrock.d.ts.map +1 -1
- package/dist/services/bedrock.js +13 -0
- package/dist/services/sarvam-speech.d.ts +47 -0
- package/dist/services/sarvam-speech.d.ts.map +1 -0
- package/dist/services/sarvam-speech.js +418 -0
- package/dist/services/voice-feedback.d.ts +7 -2
- package/dist/services/voice-feedback.d.ts.map +1 -1
- package/dist/services/voice-feedback.js +45 -5
- package/dist/types.d.ts +11 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Voice Navigation SDK
|
|
2
2
|
|
|
3
|
-
A TypeScript SDK for voice-controlled navigation using Azure Speech
|
|
3
|
+
A TypeScript SDK for voice-controlled navigation using Sarvam or Azure Speech, and AWS Bedrock for intent understanding.
|
|
4
4
|
|
|
5
5
|
## 🚀 Features
|
|
6
6
|
|
|
7
|
-
- 🎤 **Real-time speech recognition** using Azure Speech SDK
|
|
7
|
+
- 🎤 **Real-time speech recognition** using Sarvam (default) or Azure Speech SDK
|
|
8
|
+
- 🔊 **Text-to-speech feedback** using Sarvam (default) or Azure Speech SDK
|
|
8
9
|
- 🤖 **AI-powered intent extraction** using AWS Bedrock (Claude)
|
|
9
10
|
- 🌐 **Dynamic page navigation** via XML configuration
|
|
10
11
|
- 🧭 **Voice-controlled navigation** actions
|
|
@@ -48,9 +49,23 @@ The guide covers:
|
|
|
48
49
|
### Basic Setup
|
|
49
50
|
|
|
50
51
|
```typescript
|
|
51
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
initNavigationOnMicrophone,
|
|
54
|
+
buildSpeechProviderConfig,
|
|
55
|
+
} from "@myscheme/voice-navigation-sdk";
|
|
52
56
|
|
|
53
57
|
const controller = initNavigationOnMicrophone({
|
|
58
|
+
...buildSpeechProviderConfig({
|
|
59
|
+
provider: "sarvam",
|
|
60
|
+
sarvam: {
|
|
61
|
+
apiKey: "your-sarvam-api-key",
|
|
62
|
+
sttModel: "saaras:v3",
|
|
63
|
+
ttsModel: "bulbul:v3",
|
|
64
|
+
speaker: "manan",
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
|
|
68
|
+
// Azure Speech configuration (required only when speechProvider is "azure")
|
|
54
69
|
// Azure Speech configuration
|
|
55
70
|
azure: {
|
|
56
71
|
subscriptionKey: "your-azure-subscription-key",
|
|
@@ -73,6 +88,97 @@ const controller = initNavigationOnMicrophone({
|
|
|
73
88
|
});
|
|
74
89
|
```
|
|
75
90
|
|
|
91
|
+
### Runtime Provider Switch Helper
|
|
92
|
+
|
|
93
|
+
Switch between Sarvam and Azure without rebuilding your app:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { switchVoiceProvider } from "@myscheme/voice-navigation-sdk";
|
|
97
|
+
|
|
98
|
+
// Switch to Azure at runtime
|
|
99
|
+
switchVoiceProvider("azure", {
|
|
100
|
+
azure: {
|
|
101
|
+
tokenEndpoint: "/api/speech/token",
|
|
102
|
+
// or: subscriptionKey + region for direct mode
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Switch back to Sarvam at runtime
|
|
107
|
+
switchVoiceProvider("sarvam", {
|
|
108
|
+
sarvam: {
|
|
109
|
+
apiKey: process.env.NEXT_PUBLIC_SARVAM_API_KEY,
|
|
110
|
+
sttModel: "saaras:v3",
|
|
111
|
+
ttsModel: "bulbul:v3",
|
|
112
|
+
speaker: "manan",
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Ready-to-Copy Config
|
|
118
|
+
|
|
119
|
+
Sarvam (default provider):
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { initNavigationOnMicrophone } from "@myscheme/voice-navigation-sdk";
|
|
123
|
+
|
|
124
|
+
const controller = initNavigationOnMicrophone({
|
|
125
|
+
speechProvider: "sarvam",
|
|
126
|
+
sarvam: {
|
|
127
|
+
apiKey: process.env.NEXT_PUBLIC_SARVAM_API_KEY,
|
|
128
|
+
sttModel: "saaras:v3",
|
|
129
|
+
ttsModel: "bulbul:v3",
|
|
130
|
+
speaker: "manan",
|
|
131
|
+
sttSampleRate: 16000,
|
|
132
|
+
ttsSampleRate: 22050,
|
|
133
|
+
},
|
|
134
|
+
aws: {
|
|
135
|
+
bedrockEndpoint: "/api/speech/bedrock",
|
|
136
|
+
embeddingEndpoint: "/api/speech/bedrock-embedding",
|
|
137
|
+
},
|
|
138
|
+
language: "en-IN",
|
|
139
|
+
autoStart: false,
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Azure (proxy mode recommended):
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { initNavigationOnMicrophone } from "@myscheme/voice-navigation-sdk";
|
|
147
|
+
|
|
148
|
+
const controller = initNavigationOnMicrophone({
|
|
149
|
+
speechProvider: "azure",
|
|
150
|
+
azure: {
|
|
151
|
+
tokenEndpoint: "/api/speech/token",
|
|
152
|
+
},
|
|
153
|
+
aws: {
|
|
154
|
+
bedrockEndpoint: "/api/speech/bedrock",
|
|
155
|
+
embeddingEndpoint: "/api/speech/bedrock-embedding",
|
|
156
|
+
},
|
|
157
|
+
language: "en-IN",
|
|
158
|
+
autoStart: false,
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Azure (direct credentials, use only in trusted/server contexts):
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { initNavigationOnMicrophone } from "@myscheme/voice-navigation-sdk";
|
|
166
|
+
|
|
167
|
+
const controller = initNavigationOnMicrophone({
|
|
168
|
+
speechProvider: "azure",
|
|
169
|
+
azure: {
|
|
170
|
+
subscriptionKey: process.env.NEXT_PUBLIC_AZURE_SPEECH_KEY,
|
|
171
|
+
region: process.env.NEXT_PUBLIC_AZURE_SPEECH_REGION,
|
|
172
|
+
},
|
|
173
|
+
aws: {
|
|
174
|
+
bedrockEndpoint: "/api/speech/bedrock",
|
|
175
|
+
embeddingEndpoint: "/api/speech/bedrock-embedding",
|
|
176
|
+
},
|
|
177
|
+
language: "en-IN",
|
|
178
|
+
autoStart: false,
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
76
182
|
### With Dynamic Pages
|
|
77
183
|
|
|
78
184
|
```typescript
|
|
@@ -96,20 +202,27 @@ const controller = initNavigationOnMicrophone({
|
|
|
96
202
|
|
|
97
203
|
### NavigationConfig Options
|
|
98
204
|
|
|
99
|
-
| Property | Type | Required | Description
|
|
100
|
-
| ----------------------- | --------- | -------- |
|
|
101
|
-
| `
|
|
102
|
-
| `
|
|
103
|
-
| `
|
|
104
|
-
| `
|
|
105
|
-
| `
|
|
106
|
-
| `
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
109
|
-
| `
|
|
110
|
-
| `
|
|
111
|
-
| `
|
|
112
|
-
| `
|
|
205
|
+
| Property | Type | Required | Description |
|
|
206
|
+
| ----------------------- | --------- | -------- | ------------------------------------------------ |
|
|
207
|
+
| `speechProvider` | `string` | ❌ | Speech provider: `sarvam` (default) or `azure` |
|
|
208
|
+
| `sarvam.apiKey` | `string` | ✅\* | Sarvam API key (\*required when provider=sarvam) |
|
|
209
|
+
| `sarvam.sttModel` | `string` | ❌ | STT model (default: `saaras:v3`) |
|
|
210
|
+
| `sarvam.ttsModel` | `string` | ❌ | TTS model (default: `bulbul:v3`) |
|
|
211
|
+
| `sarvam.speaker` | `string` | ❌ | Sarvam speaker name |
|
|
212
|
+
| `azure.subscriptionKey` | `string` | ✅ | Azure Speech subscription key |
|
|
213
|
+
| `azure.region` | `string` | ✅ | Azure Speech region |
|
|
214
|
+
| `aws.accessKeyId` | `string` | ✅ | AWS access key ID |
|
|
215
|
+
| `aws.secretAccessKey` | `string` | ✅ | AWS secret access key |
|
|
216
|
+
| `aws.modelId` | `string` | ✅ | AWS Bedrock model ID |
|
|
217
|
+
| `aws.region` | `string` | ❌ | AWS region (default: 'ap-south-1') |
|
|
218
|
+
| `language` | `string` | ❌ | Speech recognition language (default: 'en-IN') |
|
|
219
|
+
| `autoStart` | `boolean` | ❌ | Auto-start voice control (default: false) |
|
|
220
|
+
| `actionHandlers` | `object` | ❌ | Custom action callbacks |
|
|
221
|
+
| `pages` | `object` | ❌ | Dynamic page navigation configuration |
|
|
222
|
+
| `opensearch` | `object` | ❌ | OpenSearch vector search configuration |
|
|
223
|
+
| `ui` | `object` | ❌ | UI customization (button placement & style) |
|
|
224
|
+
|
|
225
|
+
Note: Bhashini is not integrated in this release.
|
|
113
226
|
|
|
114
227
|
### OpenSearch Configuration
|
|
115
228
|
|
package/dist/actions.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare const setPageRegistry: (registry: PageRegistry) => void;
|
|
|
4
4
|
export declare const getPageRegistry: () => PageRegistry | null;
|
|
5
5
|
export declare const setZoomScale: (scale: number) => number;
|
|
6
6
|
export declare const adjustZoom: (delta: number) => number;
|
|
7
|
+
export declare const ACTION_LABELS: Record<string, string>;
|
|
7
8
|
export declare const formatActionLabel: (action: string) => string;
|
|
8
9
|
export declare const performAgentAction: (action: NavigationAction, context?: ActionContext) => ActionResult;
|
|
9
10
|
export declare const extractAgentAction: (result: any) => AgentActionResponse | null;
|
package/dist/actions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gBAAgB,EAEhB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACpB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AA4DhE,eAAO,MAAM,eAAe,GAAI,UAAU,YAAY,KAAG,IAOxD,CAAC;AAKF,eAAO,MAAM,eAAe,QAAO,YAAY,GAAG,IAEjD,CAAC;AAgGF,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,MAS5C,CAAC;AAKF,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAM1C,CAAC;
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,gBAAgB,EAEhB,aAAa,EACb,YAAY,EACZ,mBAAmB,EACpB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AA4DhE,eAAO,MAAM,eAAe,GAAI,UAAU,YAAY,KAAG,IAOxD,CAAC;AAKF,eAAO,MAAM,eAAe,QAAO,YAAY,GAAG,IAEjD,CAAC;AAgGF,eAAO,MAAM,YAAY,GAAI,OAAO,MAAM,KAAG,MAS5C,CAAC;AAKF,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAM1C,CAAC;AAOF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAiDhD,CAAC;AAQF,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,KAAG,MAElD,CAAC;AAKF,eAAO,MAAM,kBAAkB,GAC7B,QAAQ,gBAAgB,EACxB,UAAS,aAAkB,KAC1B,YAg7BF,CAAC;AAKF,eAAO,MAAM,kBAAkB,GAAI,QAAQ,GAAG,KAAG,mBAAmB,GAAG,IAiCtE,CAAC;AAKF,eAAO,MAAM,eAAe,GAAI,QAAQ,MAAM,KAAG,MAAM,IAAI,gBAY1D,CAAC"}
|
package/dist/actions.js
CHANGED
|
@@ -131,8 +131,58 @@ export const adjustZoom = (delta) => {
|
|
|
131
131
|
const current = parseFloat(document.documentElement.dataset.navigateZoom || "1");
|
|
132
132
|
return setZoomScale(current + delta);
|
|
133
133
|
};
|
|
134
|
+
export const ACTION_LABELS = {
|
|
135
|
+
zoom_in: "Zoomed in",
|
|
136
|
+
zoom_out: "Zoomed out",
|
|
137
|
+
scroll_up: "Scrolled up",
|
|
138
|
+
scroll_down: "Scrolled down",
|
|
139
|
+
scroll_left: "Scrolled left",
|
|
140
|
+
scroll_right: "Scrolled right",
|
|
141
|
+
page_up: "Moved up a page",
|
|
142
|
+
page_down: "Moved down a page",
|
|
143
|
+
scroll_top: "Jumped to the top of the page",
|
|
144
|
+
scroll_bottom: "Jumped to the bottom of the page",
|
|
145
|
+
go_back: "Went back to the previous page",
|
|
146
|
+
go_forward: "Went forward to the next page",
|
|
147
|
+
reload_page: "Reloaded the page",
|
|
148
|
+
print_page: "Opened the print dialog",
|
|
149
|
+
copy_url: "Copied the page link",
|
|
150
|
+
open_menu: "Opened the menu",
|
|
151
|
+
close_menu: "Closed the menu",
|
|
152
|
+
focus_search: "Moved to the search box",
|
|
153
|
+
toggle_fullscreen: "Turned on full screen",
|
|
154
|
+
exit_fullscreen: "Turned off full screen",
|
|
155
|
+
play_media: "Playing the video",
|
|
156
|
+
pause_media: "Paused the video",
|
|
157
|
+
mute_media: "Muted the sound",
|
|
158
|
+
unmute_media: "Unmuted the sound",
|
|
159
|
+
search_content: "Searching",
|
|
160
|
+
stop: "Stopped listening",
|
|
161
|
+
quit: "Stopped voice navigation",
|
|
162
|
+
tab_next: "Moved to the next item",
|
|
163
|
+
tab_back: "Moved to the previous item",
|
|
164
|
+
focus_next: "Moved focus to the next item",
|
|
165
|
+
focus_previous: "Moved focus to the previous item",
|
|
166
|
+
click: "Clicked",
|
|
167
|
+
enter: "Pressed enter",
|
|
168
|
+
submit: "Submitted the form",
|
|
169
|
+
activate: "Activated",
|
|
170
|
+
move_left: "Moved left",
|
|
171
|
+
move_right: "Moved right",
|
|
172
|
+
move_up: "Moved up",
|
|
173
|
+
move_down: "Moved down",
|
|
174
|
+
move_beginning: "Moved to the beginning",
|
|
175
|
+
move_end: "Moved to the end",
|
|
176
|
+
select_all: "Selected all text",
|
|
177
|
+
select_line: "Selected the line",
|
|
178
|
+
type_text: "Typed the text",
|
|
179
|
+
cut: "Cut the selection",
|
|
180
|
+
copy: "Copied the selection",
|
|
181
|
+
paste: "Pasted",
|
|
182
|
+
clear: "Cleared the field",
|
|
183
|
+
};
|
|
134
184
|
export const formatActionLabel = (action) => {
|
|
135
|
-
return action.replace(/_/g, " ");
|
|
185
|
+
return ACTION_LABELS[action] ?? action.replace(/_/g, " ");
|
|
136
186
|
};
|
|
137
187
|
export const performAgentAction = (action, context = {}) => {
|
|
138
188
|
if (!action) {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,52 @@
|
|
|
1
1
|
export { VoiceNavigationController } from "./navigation-controller.js";
|
|
2
2
|
export { MicrophoneHandler } from "./microphone-handler.js";
|
|
3
3
|
export { AzureSpeechService } from "./services/azure-speech.js";
|
|
4
|
+
export { SarvamSpeechService } from "./services/sarvam-speech.js";
|
|
4
5
|
export { BedrockService } from "./services/bedrock.js";
|
|
5
6
|
export { PageRegistry } from "./services/page-registry.js";
|
|
6
7
|
export type { NavigablePage } from "./services/page-registry.js";
|
|
7
8
|
export { parseNavigationXML, fetchNavigationXML, loadNavigationPages, } from "./services/xml-parser.js";
|
|
8
9
|
export type { PageXMLConfig } from "./services/xml-parser.js";
|
|
10
|
+
export { SARVAM_LANGUAGES, SARVAM_STT_LANGUAGES, SARVAM_TTS_LANGUAGES, DEFAULT_LANGUAGE, isSttSupported, isTtsSupported, resolveTtsLanguage, normalizeLanguageCode, } from "./languages.js";
|
|
11
|
+
export type { SarvamLanguage } from "./languages.js";
|
|
9
12
|
export * from "./types.js";
|
|
10
13
|
export * from "./actions.js";
|
|
11
14
|
export { createFloatingControl, attachToCustomButton, setState, updateStatus, updateTranscript, updateActionIndicator, showError, emitEvent, } from "./ui.js";
|
|
12
15
|
import { VoiceNavigationController } from "./navigation-controller.js";
|
|
13
|
-
import type { NavigationConfig } from "./types.js";
|
|
16
|
+
import type { NavigationConfig, SpeechProvider } from "./types.js";
|
|
17
|
+
type SpeechProviderConfigOptions = {
|
|
18
|
+
provider: SpeechProvider;
|
|
19
|
+
azure?: NavigationConfig["azure"];
|
|
20
|
+
sarvam?: NavigationConfig["sarvam"];
|
|
21
|
+
};
|
|
22
|
+
export type ProviderSwitchOptions = {
|
|
23
|
+
azure?: NavigationConfig["azure"];
|
|
24
|
+
sarvam?: NavigationConfig["sarvam"];
|
|
25
|
+
language?: NavigationConfig["language"];
|
|
26
|
+
voiceFeedback?: NavigationConfig["voiceFeedback"];
|
|
27
|
+
};
|
|
28
|
+
export type VoiceProviderDropdownOption = {
|
|
29
|
+
provider: SpeechProvider;
|
|
30
|
+
label: string;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
};
|
|
33
|
+
export type VoiceProviderDropdownConfig = {
|
|
34
|
+
container: string | HTMLElement;
|
|
35
|
+
initialProvider?: SpeechProvider;
|
|
36
|
+
options?: VoiceProviderDropdownOption[];
|
|
37
|
+
className?: string;
|
|
38
|
+
selectId?: string;
|
|
39
|
+
resolveSwitchOptions?: (provider: SpeechProvider) => ProviderSwitchOptions | Promise<ProviderSwitchOptions>;
|
|
40
|
+
onProviderChanged?: (provider: SpeechProvider) => void;
|
|
41
|
+
onError?: (error: unknown, provider: SpeechProvider) => void;
|
|
42
|
+
};
|
|
43
|
+
export type VoiceProviderDropdownHandle = {
|
|
44
|
+
element: HTMLSelectElement;
|
|
45
|
+
destroy: () => void;
|
|
46
|
+
setProvider: (provider: SpeechProvider) => void;
|
|
47
|
+
};
|
|
48
|
+
export declare function buildSpeechProviderConfig(options: SpeechProviderConfigOptions): Pick<NavigationConfig, "speechProvider" | "azure" | "sarvam">;
|
|
49
|
+
export declare function switchVoiceProvider(provider: SpeechProvider, options?: ProviderSwitchOptions): VoiceNavigationController;
|
|
50
|
+
export declare function createVoiceProviderDropdown(config: VoiceProviderDropdownConfig): VoiceProviderDropdownHandle;
|
|
14
51
|
export declare function initNavigationOnMicrophone(config: NavigationConfig): VoiceNavigationController;
|
|
15
52
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,YAAY,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,cAAc,YAAY,CAAC;AAC3B,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,QAAQ,EACR,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,SAAS,EACT,SAAS,GACV,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export { VoiceNavigationController } from "./navigation-controller.js";
|
|
2
2
|
export { MicrophoneHandler } from "./microphone-handler.js";
|
|
3
3
|
export { AzureSpeechService } from "./services/azure-speech.js";
|
|
4
|
+
export { SarvamSpeechService } from "./services/sarvam-speech.js";
|
|
4
5
|
export { BedrockService } from "./services/bedrock.js";
|
|
5
6
|
export { PageRegistry } from "./services/page-registry.js";
|
|
6
7
|
export { parseNavigationXML, fetchNavigationXML, loadNavigationPages, } from "./services/xml-parser.js";
|
|
8
|
+
export { SARVAM_LANGUAGES, SARVAM_STT_LANGUAGES, SARVAM_TTS_LANGUAGES, DEFAULT_LANGUAGE, isSttSupported, isTtsSupported, resolveTtsLanguage, normalizeLanguageCode, } from "./languages.js";
|
|
7
9
|
export * from "./types.js";
|
|
8
10
|
export * from "./actions.js";
|
|
9
11
|
export { createFloatingControl, attachToCustomButton, setState, updateStatus, updateTranscript, updateActionIndicator, showError, emitEvent, } from "./ui.js";
|
|
@@ -29,8 +31,12 @@ const buildPersistableConfig = (config) => {
|
|
|
29
31
|
const hasCustomHandlers = Boolean(normalizedConfig.actionHandlers &&
|
|
30
32
|
Object.keys(normalizedConfig.actionHandlers).length > 0);
|
|
31
33
|
const persistable = {
|
|
34
|
+
speechProvider: normalizedConfig.speechProvider,
|
|
32
35
|
aws: normalizedConfig.aws ? { ...normalizedConfig.aws } : undefined,
|
|
33
36
|
azure: normalizedConfig.azure ? { ...normalizedConfig.azure } : undefined,
|
|
37
|
+
sarvam: normalizedConfig.sarvam
|
|
38
|
+
? { ...normalizedConfig.sarvam }
|
|
39
|
+
: undefined,
|
|
34
40
|
opensearch: normalizedConfig.opensearch
|
|
35
41
|
? { ...normalizedConfig.opensearch }
|
|
36
42
|
: undefined,
|
|
@@ -87,6 +93,155 @@ const describeOpenSearchConfig = (config) => {
|
|
|
87
93
|
apiPath,
|
|
88
94
|
});
|
|
89
95
|
};
|
|
96
|
+
const resolveSpeechProviderConfig = (currentConfig, provider, options) => {
|
|
97
|
+
const merged = {
|
|
98
|
+
...currentConfig,
|
|
99
|
+
...options,
|
|
100
|
+
speechProvider: provider,
|
|
101
|
+
azure: {
|
|
102
|
+
...(currentConfig.azure ?? {}),
|
|
103
|
+
...(options?.azure ?? {}),
|
|
104
|
+
},
|
|
105
|
+
sarvam: {
|
|
106
|
+
...(currentConfig.sarvam ?? {}),
|
|
107
|
+
...(options?.sarvam ?? {}),
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
if (provider === "sarvam") {
|
|
111
|
+
const hasTtsUrl = Boolean(merged.sarvam?.ttsUrl);
|
|
112
|
+
const hasSttUrl = Boolean(merged.sarvam?.sttUrl);
|
|
113
|
+
if (!hasTtsUrl || !hasSttUrl) {
|
|
114
|
+
merged.sarvam = {
|
|
115
|
+
...(merged.sarvam ?? {}),
|
|
116
|
+
ttsUrl: merged.sarvam?.ttsUrl ?? "/api/speech/sarvam",
|
|
117
|
+
sttUrl: merged.sarvam?.sttUrl ?? "/api/speech/sarvam-stt",
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (provider === "azure") {
|
|
122
|
+
const hasTokenEndpoint = Boolean(merged.azure?.tokenEndpoint);
|
|
123
|
+
const hasDirectCredentials = Boolean(merged.azure?.subscriptionKey && merged.azure?.region);
|
|
124
|
+
if (!hasTokenEndpoint && !hasDirectCredentials) {
|
|
125
|
+
merged.azure = {
|
|
126
|
+
...(merged.azure ?? {}),
|
|
127
|
+
tokenEndpoint: "/api/speech/token",
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return normalizeNavigationConfig(merged);
|
|
132
|
+
};
|
|
133
|
+
export function buildSpeechProviderConfig(options) {
|
|
134
|
+
return resolveSpeechProviderConfig({}, options.provider, {
|
|
135
|
+
azure: options.azure,
|
|
136
|
+
sarvam: options.sarvam,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
export function switchVoiceProvider(provider, options = {}) {
|
|
140
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
141
|
+
throw new Error("switchVoiceProvider requires a browser environment");
|
|
142
|
+
}
|
|
143
|
+
const globalWindow = window;
|
|
144
|
+
const currentRaw = globalWindow.__voiceNavigationConfig ||
|
|
145
|
+
readPersistedConfig() ||
|
|
146
|
+
{};
|
|
147
|
+
const currentConfig = normalizeNavigationConfig(currentRaw);
|
|
148
|
+
const nextConfig = resolveSpeechProviderConfig(currentConfig, provider, options);
|
|
149
|
+
return initNavigationOnMicrophone(nextConfig);
|
|
150
|
+
}
|
|
151
|
+
export function createVoiceProviderDropdown(config) {
|
|
152
|
+
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
153
|
+
throw new Error("createVoiceProviderDropdown requires a browser environment");
|
|
154
|
+
}
|
|
155
|
+
const container = typeof config.container === "string"
|
|
156
|
+
? document.querySelector(config.container)
|
|
157
|
+
: config.container;
|
|
158
|
+
if (!container) {
|
|
159
|
+
throw new Error("Voice provider dropdown container was not found");
|
|
160
|
+
}
|
|
161
|
+
const defaultOptions = [
|
|
162
|
+
{ provider: "sarvam", label: "Sarvam" },
|
|
163
|
+
{ provider: "azure", label: "Azure" },
|
|
164
|
+
];
|
|
165
|
+
const options = config.options?.length ? config.options : defaultOptions;
|
|
166
|
+
const wrapper = document.createElement("div");
|
|
167
|
+
wrapper.className = config.className ?? "voice-provider-dropdown";
|
|
168
|
+
wrapper.setAttribute("data-voice-provider-dropdown", "true");
|
|
169
|
+
const select = document.createElement("select");
|
|
170
|
+
select.id = config.selectId ?? "voice-provider-select";
|
|
171
|
+
select.setAttribute("aria-label", "Voice provider");
|
|
172
|
+
options.forEach((option) => {
|
|
173
|
+
const opt = document.createElement("option");
|
|
174
|
+
opt.value = option.provider;
|
|
175
|
+
opt.textContent = option.label;
|
|
176
|
+
opt.disabled = Boolean(option.disabled);
|
|
177
|
+
select.appendChild(opt);
|
|
178
|
+
});
|
|
179
|
+
let currentProvider = config.initialProvider ?? "sarvam";
|
|
180
|
+
const activeOption = options.find((option) => option.provider === currentProvider);
|
|
181
|
+
if (!activeOption || activeOption.disabled) {
|
|
182
|
+
const fallback = options.find((option) => !option.disabled);
|
|
183
|
+
if (!fallback) {
|
|
184
|
+
throw new Error("No enabled voice providers are available for dropdown");
|
|
185
|
+
}
|
|
186
|
+
currentProvider = fallback.provider;
|
|
187
|
+
}
|
|
188
|
+
select.value = currentProvider;
|
|
189
|
+
let isSwitching = false;
|
|
190
|
+
const handleChange = async () => {
|
|
191
|
+
if (isSwitching) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const nextProvider = select.value;
|
|
195
|
+
if (nextProvider === currentProvider) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const option = options.find((item) => item.provider === nextProvider);
|
|
199
|
+
if (option?.disabled) {
|
|
200
|
+
select.value = currentProvider;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
isSwitching = true;
|
|
204
|
+
select.disabled = true;
|
|
205
|
+
try {
|
|
206
|
+
const switchOptions = config.resolveSwitchOptions
|
|
207
|
+
? await config.resolveSwitchOptions(nextProvider)
|
|
208
|
+
: {};
|
|
209
|
+
switchVoiceProvider(nextProvider, switchOptions);
|
|
210
|
+
currentProvider = nextProvider;
|
|
211
|
+
config.onProviderChanged?.(nextProvider);
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
select.value = currentProvider;
|
|
215
|
+
config.onError?.(error, nextProvider);
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
isSwitching = false;
|
|
219
|
+
select.disabled = false;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
select.addEventListener("change", handleChange);
|
|
223
|
+
wrapper.appendChild(select);
|
|
224
|
+
const existing = container.querySelector("[data-voice-provider-dropdown='true']");
|
|
225
|
+
if (existing) {
|
|
226
|
+
existing.remove();
|
|
227
|
+
}
|
|
228
|
+
container.appendChild(wrapper);
|
|
229
|
+
return {
|
|
230
|
+
element: select,
|
|
231
|
+
destroy: () => {
|
|
232
|
+
select.removeEventListener("change", handleChange);
|
|
233
|
+
wrapper.remove();
|
|
234
|
+
},
|
|
235
|
+
setProvider: (provider) => {
|
|
236
|
+
const option = options.find((item) => item.provider === provider);
|
|
237
|
+
if (!option || option.disabled) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
currentProvider = provider;
|
|
241
|
+
select.value = provider;
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
90
245
|
export function initNavigationOnMicrophone(config) {
|
|
91
246
|
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
92
247
|
throw new Error("Voice navigation requires a browser environment");
|
|
@@ -129,11 +284,13 @@ export function initNavigationOnMicrophone(config) {
|
|
|
129
284
|
previousUI?.customButtonSelector !== currentUI?.customButtonSelector ||
|
|
130
285
|
previousUI?.buttonPlacement !== currentUI?.buttonPlacement;
|
|
131
286
|
console.log("[Voice Navigation] UI config changed:", uiConfigChanged);
|
|
287
|
+
const providerChanged = previousConfig?.speechProvider !== normalizedConfig.speechProvider;
|
|
132
288
|
if ((wantsVectorSearch &&
|
|
133
289
|
(!hadVectorSearch ||
|
|
134
290
|
vectorConfigChanged ||
|
|
135
291
|
!existingHasVectorSearch)) ||
|
|
136
|
-
uiConfigChanged
|
|
292
|
+
uiConfigChanged ||
|
|
293
|
+
providerChanged) {
|
|
137
294
|
console.log("[Voice Navigation] Destroying existing controller and recreating...");
|
|
138
295
|
try {
|
|
139
296
|
existingController?.destroy?.();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface SarvamLanguage {
|
|
2
|
+
code: string;
|
|
3
|
+
name: string;
|
|
4
|
+
nativeName: string;
|
|
5
|
+
script: string;
|
|
6
|
+
stt: boolean;
|
|
7
|
+
tts: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const SARVAM_LANGUAGES: SarvamLanguage[];
|
|
10
|
+
export declare const DEFAULT_LANGUAGE = "en-IN";
|
|
11
|
+
export declare const SARVAM_STT_LANGUAGES: string[];
|
|
12
|
+
export declare const SARVAM_TTS_LANGUAGES: string[];
|
|
13
|
+
export declare function isSttSupported(code: string): boolean;
|
|
14
|
+
export declare function isTtsSupported(code: string): boolean;
|
|
15
|
+
export declare function resolveTtsLanguage(code: string): string;
|
|
16
|
+
export declare function normalizeLanguageCode(input?: string | null): string;
|
|
17
|
+
//# sourceMappingURL=languages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"languages.d.ts","sourceRoot":"","sources":["../src/languages.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,cAAc;IAE7B,IAAI,EAAE,MAAM,CAAC;IAEb,IAAI,EAAE,MAAM,CAAC;IAEb,UAAU,EAAE,MAAM,CAAC;IAEnB,MAAM,EAAE,MAAM,CAAC;IAEf,GAAG,EAAE,OAAO,CAAC;IAEb,GAAG,EAAE,OAAO,CAAC;CACd;AAMD,eAAO,MAAM,gBAAgB,EAAE,cAAc,EAwB5C,CAAC;AAGF,eAAO,MAAM,gBAAgB,UAAU,CAAC;AAGxC,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAEf,CAAC;AAG3B,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAEf,CAAC;AAuC3B,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAGD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAOD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGvD;AAOD,wBAAgB,qBAAqB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CA0BnE"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export const SARVAM_LANGUAGES = [
|
|
2
|
+
{ code: "en-IN", name: "English (India)", nativeName: "English", script: "Latin", stt: true, tts: true },
|
|
3
|
+
{ code: "hi-IN", name: "Hindi", nativeName: "हिन्दी", script: "Devanagari", stt: true, tts: true },
|
|
4
|
+
{ code: "bn-IN", name: "Bengali", nativeName: "বাংলা", script: "Bengali", stt: true, tts: true },
|
|
5
|
+
{ code: "ta-IN", name: "Tamil", nativeName: "தமிழ்", script: "Tamil", stt: true, tts: true },
|
|
6
|
+
{ code: "te-IN", name: "Telugu", nativeName: "తెలుగు", script: "Telugu", stt: true, tts: true },
|
|
7
|
+
{ code: "gu-IN", name: "Gujarati", nativeName: "ગુજરાતી", script: "Gujarati", stt: true, tts: true },
|
|
8
|
+
{ code: "kn-IN", name: "Kannada", nativeName: "ಕನ್ನಡ", script: "Kannada", stt: true, tts: true },
|
|
9
|
+
{ code: "ml-IN", name: "Malayalam", nativeName: "മലയാളം", script: "Malayalam", stt: true, tts: true },
|
|
10
|
+
{ code: "mr-IN", name: "Marathi", nativeName: "मराठी", script: "Devanagari", stt: true, tts: true },
|
|
11
|
+
{ code: "pa-IN", name: "Punjabi", nativeName: "ਪੰਜਾਬੀ", script: "Gurmukhi", stt: true, tts: true },
|
|
12
|
+
{ code: "od-IN", name: "Odia", nativeName: "ଓଡ଼ିଆ", script: "Odia", stt: true, tts: true },
|
|
13
|
+
{ code: "as-IN", name: "Assamese", nativeName: "অসমীয়া", script: "Bengali", stt: true, tts: false },
|
|
14
|
+
{ code: "ur-IN", name: "Urdu", nativeName: "اردو", script: "Perso-Arabic", stt: true, tts: false },
|
|
15
|
+
{ code: "ne-IN", name: "Nepali", nativeName: "नेपाली", script: "Devanagari", stt: true, tts: false },
|
|
16
|
+
{ code: "kok-IN", name: "Konkani", nativeName: "कोंकणी", script: "Devanagari", stt: true, tts: false },
|
|
17
|
+
{ code: "ks-IN", name: "Kashmiri", nativeName: "کٲشُر", script: "Perso-Arabic", stt: true, tts: false },
|
|
18
|
+
{ code: "sd-IN", name: "Sindhi", nativeName: "سنڌي", script: "Perso-Arabic", stt: true, tts: false },
|
|
19
|
+
{ code: "sa-IN", name: "Sanskrit", nativeName: "संस्कृतम्", script: "Devanagari", stt: true, tts: false },
|
|
20
|
+
{ code: "sat-IN", name: "Santali", nativeName: "ᱥᱟᱱᱛᱟᱲᱤ", script: "Ol Chiki", stt: true, tts: false },
|
|
21
|
+
{ code: "mni-IN", name: "Manipuri", nativeName: "ꯃꯤꯇꯩ ꯂꯣꯟ", script: "Meitei", stt: true, tts: false },
|
|
22
|
+
{ code: "brx-IN", name: "Bodo", nativeName: "बड़ो", script: "Devanagari", stt: true, tts: false },
|
|
23
|
+
{ code: "mai-IN", name: "Maithili", nativeName: "मैथिली", script: "Devanagari", stt: true, tts: false },
|
|
24
|
+
{ code: "doi-IN", name: "Dogri", nativeName: "डोगरी", script: "Devanagari", stt: true, tts: false },
|
|
25
|
+
];
|
|
26
|
+
export const DEFAULT_LANGUAGE = "en-IN";
|
|
27
|
+
export const SARVAM_STT_LANGUAGES = SARVAM_LANGUAGES.filter((lang) => lang.stt).map((lang) => lang.code);
|
|
28
|
+
export const SARVAM_TTS_LANGUAGES = SARVAM_LANGUAGES.filter((lang) => lang.tts).map((lang) => lang.code);
|
|
29
|
+
const LANGUAGE_BY_CODE = new Map(SARVAM_LANGUAGES.map((lang) => [lang.code, lang]));
|
|
30
|
+
const APP_LOCALE_ALIASES = {
|
|
31
|
+
en: "en-IN",
|
|
32
|
+
hi: "hi-IN",
|
|
33
|
+
bn: "bn-IN",
|
|
34
|
+
ta: "ta-IN",
|
|
35
|
+
te: "te-IN",
|
|
36
|
+
gu: "gu-IN",
|
|
37
|
+
kn: "kn-IN",
|
|
38
|
+
ml: "ml-IN",
|
|
39
|
+
mr: "mr-IN",
|
|
40
|
+
pa: "pa-IN",
|
|
41
|
+
or: "od-IN",
|
|
42
|
+
od: "od-IN",
|
|
43
|
+
as: "as-IN",
|
|
44
|
+
ur: "ur-IN",
|
|
45
|
+
ne: "ne-IN",
|
|
46
|
+
kok: "kok-IN",
|
|
47
|
+
ks: "ks-IN",
|
|
48
|
+
sd: "sd-IN",
|
|
49
|
+
sa: "sa-IN",
|
|
50
|
+
sat: "sat-IN",
|
|
51
|
+
mni: "mni-IN",
|
|
52
|
+
brx: "brx-IN",
|
|
53
|
+
mai: "mai-IN",
|
|
54
|
+
doi: "doi-IN",
|
|
55
|
+
};
|
|
56
|
+
export function isSttSupported(code) {
|
|
57
|
+
return LANGUAGE_BY_CODE.get(normalizeLanguageCode(code))?.stt ?? false;
|
|
58
|
+
}
|
|
59
|
+
export function isTtsSupported(code) {
|
|
60
|
+
return LANGUAGE_BY_CODE.get(normalizeLanguageCode(code))?.tts ?? false;
|
|
61
|
+
}
|
|
62
|
+
export function resolveTtsLanguage(code) {
|
|
63
|
+
const normalized = normalizeLanguageCode(code);
|
|
64
|
+
return LANGUAGE_BY_CODE.get(normalized)?.tts ? normalized : DEFAULT_LANGUAGE;
|
|
65
|
+
}
|
|
66
|
+
export function normalizeLanguageCode(input) {
|
|
67
|
+
if (!input) {
|
|
68
|
+
return DEFAULT_LANGUAGE;
|
|
69
|
+
}
|
|
70
|
+
const trimmed = input.trim();
|
|
71
|
+
if (!trimmed) {
|
|
72
|
+
return DEFAULT_LANGUAGE;
|
|
73
|
+
}
|
|
74
|
+
const lowered = trimmed.toLowerCase();
|
|
75
|
+
for (const lang of SARVAM_LANGUAGES) {
|
|
76
|
+
if (lang.code.toLowerCase() === lowered) {
|
|
77
|
+
return lang.code;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const baseLocale = lowered.split("-")[0];
|
|
81
|
+
const aliased = APP_LOCALE_ALIASES[lowered] ?? APP_LOCALE_ALIASES[baseLocale];
|
|
82
|
+
if (aliased) {
|
|
83
|
+
return aliased;
|
|
84
|
+
}
|
|
85
|
+
return DEFAULT_LANGUAGE;
|
|
86
|
+
}
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import * as sdk from "microsoft-cognitiveservices-speech-sdk";
|
|
2
|
-
import type { NavigationCallbacks, AgentActionResponse } from "./types.js";
|
|
2
|
+
import type { NavigationCallbacks, AgentActionResponse, SpeechProvider } from "./types.js";
|
|
3
3
|
import { AzureSpeechService } from "./services/azure-speech.js";
|
|
4
4
|
import { BedrockService } from "./services/bedrock.js";
|
|
5
|
+
import { SarvamSpeechService } from "./services/sarvam-speech.js";
|
|
5
6
|
interface MicrophoneConfig {
|
|
6
|
-
|
|
7
|
+
speechProvider?: SpeechProvider;
|
|
8
|
+
azureSpeechService?: AzureSpeechService;
|
|
9
|
+
sarvamSpeechService?: SarvamSpeechService;
|
|
7
10
|
bedrockService: BedrockService;
|
|
8
11
|
language?: string;
|
|
9
12
|
silenceTimeout?: number;
|
|
10
13
|
}
|
|
11
14
|
export declare class MicrophoneHandler {
|
|
15
|
+
private speechProvider;
|
|
12
16
|
private azureSpeechService;
|
|
17
|
+
private sarvamSpeechService;
|
|
13
18
|
private bedrockService;
|
|
14
19
|
private language;
|
|
15
20
|
private silenceTimeout;
|
|
@@ -50,6 +55,7 @@ export declare class MicrophoneHandler {
|
|
|
50
55
|
disposeRecognizer(): void;
|
|
51
56
|
createRecognizer(): Promise<sdk.SpeechRecognizer>;
|
|
52
57
|
startRecording(callbacks?: NavigationCallbacks): Promise<boolean>;
|
|
58
|
+
private startSarvamRecording;
|
|
53
59
|
stopRecording(): Promise<string>;
|
|
54
60
|
static isMicrophoneAvailable(): Promise<boolean>;
|
|
55
61
|
}
|