@contentgrowth/llm-service 0.8.5 → 0.8.7
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.
|
@@ -148,7 +148,7 @@ function ChatHeader({
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// src/ui/react/components/ChatInputArea.tsx
|
|
151
|
-
import { useState as useState3, useRef as useRef3, useImperativeHandle, forwardRef, useEffect as useEffect3 } from "react";
|
|
151
|
+
import { useState as useState3, useRef as useRef3, useImperativeHandle, forwardRef, useEffect as useEffect3, useCallback as useCallback3 } from "react";
|
|
152
152
|
import { StopIcon, PaperAirplaneIcon } from "@heroicons/react/24/outline";
|
|
153
153
|
|
|
154
154
|
// src/ui/react/hooks/useSpeechRecognition.ts
|
|
@@ -171,11 +171,16 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
|
|
|
171
171
|
recognition.interimResults = true;
|
|
172
172
|
recognition.lang = language;
|
|
173
173
|
recognition.onstart = () => {
|
|
174
|
+
console.log("[useSpeechRecognition] Native onstart event fired");
|
|
174
175
|
setIsListening(true);
|
|
175
176
|
setError(null);
|
|
176
177
|
};
|
|
177
178
|
recognition.onend = () => {
|
|
178
|
-
|
|
179
|
+
console.log("[useSpeechRecognition] Native onend event fired");
|
|
180
|
+
if (isSimulatingRef.current) {
|
|
181
|
+
console.log("[useSpeechRecognition] Ignoring onend due to simulation");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
179
184
|
setIsListening(false);
|
|
180
185
|
if (onEnd) onEnd();
|
|
181
186
|
};
|
|
@@ -195,6 +200,7 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
|
|
|
195
200
|
setTranscript((prev) => prev + finalTranscript);
|
|
196
201
|
};
|
|
197
202
|
recognition.onerror = (event) => {
|
|
203
|
+
console.error("[useSpeechRecognition] Native onerror event:", event.error);
|
|
198
204
|
if (event.error === "not-allowed" && process.env.NODE_ENV === "development") {
|
|
199
205
|
console.warn("Speech recognition blocked. Simulating input for development...");
|
|
200
206
|
isSimulatingRef.current = true;
|
|
@@ -227,17 +233,23 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
|
|
|
227
233
|
};
|
|
228
234
|
}, [onResult, onEnd, language]);
|
|
229
235
|
const start = useCallback(() => {
|
|
236
|
+
console.log("[useSpeechRecognition] start() called");
|
|
230
237
|
if (recognitionRef.current && !isListening) {
|
|
231
238
|
try {
|
|
232
239
|
setTranscript("");
|
|
233
240
|
recognitionRef.current.start();
|
|
241
|
+
console.log("[useSpeechRecognition] recognitionRef.current.start() executed");
|
|
234
242
|
} catch (e) {
|
|
235
|
-
console.error("Failed to start speech recognition:", e);
|
|
243
|
+
console.error("[useSpeechRecognition] Failed to start speech recognition:", e);
|
|
236
244
|
}
|
|
245
|
+
} else {
|
|
246
|
+
console.log("[useSpeechRecognition] start() ignored: already listening or no recognition instance", { hasInstance: !!recognitionRef.current, isListening });
|
|
237
247
|
}
|
|
238
248
|
}, [isListening]);
|
|
239
249
|
const stop = useCallback(() => {
|
|
250
|
+
console.log("[useSpeechRecognition] stop() called");
|
|
240
251
|
if (isSimulatingRef.current) {
|
|
252
|
+
console.log("[useSpeechRecognition] Stopping simulation");
|
|
241
253
|
if (simulationTimeoutRef.current) {
|
|
242
254
|
clearTimeout(simulationTimeoutRef.current);
|
|
243
255
|
simulationTimeoutRef.current = null;
|
|
@@ -251,7 +263,10 @@ var useSpeechRecognition = (onResult, onEnd, language = "en-US") => {
|
|
|
251
263
|
return;
|
|
252
264
|
}
|
|
253
265
|
if (recognitionRef.current && isListening) {
|
|
266
|
+
console.log("[useSpeechRecognition] recognitionRef.current.stop() executed");
|
|
254
267
|
recognitionRef.current.stop();
|
|
268
|
+
} else {
|
|
269
|
+
console.log("[useSpeechRecognition] stop() ignored: not listening", { isListening });
|
|
255
270
|
}
|
|
256
271
|
}, [isListening, onResult, onEnd]);
|
|
257
272
|
const resetTranscript = useCallback(() => {
|
|
@@ -277,23 +292,32 @@ var useAudioRecorder = (onStop) => {
|
|
|
277
292
|
const mediaRecorderRef = useRef2(null);
|
|
278
293
|
const chunksRef = useRef2([]);
|
|
279
294
|
const start = useCallback2(async () => {
|
|
295
|
+
console.log("[useAudioRecorder] start() called");
|
|
280
296
|
try {
|
|
281
297
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
298
|
+
console.log("[useAudioRecorder] Stream acquired", stream.id);
|
|
282
299
|
const mediaRecorder = new MediaRecorder(stream);
|
|
283
300
|
mediaRecorderRef.current = mediaRecorder;
|
|
284
301
|
chunksRef.current = [];
|
|
285
302
|
mediaRecorder.ondataavailable = (e) => {
|
|
303
|
+
console.log(`[useAudioRecorder] Data available, size: ${e.data.size}`);
|
|
286
304
|
if (e.data.size > 0) {
|
|
287
305
|
chunksRef.current.push(e.data);
|
|
288
306
|
}
|
|
289
307
|
};
|
|
290
308
|
mediaRecorder.onstop = () => {
|
|
309
|
+
console.log(`[useAudioRecorder] Recorder stopped. Chunks: ${chunksRef.current.length}`);
|
|
291
310
|
const audioBlob = new Blob(chunksRef.current, { type: "audio/webm" });
|
|
311
|
+
console.log(`[useAudioRecorder] Blob created. Size: ${audioBlob.size}, Type: ${audioBlob.type}`);
|
|
292
312
|
setBlob(audioBlob);
|
|
293
313
|
setIsRecording(false);
|
|
294
314
|
if (onStop) onStop(audioBlob);
|
|
295
|
-
stream.getTracks().forEach((track) =>
|
|
315
|
+
stream.getTracks().forEach((track) => {
|
|
316
|
+
console.log(`[useAudioRecorder] Stopping track: ${track.label} (${track.kind})`);
|
|
317
|
+
track.stop();
|
|
318
|
+
});
|
|
296
319
|
};
|
|
320
|
+
console.log("[useAudioRecorder] Starting MediaRecorder...");
|
|
297
321
|
mediaRecorder.start();
|
|
298
322
|
setIsRecording(true);
|
|
299
323
|
setError(null);
|
|
@@ -303,8 +327,12 @@ var useAudioRecorder = (onStop) => {
|
|
|
303
327
|
}
|
|
304
328
|
}, [onStop]);
|
|
305
329
|
const stop = useCallback2(() => {
|
|
330
|
+
console.log("[useAudioRecorder] stop() called");
|
|
306
331
|
if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
|
|
332
|
+
console.log(`[useAudioRecorder] Stopping MediaRecorder. State was: ${mediaRecorderRef.current.state}`);
|
|
307
333
|
mediaRecorderRef.current.stop();
|
|
334
|
+
} else {
|
|
335
|
+
console.log("[useAudioRecorder] stop() ignored. Recorder is inactive or missing.");
|
|
308
336
|
}
|
|
309
337
|
}, []);
|
|
310
338
|
return {
|
|
@@ -370,20 +398,30 @@ var ChatInputArea = forwardRef(({
|
|
|
370
398
|
}, [inputMode]);
|
|
371
399
|
const isControlled = value !== void 0;
|
|
372
400
|
const message = isControlled ? value : internalMessage;
|
|
401
|
+
const messageRef = useRef3(message);
|
|
402
|
+
messageRef.current = message;
|
|
403
|
+
const onChangeRef = useRef3(onChange);
|
|
404
|
+
useEffect3(() => {
|
|
405
|
+
onChangeRef.current = onChange;
|
|
406
|
+
}, [onChange]);
|
|
373
407
|
const { voice: globalVoice } = useChatConfig();
|
|
374
408
|
const isVoiceEnabled = (_a = globalVoice == null ? void 0 : globalVoice.enabled) != null ? _a : !!propVoiceConfig;
|
|
375
409
|
const voiceConfig = isVoiceEnabled ? propVoiceConfig || (globalVoice == null ? void 0 : globalVoice.config) : void 0;
|
|
376
|
-
const
|
|
377
|
-
|
|
410
|
+
const voiceConfigRef = useRef3(voiceConfig);
|
|
411
|
+
useEffect3(() => {
|
|
412
|
+
voiceConfigRef.current = voiceConfig;
|
|
413
|
+
}, [voiceConfig]);
|
|
414
|
+
const triggerChange = useCallback3((newValue) => {
|
|
415
|
+
if (isControlled && onChangeRef.current && textareaRef.current) {
|
|
378
416
|
const syntheticEvent = {
|
|
379
417
|
target: { value: newValue },
|
|
380
418
|
currentTarget: { value: newValue }
|
|
381
419
|
};
|
|
382
|
-
|
|
420
|
+
onChangeRef.current(syntheticEvent);
|
|
383
421
|
} else {
|
|
384
422
|
setInternalMessage(newValue);
|
|
385
423
|
}
|
|
386
|
-
};
|
|
424
|
+
}, [isControlled]);
|
|
387
425
|
const isInputDisabled = (currentTask == null ? void 0 : currentTask.complete) || (lastInteractiveMessage == null ? void 0 : lastInteractiveMessage.interactive) && (((_b = lastInteractiveMessage == null ? void 0 : lastInteractiveMessage.interactiveData) == null ? void 0 : _b.function) === "form" && !(lastInteractiveMessage == null ? void 0 : lastInteractiveMessage.isResponseSubmitted) || ((_c = lastInteractiveMessage == null ? void 0 : lastInteractiveMessage.interactiveData) == null ? void 0 : _c.function) === "confirm" && !(lastInteractiveMessage == null ? void 0 : lastInteractiveMessage.isResponseSubmitted));
|
|
388
426
|
useProactiveResize(textareaRef, measurementRef, message, isInputDisabled || !!voiceTrigger || inputMode === "voice");
|
|
389
427
|
const handleVoiceKeyDown = (e) => {
|
|
@@ -408,23 +446,28 @@ var ChatInputArea = forwardRef(({
|
|
|
408
446
|
}
|
|
409
447
|
}
|
|
410
448
|
};
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
449
|
+
const handleVoiceResult = useCallback3((text) => {
|
|
450
|
+
console.log("[ChatInputArea] nativeSpeech result:", text);
|
|
451
|
+
triggerChange(messageRef.current + (messageRef.current ? " " : "") + text);
|
|
452
|
+
}, []);
|
|
453
|
+
const handleVoiceEnd = useCallback3(() => {
|
|
454
|
+
var _a2, _b2;
|
|
455
|
+
console.log("[ChatInputArea] nativeSpeech onEnd triggered");
|
|
415
456
|
setVoiceTrigger(null);
|
|
416
|
-
(_a2 =
|
|
417
|
-
},
|
|
457
|
+
(_b2 = (_a2 = voiceConfigRef.current) == null ? void 0 : _a2.onVoiceEnd) == null ? void 0 : _b2.call(_a2);
|
|
458
|
+
}, []);
|
|
459
|
+
const nativeSpeech = useSpeechRecognition(handleVoiceResult, handleVoiceEnd, voiceConfig == null ? void 0 : voiceConfig.language);
|
|
418
460
|
const customRecorder = useAudioRecorder(async (blob) => {
|
|
419
|
-
var _a2;
|
|
461
|
+
var _a2, _b2, _c2;
|
|
462
|
+
console.log("[ChatInputArea] customRecorder onStop triggered");
|
|
420
463
|
setVoiceTrigger(null);
|
|
421
|
-
(_a2 =
|
|
422
|
-
if (
|
|
464
|
+
(_b2 = (_a2 = voiceConfigRef.current) == null ? void 0 : _a2.onVoiceEnd) == null ? void 0 : _b2.call(_a2);
|
|
465
|
+
if ((_c2 = voiceConfigRef.current) == null ? void 0 : _c2.onAudioCapture) {
|
|
423
466
|
try {
|
|
424
|
-
const text = await
|
|
425
|
-
if (text) triggerChange(
|
|
467
|
+
const text = await voiceConfigRef.current.onAudioCapture(blob);
|
|
468
|
+
if (text) triggerChange(messageRef.current + (messageRef.current ? " " : "") + text);
|
|
426
469
|
} catch (e) {
|
|
427
|
-
console.error("Audio capture failed", e);
|
|
470
|
+
console.error("[ChatInputArea] Audio capture failed", e);
|
|
428
471
|
}
|
|
429
472
|
}
|
|
430
473
|
});
|
|
@@ -466,6 +509,8 @@ var ChatInputArea = forwardRef(({
|
|
|
466
509
|
};
|
|
467
510
|
const startRecording = async (trigger) => {
|
|
468
511
|
var _a2;
|
|
512
|
+
console.log(`[ChatInputArea] startRecording triggered by: ${trigger}, current voiceTrigger: ${voiceTrigger}`);
|
|
513
|
+
console.log("[ChatInputArea] voiceConfig:", voiceConfig);
|
|
469
514
|
if (voiceTrigger) return;
|
|
470
515
|
setVoiceTrigger(trigger);
|
|
471
516
|
(_a2 = voiceConfig == null ? void 0 : voiceConfig.onVoiceStart) == null ? void 0 : _a2.call(voiceConfig);
|
|
@@ -475,12 +520,15 @@ var ChatInputArea = forwardRef(({
|
|
|
475
520
|
setVoiceTrigger(null);
|
|
476
521
|
return;
|
|
477
522
|
}
|
|
523
|
+
console.log("[ChatInputArea] Starting nativeSpeech");
|
|
478
524
|
nativeSpeech.start();
|
|
479
525
|
} else {
|
|
526
|
+
console.log("[ChatInputArea] Starting customRecorder");
|
|
480
527
|
await customRecorder.start();
|
|
481
528
|
}
|
|
482
529
|
};
|
|
483
530
|
const stopRecording = () => {
|
|
531
|
+
console.log(`[ChatInputArea] stopRecording called. Current voiceTrigger: ${voiceTrigger}`);
|
|
484
532
|
if (!voiceTrigger) return;
|
|
485
533
|
if ((voiceConfig == null ? void 0 : voiceConfig.mode) === "native") {
|
|
486
534
|
nativeSpeech.stop();
|