@hivegpt/hiveai-angular 0.0.480 → 0.0.481

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.
@@ -1587,11 +1587,15 @@
1587
1587
  /** Static Daily.co room URL (used instead of dynamic room_created from backend). */
1588
1588
  var STATIC_DAILY_ROOM_URL = 'https://cloud-4a46e9dfbc8c499daddd480d9c294b88.daily.co/voice-None-1772776583';
1589
1589
  /**
1590
- * Voice agent orchestrator. Connects directly to a hardcoded Daily.co room — no API or WebSocket.
1590
+ * Voice agent orchestrator. Coordinates WebSocket (signaling) and Daily.js (WebRTC audio).
1591
1591
  *
1592
- * - When the modal opens, connect() is called and joins STATIC_DAILY_ROOM_URL immediately.
1593
- * - Daily.js (DailyVoiceClientService) handles all WebRTC audio, mic, and speaking detection.
1594
- * - Maintains callState, statusText, duration, isMicMuted, isUserSpeaking, audioLevels.
1592
+ * CRITICAL: This service must NEVER use Socket.IO or ngx-socket-io. Voice flow uses only:
1593
+ * - Native WebSocket (WebSocketVoiceClientService) for signaling (transcripts)
1594
+ * - Daily.js (DailyVoiceClientService) for WebRTC audio via STATIC_DAILY_ROOM_URL.
1595
+ *
1596
+ * - Maintains callState, statusText, duration, isMicMuted, isUserSpeaking, audioLevels
1597
+ * - Uses WebSocket for transcripts only (no audio)
1598
+ * - Uses Daily.js for all audio, mic, and real-time speaking detection
1595
1599
  */
1596
1600
  var VoiceAgentService = /** @class */ (function () {
1597
1601
  function VoiceAgentService(audioAnalyzer, wsClient, dailyClient) {
@@ -1622,10 +1626,6 @@
1622
1626
  // Waveform visualization only - do NOT use for speaking state
1623
1627
  this.subscriptions.add(this.audioAnalyzer.audioLevels$.subscribe(function (levels) { return _this.audioLevelsSubject.next(levels); }));
1624
1628
  }
1625
- /** Current call state (for checking if connection was already started). */
1626
- VoiceAgentService.prototype.getCallState = function () {
1627
- return this.callStateSubject.value;
1628
- };
1629
1629
  VoiceAgentService.prototype.ngOnDestroy = function () {
1630
1630
  this.destroy$.next();
1631
1631
  this.subscriptions.unsubscribe();
@@ -1644,92 +1644,135 @@
1644
1644
  this.statusTextSubject.next('');
1645
1645
  this.durationSubject.next('0:00');
1646
1646
  };
1647
- /** Connect directly to the hardcoded Daily room. No API or WebSocket as soon as modal opens. */
1648
- VoiceAgentService.prototype.connect = function () {
1647
+ VoiceAgentService.prototype.connect = function (apiUrl, token, botId, conversationId, apiKey, eventToken, eventUrl, domainAuthority) {
1649
1648
  return __awaiter(this, void 0, void 0, function () {
1650
- var err_1;
1651
- return __generator(this, function (_a) {
1652
- switch (_a.label) {
1649
+ var _a, wsOk, error_1;
1650
+ return __generator(this, function (_b) {
1651
+ switch (_b.label) {
1653
1652
  case 0:
1654
1653
  if (this.callStateSubject.value !== 'idle') {
1655
1654
  console.warn('Call already in progress');
1656
1655
  return [2 /*return*/];
1657
1656
  }
1657
+ _b.label = 1;
1658
+ case 1:
1659
+ _b.trys.push([1, 3, , 5]);
1658
1660
  this.callStateSubject.next('connecting');
1659
1661
  this.statusTextSubject.next('Connecting...');
1660
- _a.label = 1;
1661
- case 1:
1662
- _a.trys.push([1, 3, , 5]);
1663
- return [4 /*yield*/, this.onRoomCreated(STATIC_DAILY_ROOM_URL)];
1662
+ return [4 /*yield*/, Promise.all([
1663
+ this.connectWebSocketSignaling(token, botId, conversationId, apiKey, eventToken, eventUrl, domainAuthority),
1664
+ this.dailyClient.connect(STATIC_DAILY_ROOM_URL),
1665
+ ])];
1664
1666
  case 2:
1665
- _a.sent();
1667
+ _a = __read.apply(void 0, [_b.sent(), 1]), wsOk = _a[0];
1668
+ if (!wsOk) {
1669
+ throw new Error('No ws_url in response');
1670
+ }
1671
+ this.setupDailySubscriptions();
1666
1672
  return [3 /*break*/, 5];
1667
1673
  case 3:
1668
- err_1 = _a.sent();
1669
- console.error('Daily join failed:', err_1);
1674
+ error_1 = _b.sent();
1675
+ console.error('Error connecting voice agent:', error_1);
1670
1676
  this.callStateSubject.next('ended');
1671
- this.statusTextSubject.next('Connection failed');
1672
1677
  return [4 /*yield*/, this.disconnect()];
1673
1678
  case 4:
1674
- _a.sent();
1675
- throw err_1;
1679
+ _b.sent();
1680
+ this.statusTextSubject.next('Connection failed');
1681
+ throw error_1;
1676
1682
  case 5: return [2 /*return*/];
1677
1683
  }
1678
1684
  });
1679
1685
  });
1680
1686
  };
1681
- VoiceAgentService.prototype.onRoomCreated = function (roomUrl) {
1687
+ /** POST for ws_url, wire transcript streams, connect WebSocket. Returns true if ws_url was found. */
1688
+ VoiceAgentService.prototype.connectWebSocketSignaling = function (token, botId, conversationId, apiKey, eventToken, eventUrl, domainAuthority) {
1682
1689
  return __awaiter(this, void 0, void 0, function () {
1690
+ var postUrl, headers, res, json, wsUrl;
1683
1691
  var _this = this;
1684
1692
  return __generator(this, function (_a) {
1685
1693
  switch (_a.label) {
1686
- case 0:
1687
- // Connect Daily.js for WebRTC audio
1688
- return [4 /*yield*/, this.dailyClient.connect(roomUrl)];
1694
+ case 0:
1695
+ postUrl = "https://0a19-2405-201-5c02-991e-2487-d56-2543-bda8.ngrok-free.app/ai/ask-voice";
1696
+ headers = {
1697
+ 'Content-Type': 'application/json',
1698
+ Authorization: "Bearer " + token,
1699
+ 'domain-authority': domainAuthority,
1700
+ eventtoken: eventToken,
1701
+ eventurl: eventUrl,
1702
+ 'hive-bot-id': botId,
1703
+ 'x-api-key': apiKey,
1704
+ 'ngrok-skip-browser-warning': 'true',
1705
+ };
1706
+ return [4 /*yield*/, fetch(postUrl, {
1707
+ method: 'POST',
1708
+ headers: headers,
1709
+ body: JSON.stringify({
1710
+ bot_id: botId,
1711
+ conversation_id: conversationId,
1712
+ voice: 'alloy',
1713
+ }),
1714
+ })];
1689
1715
  case 1:
1690
- // Connect Daily.js for WebRTC audio
1691
- _a.sent();
1692
- // Waveform: use local mic stream from Daily client
1693
- this.dailyClient.localStream$
1694
- .pipe(operators.filter(function (s) { return s != null; }), operators.take(1))
1695
- .subscribe(function (stream) {
1696
- _this.audioAnalyzer.start(stream);
1697
- });
1698
- this.subscriptions.add(this.dailyClient.userSpeaking$.subscribe(function (s) { return _this.isUserSpeakingSubject.next(s); }));
1699
- this.subscriptions.add(rxjs.combineLatest([
1700
- this.dailyClient.speaking$,
1701
- this.dailyClient.userSpeaking$,
1702
- ]).subscribe(function (_a) {
1703
- var _b = __read(_a, 2), bot = _b[0], user = _b[1];
1704
- var current = _this.callStateSubject.value;
1705
- if (current === 'connecting' && !bot) {
1706
- return;
1707
- }
1708
- if (current === 'connecting' && bot) {
1709
- console.log("[VoiceDebug] First bot audio arrived \u2014 transitioning to talking \u2014 " + new Date().toISOString());
1710
- _this.callStartTime = Date.now();
1711
- _this.startDurationTimer();
1712
- _this.callStateSubject.next('talking');
1713
- return;
1714
- }
1715
- if (user) {
1716
- _this.callStateSubject.next('listening');
1717
- }
1718
- else if (bot) {
1719
- _this.callStateSubject.next('talking');
1720
- }
1721
- else if (current === 'talking' || current === 'listening') {
1722
- _this.callStateSubject.next('connected');
1723
- }
1724
- }));
1725
- this.subscriptions.add(this.dailyClient.micMuted$.subscribe(function (muted) { return _this.isMicMutedSubject.next(muted); }));
1726
- console.log("[VoiceDebug] Room joined, staying in connecting until bot speaks \u2014 " + new Date().toISOString());
1727
- this.statusTextSubject.next('Connecting...');
1728
- return [2 /*return*/];
1716
+ res = _a.sent();
1717
+ if (!res.ok) {
1718
+ throw new Error("HTTP " + res.status);
1719
+ }
1720
+ return [4 /*yield*/, res.json()];
1721
+ case 2:
1722
+ json = _a.sent();
1723
+ wsUrl = json === null || json === void 0 ? void 0 : json.rn_ws_url;
1724
+ if (!wsUrl || typeof wsUrl !== 'string') {
1725
+ return [2 /*return*/, false];
1726
+ }
1727
+ this.subscriptions.add(this.wsClient.userTranscript$
1728
+ .pipe(operators.takeUntil(this.destroy$))
1729
+ .subscribe(function (t) { return _this.userTranscriptSubject.next(t); }));
1730
+ this.subscriptions.add(this.wsClient.botTranscript$
1731
+ .pipe(operators.takeUntil(this.destroy$))
1732
+ .subscribe(function (t) { return _this.botTranscriptSubject.next(t); }));
1733
+ this.wsClient.connect(wsUrl);
1734
+ return [2 /*return*/, true];
1729
1735
  }
1730
1736
  });
1731
1737
  });
1732
1738
  };
1739
+ /** Wire Daily client to UI state (waveform, speaking, mic muted). Call after Daily is connected. */
1740
+ VoiceAgentService.prototype.setupDailySubscriptions = function () {
1741
+ var _this = this;
1742
+ this.dailyClient.localStream$
1743
+ .pipe(operators.filter(function (s) { return s != null; }), operators.take(1))
1744
+ .subscribe(function (stream) {
1745
+ _this.audioAnalyzer.start(stream);
1746
+ });
1747
+ this.subscriptions.add(this.dailyClient.userSpeaking$.subscribe(function (s) { return _this.isUserSpeakingSubject.next(s); }));
1748
+ this.subscriptions.add(rxjs.combineLatest([
1749
+ this.dailyClient.speaking$,
1750
+ this.dailyClient.userSpeaking$,
1751
+ ]).subscribe(function (_a) {
1752
+ var _b = __read(_a, 2), bot = _b[0], user = _b[1];
1753
+ var current = _this.callStateSubject.value;
1754
+ if (current === 'connecting' && !bot) {
1755
+ return;
1756
+ }
1757
+ if (current === 'connecting' && bot) {
1758
+ _this.callStartTime = Date.now();
1759
+ _this.startDurationTimer();
1760
+ _this.callStateSubject.next('talking');
1761
+ return;
1762
+ }
1763
+ if (user) {
1764
+ _this.callStateSubject.next('listening');
1765
+ }
1766
+ else if (bot) {
1767
+ _this.callStateSubject.next('talking');
1768
+ }
1769
+ else if (current === 'talking' || current === 'listening') {
1770
+ _this.callStateSubject.next('connected');
1771
+ }
1772
+ }));
1773
+ this.subscriptions.add(this.dailyClient.micMuted$.subscribe(function (muted) { return _this.isMicMutedSubject.next(muted); }));
1774
+ this.statusTextSubject.next('Connecting...');
1775
+ };
1733
1776
  VoiceAgentService.prototype.disconnect = function () {
1734
1777
  return __awaiter(this, void 0, void 0, function () {
1735
1778
  return __generator(this, function (_a) {
@@ -1863,13 +1906,9 @@
1863
1906
  this.subscriptions.push(this.voiceAgentService.audioLevels$.subscribe(function (levels) {
1864
1907
  _this.audioLevels = levels;
1865
1908
  }));
1866
- // If connection was already started from the drawer (openVoiceModal), don't reset or start again.
1867
- var state = this.voiceAgentService.getCallState();
1868
- var alreadyStarted = state !== 'idle' && state !== 'ended';
1869
- if (!alreadyStarted) {
1870
- this.voiceAgentService.resetToIdle();
1871
- void this.startCall();
1872
- }
1909
+ // Modal opens in idle state, then immediately starts connecting.
1910
+ this.voiceAgentService.resetToIdle();
1911
+ void this.startCall();
1873
1912
  };
1874
1913
  VoiceAgentModalComponent.prototype.ngOnDestroy = function () {
1875
1914
  this.subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
@@ -1887,7 +1926,7 @@
1887
1926
  _g.label = 1;
1888
1927
  case 1:
1889
1928
  _g.trys.push([1, 3, 4, 5]);
1890
- return [4 /*yield*/, this.voiceAgentService.connect()];
1929
+ return [4 /*yield*/, this.voiceAgentService.connect(this.apiUrl, this.token, this.botId, this.conversationId, this.apiKey, this.eventToken, this.eventUrl, this.domainAuthority)];
1891
1930
  case 2:
1892
1931
  _g.sent();
1893
1932
  return [3 /*break*/, 5];
@@ -4244,8 +4283,6 @@
4244
4283
  var conversationId = (_b = (_a = this.conversationKey) !== null && _a !== void 0 ? _a : this.conversationService.getKey(this.botId, false)) !== null && _b !== void 0 ? _b : '';
4245
4284
  this.voiceModalConversationId = conversationId;
4246
4285
  this.setupVoiceTranscripts();
4247
- // Start connecting to the voice room immediately (no wait for modal to open)
4248
- void this.voiceAgentService.connect();
4249
4286
  // Close existing overlay if any
4250
4287
  if (this.voiceModalOverlayRef) {
4251
4288
  this.voiceModalOverlayRef.detach();