@bytexbyte/nxtlinq-ai-agent-sdk 1.6.16 → 1.6.18
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/dist/components/context/ChatBotContext.d.ts.map +1 -1
- package/dist/components/context/ChatBotContext.js +220 -9
- package/dist/components/types/ChatBotTypes.d.ts +4 -1
- package/dist/components/types/ChatBotTypes.d.ts.map +1 -1
- package/dist/components/ui/BerifyMeModal.d.ts +5 -0
- package/dist/components/ui/BerifyMeModal.d.ts.map +1 -1
- package/dist/components/ui/BerifyMeModal.js +7 -5
- package/dist/components/ui/MessageInput.d.ts.map +1 -1
- package/dist/components/ui/MessageInput.js +64 -42
- package/dist/core/lib/useSpeechToTextFromMic/helper.d.ts +3 -3
- package/dist/core/lib/useSpeechToTextFromMic/helper.d.ts.map +1 -1
- package/dist/core/lib/useSpeechToTextFromMic/helper.js +14 -12
- package/dist/core/lib/useSpeechToTextFromMic/index.d.ts +1 -1
- package/dist/core/lib/useSpeechToTextFromMic/index.d.ts.map +1 -1
- package/dist/core/lib/useSpeechToTextFromMic/index.js +28 -21
- package/package.json +1 -1
- package/umd/nxtlinq-ai-agent.umd.js +142 -134
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatBotContext.d.ts","sourceRoot":"","sources":["../../../src/components/context/ChatBotContext.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,EAEL,kBAAkB,EAClB,YAAY,EAEb,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"ChatBotContext.d.ts","sourceRoot":"","sources":["../../../src/components/context/ChatBotContext.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,EAEL,kBAAkB,EAClB,YAAY,EAEb,MAAM,uBAAuB,CAAC;AAM/B,eAAO,MAAM,UAAU,0BAMtB,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAwvElD,CAAC"}
|
|
@@ -9,6 +9,7 @@ import useSessionStorage from '../../core/lib/useSessionStorage';
|
|
|
9
9
|
import { useSpeechToTextFromMic } from '../../core/lib/useSpeechToTextFromMic';
|
|
10
10
|
import metakeepClient from '../../core/metakeepClient';
|
|
11
11
|
import { sleep } from '../../core/utils';
|
|
12
|
+
const MIC_ENABLED_SESSION_KEY = 'chatbot-mic-enabled';
|
|
12
13
|
const ChatBotContext = React.createContext(undefined);
|
|
13
14
|
export const useChatBot = () => {
|
|
14
15
|
const context = React.useContext(ChatBotContext);
|
|
@@ -36,7 +37,7 @@ isStopRecordingOnSend = false, }) => {
|
|
|
36
37
|
setApiHosts(environment);
|
|
37
38
|
const nxtlinqApi = React.useMemo(() => createNxtlinqApi(apiKey, apiSecret), [apiKey, apiSecret]);
|
|
38
39
|
// Custom hook
|
|
39
|
-
const {
|
|
40
|
+
const { isMicEnabled, transcript, partialTranscript, start: startRecording, stop: stopRecording, clear: clearRecording } = useSpeechToTextFromMic({
|
|
40
41
|
apiKey,
|
|
41
42
|
apiSecret
|
|
42
43
|
});
|
|
@@ -69,6 +70,8 @@ isStopRecordingOnSend = false, }) => {
|
|
|
69
70
|
? useSessionStorage('chatbot-suggestions', presetMessages)
|
|
70
71
|
: React.useState(presetMessages);
|
|
71
72
|
const [isAITEnabling, setIsAITEnabling] = React.useState(false);
|
|
73
|
+
const [isAwaitingMicGesture, setIsAwaitingMicGesture] = React.useState(false);
|
|
74
|
+
const [autoSendEnabled, setAutoSendEnabled] = useLocalStorage('chatbot-auto-send-enabled', true);
|
|
72
75
|
// Use refs to get latest state values in hasPermission function
|
|
73
76
|
const hitAddressRef = React.useRef(hitAddress);
|
|
74
77
|
const aitRef = React.useRef(ait);
|
|
@@ -76,9 +79,15 @@ isStopRecordingOnSend = false, }) => {
|
|
|
76
79
|
const nxtlinqAITServiceAccessTokenRef = React.useRef(nxtlinqAITServiceAccessToken);
|
|
77
80
|
const signerRef = React.useRef(signer);
|
|
78
81
|
// Refs for input value and recording state
|
|
79
|
-
const
|
|
82
|
+
const isMicEnabledRef = React.useRef(false);
|
|
83
|
+
const isRestoringRecordingRef = React.useRef(false);
|
|
84
|
+
const hasSyncedMicStateRef = React.useRef(false);
|
|
85
|
+
const isReacquiringMicRef = React.useRef(false);
|
|
86
|
+
const pendingMicAutoStartRef = React.useRef(false);
|
|
87
|
+
const autoStartGestureCleanupRef = React.useRef(null);
|
|
80
88
|
const textInputRef = React.useRef(null);
|
|
81
89
|
const lastPartialRangeRef = React.useRef(null);
|
|
90
|
+
const lastAutoSentTranscriptRef = React.useRef('');
|
|
82
91
|
function insertPartial(input, partial, caret) {
|
|
83
92
|
let start = caret;
|
|
84
93
|
let end = caret;
|
|
@@ -160,17 +169,214 @@ isStopRecordingOnSend = false, }) => {
|
|
|
160
169
|
if (!textInputRef.current)
|
|
161
170
|
return;
|
|
162
171
|
const { next, caret } = finalizePartial(inputValue, transcript);
|
|
163
|
-
|
|
172
|
+
const normalizedText = normalizeTranscript(next);
|
|
173
|
+
setInputValue(normalizedText);
|
|
164
174
|
setTimeout(() => {
|
|
165
175
|
if (textInputRef.current) {
|
|
166
176
|
textInputRef.current.selectionStart = caret;
|
|
167
177
|
textInputRef.current.selectionEnd = caret;
|
|
168
178
|
}
|
|
169
179
|
}, 0);
|
|
170
|
-
|
|
180
|
+
// Auto send on speech complete (if user enabled the toggle)
|
|
181
|
+
if (autoSendEnabled && isMicEnabled && normalizedText.trim()) {
|
|
182
|
+
// Avoid duplicate sends by checking if this transcript was already sent
|
|
183
|
+
if (lastAutoSentTranscriptRef.current !== normalizedText.trim()) {
|
|
184
|
+
lastAutoSentTranscriptRef.current = normalizedText.trim();
|
|
185
|
+
// Small delay to ensure input value is updated
|
|
186
|
+
setTimeout(() => {
|
|
187
|
+
if (normalizedText.trim() && !isLoading) {
|
|
188
|
+
sendMessage(normalizedText.trim()).catch(error => {
|
|
189
|
+
console.error('Failed to auto-send message from speech:', error);
|
|
190
|
+
// Reset the ref so user can try again
|
|
191
|
+
lastAutoSentTranscriptRef.current = '';
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}, 100);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
198
|
+
}, [transcript, autoSendEnabled, isMicEnabled, isLoading]);
|
|
199
|
+
React.useEffect(() => {
|
|
200
|
+
isMicEnabledRef.current = isMicEnabled;
|
|
201
|
+
// Reset auto-sent transcript ref when starting new recording
|
|
202
|
+
if (isMicEnabled) {
|
|
203
|
+
lastAutoSentTranscriptRef.current = '';
|
|
204
|
+
// Hide gesture prompt once mic is actually enabled
|
|
205
|
+
setIsAwaitingMicGesture(false);
|
|
206
|
+
// Remove any pending gesture listeners
|
|
207
|
+
if (autoStartGestureCleanupRef.current) {
|
|
208
|
+
autoStartGestureCleanupRef.current();
|
|
209
|
+
autoStartGestureCleanupRef.current = null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}, [isMicEnabled]);
|
|
213
|
+
React.useEffect(() => {
|
|
214
|
+
if (typeof window === 'undefined') {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (!useSessionStorageMode) {
|
|
218
|
+
sessionStorage.removeItem(MIC_ENABLED_SESSION_KEY);
|
|
219
|
+
hasSyncedMicStateRef.current = false;
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (!hasSyncedMicStateRef.current) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
sessionStorage.setItem(MIC_ENABLED_SESSION_KEY, JSON.stringify(isMicEnabled));
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
console.warn('Failed to persist recording state to sessionStorage:', error);
|
|
230
|
+
}
|
|
231
|
+
}, [isMicEnabled, useSessionStorageMode]);
|
|
171
232
|
React.useEffect(() => {
|
|
172
|
-
|
|
173
|
-
|
|
233
|
+
if (typeof window === 'undefined') {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const cleanupAutoStartListeners = () => {
|
|
237
|
+
if (autoStartGestureCleanupRef.current) {
|
|
238
|
+
autoStartGestureCleanupRef.current();
|
|
239
|
+
autoStartGestureCleanupRef.current = null;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
if (!useSessionStorageMode) {
|
|
243
|
+
cleanupAutoStartListeners();
|
|
244
|
+
pendingMicAutoStartRef.current = false;
|
|
245
|
+
setIsAwaitingMicGesture(false);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (hasSyncedMicStateRef.current || isReacquiringMicRef.current) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const rawStoredValue = sessionStorage.getItem(MIC_ENABLED_SESSION_KEY);
|
|
252
|
+
const shouldRestore = rawStoredValue === 'true';
|
|
253
|
+
if (!shouldRestore || isMicEnabledRef.current || isRestoringRecordingRef.current) {
|
|
254
|
+
hasSyncedMicStateRef.current = true;
|
|
255
|
+
setIsAwaitingMicGesture(false);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
pendingMicAutoStartRef.current = true;
|
|
259
|
+
function scheduleRetryOnUserGesture() {
|
|
260
|
+
if (autoStartGestureCleanupRef.current)
|
|
261
|
+
return;
|
|
262
|
+
setIsAwaitingMicGesture(true);
|
|
263
|
+
const events = ['pointerdown', 'keydown', 'touchstart'];
|
|
264
|
+
const handler = async () => {
|
|
265
|
+
cleanupAutoStartListeners();
|
|
266
|
+
await attemptAutoStart('user-gesture');
|
|
267
|
+
};
|
|
268
|
+
events.forEach(event => window.addEventListener(event, handler, { once: true }));
|
|
269
|
+
autoStartGestureCleanupRef.current = () => {
|
|
270
|
+
events.forEach(event => window.removeEventListener(event, handler));
|
|
271
|
+
autoStartGestureCleanupRef.current = null;
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
async function attemptAutoStart(reason) {
|
|
275
|
+
isReacquiringMicRef.current = true;
|
|
276
|
+
// For initial restore, show gesture prompt immediately while checking
|
|
277
|
+
// This gives user early feedback and allows them to click anytime
|
|
278
|
+
if (reason === 'initial') {
|
|
279
|
+
scheduleRetryOnUserGesture();
|
|
280
|
+
}
|
|
281
|
+
if (typeof navigator !== 'undefined' && navigator.mediaDevices?.getUserMedia) {
|
|
282
|
+
try {
|
|
283
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
284
|
+
stream.getTracks().forEach(track => track.stop());
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
console.error('Failed to reacquire microphone stream:', error);
|
|
288
|
+
const errorName = error?.name || '';
|
|
289
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
290
|
+
if (reason === 'initial') {
|
|
291
|
+
const isPermissionPermanentlyDenied = errorName === 'NotAllowedError' &&
|
|
292
|
+
/permission.*denied|blocked|not.*granted/i.test(errorMessage);
|
|
293
|
+
if (isPermissionPermanentlyDenied) {
|
|
294
|
+
// Permission permanently denied, hide the prompt
|
|
295
|
+
pendingMicAutoStartRef.current = false;
|
|
296
|
+
setIsAwaitingMicGesture(false);
|
|
297
|
+
try {
|
|
298
|
+
sessionStorage.setItem(MIC_ENABLED_SESSION_KEY, JSON.stringify(false));
|
|
299
|
+
}
|
|
300
|
+
catch (storageError) {
|
|
301
|
+
console.warn('Failed to reset recording state in sessionStorage:', storageError);
|
|
302
|
+
}
|
|
303
|
+
cleanupAutoStartListeners();
|
|
304
|
+
}
|
|
305
|
+
// Otherwise, keep the prompt showing (already shown above)
|
|
306
|
+
isReacquiringMicRef.current = false;
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
// For user-gesture retry, treat as error
|
|
310
|
+
pendingMicAutoStartRef.current = false;
|
|
311
|
+
setIsAwaitingMicGesture(false);
|
|
312
|
+
try {
|
|
313
|
+
sessionStorage.setItem(MIC_ENABLED_SESSION_KEY, JSON.stringify(false));
|
|
314
|
+
}
|
|
315
|
+
catch (storageError) {
|
|
316
|
+
console.warn('Failed to reset recording state in sessionStorage:', storageError);
|
|
317
|
+
}
|
|
318
|
+
isReacquiringMicRef.current = false;
|
|
319
|
+
hasSyncedMicStateRef.current = true;
|
|
320
|
+
cleanupAutoStartListeners();
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
else if (reason === 'initial') {
|
|
325
|
+
// getUserMedia not available, prompt already shown above
|
|
326
|
+
isReacquiringMicRef.current = false;
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
isRestoringRecordingRef.current = true;
|
|
330
|
+
// Intercept console.warn to detect AudioContext warnings
|
|
331
|
+
let audioContextWarningDetected = false;
|
|
332
|
+
const originalWarn = console.warn;
|
|
333
|
+
console.warn = (...args) => {
|
|
334
|
+
const message = args.join(' ');
|
|
335
|
+
if (message.includes('AudioContext was not allowed to start')) {
|
|
336
|
+
audioContextWarningDetected = true;
|
|
337
|
+
}
|
|
338
|
+
originalWarn.apply(console, args);
|
|
339
|
+
};
|
|
340
|
+
try {
|
|
341
|
+
await startRecording();
|
|
342
|
+
console.warn = originalWarn;
|
|
343
|
+
// Check mic status after a short delay
|
|
344
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
345
|
+
// If mic started successfully, hide the prompt
|
|
346
|
+
if (isMicEnabledRef.current) {
|
|
347
|
+
pendingMicAutoStartRef.current = false;
|
|
348
|
+
setIsAwaitingMicGesture(false);
|
|
349
|
+
cleanupAutoStartListeners();
|
|
350
|
+
}
|
|
351
|
+
else if (reason === 'initial') {
|
|
352
|
+
// Mic didn't start, keep the prompt showing (already shown earlier)
|
|
353
|
+
isRestoringRecordingRef.current = false;
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
console.error('startRecording threw an error:', error);
|
|
359
|
+
try {
|
|
360
|
+
sessionStorage.setItem(MIC_ENABLED_SESSION_KEY, JSON.stringify(false));
|
|
361
|
+
}
|
|
362
|
+
catch (storageError) {
|
|
363
|
+
console.warn('Failed to reset recording state in sessionStorage:', storageError);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
finally {
|
|
367
|
+
console.warn = originalWarn;
|
|
368
|
+
isRestoringRecordingRef.current = false;
|
|
369
|
+
isReacquiringMicRef.current = false;
|
|
370
|
+
hasSyncedMicStateRef.current = true;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
attemptAutoStart('initial');
|
|
374
|
+
return () => {
|
|
375
|
+
cleanupAutoStartListeners();
|
|
376
|
+
pendingMicAutoStartRef.current = false;
|
|
377
|
+
setIsAwaitingMicGesture(false);
|
|
378
|
+
};
|
|
379
|
+
}, [useSessionStorageMode, startRecording]);
|
|
174
380
|
const [notification, setNotification] = React.useState({
|
|
175
381
|
show: false,
|
|
176
382
|
type: 'info',
|
|
@@ -1282,15 +1488,17 @@ isStopRecordingOnSend = false, }) => {
|
|
|
1282
1488
|
const handleSubmit = async (e) => {
|
|
1283
1489
|
e.preventDefault();
|
|
1284
1490
|
if (isStopRecordingOnSend) {
|
|
1285
|
-
while (
|
|
1491
|
+
while (isMicEnabledRef.current) {
|
|
1286
1492
|
stopRecording();
|
|
1287
1493
|
await sleep(1000);
|
|
1288
1494
|
}
|
|
1289
1495
|
}
|
|
1290
1496
|
else {
|
|
1291
|
-
if (
|
|
1497
|
+
if (isMicEnabledRef.current) {
|
|
1292
1498
|
await sleep(1000);
|
|
1293
1499
|
clearRecording();
|
|
1500
|
+
// Reset auto-sent transcript ref when clearing recording
|
|
1501
|
+
lastAutoSentTranscriptRef.current = '';
|
|
1294
1502
|
}
|
|
1295
1503
|
}
|
|
1296
1504
|
if (!textInputRef.current)
|
|
@@ -1816,9 +2024,11 @@ isStopRecordingOnSend = false, }) => {
|
|
|
1816
2024
|
isWalletLoading,
|
|
1817
2025
|
isAutoConnecting,
|
|
1818
2026
|
notification,
|
|
1819
|
-
|
|
2027
|
+
isMicEnabled,
|
|
2028
|
+
isAwaitingMicGesture,
|
|
1820
2029
|
transcript,
|
|
1821
2030
|
textInputRef,
|
|
2031
|
+
autoSendEnabled,
|
|
1822
2032
|
// AI Model related state
|
|
1823
2033
|
availableModels: effectiveAvailableModels,
|
|
1824
2034
|
selectedModelIndex,
|
|
@@ -1837,6 +2047,7 @@ isStopRecordingOnSend = false, }) => {
|
|
|
1837
2047
|
// AI Model related actions
|
|
1838
2048
|
setSelectedModelIndex,
|
|
1839
2049
|
setSuggestions,
|
|
2050
|
+
setAutoSendEnabled,
|
|
1840
2051
|
// Functions
|
|
1841
2052
|
connectWallet,
|
|
1842
2053
|
signInWallet,
|
|
@@ -81,9 +81,11 @@ export interface ChatBotContextType {
|
|
|
81
81
|
autoHide?: boolean;
|
|
82
82
|
duration?: number;
|
|
83
83
|
};
|
|
84
|
-
|
|
84
|
+
isMicEnabled: boolean;
|
|
85
|
+
isAwaitingMicGesture: boolean;
|
|
85
86
|
transcript: string;
|
|
86
87
|
textInputRef: React.RefObject<HTMLInputElement>;
|
|
88
|
+
autoSendEnabled: boolean;
|
|
87
89
|
availableModels: AIModel[];
|
|
88
90
|
selectedModelIndex: number;
|
|
89
91
|
showModelSelector: boolean;
|
|
@@ -98,6 +100,7 @@ export interface ChatBotContextType {
|
|
|
98
100
|
setNotification: (notification: any) => void;
|
|
99
101
|
setSelectedModelIndex: (index: number) => void;
|
|
100
102
|
setSuggestions: (suggestions: PresetMessage[]) => void;
|
|
103
|
+
setAutoSendEnabled: (enabled: boolean) => void;
|
|
101
104
|
connectWallet: (autoShowSignInMessage?: boolean) => Promise<string | false | undefined>;
|
|
102
105
|
signInWallet: (autoShowSuccessMessage?: boolean) => Promise<void>;
|
|
103
106
|
sendMessage: (content: string, retryCount?: number) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatBotTypes.d.ts","sourceRoot":"","sources":["../../../src/components/types/ChatBotTypes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE9E,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"ChatBotTypes.d.ts","sourceRoot":"","sources":["../../../src/components/types/ChatBotTypes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @jsxImportSource @emotion/react */
|
|
1
2
|
import React from 'react';
|
|
2
3
|
interface BerifyMeModalProps {
|
|
3
4
|
isOpen: boolean;
|
|
@@ -10,6 +11,10 @@ declare global {
|
|
|
10
11
|
interface Window {
|
|
11
12
|
BerifyMeSDK?: {
|
|
12
13
|
modal: any;
|
|
14
|
+
environment: {
|
|
15
|
+
Staging: any;
|
|
16
|
+
Production: any;
|
|
17
|
+
};
|
|
13
18
|
};
|
|
14
19
|
}
|
|
15
20
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BerifyMeModal.d.ts","sourceRoot":"","sources":["../../../src/components/ui/BerifyMeModal.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BerifyMeModal.d.ts","sourceRoot":"","sources":["../../../src/components/ui/BerifyMeModal.tsx"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,KAA4B,MAAM,OAAO,CAAC;AAIjD,UAAU,kBAAkB;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,sBAAsB,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,IAAI,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CAChC;AASD,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAsHtD,CAAC;AAGF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,WAAW,CAAC,EAAE;YACZ,KAAK,EAAE,GAAG,CAAC;YACX,WAAW,EAAE;gBACX,OAAO,EAAE,GAAG,CAAC;gBACb,UAAU,EAAE,GAAG,CAAC;aACjB,CAAC;SACH,CAAC;KACH;CACF"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "@emotion/react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
|
-
import { css } from '@emotion/react';
|
|
4
3
|
import React, { useEffect, useRef } from 'react';
|
|
4
|
+
import { css } from '@emotion/react';
|
|
5
5
|
import { modalOverlay } from './styles/isolatedStyles';
|
|
6
6
|
// Built-in BerifyMe configuration
|
|
7
7
|
const BUILT_IN_BERIFYME_CONFIG = {
|
|
8
|
-
apiKeyId: '
|
|
9
|
-
secretKey: '
|
|
10
|
-
environment: '
|
|
8
|
+
apiKeyId: 'staging_83dc824cb50b4e76747e352b4228f2ee',
|
|
9
|
+
secretKey: 'ee96158a-9ae2-42ad-8c30-f7b23edbf258',
|
|
10
|
+
environment: 'staging'
|
|
11
11
|
};
|
|
12
12
|
export const BerifyMeModal = ({ isOpen, onClose, onVerificationComplete, mode = 'built-in' }) => {
|
|
13
13
|
const modalRef = useRef(null);
|
|
@@ -71,12 +71,14 @@ export const BerifyMeModal = ({ isOpen, onClose, onVerificationComplete, mode =
|
|
|
71
71
|
const redirectUrl = `${window.location.origin}${window.location.pathname}?isAutoConnect=true&method=berifyme&returnUrl=${encodeURIComponent(currentUrl)}`;
|
|
72
72
|
// Create BerifyMe modal using built-in config
|
|
73
73
|
const berifyMeModal = window.BerifyMeSDK.modal;
|
|
74
|
+
// Always use staging environment for now
|
|
75
|
+
const environment = window.BerifyMeSDK.environment.Staging;
|
|
74
76
|
// Use React 18's createRoot
|
|
75
77
|
const { createRoot } = require('react-dom/client');
|
|
76
78
|
const root = createRoot(modalRef.current);
|
|
77
79
|
berifyMeModalRef.current = root;
|
|
78
80
|
root.render(React.createElement(berifyMeModal, {
|
|
79
|
-
environment
|
|
81
|
+
environment,
|
|
80
82
|
apiKeyId: BUILT_IN_BERIFYME_CONFIG.apiKeyId,
|
|
81
83
|
secretKey: BUILT_IN_BERIFYME_CONFIG.secretKey,
|
|
82
84
|
redirectUrl,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageInput.d.ts","sourceRoot":"","sources":["../../../src/components/ui/MessageInput.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MessageInput.d.ts","sourceRoot":"","sources":["../../../src/components/ui/MessageInput.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAwKhC,CAAC"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
|
|
2
2
|
/** @jsxImportSource @emotion/react */
|
|
3
3
|
import { css } from '@emotion/react';
|
|
4
4
|
import MicIcon from '@mui/icons-material/Mic';
|
|
5
5
|
import MicOffIcon from '@mui/icons-material/MicOff';
|
|
6
|
-
import
|
|
6
|
+
import SendIcon from '@mui/icons-material/Send';
|
|
7
|
+
import { IconButton, InputBase, Tooltip } from '@mui/material';
|
|
7
8
|
import { useChatBot } from '../context/ChatBotContext';
|
|
8
9
|
import { actionButton } from './styles/isolatedStyles';
|
|
9
10
|
export const MessageInput = () => {
|
|
10
|
-
const { inputValue, setInputValue, isLoading, isAITLoading, handleSubmit,
|
|
11
|
+
const { inputValue, setInputValue, isLoading, isAITLoading, handleSubmit, isMicEnabled, isAwaitingMicGesture, startRecording, stopRecording, textInputRef, autoSendEnabled, setAutoSendEnabled, props: { placeholder = 'Type a message...' } } = useChatBot();
|
|
11
12
|
const isDisabled = isLoading || isAITLoading;
|
|
12
13
|
const inputPlaceholder = isAITLoading ? 'Loading wallet configuration...' : placeholder;
|
|
13
14
|
const handleKeyPress = (e) => {
|
|
@@ -16,47 +17,68 @@ export const MessageInput = () => {
|
|
|
16
17
|
handleSubmit(e);
|
|
17
18
|
}
|
|
18
19
|
};
|
|
19
|
-
return (_jsxs("div", { css: css `
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
height: 40px !important;
|
|
36
|
-
box-sizing: border-box !important;
|
|
37
|
-
` }), _jsxs("button", { onClick: (e) => handleSubmit(e), disabled: isDisabled || !inputValue.trim(), css: css `
|
|
38
|
-
${actionButton}
|
|
39
|
-
padding: 10px 20px !important;
|
|
40
|
-
border-radius: 20px !important;
|
|
41
|
-
position: relative !important;
|
|
20
|
+
return (_jsxs(_Fragment, { children: [isAwaitingMicGesture && (_jsx("div", { role: "status", "aria-live": "polite", css: css `
|
|
21
|
+
margin: 12px 15px 0 !important;
|
|
22
|
+
padding: 10px 14px !important;
|
|
23
|
+
border-radius: 8px !important;
|
|
24
|
+
border: 1px solid #ffeeba !important;
|
|
25
|
+
background-color: #fff3cd !important;
|
|
26
|
+
color: #856404 !important;
|
|
27
|
+
font-size: 13px !important;
|
|
28
|
+
line-height: 1.4 !important;
|
|
29
|
+
z-index: 1000 !important;
|
|
30
|
+
position: relative !important;
|
|
31
|
+
display: block !important;
|
|
32
|
+
visibility: visible !important;
|
|
33
|
+
opacity: 1 !important;
|
|
34
|
+
`, children: "\u26A0\uFE0F The microphone needs a user interaction to re-enable. Please click on the page or press any key." })), _jsxs("div", { css: css `
|
|
35
|
+
padding: 15px !important;
|
|
42
36
|
display: flex !important;
|
|
43
37
|
align-items: center !important;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
38
|
+
gap: 10px !important;
|
|
39
|
+
border-top: 1px solid #eee !important;
|
|
40
|
+
`, children: [_jsx(InputBase, { value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyPress: handleKeyPress, placeholder: inputPlaceholder, fullWidth: true, inputProps: {
|
|
41
|
+
ref: textInputRef
|
|
42
|
+
}, endAdornment: _jsxs(_Fragment, { children: [isMicEnabled && (_jsx(Tooltip, { title: autoSendEnabled ? 'Auto send enabled' : 'Auto send disabled', children: _jsx(IconButton, { size: "small", onClick: (e) => {
|
|
43
|
+
e.stopPropagation();
|
|
44
|
+
setAutoSendEnabled(!autoSendEnabled);
|
|
45
|
+
}, css: css `
|
|
46
|
+
padding: 4px !important;
|
|
47
|
+
margin-right: 4px !important;
|
|
48
|
+
color: ${autoSendEnabled ? '#1976d2' : '#9e9e9e'} !important;
|
|
49
|
+
`, children: _jsx(SendIcon, { fontSize: "small" }) }) })), _jsx(IconButton, { onClick: () => (isMicEnabled ? stopRecording() : startRecording()), children: isMicEnabled ? _jsx(MicIcon, {}) : _jsx(MicOffIcon, {}) })] }), css: css `
|
|
50
|
+
flex: 1 !important;
|
|
51
|
+
padding: 10px !important;
|
|
52
|
+
border: 1px solid #ddd !important;
|
|
53
|
+
border-radius: 20px !important;
|
|
54
|
+
outline: none !important;
|
|
55
|
+
font-size: 14px !important;
|
|
56
|
+
background-color: #fff !important;
|
|
57
|
+
height: 40px !important;
|
|
58
|
+
box-sizing: border-box !important;
|
|
59
|
+
` }), _jsxs("button", { onClick: (e) => handleSubmit(e), disabled: isDisabled || !inputValue.trim(), css: css `
|
|
60
|
+
${actionButton}
|
|
61
|
+
padding: 10px 20px !important;
|
|
62
|
+
border-radius: 20px !important;
|
|
63
|
+
position: relative !important;
|
|
59
64
|
display: flex !important;
|
|
60
65
|
align-items: center !important;
|
|
61
|
-
|
|
66
|
+
justify-content: center !important;
|
|
67
|
+
height: 40px !important;
|
|
68
|
+
box-sizing: border-box !important;
|
|
69
|
+
|
|
70
|
+
&:disabled {
|
|
71
|
+
background-color: #e9ecef !important;
|
|
72
|
+
color: #6c757d !important;
|
|
73
|
+
cursor: not-allowed !important;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
&:hover:not(:disabled) {
|
|
77
|
+
background-color: #0056b3 !important;
|
|
78
|
+
}
|
|
79
|
+
`, children: ["Send", (isLoading || isAITLoading) && (_jsx("span", { css: css `
|
|
80
|
+
margin-left: 8px !important;
|
|
81
|
+
display: flex !important;
|
|
82
|
+
align-items: center !important;
|
|
83
|
+
`, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 50 50", children: _jsx("circle", { cx: "25", cy: "25", r: "20", fill: "none", stroke: "#fff", strokeWidth: "4", strokeDasharray: "31.4 31.4", strokeLinecap: "round", children: _jsx("animateTransform", { attributeName: "transform", type: "rotate", from: "0 25 25", to: "360 25 25", dur: "1s", repeatCount: "indefinite" }) }) }) }))] })] })] }));
|
|
62
84
|
};
|
|
@@ -2,10 +2,10 @@ import { SpeechRecognizer } from 'microsoft-cognitiveservices-speech-sdk';
|
|
|
2
2
|
import { Dispatch, SetStateAction } from 'react';
|
|
3
3
|
/**
|
|
4
4
|
* Start speech recognition
|
|
5
|
-
* - partialTranscript:
|
|
6
|
-
* - setSpeechToTextArray:
|
|
5
|
+
* - partialTranscript: temporary partial transcription (recognizing)
|
|
6
|
+
* - setSpeechToTextArray: finalized sentence array (recognized)
|
|
7
7
|
*/
|
|
8
|
-
export declare const startSpeechToTextFromMic: (setSpeechToTextArray: Dispatch<SetStateAction<string[]>>, //
|
|
8
|
+
export declare const startSpeechToTextFromMic: (setSpeechToTextArray: Dispatch<SetStateAction<string[]>>, // finalized sentences
|
|
9
9
|
config: {
|
|
10
10
|
apiKey: string;
|
|
11
11
|
apiSecret: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../../../src/core/lib/useSpeechToTextFromMic/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,gBAAgB,EACjB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAIjD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACnC,sBAAsB,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,EAAI,
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../../../../src/core/lib/useSpeechToTextFromMic/helper.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,gBAAgB,EACjB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,OAAO,CAAC;AAIjD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,GACnC,sBAAsB,QAAQ,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,EAAI,sBAAsB;AAClF,QAAQ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAC7C,YAAY,KAAK,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,EAC5C,UAAU,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,EACxC,uBAAuB,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,KACtD,OAAO,CAAC,gBAAgB,GAAG,SAAS,CA2DtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,YAAY,gBAAgB,GAAG,SAAS,SAIvE,CAAC;AAEF,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM;;;;;;;;GAwBxE"}
|
|
@@ -3,11 +3,11 @@ import Cookie from 'universal-cookie';
|
|
|
3
3
|
import { createNxtlinqApi } from '../../../api/nxtlinq-api';
|
|
4
4
|
/**
|
|
5
5
|
* Start speech recognition
|
|
6
|
-
* - partialTranscript:
|
|
7
|
-
* - setSpeechToTextArray:
|
|
6
|
+
* - partialTranscript: temporary partial transcription (recognizing)
|
|
7
|
+
* - setSpeechToTextArray: finalized sentence array (recognized)
|
|
8
8
|
*/
|
|
9
|
-
export const startSpeechToTextFromMic = async (setSpeechToTextArray, //
|
|
10
|
-
config, historyRef, indexRef, setPartialTranscript //
|
|
9
|
+
export const startSpeechToTextFromMic = async (setSpeechToTextArray, // finalized sentences
|
|
10
|
+
config, historyRef, indexRef, setPartialTranscript // temporary partial transcription state updater
|
|
11
11
|
) => {
|
|
12
12
|
const tokenRes = await getTokenOrRefresh(config.apiKey, config.apiSecret);
|
|
13
13
|
if (!tokenRes.authToken || !tokenRes.region) {
|
|
@@ -16,25 +16,25 @@ config, historyRef, indexRef, setPartialTranscript // ✅ 新增:暫存逐字
|
|
|
16
16
|
}
|
|
17
17
|
const speechConfig = SpeechConfig.fromAuthorizationToken(tokenRes.authToken, tokenRes.region);
|
|
18
18
|
speechConfig.speechRecognitionLanguage = 'en-US';
|
|
19
|
-
//
|
|
19
|
+
// silence detection and segmentation configuration
|
|
20
20
|
speechConfig.setProperty(PropertyId.SpeechServiceConnection_InitialSilenceTimeoutMs, '10000');
|
|
21
21
|
speechConfig.setProperty(PropertyId.SpeechServiceConnection_EndSilenceTimeoutMs, '86400000');
|
|
22
22
|
speechConfig.setProperty(PropertyId.Speech_SegmentationSilenceTimeoutMs, '1000');
|
|
23
23
|
const audioConfig = AudioConfig.fromDefaultMicrophoneInput();
|
|
24
24
|
const recognizer = new SpeechRecognizer(speechConfig, audioConfig);
|
|
25
|
-
//
|
|
25
|
+
// temporary partial transcription
|
|
26
26
|
recognizer.recognizing = (_s, e) => {
|
|
27
27
|
if (setPartialTranscript) {
|
|
28
28
|
setPartialTranscript(e.result.text);
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
|
-
//
|
|
31
|
+
// finalized sentences
|
|
32
32
|
recognizer.recognized = (_s, e) => {
|
|
33
33
|
if (e.result.reason === ResultReason.RecognizedSpeech) {
|
|
34
34
|
const text = e.result.text;
|
|
35
35
|
historyRef.current[indexRef.current] = text;
|
|
36
36
|
indexRef.current += 1;
|
|
37
|
-
//
|
|
37
|
+
// return only the latest finalized sentence to the UI
|
|
38
38
|
setSpeechToTextArray([text]);
|
|
39
39
|
if (setPartialTranscript)
|
|
40
40
|
setPartialTranscript('');
|
|
@@ -47,10 +47,12 @@ config, historyRef, indexRef, setPartialTranscript // ✅ 新增:暫存逐字
|
|
|
47
47
|
console.error(`Error details: ${e.errorDetails}`);
|
|
48
48
|
}
|
|
49
49
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
await new Promise((resolve, reject) => {
|
|
51
|
+
recognizer.startContinuousRecognitionAsync(() => resolve(), error => {
|
|
52
|
+
console.error('Failed to start continuous speech recognition:', error);
|
|
53
|
+
reject(error);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
54
56
|
return recognizer;
|
|
55
57
|
};
|
|
56
58
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/lib/useSpeechToTextFromMic/index.ts"],"names":[],"mappings":"AAIA,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,KAAK,4BAA4B,GAAG;IAClC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/lib/useSpeechToTextFromMic/index.ts"],"names":[],"mappings":"AAIA,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,KAAK,4BAA4B,GAAG;IAClC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,EACN,SAAS,EACT,mBAA0B,GAC3B,EAAE,KAAK,GAAG,4BAA4B,CA4EtC"}
|