@hivegpt/hiveai-angular 0.0.575 → 0.0.577
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/bundles/hivegpt-hiveai-angular.umd.js +195 -328
- package/bundles/hivegpt-hiveai-angular.umd.js.map +1 -1
- package/bundles/hivegpt-hiveai-angular.umd.min.js +1 -1
- package/bundles/hivegpt-hiveai-angular.umd.min.js.map +1 -1
- package/esm2015/lib/components/voice-agent/components/voice-agent-modal/voice-agent-modal.component.js +54 -85
- package/esm2015/lib/components/voice-agent/services/daily-voice-client.service.js +14 -22
- package/esm2015/lib/components/voice-agent/services/voice-agent.service.js +45 -67
- package/esm2015/lib/components/voice-agent/services/websocket-voice-client.service.js +34 -79
- package/fesm2015/hivegpt-hiveai-angular.js +142 -247
- package/fesm2015/hivegpt-hiveai-angular.js.map +1 -1
- package/hivegpt-hiveai-angular.metadata.json +1 -1
- package/lib/components/voice-agent/components/voice-agent-modal/voice-agent-modal.component.d.ts +1 -7
- package/lib/components/voice-agent/components/voice-agent-modal/voice-agent-modal.component.d.ts.map +1 -1
- package/lib/components/voice-agent/services/daily-voice-client.service.d.ts +3 -5
- package/lib/components/voice-agent/services/daily-voice-client.service.d.ts.map +1 -1
- package/lib/components/voice-agent/services/voice-agent.service.d.ts +1 -3
- package/lib/components/voice-agent/services/voice-agent.service.d.ts.map +1 -1
- package/lib/components/voice-agent/services/websocket-voice-client.service.d.ts +12 -5
- package/lib/components/voice-agent/services/websocket-voice-client.service.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1349,7 +1349,6 @@
|
|
|
1349
1349
|
* - Emit roomCreated$, userTranscript$, botTranscript$
|
|
1350
1350
|
* - NO audio logic, NO mic logic. Audio is handled by Daily.js (WebRTC).
|
|
1351
1351
|
*/
|
|
1352
|
-
var WS_CONNECT_TIMEOUT_MS = 10000;
|
|
1353
1352
|
var WebSocketVoiceClientService = /** @class */ (function () {
|
|
1354
1353
|
function WebSocketVoiceClientService() {
|
|
1355
1354
|
this.ws = null;
|
|
@@ -1363,99 +1362,55 @@
|
|
|
1363
1362
|
/** Emits bot transcript updates. */
|
|
1364
1363
|
this.botTranscript$ = this.botTranscriptSubject.asObservable();
|
|
1365
1364
|
}
|
|
1366
|
-
/**
|
|
1367
|
-
* Connect to signaling WebSocket. No audio over this connection.
|
|
1368
|
-
* Resolves when the socket is open; rejects if the connection fails.
|
|
1369
|
-
*/
|
|
1365
|
+
/** Connect to signaling WebSocket. No audio over this connection. */
|
|
1370
1366
|
WebSocketVoiceClientService.prototype.connect = function (wsUrl) {
|
|
1371
1367
|
var _this = this;
|
|
1372
1368
|
var _a;
|
|
1373
1369
|
if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) {
|
|
1374
|
-
return
|
|
1370
|
+
return;
|
|
1375
1371
|
}
|
|
1376
1372
|
if (this.ws) {
|
|
1377
1373
|
this.ws.close();
|
|
1378
1374
|
this.ws = null;
|
|
1379
1375
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1376
|
+
try {
|
|
1377
|
+
this.ws = new WebSocket(wsUrl);
|
|
1378
|
+
this.ws.onmessage = function (event) {
|
|
1383
1379
|
var _a;
|
|
1384
|
-
if (settled)
|
|
1385
|
-
return;
|
|
1386
|
-
settled = true;
|
|
1387
1380
|
try {
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
_this.ws = null;
|
|
1394
|
-
reject(new Error('WebSocket connection timed out'));
|
|
1395
|
-
}, WS_CONNECT_TIMEOUT_MS);
|
|
1396
|
-
var clear = function () {
|
|
1397
|
-
clearTimeout(timeout);
|
|
1398
|
-
};
|
|
1399
|
-
try {
|
|
1400
|
-
var ws = new WebSocket(wsUrl);
|
|
1401
|
-
_this.ws = ws;
|
|
1402
|
-
ws.onopen = function () {
|
|
1403
|
-
if (settled)
|
|
1404
|
-
return;
|
|
1405
|
-
settled = true;
|
|
1406
|
-
clear();
|
|
1407
|
-
resolve();
|
|
1408
|
-
};
|
|
1409
|
-
ws.onmessage = function (event) {
|
|
1410
|
-
var _a;
|
|
1411
|
-
try {
|
|
1412
|
-
var msg = JSON.parse(event.data);
|
|
1413
|
-
if ((msg === null || msg === void 0 ? void 0 : msg.type) === 'room_created') {
|
|
1414
|
-
var roomUrl = ((_a = msg.room_url) !== null && _a !== void 0 ? _a : msg.roomUrl);
|
|
1415
|
-
if (typeof roomUrl === 'string') {
|
|
1416
|
-
_this.roomCreatedSubject.next(roomUrl);
|
|
1417
|
-
}
|
|
1381
|
+
var msg = JSON.parse(event.data);
|
|
1382
|
+
if ((msg === null || msg === void 0 ? void 0 : msg.type) === 'room_created') {
|
|
1383
|
+
var roomUrl = ((_a = msg.room_url) !== null && _a !== void 0 ? _a : msg.roomUrl);
|
|
1384
|
+
if (typeof roomUrl === 'string') {
|
|
1385
|
+
_this.roomCreatedSubject.next(roomUrl);
|
|
1418
1386
|
}
|
|
1419
|
-
else if ((msg === null || msg === void 0 ? void 0 : msg.type) === 'user_transcript' && typeof msg.text === 'string') {
|
|
1420
|
-
_this.userTranscriptSubject.next({
|
|
1421
|
-
text: msg.text,
|
|
1422
|
-
final: msg.final === true,
|
|
1423
|
-
});
|
|
1424
|
-
}
|
|
1425
|
-
else if ((msg === null || msg === void 0 ? void 0 : msg.type) === 'bot_transcript' && typeof msg.text === 'string') {
|
|
1426
|
-
_this.botTranscriptSubject.next(msg.text);
|
|
1427
|
-
}
|
|
1428
|
-
}
|
|
1429
|
-
catch (_b) {
|
|
1430
|
-
// Ignore non-JSON or unknown messages
|
|
1431
1387
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
_this.disconnect();
|
|
1438
|
-
reject(new Error('WebSocket connection failed'));
|
|
1439
|
-
return;
|
|
1388
|
+
else if ((msg === null || msg === void 0 ? void 0 : msg.type) === 'user_transcript' && typeof msg.text === 'string') {
|
|
1389
|
+
_this.userTranscriptSubject.next({
|
|
1390
|
+
text: msg.text,
|
|
1391
|
+
final: msg.final === true,
|
|
1392
|
+
});
|
|
1440
1393
|
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
ws.onclose = function () {
|
|
1444
|
-
_this.ws = null;
|
|
1445
|
-
if (!settled) {
|
|
1446
|
-
settled = true;
|
|
1447
|
-
clear();
|
|
1448
|
-
reject(new Error('WebSocket connection failed'));
|
|
1394
|
+
else if ((msg === null || msg === void 0 ? void 0 : msg.type) === 'bot_transcript' && typeof msg.text === 'string') {
|
|
1395
|
+
_this.botTranscriptSubject.next(msg.text);
|
|
1449
1396
|
}
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1397
|
+
}
|
|
1398
|
+
catch (_b) {
|
|
1399
|
+
// Ignore non-JSON or unknown messages
|
|
1400
|
+
}
|
|
1401
|
+
};
|
|
1402
|
+
this.ws.onerror = function () {
|
|
1403
|
+
_this.disconnect();
|
|
1404
|
+
};
|
|
1405
|
+
this.ws.onclose = function () {
|
|
1455
1406
|
_this.ws = null;
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1407
|
+
};
|
|
1408
|
+
}
|
|
1409
|
+
catch (err) {
|
|
1410
|
+
console.error('WebSocketVoiceClient: connect failed', err);
|
|
1411
|
+
this.ws = null;
|
|
1412
|
+
throw err;
|
|
1413
|
+
}
|
|
1459
1414
|
};
|
|
1460
1415
|
/** Disconnect and cleanup. */
|
|
1461
1416
|
WebSocketVoiceClientService.prototype.disconnect = function () {
|
|
@@ -1503,8 +1458,7 @@
|
|
|
1503
1458
|
this.remoteAudioElement = null;
|
|
1504
1459
|
/** AnalyserNode-based remote audio monitor for instant bot speaking detection. */
|
|
1505
1460
|
this.remoteAudioContext = null;
|
|
1506
|
-
|
|
1507
|
-
this.remoteSpeakingPollId = null;
|
|
1461
|
+
this.remoteSpeakingRAF = null;
|
|
1508
1462
|
this.speakingSubject = new rxjs.BehaviorSubject(false);
|
|
1509
1463
|
this.userSpeakingSubject = new rxjs.BehaviorSubject(false);
|
|
1510
1464
|
this.micMutedSubject = new rxjs.BehaviorSubject(false);
|
|
@@ -1522,31 +1476,23 @@
|
|
|
1522
1476
|
* Connect to Daily room. Acquires mic first for waveform, then joins with audio.
|
|
1523
1477
|
* @param roomUrl Daily room URL (from room_created)
|
|
1524
1478
|
* @param token Optional meeting token
|
|
1525
|
-
* @param existingStream Optional pre-acquired mic (avoids a second getUserMedia / extra prompts on some browsers)
|
|
1526
1479
|
*/
|
|
1527
|
-
DailyVoiceClientService.prototype.connect = function (roomUrl, token
|
|
1480
|
+
DailyVoiceClientService.prototype.connect = function (roomUrl, token) {
|
|
1528
1481
|
return __awaiter(this, void 0, void 0, function () {
|
|
1529
|
-
var
|
|
1530
|
-
return __generator(this, function (
|
|
1531
|
-
switch (
|
|
1482
|
+
var stream, audioTrack, callObject, joinOptions, participants, err_1;
|
|
1483
|
+
return __generator(this, function (_e) {
|
|
1484
|
+
switch (_e.label) {
|
|
1532
1485
|
case 0:
|
|
1533
1486
|
if (!this.callObject) return [3 /*break*/, 2];
|
|
1534
1487
|
return [4 /*yield*/, this.disconnect()];
|
|
1535
1488
|
case 1:
|
|
1536
|
-
|
|
1537
|
-
|
|
1489
|
+
_e.sent();
|
|
1490
|
+
_e.label = 2;
|
|
1538
1491
|
case 2:
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
return [3 /*break*/, 5];
|
|
1544
|
-
case 3: return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
|
|
1545
|
-
case 4:
|
|
1546
|
-
_e = _f.sent();
|
|
1547
|
-
_f.label = 5;
|
|
1548
|
-
case 5:
|
|
1549
|
-
stream = _e;
|
|
1492
|
+
_e.trys.push([2, 5, , 6]);
|
|
1493
|
+
return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
|
|
1494
|
+
case 3:
|
|
1495
|
+
stream = _e.sent();
|
|
1550
1496
|
audioTrack = stream.getAudioTracks()[0];
|
|
1551
1497
|
if (!audioTrack) {
|
|
1552
1498
|
stream.getTracks().forEach(function (t) { return t.stop(); });
|
|
@@ -1565,8 +1511,8 @@
|
|
|
1565
1511
|
joinOptions.token = token;
|
|
1566
1512
|
}
|
|
1567
1513
|
return [4 /*yield*/, callObject.join(joinOptions)];
|
|
1568
|
-
case
|
|
1569
|
-
|
|
1514
|
+
case 4:
|
|
1515
|
+
_e.sent();
|
|
1570
1516
|
console.log("[VoiceDebug] Room connected (Daily join complete) \u2014 " + new Date().toISOString());
|
|
1571
1517
|
participants = callObject.participants();
|
|
1572
1518
|
if (participants === null || participants === void 0 ? void 0 : participants.local) {
|
|
@@ -1574,12 +1520,12 @@
|
|
|
1574
1520
|
}
|
|
1575
1521
|
// Initial mute state: Daily starts with audio on
|
|
1576
1522
|
this.micMutedSubject.next(!callObject.localAudio());
|
|
1577
|
-
return [3 /*break*/,
|
|
1578
|
-
case
|
|
1579
|
-
err_1 =
|
|
1523
|
+
return [3 /*break*/, 6];
|
|
1524
|
+
case 5:
|
|
1525
|
+
err_1 = _e.sent();
|
|
1580
1526
|
this.cleanup();
|
|
1581
1527
|
throw err_1;
|
|
1582
|
-
case
|
|
1528
|
+
case 6: return [2 /*return*/];
|
|
1583
1529
|
}
|
|
1584
1530
|
});
|
|
1585
1531
|
});
|
|
@@ -1680,7 +1626,7 @@
|
|
|
1680
1626
|
};
|
|
1681
1627
|
/**
|
|
1682
1628
|
* Monitor remote audio track energy via AnalyserNode.
|
|
1683
|
-
* Polls at ~
|
|
1629
|
+
* Polls at ~60fps and flips speakingSubject based on actual audio energy.
|
|
1684
1630
|
*/
|
|
1685
1631
|
DailyVoiceClientService.prototype.monitorRemoteAudio = function (track) {
|
|
1686
1632
|
var _this = this;
|
|
@@ -1695,17 +1641,11 @@
|
|
|
1695
1641
|
var dataArray_1 = new Uint8Array(analyser_1.frequencyBinCount);
|
|
1696
1642
|
var THRESHOLD_1 = 5;
|
|
1697
1643
|
var SILENCE_MS_1 = 1500;
|
|
1698
|
-
var POLL_MS = 100;
|
|
1699
1644
|
var lastSoundTime_1 = 0;
|
|
1700
1645
|
var isSpeaking_1 = false;
|
|
1701
|
-
|
|
1702
|
-
if (!_this.remoteAudioContext)
|
|
1703
|
-
if (_this.remoteSpeakingPollId) {
|
|
1704
|
-
clearInterval(_this.remoteSpeakingPollId);
|
|
1705
|
-
_this.remoteSpeakingPollId = null;
|
|
1706
|
-
}
|
|
1646
|
+
var poll_1 = function () {
|
|
1647
|
+
if (!_this.remoteAudioContext)
|
|
1707
1648
|
return;
|
|
1708
|
-
}
|
|
1709
1649
|
analyser_1.getByteFrequencyData(dataArray_1);
|
|
1710
1650
|
var sum = 0;
|
|
1711
1651
|
for (var i = 0; i < dataArray_1.length; i++) {
|
|
@@ -1729,16 +1669,18 @@
|
|
|
1729
1669
|
console.log("[VoiceDebug] Bot audio silence detected (speaking=false) \u2014 " + new Date().toISOString());
|
|
1730
1670
|
_this.ngZone.run(function () { return _this.speakingSubject.next(false); });
|
|
1731
1671
|
}
|
|
1732
|
-
|
|
1672
|
+
_this.remoteSpeakingRAF = requestAnimationFrame(poll_1);
|
|
1673
|
+
};
|
|
1674
|
+
this.remoteSpeakingRAF = requestAnimationFrame(poll_1);
|
|
1733
1675
|
}
|
|
1734
1676
|
catch (err) {
|
|
1735
1677
|
console.warn('DailyVoiceClient: failed to create remote audio monitor', err);
|
|
1736
1678
|
}
|
|
1737
1679
|
};
|
|
1738
1680
|
DailyVoiceClientService.prototype.stopRemoteAudioMonitor = function () {
|
|
1739
|
-
if (this.
|
|
1740
|
-
|
|
1741
|
-
this.
|
|
1681
|
+
if (this.remoteSpeakingRAF) {
|
|
1682
|
+
cancelAnimationFrame(this.remoteSpeakingRAF);
|
|
1683
|
+
this.remoteSpeakingRAF = null;
|
|
1742
1684
|
}
|
|
1743
1685
|
if (this.remoteAudioContext) {
|
|
1744
1686
|
this.remoteAudioContext.close().catch(function () { });
|
|
@@ -1851,8 +1793,6 @@
|
|
|
1851
1793
|
this.callStartTime = 0;
|
|
1852
1794
|
this.durationInterval = null;
|
|
1853
1795
|
this.subscriptions = new rxjs.Subscription();
|
|
1854
|
-
/** Per-call only; cleared on disconnect / reset / new room so handlers do not stack. */
|
|
1855
|
-
this.callSubscriptions = new rxjs.Subscription();
|
|
1856
1796
|
this.destroy$ = new rxjs.Subject();
|
|
1857
1797
|
this.callState$ = this.callStateSubject.asObservable();
|
|
1858
1798
|
this.statusText$ = this.statusTextSubject.asObservable();
|
|
@@ -1864,15 +1804,6 @@
|
|
|
1864
1804
|
this.botTranscript$ = this.botTranscriptSubject.asObservable();
|
|
1865
1805
|
// Waveform visualization only - do NOT use for speaking state
|
|
1866
1806
|
this.subscriptions.add(this.audioAnalyzer.audioLevels$.subscribe(function (levels) { return _this.audioLevelsSubject.next(levels); }));
|
|
1867
|
-
// Transcripts: single subscription for service lifetime (avoid stacking on each connect()).
|
|
1868
|
-
// WebSocket is disconnected between calls; no replay — new subscribers (setupVoiceTranscripts)
|
|
1869
|
-
// only receive messages from the new WS after connect.
|
|
1870
|
-
this.subscriptions.add(this.wsClient.userTranscript$
|
|
1871
|
-
.pipe(operators.takeUntil(this.destroy$))
|
|
1872
|
-
.subscribe(function (t) { return _this.userTranscriptSubject.next(t); }));
|
|
1873
|
-
this.subscriptions.add(this.wsClient.botTranscript$
|
|
1874
|
-
.pipe(operators.takeUntil(this.destroy$))
|
|
1875
|
-
.subscribe(function (t) { return _this.botTranscriptSubject.next(t); }));
|
|
1876
1807
|
}
|
|
1877
1808
|
VoiceAgentService.prototype.ngOnDestroy = function () {
|
|
1878
1809
|
this.destroy$.next();
|
|
@@ -1883,8 +1814,6 @@
|
|
|
1883
1814
|
VoiceAgentService.prototype.resetToIdle = function () {
|
|
1884
1815
|
if (this.callStateSubject.value === 'idle')
|
|
1885
1816
|
return;
|
|
1886
|
-
this.callSubscriptions.unsubscribe();
|
|
1887
|
-
this.callSubscriptions = new rxjs.Subscription();
|
|
1888
1817
|
this.stopDurationTimer();
|
|
1889
1818
|
this.audioAnalyzer.stop();
|
|
1890
1819
|
this.wsClient.disconnect();
|
|
@@ -1894,60 +1823,44 @@
|
|
|
1894
1823
|
this.statusTextSubject.next('');
|
|
1895
1824
|
this.durationSubject.next('0:00');
|
|
1896
1825
|
};
|
|
1897
|
-
VoiceAgentService.prototype.connect = function (apiUrl, token, botId, conversationId, apiKey, eventToken, eventId, eventUrl, domainAuthority, usersApiUrl
|
|
1898
|
-
var _a;
|
|
1826
|
+
VoiceAgentService.prototype.connect = function (apiUrl, token, botId, conversationId, apiKey, eventToken, eventId, eventUrl, domainAuthority, usersApiUrl) {
|
|
1899
1827
|
return __awaiter(this, void 0, void 0, function () {
|
|
1900
|
-
var
|
|
1828
|
+
var accessToken, ensured, e_1, baseUrl, postUrl, headers, res, json, wsUrl, error_1;
|
|
1901
1829
|
var _this = this;
|
|
1902
|
-
return __generator(this, function (
|
|
1903
|
-
switch (
|
|
1830
|
+
return __generator(this, function (_a) {
|
|
1831
|
+
switch (_a.label) {
|
|
1904
1832
|
case 0:
|
|
1905
1833
|
if (this.callStateSubject.value !== 'idle') {
|
|
1906
1834
|
console.warn('Call already in progress');
|
|
1907
1835
|
return [2 /*return*/];
|
|
1908
1836
|
}
|
|
1909
|
-
|
|
1837
|
+
_a.label = 1;
|
|
1910
1838
|
case 1:
|
|
1911
|
-
|
|
1839
|
+
_a.trys.push([1, 8, , 10]);
|
|
1912
1840
|
this.callStateSubject.next('connecting');
|
|
1913
1841
|
this.statusTextSubject.next('Connecting...');
|
|
1914
|
-
|
|
1915
|
-
|
|
1842
|
+
accessToken = token;
|
|
1843
|
+
if (!(usersApiUrl && common.isPlatformBrowser(this.platformId))) return [3 /*break*/, 5];
|
|
1844
|
+
_a.label = 2;
|
|
1845
|
+
case 2:
|
|
1846
|
+
_a.trys.push([2, 4, , 5]);
|
|
1847
|
+
return [4 /*yield*/, this.platformTokenRefresh
|
|
1916
1848
|
.ensureValidAccessToken(token, usersApiUrl)
|
|
1917
1849
|
.pipe(operators.take(1))
|
|
1918
|
-
.toPromise()
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
voice: 'alloy',
|
|
1933
|
-
}),
|
|
1934
|
-
};
|
|
1935
|
-
});
|
|
1936
|
-
micPromise = (existingMicStream === null || existingMicStream === void 0 ? void 0 : existingMicStream.getAudioTracks().some(function (t) { return t.readyState === 'live'; }))
|
|
1937
|
-
? Promise.resolve(existingMicStream)
|
|
1938
|
-
: common.isPlatformBrowser(this.platformId) &&
|
|
1939
|
-
((_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia)
|
|
1940
|
-
? navigator.mediaDevices
|
|
1941
|
-
.getUserMedia({ audio: true })
|
|
1942
|
-
.catch(function () { return undefined; })
|
|
1943
|
-
: Promise.resolve(undefined);
|
|
1944
|
-
return [4 /*yield*/, Promise.all([
|
|
1945
|
-
tokenPromise,
|
|
1946
|
-
prepPromise,
|
|
1947
|
-
micPromise,
|
|
1948
|
-
])];
|
|
1949
|
-
case 2:
|
|
1950
|
-
_b = __read.apply(void 0, [_d.sent(), 3]), accessToken = _b[0], _c = _b[1], postUrl = _c.postUrl, body = _c.body, micStream_1 = _b[2];
|
|
1850
|
+
.toPromise()];
|
|
1851
|
+
case 3:
|
|
1852
|
+
ensured = _a.sent();
|
|
1853
|
+
if (ensured === null || ensured === void 0 ? void 0 : ensured.accessToken) {
|
|
1854
|
+
accessToken = ensured.accessToken;
|
|
1855
|
+
}
|
|
1856
|
+
return [3 /*break*/, 5];
|
|
1857
|
+
case 4:
|
|
1858
|
+
e_1 = _a.sent();
|
|
1859
|
+
console.warn('[HiveGpt Voice] Token refresh before connect failed', e_1);
|
|
1860
|
+
return [3 /*break*/, 5];
|
|
1861
|
+
case 5:
|
|
1862
|
+
baseUrl = apiUrl.replace(/\/$/, '');
|
|
1863
|
+
postUrl = baseUrl + "/ai/ask-voice";
|
|
1951
1864
|
headers = {
|
|
1952
1865
|
'Content-Type': 'application/json',
|
|
1953
1866
|
Authorization: "Bearer " + accessToken,
|
|
@@ -1962,16 +1875,20 @@
|
|
|
1962
1875
|
return [4 /*yield*/, fetch(postUrl, {
|
|
1963
1876
|
method: 'POST',
|
|
1964
1877
|
headers: headers,
|
|
1965
|
-
body:
|
|
1878
|
+
body: JSON.stringify({
|
|
1879
|
+
bot_id: botId,
|
|
1880
|
+
conversation_id: conversationId,
|
|
1881
|
+
voice: 'alloy',
|
|
1882
|
+
}),
|
|
1966
1883
|
})];
|
|
1967
|
-
case
|
|
1968
|
-
res =
|
|
1884
|
+
case 6:
|
|
1885
|
+
res = _a.sent();
|
|
1969
1886
|
if (!res.ok) {
|
|
1970
1887
|
throw new Error("HTTP " + res.status);
|
|
1971
1888
|
}
|
|
1972
1889
|
return [4 /*yield*/, res.json()];
|
|
1973
|
-
case
|
|
1974
|
-
json =
|
|
1890
|
+
case 7:
|
|
1891
|
+
json = _a.sent();
|
|
1975
1892
|
wsUrl = json === null || json === void 0 ? void 0 : json.rn_ws_url;
|
|
1976
1893
|
if (!wsUrl || typeof wsUrl !== 'string') {
|
|
1977
1894
|
throw new Error('No ws_url in response');
|
|
@@ -1981,69 +1898,74 @@
|
|
|
1981
1898
|
.pipe(operators.take(1), operators.takeUntil(this.destroy$))
|
|
1982
1899
|
.subscribe(function (roomUrl) { return __awaiter(_this, void 0, void 0, function () {
|
|
1983
1900
|
var err_1;
|
|
1984
|
-
return __generator(this, function (
|
|
1985
|
-
switch (
|
|
1901
|
+
return __generator(this, function (_a) {
|
|
1902
|
+
switch (_a.label) {
|
|
1986
1903
|
case 0:
|
|
1987
|
-
|
|
1988
|
-
return [4 /*yield*/, this.onRoomCreated(roomUrl
|
|
1904
|
+
_a.trys.push([0, 2, , 4]);
|
|
1905
|
+
return [4 /*yield*/, this.onRoomCreated(roomUrl)];
|
|
1989
1906
|
case 1:
|
|
1990
|
-
|
|
1907
|
+
_a.sent();
|
|
1991
1908
|
return [3 /*break*/, 4];
|
|
1992
1909
|
case 2:
|
|
1993
|
-
err_1 =
|
|
1910
|
+
err_1 = _a.sent();
|
|
1994
1911
|
console.error('Daily join failed:', err_1);
|
|
1995
1912
|
this.callStateSubject.next('ended');
|
|
1996
1913
|
this.statusTextSubject.next('Connection failed');
|
|
1997
1914
|
return [4 /*yield*/, this.disconnect()];
|
|
1998
1915
|
case 3:
|
|
1999
|
-
|
|
1916
|
+
_a.sent();
|
|
2000
1917
|
throw err_1;
|
|
2001
1918
|
case 4: return [2 /*return*/];
|
|
2002
1919
|
}
|
|
2003
1920
|
});
|
|
2004
1921
|
}); });
|
|
1922
|
+
// Forward transcripts from WebSocket
|
|
1923
|
+
this.subscriptions.add(this.wsClient.userTranscript$
|
|
1924
|
+
.pipe(operators.takeUntil(this.destroy$))
|
|
1925
|
+
.subscribe(function (t) { return _this.userTranscriptSubject.next(t); }));
|
|
1926
|
+
this.subscriptions.add(this.wsClient.botTranscript$
|
|
1927
|
+
.pipe(operators.takeUntil(this.destroy$))
|
|
1928
|
+
.subscribe(function (t) { return _this.botTranscriptSubject.next(t); }));
|
|
2005
1929
|
// Connect signaling WebSocket (no audio over WS)
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
return [3 /*break*/, 8];
|
|
2011
|
-
case 6:
|
|
2012
|
-
error_1 = _d.sent();
|
|
1930
|
+
this.wsClient.connect(wsUrl);
|
|
1931
|
+
return [3 /*break*/, 10];
|
|
1932
|
+
case 8:
|
|
1933
|
+
error_1 = _a.sent();
|
|
2013
1934
|
console.error('Error connecting voice agent:', error_1);
|
|
2014
1935
|
this.callStateSubject.next('ended');
|
|
2015
1936
|
return [4 /*yield*/, this.disconnect()];
|
|
2016
|
-
case
|
|
2017
|
-
|
|
1937
|
+
case 9:
|
|
1938
|
+
_a.sent();
|
|
2018
1939
|
this.statusTextSubject.next('Connection failed');
|
|
2019
1940
|
throw error_1;
|
|
2020
|
-
case
|
|
1941
|
+
case 10: return [2 /*return*/];
|
|
2021
1942
|
}
|
|
2022
1943
|
});
|
|
2023
1944
|
});
|
|
2024
1945
|
};
|
|
2025
|
-
VoiceAgentService.prototype.onRoomCreated = function (roomUrl
|
|
1946
|
+
VoiceAgentService.prototype.onRoomCreated = function (roomUrl) {
|
|
2026
1947
|
return __awaiter(this, void 0, void 0, function () {
|
|
2027
1948
|
var _this = this;
|
|
2028
|
-
return __generator(this, function (
|
|
2029
|
-
switch (
|
|
2030
|
-
case 0:
|
|
1949
|
+
return __generator(this, function (_a) {
|
|
1950
|
+
switch (_a.label) {
|
|
1951
|
+
case 0:
|
|
1952
|
+
// Connect Daily.js for WebRTC audio
|
|
1953
|
+
return [4 /*yield*/, this.dailyClient.connect(roomUrl)];
|
|
2031
1954
|
case 1:
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
this.callSubscriptions = new rxjs.Subscription();
|
|
1955
|
+
// Connect Daily.js for WebRTC audio
|
|
1956
|
+
_a.sent();
|
|
2035
1957
|
// Waveform: use local mic stream from Daily client
|
|
2036
|
-
this.
|
|
1958
|
+
this.dailyClient.localStream$
|
|
2037
1959
|
.pipe(operators.filter(function (s) { return s != null; }), operators.take(1))
|
|
2038
1960
|
.subscribe(function (stream) {
|
|
2039
1961
|
_this.audioAnalyzer.start(stream);
|
|
2040
|
-
})
|
|
2041
|
-
this.
|
|
2042
|
-
this.
|
|
1962
|
+
});
|
|
1963
|
+
this.subscriptions.add(this.dailyClient.userSpeaking$.subscribe(function (s) { return _this.isUserSpeakingSubject.next(s); }));
|
|
1964
|
+
this.subscriptions.add(rxjs.combineLatest([
|
|
2043
1965
|
this.dailyClient.speaking$,
|
|
2044
1966
|
this.dailyClient.userSpeaking$,
|
|
2045
|
-
]).subscribe(function (
|
|
2046
|
-
var
|
|
1967
|
+
]).subscribe(function (_a) {
|
|
1968
|
+
var _b = __read(_a, 2), bot = _b[0], user = _b[1];
|
|
2047
1969
|
var current = _this.callStateSubject.value;
|
|
2048
1970
|
if (current === 'connecting' && !bot) {
|
|
2049
1971
|
return;
|
|
@@ -2060,12 +1982,11 @@
|
|
|
2060
1982
|
else if (bot) {
|
|
2061
1983
|
_this.callStateSubject.next('talking');
|
|
2062
1984
|
}
|
|
2063
|
-
else {
|
|
2064
|
-
|
|
2065
|
-
_this.callStateSubject.next('listening');
|
|
1985
|
+
else if (current === 'talking' || current === 'listening') {
|
|
1986
|
+
_this.callStateSubject.next('connected');
|
|
2066
1987
|
}
|
|
2067
1988
|
}));
|
|
2068
|
-
this.
|
|
1989
|
+
this.subscriptions.add(this.dailyClient.micMuted$.subscribe(function (muted) { return _this.isMicMutedSubject.next(muted); }));
|
|
2069
1990
|
this.statusTextSubject.next('Connecting...');
|
|
2070
1991
|
return [2 /*return*/];
|
|
2071
1992
|
}
|
|
@@ -2074,18 +1995,16 @@
|
|
|
2074
1995
|
};
|
|
2075
1996
|
VoiceAgentService.prototype.disconnect = function () {
|
|
2076
1997
|
return __awaiter(this, void 0, void 0, function () {
|
|
2077
|
-
return __generator(this, function (
|
|
2078
|
-
switch (
|
|
1998
|
+
return __generator(this, function (_a) {
|
|
1999
|
+
switch (_a.label) {
|
|
2079
2000
|
case 0:
|
|
2080
|
-
this.callSubscriptions.unsubscribe();
|
|
2081
|
-
this.callSubscriptions = new rxjs.Subscription();
|
|
2082
2001
|
this.stopDurationTimer();
|
|
2083
2002
|
this.audioAnalyzer.stop();
|
|
2084
2003
|
// Daily first, then WebSocket
|
|
2085
2004
|
return [4 /*yield*/, this.dailyClient.disconnect()];
|
|
2086
2005
|
case 1:
|
|
2087
2006
|
// Daily first, then WebSocket
|
|
2088
|
-
|
|
2007
|
+
_a.sent();
|
|
2089
2008
|
this.wsClient.disconnect();
|
|
2090
2009
|
this.callStateSubject.next('ended');
|
|
2091
2010
|
this.statusTextSubject.next('Call Ended');
|
|
@@ -2137,11 +2056,10 @@
|
|
|
2137
2056
|
var VOICE_MODAL_CLOSE_CALLBACK = new i0.InjectionToken('VOICE_MODAL_CLOSE_CALLBACK');
|
|
2138
2057
|
|
|
2139
2058
|
var VoiceAgentModalComponent = /** @class */ (function () {
|
|
2140
|
-
function VoiceAgentModalComponent(voiceAgentService, audioAnalyzer, injector
|
|
2059
|
+
function VoiceAgentModalComponent(voiceAgentService, audioAnalyzer, injector) {
|
|
2141
2060
|
this.voiceAgentService = voiceAgentService;
|
|
2142
2061
|
this.audioAnalyzer = audioAnalyzer;
|
|
2143
2062
|
this.injector = injector;
|
|
2144
|
-
this.platformId = platformId;
|
|
2145
2063
|
this.close = new i0.EventEmitter();
|
|
2146
2064
|
this.apiKey = '';
|
|
2147
2065
|
this.eventToken = '';
|
|
@@ -2153,8 +2071,6 @@
|
|
|
2153
2071
|
this.usersApiUrl = '';
|
|
2154
2072
|
this.injectedConfig = null;
|
|
2155
2073
|
this.onCloseCallback = null;
|
|
2156
|
-
/** Held until destroy; passed to Daily so we do not stop/re-acquire (avoids extra prompts on some browsers). */
|
|
2157
|
-
this.warmMicStream = null;
|
|
2158
2074
|
/** Hardcoded voice agent avatar (Nia). */
|
|
2159
2075
|
this.displayAvatarUrl = 'https://www.jotform.com/uploads/mehmetkarakasli/form_files/1564593667676a8e85f23758.86945537_icon.png';
|
|
2160
2076
|
this.callState = 'idle';
|
|
@@ -2170,108 +2086,63 @@
|
|
|
2170
2086
|
this.isConnecting = false;
|
|
2171
2087
|
}
|
|
2172
2088
|
VoiceAgentModalComponent.prototype.ngOnInit = function () {
|
|
2173
|
-
|
|
2174
|
-
};
|
|
2175
|
-
VoiceAgentModalComponent.prototype.bootstrap = function () {
|
|
2089
|
+
var _this = this;
|
|
2176
2090
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
}));
|
|
2225
|
-
this.voiceAgentService.resetToIdle();
|
|
2226
|
-
return [4 /*yield*/, this.startCall()];
|
|
2227
|
-
case 1:
|
|
2228
|
-
_j.sent();
|
|
2229
|
-
return [2 /*return*/];
|
|
2230
|
-
}
|
|
2231
|
-
});
|
|
2232
|
-
});
|
|
2091
|
+
// When opened via Overlay, config is provided by injection
|
|
2092
|
+
this.injectedConfig = this.injector.get(VOICE_MODAL_CONFIG, null);
|
|
2093
|
+
this.onCloseCallback = this.injector.get(VOICE_MODAL_CLOSE_CALLBACK, null);
|
|
2094
|
+
if (this.injectedConfig) {
|
|
2095
|
+
this.apiUrl = this.injectedConfig.apiUrl;
|
|
2096
|
+
this.token = this.injectedConfig.token;
|
|
2097
|
+
this.botId = this.injectedConfig.botId;
|
|
2098
|
+
this.conversationId = this.injectedConfig.conversationId;
|
|
2099
|
+
this.apiKey = (_a = this.injectedConfig.apiKey) !== null && _a !== void 0 ? _a : '';
|
|
2100
|
+
this.eventToken = (_b = this.injectedConfig.eventToken) !== null && _b !== void 0 ? _b : '';
|
|
2101
|
+
this.eventId = (_c = this.injectedConfig.eventId) !== null && _c !== void 0 ? _c : '';
|
|
2102
|
+
this.eventUrl = (_d = this.injectedConfig.eventUrl) !== null && _d !== void 0 ? _d : '';
|
|
2103
|
+
this.domainAuthority = (_e = this.injectedConfig.domainAuthority) !== null && _e !== void 0 ? _e : 'prod-lite';
|
|
2104
|
+
this.agentName = (_f = this.injectedConfig.agentName) !== null && _f !== void 0 ? _f : this.agentName;
|
|
2105
|
+
this.agentRole = (_g = this.injectedConfig.agentRole) !== null && _g !== void 0 ? _g : this.agentRole;
|
|
2106
|
+
this.agentAvatar = this.injectedConfig.agentAvatar;
|
|
2107
|
+
this.usersApiUrl = (_h = this.injectedConfig.usersApiUrl) !== null && _h !== void 0 ? _h : this.usersApiUrl;
|
|
2108
|
+
}
|
|
2109
|
+
// Subscribe to observables
|
|
2110
|
+
this.subscriptions.push(this.voiceAgentService.callState$.subscribe(function (state) {
|
|
2111
|
+
_this.callState = state;
|
|
2112
|
+
_this.isSpeaking = state === 'talking';
|
|
2113
|
+
if (state === 'listening' || state === 'talking') {
|
|
2114
|
+
_this.hasLeftConnectedOnce = true;
|
|
2115
|
+
}
|
|
2116
|
+
if (state === 'idle' || state === 'ended') {
|
|
2117
|
+
_this.hasLeftConnectedOnce = false;
|
|
2118
|
+
}
|
|
2119
|
+
}));
|
|
2120
|
+
this.subscriptions.push(this.voiceAgentService.statusText$.subscribe(function (text) {
|
|
2121
|
+
_this.statusText = text;
|
|
2122
|
+
}));
|
|
2123
|
+
this.subscriptions.push(this.voiceAgentService.duration$.subscribe(function (duration) {
|
|
2124
|
+
_this.duration = duration;
|
|
2125
|
+
}));
|
|
2126
|
+
this.subscriptions.push(this.voiceAgentService.isMicMuted$.subscribe(function (muted) {
|
|
2127
|
+
_this.isMicMuted = muted;
|
|
2128
|
+
}));
|
|
2129
|
+
this.subscriptions.push(this.voiceAgentService.isUserSpeaking$.subscribe(function (speaking) {
|
|
2130
|
+
_this.isUserSpeaking = speaking;
|
|
2131
|
+
}));
|
|
2132
|
+
this.subscriptions.push(this.voiceAgentService.audioLevels$.subscribe(function (levels) {
|
|
2133
|
+
_this.audioLevels = levels;
|
|
2134
|
+
}));
|
|
2135
|
+
// Modal opens in idle state, then immediately starts connecting.
|
|
2136
|
+
this.voiceAgentService.resetToIdle();
|
|
2137
|
+
void this.startCall();
|
|
2233
2138
|
};
|
|
2234
2139
|
VoiceAgentModalComponent.prototype.ngOnDestroy = function () {
|
|
2235
|
-
var _this = this;
|
|
2236
2140
|
this.subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
|
|
2237
|
-
|
|
2238
|
-
var _a;
|
|
2239
|
-
(_a = _this.warmMicStream) === null || _a === void 0 ? void 0 : _a.getTracks().forEach(function (t) { return t.stop(); });
|
|
2240
|
-
_this.warmMicStream = null;
|
|
2241
|
-
});
|
|
2242
|
-
};
|
|
2243
|
-
/** Ensures a live mic stream for this call (re-acquire after Daily stops tracks on hang-up). */
|
|
2244
|
-
VoiceAgentModalComponent.prototype.ensureMicForCall = function () {
|
|
2245
|
-
var _a;
|
|
2246
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
2247
|
-
var _j, _b_1;
|
|
2248
|
-
return __generator(this, function (_k) {
|
|
2249
|
-
switch (_k.label) {
|
|
2250
|
-
case 0:
|
|
2251
|
-
if (!common.isPlatformBrowser(this.platformId))
|
|
2252
|
-
return [2 /*return*/, undefined];
|
|
2253
|
-
if ((_a = this.warmMicStream) === null || _a === void 0 ? void 0 : _a.getAudioTracks().some(function (t) { return t.readyState === 'live'; })) {
|
|
2254
|
-
return [2 /*return*/, this.warmMicStream];
|
|
2255
|
-
}
|
|
2256
|
-
_k.label = 1;
|
|
2257
|
-
case 1:
|
|
2258
|
-
_k.trys.push([1, 3, , 4]);
|
|
2259
|
-
_j = this;
|
|
2260
|
-
return [4 /*yield*/, navigator.mediaDevices.getUserMedia({ audio: true })];
|
|
2261
|
-
case 2:
|
|
2262
|
-
_j.warmMicStream = _k.sent();
|
|
2263
|
-
return [2 /*return*/, this.warmMicStream];
|
|
2264
|
-
case 3:
|
|
2265
|
-
_b_1 = _k.sent();
|
|
2266
|
-
return [2 /*return*/, undefined];
|
|
2267
|
-
case 4: return [2 /*return*/];
|
|
2268
|
-
}
|
|
2269
|
-
});
|
|
2270
|
-
});
|
|
2141
|
+
this.disconnect();
|
|
2271
2142
|
};
|
|
2272
2143
|
VoiceAgentModalComponent.prototype.startCall = function () {
|
|
2273
2144
|
return __awaiter(this, void 0, void 0, function () {
|
|
2274
|
-
var
|
|
2145
|
+
var error_1;
|
|
2275
2146
|
return __generator(this, function (_j) {
|
|
2276
2147
|
switch (_j.label) {
|
|
2277
2148
|
case 0:
|
|
@@ -2280,22 +2151,19 @@
|
|
|
2280
2151
|
this.isConnecting = true;
|
|
2281
2152
|
_j.label = 1;
|
|
2282
2153
|
case 1:
|
|
2283
|
-
_j.trys.push([1, 4, 5
|
|
2284
|
-
return [4 /*yield*/, this.
|
|
2154
|
+
_j.trys.push([1, 3, 4, 5]);
|
|
2155
|
+
return [4 /*yield*/, this.voiceAgentService.connect(this.apiUrl, this.token, this.botId, this.conversationId, this.apiKey, this.eventToken, this.eventId, this.eventUrl, this.domainAuthority, this.usersApiUrl || undefined)];
|
|
2285
2156
|
case 2:
|
|
2286
|
-
mic = _j.sent();
|
|
2287
|
-
return [4 /*yield*/, this.voiceAgentService.connect(this.apiUrl, this.token, this.botId, this.conversationId, this.apiKey, this.eventToken, this.eventId, this.eventUrl, this.domainAuthority, this.usersApiUrl || undefined, mic)];
|
|
2288
|
-
case 3:
|
|
2289
2157
|
_j.sent();
|
|
2290
|
-
return [3 /*break*/,
|
|
2291
|
-
case
|
|
2158
|
+
return [3 /*break*/, 5];
|
|
2159
|
+
case 3:
|
|
2292
2160
|
error_1 = _j.sent();
|
|
2293
2161
|
console.error('Failed to connect voice agent:', error_1);
|
|
2294
|
-
return [3 /*break*/,
|
|
2295
|
-
case
|
|
2162
|
+
return [3 /*break*/, 5];
|
|
2163
|
+
case 4:
|
|
2296
2164
|
this.isConnecting = false;
|
|
2297
2165
|
return [7 /*endfinally*/];
|
|
2298
|
-
case
|
|
2166
|
+
case 5: return [2 /*return*/];
|
|
2299
2167
|
}
|
|
2300
2168
|
});
|
|
2301
2169
|
});
|
|
@@ -2340,7 +2208,7 @@
|
|
|
2340
2208
|
/** Call Again: reset to idle then start a new call. */
|
|
2341
2209
|
VoiceAgentModalComponent.prototype.callAgain = function () {
|
|
2342
2210
|
this.voiceAgentService.resetToIdle();
|
|
2343
|
-
|
|
2211
|
+
this.startCall();
|
|
2344
2212
|
};
|
|
2345
2213
|
/** Back to Chat: close modal and disconnect. */
|
|
2346
2214
|
VoiceAgentModalComponent.prototype.backToChat = function () {
|
|
@@ -2368,8 +2236,7 @@
|
|
|
2368
2236
|
VoiceAgentModalComponent.ctorParameters = function () { return [
|
|
2369
2237
|
{ type: VoiceAgentService },
|
|
2370
2238
|
{ type: AudioAnalyzerService },
|
|
2371
|
-
{ type: i0.Injector }
|
|
2372
|
-
{ type: Object, decorators: [{ type: i0.Inject, args: [i0.PLATFORM_ID,] }] }
|
|
2239
|
+
{ type: i0.Injector }
|
|
2373
2240
|
]; };
|
|
2374
2241
|
VoiceAgentModalComponent.propDecorators = {
|
|
2375
2242
|
close: [{ type: i0.Output }],
|