@bytexbyte/nxtlinq-ai-agent-sdk 1.6.16 → 1.6.17
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 +217 -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,CAovElD,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] = React.useState(false);
|
|
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,211 @@ 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
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
// Reset auto send when mic is disabled
|
|
207
|
+
setAutoSendEnabled(false);
|
|
208
|
+
}
|
|
209
|
+
}, [isMicEnabled]);
|
|
171
210
|
React.useEffect(() => {
|
|
172
|
-
|
|
173
|
-
|
|
211
|
+
if (typeof window === 'undefined') {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (!useSessionStorageMode) {
|
|
215
|
+
sessionStorage.removeItem(MIC_ENABLED_SESSION_KEY);
|
|
216
|
+
hasSyncedMicStateRef.current = false;
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
if (!hasSyncedMicStateRef.current) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
sessionStorage.setItem(MIC_ENABLED_SESSION_KEY, JSON.stringify(isMicEnabled));
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
console.warn('Failed to persist recording state to sessionStorage:', error);
|
|
227
|
+
}
|
|
228
|
+
}, [isMicEnabled, useSessionStorageMode]);
|
|
229
|
+
React.useEffect(() => {
|
|
230
|
+
if (typeof window === 'undefined') {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const cleanupAutoStartListeners = () => {
|
|
234
|
+
if (autoStartGestureCleanupRef.current) {
|
|
235
|
+
autoStartGestureCleanupRef.current();
|
|
236
|
+
autoStartGestureCleanupRef.current = null;
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
if (!useSessionStorageMode) {
|
|
240
|
+
cleanupAutoStartListeners();
|
|
241
|
+
pendingMicAutoStartRef.current = false;
|
|
242
|
+
setIsAwaitingMicGesture(false);
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (hasSyncedMicStateRef.current || isReacquiringMicRef.current) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const rawStoredValue = sessionStorage.getItem(MIC_ENABLED_SESSION_KEY);
|
|
249
|
+
const shouldRestore = rawStoredValue === 'true';
|
|
250
|
+
if (!shouldRestore || isMicEnabledRef.current || isRestoringRecordingRef.current) {
|
|
251
|
+
hasSyncedMicStateRef.current = true;
|
|
252
|
+
setIsAwaitingMicGesture(false);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
pendingMicAutoStartRef.current = true;
|
|
256
|
+
function scheduleRetryOnUserGesture() {
|
|
257
|
+
if (autoStartGestureCleanupRef.current)
|
|
258
|
+
return;
|
|
259
|
+
setIsAwaitingMicGesture(true);
|
|
260
|
+
const events = ['pointerdown', 'keydown', 'touchstart'];
|
|
261
|
+
const handler = async () => {
|
|
262
|
+
cleanupAutoStartListeners();
|
|
263
|
+
await attemptAutoStart('user-gesture');
|
|
264
|
+
};
|
|
265
|
+
events.forEach(event => window.addEventListener(event, handler, { once: true }));
|
|
266
|
+
autoStartGestureCleanupRef.current = () => {
|
|
267
|
+
events.forEach(event => window.removeEventListener(event, handler));
|
|
268
|
+
autoStartGestureCleanupRef.current = null;
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
async function attemptAutoStart(reason) {
|
|
272
|
+
isReacquiringMicRef.current = true;
|
|
273
|
+
// For initial restore, show gesture prompt immediately while checking
|
|
274
|
+
// This gives user early feedback and allows them to click anytime
|
|
275
|
+
if (reason === 'initial') {
|
|
276
|
+
scheduleRetryOnUserGesture();
|
|
277
|
+
}
|
|
278
|
+
if (typeof navigator !== 'undefined' && navigator.mediaDevices?.getUserMedia) {
|
|
279
|
+
try {
|
|
280
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
281
|
+
stream.getTracks().forEach(track => track.stop());
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
console.error('Failed to reacquire microphone stream:', error);
|
|
285
|
+
const errorName = error?.name || '';
|
|
286
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
287
|
+
if (reason === 'initial') {
|
|
288
|
+
const isPermissionPermanentlyDenied = errorName === 'NotAllowedError' &&
|
|
289
|
+
/permission.*denied|blocked|not.*granted/i.test(errorMessage);
|
|
290
|
+
if (isPermissionPermanentlyDenied) {
|
|
291
|
+
// Permission permanently denied, hide the prompt
|
|
292
|
+
pendingMicAutoStartRef.current = false;
|
|
293
|
+
setIsAwaitingMicGesture(false);
|
|
294
|
+
try {
|
|
295
|
+
sessionStorage.setItem(MIC_ENABLED_SESSION_KEY, JSON.stringify(false));
|
|
296
|
+
}
|
|
297
|
+
catch (storageError) {
|
|
298
|
+
console.warn('Failed to reset recording state in sessionStorage:', storageError);
|
|
299
|
+
}
|
|
300
|
+
cleanupAutoStartListeners();
|
|
301
|
+
}
|
|
302
|
+
// Otherwise, keep the prompt showing (already shown above)
|
|
303
|
+
isReacquiringMicRef.current = false;
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
// For user-gesture retry, treat as error
|
|
307
|
+
pendingMicAutoStartRef.current = false;
|
|
308
|
+
setIsAwaitingMicGesture(false);
|
|
309
|
+
try {
|
|
310
|
+
sessionStorage.setItem(MIC_ENABLED_SESSION_KEY, JSON.stringify(false));
|
|
311
|
+
}
|
|
312
|
+
catch (storageError) {
|
|
313
|
+
console.warn('Failed to reset recording state in sessionStorage:', storageError);
|
|
314
|
+
}
|
|
315
|
+
isReacquiringMicRef.current = false;
|
|
316
|
+
hasSyncedMicStateRef.current = true;
|
|
317
|
+
cleanupAutoStartListeners();
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
else if (reason === 'initial') {
|
|
322
|
+
// getUserMedia not available, prompt already shown above
|
|
323
|
+
isReacquiringMicRef.current = false;
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
isRestoringRecordingRef.current = true;
|
|
327
|
+
// Intercept console.warn to detect AudioContext warnings
|
|
328
|
+
let audioContextWarningDetected = false;
|
|
329
|
+
const originalWarn = console.warn;
|
|
330
|
+
console.warn = (...args) => {
|
|
331
|
+
const message = args.join(' ');
|
|
332
|
+
if (message.includes('AudioContext was not allowed to start')) {
|
|
333
|
+
audioContextWarningDetected = true;
|
|
334
|
+
}
|
|
335
|
+
originalWarn.apply(console, args);
|
|
336
|
+
};
|
|
337
|
+
try {
|
|
338
|
+
await startRecording();
|
|
339
|
+
console.warn = originalWarn;
|
|
340
|
+
// Check mic status after a short delay
|
|
341
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
342
|
+
// If mic started successfully, hide the prompt
|
|
343
|
+
if (isMicEnabled) {
|
|
344
|
+
pendingMicAutoStartRef.current = false;
|
|
345
|
+
setIsAwaitingMicGesture(false);
|
|
346
|
+
cleanupAutoStartListeners();
|
|
347
|
+
}
|
|
348
|
+
else if (reason === 'initial') {
|
|
349
|
+
// Mic didn't start, keep the prompt showing (already shown earlier)
|
|
350
|
+
isRestoringRecordingRef.current = false;
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
console.error('startRecording threw an error:', error);
|
|
356
|
+
try {
|
|
357
|
+
sessionStorage.setItem(MIC_ENABLED_SESSION_KEY, JSON.stringify(false));
|
|
358
|
+
}
|
|
359
|
+
catch (storageError) {
|
|
360
|
+
console.warn('Failed to reset recording state in sessionStorage:', storageError);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
finally {
|
|
364
|
+
console.warn = originalWarn;
|
|
365
|
+
isRestoringRecordingRef.current = false;
|
|
366
|
+
isReacquiringMicRef.current = false;
|
|
367
|
+
hasSyncedMicStateRef.current = true;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
attemptAutoStart('initial');
|
|
371
|
+
return () => {
|
|
372
|
+
cleanupAutoStartListeners();
|
|
373
|
+
pendingMicAutoStartRef.current = false;
|
|
374
|
+
setIsAwaitingMicGesture(false);
|
|
375
|
+
};
|
|
376
|
+
}, [useSessionStorageMode, startRecording]);
|
|
174
377
|
const [notification, setNotification] = React.useState({
|
|
175
378
|
show: false,
|
|
176
379
|
type: 'info',
|
|
@@ -1282,15 +1485,17 @@ isStopRecordingOnSend = false, }) => {
|
|
|
1282
1485
|
const handleSubmit = async (e) => {
|
|
1283
1486
|
e.preventDefault();
|
|
1284
1487
|
if (isStopRecordingOnSend) {
|
|
1285
|
-
while (
|
|
1488
|
+
while (isMicEnabledRef.current) {
|
|
1286
1489
|
stopRecording();
|
|
1287
1490
|
await sleep(1000);
|
|
1288
1491
|
}
|
|
1289
1492
|
}
|
|
1290
1493
|
else {
|
|
1291
|
-
if (
|
|
1494
|
+
if (isMicEnabledRef.current) {
|
|
1292
1495
|
await sleep(1000);
|
|
1293
1496
|
clearRecording();
|
|
1497
|
+
// Reset auto-sent transcript ref when clearing recording
|
|
1498
|
+
lastAutoSentTranscriptRef.current = '';
|
|
1294
1499
|
}
|
|
1295
1500
|
}
|
|
1296
1501
|
if (!textInputRef.current)
|
|
@@ -1816,9 +2021,11 @@ isStopRecordingOnSend = false, }) => {
|
|
|
1816
2021
|
isWalletLoading,
|
|
1817
2022
|
isAutoConnecting,
|
|
1818
2023
|
notification,
|
|
1819
|
-
|
|
2024
|
+
isMicEnabled,
|
|
2025
|
+
isAwaitingMicGesture,
|
|
1820
2026
|
transcript,
|
|
1821
2027
|
textInputRef,
|
|
2028
|
+
autoSendEnabled,
|
|
1822
2029
|
// AI Model related state
|
|
1823
2030
|
availableModels: effectiveAvailableModels,
|
|
1824
2031
|
selectedModelIndex,
|
|
@@ -1837,6 +2044,7 @@ isStopRecordingOnSend = false, }) => {
|
|
|
1837
2044
|
// AI Model related actions
|
|
1838
2045
|
setSelectedModelIndex,
|
|
1839
2046
|
setSuggestions,
|
|
2047
|
+
setAutoSendEnabled,
|
|
1840
2048
|
// Functions
|
|
1841
2049
|
connectWallet,
|
|
1842
2050
|
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"}
|