@apteva/apteva-kit 0.1.112 → 0.1.113
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/index.d.mts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +366 -132
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +301 -67
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
4
4
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
5
|
|
|
6
6
|
// src/components/Chat/Chat.tsx
|
|
7
|
-
import { useState as useState9, useEffect as
|
|
7
|
+
import { useState as useState9, useEffect as useEffect9, useRef as useRef9, useMemo as useMemo2, useCallback as useCallback4, forwardRef, useImperativeHandle } from "react";
|
|
8
8
|
|
|
9
9
|
// src/components/Chat/MessageList.tsx
|
|
10
10
|
import { useEffect as useEffect7, useRef as useRef6 } from "react";
|
|
@@ -3336,9 +3336,13 @@ function MessageList({
|
|
|
3336
3336
|
}
|
|
3337
3337
|
|
|
3338
3338
|
// src/components/Chat/Composer.tsx
|
|
3339
|
-
import { useState as useState6, useRef as useRef7 } from "react";
|
|
3339
|
+
import { useState as useState6, useEffect as useEffect8, useCallback as useCallback3, useRef as useRef7 } from "react";
|
|
3340
3340
|
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
3341
|
-
|
|
3341
|
+
var getSpeechRecognition = () => {
|
|
3342
|
+
if (typeof window === "undefined") return null;
|
|
3343
|
+
return window.SpeechRecognition || window.webkitSpeechRecognition || null;
|
|
3344
|
+
};
|
|
3345
|
+
function Composer({ onSendMessage, placeholder = "Type a message...", disabled = false, isLoading = false, onStop, onFileUpload, onSwitchMode, speechToText }) {
|
|
3342
3346
|
const [text, setText] = useState6("");
|
|
3343
3347
|
const [showMenu, setShowMenu] = useState6(false);
|
|
3344
3348
|
const [pendingFiles, setPendingFiles] = useState6([]);
|
|
@@ -3347,6 +3351,190 @@ function Composer({ onSendMessage, placeholder = "Type a message...", disabled =
|
|
|
3347
3351
|
const textareaRef = useRef7(null);
|
|
3348
3352
|
const fileInputRef = useRef7(null);
|
|
3349
3353
|
const menuButtonRef = useRef7(null);
|
|
3354
|
+
const [isRecording, setIsRecording] = useState6(false);
|
|
3355
|
+
const [recordingTime, setRecordingTime] = useState6(0);
|
|
3356
|
+
const [transcriptFlash, setTranscriptFlash] = useState6(null);
|
|
3357
|
+
const recognitionRef = useRef7(null);
|
|
3358
|
+
const mediaStreamRef = useRef7(null);
|
|
3359
|
+
const audioContextRef = useRef7(null);
|
|
3360
|
+
const analyserRef = useRef7(null);
|
|
3361
|
+
const canvasRef = useRef7(null);
|
|
3362
|
+
const animFrameRef = useRef7(0);
|
|
3363
|
+
const silenceTimerRef = useRef7(null);
|
|
3364
|
+
const recordingTimerRef = useRef7(null);
|
|
3365
|
+
const finalTranscriptRef = useRef7("");
|
|
3366
|
+
const manualStopRef = useRef7(false);
|
|
3367
|
+
const sttConfig = speechToText ? typeof speechToText === "object" ? speechToText : {} : null;
|
|
3368
|
+
const sttSupported = !!sttConfig && !!getSpeechRecognition();
|
|
3369
|
+
const silenceTimeout = sttConfig?.silenceTimeout ?? 2e3;
|
|
3370
|
+
const autoSend = sttConfig?.autoSend !== false;
|
|
3371
|
+
useEffect8(() => {
|
|
3372
|
+
return () => {
|
|
3373
|
+
stopRecording(true);
|
|
3374
|
+
};
|
|
3375
|
+
}, []);
|
|
3376
|
+
const drawWaveform = useCallback3(() => {
|
|
3377
|
+
const canvas = canvasRef.current;
|
|
3378
|
+
const analyser = analyserRef.current;
|
|
3379
|
+
if (!canvas || !analyser) return;
|
|
3380
|
+
const ctx = canvas.getContext("2d");
|
|
3381
|
+
if (!ctx) return;
|
|
3382
|
+
const bufferLength = analyser.frequencyBinCount;
|
|
3383
|
+
const dataArray = new Uint8Array(bufferLength);
|
|
3384
|
+
const draw = () => {
|
|
3385
|
+
animFrameRef.current = requestAnimationFrame(draw);
|
|
3386
|
+
analyser.getByteTimeDomainData(dataArray);
|
|
3387
|
+
const { width, height } = canvas;
|
|
3388
|
+
ctx.clearRect(0, 0, width, height);
|
|
3389
|
+
const barCount = 32;
|
|
3390
|
+
const barWidth = Math.max(2, (width - (barCount - 1) * 2) / barCount);
|
|
3391
|
+
const gap = 2;
|
|
3392
|
+
const samplesPerBar = Math.floor(bufferLength / barCount);
|
|
3393
|
+
for (let i = 0; i < barCount; i++) {
|
|
3394
|
+
let sum = 0;
|
|
3395
|
+
for (let j = 0; j < samplesPerBar; j++) {
|
|
3396
|
+
const val = dataArray[i * samplesPerBar + j] - 128;
|
|
3397
|
+
sum += Math.abs(val);
|
|
3398
|
+
}
|
|
3399
|
+
const avg = sum / samplesPerBar;
|
|
3400
|
+
const barHeight = Math.max(3, avg / 128 * height * 2.5);
|
|
3401
|
+
const x = i * (barWidth + gap);
|
|
3402
|
+
const y = (height - barHeight) / 2;
|
|
3403
|
+
ctx.fillStyle = "#3b82f6";
|
|
3404
|
+
ctx.beginPath();
|
|
3405
|
+
ctx.roundRect(x, y, barWidth, barHeight, barWidth / 2);
|
|
3406
|
+
ctx.fill();
|
|
3407
|
+
}
|
|
3408
|
+
};
|
|
3409
|
+
draw();
|
|
3410
|
+
}, []);
|
|
3411
|
+
const startRecording = useCallback3(async () => {
|
|
3412
|
+
const SpeechRecognitionCtor = getSpeechRecognition();
|
|
3413
|
+
if (!SpeechRecognitionCtor) return;
|
|
3414
|
+
try {
|
|
3415
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
3416
|
+
mediaStreamRef.current = stream;
|
|
3417
|
+
const audioCtx = new AudioContext();
|
|
3418
|
+
audioContextRef.current = audioCtx;
|
|
3419
|
+
const source = audioCtx.createMediaStreamSource(stream);
|
|
3420
|
+
const analyser = audioCtx.createAnalyser();
|
|
3421
|
+
analyser.fftSize = 256;
|
|
3422
|
+
source.connect(analyser);
|
|
3423
|
+
analyserRef.current = analyser;
|
|
3424
|
+
const recognition = new SpeechRecognitionCtor();
|
|
3425
|
+
recognition.continuous = true;
|
|
3426
|
+
recognition.interimResults = true;
|
|
3427
|
+
recognition.lang = sttConfig?.language || navigator.language || "en-US";
|
|
3428
|
+
recognitionRef.current = recognition;
|
|
3429
|
+
finalTranscriptRef.current = "";
|
|
3430
|
+
manualStopRef.current = false;
|
|
3431
|
+
recognition.onresult = (event) => {
|
|
3432
|
+
let final = "";
|
|
3433
|
+
let interim = "";
|
|
3434
|
+
for (let i = 0; i < event.results.length; i++) {
|
|
3435
|
+
const result = event.results[i];
|
|
3436
|
+
if (result.isFinal) {
|
|
3437
|
+
final += result[0].transcript;
|
|
3438
|
+
} else {
|
|
3439
|
+
interim += result[0].transcript;
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
finalTranscriptRef.current = final;
|
|
3443
|
+
if (silenceTimerRef.current) {
|
|
3444
|
+
clearTimeout(silenceTimerRef.current);
|
|
3445
|
+
}
|
|
3446
|
+
silenceTimerRef.current = setTimeout(() => {
|
|
3447
|
+
stopRecording(false);
|
|
3448
|
+
}, silenceTimeout);
|
|
3449
|
+
};
|
|
3450
|
+
recognition.onerror = (event) => {
|
|
3451
|
+
if (event.error !== "aborted") {
|
|
3452
|
+
console.warn("Speech recognition error:", event.error);
|
|
3453
|
+
}
|
|
3454
|
+
stopRecording(true);
|
|
3455
|
+
};
|
|
3456
|
+
recognition.onend = () => {
|
|
3457
|
+
if (!manualStopRef.current && isRecording) {
|
|
3458
|
+
finishRecording();
|
|
3459
|
+
}
|
|
3460
|
+
};
|
|
3461
|
+
recognition.start();
|
|
3462
|
+
setIsRecording(true);
|
|
3463
|
+
setRecordingTime(0);
|
|
3464
|
+
recordingTimerRef.current = setInterval(() => {
|
|
3465
|
+
setRecordingTime((t) => t + 1);
|
|
3466
|
+
}, 1e3);
|
|
3467
|
+
requestAnimationFrame(() => drawWaveform());
|
|
3468
|
+
silenceTimerRef.current = setTimeout(() => {
|
|
3469
|
+
stopRecording(false);
|
|
3470
|
+
}, silenceTimeout + 1e3);
|
|
3471
|
+
} catch (err) {
|
|
3472
|
+
console.warn("Microphone access denied or error:", err);
|
|
3473
|
+
setFileError("Microphone access denied");
|
|
3474
|
+
setTimeout(() => setFileError(null), 3e3);
|
|
3475
|
+
}
|
|
3476
|
+
}, [sttConfig?.language, silenceTimeout, drawWaveform]);
|
|
3477
|
+
const finishRecording = useCallback3(() => {
|
|
3478
|
+
const transcript = finalTranscriptRef.current.trim();
|
|
3479
|
+
setIsRecording(false);
|
|
3480
|
+
setRecordingTime(0);
|
|
3481
|
+
if (transcript) {
|
|
3482
|
+
if (autoSend) {
|
|
3483
|
+
setTranscriptFlash(transcript);
|
|
3484
|
+
setTimeout(() => {
|
|
3485
|
+
setTranscriptFlash(null);
|
|
3486
|
+
onSendMessage(transcript);
|
|
3487
|
+
}, 600);
|
|
3488
|
+
} else {
|
|
3489
|
+
setText((prev) => prev ? `${prev} ${transcript}` : transcript);
|
|
3490
|
+
}
|
|
3491
|
+
}
|
|
3492
|
+
}, [autoSend, onSendMessage]);
|
|
3493
|
+
const stopRecording = useCallback3((isCleanupOnly) => {
|
|
3494
|
+
manualStopRef.current = true;
|
|
3495
|
+
if (silenceTimerRef.current) {
|
|
3496
|
+
clearTimeout(silenceTimerRef.current);
|
|
3497
|
+
silenceTimerRef.current = null;
|
|
3498
|
+
}
|
|
3499
|
+
if (recordingTimerRef.current) {
|
|
3500
|
+
clearInterval(recordingTimerRef.current);
|
|
3501
|
+
recordingTimerRef.current = null;
|
|
3502
|
+
}
|
|
3503
|
+
if (animFrameRef.current) {
|
|
3504
|
+
cancelAnimationFrame(animFrameRef.current);
|
|
3505
|
+
animFrameRef.current = 0;
|
|
3506
|
+
}
|
|
3507
|
+
if (recognitionRef.current) {
|
|
3508
|
+
try {
|
|
3509
|
+
recognitionRef.current.stop();
|
|
3510
|
+
} catch (_e) {
|
|
3511
|
+
}
|
|
3512
|
+
recognitionRef.current = null;
|
|
3513
|
+
}
|
|
3514
|
+
if (mediaStreamRef.current) {
|
|
3515
|
+
mediaStreamRef.current.getTracks().forEach((t) => t.stop());
|
|
3516
|
+
mediaStreamRef.current = null;
|
|
3517
|
+
}
|
|
3518
|
+
if (audioContextRef.current) {
|
|
3519
|
+
try {
|
|
3520
|
+
audioContextRef.current.close();
|
|
3521
|
+
} catch (_e) {
|
|
3522
|
+
}
|
|
3523
|
+
audioContextRef.current = null;
|
|
3524
|
+
}
|
|
3525
|
+
analyserRef.current = null;
|
|
3526
|
+
if (!isCleanupOnly) {
|
|
3527
|
+
finishRecording();
|
|
3528
|
+
} else {
|
|
3529
|
+
setIsRecording(false);
|
|
3530
|
+
setRecordingTime(0);
|
|
3531
|
+
}
|
|
3532
|
+
}, [finishRecording]);
|
|
3533
|
+
const formatTime = (seconds) => {
|
|
3534
|
+
const m = Math.floor(seconds / 60);
|
|
3535
|
+
const s = seconds % 60;
|
|
3536
|
+
return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
|
|
3537
|
+
};
|
|
3350
3538
|
const handleKeyDown = (e) => {
|
|
3351
3539
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
3352
3540
|
e.preventDefault();
|
|
@@ -3429,12 +3617,17 @@ function Composer({ onSendMessage, placeholder = "Type a message...", disabled =
|
|
|
3429
3617
|
}
|
|
3430
3618
|
return /* @__PURE__ */ jsx23("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx23("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" }) });
|
|
3431
3619
|
};
|
|
3620
|
+
const hasMic = sttSupported && !isRecording;
|
|
3621
|
+
const gridCols = hasMic ? "auto 1fr auto auto" : "auto 1fr auto";
|
|
3622
|
+
const gridAreas = isRecording ? '"plus waveform waveform stop"' : isMultiLine ? hasMic ? '"textarea textarea textarea textarea" "plus . mic send"' : '"textarea textarea textarea" "plus . send"' : hasMic ? '"plus textarea mic send"' : '"plus textarea send"';
|
|
3623
|
+
const gridColsRecording = "auto 1fr auto";
|
|
3432
3624
|
return /* @__PURE__ */ jsxs17("div", { className: "px-4 py-3 relative", children: [
|
|
3433
3625
|
fileError && /* @__PURE__ */ jsx23("div", { className: "apteva-file-error", children: /* @__PURE__ */ jsxs17("div", { className: "apteva-file-error-content", children: [
|
|
3434
3626
|
/* @__PURE__ */ jsx23("svg", { fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx23("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }),
|
|
3435
3627
|
/* @__PURE__ */ jsx23("span", { children: fileError })
|
|
3436
3628
|
] }) }),
|
|
3437
|
-
|
|
3629
|
+
transcriptFlash && /* @__PURE__ */ jsx23("div", { className: "apteva-transcript-flash", children: /* @__PURE__ */ jsx23("span", { children: transcriptFlash }) }),
|
|
3630
|
+
pendingFiles.length > 0 && !isRecording && /* @__PURE__ */ jsx23("div", { className: "apteva-file-preview", children: pendingFiles.map((pf, index) => /* @__PURE__ */ jsxs17("div", { className: "apteva-file-item", children: [
|
|
3438
3631
|
pf.preview ? /* @__PURE__ */ jsx23("img", { src: pf.preview, alt: pf.file.name, className: "apteva-file-thumb" }) : /* @__PURE__ */ jsx23("div", { className: "apteva-file-icon", children: getFileIcon(pf.file.type) }),
|
|
3439
3632
|
/* @__PURE__ */ jsxs17("div", { className: "apteva-file-info", children: [
|
|
3440
3633
|
/* @__PURE__ */ jsx23("span", { className: "apteva-file-name", children: pf.file.name }),
|
|
@@ -3455,12 +3648,12 @@ function Composer({ onSendMessage, placeholder = "Type a message...", disabled =
|
|
|
3455
3648
|
{
|
|
3456
3649
|
className: "apteva-composer",
|
|
3457
3650
|
style: {
|
|
3458
|
-
gridTemplateColumns:
|
|
3459
|
-
gridTemplateAreas:
|
|
3651
|
+
gridTemplateColumns: isRecording ? gridColsRecording : gridCols,
|
|
3652
|
+
gridTemplateAreas: isRecording ? '"plus waveform stop"' : gridAreas,
|
|
3460
3653
|
alignItems: "end"
|
|
3461
3654
|
},
|
|
3462
3655
|
children: [
|
|
3463
|
-
/* @__PURE__ */
|
|
3656
|
+
/* @__PURE__ */ jsx23("div", { className: "relative flex-shrink-0 self-end", style: { gridArea: "plus" }, children: isRecording ? /* @__PURE__ */ jsx23("div", { className: "apteva-composer-rec-dot", title: "Recording...", children: /* @__PURE__ */ jsx23("span", {}) }) : /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
3464
3657
|
/* @__PURE__ */ jsx23(
|
|
3465
3658
|
"button",
|
|
3466
3659
|
{
|
|
@@ -3514,39 +3707,77 @@ function Composer({ onSendMessage, placeholder = "Type a message...", disabled =
|
|
|
3514
3707
|
}
|
|
3515
3708
|
)
|
|
3516
3709
|
] })
|
|
3517
|
-
] }),
|
|
3518
|
-
/* @__PURE__ */
|
|
3519
|
-
"
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
}
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
|
|
3539
|
-
}
|
|
3540
|
-
) : /* @__PURE__ */
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3710
|
+
] }) }),
|
|
3711
|
+
isRecording ? /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
3712
|
+
/* @__PURE__ */ jsxs17("div", { className: "apteva-composer-waveform", style: { gridArea: "waveform" }, children: [
|
|
3713
|
+
/* @__PURE__ */ jsx23(
|
|
3714
|
+
"canvas",
|
|
3715
|
+
{
|
|
3716
|
+
ref: canvasRef,
|
|
3717
|
+
width: 300,
|
|
3718
|
+
height: 36,
|
|
3719
|
+
className: "apteva-composer-waveform-canvas"
|
|
3720
|
+
}
|
|
3721
|
+
),
|
|
3722
|
+
/* @__PURE__ */ jsx23("span", { className: "apteva-composer-recording-timer", children: formatTime(recordingTime) })
|
|
3723
|
+
] }),
|
|
3724
|
+
/* @__PURE__ */ jsx23("div", { className: "self-end", style: { gridArea: "stop" }, children: /* @__PURE__ */ jsx23(
|
|
3725
|
+
"button",
|
|
3726
|
+
{
|
|
3727
|
+
onClick: () => stopRecording(false),
|
|
3728
|
+
className: "apteva-composer-stop-btn",
|
|
3729
|
+
title: "Stop recording",
|
|
3730
|
+
children: /* @__PURE__ */ jsx23("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx23("rect", { x: "2", y: "2", width: "10", height: "10", rx: "1", fill: "currentColor" }) })
|
|
3731
|
+
}
|
|
3732
|
+
) })
|
|
3733
|
+
] }) : /* @__PURE__ */ jsxs17(Fragment4, { children: [
|
|
3734
|
+
/* @__PURE__ */ jsx23(
|
|
3735
|
+
"textarea",
|
|
3736
|
+
{
|
|
3737
|
+
ref: textareaRef,
|
|
3738
|
+
value: text,
|
|
3739
|
+
onChange: handleChange,
|
|
3740
|
+
onKeyDown: handleKeyDown,
|
|
3741
|
+
placeholder,
|
|
3742
|
+
disabled,
|
|
3743
|
+
className: "apteva-composer-textarea resize-none bg-transparent border-none focus:outline-none !text-neutral-900 dark:!text-neutral-100 placeholder-neutral-400 dark:placeholder-neutral-500 py-1 disabled:opacity-50 disabled:cursor-not-allowed overflow-y-auto max-h-[200px]",
|
|
3744
|
+
style: { gridArea: "textarea" },
|
|
3745
|
+
rows: 1
|
|
3746
|
+
}
|
|
3747
|
+
),
|
|
3748
|
+
sttSupported && /* @__PURE__ */ jsx23("div", { className: "self-end", style: { gridArea: "mic" }, children: /* @__PURE__ */ jsx23(
|
|
3749
|
+
"button",
|
|
3750
|
+
{
|
|
3751
|
+
onClick: startRecording,
|
|
3752
|
+
disabled: disabled || isLoading,
|
|
3753
|
+
className: "apteva-composer-mic-btn",
|
|
3754
|
+
title: "Voice input",
|
|
3755
|
+
children: /* @__PURE__ */ jsxs17("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
|
|
3756
|
+
/* @__PURE__ */ jsx23("path", { d: "M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z", fill: "currentColor" }),
|
|
3757
|
+
/* @__PURE__ */ jsx23("path", { d: "M19 10v2a7 7 0 01-14 0v-2", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
3758
|
+
/* @__PURE__ */ jsx23("path", { d: "M12 19v4M8 23h8", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
3759
|
+
] })
|
|
3760
|
+
}
|
|
3761
|
+
) }),
|
|
3762
|
+
/* @__PURE__ */ jsx23("div", { className: "self-end", style: { gridArea: "send" }, children: isLoading && onStop ? /* @__PURE__ */ jsx23(
|
|
3763
|
+
"button",
|
|
3764
|
+
{
|
|
3765
|
+
onClick: onStop,
|
|
3766
|
+
className: "apteva-composer-stop-btn",
|
|
3767
|
+
title: "Stop generation",
|
|
3768
|
+
children: /* @__PURE__ */ jsx23("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx23("rect", { x: "2", y: "2", width: "10", height: "10", rx: "1", fill: "currentColor" }) })
|
|
3769
|
+
}
|
|
3770
|
+
) : /* @__PURE__ */ jsx23(
|
|
3771
|
+
"button",
|
|
3772
|
+
{
|
|
3773
|
+
onClick: handleSend,
|
|
3774
|
+
disabled: !text.trim() && pendingFiles.length === 0 || disabled,
|
|
3775
|
+
className: "apteva-composer-send-btn w-8 h-8 rounded-lg flex items-center justify-center font-bold transition-all flex-shrink-0 border border-neutral-300 dark:border-neutral-600 bg-white dark:bg-neutral-800 !text-neutral-700 dark:!text-neutral-300 hover:bg-neutral-50 dark:hover:bg-neutral-700 disabled:opacity-30 disabled:cursor-not-allowed !text-lg",
|
|
3776
|
+
title: "Send message",
|
|
3777
|
+
children: /* @__PURE__ */ jsx23("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx23("path", { d: "M8 3L8 13M8 3L4 7M8 3L12 7", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })
|
|
3778
|
+
}
|
|
3779
|
+
) })
|
|
3780
|
+
] })
|
|
3550
3781
|
]
|
|
3551
3782
|
}
|
|
3552
3783
|
),
|
|
@@ -4145,6 +4376,8 @@ var Chat = forwardRef(function Chat2({
|
|
|
4145
4376
|
availableWidgets,
|
|
4146
4377
|
compactWidgetContext = false,
|
|
4147
4378
|
onWidgetRender,
|
|
4379
|
+
// Speech to text
|
|
4380
|
+
speechToText,
|
|
4148
4381
|
className
|
|
4149
4382
|
}, ref) {
|
|
4150
4383
|
const [messages, setMessages] = useState9(initialMessages);
|
|
@@ -4166,7 +4399,7 @@ var Chat = forwardRef(function Chat2({
|
|
|
4166
4399
|
const [showSettingsMenu, setShowSettingsMenu] = useState9(false);
|
|
4167
4400
|
const fileInputRef = useRef9(null);
|
|
4168
4401
|
const [persistentWidgets, setPersistentWidgets] = useState9(/* @__PURE__ */ new Map());
|
|
4169
|
-
const updatePersistentWidgets =
|
|
4402
|
+
const updatePersistentWidgets = useCallback4((msgs) => {
|
|
4170
4403
|
setPersistentWidgets((prev) => {
|
|
4171
4404
|
const next = new Map(prev);
|
|
4172
4405
|
let changed = false;
|
|
@@ -4184,7 +4417,7 @@ var Chat = forwardRef(function Chat2({
|
|
|
4184
4417
|
return changed ? next : prev;
|
|
4185
4418
|
});
|
|
4186
4419
|
}, []);
|
|
4187
|
-
|
|
4420
|
+
useEffect9(() => {
|
|
4188
4421
|
updatePersistentWidgets(messages);
|
|
4189
4422
|
}, [messages, updatePersistentWidgets]);
|
|
4190
4423
|
const persistentWidgetList = useMemo2(() => Array.from(persistentWidgets.values()), [persistentWidgets]);
|
|
@@ -4210,7 +4443,7 @@ var Chat = forwardRef(function Chat2({
|
|
|
4210
4443
|
return context ? `${context}
|
|
4211
4444
|
${widgetContext}` : widgetContext;
|
|
4212
4445
|
}, [context, enableWidgets, availableWidgets, compactWidgetContext]);
|
|
4213
|
-
|
|
4446
|
+
useEffect9(() => {
|
|
4214
4447
|
if (apiUrl || apiKey) {
|
|
4215
4448
|
aptevaClient.configure({
|
|
4216
4449
|
...apiUrl && { apiUrl },
|
|
@@ -4218,15 +4451,15 @@ ${widgetContext}` : widgetContext;
|
|
|
4218
4451
|
});
|
|
4219
4452
|
}
|
|
4220
4453
|
}, [apiUrl, apiKey]);
|
|
4221
|
-
|
|
4454
|
+
useEffect9(() => {
|
|
4222
4455
|
if (threadId) {
|
|
4223
4456
|
onThreadChange?.(threadId);
|
|
4224
4457
|
}
|
|
4225
4458
|
}, [threadId, onThreadChange]);
|
|
4226
|
-
|
|
4459
|
+
useEffect9(() => {
|
|
4227
4460
|
setInternalPlanMode(planMode);
|
|
4228
4461
|
}, [planMode]);
|
|
4229
|
-
|
|
4462
|
+
useEffect9(() => {
|
|
4230
4463
|
const handleClickOutside = (event) => {
|
|
4231
4464
|
const target = event.target;
|
|
4232
4465
|
if (showSettingsMenu && !target.closest(".settings-menu-container")) {
|
|
@@ -4246,7 +4479,7 @@ ${widgetContext}` : widgetContext;
|
|
|
4246
4479
|
}
|
|
4247
4480
|
};
|
|
4248
4481
|
const defaultPlaceholder = mode === "chat" ? "Type a message..." : "Enter your command...";
|
|
4249
|
-
const handleWidgetAction =
|
|
4482
|
+
const handleWidgetAction = useCallback4((action) => {
|
|
4250
4483
|
onAction?.(action);
|
|
4251
4484
|
if (action.type === "submit" && action.payload?.formData) {
|
|
4252
4485
|
const formData = action.payload.formData;
|
|
@@ -4800,7 +5033,8 @@ ${planToExecute}`;
|
|
|
4800
5033
|
isLoading,
|
|
4801
5034
|
onStop: handleStop,
|
|
4802
5035
|
onFileUpload,
|
|
4803
|
-
onSwitchMode: showModeToggle ? () => handleModeChange("command") : void 0
|
|
5036
|
+
onSwitchMode: showModeToggle ? () => handleModeChange("command") : void 0,
|
|
5037
|
+
speechToText
|
|
4804
5038
|
}
|
|
4805
5039
|
)
|
|
4806
5040
|
] }),
|
|
@@ -4847,7 +5081,7 @@ import { useState as useState10 } from "react";
|
|
|
4847
5081
|
import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
4848
5082
|
|
|
4849
5083
|
// src/components/Command/Command.tsx
|
|
4850
|
-
import React, { useState as useState11, useEffect as
|
|
5084
|
+
import React, { useState as useState11, useEffect as useEffect10 } from "react";
|
|
4851
5085
|
import { Fragment as Fragment7, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
4852
5086
|
function Command({
|
|
4853
5087
|
agentId,
|
|
@@ -4888,15 +5122,15 @@ function Command({
|
|
|
4888
5122
|
const [showSettingsMenu, setShowSettingsMenu] = useState11(false);
|
|
4889
5123
|
const [internalPlanMode, setInternalPlanMode] = useState11(planMode);
|
|
4890
5124
|
const fileInputRef = React.useRef(null);
|
|
4891
|
-
|
|
5125
|
+
useEffect10(() => {
|
|
4892
5126
|
if (autoExecute && state === "idle" && command) {
|
|
4893
5127
|
executeCommand();
|
|
4894
5128
|
}
|
|
4895
5129
|
}, [autoExecute]);
|
|
4896
|
-
|
|
5130
|
+
useEffect10(() => {
|
|
4897
5131
|
setInternalPlanMode(planMode);
|
|
4898
5132
|
}, [planMode]);
|
|
4899
|
-
|
|
5133
|
+
useEffect10(() => {
|
|
4900
5134
|
const handleClickOutside = (event) => {
|
|
4901
5135
|
const target = event.target;
|
|
4902
5136
|
if (showSettingsMenu && !target.closest(".settings-menu-container")) {
|
|
@@ -5929,7 +6163,7 @@ function Prompt({
|
|
|
5929
6163
|
}
|
|
5930
6164
|
|
|
5931
6165
|
// src/components/Stream/Stream.tsx
|
|
5932
|
-
import { useState as useState13, useEffect as
|
|
6166
|
+
import { useState as useState13, useEffect as useEffect11 } from "react";
|
|
5933
6167
|
import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
5934
6168
|
function Stream({
|
|
5935
6169
|
agentId,
|
|
@@ -5949,7 +6183,7 @@ function Stream({
|
|
|
5949
6183
|
const [text, setText] = useState13("");
|
|
5950
6184
|
const [isStreaming, setIsStreaming] = useState13(false);
|
|
5951
6185
|
const [isComplete, setIsComplete] = useState13(false);
|
|
5952
|
-
|
|
6186
|
+
useEffect11(() => {
|
|
5953
6187
|
if (autoStart && !isStreaming && !isComplete) {
|
|
5954
6188
|
startStreaming();
|
|
5955
6189
|
}
|
|
@@ -6220,7 +6454,7 @@ function Threads({
|
|
|
6220
6454
|
}
|
|
6221
6455
|
|
|
6222
6456
|
// src/components/AutoInterface/AutoInterface.tsx
|
|
6223
|
-
import { useState as useState16, useRef as useRef10, useCallback as
|
|
6457
|
+
import { useState as useState16, useRef as useRef10, useCallback as useCallback5, useEffect as useEffect12 } from "react";
|
|
6224
6458
|
|
|
6225
6459
|
// src/components/AutoInterface/LayoutRenderer.tsx
|
|
6226
6460
|
import { useState as useState15 } from "react";
|
|
@@ -6498,11 +6732,11 @@ function AutoInterface({
|
|
|
6498
6732
|
generateInterfaceContext(),
|
|
6499
6733
|
context || ""
|
|
6500
6734
|
].filter(Boolean).join("\n\n");
|
|
6501
|
-
const updateInterface =
|
|
6735
|
+
const updateInterface = useCallback5((newSpec) => {
|
|
6502
6736
|
setInterfaceSpec(newSpec);
|
|
6503
6737
|
onInterfaceChange?.(newSpec);
|
|
6504
6738
|
}, [onInterfaceChange]);
|
|
6505
|
-
const handleAction =
|
|
6739
|
+
const handleAction = useCallback5((action) => {
|
|
6506
6740
|
onAction?.(action);
|
|
6507
6741
|
if (chatRef.current) {
|
|
6508
6742
|
chatRef.current.sendMessage(
|
|
@@ -6510,7 +6744,7 @@ function AutoInterface({
|
|
|
6510
6744
|
);
|
|
6511
6745
|
}
|
|
6512
6746
|
}, [onAction]);
|
|
6513
|
-
const handleMessageComplete =
|
|
6747
|
+
const handleMessageComplete = useCallback5((result) => {
|
|
6514
6748
|
if (!result?.data) return;
|
|
6515
6749
|
const text = typeof result.data === "string" ? result.data : result.data.message || "";
|
|
6516
6750
|
console.log("[AutoInterface] Chat message complete, text (" + text.length + " chars):", text.substring(0, 300));
|
|
@@ -6531,7 +6765,7 @@ function AutoInterface({
|
|
|
6531
6765
|
}
|
|
6532
6766
|
setIsGenerating(false);
|
|
6533
6767
|
}, [interfaceSpec, updateInterface]);
|
|
6534
|
-
|
|
6768
|
+
useEffect12(() => {
|
|
6535
6769
|
if (!initialPrompt || initialInterface || useMock) return;
|
|
6536
6770
|
if (!apiUrl) return;
|
|
6537
6771
|
let cancelled = false;
|
|
@@ -6656,29 +6890,29 @@ function getThemeScript() {
|
|
|
6656
6890
|
}
|
|
6657
6891
|
|
|
6658
6892
|
// src/hooks/useInterfaceState.ts
|
|
6659
|
-
import { useState as useState17, useCallback as
|
|
6893
|
+
import { useState as useState17, useCallback as useCallback6 } from "react";
|
|
6660
6894
|
function useInterfaceState(initialSpec) {
|
|
6661
6895
|
const [spec, setSpec] = useState17(initialSpec || null);
|
|
6662
6896
|
const [isStreaming, setIsStreaming] = useState17(false);
|
|
6663
|
-
const setInterface =
|
|
6897
|
+
const setInterface = useCallback6((newSpec) => {
|
|
6664
6898
|
setSpec(newSpec);
|
|
6665
6899
|
}, []);
|
|
6666
|
-
const clearInterface =
|
|
6900
|
+
const clearInterface = useCallback6(() => {
|
|
6667
6901
|
setSpec(null);
|
|
6668
6902
|
}, []);
|
|
6669
|
-
const applyInterfaceUpdate =
|
|
6903
|
+
const applyInterfaceUpdate = useCallback6((update) => {
|
|
6670
6904
|
setSpec((prev) => {
|
|
6671
6905
|
if (!prev) return prev;
|
|
6672
6906
|
return applyUpdate(prev, update);
|
|
6673
6907
|
});
|
|
6674
6908
|
}, []);
|
|
6675
|
-
const applyInterfaceUpdates =
|
|
6909
|
+
const applyInterfaceUpdates = useCallback6((updates) => {
|
|
6676
6910
|
setSpec((prev) => {
|
|
6677
6911
|
if (!prev) return prev;
|
|
6678
6912
|
return applyUpdates(prev, updates);
|
|
6679
6913
|
});
|
|
6680
6914
|
}, []);
|
|
6681
|
-
const getNode =
|
|
6915
|
+
const getNode = useCallback6((id) => {
|
|
6682
6916
|
if (!spec) return null;
|
|
6683
6917
|
return findNode(spec.root, id);
|
|
6684
6918
|
}, [spec]);
|
|
@@ -6695,7 +6929,7 @@ function useInterfaceState(initialSpec) {
|
|
|
6695
6929
|
}
|
|
6696
6930
|
|
|
6697
6931
|
// src/hooks/useInterfaceAI.ts
|
|
6698
|
-
import { useCallback as
|
|
6932
|
+
import { useCallback as useCallback7, useRef as useRef11 } from "react";
|
|
6699
6933
|
function useInterfaceAI({
|
|
6700
6934
|
agentId,
|
|
6701
6935
|
apiUrl,
|
|
@@ -6715,7 +6949,7 @@ function useInterfaceAI({
|
|
|
6715
6949
|
...apiKey && { apiKey }
|
|
6716
6950
|
});
|
|
6717
6951
|
}
|
|
6718
|
-
const sendMessage =
|
|
6952
|
+
const sendMessage = useCallback7(async (message) => {
|
|
6719
6953
|
accumulatedTextRef.current = "";
|
|
6720
6954
|
onStreamStart?.();
|
|
6721
6955
|
const systemPrompt = [
|