@mirai/core 0.4.664 → 0.4.666
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/build/components/Chat/components/Aura/Aura.js +40 -14
- package/build/components/Chat/components/Aura/Aura.js.map +1 -1
- package/build/components/Chat/components/Aura/helpers/getAllowedOpenUrl.js +30 -0
- package/build/components/Chat/components/Aura/helpers/getAllowedOpenUrl.js.map +1 -0
- package/build/components/Chat/components/Aura/helpers/index.js +17 -0
- package/build/components/Chat/components/Aura/helpers/index.js.map +1 -0
- package/build/components/Chat/components/Aura/hooks/useLiveSession.js +507 -0
- package/build/components/Chat/components/Aura/hooks/useLiveSession.js.map +1 -0
- package/build/components/Chat/components/Aura/hooks/useOpenAiRealtimeSession.js +6 -9
- package/build/components/Chat/components/Aura/hooks/useOpenAiRealtimeSession.js.map +1 -1
- package/build/components/Chat/components/Aura/hooks/useXaiRealtimeSession.js +5 -6
- package/build/components/Chat/components/Aura/hooks/useXaiRealtimeSession.js.map +1 -1
- package/build/components/helpers/constants.js +1 -0
- package/build/components/helpers/constants.js.map +1 -1
- package/build/helpers/getSuperProps.js +1 -1
- package/build/helpers/getSuperProps.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,507 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useLiveSession = void 0;
|
|
7
|
+
var _dataSources = require("@mirai/data-sources");
|
|
8
|
+
var _react = require("react");
|
|
9
|
+
var _helpers = require("../../../../helpers");
|
|
10
|
+
var _helpers2 = require("../../../helpers");
|
|
11
|
+
var _helpers3 = require("../helpers");
|
|
12
|
+
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
13
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
14
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
15
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
16
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
17
|
+
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
18
|
+
const AUDIO_CONSTRAINTS = {
|
|
19
|
+
autoGainControl: true,
|
|
20
|
+
echoCancellation: true,
|
|
21
|
+
noiseSuppression: true
|
|
22
|
+
};
|
|
23
|
+
const CLOSE_TIMEOUT_RESULT = {};
|
|
24
|
+
const DATA_CHANNEL_LABEL = 'oai-events';
|
|
25
|
+
const ERROR_AUDIO_PLAYBACK_BLOCKED = 'audio_playback_blocked';
|
|
26
|
+
const ERROR_BLOCKED_OPEN_URL = 'blocked_url';
|
|
27
|
+
const ERROR_ICE_TIMEOUT = 'Timed out while gathering ICE candidates';
|
|
28
|
+
const ERROR_MISSING_AUDIO_CONTEXT = 'AudioContext not supported';
|
|
29
|
+
const ERROR_MISSING_LOCAL_SDP = 'Missing local SDP offer';
|
|
30
|
+
const ERROR_MISSING_REMOTE_SDP = 'Missing remote SDP answer';
|
|
31
|
+
const ERROR_SESSION_CLOSE_UNCONFIRMED = 'session_close_unconfirmed';
|
|
32
|
+
const FFT_SIZE = 1024;
|
|
33
|
+
const ICE_GATHERING_TIMEOUT = 10000;
|
|
34
|
+
const SESSION_CLOSE_TIMEOUT = 15000;
|
|
35
|
+
const SESSION_ENDPOINT = '/voice/live/session';
|
|
36
|
+
const TERMINAL_CONNECTION_STATES = ['closed', 'failed'];
|
|
37
|
+
const SSE_EVENT_CLOSED = 'closed';
|
|
38
|
+
const SSE_EVENT_OPEN_URL = 'open_url';
|
|
39
|
+
const createConnectionState = () => ({
|
|
40
|
+
connected: false,
|
|
41
|
+
ready: false,
|
|
42
|
+
receiving: false,
|
|
43
|
+
started: false
|
|
44
|
+
});
|
|
45
|
+
const parseServerEvent = value => {
|
|
46
|
+
if (typeof value !== 'string') return null;
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(value);
|
|
49
|
+
} catch (_unused) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const stopMediaStream = mediaStream => {
|
|
54
|
+
if (!mediaStream) return;
|
|
55
|
+
mediaStream.getTracks().forEach(track => track.stop());
|
|
56
|
+
};
|
|
57
|
+
const useLiveSession = () => {
|
|
58
|
+
const attemptRef = (0, _react.useRef)(0);
|
|
59
|
+
const audioContextRef = (0, _react.useRef)(null);
|
|
60
|
+
const audioElementRef = (0, _react.useRef)(null);
|
|
61
|
+
const closingRef = (0, _react.useRef)(null);
|
|
62
|
+
const connectionStateRef = (0, _react.useRef)(createConnectionState());
|
|
63
|
+
const dataChannelRef = (0, _react.useRef)(null);
|
|
64
|
+
const eventSourceRef = (0, _react.useRef)(null);
|
|
65
|
+
const fingerprintRef = (0, _react.useRef)(null);
|
|
66
|
+
const inputFrequencyDataRef = (0, _react.useRef)(null);
|
|
67
|
+
const inputSourceRef = (0, _react.useRef)(null);
|
|
68
|
+
const localStreamRef = (0, _react.useRef)(null);
|
|
69
|
+
const outputFrequencyDataRef = (0, _react.useRef)(null);
|
|
70
|
+
const outputSourceRef = (0, _react.useRef)(null);
|
|
71
|
+
const pageHideHandlerRef = (0, _react.useRef)(null);
|
|
72
|
+
const peerConnectionRef = (0, _react.useRef)(null);
|
|
73
|
+
const sessionIdRef = (0, _react.useRef)(null);
|
|
74
|
+
const audioAnalyzersRef = (0, _react.useRef)({
|
|
75
|
+
inputAnalyser: null,
|
|
76
|
+
outputAnalyser: null,
|
|
77
|
+
getInputByteFrequencyData: () => null,
|
|
78
|
+
getOutputByteFrequencyData: () => null
|
|
79
|
+
});
|
|
80
|
+
const cleanupLiveSession = (0, _react.useCallback)(() => {
|
|
81
|
+
attemptRef.current += 1;
|
|
82
|
+
if (pageHideHandlerRef.current) {
|
|
83
|
+
window.removeEventListener('pagehide', pageHideHandlerRef.current);
|
|
84
|
+
pageHideHandlerRef.current = null;
|
|
85
|
+
}
|
|
86
|
+
const eventSource = eventSourceRef.current;
|
|
87
|
+
if (eventSource) {
|
|
88
|
+
eventSource.close();
|
|
89
|
+
eventSourceRef.current = null;
|
|
90
|
+
}
|
|
91
|
+
const dataChannel = dataChannelRef.current;
|
|
92
|
+
if (dataChannel) {
|
|
93
|
+
dataChannel.close();
|
|
94
|
+
dataChannelRef.current = null;
|
|
95
|
+
}
|
|
96
|
+
const peerConnection = peerConnectionRef.current;
|
|
97
|
+
if (peerConnection) {
|
|
98
|
+
peerConnection.getSenders().forEach(_ref => {
|
|
99
|
+
let track = _ref.track;
|
|
100
|
+
if (track) track.stop();
|
|
101
|
+
});
|
|
102
|
+
peerConnection.close();
|
|
103
|
+
peerConnectionRef.current = null;
|
|
104
|
+
}
|
|
105
|
+
stopMediaStream(localStreamRef.current);
|
|
106
|
+
localStreamRef.current = null;
|
|
107
|
+
if (audioElementRef.current) {
|
|
108
|
+
audioElementRef.current.srcObject = null;
|
|
109
|
+
audioElementRef.current = null;
|
|
110
|
+
}
|
|
111
|
+
if (inputSourceRef.current) {
|
|
112
|
+
inputSourceRef.current.disconnect();
|
|
113
|
+
inputSourceRef.current = null;
|
|
114
|
+
}
|
|
115
|
+
if (outputSourceRef.current) {
|
|
116
|
+
outputSourceRef.current.disconnect();
|
|
117
|
+
outputSourceRef.current = null;
|
|
118
|
+
}
|
|
119
|
+
audioAnalyzersRef.current.inputAnalyser = null;
|
|
120
|
+
audioAnalyzersRef.current.outputAnalyser = null;
|
|
121
|
+
audioAnalyzersRef.current.getInputByteFrequencyData = () => null;
|
|
122
|
+
audioAnalyzersRef.current.getOutputByteFrequencyData = () => null;
|
|
123
|
+
inputFrequencyDataRef.current = null;
|
|
124
|
+
outputFrequencyDataRef.current = null;
|
|
125
|
+
const audioContext = audioContextRef.current;
|
|
126
|
+
if (audioContext) {
|
|
127
|
+
Promise.resolve(audioContext.close()).catch(() => {});
|
|
128
|
+
audioContextRef.current = null;
|
|
129
|
+
}
|
|
130
|
+
closingRef.current = null;
|
|
131
|
+
connectionStateRef.current = createConnectionState();
|
|
132
|
+
fingerprintRef.current = null;
|
|
133
|
+
sessionIdRef.current = null;
|
|
134
|
+
}, []);
|
|
135
|
+
const releaseLiveSession = (0, _react.useCallback)(() => {
|
|
136
|
+
if (closingRef.current) return;
|
|
137
|
+
cleanupLiveSession();
|
|
138
|
+
}, [cleanupLiveSession]);
|
|
139
|
+
(0, _react.useEffect)(() => releaseLiveSession, [releaseLiveSession]);
|
|
140
|
+
const createAudioAnalyzers = (0, _react.useCallback)(async (mediaStream, isCurrentAttempt) => {
|
|
141
|
+
const AudioContextConstructor = globalThis.AudioContext || globalThis.webkitAudioContext;
|
|
142
|
+
if (!AudioContextConstructor) throw new Error(ERROR_MISSING_AUDIO_CONTEXT);
|
|
143
|
+
const audioContext = new AudioContextConstructor();
|
|
144
|
+
if (audioContext.state === 'suspended') await audioContext.resume();
|
|
145
|
+
if (!isCurrentAttempt()) {
|
|
146
|
+
Promise.resolve(audioContext.close()).catch(() => {});
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
audioContextRef.current = audioContext;
|
|
150
|
+
const inputAnalyser = audioContext.createAnalyser();
|
|
151
|
+
const outputAnalyser = audioContext.createAnalyser();
|
|
152
|
+
inputAnalyser.fftSize = FFT_SIZE;
|
|
153
|
+
outputAnalyser.fftSize = FFT_SIZE;
|
|
154
|
+
audioAnalyzersRef.current.inputAnalyser = inputAnalyser;
|
|
155
|
+
audioAnalyzersRef.current.outputAnalyser = outputAnalyser;
|
|
156
|
+
inputFrequencyDataRef.current = new Uint8Array(inputAnalyser.frequencyBinCount);
|
|
157
|
+
outputFrequencyDataRef.current = new Uint8Array(outputAnalyser.frequencyBinCount);
|
|
158
|
+
audioAnalyzersRef.current.getInputByteFrequencyData = () => {
|
|
159
|
+
if (!audioAnalyzersRef.current.inputAnalyser || !inputFrequencyDataRef.current) return null;
|
|
160
|
+
audioAnalyzersRef.current.inputAnalyser.getByteFrequencyData(inputFrequencyDataRef.current);
|
|
161
|
+
return inputFrequencyDataRef.current;
|
|
162
|
+
};
|
|
163
|
+
audioAnalyzersRef.current.getOutputByteFrequencyData = () => {
|
|
164
|
+
if (!audioAnalyzersRef.current.outputAnalyser || !outputFrequencyDataRef.current) return null;
|
|
165
|
+
audioAnalyzersRef.current.outputAnalyser.getByteFrequencyData(outputFrequencyDataRef.current);
|
|
166
|
+
return outputFrequencyDataRef.current;
|
|
167
|
+
};
|
|
168
|
+
const inputSource = audioContext.createMediaStreamSource(mediaStream);
|
|
169
|
+
inputSourceRef.current = inputSource;
|
|
170
|
+
inputSource.connect(inputAnalyser);
|
|
171
|
+
return true;
|
|
172
|
+
}, []);
|
|
173
|
+
const waitForIceGathering = (0, _react.useCallback)(peerConnection => new Promise((resolve, reject) => {
|
|
174
|
+
if (peerConnection.iceGatheringState === 'complete') {
|
|
175
|
+
resolve();
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
let timeoutId = null;
|
|
179
|
+
const handleStateChange = () => {
|
|
180
|
+
if (peerConnection.iceGatheringState !== 'complete') return;
|
|
181
|
+
clearTimeout(timeoutId);
|
|
182
|
+
peerConnection.removeEventListener('icegatheringstatechange', handleStateChange);
|
|
183
|
+
resolve();
|
|
184
|
+
};
|
|
185
|
+
timeoutId = setTimeout(() => {
|
|
186
|
+
peerConnection.removeEventListener('icegatheringstatechange', handleStateChange);
|
|
187
|
+
reject(new Error(ERROR_ICE_TIMEOUT));
|
|
188
|
+
}, ICE_GATHERING_TIMEOUT);
|
|
189
|
+
peerConnection.addEventListener('icegatheringstatechange', handleStateChange);
|
|
190
|
+
}), []);
|
|
191
|
+
const registerPageHide = (0, _react.useCallback)(fingerprint => {
|
|
192
|
+
const handlePageHide = () => {
|
|
193
|
+
const sessionId = sessionIdRef.current;
|
|
194
|
+
if (!sessionId || !fingerprint || typeof navigator.sendBeacon !== 'function') return;
|
|
195
|
+
const query = new URLSearchParams({
|
|
196
|
+
fingerprint
|
|
197
|
+
}).toString();
|
|
198
|
+
navigator.sendBeacon("".concat(process.env.SERVICE_SYNAPSE).concat(SESSION_ENDPOINT, "/").concat(sessionId, "/close?").concat(query));
|
|
199
|
+
};
|
|
200
|
+
pageHideHandlerRef.current = handlePageHide;
|
|
201
|
+
window.addEventListener('pagehide', handlePageHide);
|
|
202
|
+
}, []);
|
|
203
|
+
const openEventStream = (0, _react.useCallback)(_ref2 => {
|
|
204
|
+
let fingerprint = _ref2.fingerprint,
|
|
205
|
+
onClosed = _ref2.onClosed,
|
|
206
|
+
onOpenUrl = _ref2.onOpenUrl,
|
|
207
|
+
sessionId = _ref2.sessionId;
|
|
208
|
+
const EventSourceConstructor = globalThis.EventSource;
|
|
209
|
+
if (!EventSourceConstructor || !sessionId || !fingerprint) return;
|
|
210
|
+
const query = new URLSearchParams({
|
|
211
|
+
fingerprint
|
|
212
|
+
}).toString();
|
|
213
|
+
const eventSource = new EventSourceConstructor("".concat(process.env.SERVICE_SYNAPSE).concat(SESSION_ENDPOINT, "/").concat(sessionId, "/events?").concat(query));
|
|
214
|
+
eventSourceRef.current = eventSource;
|
|
215
|
+
eventSource.addEventListener(SSE_EVENT_OPEN_URL, onOpenUrl);
|
|
216
|
+
eventSource.addEventListener(SSE_EVENT_CLOSED, onClosed);
|
|
217
|
+
}, []);
|
|
218
|
+
const playRemoteAudio = (0, _react.useCallback)(() => {
|
|
219
|
+
const audioElement = audioElementRef.current;
|
|
220
|
+
if (!audioElement || typeof audioElement.play !== 'function') return;
|
|
221
|
+
const reportBlockedPlayback = () => {
|
|
222
|
+
_dataSources.Event.publish(_helpers.EVENT.METRICS, {
|
|
223
|
+
id: _helpers.METRICS_EVENTS.AURA_ERROR,
|
|
224
|
+
error: ERROR_AUDIO_PLAYBACK_BLOCKED
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
try {
|
|
228
|
+
const played = audioElement.play();
|
|
229
|
+
if (played && typeof played.catch === 'function') played.catch(reportBlockedPlayback);
|
|
230
|
+
} catch (_unused2) {
|
|
231
|
+
reportBlockedPlayback();
|
|
232
|
+
}
|
|
233
|
+
}, []);
|
|
234
|
+
const endSession = (0, _react.useCallback)(async () => {
|
|
235
|
+
if (closingRef.current) {
|
|
236
|
+
await closingRef.current;
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const attempt = attemptRef.current;
|
|
240
|
+
const isCurrentAttempt = () => attemptRef.current === attempt;
|
|
241
|
+
const fingerprint = fingerprintRef.current;
|
|
242
|
+
const sessionId = sessionIdRef.current;
|
|
243
|
+
if (!fingerprint || !sessionId) {
|
|
244
|
+
cleanupLiveSession();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
let timeoutId = null;
|
|
248
|
+
const closing = Promise.race([(0, _dataSources.request)({
|
|
249
|
+
endpoint: "".concat(SESSION_ENDPOINT, "/").concat(sessionId, "/close"),
|
|
250
|
+
hostname: process.env.SERVICE_SYNAPSE,
|
|
251
|
+
method: 'POST',
|
|
252
|
+
fingerprint
|
|
253
|
+
}), new Promise(resolve => {
|
|
254
|
+
timeoutId = setTimeout(() => resolve(CLOSE_TIMEOUT_RESULT), SESSION_CLOSE_TIMEOUT);
|
|
255
|
+
})]);
|
|
256
|
+
closingRef.current = closing;
|
|
257
|
+
try {
|
|
258
|
+
const result = await closing;
|
|
259
|
+
if (result === CLOSE_TIMEOUT_RESULT) {
|
|
260
|
+
_dataSources.Event.publish(_helpers.EVENT.METRICS, {
|
|
261
|
+
id: _helpers.METRICS_EVENTS.AURA_ERROR,
|
|
262
|
+
error: ERROR_SESSION_CLOSE_UNCONFIRMED
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
} catch (error) {
|
|
266
|
+
_dataSources.Event.publish(_helpers.EVENT.METRICS, {
|
|
267
|
+
id: _helpers.METRICS_EVENTS.AURA_ERROR,
|
|
268
|
+
error: ERROR_SESSION_CLOSE_UNCONFIRMED,
|
|
269
|
+
reason: error === null || error === void 0 ? void 0 : error.message
|
|
270
|
+
});
|
|
271
|
+
} finally {
|
|
272
|
+
clearTimeout(timeoutId);
|
|
273
|
+
if (isCurrentAttempt()) cleanupLiveSession();
|
|
274
|
+
}
|
|
275
|
+
}, [cleanupLiveSession]);
|
|
276
|
+
const startSession = (0, _react.useCallback)(async _ref3 => {
|
|
277
|
+
let chainId = _ref3.chainId,
|
|
278
|
+
currency = _ref3.currency,
|
|
279
|
+
hotelId = _ref3.hotelId,
|
|
280
|
+
isChain = _ref3.isChain,
|
|
281
|
+
locale = _ref3.locale,
|
|
282
|
+
setIsConnecting = _ref3.setIsConnecting,
|
|
283
|
+
setReady = _ref3.setReady;
|
|
284
|
+
cleanupLiveSession();
|
|
285
|
+
attemptRef.current += 1;
|
|
286
|
+
const attempt = attemptRef.current;
|
|
287
|
+
const isCurrentAttempt = () => attemptRef.current === attempt;
|
|
288
|
+
let createdSessionId = null;
|
|
289
|
+
let dataChannel = null;
|
|
290
|
+
let mediaStream = null;
|
|
291
|
+
let peerConnection = null;
|
|
292
|
+
const releaseAttempt = () => {
|
|
293
|
+
if (dataChannel) dataChannel.close();
|
|
294
|
+
if (peerConnection) {
|
|
295
|
+
peerConnection.getSenders().forEach(_ref4 => {
|
|
296
|
+
let track = _ref4.track;
|
|
297
|
+
if (track) track.stop();
|
|
298
|
+
});
|
|
299
|
+
peerConnection.close();
|
|
300
|
+
}
|
|
301
|
+
stopMediaStream(mediaStream);
|
|
302
|
+
if (!createdSessionId) return;
|
|
303
|
+
const abandonedSessionId = createdSessionId;
|
|
304
|
+
createdSessionId = null;
|
|
305
|
+
(0, _dataSources.request)({
|
|
306
|
+
endpoint: "".concat(SESSION_ENDPOINT, "/").concat(abandonedSessionId, "/close"),
|
|
307
|
+
hostname: process.env.SERVICE_SYNAPSE,
|
|
308
|
+
method: 'POST',
|
|
309
|
+
fingerprint
|
|
310
|
+
}).catch(() => {});
|
|
311
|
+
};
|
|
312
|
+
const abortWhenStale = () => {
|
|
313
|
+
if (isCurrentAttempt()) return false;
|
|
314
|
+
releaseAttempt();
|
|
315
|
+
return true;
|
|
316
|
+
};
|
|
317
|
+
const fingerprint = (0, _helpers2.getClientFingerprint)();
|
|
318
|
+
fingerprintRef.current = fingerprint;
|
|
319
|
+
registerPageHide(fingerprint);
|
|
320
|
+
const finalizeSession = () => {
|
|
321
|
+
if (!isCurrentAttempt()) return;
|
|
322
|
+
cleanupLiveSession();
|
|
323
|
+
setReady(false);
|
|
324
|
+
setIsConnecting(false);
|
|
325
|
+
};
|
|
326
|
+
const markReady = () => {
|
|
327
|
+
if (!isCurrentAttempt()) return;
|
|
328
|
+
const _connectionStateRef$c = connectionStateRef.current,
|
|
329
|
+
connected = _connectionStateRef$c.connected,
|
|
330
|
+
ready = _connectionStateRef$c.ready,
|
|
331
|
+
receiving = _connectionStateRef$c.receiving,
|
|
332
|
+
started = _connectionStateRef$c.started;
|
|
333
|
+
if (ready || !connected || !receiving || !started) return;
|
|
334
|
+
connectionStateRef.current.ready = true;
|
|
335
|
+
_dataSources.Event.publish(_helpers.EVENT.METRICS, {
|
|
336
|
+
id: _helpers.METRICS_EVENTS.AURA_START
|
|
337
|
+
});
|
|
338
|
+
setReady(true);
|
|
339
|
+
setIsConnecting(false);
|
|
340
|
+
};
|
|
341
|
+
const handleSessionClosed = payload => {
|
|
342
|
+
var _payload$usage;
|
|
343
|
+
const reason = payload.reason;
|
|
344
|
+
_dataSources.Event.publish(_helpers.EVENT.METRICS, {
|
|
345
|
+
id: _helpers.METRICS_EVENTS.AURA_USAGE,
|
|
346
|
+
reason,
|
|
347
|
+
seconds: (_payload$usage = payload.usage) === null || _payload$usage === void 0 ? void 0 : _payload$usage.seconds
|
|
348
|
+
});
|
|
349
|
+
if (closingRef.current) return;
|
|
350
|
+
finalizeSession();
|
|
351
|
+
};
|
|
352
|
+
const handleServerEvent = _ref5 => {
|
|
353
|
+
let data = _ref5.data;
|
|
354
|
+
if (!isCurrentAttempt()) return;
|
|
355
|
+
const payload = parseServerEvent(data);
|
|
356
|
+
if (!payload) return;
|
|
357
|
+
const error = payload.error,
|
|
358
|
+
session = payload.session,
|
|
359
|
+
type = payload.type;
|
|
360
|
+
if (type === 'session.started') {
|
|
361
|
+
var _session$id;
|
|
362
|
+
sessionIdRef.current = (_session$id = session === null || session === void 0 ? void 0 : session.id) !== null && _session$id !== void 0 ? _session$id : sessionIdRef.current;
|
|
363
|
+
connectionStateRef.current.started = true;
|
|
364
|
+
markReady();
|
|
365
|
+
}
|
|
366
|
+
if (type === 'session.closed') handleSessionClosed(payload);
|
|
367
|
+
if (type === 'error') _dataSources.Event.publish(_helpers.EVENT.METRICS, {
|
|
368
|
+
id: _helpers.METRICS_EVENTS.AURA_ERROR,
|
|
369
|
+
error: error === null || error === void 0 ? void 0 : error.message
|
|
370
|
+
});
|
|
371
|
+
};
|
|
372
|
+
const handleStreamClosed = () => {
|
|
373
|
+
if (!isCurrentAttempt() || closingRef.current) return;
|
|
374
|
+
finalizeSession();
|
|
375
|
+
};
|
|
376
|
+
const handleStreamOpenUrl = _ref6 => {
|
|
377
|
+
let data = _ref6.data;
|
|
378
|
+
if (!isCurrentAttempt()) return;
|
|
379
|
+
const _ref7 = parseServerEvent(data) || {},
|
|
380
|
+
url = _ref7.url;
|
|
381
|
+
const allowedUrl = (0, _helpers3.getAllowedOpenUrl)(url);
|
|
382
|
+
if (!allowedUrl) {
|
|
383
|
+
_dataSources.Event.publish(_helpers.EVENT.METRICS, {
|
|
384
|
+
id: _helpers.METRICS_EVENTS.AURA_ERROR,
|
|
385
|
+
error: ERROR_BLOCKED_OPEN_URL
|
|
386
|
+
});
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
Promise.resolve(endSession()).catch(() => {}).then(() => window.location.assign(allowedUrl));
|
|
390
|
+
};
|
|
391
|
+
try {
|
|
392
|
+
var _session$id2;
|
|
393
|
+
mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
394
|
+
audio: AUDIO_CONSTRAINTS
|
|
395
|
+
});
|
|
396
|
+
if (abortWhenStale()) return;
|
|
397
|
+
localStreamRef.current = mediaStream;
|
|
398
|
+
const analyzersReady = await createAudioAnalyzers(mediaStream, isCurrentAttempt);
|
|
399
|
+
if (!analyzersReady || abortWhenStale()) return;
|
|
400
|
+
peerConnection = new RTCPeerConnection();
|
|
401
|
+
peerConnectionRef.current = peerConnection;
|
|
402
|
+
audioElementRef.current = document.createElement('audio');
|
|
403
|
+
audioElementRef.current.autoplay = true;
|
|
404
|
+
peerConnection.addEventListener('connectionstatechange', () => {
|
|
405
|
+
if (!isCurrentAttempt()) return;
|
|
406
|
+
const _peerConnection = peerConnection,
|
|
407
|
+
connectionState = _peerConnection.connectionState;
|
|
408
|
+
if (connectionState === 'connected') {
|
|
409
|
+
connectionStateRef.current.connected = true;
|
|
410
|
+
markReady();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (TERMINAL_CONNECTION_STATES.includes(connectionState)) finalizeSession();
|
|
414
|
+
});
|
|
415
|
+
peerConnection.ontrack = _ref8 => {
|
|
416
|
+
let streams = _ref8.streams;
|
|
417
|
+
if (!isCurrentAttempt()) return;
|
|
418
|
+
const _ref9 = streams || [],
|
|
419
|
+
_ref0 = _slicedToArray(_ref9, 1),
|
|
420
|
+
remoteStream = _ref0[0];
|
|
421
|
+
if (!remoteStream) return;
|
|
422
|
+
if (audioElementRef.current) audioElementRef.current.srcObject = remoteStream;
|
|
423
|
+
playRemoteAudio();
|
|
424
|
+
const audioContext = audioContextRef.current;
|
|
425
|
+
const outputAnalyser = audioAnalyzersRef.current.outputAnalyser;
|
|
426
|
+
if (audioContext && outputAnalyser) {
|
|
427
|
+
if (outputSourceRef.current) outputSourceRef.current.disconnect();
|
|
428
|
+
outputSourceRef.current = audioContext.createMediaStreamSource(remoteStream);
|
|
429
|
+
outputSourceRef.current.connect(outputAnalyser);
|
|
430
|
+
}
|
|
431
|
+
connectionStateRef.current.receiving = true;
|
|
432
|
+
markReady();
|
|
433
|
+
};
|
|
434
|
+
dataChannel = peerConnection.createDataChannel(DATA_CHANNEL_LABEL);
|
|
435
|
+
dataChannelRef.current = dataChannel;
|
|
436
|
+
dataChannel.addEventListener('message', handleServerEvent);
|
|
437
|
+
dataChannel.addEventListener('close', () => {
|
|
438
|
+
if (!isCurrentAttempt() || closingRef.current) return;
|
|
439
|
+
finalizeSession();
|
|
440
|
+
});
|
|
441
|
+
dataChannel.addEventListener('error', () => {
|
|
442
|
+
if (!isCurrentAttempt()) return;
|
|
443
|
+
finalizeSession();
|
|
444
|
+
});
|
|
445
|
+
const _mediaStream$getAudio = mediaStream.getAudioTracks(),
|
|
446
|
+
_mediaStream$getAudio2 = _slicedToArray(_mediaStream$getAudio, 1),
|
|
447
|
+
track = _mediaStream$getAudio2[0];
|
|
448
|
+
if (track) peerConnection.addTrack(track, mediaStream);
|
|
449
|
+
const offer = await peerConnection.createOffer();
|
|
450
|
+
if (abortWhenStale()) return;
|
|
451
|
+
await peerConnection.setLocalDescription(offer);
|
|
452
|
+
if (abortWhenStale()) return;
|
|
453
|
+
await waitForIceGathering(peerConnection);
|
|
454
|
+
if (abortWhenStale()) return;
|
|
455
|
+
const _ref1 = peerConnection.localDescription || {},
|
|
456
|
+
sdp = _ref1.sdp;
|
|
457
|
+
if (!sdp) throw new Error(ERROR_MISSING_LOCAL_SDP);
|
|
458
|
+
const _await$request = await (0, _dataSources.request)({
|
|
459
|
+
endpoint: SESSION_ENDPOINT,
|
|
460
|
+
hostname: process.env.SERVICE_SYNAPSE,
|
|
461
|
+
method: 'POST',
|
|
462
|
+
chainId: isChain ? chainId : undefined,
|
|
463
|
+
currency,
|
|
464
|
+
fingerprint,
|
|
465
|
+
hotelId: isChain ? undefined : hotelId,
|
|
466
|
+
locale,
|
|
467
|
+
sdp
|
|
468
|
+
}),
|
|
469
|
+
session = _await$request.session,
|
|
470
|
+
transport = _await$request.transport;
|
|
471
|
+
createdSessionId = (_session$id2 = session === null || session === void 0 ? void 0 : session.id) !== null && _session$id2 !== void 0 ? _session$id2 : null;
|
|
472
|
+
if (abortWhenStale()) return;
|
|
473
|
+
if (!(transport !== null && transport !== void 0 && transport.sdp)) throw new Error(ERROR_MISSING_REMOTE_SDP);
|
|
474
|
+
sessionIdRef.current = createdSessionId;
|
|
475
|
+
await peerConnection.setRemoteDescription({
|
|
476
|
+
type: 'answer',
|
|
477
|
+
sdp: transport.sdp
|
|
478
|
+
});
|
|
479
|
+
if (abortWhenStale()) return;
|
|
480
|
+
openEventStream({
|
|
481
|
+
fingerprint,
|
|
482
|
+
onClosed: handleStreamClosed,
|
|
483
|
+
onOpenUrl: handleStreamOpenUrl,
|
|
484
|
+
sessionId: sessionIdRef.current
|
|
485
|
+
});
|
|
486
|
+
} catch (error) {
|
|
487
|
+
releaseAttempt();
|
|
488
|
+
_dataSources.Event.publish(_helpers.EVENT.METRICS, {
|
|
489
|
+
id: _helpers.METRICS_EVENTS.AURA_ERROR,
|
|
490
|
+
error: error === null || error === void 0 ? void 0 : error.message
|
|
491
|
+
});
|
|
492
|
+
if (isCurrentAttempt()) {
|
|
493
|
+
cleanupLiveSession();
|
|
494
|
+
setReady(false);
|
|
495
|
+
setIsConnecting(false);
|
|
496
|
+
}
|
|
497
|
+
throw error;
|
|
498
|
+
}
|
|
499
|
+
}, [cleanupLiveSession, createAudioAnalyzers, endSession, openEventStream, playRemoteAudio, registerPageHide, waitForIceGathering]);
|
|
500
|
+
return {
|
|
501
|
+
startSession,
|
|
502
|
+
endSession,
|
|
503
|
+
audioAnalyzers: audioAnalyzersRef.current
|
|
504
|
+
};
|
|
505
|
+
};
|
|
506
|
+
exports.useLiveSession = useLiveSession;
|
|
507
|
+
//# sourceMappingURL=useLiveSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLiveSession.js","names":["_dataSources","require","_react","_helpers","_helpers2","_helpers3","_slicedToArray","r","e","_arrayWithHoles","_iterableToArrayLimit","_unsupportedIterableToArray","_nonIterableRest","TypeError","a","_arrayLikeToArray","t","toString","call","slice","constructor","name","Array","from","test","length","n","l","Symbol","iterator","i","u","f","o","next","Object","done","push","value","return","isArray","AUDIO_CONSTRAINTS","autoGainControl","echoCancellation","noiseSuppression","CLOSE_TIMEOUT_RESULT","DATA_CHANNEL_LABEL","ERROR_AUDIO_PLAYBACK_BLOCKED","ERROR_BLOCKED_OPEN_URL","ERROR_ICE_TIMEOUT","ERROR_MISSING_AUDIO_CONTEXT","ERROR_MISSING_LOCAL_SDP","ERROR_MISSING_REMOTE_SDP","ERROR_SESSION_CLOSE_UNCONFIRMED","FFT_SIZE","ICE_GATHERING_TIMEOUT","SESSION_CLOSE_TIMEOUT","SESSION_ENDPOINT","TERMINAL_CONNECTION_STATES","SSE_EVENT_CLOSED","SSE_EVENT_OPEN_URL","createConnectionState","connected","ready","receiving","started","parseServerEvent","JSON","parse","_unused","stopMediaStream","mediaStream","getTracks","forEach","track","stop","useLiveSession","attemptRef","useRef","audioContextRef","audioElementRef","closingRef","connectionStateRef","dataChannelRef","eventSourceRef","fingerprintRef","inputFrequencyDataRef","inputSourceRef","localStreamRef","outputFrequencyDataRef","outputSourceRef","pageHideHandlerRef","peerConnectionRef","sessionIdRef","audioAnalyzersRef","inputAnalyser","outputAnalyser","getInputByteFrequencyData","getOutputByteFrequencyData","cleanupLiveSession","useCallback","current","window","removeEventListener","eventSource","close","dataChannel","peerConnection","getSenders","_ref","srcObject","disconnect","audioContext","Promise","resolve","catch","releaseLiveSession","useEffect","createAudioAnalyzers","isCurrentAttempt","AudioContextConstructor","globalThis","AudioContext","webkitAudioContext","Error","state","resume","createAnalyser","fftSize","Uint8Array","frequencyBinCount","getByteFrequencyData","inputSource","createMediaStreamSource","connect","waitForIceGathering","reject","iceGatheringState","timeoutId","handleStateChange","clearTimeout","setTimeout","addEventListener","registerPageHide","fingerprint","handlePageHide","sessionId","navigator","sendBeacon","query","URLSearchParams","concat","process","env","SERVICE_SYNAPSE","openEventStream","_ref2","onClosed","onOpenUrl","EventSourceConstructor","EventSource","playRemoteAudio","audioElement","play","reportBlockedPlayback","Event","publish","EVENT","METRICS","id","METRICS_EVENTS","AURA_ERROR","error","played","_unused2","endSession","attempt","closing","race","request","endpoint","hostname","method","result","reason","message","startSession","_ref3","chainId","currency","hotelId","isChain","locale","setIsConnecting","setReady","createdSessionId","releaseAttempt","_ref4","abandonedSessionId","abortWhenStale","getClientFingerprint","finalizeSession","markReady","_connectionStateRef$c","AURA_START","handleSessionClosed","payload","_payload$usage","AURA_USAGE","seconds","usage","handleServerEvent","_ref5","data","session","type","_session$id","handleStreamClosed","handleStreamOpenUrl","_ref6","_ref7","url","allowedUrl","getAllowedOpenUrl","then","location","assign","_session$id2","mediaDevices","getUserMedia","audio","analyzersReady","RTCPeerConnection","document","createElement","autoplay","_peerConnection","connectionState","includes","ontrack","_ref8","streams","_ref9","_ref0","remoteStream","createDataChannel","_mediaStream$getAudio","getAudioTracks","_mediaStream$getAudio2","addTrack","offer","createOffer","setLocalDescription","_ref1","localDescription","sdp","_await$request","undefined","transport","setRemoteDescription","audioAnalyzers","exports"],"sources":["../../../../../../src/components/Chat/components/Aura/hooks/useLiveSession.js"],"sourcesContent":["import { Event, request } from '@mirai/data-sources';\nimport { useCallback, useEffect, useRef } from 'react';\n\nimport { EVENT, METRICS_EVENTS } from '../../../../helpers';\nimport { getClientFingerprint } from '../../../helpers';\nimport { getAllowedOpenUrl } from '../helpers';\n\nconst AUDIO_CONSTRAINTS = { autoGainControl: true, echoCancellation: true, noiseSuppression: true };\nconst CLOSE_TIMEOUT_RESULT = {};\nconst DATA_CHANNEL_LABEL = 'oai-events';\nconst ERROR_AUDIO_PLAYBACK_BLOCKED = 'audio_playback_blocked';\nconst ERROR_BLOCKED_OPEN_URL = 'blocked_url';\nconst ERROR_ICE_TIMEOUT = 'Timed out while gathering ICE candidates';\nconst ERROR_MISSING_AUDIO_CONTEXT = 'AudioContext not supported';\nconst ERROR_MISSING_LOCAL_SDP = 'Missing local SDP offer';\nconst ERROR_MISSING_REMOTE_SDP = 'Missing remote SDP answer';\nconst ERROR_SESSION_CLOSE_UNCONFIRMED = 'session_close_unconfirmed';\nconst FFT_SIZE = 1024;\nconst ICE_GATHERING_TIMEOUT = 10000;\nconst SESSION_CLOSE_TIMEOUT = 15000;\nconst SESSION_ENDPOINT = '/voice/live/session';\nconst TERMINAL_CONNECTION_STATES = ['closed', 'failed'];\nconst SSE_EVENT_CLOSED = 'closed';\nconst SSE_EVENT_OPEN_URL = 'open_url';\n\nconst createConnectionState = () => ({ connected: false, ready: false, receiving: false, started: false });\n\nconst parseServerEvent = (value) => {\n if (typeof value !== 'string') return null;\n try {\n return JSON.parse(value);\n } catch {\n return null;\n }\n};\n\nconst stopMediaStream = (mediaStream) => {\n if (!mediaStream) return;\n mediaStream.getTracks().forEach((track) => track.stop());\n};\n\nconst useLiveSession = () => {\n const attemptRef = useRef(0);\n const audioContextRef = useRef(null);\n const audioElementRef = useRef(null);\n const closingRef = useRef(null);\n const connectionStateRef = useRef(createConnectionState());\n const dataChannelRef = useRef(null);\n const eventSourceRef = useRef(null);\n const fingerprintRef = useRef(null);\n const inputFrequencyDataRef = useRef(null);\n const inputSourceRef = useRef(null);\n const localStreamRef = useRef(null);\n const outputFrequencyDataRef = useRef(null);\n const outputSourceRef = useRef(null);\n const pageHideHandlerRef = useRef(null);\n const peerConnectionRef = useRef(null);\n const sessionIdRef = useRef(null);\n const audioAnalyzersRef = useRef({\n inputAnalyser: null,\n outputAnalyser: null,\n getInputByteFrequencyData: () => null,\n getOutputByteFrequencyData: () => null,\n });\n\n const cleanupLiveSession = useCallback(() => {\n attemptRef.current += 1;\n\n if (pageHideHandlerRef.current) {\n window.removeEventListener('pagehide', pageHideHandlerRef.current);\n pageHideHandlerRef.current = null;\n }\n\n const eventSource = eventSourceRef.current;\n if (eventSource) {\n eventSource.close();\n eventSourceRef.current = null;\n }\n\n const dataChannel = dataChannelRef.current;\n if (dataChannel) {\n dataChannel.close();\n dataChannelRef.current = null;\n }\n\n const peerConnection = peerConnectionRef.current;\n if (peerConnection) {\n peerConnection.getSenders().forEach(({ track }) => {\n if (track) track.stop();\n });\n peerConnection.close();\n peerConnectionRef.current = null;\n }\n\n stopMediaStream(localStreamRef.current);\n localStreamRef.current = null;\n\n if (audioElementRef.current) {\n audioElementRef.current.srcObject = null;\n audioElementRef.current = null;\n }\n\n if (inputSourceRef.current) {\n inputSourceRef.current.disconnect();\n inputSourceRef.current = null;\n }\n\n if (outputSourceRef.current) {\n outputSourceRef.current.disconnect();\n outputSourceRef.current = null;\n }\n\n audioAnalyzersRef.current.inputAnalyser = null;\n audioAnalyzersRef.current.outputAnalyser = null;\n audioAnalyzersRef.current.getInputByteFrequencyData = () => null;\n audioAnalyzersRef.current.getOutputByteFrequencyData = () => null;\n inputFrequencyDataRef.current = null;\n outputFrequencyDataRef.current = null;\n\n const audioContext = audioContextRef.current;\n if (audioContext) {\n Promise.resolve(audioContext.close()).catch(() => {});\n audioContextRef.current = null;\n }\n\n closingRef.current = null;\n connectionStateRef.current = createConnectionState();\n fingerprintRef.current = null;\n sessionIdRef.current = null;\n }, []);\n\n const releaseLiveSession = useCallback(() => {\n if (closingRef.current) return;\n\n cleanupLiveSession();\n }, [cleanupLiveSession]);\n\n useEffect(() => releaseLiveSession, [releaseLiveSession]);\n\n const createAudioAnalyzers = useCallback(async (mediaStream, isCurrentAttempt) => {\n const AudioContextConstructor = globalThis.AudioContext || globalThis.webkitAudioContext;\n if (!AudioContextConstructor) throw new Error(ERROR_MISSING_AUDIO_CONTEXT);\n\n const audioContext = new AudioContextConstructor();\n if (audioContext.state === 'suspended') await audioContext.resume();\n\n if (!isCurrentAttempt()) {\n Promise.resolve(audioContext.close()).catch(() => {});\n return false;\n }\n\n audioContextRef.current = audioContext;\n const inputAnalyser = audioContext.createAnalyser();\n const outputAnalyser = audioContext.createAnalyser();\n inputAnalyser.fftSize = FFT_SIZE;\n outputAnalyser.fftSize = FFT_SIZE;\n audioAnalyzersRef.current.inputAnalyser = inputAnalyser;\n audioAnalyzersRef.current.outputAnalyser = outputAnalyser;\n inputFrequencyDataRef.current = new Uint8Array(inputAnalyser.frequencyBinCount);\n outputFrequencyDataRef.current = new Uint8Array(outputAnalyser.frequencyBinCount);\n audioAnalyzersRef.current.getInputByteFrequencyData = () => {\n if (!audioAnalyzersRef.current.inputAnalyser || !inputFrequencyDataRef.current) return null;\n audioAnalyzersRef.current.inputAnalyser.getByteFrequencyData(inputFrequencyDataRef.current);\n return inputFrequencyDataRef.current;\n };\n audioAnalyzersRef.current.getOutputByteFrequencyData = () => {\n if (!audioAnalyzersRef.current.outputAnalyser || !outputFrequencyDataRef.current) return null;\n audioAnalyzersRef.current.outputAnalyser.getByteFrequencyData(outputFrequencyDataRef.current);\n return outputFrequencyDataRef.current;\n };\n\n const inputSource = audioContext.createMediaStreamSource(mediaStream);\n inputSourceRef.current = inputSource;\n inputSource.connect(inputAnalyser);\n\n return true;\n }, []);\n\n const waitForIceGathering = useCallback(\n (peerConnection) =>\n new Promise((resolve, reject) => {\n if (peerConnection.iceGatheringState === 'complete') {\n resolve();\n return;\n }\n\n let timeoutId = null;\n const handleStateChange = () => {\n if (peerConnection.iceGatheringState !== 'complete') return;\n clearTimeout(timeoutId);\n peerConnection.removeEventListener('icegatheringstatechange', handleStateChange);\n resolve();\n };\n\n timeoutId = setTimeout(() => {\n peerConnection.removeEventListener('icegatheringstatechange', handleStateChange);\n reject(new Error(ERROR_ICE_TIMEOUT));\n }, ICE_GATHERING_TIMEOUT);\n\n peerConnection.addEventListener('icegatheringstatechange', handleStateChange);\n }),\n [],\n );\n\n const registerPageHide = useCallback((fingerprint) => {\n const handlePageHide = () => {\n const sessionId = sessionIdRef.current;\n if (!sessionId || !fingerprint || typeof navigator.sendBeacon !== 'function') return;\n const query = new URLSearchParams({ fingerprint }).toString();\n navigator.sendBeacon(`${process.env.SERVICE_SYNAPSE}${SESSION_ENDPOINT}/${sessionId}/close?${query}`);\n };\n\n pageHideHandlerRef.current = handlePageHide;\n window.addEventListener('pagehide', handlePageHide);\n }, []);\n\n const openEventStream = useCallback(({ fingerprint, onClosed, onOpenUrl, sessionId }) => {\n const EventSourceConstructor = globalThis.EventSource;\n if (!EventSourceConstructor || !sessionId || !fingerprint) return;\n\n const query = new URLSearchParams({ fingerprint }).toString();\n const eventSource = new EventSourceConstructor(\n `${process.env.SERVICE_SYNAPSE}${SESSION_ENDPOINT}/${sessionId}/events?${query}`,\n );\n eventSourceRef.current = eventSource;\n eventSource.addEventListener(SSE_EVENT_OPEN_URL, onOpenUrl);\n eventSource.addEventListener(SSE_EVENT_CLOSED, onClosed);\n }, []);\n\n const playRemoteAudio = useCallback(() => {\n const audioElement = audioElementRef.current;\n if (!audioElement || typeof audioElement.play !== 'function') return;\n\n const reportBlockedPlayback = () => {\n Event.publish(EVENT.METRICS, { id: METRICS_EVENTS.AURA_ERROR, error: ERROR_AUDIO_PLAYBACK_BLOCKED });\n };\n\n try {\n const played = audioElement.play();\n if (played && typeof played.catch === 'function') played.catch(reportBlockedPlayback);\n } catch {\n reportBlockedPlayback();\n }\n }, []);\n\n const endSession = useCallback(async () => {\n if (closingRef.current) {\n await closingRef.current;\n return;\n }\n\n const attempt = attemptRef.current;\n const isCurrentAttempt = () => attemptRef.current === attempt;\n const fingerprint = fingerprintRef.current;\n const sessionId = sessionIdRef.current;\n if (!fingerprint || !sessionId) {\n cleanupLiveSession();\n return;\n }\n\n let timeoutId = null;\n const closing = Promise.race([\n request({\n endpoint: `${SESSION_ENDPOINT}/${sessionId}/close`,\n hostname: process.env.SERVICE_SYNAPSE,\n method: 'POST',\n fingerprint,\n }),\n new Promise((resolve) => {\n timeoutId = setTimeout(() => resolve(CLOSE_TIMEOUT_RESULT), SESSION_CLOSE_TIMEOUT);\n }),\n ]);\n closingRef.current = closing;\n\n try {\n const result = await closing;\n if (result === CLOSE_TIMEOUT_RESULT) {\n Event.publish(EVENT.METRICS, { id: METRICS_EVENTS.AURA_ERROR, error: ERROR_SESSION_CLOSE_UNCONFIRMED });\n }\n } catch (error) {\n Event.publish(EVENT.METRICS, {\n id: METRICS_EVENTS.AURA_ERROR,\n error: ERROR_SESSION_CLOSE_UNCONFIRMED,\n reason: error?.message,\n });\n } finally {\n clearTimeout(timeoutId);\n if (isCurrentAttempt()) cleanupLiveSession();\n }\n }, [cleanupLiveSession]);\n\n const startSession = useCallback(\n async ({ chainId, currency, hotelId, isChain, locale, setIsConnecting, setReady }) => {\n cleanupLiveSession();\n attemptRef.current += 1;\n\n const attempt = attemptRef.current;\n const isCurrentAttempt = () => attemptRef.current === attempt;\n\n let createdSessionId = null;\n let dataChannel = null;\n let mediaStream = null;\n let peerConnection = null;\n\n const releaseAttempt = () => {\n if (dataChannel) dataChannel.close();\n if (peerConnection) {\n peerConnection.getSenders().forEach(({ track }) => {\n if (track) track.stop();\n });\n peerConnection.close();\n }\n stopMediaStream(mediaStream);\n if (!createdSessionId) return;\n\n const abandonedSessionId = createdSessionId;\n createdSessionId = null;\n request({\n endpoint: `${SESSION_ENDPOINT}/${abandonedSessionId}/close`,\n hostname: process.env.SERVICE_SYNAPSE,\n method: 'POST',\n fingerprint,\n }).catch(() => {});\n };\n\n const abortWhenStale = () => {\n if (isCurrentAttempt()) return false;\n releaseAttempt();\n return true;\n };\n\n const fingerprint = getClientFingerprint();\n fingerprintRef.current = fingerprint;\n registerPageHide(fingerprint);\n\n const finalizeSession = () => {\n if (!isCurrentAttempt()) return;\n cleanupLiveSession();\n setReady(false);\n setIsConnecting(false);\n };\n\n const markReady = () => {\n if (!isCurrentAttempt()) return;\n const { connected, ready, receiving, started } = connectionStateRef.current;\n if (ready || !connected || !receiving || !started) return;\n connectionStateRef.current.ready = true;\n Event.publish(EVENT.METRICS, { id: METRICS_EVENTS.AURA_START });\n setReady(true);\n setIsConnecting(false);\n };\n\n const handleSessionClosed = (payload) => {\n const { reason } = payload;\n Event.publish(EVENT.METRICS, { id: METRICS_EVENTS.AURA_USAGE, reason, seconds: payload.usage?.seconds });\n if (closingRef.current) return;\n finalizeSession();\n };\n\n const handleServerEvent = ({ data }) => {\n if (!isCurrentAttempt()) return;\n const payload = parseServerEvent(data);\n if (!payload) return;\n const { error, session, type } = payload;\n\n if (type === 'session.started') {\n sessionIdRef.current = session?.id ?? sessionIdRef.current;\n connectionStateRef.current.started = true;\n markReady();\n }\n if (type === 'session.closed') handleSessionClosed(payload);\n if (type === 'error') Event.publish(EVENT.METRICS, { id: METRICS_EVENTS.AURA_ERROR, error: error?.message });\n };\n\n const handleStreamClosed = () => {\n if (!isCurrentAttempt() || closingRef.current) return;\n finalizeSession();\n };\n\n const handleStreamOpenUrl = ({ data }) => {\n if (!isCurrentAttempt()) return;\n const { url } = parseServerEvent(data) || {};\n const allowedUrl = getAllowedOpenUrl(url);\n\n if (!allowedUrl) {\n Event.publish(EVENT.METRICS, { id: METRICS_EVENTS.AURA_ERROR, error: ERROR_BLOCKED_OPEN_URL });\n return;\n }\n\n Promise.resolve(endSession())\n .catch(() => {})\n .then(() => window.location.assign(allowedUrl));\n };\n\n try {\n mediaStream = await navigator.mediaDevices.getUserMedia({ audio: AUDIO_CONSTRAINTS });\n if (abortWhenStale()) return;\n localStreamRef.current = mediaStream;\n\n const analyzersReady = await createAudioAnalyzers(mediaStream, isCurrentAttempt);\n if (!analyzersReady || abortWhenStale()) return;\n\n peerConnection = new RTCPeerConnection();\n peerConnectionRef.current = peerConnection;\n\n audioElementRef.current = document.createElement('audio');\n audioElementRef.current.autoplay = true;\n\n peerConnection.addEventListener('connectionstatechange', () => {\n if (!isCurrentAttempt()) return;\n const { connectionState } = peerConnection;\n if (connectionState === 'connected') {\n connectionStateRef.current.connected = true;\n markReady();\n return;\n }\n if (TERMINAL_CONNECTION_STATES.includes(connectionState)) finalizeSession();\n });\n\n peerConnection.ontrack = ({ streams }) => {\n if (!isCurrentAttempt()) return;\n const [remoteStream] = streams || [];\n if (!remoteStream) return;\n\n if (audioElementRef.current) audioElementRef.current.srcObject = remoteStream;\n playRemoteAudio();\n\n const audioContext = audioContextRef.current;\n const { outputAnalyser } = audioAnalyzersRef.current;\n if (audioContext && outputAnalyser) {\n if (outputSourceRef.current) outputSourceRef.current.disconnect();\n outputSourceRef.current = audioContext.createMediaStreamSource(remoteStream);\n outputSourceRef.current.connect(outputAnalyser);\n }\n\n connectionStateRef.current.receiving = true;\n markReady();\n };\n\n dataChannel = peerConnection.createDataChannel(DATA_CHANNEL_LABEL);\n dataChannelRef.current = dataChannel;\n dataChannel.addEventListener('message', handleServerEvent);\n dataChannel.addEventListener('close', () => {\n if (!isCurrentAttempt() || closingRef.current) return;\n finalizeSession();\n });\n dataChannel.addEventListener('error', () => {\n if (!isCurrentAttempt()) return;\n finalizeSession();\n });\n\n const [track] = mediaStream.getAudioTracks();\n if (track) peerConnection.addTrack(track, mediaStream);\n\n const offer = await peerConnection.createOffer();\n if (abortWhenStale()) return;\n\n await peerConnection.setLocalDescription(offer);\n if (abortWhenStale()) return;\n\n await waitForIceGathering(peerConnection);\n if (abortWhenStale()) return;\n\n const { sdp } = peerConnection.localDescription || {};\n if (!sdp) throw new Error(ERROR_MISSING_LOCAL_SDP);\n\n const { session, transport } = await request({\n endpoint: SESSION_ENDPOINT,\n hostname: process.env.SERVICE_SYNAPSE,\n method: 'POST',\n chainId: isChain ? chainId : undefined,\n currency,\n fingerprint,\n hotelId: isChain ? undefined : hotelId,\n locale,\n sdp,\n });\n createdSessionId = session?.id ?? null;\n if (abortWhenStale()) return;\n\n if (!transport?.sdp) throw new Error(ERROR_MISSING_REMOTE_SDP);\n sessionIdRef.current = createdSessionId;\n\n await peerConnection.setRemoteDescription({ type: 'answer', sdp: transport.sdp });\n if (abortWhenStale()) return;\n\n openEventStream({\n fingerprint,\n onClosed: handleStreamClosed,\n onOpenUrl: handleStreamOpenUrl,\n sessionId: sessionIdRef.current,\n });\n } catch (error) {\n releaseAttempt();\n Event.publish(EVENT.METRICS, { id: METRICS_EVENTS.AURA_ERROR, error: error?.message });\n if (isCurrentAttempt()) {\n cleanupLiveSession();\n setReady(false);\n setIsConnecting(false);\n }\n throw error;\n }\n },\n [\n cleanupLiveSession,\n createAudioAnalyzers,\n endSession,\n openEventStream,\n playRemoteAudio,\n registerPageHide,\n waitForIceGathering,\n ],\n );\n\n return { startSession, endSession, audioAnalyzers: audioAnalyzersRef.current };\n};\n\nexport { useLiveSession };\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -8,6 +8,7 @@ var _dataSources = require("@mirai/data-sources");
|
|
|
8
8
|
var _react = require("react");
|
|
9
9
|
var _helpers = require("../../../../helpers");
|
|
10
10
|
var _helpers2 = require("../../../helpers");
|
|
11
|
+
var _helpers3 = require("../helpers");
|
|
11
12
|
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
12
13
|
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
13
14
|
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
@@ -139,10 +140,6 @@ const useOpenAiRealtimeSession = () => {
|
|
|
139
140
|
return null;
|
|
140
141
|
}
|
|
141
142
|
}, []);
|
|
142
|
-
const isAllowedOpenUrl = (0, _react.useCallback)(url => {
|
|
143
|
-
if (typeof url !== 'string') return false;
|
|
144
|
-
return url.trim().startsWith('https://api.mirai');
|
|
145
|
-
}, []);
|
|
146
143
|
const enableMicrophone = (0, _react.useCallback)(() => {
|
|
147
144
|
const track = localAudioTrackRef.current;
|
|
148
145
|
if (!track || microphoneEnabledRef.current) return;
|
|
@@ -340,12 +337,12 @@ const useOpenAiRealtimeSession = () => {
|
|
|
340
337
|
const callKey = call.key || call.callId || call.args || null;
|
|
341
338
|
if (callKey && functionStateRef.current.handledOpenUrlCalls.has(callKey)) continue;
|
|
342
339
|
const args = safeJsonParse(call.args);
|
|
343
|
-
const
|
|
344
|
-
if (!
|
|
340
|
+
const allowedUrl = (0, _helpers3.getAllowedOpenUrl)(args === null || args === void 0 ? void 0 : args.url);
|
|
341
|
+
if (!allowedUrl) {
|
|
345
342
|
if (call.callId) {
|
|
346
343
|
sendFunctionCallOutput(call.callId, {
|
|
347
344
|
error: 'blocked_url',
|
|
348
|
-
allowed_prefix:
|
|
345
|
+
allowed_prefix: (0, _helpers3.getAllowedOpenUrlPrefix)()
|
|
349
346
|
});
|
|
350
347
|
requestFollowupResponse('open_url_blocked', call.callId);
|
|
351
348
|
}
|
|
@@ -355,11 +352,11 @@ const useOpenAiRealtimeSession = () => {
|
|
|
355
352
|
if (callKey) functionStateRef.current.handledOpenUrlCalls.add(callKey);
|
|
356
353
|
if (call.key) functionStateRef.current.pendingCalls.delete(call.key);
|
|
357
354
|
cleanupRealtimeSession(true);
|
|
358
|
-
window.location.assign(
|
|
355
|
+
window.location.assign(allowedUrl);
|
|
359
356
|
return true;
|
|
360
357
|
}
|
|
361
358
|
return false;
|
|
362
|
-
}, [cleanupRealtimeSession, getFunctionCallKey,
|
|
359
|
+
}, [cleanupRealtimeSession, getFunctionCallKey, requestFollowupResponse, safeJsonParse, sendFunctionCallOutput, upsertFunctionCall]);
|
|
363
360
|
const startSession = (0, _react.useCallback)(async _ref3 => {
|
|
364
361
|
let assistant_name = _ref3.assistant_name,
|
|
365
362
|
chainId = _ref3.chainId,
|