@uipath/apollo-react 4.13.1 → 4.14.0-pr593.59e5bb0
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/canvas/components/Edges/SequenceEdge.cjs +10 -8
- package/dist/canvas/components/Edges/SequenceEdge.d.ts.map +1 -1
- package/dist/canvas/components/Edges/SequenceEdge.js +10 -8
- package/dist/material/components/ap-chat/components/common/action-button.cjs +7 -33
- package/dist/material/components/ap-chat/components/common/action-button.d.ts +3 -9
- package/dist/material/components/ap-chat/components/common/action-button.d.ts.map +1 -1
- package/dist/material/components/ap-chat/components/common/action-button.js +7 -33
- package/dist/material/components/ap-chat/components/input/always-on-voice-button.cjs +183 -0
- package/dist/material/components/ap-chat/components/input/always-on-voice-button.d.ts +10 -0
- package/dist/material/components/ap-chat/components/input/always-on-voice-button.d.ts.map +1 -0
- package/dist/material/components/ap-chat/components/input/always-on-voice-button.js +136 -0
- package/dist/material/components/ap-chat/components/input/chat-input-actions.cjs +46 -4
- package/dist/material/components/ap-chat/components/input/chat-input-actions.d.ts +4 -1
- package/dist/material/components/ap-chat/components/input/chat-input-actions.d.ts.map +1 -1
- package/dist/material/components/ap-chat/components/input/chat-input-actions.js +46 -4
- package/dist/material/components/ap-chat/components/input/chat-input.cjs +19 -5
- package/dist/material/components/ap-chat/components/input/chat-input.d.ts.map +1 -1
- package/dist/material/components/ap-chat/components/input/chat-input.js +19 -5
- package/dist/material/components/ap-chat/locales/en.cjs +1 -1
- package/dist/material/components/ap-chat/locales/en.d.ts.map +1 -1
- package/dist/material/components/ap-chat/locales/en.js +1 -1
- package/dist/material/components/ap-chat/service/ChatModel.cjs +2 -0
- package/dist/material/components/ap-chat/service/ChatModel.d.ts +4 -1
- package/dist/material/components/ap-chat/service/ChatModel.d.ts.map +1 -1
- package/dist/material/components/ap-chat/service/ChatModel.js +2 -0
- package/dist/material/components/ap-chat/service/ChatService.cjs +14 -0
- package/dist/material/components/ap-chat/service/ChatService.d.ts +4 -0
- package/dist/material/components/ap-chat/service/ChatService.d.ts.map +1 -1
- package/dist/material/components/ap-chat/service/ChatService.js +14 -0
- package/package.json +1 -1
- package/dist/material/components/ap-chat/components/audio/chat-audio.cjs +0 -334
- package/dist/material/components/ap-chat/components/audio/chat-audio.d.ts +0 -10
- package/dist/material/components/ap-chat/components/audio/chat-audio.d.ts.map +0 -1
- package/dist/material/components/ap-chat/components/audio/chat-audio.js +0 -290
package/package.json
CHANGED
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __webpack_require__ = {};
|
|
3
|
-
(()=>{
|
|
4
|
-
__webpack_require__.n = (module)=>{
|
|
5
|
-
var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
|
|
6
|
-
__webpack_require__.d(getter, {
|
|
7
|
-
a: getter
|
|
8
|
-
});
|
|
9
|
-
return getter;
|
|
10
|
-
};
|
|
11
|
-
})();
|
|
12
|
-
(()=>{
|
|
13
|
-
__webpack_require__.d = (exports1, definition)=>{
|
|
14
|
-
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
15
|
-
enumerable: true,
|
|
16
|
-
get: definition[key]
|
|
17
|
-
});
|
|
18
|
-
};
|
|
19
|
-
})();
|
|
20
|
-
(()=>{
|
|
21
|
-
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
22
|
-
})();
|
|
23
|
-
(()=>{
|
|
24
|
-
__webpack_require__.r = (exports1)=>{
|
|
25
|
-
if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
26
|
-
value: 'Module'
|
|
27
|
-
});
|
|
28
|
-
Object.defineProperty(exports1, '__esModule', {
|
|
29
|
-
value: true
|
|
30
|
-
});
|
|
31
|
-
};
|
|
32
|
-
})();
|
|
33
|
-
var __webpack_exports__ = {};
|
|
34
|
-
__webpack_require__.r(__webpack_exports__);
|
|
35
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
36
|
-
AutopilotChatAudio: ()=>AutopilotChatAudio
|
|
37
|
-
});
|
|
38
|
-
const jsx_runtime_namespaceObject = require("react/jsx-runtime");
|
|
39
|
-
const styles_namespaceObject = require("@mui/material/styles");
|
|
40
|
-
const external_react_namespaceObject = require("react");
|
|
41
|
-
var external_react_default = /*#__PURE__*/ __webpack_require__.n(external_react_namespaceObject);
|
|
42
|
-
const chat_service_provider_cjs_namespaceObject = require("../../providers/chat-service.provider.cjs");
|
|
43
|
-
const index_cjs_namespaceObject = require("../../service/index.cjs");
|
|
44
|
-
const action_button_cjs_namespaceObject = require("../common/action-button.cjs");
|
|
45
|
-
const external_chat_audio_input_cjs_namespaceObject = require("./chat-audio-input.cjs");
|
|
46
|
-
const external_chat_audio_output_cjs_namespaceObject = require("./chat-audio-output.cjs");
|
|
47
|
-
const audioInputIconMap = {
|
|
48
|
-
active: 'mic',
|
|
49
|
-
starting: 'mic_off',
|
|
50
|
-
inactive: 'mic_off'
|
|
51
|
-
};
|
|
52
|
-
const audioInputTooltipMap = {
|
|
53
|
-
active: 'Release When Finished Talking',
|
|
54
|
-
starting: 'Preparing to Listen',
|
|
55
|
-
inactive: 'Push to Talk, or Ctrl+Click for Always On Mode'
|
|
56
|
-
};
|
|
57
|
-
const audioInputTooltipAutoMap = {
|
|
58
|
-
active: 'Click to Stop Listening',
|
|
59
|
-
starting: 'Preparing to Listen',
|
|
60
|
-
inactive: 'Ctrl+Click for Auto Detection Mode'
|
|
61
|
-
};
|
|
62
|
-
const audioInputColorMap = {
|
|
63
|
-
active: 'var(--color-foreground-highlight)',
|
|
64
|
-
starting: 'var(--color-foreground-disable)',
|
|
65
|
-
inactive: 'var(--color-foreground)'
|
|
66
|
-
};
|
|
67
|
-
function joinClasses(...classes) {
|
|
68
|
-
return classes.filter(Boolean).join(' ');
|
|
69
|
-
}
|
|
70
|
-
const AutopilotChatAudio = (props)=>{
|
|
71
|
-
const { disabled = false } = props;
|
|
72
|
-
const [audioInputState, setAudioInputState] = (0, external_react_namespaceObject.useState)('inactive');
|
|
73
|
-
const [audioInputMode, setAudioInputMode] = (0, external_react_namespaceObject.useState)('push-to-talk');
|
|
74
|
-
const [ignoreOutputStreamData, setIgnoreOutputStreamData] = (0, external_react_namespaceObject.useState)(false);
|
|
75
|
-
const chatService = (0, chat_service_provider_cjs_namespaceObject.useChatService)();
|
|
76
|
-
const handleAudioInputStart = (0, external_react_namespaceObject.useCallback)((automaticActivityDetectionEnabled)=>{
|
|
77
|
-
if (!chatService) return;
|
|
78
|
-
setAudioInputState('active');
|
|
79
|
-
chatService.sendInputStreamEvent({
|
|
80
|
-
activityStart: {
|
|
81
|
-
automaticActivityDetectionEnabled
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
}, [
|
|
85
|
-
chatService
|
|
86
|
-
]);
|
|
87
|
-
const handleAudioInputEnd = (0, external_react_namespaceObject.useCallback)((sequenceNumber)=>{
|
|
88
|
-
if (!chatService) return;
|
|
89
|
-
setAudioInputState('inactive');
|
|
90
|
-
chatService.sendInputStreamEvent({
|
|
91
|
-
activityEnd: {
|
|
92
|
-
sequenceNumber
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
}, [
|
|
96
|
-
chatService
|
|
97
|
-
]);
|
|
98
|
-
const handleAudioInputData = external_react_default().useCallback((mimeType, data, sequenceNumber)=>{
|
|
99
|
-
if (!chatService) return;
|
|
100
|
-
chatService.sendInputStreamEvent({
|
|
101
|
-
mediaChunks: [
|
|
102
|
-
{
|
|
103
|
-
mimeType,
|
|
104
|
-
data,
|
|
105
|
-
sequenceNumber
|
|
106
|
-
}
|
|
107
|
-
]
|
|
108
|
-
});
|
|
109
|
-
}, [
|
|
110
|
-
chatService
|
|
111
|
-
]);
|
|
112
|
-
const { startAudioInput, stopAudioInput, audioInputError } = (0, external_chat_audio_input_cjs_namespaceObject.useAudioInput)({
|
|
113
|
-
handleAudioInputData,
|
|
114
|
-
handleAudioInputStart,
|
|
115
|
-
handleAudioInputEnd
|
|
116
|
-
});
|
|
117
|
-
const { queueOutputAudio, clearOutputAudioQueue, isOutputAudioActive } = (0, external_chat_audio_output_cjs_namespaceObject.useAudioOutput)();
|
|
118
|
-
external_react_default().useEffect(()=>{
|
|
119
|
-
if (!chatService) return;
|
|
120
|
-
return chatService.on(index_cjs_namespaceObject.AutopilotChatEvent.OutputStream, (event)=>{
|
|
121
|
-
if (event.mediaChunks) {
|
|
122
|
-
for (const mediaChunk of event.mediaChunks)if (mediaChunk.mimeType.startsWith('audio/pcm;') && !ignoreOutputStreamData) queueOutputAudio(mediaChunk.mimeType, mediaChunk.data, mediaChunk.sequenceNumber);
|
|
123
|
-
}
|
|
124
|
-
if (event.interrupted) {
|
|
125
|
-
console.log('Received interrupted event, clearing queue', {
|
|
126
|
-
ignoreOutputStreamData
|
|
127
|
-
});
|
|
128
|
-
setIgnoreOutputStreamData(true);
|
|
129
|
-
clearOutputAudioQueue();
|
|
130
|
-
}
|
|
131
|
-
if (event.generationComplete) {
|
|
132
|
-
console.log('Received generationComplete event, clearing ignoreOutputStreamData', {
|
|
133
|
-
ignoreOutputStreamData
|
|
134
|
-
});
|
|
135
|
-
setIgnoreOutputStreamData(false);
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
}, [
|
|
139
|
-
chatService,
|
|
140
|
-
queueOutputAudio,
|
|
141
|
-
ignoreOutputStreamData,
|
|
142
|
-
clearOutputAudioQueue
|
|
143
|
-
]);
|
|
144
|
-
const onTalkButtonPressed = (0, external_react_namespaceObject.useCallback)(async (event)=>{
|
|
145
|
-
if (disabled) return;
|
|
146
|
-
if ('automatic-detection' === audioInputMode && 'active' === audioInputState) {
|
|
147
|
-
stopAudioInput();
|
|
148
|
-
setAudioInputState('inactive');
|
|
149
|
-
setAudioInputMode('push-to-talk');
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
if (event.ctrlKey) {
|
|
153
|
-
if ('inactive' === audioInputState) {
|
|
154
|
-
setAudioInputMode('automatic-detection');
|
|
155
|
-
setAudioInputState('starting');
|
|
156
|
-
setIgnoreOutputStreamData(false);
|
|
157
|
-
try {
|
|
158
|
-
const success = await startAudioInput(true);
|
|
159
|
-
if (!success) {
|
|
160
|
-
setAudioInputState('inactive');
|
|
161
|
-
setAudioInputMode('push-to-talk');
|
|
162
|
-
}
|
|
163
|
-
} catch (error) {
|
|
164
|
-
console.error(`Failed to start audio input (automatic detection): ${error}`);
|
|
165
|
-
setAudioInputState('inactive');
|
|
166
|
-
setAudioInputMode('push-to-talk');
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return;
|
|
170
|
-
}
|
|
171
|
-
if ('inactive' !== audioInputState) return;
|
|
172
|
-
setAudioInputMode('push-to-talk');
|
|
173
|
-
setAudioInputState('starting');
|
|
174
|
-
setIgnoreOutputStreamData(true);
|
|
175
|
-
clearOutputAudioQueue();
|
|
176
|
-
try {
|
|
177
|
-
const success = await startAudioInput(false);
|
|
178
|
-
if (!success) setAudioInputState('inactive');
|
|
179
|
-
} catch (error) {
|
|
180
|
-
console.error(`Failed to start audio input (${audioInputState}): ${error}`);
|
|
181
|
-
setAudioInputState('inactive');
|
|
182
|
-
}
|
|
183
|
-
}, [
|
|
184
|
-
disabled,
|
|
185
|
-
audioInputState,
|
|
186
|
-
audioInputMode,
|
|
187
|
-
startAudioInput,
|
|
188
|
-
stopAudioInput,
|
|
189
|
-
clearOutputAudioQueue
|
|
190
|
-
]);
|
|
191
|
-
const onTalkButtonReleased = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
192
|
-
if (disabled) return;
|
|
193
|
-
if ('push-to-talk' === audioInputMode) {
|
|
194
|
-
stopAudioInput();
|
|
195
|
-
setAudioInputState('inactive');
|
|
196
|
-
setIgnoreOutputStreamData(false);
|
|
197
|
-
}
|
|
198
|
-
}, [
|
|
199
|
-
disabled,
|
|
200
|
-
stopAudioInput,
|
|
201
|
-
audioInputMode
|
|
202
|
-
]);
|
|
203
|
-
const handlePlaybackStopClick = (0, external_react_namespaceObject.useCallback)(()=>{
|
|
204
|
-
if (disabled) return;
|
|
205
|
-
clearOutputAudioQueue();
|
|
206
|
-
setIgnoreOutputStreamData(true);
|
|
207
|
-
}, [
|
|
208
|
-
clearOutputAudioQueue,
|
|
209
|
-
disabled
|
|
210
|
-
]);
|
|
211
|
-
return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(AudioControlsContainer, {
|
|
212
|
-
children: [
|
|
213
|
-
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
214
|
-
className: joinClasses('audio-output-button', isOutputAudioActive && 'playing'),
|
|
215
|
-
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(action_button_cjs_namespaceObject.AutopilotChatActionButton, {
|
|
216
|
-
iconName: isOutputAudioActive ? 'volume_up' : 'volume_mute',
|
|
217
|
-
disabled: disabled || !isOutputAudioActive,
|
|
218
|
-
onClick: handlePlaybackStopClick,
|
|
219
|
-
tooltip: isOutputAudioActive ? "Stop Audio" : 'No Audio Is Playing',
|
|
220
|
-
preventHover: true,
|
|
221
|
-
overrideColor: isOutputAudioActive ? 'var(--color-foreground-highlight)' : 'var(--color-foreground-disable)',
|
|
222
|
-
"data-testid": "autopilot-chat-audio-output"
|
|
223
|
-
})
|
|
224
|
-
}),
|
|
225
|
-
/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("div", {
|
|
226
|
-
className: joinClasses('audio-input-button', audioInputState),
|
|
227
|
-
children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(action_button_cjs_namespaceObject.AutopilotChatActionButton, {
|
|
228
|
-
iconName: audioInputIconMap[audioInputState],
|
|
229
|
-
disabled: disabled,
|
|
230
|
-
onPress: onTalkButtonPressed,
|
|
231
|
-
onRelease: onTalkButtonReleased,
|
|
232
|
-
tooltip: 'automatic-detection' === audioInputMode ? audioInputTooltipAutoMap[audioInputState] : audioInputTooltipMap[audioInputState],
|
|
233
|
-
tooltipPlacement: "top-start",
|
|
234
|
-
preventHover: true,
|
|
235
|
-
overrideColor: audioInputColorMap[audioInputState],
|
|
236
|
-
"data-testid": "autopilot-chat-audio-input"
|
|
237
|
-
})
|
|
238
|
-
}),
|
|
239
|
-
audioInputError && /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsxs)(ErrorMessage, {
|
|
240
|
-
children: [
|
|
241
|
-
"Audio Input Error: ",
|
|
242
|
-
audioInputError
|
|
243
|
-
]
|
|
244
|
-
})
|
|
245
|
-
]
|
|
246
|
-
});
|
|
247
|
-
};
|
|
248
|
-
const pulseAnimation = (0, styles_namespaceObject.keyframes)`
|
|
249
|
-
0% {
|
|
250
|
-
opacity: 1;
|
|
251
|
-
transform: scale(1);
|
|
252
|
-
}
|
|
253
|
-
50% {
|
|
254
|
-
opacity: 0.5;
|
|
255
|
-
transform: scale(1.1);
|
|
256
|
-
}
|
|
257
|
-
100% {
|
|
258
|
-
opacity: 1;
|
|
259
|
-
transform: scale(1);
|
|
260
|
-
}
|
|
261
|
-
`;
|
|
262
|
-
const waveAnimation = (0, styles_namespaceObject.keyframes)`
|
|
263
|
-
0%, 100% {
|
|
264
|
-
transform: scaleX(1);
|
|
265
|
-
}
|
|
266
|
-
25% {
|
|
267
|
-
transform: scaleX(1.2);
|
|
268
|
-
}
|
|
269
|
-
50% {
|
|
270
|
-
transform: scaleX(0.8);
|
|
271
|
-
}
|
|
272
|
-
75% {
|
|
273
|
-
transform: scaleX(1.1);
|
|
274
|
-
}
|
|
275
|
-
`;
|
|
276
|
-
const AudioControlsContainer = (0, styles_namespaceObject.styled)('div')(({ theme })=>({
|
|
277
|
-
display: 'flex',
|
|
278
|
-
alignItems: 'center',
|
|
279
|
-
gap: theme.spacing(1),
|
|
280
|
-
position: 'relative',
|
|
281
|
-
'& .audio-input-button': {
|
|
282
|
-
'&.starting': {
|
|
283
|
-
'& .MuiIconButton-root': {
|
|
284
|
-
backgroundColor: "var(--color-background-disabled)"
|
|
285
|
-
}
|
|
286
|
-
},
|
|
287
|
-
'&.active': {
|
|
288
|
-
'& .MuiSvgIcon-root': {
|
|
289
|
-
animation: `${pulseAnimation} 1.2s ease-in-out infinite`
|
|
290
|
-
},
|
|
291
|
-
'& .MuiIconButton-root': {
|
|
292
|
-
backgroundColor: "var(--color-background-highlight)"
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
},
|
|
296
|
-
'& .audio-output-button': {
|
|
297
|
-
'&.playing': {
|
|
298
|
-
'& .MuiSvgIcon-root': {
|
|
299
|
-
animation: `${waveAnimation} 0.8s ease-in-out infinite`
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
}));
|
|
304
|
-
const ErrorMessage = (0, styles_namespaceObject.styled)('div')(({ theme })=>({
|
|
305
|
-
position: 'absolute',
|
|
306
|
-
top: '100%',
|
|
307
|
-
left: 0,
|
|
308
|
-
marginTop: theme.spacing(1),
|
|
309
|
-
padding: `${theme.spacing(1)} ${theme.spacing(1.5)}`,
|
|
310
|
-
backgroundColor: theme.palette.error.light,
|
|
311
|
-
color: theme.palette.error.contrastText,
|
|
312
|
-
borderRadius: theme.spacing(0.5),
|
|
313
|
-
whiteSpace: 'nowrap',
|
|
314
|
-
zIndex: 1000,
|
|
315
|
-
'&::before': {
|
|
316
|
-
content: '""',
|
|
317
|
-
position: 'absolute',
|
|
318
|
-
top: theme.spacing(-0.5),
|
|
319
|
-
left: theme.spacing(1.5),
|
|
320
|
-
width: 0,
|
|
321
|
-
height: 0,
|
|
322
|
-
borderLeft: `${theme.spacing(0.5)} solid transparent`,
|
|
323
|
-
borderRight: `${theme.spacing(0.5)} solid transparent`,
|
|
324
|
-
borderBottom: `${theme.spacing(0.5)} solid ${theme.palette.error.light}`
|
|
325
|
-
}
|
|
326
|
-
}));
|
|
327
|
-
AutopilotChatAudio.displayName = 'AutopilotChatAudio';
|
|
328
|
-
exports.AutopilotChatAudio = __webpack_exports__.AutopilotChatAudio;
|
|
329
|
-
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
330
|
-
"AutopilotChatAudio"
|
|
331
|
-
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
332
|
-
Object.defineProperty(exports, '__esModule', {
|
|
333
|
-
value: true
|
|
334
|
-
});
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
type AutopilotChatAudioProps = React.PropsWithoutRef<{
|
|
3
|
-
disabled?: boolean;
|
|
4
|
-
}>;
|
|
5
|
-
export declare const AutopilotChatAudio: {
|
|
6
|
-
(props: AutopilotChatAudioProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
-
displayName: string;
|
|
8
|
-
};
|
|
9
|
-
export {};
|
|
10
|
-
//# sourceMappingURL=chat-audio.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chat-audio.d.ts","sourceRoot":"","sources":["../../../../../../src/material/components/ap-chat/components/audio/chat-audio.tsx"],"names":[],"mappings":"AACA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAQrD,KAAK,uBAAuB,GAAG,KAAK,CAAC,eAAe,CAAC;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC,CAAC;AA2CH,eAAO,MAAM,kBAAkB;YAAW,uBAAuB;;CAsOhE,CAAC"}
|
|
@@ -1,290 +0,0 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { keyframes, styled } from "@mui/material/styles";
|
|
3
|
-
import react, { useCallback, useState } from "react";
|
|
4
|
-
import { useChatService } from "../../providers/chat-service.provider.js";
|
|
5
|
-
import { AutopilotChatEvent } from "../../service/index.js";
|
|
6
|
-
import { AutopilotChatActionButton } from "../common/action-button.js";
|
|
7
|
-
import { useAudioInput } from "./chat-audio-input.js";
|
|
8
|
-
import { useAudioOutput } from "./chat-audio-output.js";
|
|
9
|
-
const audioInputIconMap = {
|
|
10
|
-
active: 'mic',
|
|
11
|
-
starting: 'mic_off',
|
|
12
|
-
inactive: 'mic_off'
|
|
13
|
-
};
|
|
14
|
-
const audioInputTooltipMap = {
|
|
15
|
-
active: 'Release When Finished Talking',
|
|
16
|
-
starting: 'Preparing to Listen',
|
|
17
|
-
inactive: 'Push to Talk, or Ctrl+Click for Always On Mode'
|
|
18
|
-
};
|
|
19
|
-
const audioInputTooltipAutoMap = {
|
|
20
|
-
active: 'Click to Stop Listening',
|
|
21
|
-
starting: 'Preparing to Listen',
|
|
22
|
-
inactive: 'Ctrl+Click for Auto Detection Mode'
|
|
23
|
-
};
|
|
24
|
-
const audioInputColorMap = {
|
|
25
|
-
active: 'var(--color-foreground-highlight)',
|
|
26
|
-
starting: 'var(--color-foreground-disable)',
|
|
27
|
-
inactive: 'var(--color-foreground)'
|
|
28
|
-
};
|
|
29
|
-
function joinClasses(...classes) {
|
|
30
|
-
return classes.filter(Boolean).join(' ');
|
|
31
|
-
}
|
|
32
|
-
const AutopilotChatAudio = (props)=>{
|
|
33
|
-
const { disabled = false } = props;
|
|
34
|
-
const [audioInputState, setAudioInputState] = useState('inactive');
|
|
35
|
-
const [audioInputMode, setAudioInputMode] = useState('push-to-talk');
|
|
36
|
-
const [ignoreOutputStreamData, setIgnoreOutputStreamData] = useState(false);
|
|
37
|
-
const chatService = useChatService();
|
|
38
|
-
const handleAudioInputStart = useCallback((automaticActivityDetectionEnabled)=>{
|
|
39
|
-
if (!chatService) return;
|
|
40
|
-
setAudioInputState('active');
|
|
41
|
-
chatService.sendInputStreamEvent({
|
|
42
|
-
activityStart: {
|
|
43
|
-
automaticActivityDetectionEnabled
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
}, [
|
|
47
|
-
chatService
|
|
48
|
-
]);
|
|
49
|
-
const handleAudioInputEnd = useCallback((sequenceNumber)=>{
|
|
50
|
-
if (!chatService) return;
|
|
51
|
-
setAudioInputState('inactive');
|
|
52
|
-
chatService.sendInputStreamEvent({
|
|
53
|
-
activityEnd: {
|
|
54
|
-
sequenceNumber
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
}, [
|
|
58
|
-
chatService
|
|
59
|
-
]);
|
|
60
|
-
const handleAudioInputData = react.useCallback((mimeType, data, sequenceNumber)=>{
|
|
61
|
-
if (!chatService) return;
|
|
62
|
-
chatService.sendInputStreamEvent({
|
|
63
|
-
mediaChunks: [
|
|
64
|
-
{
|
|
65
|
-
mimeType,
|
|
66
|
-
data,
|
|
67
|
-
sequenceNumber
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
});
|
|
71
|
-
}, [
|
|
72
|
-
chatService
|
|
73
|
-
]);
|
|
74
|
-
const { startAudioInput, stopAudioInput, audioInputError } = useAudioInput({
|
|
75
|
-
handleAudioInputData,
|
|
76
|
-
handleAudioInputStart,
|
|
77
|
-
handleAudioInputEnd
|
|
78
|
-
});
|
|
79
|
-
const { queueOutputAudio, clearOutputAudioQueue, isOutputAudioActive } = useAudioOutput();
|
|
80
|
-
react.useEffect(()=>{
|
|
81
|
-
if (!chatService) return;
|
|
82
|
-
return chatService.on(AutopilotChatEvent.OutputStream, (event)=>{
|
|
83
|
-
if (event.mediaChunks) {
|
|
84
|
-
for (const mediaChunk of event.mediaChunks)if (mediaChunk.mimeType.startsWith('audio/pcm;') && !ignoreOutputStreamData) queueOutputAudio(mediaChunk.mimeType, mediaChunk.data, mediaChunk.sequenceNumber);
|
|
85
|
-
}
|
|
86
|
-
if (event.interrupted) {
|
|
87
|
-
console.log('Received interrupted event, clearing queue', {
|
|
88
|
-
ignoreOutputStreamData
|
|
89
|
-
});
|
|
90
|
-
setIgnoreOutputStreamData(true);
|
|
91
|
-
clearOutputAudioQueue();
|
|
92
|
-
}
|
|
93
|
-
if (event.generationComplete) {
|
|
94
|
-
console.log('Received generationComplete event, clearing ignoreOutputStreamData', {
|
|
95
|
-
ignoreOutputStreamData
|
|
96
|
-
});
|
|
97
|
-
setIgnoreOutputStreamData(false);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}, [
|
|
101
|
-
chatService,
|
|
102
|
-
queueOutputAudio,
|
|
103
|
-
ignoreOutputStreamData,
|
|
104
|
-
clearOutputAudioQueue
|
|
105
|
-
]);
|
|
106
|
-
const onTalkButtonPressed = useCallback(async (event)=>{
|
|
107
|
-
if (disabled) return;
|
|
108
|
-
if ('automatic-detection' === audioInputMode && 'active' === audioInputState) {
|
|
109
|
-
stopAudioInput();
|
|
110
|
-
setAudioInputState('inactive');
|
|
111
|
-
setAudioInputMode('push-to-talk');
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
if (event.ctrlKey) {
|
|
115
|
-
if ('inactive' === audioInputState) {
|
|
116
|
-
setAudioInputMode('automatic-detection');
|
|
117
|
-
setAudioInputState('starting');
|
|
118
|
-
setIgnoreOutputStreamData(false);
|
|
119
|
-
try {
|
|
120
|
-
const success = await startAudioInput(true);
|
|
121
|
-
if (!success) {
|
|
122
|
-
setAudioInputState('inactive');
|
|
123
|
-
setAudioInputMode('push-to-talk');
|
|
124
|
-
}
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error(`Failed to start audio input (automatic detection): ${error}`);
|
|
127
|
-
setAudioInputState('inactive');
|
|
128
|
-
setAudioInputMode('push-to-talk');
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if ('inactive' !== audioInputState) return;
|
|
134
|
-
setAudioInputMode('push-to-talk');
|
|
135
|
-
setAudioInputState('starting');
|
|
136
|
-
setIgnoreOutputStreamData(true);
|
|
137
|
-
clearOutputAudioQueue();
|
|
138
|
-
try {
|
|
139
|
-
const success = await startAudioInput(false);
|
|
140
|
-
if (!success) setAudioInputState('inactive');
|
|
141
|
-
} catch (error) {
|
|
142
|
-
console.error(`Failed to start audio input (${audioInputState}): ${error}`);
|
|
143
|
-
setAudioInputState('inactive');
|
|
144
|
-
}
|
|
145
|
-
}, [
|
|
146
|
-
disabled,
|
|
147
|
-
audioInputState,
|
|
148
|
-
audioInputMode,
|
|
149
|
-
startAudioInput,
|
|
150
|
-
stopAudioInput,
|
|
151
|
-
clearOutputAudioQueue
|
|
152
|
-
]);
|
|
153
|
-
const onTalkButtonReleased = useCallback(()=>{
|
|
154
|
-
if (disabled) return;
|
|
155
|
-
if ('push-to-talk' === audioInputMode) {
|
|
156
|
-
stopAudioInput();
|
|
157
|
-
setAudioInputState('inactive');
|
|
158
|
-
setIgnoreOutputStreamData(false);
|
|
159
|
-
}
|
|
160
|
-
}, [
|
|
161
|
-
disabled,
|
|
162
|
-
stopAudioInput,
|
|
163
|
-
audioInputMode
|
|
164
|
-
]);
|
|
165
|
-
const handlePlaybackStopClick = useCallback(()=>{
|
|
166
|
-
if (disabled) return;
|
|
167
|
-
clearOutputAudioQueue();
|
|
168
|
-
setIgnoreOutputStreamData(true);
|
|
169
|
-
}, [
|
|
170
|
-
clearOutputAudioQueue,
|
|
171
|
-
disabled
|
|
172
|
-
]);
|
|
173
|
-
return /*#__PURE__*/ jsxs(AudioControlsContainer, {
|
|
174
|
-
children: [
|
|
175
|
-
/*#__PURE__*/ jsx("div", {
|
|
176
|
-
className: joinClasses('audio-output-button', isOutputAudioActive && 'playing'),
|
|
177
|
-
children: /*#__PURE__*/ jsx(AutopilotChatActionButton, {
|
|
178
|
-
iconName: isOutputAudioActive ? 'volume_up' : 'volume_mute',
|
|
179
|
-
disabled: disabled || !isOutputAudioActive,
|
|
180
|
-
onClick: handlePlaybackStopClick,
|
|
181
|
-
tooltip: isOutputAudioActive ? "Stop Audio" : 'No Audio Is Playing',
|
|
182
|
-
preventHover: true,
|
|
183
|
-
overrideColor: isOutputAudioActive ? 'var(--color-foreground-highlight)' : 'var(--color-foreground-disable)',
|
|
184
|
-
"data-testid": "autopilot-chat-audio-output"
|
|
185
|
-
})
|
|
186
|
-
}),
|
|
187
|
-
/*#__PURE__*/ jsx("div", {
|
|
188
|
-
className: joinClasses('audio-input-button', audioInputState),
|
|
189
|
-
children: /*#__PURE__*/ jsx(AutopilotChatActionButton, {
|
|
190
|
-
iconName: audioInputIconMap[audioInputState],
|
|
191
|
-
disabled: disabled,
|
|
192
|
-
onPress: onTalkButtonPressed,
|
|
193
|
-
onRelease: onTalkButtonReleased,
|
|
194
|
-
tooltip: 'automatic-detection' === audioInputMode ? audioInputTooltipAutoMap[audioInputState] : audioInputTooltipMap[audioInputState],
|
|
195
|
-
tooltipPlacement: "top-start",
|
|
196
|
-
preventHover: true,
|
|
197
|
-
overrideColor: audioInputColorMap[audioInputState],
|
|
198
|
-
"data-testid": "autopilot-chat-audio-input"
|
|
199
|
-
})
|
|
200
|
-
}),
|
|
201
|
-
audioInputError && /*#__PURE__*/ jsxs(ErrorMessage, {
|
|
202
|
-
children: [
|
|
203
|
-
"Audio Input Error: ",
|
|
204
|
-
audioInputError
|
|
205
|
-
]
|
|
206
|
-
})
|
|
207
|
-
]
|
|
208
|
-
});
|
|
209
|
-
};
|
|
210
|
-
const pulseAnimation = keyframes`
|
|
211
|
-
0% {
|
|
212
|
-
opacity: 1;
|
|
213
|
-
transform: scale(1);
|
|
214
|
-
}
|
|
215
|
-
50% {
|
|
216
|
-
opacity: 0.5;
|
|
217
|
-
transform: scale(1.1);
|
|
218
|
-
}
|
|
219
|
-
100% {
|
|
220
|
-
opacity: 1;
|
|
221
|
-
transform: scale(1);
|
|
222
|
-
}
|
|
223
|
-
`;
|
|
224
|
-
const waveAnimation = keyframes`
|
|
225
|
-
0%, 100% {
|
|
226
|
-
transform: scaleX(1);
|
|
227
|
-
}
|
|
228
|
-
25% {
|
|
229
|
-
transform: scaleX(1.2);
|
|
230
|
-
}
|
|
231
|
-
50% {
|
|
232
|
-
transform: scaleX(0.8);
|
|
233
|
-
}
|
|
234
|
-
75% {
|
|
235
|
-
transform: scaleX(1.1);
|
|
236
|
-
}
|
|
237
|
-
`;
|
|
238
|
-
const AudioControlsContainer = styled('div')(({ theme })=>({
|
|
239
|
-
display: 'flex',
|
|
240
|
-
alignItems: 'center',
|
|
241
|
-
gap: theme.spacing(1),
|
|
242
|
-
position: 'relative',
|
|
243
|
-
'& .audio-input-button': {
|
|
244
|
-
'&.starting': {
|
|
245
|
-
'& .MuiIconButton-root': {
|
|
246
|
-
backgroundColor: "var(--color-background-disabled)"
|
|
247
|
-
}
|
|
248
|
-
},
|
|
249
|
-
'&.active': {
|
|
250
|
-
'& .MuiSvgIcon-root': {
|
|
251
|
-
animation: `${pulseAnimation} 1.2s ease-in-out infinite`
|
|
252
|
-
},
|
|
253
|
-
'& .MuiIconButton-root': {
|
|
254
|
-
backgroundColor: "var(--color-background-highlight)"
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
},
|
|
258
|
-
'& .audio-output-button': {
|
|
259
|
-
'&.playing': {
|
|
260
|
-
'& .MuiSvgIcon-root': {
|
|
261
|
-
animation: `${waveAnimation} 0.8s ease-in-out infinite`
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
}));
|
|
266
|
-
const ErrorMessage = styled('div')(({ theme })=>({
|
|
267
|
-
position: 'absolute',
|
|
268
|
-
top: '100%',
|
|
269
|
-
left: 0,
|
|
270
|
-
marginTop: theme.spacing(1),
|
|
271
|
-
padding: `${theme.spacing(1)} ${theme.spacing(1.5)}`,
|
|
272
|
-
backgroundColor: theme.palette.error.light,
|
|
273
|
-
color: theme.palette.error.contrastText,
|
|
274
|
-
borderRadius: theme.spacing(0.5),
|
|
275
|
-
whiteSpace: 'nowrap',
|
|
276
|
-
zIndex: 1000,
|
|
277
|
-
'&::before': {
|
|
278
|
-
content: '""',
|
|
279
|
-
position: 'absolute',
|
|
280
|
-
top: theme.spacing(-0.5),
|
|
281
|
-
left: theme.spacing(1.5),
|
|
282
|
-
width: 0,
|
|
283
|
-
height: 0,
|
|
284
|
-
borderLeft: `${theme.spacing(0.5)} solid transparent`,
|
|
285
|
-
borderRight: `${theme.spacing(0.5)} solid transparent`,
|
|
286
|
-
borderBottom: `${theme.spacing(0.5)} solid ${theme.palette.error.light}`
|
|
287
|
-
}
|
|
288
|
-
}));
|
|
289
|
-
AutopilotChatAudio.displayName = 'AutopilotChatAudio';
|
|
290
|
-
export { AutopilotChatAudio };
|