genassist-chat-react 1.0.38-rc.0 → 1.0.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -4
- package/dist/components/AudioPlayer.d.ts +11 -0
- package/dist/components/AudioPlayer.js +199 -0
- package/dist/components/ChatBubble.d.ts +1 -0
- package/dist/components/ChatBubble.js +4 -4
- package/dist/components/ChatMessage.d.ts +3 -0
- package/dist/components/ChatMessage.js +10 -5
- package/dist/components/GenAgentChat.js +279 -845
- package/dist/components/LiveCallControl.d.ts +25 -0
- package/dist/components/LiveCallControl.js +83 -0
- package/dist/components/MarkdownMessage.js +23 -1
- package/dist/components/VoiceInput.d.ts +1 -3
- package/dist/components/VoiceInput.js +262 -48
- package/dist/genassist-chat.es.js +16915 -0
- package/dist/genassist-chat.umd.js +91 -0
- package/dist/hooks/useAudioRecorder.d.ts +8 -0
- package/dist/hooks/useAudioRecorder.js +196 -0
- package/dist/hooks/useChat.d.ts +4 -0
- package/dist/hooks/useChat.js +60 -13
- package/dist/hooks/useFileAttachments.d.ts +16 -0
- package/dist/hooks/useFileAttachments.js +183 -0
- package/dist/hooks/useLiveVoice.d.ts +32 -0
- package/dist/hooks/useLiveVoice.js +292 -0
- package/dist/hooks/useScrollManagement.d.ts +15 -0
- package/dist/hooks/useScrollManagement.js +124 -0
- package/dist/hooks/useThinkingAnimation.d.ts +12 -0
- package/dist/hooks/useThinkingAnimation.js +53 -0
- package/dist/hooks/useViewportManager.d.ts +20 -0
- package/dist/hooks/useViewportManager.js +100 -0
- package/dist/services/chatService.d.ts +1 -0
- package/dist/services/chatService.js +76 -17
- package/dist/styles/genAgentChatStyles.d.ts +82 -0
- package/dist/styles/genAgentChatStyles.js +441 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +1 -1
- package/package.json +2 -2
- package/dist/components/AttachmentPreview.d.ts +0 -8
- package/dist/components/AttachmentPreview.js +0 -77
- package/dist/utils/urlUtil.d.ts +0 -2
- package/dist/utils/urlUtil.js +0 -7
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
13
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
14
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
15
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
16
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
17
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
18
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
22
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
23
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
24
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
25
|
+
function step(op) {
|
|
26
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
27
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
28
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
29
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
30
|
+
switch (op[0]) {
|
|
31
|
+
case 0: case 1: t = op; break;
|
|
32
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
33
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
34
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
35
|
+
default:
|
|
36
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
37
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
38
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
39
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
40
|
+
if (t[2]) _.ops.pop();
|
|
41
|
+
_.trys.pop(); continue;
|
|
42
|
+
}
|
|
43
|
+
op = body.call(thisArg, _);
|
|
44
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
45
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
49
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
50
|
+
if (ar || !(i in from)) {
|
|
51
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
52
|
+
ar[i] = from[i];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
56
|
+
};
|
|
57
|
+
import { useState, useRef, useEffect } from 'react';
|
|
58
|
+
export function useFileAttachments(_a) {
|
|
59
|
+
var _this = this;
|
|
60
|
+
var uploadFile = _a.uploadFile, t = _a.t;
|
|
61
|
+
var _b = useState([]), attachments = _b[0], setAttachments = _b[1];
|
|
62
|
+
var _c = useState(new Set()), uploadingFiles = _c[0], setUploadingFiles = _c[1];
|
|
63
|
+
var _d = useState(null), fileErrorToast = _d[0], setFileErrorToast = _d[1];
|
|
64
|
+
var fileErrorToastTimeoutRef = useRef(null);
|
|
65
|
+
var fileInputRef = useRef(null);
|
|
66
|
+
useEffect(function () {
|
|
67
|
+
return function () {
|
|
68
|
+
if (fileErrorToastTimeoutRef.current) {
|
|
69
|
+
clearTimeout(fileErrorToastTimeoutRef.current);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}, []);
|
|
73
|
+
var handleFileChange = function (e) { return __awaiter(_this, void 0, void 0, function () {
|
|
74
|
+
var newFiles_1, newAttachments_1, newUploadingFiles_1, settled, fileToAttachmentMap_1, failedFileKeys_1, hasFailedUploads, error_1, finalUploadingFiles_1;
|
|
75
|
+
var _this = this;
|
|
76
|
+
return __generator(this, function (_a) {
|
|
77
|
+
switch (_a.label) {
|
|
78
|
+
case 0:
|
|
79
|
+
if (!(e.target.files && e.target.files.length > 0)) return [3 /*break*/, 5];
|
|
80
|
+
newFiles_1 = Array.from(e.target.files);
|
|
81
|
+
newAttachments_1 = newFiles_1.map(function (file) { return ({ file: file, attachment: null }); });
|
|
82
|
+
setAttachments(function (prev) { return __spreadArray(__spreadArray([], prev, true), newAttachments_1, true); });
|
|
83
|
+
newUploadingFiles_1 = new Set(uploadingFiles);
|
|
84
|
+
newFiles_1.forEach(function (file) { return newUploadingFiles_1.add(file.name); });
|
|
85
|
+
setUploadingFiles(newUploadingFiles_1);
|
|
86
|
+
_a.label = 1;
|
|
87
|
+
case 1:
|
|
88
|
+
_a.trys.push([1, 3, 4, 5]);
|
|
89
|
+
return [4 /*yield*/, Promise.allSettled(newFiles_1.map(function (file) { return __awaiter(_this, void 0, void 0, function () {
|
|
90
|
+
var _a;
|
|
91
|
+
return __generator(this, function (_b) {
|
|
92
|
+
switch (_b.label) {
|
|
93
|
+
case 0:
|
|
94
|
+
_a = { file: file };
|
|
95
|
+
return [4 /*yield*/, uploadFile(file)];
|
|
96
|
+
case 1: return [2 /*return*/, (_a.attachment = _b.sent(), _a)];
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}); }))];
|
|
100
|
+
case 2:
|
|
101
|
+
settled = _a.sent();
|
|
102
|
+
fileToAttachmentMap_1 = new Map();
|
|
103
|
+
failedFileKeys_1 = new Set();
|
|
104
|
+
settled.forEach(function (result, index) {
|
|
105
|
+
var file = newFiles_1[index];
|
|
106
|
+
if (!file)
|
|
107
|
+
return;
|
|
108
|
+
var fileKey = "".concat(file.name, ":").concat(file.size, ":").concat(file.lastModified);
|
|
109
|
+
if (result.status === 'rejected') {
|
|
110
|
+
fileToAttachmentMap_1.set(fileKey, null);
|
|
111
|
+
failedFileKeys_1.add(fileKey);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
var attachment = result.value.attachment;
|
|
115
|
+
fileToAttachmentMap_1.set(fileKey, attachment);
|
|
116
|
+
if (attachment === null) {
|
|
117
|
+
failedFileKeys_1.add(fileKey);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
hasFailedUploads = failedFileKeys_1.size > 0;
|
|
121
|
+
setAttachments(function (prev) {
|
|
122
|
+
return prev
|
|
123
|
+
.filter(function (att) {
|
|
124
|
+
var fileKey = "".concat(att.file.name, ":").concat(att.file.size, ":").concat(att.file.lastModified);
|
|
125
|
+
return !failedFileKeys_1.has(fileKey);
|
|
126
|
+
})
|
|
127
|
+
.map(function (att) {
|
|
128
|
+
var fileKey = "".concat(att.file.name, ":").concat(att.file.size, ":").concat(att.file.lastModified);
|
|
129
|
+
var uploadedAttachment = fileToAttachmentMap_1.get(fileKey);
|
|
130
|
+
if (uploadedAttachment !== undefined) {
|
|
131
|
+
return __assign(__assign({}, att), { attachment: uploadedAttachment });
|
|
132
|
+
}
|
|
133
|
+
return att;
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
if (hasFailedUploads) {
|
|
137
|
+
if (fileErrorToastTimeoutRef.current) {
|
|
138
|
+
clearTimeout(fileErrorToastTimeoutRef.current);
|
|
139
|
+
}
|
|
140
|
+
setFileErrorToast(t('fileUpload.fileTypeNotSupported', 'This file type is not supported.'));
|
|
141
|
+
fileErrorToastTimeoutRef.current = setTimeout(function () {
|
|
142
|
+
setFileErrorToast(null);
|
|
143
|
+
fileErrorToastTimeoutRef.current = null;
|
|
144
|
+
}, 4000);
|
|
145
|
+
}
|
|
146
|
+
return [3 /*break*/, 5];
|
|
147
|
+
case 3:
|
|
148
|
+
error_1 = _a.sent();
|
|
149
|
+
console.error('Error uploading file', error_1);
|
|
150
|
+
return [3 /*break*/, 5];
|
|
151
|
+
case 4:
|
|
152
|
+
finalUploadingFiles_1 = new Set(uploadingFiles);
|
|
153
|
+
newFiles_1.forEach(function (file) { return finalUploadingFiles_1.delete(file.name); });
|
|
154
|
+
setUploadingFiles(finalUploadingFiles_1);
|
|
155
|
+
if (fileInputRef.current) {
|
|
156
|
+
fileInputRef.current.value = '';
|
|
157
|
+
}
|
|
158
|
+
return [7 /*endfinally*/];
|
|
159
|
+
case 5: return [2 /*return*/];
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}); };
|
|
163
|
+
var handleRemoveAttachment = function (fileName) {
|
|
164
|
+
setAttachments(function (prev) { return prev.filter(function (att) { return att.file.name !== fileName; }); });
|
|
165
|
+
};
|
|
166
|
+
var clearAttachments = function () {
|
|
167
|
+
setAttachments([]);
|
|
168
|
+
if (fileInputRef.current) {
|
|
169
|
+
fileInputRef.current.value = '';
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
return {
|
|
173
|
+
attachments: attachments,
|
|
174
|
+
setAttachments: setAttachments,
|
|
175
|
+
uploadingFiles: uploadingFiles,
|
|
176
|
+
fileErrorToast: fileErrorToast,
|
|
177
|
+
fileInputRef: fileInputRef,
|
|
178
|
+
handleFileChange: handleFileChange,
|
|
179
|
+
handleRemoveAttachment: handleRemoveAttachment,
|
|
180
|
+
clearAttachments: clearAttachments,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlRmlsZUF0dGFjaG1lbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hvb2tzL3VzZUZpbGVBdHRhY2htZW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLE9BQU8sQ0FBQztBQVFwRCxNQUFNLFVBQVUsa0JBQWtCLENBQUMsRUFBNEM7SUFBL0UsaUJBK0dDO1FBL0dvQyxVQUFVLGdCQUFBLEVBQUUsQ0FBQyxPQUFBO0lBQzFDLElBQUEsS0FBZ0MsUUFBUSxDQUF1QixFQUFFLENBQUMsRUFBakUsV0FBVyxRQUFBLEVBQUUsY0FBYyxRQUFzQyxDQUFDO0lBQ25FLElBQUEsS0FBc0MsUUFBUSxDQUFjLElBQUksR0FBRyxFQUFFLENBQUMsRUFBckUsY0FBYyxRQUFBLEVBQUUsaUJBQWlCLFFBQW9DLENBQUM7SUFDdkUsSUFBQSxLQUFzQyxRQUFRLENBQWdCLElBQUksQ0FBQyxFQUFsRSxjQUFjLFFBQUEsRUFBRSxpQkFBaUIsUUFBaUMsQ0FBQztJQUMxRSxJQUFNLHdCQUF3QixHQUFHLE1BQU0sQ0FBdUMsSUFBSSxDQUFDLENBQUM7SUFDcEYsSUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFtQixJQUFJLENBQUMsQ0FBQztJQUVwRCxTQUFTLENBQUM7UUFDUixPQUFPO1lBQ0wsSUFBSSx3QkFBd0IsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDckMsWUFBWSxDQUFDLHdCQUF3QixDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ2pELENBQUM7UUFDSCxDQUFDLENBQUM7SUFDSixDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFUCxJQUFNLGdCQUFnQixHQUFHLFVBQU8sQ0FBc0M7Ozs7Ozt5QkFDaEUsQ0FBQSxDQUFDLENBQUMsTUFBTSxDQUFDLEtB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QyxPQUFPLEVBQUUsQ0FBQzt3QkFDekIsWUFBWSxDQUFDLE9BQVEsQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO29CQUNuQyxDQUFDOzs7OztTQUdOLENBQUM7SUFFRixJQUFNLHNCQUFzQixHQUFHLFVBQUMsUUFBZ0I7UUFDOUMsY0FBYyxDQUFDLFVBQUEsSUFBSSxJQUFJLE9BQUEsSUFBSSxDQUFDLE1BQU0sQ0FBQyxVQUFBLEdBQUcsSUFBSSxPQUFBLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLFFBQVEsRUFBMUIsQ0FBMEIsQ0FBQyxFQUE5QyxDQUE4QyxDQUFDLENBQUM7SUFDekUsQ0FBQyxDQUFDO0lBRUYsSUFBTSxnQkFBZ0IsR0FBRztRQUN2QixjQUFjLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbkIsSUFBSSxZQUFZLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekIsWUFBWSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBQ2xDLENBQUM7SUFDSCxDQUFDLENBQUM7SUFFRixPQUFPO1FBQ0wsV0FBVyxhQUFBO1FBQ1gsY0FBYyxnQkFBQTtRQUNkLGNBQWMsZ0JBQUE7UUFDZCxjQUFjLGdCQUFBO1FBQ2QsWUFBWSxjQUFBO1FBQ1osZ0JBQWdCLGtCQUFBO1FBQ2hCLHNCQUFzQix3QkFBQTtRQUN0QixnQkFBZ0Isa0JBQUE7S0FDakIsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB1c2VTdGF0ZSwgdXNlUmVmLCB1c2VFZmZlY3QgfSBmcm9tICdyZWFjdCc7XG5pbXBvcnQgeyBBdHRhY2htZW50LCBBdHRhY2htZW50V2l0aEZpbGUgfSBmcm9tICcuLi90eXBlcyc7XG5cbmludGVyZmFjZSBVc2VGaWxlQXR0YWNobWVudHNPcHRpb25zIHtcbiAgdXBsb2FkRmlsZTogKGZpbGU6IEZpbGUpID0+IFByb21pc2U8QXR0YWNobWVudCB8IG51bGw+O1xuICB0OiAoa2V5OiBzdHJpbmcsIGZhbGxiYWNrPzogc3RyaW5nKSA9PiBzdHJpbmc7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB1c2VGaWxlQXR0YWNobWVudHMoeyB1cGxvYWRGaWxlLCB0IH06IFVzZUZpbGVBdHRhY2htZW50c09wdGlvbnMpIHtcbiAgY29uc3QgW2F0dGFjaG1lbnRzLCBzZXRBdHRhY2htZW50c10gPSB1c2VTdGF0ZTxBdHRhY2htZW50V2l0aEZpbGVbXT4oW10pO1xuICBjb25zdCBbdXBsb2FkaW5nRmlsZXMsIHNldFVwbG9hZGluZ0ZpbGVzXSA9IHVzZVN0YXRlPFNldDxzdHJpbmc+PihuZXcgU2V0KCkpO1xuICBjb25zdCBbZmlsZUVycm9yVG9hc3QsIHNldEZpbGVFcnJvclRvYXN0XSA9IHVzZVN0YXRlPHN0cmluZyB8IG51bGw+KG51bGwpO1xuICBjb25zdCBmaWxlRXJyb3JUb2FzdFRpbWVvdXRSZWYgPSB1c2VSZWY8UmV0dXJuVHlwZTx0eXBlb2Ygc2V0VGltZW91dD4gfCBudWxsPihudWxsKTtcbiAgY29uc3QgZmlsZUlucHV0UmVmID0gdXNlUmVmPEhUTUxJbnB1dEVsZW1lbnQ+KG51bGwpO1xuXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgcmV0dXJuICgpID0+IHtcbiAgICAgIGlmIChmaWxlRXJyb3JUb2FzdFRpbWVvdXRSZWYuY3VycmVudCkge1xuICAgICAgICBjbGVhclRpbWVvdXQoZmlsZUVycm9yVG9hc3RUaW1lb3V0UmVmLmN1cnJlbnQpO1xuICAgICAgfVxuICAgIH07XG4gIH0sIFtdKTtcblxuICBjb25zdCBoYW5kbGVGaWxlQ2hhbmdlID0gYXN5bmMgKGU6IFJlYWN0LkNoYW5nZUV2ZW50PEhUTUxJbnB1dEVsZW1lbnQ+KSA9PiB7XG4gICAgaWYgKGUudGFyZ2V0LmZpbGVzICYmIGUudGFyZ2V0LmZpbGVzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnN0IG5ld0ZpbGVzID0gQXJyYXkuZnJvbShlLnRhcmdldC5maWxlcyk7XG5cbiAgICAgIGNvbnN0IG5ld0F0dGFjaG1lbnRzOiBBdHRhY2htZW50V2l0aEZpbGVbXSA9IG5ld0ZpbGVzLm1hcChmaWxlID0+ICh7IGZpbGUsIGF0dGFjaG1lbnQ6IG51bGwgfSkpO1xuICAgICAgc2V0QXR0YWNobWVudHMocHJldiA9PiBbLi4ucHJldiwgLi4ubmV3QXR0YWNobWVudHNdKTtcblxuICAgICAgY29uc3QgbmV3VXBsb2FkaW5nRmlsZXMgPSBuZXcgU2V0KHVwbG9hZGluZ0ZpbGVzKTtcbiAgICAgIG5ld0ZpbGVzLmZvckVhY2goZmlsZSA9PiBuZXdVcGxvYWRpbmdGaWxlcy5hZGQoZmlsZS5uYW1lKSk7XG4gICAgICBzZXRVcGxvYWRpbmdGaWxlcyhuZXdVcGxvYWRpbmdGaWxlcyk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHNldHRsZWQgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoXG4gICAgICAgICAgbmV3RmlsZXMubWFwKGFzeW5jIChmaWxlKSA9PiAoeyBmaWxlLCBhdHRhY2htZW50OiBhd2FpdCB1cGxvYWRGaWxlKGZpbGUpIH0pKVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IGZpbGVUb0F0dGFjaG1lbnRNYXAgPSBuZXcgTWFwPHN0cmluZywgQXR0YWNobWVudCB8IG51bGw+KCk7XG4gICAgICAgIGNvbnN0IGZhaWxlZEZpbGVLZXlzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgICAgIHNldHRsZWQuZm9yRWFjaCgocmVzdWx0LCBpbmRleCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGZpbGUgPSBuZXdGaWxlc1tpbmRleF07XG4gICAgICAgICAgaWYgKCFmaWxlKSByZXR1cm47XG4gICAgICAgICAgY29uc3QgZmlsZUtleSA9IGAke2ZpbGUubmFtZX06JHtmaWxlLnNpemV9OiR7ZmlsZS5sYXN0TW9kaWZpZWR9YDtcbiAgICAgICAgICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gJ3JlamVjdGVkJykge1xuICAgICAgICAgICAgZmlsZVRvQXR0YWNobWVudE1hcC5zZXQoZmlsZUtleSwgbnVsbCk7XG4gICAgICAgICAgICBmYWlsZWRGaWxlS2V5cy5hZGQoZmlsZUtleSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbnN0IHsgYXR0YWNobWVudCB9ID0gcmVzdWx0LnZhbHVlO1xuICAgICAgICAgIGZpbGVUb0F0dGFjaG1lbnRNYXAuc2V0KGZpbGVLZXksIGF0dGFjaG1lbnQpO1xuICAgICAgICAgIGlmIChhdHRhY2htZW50ID09PSBudWxsKSB7XG4gICAgICAgICAgICBmYWlsZWRGaWxlS2V5cy5hZGQoZmlsZUtleSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBoYXNGYWlsZWRVcGxvYWRzID0gZmFpbGVkRmlsZUtleXMuc2l6ZSA+IDA7XG5cbiAgICAgICAgc2V0QXR0YWNobWVudHMocHJldiA9PiB7XG4gICAgICAgICAgcmV0dXJuIHByZXZcbiAgICAgICAgICAgIC5maWx0ZXIoYXR0ID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgZmlsZUtleSA9IGAke2F0dC5maWxlLm5hbWV9OiR7YXR0LmZpbGUuc2l6ZX06JHthdHQuZmlsZS5sYXN0TW9kaWZpZWR9YDtcbiAgICAgICAgICAgICAgcmV0dXJuICFmYWlsZWRGaWxlS2V5cy5oYXMoZmlsZUtleSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLm1hcChhdHQgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBmaWxlS2V5ID0gYCR7YXR0LmZpbGUubmFtZX06JHthdHQuZmlsZS5zaXplfToke2F0dC5maWxlLmxhc3RNb2RpZmllZH1gO1xuICAgICAgICAgICAgICBjb25zdCB1cGxvYWRlZEF0dGFjaG1lbnQgPSBmaWxlVG9BdHRhY2htZW50TWFwLmdldChmaWxlS2V5KTtcbiAgICAgICAgICAgICAgaWYgKHVwbG9hZGVkQXR0YWNobWVudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHsgLi4uYXR0LCBhdHRhY2htZW50OiB1cGxvYWRlZEF0dGFjaG1lbnQgfTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gYXR0O1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChoYXNGYWlsZWRVcGxvYWRzKSB7XG4gICAgICAgICAgaWYgKGZpbGVFcnJvclRvYXN0VGltZW91dFJlZi5jdXJyZW50KSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQoZmlsZUVycm9yVG9hc3RUaW1lb3V0UmVmLmN1cnJlbnQpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBzZXRGaWxlRXJyb3JUb2FzdCh0KCdmaWxlVXBsb2FkLmZpbGVUeXBlTm90U3VwcG9ydGVkJywgJ1RoaXMgZmlsZSB0eXBlIGlzIG5vdCBzdXBwb3J0ZWQuJykpO1xuICAgICAgICAgIGZpbGVFcnJvclRvYXN0VGltZW91dFJlZi5jdXJyZW50ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICBzZXRGaWxlRXJyb3JUb2FzdChudWxsKTtcbiAgICAgICAgICAgIGZpbGVFcnJvclRvYXN0VGltZW91dFJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICAgICAgICB9LCA0MDAwKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignRXJyb3IgdXBsb2FkaW5nIGZpbGUnLCBlcnJvcik7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBjb25zdCBmaW5hbFVwbG9hZGluZ0ZpbGVzID0gbmV3IFNldCh1cGxvYWRpbmdGaWxlcyk7XG4gICAgICAgIG5ld0ZpbGVzLmZvckVhY2goZmlsZSA9PiBmaW5hbFVwbG9hZGluZ0ZpbGVzLmRlbGV0ZShmaWxlLm5hbWUpKTtcbiAgICAgICAgc2V0VXBsb2FkaW5nRmlsZXMoZmluYWxVcGxvYWRpbmdGaWxlcyk7XG4gICAgICAgIGlmIChmaWxlSW5wdXRSZWYuY3VycmVudCkge1xuICAgICAgICAgIGZpbGVJbnB1dFJlZi5jdXJyZW50IS52YWx1ZSA9ICcnO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IGhhbmRsZVJlbW92ZUF0dGFjaG1lbnQgPSAoZmlsZU5hbWU6IHN0cmluZykgPT4ge1xuICAgIHNldEF0dGFjaG1lbnRzKHByZXYgPT4gcHJldi5maWx0ZXIoYXR0ID0+IGF0dC5maWxlLm5hbWUgIT09IGZpbGVOYW1lKSk7XG4gIH07XG5cbiAgY29uc3QgY2xlYXJBdHRhY2htZW50cyA9ICgpID0+IHtcbiAgICBzZXRBdHRhY2htZW50cyhbXSk7XG4gICAgaWYgKGZpbGVJbnB1dFJlZi5jdXJyZW50KSB7XG4gICAgICBmaWxlSW5wdXRSZWYuY3VycmVudC52YWx1ZSA9ICcnO1xuICAgIH1cbiAgfTtcblxuICByZXR1cm4ge1xuICAgIGF0dGFjaG1lbnRzLFxuICAgIHNldEF0dGFjaG1lbnRzLFxuICAgIHVwbG9hZGluZ0ZpbGVzLFxuICAgIGZpbGVFcnJvclRvYXN0LFxuICAgIGZpbGVJbnB1dFJlZixcbiAgICBoYW5kbGVGaWxlQ2hhbmdlLFxuICAgIGhhbmRsZVJlbW92ZUF0dGFjaG1lbnQsXG4gICAgY2xlYXJBdHRhY2htZW50cyxcbiAgfTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export type LiveVoiceStatus = 'idle' | 'connecting' | 'listening' | 'speaking' | 'error';
|
|
2
|
+
interface UseLiveVoiceOptions {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
apiKey: string;
|
|
5
|
+
guestToken?: string | null;
|
|
6
|
+
tenant?: string;
|
|
7
|
+
agentId?: string | null;
|
|
8
|
+
conversationId?: string | null;
|
|
9
|
+
language?: string;
|
|
10
|
+
onError?: (error: Error) => void;
|
|
11
|
+
onInputTranscript?: (text: string) => void;
|
|
12
|
+
onOutputTranscript?: (text: string) => void;
|
|
13
|
+
onTurnComplete?: (turn: {
|
|
14
|
+
transcript: string;
|
|
15
|
+
response: string;
|
|
16
|
+
}) => void;
|
|
17
|
+
}
|
|
18
|
+
interface UseLiveVoiceReturn {
|
|
19
|
+
isActive: boolean;
|
|
20
|
+
status: LiveVoiceStatus;
|
|
21
|
+
start: () => Promise<void>;
|
|
22
|
+
stop: () => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Continuous, two-way voice conversation with a Voice Agent node.
|
|
26
|
+
*
|
|
27
|
+
* Streams 16 kHz mic PCM up a WebSocket to a persistent Gemini Live session and
|
|
28
|
+
* plays the 24 kHz reply audio back as it arrives (no record/stop/send). Supports
|
|
29
|
+
* barge-in: when the agent is interrupted, queued playback is flushed instantly.
|
|
30
|
+
*/
|
|
31
|
+
export declare function useLiveVoice(opts: UseLiveVoiceOptions): UseLiveVoiceReturn;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
38
|
+
import { createWebSocket } from '../utils/websocket';
|
|
39
|
+
var LIVE_INPUT_SAMPLE_RATE = 16000; // Gemini Live expects 16 kHz mono PCM in
|
|
40
|
+
var LIVE_OUTPUT_SAMPLE_RATE = 24000; // Gemini Live emits 24 kHz mono PCM out
|
|
41
|
+
var CAPTURE_BUFFER_SIZE = 4096;
|
|
42
|
+
/** Downsample a mono Float32 buffer to 16 kHz Int16 PCM (little-endian). */
|
|
43
|
+
function floatTo16kPcm(input, inputRate) {
|
|
44
|
+
var ratio = inputRate / LIVE_INPUT_SAMPLE_RATE;
|
|
45
|
+
var outLength = Math.floor(input.length / ratio);
|
|
46
|
+
var out = new Int16Array(outLength);
|
|
47
|
+
for (var i = 0; i < outLength; i++) {
|
|
48
|
+
var sample = input[Math.floor(i * ratio)] || 0;
|
|
49
|
+
var clamped = Math.max(-1, Math.min(1, sample));
|
|
50
|
+
out[i] = clamped < 0 ? clamped * 0x8000 : clamped * 0x7fff;
|
|
51
|
+
}
|
|
52
|
+
return out.buffer;
|
|
53
|
+
}
|
|
54
|
+
function buildLiveUrl(opts, threadId) {
|
|
55
|
+
// Live voice is a stateful 1:1 audio stream held by the backend, so the plugin
|
|
56
|
+
// connects directly to the backend (not the fan-out websocket service).
|
|
57
|
+
var wsBase = opts.baseUrl.replace(/^http/, 'ws').replace(/\/$/, '');
|
|
58
|
+
var auth = opts.guestToken
|
|
59
|
+
? "access_token=".concat(encodeURIComponent(opts.guestToken))
|
|
60
|
+
: "api_key=".concat(encodeURIComponent(opts.apiKey));
|
|
61
|
+
var params = [auth, "thread_id=".concat(encodeURIComponent(threadId))];
|
|
62
|
+
if (opts.tenant)
|
|
63
|
+
params.push("x-tenant-id=".concat(encodeURIComponent(opts.tenant)));
|
|
64
|
+
if (opts.language)
|
|
65
|
+
params.push("lang=".concat(encodeURIComponent(opts.language)));
|
|
66
|
+
return "".concat(wsBase, "/api/voice/live/").concat(opts.agentId, "?").concat(params.join('&'));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Continuous, two-way voice conversation with a Voice Agent node.
|
|
70
|
+
*
|
|
71
|
+
* Streams 16 kHz mic PCM up a WebSocket to a persistent Gemini Live session and
|
|
72
|
+
* plays the 24 kHz reply audio back as it arrives (no record/stop/send). Supports
|
|
73
|
+
* barge-in: when the agent is interrupted, queued playback is flushed instantly.
|
|
74
|
+
*/
|
|
75
|
+
export function useLiveVoice(opts) {
|
|
76
|
+
var _this = this;
|
|
77
|
+
var _a = useState(false), isActive = _a[0], setIsActive = _a[1];
|
|
78
|
+
var _b = useState('idle'), status = _b[0], setStatus = _b[1];
|
|
79
|
+
var wsRef = useRef(null);
|
|
80
|
+
var streamRef = useRef(null);
|
|
81
|
+
var captureCtxRef = useRef(null);
|
|
82
|
+
var processorRef = useRef(null);
|
|
83
|
+
var playbackCtxRef = useRef(null);
|
|
84
|
+
var playheadRef = useRef(0);
|
|
85
|
+
var sourcesRef = useRef([]);
|
|
86
|
+
var speakingTimerRef = useRef(null);
|
|
87
|
+
// Mirror `isActive` into a ref so async callbacks (e.g. the speaking timer)
|
|
88
|
+
// can read the latest value without being re-created.
|
|
89
|
+
var isActiveRef = useRef(false);
|
|
90
|
+
isActiveRef.current = isActive;
|
|
91
|
+
// Keep the latest callbacks without re-creating start/stop.
|
|
92
|
+
var optsRef = useRef(opts);
|
|
93
|
+
optsRef.current = opts;
|
|
94
|
+
var flushPlayback = useCallback(function () {
|
|
95
|
+
sourcesRef.current.forEach(function (src) {
|
|
96
|
+
try {
|
|
97
|
+
src.stop();
|
|
98
|
+
}
|
|
99
|
+
catch (_a) {
|
|
100
|
+
/* already stopped */
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
sourcesRef.current = [];
|
|
104
|
+
if (playbackCtxRef.current) {
|
|
105
|
+
playheadRef.current = playbackCtxRef.current.currentTime;
|
|
106
|
+
}
|
|
107
|
+
}, []);
|
|
108
|
+
var stop = useCallback(function () {
|
|
109
|
+
var _a, _b, _c, _d;
|
|
110
|
+
if (speakingTimerRef.current)
|
|
111
|
+
clearTimeout(speakingTimerRef.current);
|
|
112
|
+
flushPlayback();
|
|
113
|
+
(_a = processorRef.current) === null || _a === void 0 ? void 0 : _a.disconnect();
|
|
114
|
+
processorRef.current = null;
|
|
115
|
+
(_b = streamRef.current) === null || _b === void 0 ? void 0 : _b.getTracks().forEach(function (t) { return t.stop(); });
|
|
116
|
+
streamRef.current = null;
|
|
117
|
+
(_c = captureCtxRef.current) === null || _c === void 0 ? void 0 : _c.close().catch(function () { return undefined; });
|
|
118
|
+
captureCtxRef.current = null;
|
|
119
|
+
(_d = playbackCtxRef.current) === null || _d === void 0 ? void 0 : _d.close().catch(function () { return undefined; });
|
|
120
|
+
playbackCtxRef.current = null;
|
|
121
|
+
if (wsRef.current) {
|
|
122
|
+
wsRef.current.onclose = null;
|
|
123
|
+
try {
|
|
124
|
+
wsRef.current.close();
|
|
125
|
+
}
|
|
126
|
+
catch (_e) {
|
|
127
|
+
/* noop */
|
|
128
|
+
}
|
|
129
|
+
wsRef.current = null;
|
|
130
|
+
}
|
|
131
|
+
setIsActive(false);
|
|
132
|
+
setStatus('idle');
|
|
133
|
+
}, [flushPlayback]);
|
|
134
|
+
var playPcmChunk = useCallback(function (pcm) {
|
|
135
|
+
var ctx = playbackCtxRef.current;
|
|
136
|
+
if (!ctx)
|
|
137
|
+
return;
|
|
138
|
+
var ints = new Int16Array(pcm);
|
|
139
|
+
if (ints.length === 0)
|
|
140
|
+
return;
|
|
141
|
+
var floats = new Float32Array(ints.length);
|
|
142
|
+
for (var i = 0; i < ints.length; i++)
|
|
143
|
+
floats[i] = ints[i] / 0x8000;
|
|
144
|
+
var buffer = ctx.createBuffer(1, floats.length, LIVE_OUTPUT_SAMPLE_RATE);
|
|
145
|
+
buffer.copyToChannel(floats, 0);
|
|
146
|
+
var source = ctx.createBufferSource();
|
|
147
|
+
source.buffer = buffer;
|
|
148
|
+
source.connect(ctx.destination);
|
|
149
|
+
var startAt = Math.max(ctx.currentTime, playheadRef.current);
|
|
150
|
+
source.start(startAt);
|
|
151
|
+
playheadRef.current = startAt + buffer.duration;
|
|
152
|
+
sourcesRef.current.push(source);
|
|
153
|
+
source.onended = function () {
|
|
154
|
+
sourcesRef.current = sourcesRef.current.filter(function (s) { return s !== source; });
|
|
155
|
+
};
|
|
156
|
+
// Reflect "speaking" until the scheduled audio drains.
|
|
157
|
+
setStatus('speaking');
|
|
158
|
+
if (speakingTimerRef.current)
|
|
159
|
+
clearTimeout(speakingTimerRef.current);
|
|
160
|
+
var remainingMs = (playheadRef.current - ctx.currentTime) * 1000 + 150;
|
|
161
|
+
speakingTimerRef.current = setTimeout(function () {
|
|
162
|
+
if (isActiveRef.current)
|
|
163
|
+
setStatus('listening');
|
|
164
|
+
}, remainingMs);
|
|
165
|
+
}, []);
|
|
166
|
+
var handleEvent = useCallback(function (data) {
|
|
167
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
168
|
+
var cb = optsRef.current;
|
|
169
|
+
switch (data.type) {
|
|
170
|
+
case 'ready':
|
|
171
|
+
setStatus('listening');
|
|
172
|
+
break;
|
|
173
|
+
case 'input_transcript':
|
|
174
|
+
if (typeof data.text === 'string')
|
|
175
|
+
(_a = cb.onInputTranscript) === null || _a === void 0 ? void 0 : _a.call(cb, data.text);
|
|
176
|
+
break;
|
|
177
|
+
case 'output_transcript':
|
|
178
|
+
if (typeof data.text === 'string')
|
|
179
|
+
(_b = cb.onOutputTranscript) === null || _b === void 0 ? void 0 : _b.call(cb, data.text);
|
|
180
|
+
break;
|
|
181
|
+
case 'interrupted':
|
|
182
|
+
flushPlayback();
|
|
183
|
+
setStatus('listening');
|
|
184
|
+
break;
|
|
185
|
+
case 'turn_complete':
|
|
186
|
+
(_c = cb.onTurnComplete) === null || _c === void 0 ? void 0 : _c.call(cb, {
|
|
187
|
+
transcript: String((_d = data.transcript) !== null && _d !== void 0 ? _d : ''),
|
|
188
|
+
response: String((_e = data.response) !== null && _e !== void 0 ? _e : ''),
|
|
189
|
+
});
|
|
190
|
+
break;
|
|
191
|
+
case 'error':
|
|
192
|
+
(_f = cb.onError) === null || _f === void 0 ? void 0 : _f.call(cb, new Error(String((_g = data.message) !== null && _g !== void 0 ? _g : 'Live voice error')));
|
|
193
|
+
setStatus('error');
|
|
194
|
+
break;
|
|
195
|
+
default:
|
|
196
|
+
break;
|
|
197
|
+
}
|
|
198
|
+
}, [flushPlayback]);
|
|
199
|
+
var start = useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
|
|
200
|
+
var cb, threadId, stream_1, AudioCtx, captureCtx_1, ws_1, err_1;
|
|
201
|
+
var _a, _b;
|
|
202
|
+
return __generator(this, function (_c) {
|
|
203
|
+
switch (_c.label) {
|
|
204
|
+
case 0:
|
|
205
|
+
cb = optsRef.current;
|
|
206
|
+
if (!cb.agentId) {
|
|
207
|
+
(_a = cb.onError) === null || _a === void 0 ? void 0 : _a.call(cb, new Error('Live voice unavailable: agent is still loading'));
|
|
208
|
+
return [2 /*return*/];
|
|
209
|
+
}
|
|
210
|
+
if (wsRef.current)
|
|
211
|
+
return [2 /*return*/]; // already active
|
|
212
|
+
setStatus('connecting');
|
|
213
|
+
// Persistence (transcript/dashboard) keys off an existing conversation UUID.
|
|
214
|
+
// Without one the call still works, but the backend skips saving the turns.
|
|
215
|
+
if (!cb.conversationId) {
|
|
216
|
+
console.warn('[useLiveVoice] No conversationId yet — the live call will run but its ' +
|
|
217
|
+
'transcripts will not be persisted.');
|
|
218
|
+
}
|
|
219
|
+
threadId = cb.conversationId ||
|
|
220
|
+
(typeof crypto !== 'undefined' && 'randomUUID' in crypto
|
|
221
|
+
? crypto.randomUUID()
|
|
222
|
+
: "live-".concat(Date.now()));
|
|
223
|
+
_c.label = 1;
|
|
224
|
+
case 1:
|
|
225
|
+
_c.trys.push([1, 3, , 4]);
|
|
226
|
+
return [4 /*yield*/, navigator.mediaDevices.getUserMedia({
|
|
227
|
+
audio: { channelCount: 1, echoCancellation: true, noiseSuppression: true },
|
|
228
|
+
})];
|
|
229
|
+
case 2:
|
|
230
|
+
stream_1 = _c.sent();
|
|
231
|
+
streamRef.current = stream_1;
|
|
232
|
+
AudioCtx = window.AudioContext ||
|
|
233
|
+
window.webkitAudioContext;
|
|
234
|
+
captureCtx_1 = new AudioCtx();
|
|
235
|
+
captureCtxRef.current = captureCtx_1;
|
|
236
|
+
playbackCtxRef.current = new AudioCtx();
|
|
237
|
+
playheadRef.current = playbackCtxRef.current.currentTime;
|
|
238
|
+
ws_1 = createWebSocket(buildLiveUrl(cb, threadId));
|
|
239
|
+
ws_1.binaryType = 'arraybuffer';
|
|
240
|
+
wsRef.current = ws_1;
|
|
241
|
+
ws_1.onopen = function () {
|
|
242
|
+
var source = captureCtx_1.createMediaStreamSource(stream_1);
|
|
243
|
+
// TODO: migrate to AudioWorklet — ScriptProcessorNode is deprecated and
|
|
244
|
+
// runs the downsample on the main thread (can jank on slow devices).
|
|
245
|
+
var processor = captureCtx_1.createScriptProcessor(CAPTURE_BUFFER_SIZE, 1, 1);
|
|
246
|
+
processorRef.current = processor;
|
|
247
|
+
processor.onaudioprocess = function (e) {
|
|
248
|
+
if (ws_1.readyState !== ws_1.OPEN)
|
|
249
|
+
return;
|
|
250
|
+
var pcm = floatTo16kPcm(e.inputBuffer.getChannelData(0), captureCtx_1.sampleRate);
|
|
251
|
+
ws_1.send(pcm);
|
|
252
|
+
};
|
|
253
|
+
source.connect(processor);
|
|
254
|
+
processor.connect(captureCtx_1.destination); // required to drive onaudioprocess
|
|
255
|
+
setIsActive(true);
|
|
256
|
+
setStatus('listening');
|
|
257
|
+
};
|
|
258
|
+
ws_1.onmessage = function (event) {
|
|
259
|
+
if (event.data instanceof ArrayBuffer) {
|
|
260
|
+
playPcmChunk(event.data);
|
|
261
|
+
}
|
|
262
|
+
else if (typeof event.data === 'string') {
|
|
263
|
+
try {
|
|
264
|
+
handleEvent(JSON.parse(event.data));
|
|
265
|
+
}
|
|
266
|
+
catch (_a) {
|
|
267
|
+
/* ignore malformed event */
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
ws_1.onerror = function () {
|
|
272
|
+
var _a;
|
|
273
|
+
(_a = cb.onError) === null || _a === void 0 ? void 0 : _a.call(cb, new Error('Live voice connection error'));
|
|
274
|
+
};
|
|
275
|
+
ws_1.onclose = function () {
|
|
276
|
+
stop();
|
|
277
|
+
};
|
|
278
|
+
return [3 /*break*/, 4];
|
|
279
|
+
case 3:
|
|
280
|
+
err_1 = _c.sent();
|
|
281
|
+
(_b = cb.onError) === null || _b === void 0 ? void 0 : _b.call(cb, err_1 instanceof Error ? err_1 : new Error(String(err_1)));
|
|
282
|
+
stop();
|
|
283
|
+
return [3 /*break*/, 4];
|
|
284
|
+
case 4: return [2 /*return*/];
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
}); }, [handleEvent, playPcmChunk, stop]);
|
|
288
|
+
// Tear down on unmount.
|
|
289
|
+
useEffect(function () { return function () { return stop(); }; }, [stop]);
|
|
290
|
+
return { isActive: isActive, status: status, start: start, stop: stop };
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlTGl2ZVZvaWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2hvb2tzL3VzZUxpdmVWb2ljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLE1BQU0sT0FBTyxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxJQUFNLHNCQUFzQixHQUFHLEtBQUssQ0FBQyxDQUFDLHlDQUF5QztBQUMvRSxJQUFNLHVCQUF1QixHQUFHLEtBQUssQ0FBQyxDQUFDLHdDQUF3QztBQUMvRSxJQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQztBQWlDakMsNEVBQTRFO0FBQzVFLFNBQVMsYUFBYSxDQUFDLEtBQW1CLEVBQUUsU0FBaUI7SUFDM0QsSUFBTSxLQUFLLEdBQUcsU0FBUyxHQUFHLHNCQUFzQixDQUFDO0lBQ2pELElBQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQztJQUNuRCxJQUFNLEdBQUcsR0FBRyxJQUFJLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN0QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDbkMsSUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2pELElBQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUNsRCxHQUFH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T0FBQSxFQUFFLElBQUksTUFBQSxFQUFFLENBQUM7QUFDM0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHVzZUNhbGxiYWNrLCB1c2VFZmZlY3QsIHVzZVJlZiwgdXNlU3RhdGUgfSBmcm9tICdyZWFjdCc7XG5pbXBvcnQgeyBjcmVhdGVXZWJTb2NrZXQgfSBmcm9tICcuLi91dGlscy93ZWJzb2NrZXQnO1xuXG5jb25zdCBMSVZFX0lOUFVUX1NBTVBMRV9SQVRFID0gMTYwMDA7IC8vIEdlbWluaSBMaXZlIGV4cGVjdHMgMTYga0h6IG1vbm8gUENNIGluXG5jb25zdCBMSVZFX09VVFBVVF9TQU1QTEVfUkFURSA9IDI0MDAwOyAvLyBHZW1pbmkgTGl2ZSBlbWl0cyAyNCBrSHogbW9ubyBQQ00gb3V0XG5jb25zdCBDQVBUVVJFX0JVRkZFUl9TSVpFID0gNDA5NjtcblxuZXhwb3J0IHR5cGUgTGl2ZVZvaWNlU3RhdHVzID1cbiAgfCAnaWRsZSdcbiAgfCAnY29ubmVjdGluZydcbiAgfCAnbGlzdGVuaW5nJ1xuICB8ICdzcGVha2luZydcbiAgfCAnZXJyb3InO1xuXG5pbnRlcmZhY2UgVXNlTGl2ZVZvaWNlT3B0aW9ucyB7XG4gIC8vIEJhY2tlbmQgYmFzZSBVUkwgKGh0dHAvaHR0cHMpLiBMaXZlIHZvaWNlIGlzIGEgc3RhdGVmdWwgMToxIGF1ZGlvIHN0cmVhbVxuICAvLyBoZWxkIGJ5IHRoZSBiYWNrZW5kLCBzbyB0aGUgcGx1Z2luIGNvbm5lY3RzIHRoZXJlIGRpcmVjdGx5ICh0aGUgZmFuLW91dFxuICAvLyB3ZWJzb2NrZXQgc2VydmljZSBpcyBub3QgaW52b2x2ZWQpLlxuICBiYXNlVXJsOiBzdHJpbmc7XG4gIGFwaUtleTogc3RyaW5nO1xuICBndWVzdFRva2VuPzogc3RyaW5nIHwgbnVsbDtcbiAgdGVuYW50Pzogc3RyaW5nO1xuICBhZ2VudElkPzogc3RyaW5nIHwgbnVsbDtcbiAgY29udmVyc2F0aW9uSWQ/OiBzdHJpbmcgfCBudWxsO1xuICBsYW5ndWFnZT86IHN0cmluZztcbiAgb25FcnJvcj86IChlcnJvcjogRXJyb3IpID0+IHZvaWQ7XG4gIG9uSW5wdXRUcmFuc2NyaXB0PzogKHRleHQ6IHN0cmluZykgPT4gdm9pZDtcbiAgb25PdXRwdXRUcmFuc2NyaXB0PzogKHRleHQ6IHN0cmluZykgPT4gdm9pZDtcbiAgb25UdXJuQ29tcGxldGU/OiAodHVybjogeyB0cmFuc2NyaXB0OiBzdHJpbmc7IHJlc3BvbnNlOiBzdHJpbmcgfSkgPT4gdm9pZDtcbn1cblxuaW50ZXJmYWNlIFVzZUxpdmVWb2ljZVJldHVybiB7XG4gIGlzQWN0aXZlOiBib29sZWFuO1xuICBzdGF0dXM6IExpdmVWb2ljZVN0YXR1cztcbiAgc3RhcnQ6ICgpID0+IFByb21pc2U8dm9pZD47XG4gIHN0b3A6ICgpID0+IHZvaWQ7XG59XG5cbi8qKiBEb3duc2FtcGxlIGEgbW9ubyBGbG9hdDMyIGJ1ZmZlciB0byAxNiBrSHogSW50MTYgUENNIChsaXR0bGUtZW5kaWFuKS4gKi9cbmZ1bmN0aW9uIGZsb2F0VG8xNmtQY20oaW5wdXQ6IEZsb2F0MzJBcnJheSwgaW5wdXRSYXRlOiBudW1iZXIpOiBBcnJheUJ1ZmZlciB7XG4gIGNvbnN0IHJhdGlvID0gaW5wdXRSYXRlIC8gTElWRV9JTlBVVF9TQU1QTEVfUkFURTtcbiAgY29uc3Qgb3V0TGVuZ3RoID0gTWF0aC5mbG9vcihpbnB1dC5sZW5ndGggLyByYXRpbyk7XG4gIGNvbnN0IG91dCA9IG5ldyBJbnQxNkFycmF5KG91dExlbmd0aCk7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgb3V0TGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBzYW1wbGUgPSBpbnB1dFtNYXRoLmZsb29yKGkgKiByYXRpbyldIHx8IDA7XG4gICAgY29uc3QgY2xhbXBlZCA9IE1hdGgubWF4KC0xLCBNYXRoLm1pbigxLCBzYW1wbGUpKTtcbiAgICBvdXRbaV0gPSBjbGFtcGVkIDwgMCA/IGNsYW1wZWQgKiAweDgwMDAgOiBjbGFtcGVkICogMHg3ZmZmO1xuICB9XG4gIHJldHVybiBvdXQuYnVmZmVyO1xufVxuXG5mdW5jdGlvbiBidWlsZExpdmVVcmwob3B0czogVXNlTGl2ZVZvaWNlT3B0aW9ucywgdGhyZWFkSWQ6IHN0cmluZyk6IHN0cmluZyB7XG4gIC8vIExpdmUgdm9pY2UgaXMgYSBzdGF0ZWZ1bCAxOjEgYXVkaW8gc3RyZWFtIGhlbGQgYnkgdGhlIGJhY2tlbmQsIHNvIHRoZSBwbHVnaW5cbiAgLy8gY29ubmVjdHMgZGlyZWN0bHkgdG8gdGhlIGJhY2tlbmQgKG5vdCB0aGUgZmFuLW91dCB3ZWJzb2NrZXQgc2VydmljZSkuXG4gIGNvbnN0IHdzQmFzZSA9IG9wdHMuYmFzZVVybC5yZXBsYWNlKC9eaHR0cC8sICd3cycpLnJlcGxhY2UoL1xcLyQvLCAnJyk7XG4gIGNvbnN0IGF1dGggPSBvcHRzLmd1ZXN0VG9rZW5cbiAgICA/IGBhY2Nlc3NfdG9rZW49JHtlbmNvZGVVUklDb21wb25lbnQob3B0cy5ndWVzdFRva2VuKX1gXG4gICAgOiBgYXBpX2tleT0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLmFwaUtleSl9YDtcbiAgY29uc3QgcGFyYW1zID0gW2F1dGgsIGB0aHJlYWRfaWQ9JHtlbmNvZGVVUklDb21wb25lbnQodGhyZWFkSWQpfWBdO1xuICBpZiAob3B0cy50ZW5hbnQpIHBhcmFtcy5wdXNoKGB4LXRlbmFudC1pZD0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLnRlbmFudCl9YCk7XG4gIGlmIChvcHRzLmxhbmd1YWdlKSBwYXJhbXMucHVzaChgbGFuZz0ke2VuY29kZVVSSUNvbXBvbmVudChvcHRzLmxhbmd1YWdlKX1gKTtcbiAgcmV0dXJuIGAke3dzQmFzZX0vYXBpL3ZvaWNlL2xpdmUvJHtvcHRzLmFnZW50SWR9PyR7cGFyYW1zLmpvaW4oJyYnKX1gO1xufVxuXG4vKipcbiAqIENvbnRpbnVvdXMsIHR3by13YXkgdm9pY2UgY29udmVyc2F0aW9uIHdpdGggYSBWb2ljZSBBZ2VudCBub2RlLlxuICpcbiAqIFN0cmVhbXMgMTYga0h6IG1pYyBQQ00gdXAgYSBXZWJTb2NrZXQgdG8gYSBwZXJzaXN0ZW50IEdlbWluaSBMaXZlIHNlc3Npb24gYW5kXG4gKiBwbGF5cyB0aGUgMjQga0h6IHJlcGx5IGF1ZGlvIGJhY2sgYXMgaXQgYXJyaXZlcyAobm8gcmVjb3JkL3N0b3Avc2VuZCkuIFN1cHBvcnRzXG4gKiBiYXJnZS1pbjogd2hlbiB0aGUgYWdlbnQgaXMgaW50ZXJydXB0ZWQsIHF1ZXVlZCBwbGF5YmFjayBpcyBmbHVzaGVkIGluc3RhbnRseS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZUxpdmVWb2ljZShvcHRzOiBVc2VMaXZlVm9pY2VPcHRpb25zKTogVXNlTGl2ZVZvaWNlUmV0dXJuIHtcbiAgY29uc3QgW2lzQWN0aXZlLCBzZXRJc0FjdGl2ZV0gPSB1c2VTdGF0ZShmYWxzZSk7XG4gIGNvbnN0IFtzdGF0dXMsIHNldFN0YXR1c10gPSB1c2VTdGF0ZTxMaXZlVm9pY2VTdGF0dXM+KCdpZGxlJyk7XG5cbiAgY29uc3Qgd3NSZWYgPSB1c2VSZWY8V2ViU29ja2V0IHwgbnVsbD4obnVsbCk7XG4gIGNvbnN0IHN0cmVhbVJlZiA9IHVzZVJlZjxNZWRpYVN0cmVhbSB8IG51bGw+KG51bGwpO1xuICBjb25zdCBjYXB0dXJlQ3R4UmVmID0gdXNlUmVmPEF1ZGlvQ29udGV4dCB8IG51bGw+KG51bGwpO1xuICBjb25zdCBwcm9jZXNzb3JSZWYgPSB1c2VSZWY8U2NyaXB0UHJvY2Vzc29yTm9kZSB8IG51bGw+KG51bGwpO1xuICBjb25zdCBwbGF5YmFja0N0eFJlZiA9IHVzZVJlZjxBdWRpb0NvbnRleHQgfCBudWxsPihudWxsKTtcbiAgY29uc3QgcGxheWhlYWRSZWYgPSB1c2VSZWY8bnVtYmVyPigwKTtcbiAgY29uc3Qgc291cmNlc1JlZiA9IHVzZVJlZjxBdWRpb0J1ZmZlclNvdXJjZU5vZGVbXT4oW10pO1xuICBjb25zdCBzcGVha2luZ1RpbWVyUmVmID0gdXNlUmVmPFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgbnVsbD4obnVsbCk7XG5cbiAgLy8gTWlycm9yIGBpc0FjdGl2ZWAgaW50byBhIHJlZiBzbyBhc3luYyBjYWxsYmFja3MgKGUuZy4gdGhlIHNwZWFraW5nIHRpbWVyKVxuICAvLyBjYW4gcmVhZCB0aGUgbGF0ZXN0IHZhbHVlIHdpdGhvdXQgYmVpbmcgcmUtY3JlYXRlZC5cbiAgY29uc3QgaXNBY3RpdmVSZWYgPSB1c2VSZWYoZmFsc2UpO1xuICBpc0FjdGl2ZVJlZi5jdXJyZW50ID0gaXNBY3RpdmU7XG5cbiAgLy8gS2VlcCB0aGUgbGF0ZXN0IGNhbGxiYWNrcyB3aXRob3V0IHJlLWNyZWF0aW5nIHN0YXJ0L3N0b3AuXG4gIGNvbnN0IG9wdHNSZWYgPSB1c2VSZWYob3B0cyk7XG4gIG9wdHNSZWYuY3VycmVudCA9IG9wdHM7XG5cbiAgY29uc3QgZmx1c2hQbGF5YmFjayA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICBzb3VyY2VzUmVmLmN1cnJlbnQuZm9yRWFjaCgoc3JjKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBzcmMuc3RvcCgpO1xuICAgICAgfSBjYXRjaCB7XG4gICAgICAgIC8qIGFscmVhZHkgc3RvcHBlZCAqL1xuICAgICAgfVxuICAgIH0pO1xuICAgIHNvdXJjZXNSZWYuY3VycmVudCA9IFtdO1xuICAgIGlmIChwbGF5YmFja0N0eFJlZi5jdXJyZW50KSB7XG4gICAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudC5jdXJyZW50VGltZTtcbiAgICB9XG4gIH0sIFtdKTtcblxuICBjb25zdCBzdG9wID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgIGlmIChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpIGNsZWFyVGltZW91dChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpO1xuICAgIGZsdXNoUGxheWJhY2soKTtcbiAgICBwcm9jZXNzb3JSZWYuY3VycmVudD8uZGlzY29ubmVjdCgpO1xuICAgIHByb2Nlc3NvclJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBzdHJlYW1SZWYuY3VycmVudD8uZ2V0VHJhY2tzKCkuZm9yRWFjaCgodCkgPT4gdC5zdG9wKCkpO1xuICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBjYXB0dXJlQ3R4UmVmLmN1cnJlbnQ/LmNsb3NlKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBjYXB0dXJlQ3R4UmVmLmN1cnJlbnQgPSBudWxsO1xuICAgIHBsYXliYWNrQ3R4UmVmLmN1cnJlbnQ/LmNsb3NlKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICBwbGF5YmFja0N0eFJlZi5jdXJyZW50ID0gbnVsbDtcbiAgICBpZiAod3NSZWYuY3VycmVudCkge1xuICAgICAgd3NSZWYuY3VycmVudC5vbmNsb3NlID0gbnVsbDtcbiAgICAgIHRyeSB7XG4gICAgICAgIHdzUmVmLmN1cnJlbnQuY2xvc2UoKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvKiBub29wICovXG4gICAgICB9XG4gICAgICB3c1JlZi5jdXJyZW50ID0gbnVsbDtcbiAgICB9XG4gICAgc2V0SXNBY3RpdmUoZmFsc2UpO1xuICAgIHNldFN0YXR1cygnaWRsZScpO1xuICB9LCBbZmx1c2hQbGF5YmFja10pO1xuXG4gIGNvbnN0IHBsYXlQY21DaHVuayA9IHVzZUNhbGxiYWNrKChwY206IEFycmF5QnVmZmVyKSA9PiB7XG4gICAgY29uc3QgY3R4ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudDtcbiAgICBpZiAoIWN0eCkgcmV0dXJuO1xuICAgIGNvbnN0IGludHMgPSBuZXcgSW50MTZBcnJheShwY20pO1xuICAgIGlmIChpbnRzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuICAgIGNvbnN0IGZsb2F0cyA9IG5ldyBGbG9hdDMyQXJyYXkoaW50cy5sZW5ndGgpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgaW50cy5sZW5ndGg7IGkrKykgZmxvYXRzW2ldID0gaW50c1tpXSAvIDB4ODAwMDtcblxuICAgIGNvbnN0IGJ1ZmZlciA9IGN0eC5jcmVhdGVCdWZmZXIoMSwgZmxvYXRzLmxlbmd0aCwgTElWRV9PVVRQVVRfU0FNUExFX1JBVEUpO1xuICAgIGJ1ZmZlci5jb3B5VG9DaGFubmVsKGZsb2F0cywgMCk7XG4gICAgY29uc3Qgc291cmNlID0gY3R4LmNyZWF0ZUJ1ZmZlclNvdXJjZSgpO1xuICAgIHNvdXJjZS5idWZmZXIgPSBidWZmZXI7XG4gICAgc291cmNlLmNvbm5lY3QoY3R4LmRlc3RpbmF0aW9uKTtcblxuICAgIGNvbnN0IHN0YXJ0QXQgPSBNYXRoLm1heChjdHguY3VycmVudFRpbWUsIHBsYXloZWFkUmVmLmN1cnJlbnQpO1xuICAgIHNvdXJjZS5zdGFydChzdGFydEF0KTtcbiAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gc3RhcnRBdCArIGJ1ZmZlci5kdXJhdGlvbjtcbiAgICBzb3VyY2VzUmVmLmN1cnJlbnQucHVzaChzb3VyY2UpO1xuICAgIHNvdXJjZS5vbmVuZGVkID0gKCkgPT4ge1xuICAgICAgc291cmNlc1JlZi5jdXJyZW50ID0gc291cmNlc1JlZi5jdXJyZW50LmZpbHRlcigocykgPT4gcyAhPT0gc291cmNlKTtcbiAgICB9O1xuXG4gICAgLy8gUmVmbGVjdCBcInNwZWFraW5nXCIgdW50aWwgdGhlIHNjaGVkdWxlZCBhdWRpbyBkcmFpbnMuXG4gICAgc2V0U3RhdHVzKCdzcGVha2luZycpO1xuICAgIGlmIChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpIGNsZWFyVGltZW91dChzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQpO1xuICAgIGNvbnN0IHJlbWFpbmluZ01zID0gKHBsYXloZWFkUmVmLmN1cnJlbnQgLSBjdHguY3VycmVudFRpbWUpICogMTAwMCArIDE1MDtcbiAgICBzcGVha2luZ1RpbWVyUmVmLmN1cnJlbnQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIGlmIChpc0FjdGl2ZVJlZi5jdXJyZW50KSBzZXRTdGF0dXMoJ2xpc3RlbmluZycpO1xuICAgIH0sIHJlbWFpbmluZ01zKTtcbiAgfSwgW10pO1xuXG4gIGNvbnN0IGhhbmRsZUV2ZW50ID0gdXNlQ2FsbGJhY2soKGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd24+KSA9PiB7XG4gICAgY29uc3QgY2IgPSBvcHRzUmVmLmN1cnJlbnQ7XG4gICAgc3dpdGNoIChkYXRhLnR5cGUpIHtcbiAgICAgIGNhc2UgJ3JlYWR5JzpcbiAgICAgICAgc2V0U3RhdHVzKCdsaXN0ZW5pbmcnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdpbnB1dF90cmFuc2NyaXB0JzpcbiAgICAgICAgaWYgKHR5cGVvZiBkYXRhLnRleHQgPT09ICdzdHJpbmcnKSBjYi5vbklucHV0VHJhbnNjcmlwdD8uKGRhdGEudGV4dCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnb3V0cHV0X3RyYW5zY3JpcHQnOlxuICAgICAgICBpZiAodHlwZW9mIGRhdGEudGV4dCA9PT0gJ3N0cmluZycpIGNiLm9uT3V0cHV0VHJhbnNjcmlwdD8uKGRhdGEudGV4dCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnaW50ZXJydXB0ZWQnOlxuICAgICAgICBmbHVzaFBsYXliYWNrKCk7XG4gICAgICAgIHNldFN0YXR1cygnbGlzdGVuaW5nJyk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAndHVybl9jb21wbGV0ZSc6XG4gICAgICAgIGNiLm9uVHVybkNvbXBsZXRlPy4oe1xuICAgICAgICAgIHRyYW5zY3JpcHQ6IFN0cmluZyhkYXRhLnRyYW5zY3JpcHQgPz8gJycpLFxuICAgICAgICAgIHJlc3BvbnNlOiBTdHJpbmcoZGF0YS5yZXNwb25zZSA/PyAnJyksXG4gICAgICAgIH0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2Vycm9yJzpcbiAgICAgICAgY2Iub25FcnJvcj8uKG5ldyBFcnJvcihTdHJpbmcoZGF0YS5tZXNzYWdlID8/ICdMaXZlIHZvaWNlIGVycm9yJykpKTtcbiAgICAgICAgc2V0U3RhdHVzKCdlcnJvcicpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfSwgW2ZsdXNoUGxheWJhY2tdKTtcblxuICBjb25zdCBzdGFydCA9IHVzZUNhbGxiYWNrKGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBjYiA9IG9wdHNSZWYuY3VycmVudDtcbiAgICBpZiAoIWNiLmFnZW50SWQpIHtcbiAgICAgIGNiLm9uRXJyb3I/LihuZXcgRXJyb3IoJ0xpdmUgdm9pY2UgdW5hdmFpbGFibGU6IGFnZW50IGlzIHN0aWxsIGxvYWRpbmcnKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh3c1JlZi5jdXJyZW50KSByZXR1cm47IC8vIGFscmVhZHkgYWN0aXZlXG5cbiAgICBzZXRTdGF0dXMoJ2Nvbm5lY3RpbmcnKTtcbiAgICAvLyBQZXJzaXN0ZW5jZSAodHJhbnNjcmlwdC9kYXNoYm9hcmQpIGtleXMgb2ZmIGFuIGV4aXN0aW5nIGNvbnZlcnNhdGlvbiBVVUlELlxuICAgIC8vIFdpdGhvdXQgb25lIHRoZSBjYWxsIHN0aWxsIHdvcmtzLCBidXQgdGhlIGJhY2tlbmQgc2tpcHMgc2F2aW5nIHRoZSB0dXJucy5cbiAgICBpZiAoIWNiLmNvbnZlcnNhdGlvbklkKSB7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICdbdXNlTGl2ZVZvaWNlXSBObyBjb252ZXJzYXRpb25JZCB5ZXQg4oCUIHRoZSBsaXZlIGNhbGwgd2lsbCBydW4gYnV0IGl0cyAnICtcbiAgICAgICAgICAndHJhbnNjcmlwdHMgd2lsbCBub3QgYmUgcGVyc2lzdGVkLicsXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCB0aHJlYWRJZCA9XG4gICAgICBjYi5jb252ZXJzYXRpb25JZCB8fFxuICAgICAgKHR5cGVvZiBjcnlwdG8gIT09ICd1bmRlZmluZWQnICYmICdyYW5kb21VVUlEJyBpbiBjcnlwdG9cbiAgICAgICAgPyBjcnlwdG8ucmFuZG9tVVVJRCgpXG4gICAgICAgIDogYGxpdmUtJHtEYXRlLm5vdygpfWApO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHN0cmVhbSA9IGF3YWl0IG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhKHtcbiAgICAgICAgYXVkaW86IHsgY2hhbm5lbENvdW50OiAxLCBlY2hvQ2FuY2VsbGF0aW9uOiB0cnVlLCBub2lzZVN1cHByZXNzaW9uOiB0cnVlIH0sXG4gICAgICB9KTtcbiAgICAgIHN0cmVhbVJlZi5jdXJyZW50ID0gc3RyZWFtO1xuXG4gICAgICBjb25zdCBBdWRpb0N0eCA9XG4gICAgICAgIHdpbmRvdy5BdWRpb0NvbnRleHQgfHxcbiAgICAgICAgKHdpbmRvdyBhcyB1bmtub3duIGFzIHsgd2Via2l0QXVkaW9Db250ZXh0OiB0eXBlb2YgQXVkaW9Db250ZXh0IH0pLndlYmtpdEF1ZGlvQ29udGV4dDtcbiAgICAgIGNvbnN0IGNhcHR1cmVDdHggPSBuZXcgQXVkaW9DdHgoKTtcbiAgICAgIGNhcHR1cmVDdHhSZWYuY3VycmVudCA9IGNhcHR1cmVDdHg7XG4gICAgICBwbGF5YmFja0N0eFJlZi5jdXJyZW50ID0gbmV3IEF1ZGlvQ3R4KCk7XG4gICAgICBwbGF5aGVhZFJlZi5jdXJyZW50ID0gcGxheWJhY2tDdHhSZWYuY3VycmVudC5jdXJyZW50VGltZTtcblxuICAgICAgY29uc3Qgd3MgPSBjcmVhdGVXZWJTb2NrZXQoYnVpbGRMaXZlVXJsKGNiLCB0aHJlYWRJZCkpO1xuICAgICAgd3MuYmluYXJ5VHlwZSA9ICdhcnJheWJ1ZmZlcic7XG4gICAgICB3c1JlZi5jdXJyZW50ID0gd3M7XG5cbiAgICAgIHdzLm9ub3BlbiA9ICgpID0+IHtcbiAgICAgICAgY29uc3Qgc291cmNlID0gY2FwdHVyZUN0eC5jcmVhdGVNZWRpYVN0cmVhbVNvdXJjZShzdHJlYW0pO1xuICAgICAgICAvLyBUT0RPOiBtaWdyYXRlIHRvIEF1ZGlvV29ya2xldCDigJQgU2NyaXB0UHJvY2Vzc29yTm9kZSBpcyBkZXByZWNhdGVkIGFuZFxuICAgICAgICAvLyBydW5zIHRoZSBkb3duc2FtcGxlIG9uIHRoZSBtYWluIHRocmVhZCAoY2FuIGphbmsgb24gc2xvdyBkZXZpY2VzKS5cbiAgICAgICAgY29uc3QgcHJvY2Vzc29yID0gY2FwdHVyZUN0eC5jcmVhdGVTY3JpcHRQcm9jZXNzb3IoQ0FQVFVSRV9CVUZGRVJfU0laRSwgMSwgMSk7XG4gICAgICAgIHByb2Nlc3NvclJlZi5jdXJyZW50ID0gcHJvY2Vzc29yO1xuICAgICAgICBwcm9jZXNzb3Iub25hdWRpb3Byb2Nlc3MgPSAoZSkgPT4ge1xuICAgICAgICAgIGlmICh3cy5yZWFkeVN0YXRlICE9PSB3cy5PUEVOKSByZXR1cm47XG4gICAgICAgICAgY29uc3QgcGNtID0gZmxvYXRUbzE2a1BjbShlLmlucHV0QnVmZmVyLmdldENoYW5uZWxEYXRhKDApLCBjYXB0dXJlQ3R4LnNhbXBsZVJhdGUpO1xuICAgICAgICAgIHdzLnNlbmQocGNtKTtcbiAgICAgICAgfTtcbiAgICAgICAgc291cmNlLmNvbm5lY3QocHJvY2Vzc29yKTtcbiAgICAgICAgcHJvY2Vzc29yLmNvbm5lY3QoY2FwdHVyZUN0eC5kZXN0aW5hdGlvbik7IC8vIHJlcXVpcmVkIHRvIGRyaXZlIG9uYXVkaW9wcm9jZXNzXG4gICAgICAgIHNldElzQWN0aXZlKHRydWUpO1xuICAgICAgICBzZXRTdGF0dXMoJ2xpc3RlbmluZycpO1xuICAgICAgfTtcblxuICAgICAgd3Mub25tZXNzYWdlID0gKGV2ZW50OiBNZXNzYWdlRXZlbnQpID0+IHtcbiAgICAgICAgaWYgKGV2ZW50LmRhdGEgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xuICAgICAgICAgIHBsYXlQY21DaHVuayhldmVudC5kYXRhKTtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgZXZlbnQuZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgaGFuZGxlRXZlbnQoSlNPTi5wYXJzZShldmVudC5kYXRhKSk7XG4gICAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICAvKiBpZ25vcmUgbWFsZm9ybWVkIGV2ZW50ICovXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICB3cy5vbmVycm9yID0gKCkgPT4ge1xuICAgICAgICBjYi5vbkVycm9yPy4obmV3IEVycm9yKCdMaXZlIHZvaWNlIGNvbm5lY3Rpb24gZXJyb3InKSk7XG4gICAgICB9O1xuXG4gICAgICB3cy5vbmNsb3NlID0gKCkgPT4ge1xuICAgICAgICBzdG9wKCk7XG4gICAgICB9O1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY2Iub25FcnJvcj8uKGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyIDogbmV3IEVycm9yKFN0cmluZyhlcnIpKSk7XG4gICAgICBzdG9wKCk7XG4gICAgfVxuICB9LCBbaGFuZGxlRXZlbnQsIHBsYXlQY21DaHVuaywgc3RvcF0pO1xuXG4gIC8vIFRlYXIgZG93biBvbiB1bm1vdW50LlxuICB1c2VFZmZlY3QoKCkgPT4gKCkgPT4gc3RvcCgpLCBbc3RvcF0pO1xuXG4gIHJldHVybiB7IGlzQWN0aXZlLCBzdGF0dXMsIHN0YXJ0LCBzdG9wIH07XG59XG4iXX0=
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ChatMessage } from '../types';
|
|
2
|
+
interface UseScrollManagementOptions {
|
|
3
|
+
messages: ChatMessage[];
|
|
4
|
+
isAgentTyping: boolean;
|
|
5
|
+
currentThinkingPartIndex: number;
|
|
6
|
+
currentThinkingPartsLength: number;
|
|
7
|
+
conversationId: string | null | undefined;
|
|
8
|
+
isFloatingOpen: boolean;
|
|
9
|
+
mode: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function useScrollManagement({ messages, isAgentTyping, currentThinkingPartIndex, currentThinkingPartsLength, conversationId, isFloatingOpen, mode, }: UseScrollManagementOptions): {
|
|
12
|
+
messagesEndRef: import("react").RefObject<HTMLDivElement>;
|
|
13
|
+
chatContainerRef: import("react").RefObject<HTMLDivElement>;
|
|
14
|
+
};
|
|
15
|
+
export {};
|