avin-ai 0.1.4 â 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avin-ai.es.js +119 -75
- package/dist/avin-ai.js +13 -7
- package/dist/avin-ai.umd.js +17 -11
- package/package.json +1 -1
package/dist/avin-ai.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var a = (
|
|
4
|
-
class
|
|
1
|
+
var b = Object.defineProperty;
|
|
2
|
+
var f = (c, e, t) => e in c ? b(c, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : c[e] = t;
|
|
3
|
+
var a = (c, e, t) => f(c, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
class w {
|
|
5
5
|
constructor(e) {
|
|
6
6
|
a(this, "serverUrl");
|
|
7
7
|
a(this, "agentId");
|
|
@@ -43,40 +43,40 @@ class f {
|
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
45
|
if (console.log("đ¤ [WebRTC] Microphone access granted"), !this.pc) {
|
|
46
|
-
console.log("[WebRTC] Connection aborted: peer connection closed during setup"), e.getTracks().forEach((
|
|
46
|
+
console.log("[WebRTC] Connection aborted: peer connection closed during setup"), e.getTracks().forEach((n) => n.stop());
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
if (e.getTracks().forEach((
|
|
50
|
-
var
|
|
51
|
-
(
|
|
49
|
+
if (e.getTracks().forEach((n) => {
|
|
50
|
+
var i;
|
|
51
|
+
(i = this.pc) == null || i.addTrack(n, e);
|
|
52
52
|
}), !this.pc)
|
|
53
53
|
throw new Error("RTCPeerConnection was closed unexpectedly");
|
|
54
|
-
this.dataChannel = this.pc.createDataChannel("control"), this.dataChannel.onopen = () => console.log("đĄ [WebRTC] DataChannel opened"), this.dataChannel.onmessage = (
|
|
55
|
-
if (typeof
|
|
54
|
+
this.dataChannel = this.pc.createDataChannel("control"), this.dataChannel.onopen = () => console.log("đĄ [WebRTC] DataChannel opened"), this.dataChannel.onmessage = (n) => {
|
|
55
|
+
if (typeof n.data == "string")
|
|
56
56
|
try {
|
|
57
|
-
this.handleControlEvent(JSON.parse(
|
|
57
|
+
this.handleControlEvent(JSON.parse(n.data));
|
|
58
58
|
} catch {
|
|
59
|
-
console.warn("[WebRTC] Failed to parse message:",
|
|
59
|
+
console.warn("[WebRTC] Failed to parse message:", n.data);
|
|
60
60
|
}
|
|
61
|
-
else
|
|
61
|
+
else n.data instanceof ArrayBuffer ? console.log("[WebRTC] Received binary data:", n.data.byteLength, "bytes") : n.data instanceof Blob && n.data.text().then((i) => {
|
|
62
62
|
try {
|
|
63
|
-
this.handleControlEvent(JSON.parse(
|
|
63
|
+
this.handleControlEvent(JSON.parse(i));
|
|
64
64
|
} catch {
|
|
65
|
-
console.warn("[WebRTC] Failed to parse blob data:",
|
|
65
|
+
console.warn("[WebRTC] Failed to parse blob data:", i);
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
|
-
}, this.dataChannel.onerror = (
|
|
69
|
-
const
|
|
70
|
-
console.log(`đĨ [WebRTC] Received ${
|
|
68
|
+
}, this.dataChannel.onerror = (n) => console.error("â [WebRTC] DataChannel error:", n), this.pc.ontrack = (n) => {
|
|
69
|
+
const i = n.track, s = n.streams[0];
|
|
70
|
+
console.log(`đĨ [WebRTC] Received ${i.kind} track`), i.kind === "audio" ? (console.log("đ [WebRTC] Received audio track from server"), this.audioElement = new Audio(), this.audioElement.srcObject = s, this.audioElement.play().catch((l) => console.warn("Audio autoplay blocked:", l)), this.audioElement.onended = () => {
|
|
71
71
|
this.sendEvent("playedStream"), console.log("â
[WebRTC] TTS playback complete");
|
|
72
|
-
}) :
|
|
72
|
+
}) : i.kind === "video" && (console.log("đš [WebRTC] Video track received"), this.onRemoteTrack(i, s));
|
|
73
73
|
}, this.pc.onconnectionstatechange = () => {
|
|
74
|
-
var
|
|
75
|
-
console.log("đ [WebRTC] State:", (
|
|
74
|
+
var n, i, s, l, h;
|
|
75
|
+
console.log("đ [WebRTC] State:", (n = this.pc) == null ? void 0 : n.connectionState), ((i = this.pc) == null ? void 0 : i.connectionState) === "connected" ? (this.connected = !0, this.onConnected()) : (((s = this.pc) == null ? void 0 : s.connectionState) === "failed" || ((l = this.pc) == null ? void 0 : l.connectionState) === "disconnected" || ((h = this.pc) == null ? void 0 : h.connectionState) === "closed") && (this.connected = !1, this.onDisconnected());
|
|
76
76
|
};
|
|
77
77
|
const t = await this.pc.createOffer();
|
|
78
78
|
await this.pc.setLocalDescription(t), console.log("đ [WebRTC] Created offer, waiting for ICE gathering..."), await this.waitForIceGathering(), console.log("đ§ [WebRTC] ICE gathering complete"), console.log("đ¤ [WebRTC] Sending offer via HTTP...");
|
|
79
|
-
const
|
|
79
|
+
const o = await fetch(`${this.serverUrl}/webrtc?agent=${this.agentId}_${this.callId}`, {
|
|
80
80
|
method: "POST",
|
|
81
81
|
headers: { "Content-Type": "application/json" },
|
|
82
82
|
body: JSON.stringify({
|
|
@@ -85,12 +85,12 @@ class f {
|
|
|
85
85
|
callId: this.callId
|
|
86
86
|
})
|
|
87
87
|
});
|
|
88
|
-
if (!
|
|
89
|
-
const
|
|
90
|
-
throw new Error(
|
|
88
|
+
if (!o.ok) {
|
|
89
|
+
const n = await o.json();
|
|
90
|
+
throw new Error(n.error || `HTTP ${o.status}`);
|
|
91
91
|
}
|
|
92
|
-
const { answer:
|
|
93
|
-
console.log("đĨ [WebRTC] Received answer from server"), await this.pc.setRemoteDescription(
|
|
92
|
+
const { answer: r } = await o.json();
|
|
93
|
+
console.log("đĨ [WebRTC] Received answer from server"), await this.pc.setRemoteDescription(r), console.log("â
[WebRTC] Connection established!");
|
|
94
94
|
} catch (e) {
|
|
95
95
|
throw console.error("â [WebRTC] Connection failed:", e), this.disconnect(), this.onError(e.message || e), e;
|
|
96
96
|
}
|
|
@@ -105,12 +105,12 @@ class f {
|
|
|
105
105
|
e();
|
|
106
106
|
else {
|
|
107
107
|
const t = () => {
|
|
108
|
-
var
|
|
109
|
-
((
|
|
108
|
+
var o, r;
|
|
109
|
+
((o = this.pc) == null ? void 0 : o.iceGatheringState) === "complete" && ((r = this.pc) == null || r.removeEventListener("icegatheringstatechange", t), e());
|
|
110
110
|
};
|
|
111
111
|
this.pc.addEventListener("icegatheringstatechange", t), setTimeout(() => {
|
|
112
|
-
var
|
|
113
|
-
(
|
|
112
|
+
var o;
|
|
113
|
+
(o = this.pc) == null || o.removeEventListener("icegatheringstatechange", t), console.warn("â ī¸ [WebRTC] ICE gathering timeout, proceeding anyway"), e();
|
|
114
114
|
}, 5e3);
|
|
115
115
|
}
|
|
116
116
|
});
|
|
@@ -119,8 +119,8 @@ class f {
|
|
|
119
119
|
* Send control event via DataChannel
|
|
120
120
|
*/
|
|
121
121
|
sendEvent(e, t = {}) {
|
|
122
|
-
var
|
|
123
|
-
((
|
|
122
|
+
var o;
|
|
123
|
+
((o = this.dataChannel) == null ? void 0 : o.readyState) === "open" && this.dataChannel.send(JSON.stringify({ event: e, ...t }));
|
|
124
124
|
}
|
|
125
125
|
/**
|
|
126
126
|
* Handle control events from server
|
|
@@ -155,8 +155,8 @@ class f {
|
|
|
155
155
|
return "web_" + Date.now() + "_" + Math.random().toString(36).substr(2, 8);
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
-
const
|
|
159
|
-
async function v(
|
|
158
|
+
const p = "https://coredb.travelr.club/v1/graphql";
|
|
159
|
+
async function v(c) {
|
|
160
160
|
var t;
|
|
161
161
|
const e = `
|
|
162
162
|
query GetWidgetConfig($id: uuid!) {
|
|
@@ -175,21 +175,57 @@ async function v(s) {
|
|
|
175
175
|
}
|
|
176
176
|
`;
|
|
177
177
|
try {
|
|
178
|
-
const
|
|
178
|
+
const n = (t = (await (await fetch(p, {
|
|
179
179
|
method: "POST",
|
|
180
180
|
headers: {
|
|
181
181
|
"Content-Type": "application/json"
|
|
182
182
|
},
|
|
183
183
|
body: JSON.stringify({
|
|
184
184
|
query: e,
|
|
185
|
-
variables: { id:
|
|
185
|
+
variables: { id: c }
|
|
186
186
|
})
|
|
187
187
|
})).json()).data) == null ? void 0 : t.app_widget_by_pk;
|
|
188
|
-
if (!
|
|
189
|
-
throw new Error(`Widget configuration not found for ID: ${
|
|
190
|
-
return
|
|
191
|
-
} catch (
|
|
192
|
-
throw console.error("[AvinAI] Failed to fetch widget config:",
|
|
188
|
+
if (!n)
|
|
189
|
+
throw new Error(`Widget configuration not found for ID: ${c}`);
|
|
190
|
+
return n;
|
|
191
|
+
} catch (o) {
|
|
192
|
+
throw console.error("[AvinAI] Failed to fetch widget config:", o), o;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function m(c, e = !1) {
|
|
196
|
+
var r, n;
|
|
197
|
+
const t = `
|
|
198
|
+
mutation CreateWebCall($object: calls_insert_input!) {
|
|
199
|
+
insert_calls_one(object: $object) {
|
|
200
|
+
id
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
`, o = {
|
|
204
|
+
object: {
|
|
205
|
+
agent_id: c,
|
|
206
|
+
status: "in-progress",
|
|
207
|
+
type: "web_call",
|
|
208
|
+
direction: "inbound",
|
|
209
|
+
phone_to: "web_user",
|
|
210
|
+
is_ai_avatar_enabled: e
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
try {
|
|
214
|
+
const s = await (await fetch(p, {
|
|
215
|
+
method: "POST",
|
|
216
|
+
headers: {
|
|
217
|
+
"Content-Type": "application/json"
|
|
218
|
+
},
|
|
219
|
+
body: JSON.stringify({
|
|
220
|
+
query: t,
|
|
221
|
+
variables: o
|
|
222
|
+
})
|
|
223
|
+
})).json();
|
|
224
|
+
if (s.errors)
|
|
225
|
+
throw new Error(s.errors[0].message);
|
|
226
|
+
return (n = (r = s.data) == null ? void 0 : r.insert_calls_one) == null ? void 0 : n.id;
|
|
227
|
+
} catch (i) {
|
|
228
|
+
throw console.error("[AvinAI] Failed to create call record:", i), i;
|
|
193
229
|
}
|
|
194
230
|
}
|
|
195
231
|
const d = {
|
|
@@ -226,7 +262,7 @@ const d = {
|
|
|
226
262
|
<path d="M2 18c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 2.6 0 2.4 2 5 2 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/>
|
|
227
263
|
</svg>
|
|
228
264
|
`
|
|
229
|
-
},
|
|
265
|
+
}, y = `
|
|
230
266
|
* {
|
|
231
267
|
box-sizing: border-box;
|
|
232
268
|
}
|
|
@@ -484,7 +520,7 @@ const d = {
|
|
|
484
520
|
}
|
|
485
521
|
}
|
|
486
522
|
`;
|
|
487
|
-
class
|
|
523
|
+
class C extends HTMLElement {
|
|
488
524
|
constructor() {
|
|
489
525
|
super();
|
|
490
526
|
a(this, "isPanelOpen", !1);
|
|
@@ -504,36 +540,36 @@ class y extends HTMLElement {
|
|
|
504
540
|
}
|
|
505
541
|
connectedCallback() {
|
|
506
542
|
console.log("[AvinAI Widget] Initializing..."), this.widgetId = this.getAttribute("widget-id") || "", this.agentId = this.getAttribute("agent-id") || "", this.serverUrl = this.getAttribute("server-url") || "https://api.travelr.club";
|
|
507
|
-
const t = this.getAttribute("position") || "bottom-right",
|
|
508
|
-
this.render(t,
|
|
543
|
+
const t = this.getAttribute("position") || "bottom-right", o = this.getAttribute("primary-color") || "#6366f1";
|
|
544
|
+
this.render(t, o), this.attachEventListeners(), this.widgetId && !this.agentId && this.initializeConfig();
|
|
509
545
|
}
|
|
510
546
|
async initializeConfig() {
|
|
511
|
-
var t,
|
|
547
|
+
var t, o, r, n;
|
|
512
548
|
try {
|
|
513
549
|
console.log(`[AvinAI Widget] Fetching config for widget: ${this.widgetId}`);
|
|
514
|
-
const
|
|
515
|
-
this.agentId =
|
|
516
|
-
} catch (
|
|
517
|
-
console.error("[AvinAI Widget] Configuration failed:",
|
|
550
|
+
const i = await v(this.widgetId);
|
|
551
|
+
this.agentId = i.agent_id, ((n = (r = (o = (t = i.agent) == null ? void 0 : t.tts_voice) == null ? void 0 : o.provider) == null ? void 0 : r.root_name) == null ? void 0 : n.toLowerCase()) === "premium" ? this.serverUrl = "https://godspeed.travelr.club" : this.serverUrl = "https://in-godspeed.travelr.club", console.log(`[AvinAI Widget] Configured for Agent ID: ${this.agentId}`), console.log(`[AvinAI Widget] Using Server URL: ${this.serverUrl}`);
|
|
552
|
+
} catch (i) {
|
|
553
|
+
console.error("[AvinAI Widget] Configuration failed:", i), this.updateStatus("Configuration Failed", "error");
|
|
518
554
|
}
|
|
519
555
|
}
|
|
520
|
-
render(t,
|
|
521
|
-
const
|
|
556
|
+
render(t, o) {
|
|
557
|
+
const r = {
|
|
522
558
|
"bottom-right": { bottom: "24px", right: "24px" },
|
|
523
559
|
"bottom-left": { bottom: "24px", left: "24px" },
|
|
524
560
|
"top-right": { top: "24px", right: "24px" },
|
|
525
561
|
"top-left": { top: "24px", left: "24px" }
|
|
526
|
-
},
|
|
562
|
+
}, n = r[t] || r["bottom-right"], i = Object.entries(n).map(([g, u]) => `${g}: ${u}`).join("; "), s = t.includes("bottom") ? "bottom: 100px;" : "top: 100px;", l = t.includes("right") ? "right: 24px;" : "left: 24px;", h = y.replace("--primary: #6366f1", `--primary: ${o}`);
|
|
527
563
|
this.shadow.innerHTML = `
|
|
528
564
|
<style>${h}</style>
|
|
529
565
|
|
|
530
566
|
<!-- Floating Action Button -->
|
|
531
|
-
<button class="widget-fab" style="${
|
|
567
|
+
<button class="widget-fab" style="${i}">
|
|
532
568
|
${d.phone}
|
|
533
569
|
</button>
|
|
534
570
|
|
|
535
571
|
<!-- Voice Panel -->
|
|
536
|
-
<div class="widget-panel hidden" style="width: 380px; height: 480px; ${
|
|
572
|
+
<div class="widget-panel hidden" style="width: 380px; height: 480px; ${s} ${l}">
|
|
537
573
|
<div class="widget-header">
|
|
538
574
|
<h3 class="widget-title">Voice Assistant</h3>
|
|
539
575
|
<button class="close-btn" id="close-panel">
|
|
@@ -562,45 +598,53 @@ class y extends HTMLElement {
|
|
|
562
598
|
`;
|
|
563
599
|
}
|
|
564
600
|
attachEventListeners() {
|
|
565
|
-
const t = this.shadow.querySelector(".widget-fab"),
|
|
601
|
+
const t = this.shadow.querySelector(".widget-fab"), o = this.shadow.querySelector(".widget-panel"), r = this.shadow.querySelector("#close-panel"), n = this.shadow.querySelector("#start-btn");
|
|
566
602
|
t == null || t.addEventListener("click", () => {
|
|
567
|
-
this.isPanelOpen = !this.isPanelOpen,
|
|
568
|
-
}),
|
|
569
|
-
this.isPanelOpen = !1,
|
|
570
|
-
}),
|
|
603
|
+
this.isPanelOpen = !this.isPanelOpen, o == null || o.classList.toggle("hidden", !this.isPanelOpen);
|
|
604
|
+
}), r == null || r.addEventListener("click", () => {
|
|
605
|
+
this.isPanelOpen = !1, o == null || o.classList.add("hidden");
|
|
606
|
+
}), n == null || n.addEventListener("click", () => {
|
|
571
607
|
this.callActive ? this.stopCall() : this.startCall();
|
|
572
608
|
});
|
|
573
609
|
}
|
|
574
|
-
updateStatus(t,
|
|
575
|
-
const
|
|
576
|
-
|
|
610
|
+
updateStatus(t, o) {
|
|
611
|
+
const r = this.shadow.querySelector("#status-text"), n = this.shadow.querySelector("#status-dot");
|
|
612
|
+
r && (r.textContent = t), n && (o === "idle" && (n.style.background = "#ef4444"), o === "connecting" && (n.style.background = "#f59e0b"), o === "connected" && (n.style.background = "#10b981"), o === "error" && (n.style.background = "#ef4444"));
|
|
577
613
|
}
|
|
578
614
|
async startCall() {
|
|
579
615
|
if (!this.agentId) {
|
|
580
616
|
this.updateStatus("Error: Agent ID not configured", "error");
|
|
581
617
|
return;
|
|
582
618
|
}
|
|
583
|
-
const t = this.shadow.querySelector("#start-btn"),
|
|
619
|
+
const t = this.shadow.querySelector("#start-btn"), o = this.shadow.querySelector("#transcript");
|
|
584
620
|
try {
|
|
585
|
-
this.updateStatus("Connecting...", "connecting"), t && (t.disabled = !0),
|
|
621
|
+
this.updateStatus("Connecting...", "connecting"), t && (t.disabled = !0), console.log("[AvinAI Widget] Creating call record...");
|
|
622
|
+
const r = await m(this.agentId);
|
|
623
|
+
console.log(`[AvinAI Widget] Call created with ID: ${r}`), this.client = new w({
|
|
586
624
|
serverUrl: this.serverUrl,
|
|
587
625
|
agentId: this.agentId,
|
|
626
|
+
callId: r,
|
|
627
|
+
// Pass the DB-generated Call UUID
|
|
588
628
|
onConnected: () => {
|
|
589
629
|
this.callActive = !0, this.updateStatus("Connected - Listening...", "connected"), t && (t.innerHTML = `${d.close}<span>End Call</span>`, t.className = "control-btn danger", t.disabled = !1);
|
|
590
630
|
},
|
|
591
631
|
onDisconnected: () => {
|
|
592
632
|
this.stopCall();
|
|
593
633
|
},
|
|
594
|
-
onError: (
|
|
595
|
-
this.updateStatus(`Error: ${
|
|
634
|
+
onError: (n) => {
|
|
635
|
+
this.updateStatus(`Error: ${n.message || "Connection failed"}`, "error"), t && (t.disabled = !1);
|
|
636
|
+
},
|
|
637
|
+
// @ts-ignore
|
|
638
|
+
onRemoteTrack: (n, i) => {
|
|
639
|
+
console.log("[AvinAI Widget] Remote track received:", n.kind);
|
|
596
640
|
},
|
|
597
|
-
onTranscription: (
|
|
598
|
-
|
|
599
|
-
` : "") +
|
|
641
|
+
onTranscription: (n, i) => {
|
|
642
|
+
i && (this.transcript += (this.transcript ? `
|
|
643
|
+
` : "") + n, o && (o.innerHTML = this.transcript, o.scrollTop = o.scrollHeight));
|
|
600
644
|
}
|
|
601
645
|
}), await this.client.connect();
|
|
602
|
-
} catch (
|
|
603
|
-
console.error("[AvinAI Widget] Start call failed:",
|
|
646
|
+
} catch (r) {
|
|
647
|
+
console.error("[AvinAI Widget] Start call failed:", r), this.updateStatus(`Connection failed: ${r.message}`, "error"), t && (t.disabled = !1);
|
|
604
648
|
}
|
|
605
649
|
}
|
|
606
650
|
stopCall() {
|
|
@@ -613,7 +657,7 @@ class y extends HTMLElement {
|
|
|
613
657
|
}
|
|
614
658
|
}
|
|
615
659
|
export {
|
|
616
|
-
|
|
617
|
-
|
|
660
|
+
C as AvinWidget,
|
|
661
|
+
w as WebRTCClient,
|
|
618
662
|
v as fetchWidgetConfig
|
|
619
663
|
};
|
package/dist/avin-ai.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var
|
|
1
|
+
var x=Object.defineProperty;var C=(d,c,p)=>c in d?x(d,c,{enumerable:!0,configurable:!0,writable:!0,value:p}):d[c]=p;var a=(d,c,p)=>C(d,typeof c!="symbol"?c+"":c,p);(function(){"use strict";class d{constructor(n){a(this,"serverUrl");a(this,"agentId");a(this,"callId");a(this,"onConnected");a(this,"onDisconnected");a(this,"onError");a(this,"onTranscription");a(this,"onRemoteTrack");a(this,"pc",null);a(this,"dataChannel",null);a(this,"audioElement",null);a(this,"connected",!1);if(!n.serverUrl)throw new Error("serverUrl is required");if(!n.agentId)throw new Error("agentId is required");this.serverUrl=n.serverUrl.replace(/\/$/,""),this.agentId=n.agentId,this.callId=n.callId||this.generateCallId(),this.onConnected=n.onConnected||(()=>{}),this.onDisconnected=n.onDisconnected||(()=>{}),this.onError=n.onError||(e=>console.error("[WebRTC]",e)),this.onTranscription=n.onTranscription||(()=>{}),this.onRemoteTrack=n.onRemoteTrack||(()=>{})}async connect(){console.log("đĩ [WebRTC] Starting connection...");try{this.pc=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]}),this.pc.addTransceiver("video",{direction:"recvonly"});const n=await navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,sampleRate:{ideal:16e3},channelCount:1}});if(console.log("đ¤ [WebRTC] Microphone access granted"),!this.pc){console.log("[WebRTC] Connection aborted: peer connection closed during setup"),n.getTracks().forEach(t=>t.stop());return}if(n.getTracks().forEach(t=>{var r;(r=this.pc)==null||r.addTrack(t,n)}),!this.pc)throw new Error("RTCPeerConnection was closed unexpectedly");this.dataChannel=this.pc.createDataChannel("control"),this.dataChannel.onopen=()=>console.log("đĄ [WebRTC] DataChannel opened"),this.dataChannel.onmessage=t=>{if(typeof t.data=="string")try{this.handleControlEvent(JSON.parse(t.data))}catch{console.warn("[WebRTC] Failed to parse message:",t.data)}else t.data instanceof ArrayBuffer?console.log("[WebRTC] Received binary data:",t.data.byteLength,"bytes"):t.data instanceof Blob&&t.data.text().then(r=>{try{this.handleControlEvent(JSON.parse(r))}catch{console.warn("[WebRTC] Failed to parse blob data:",r)}})},this.dataChannel.onerror=t=>console.error("â [WebRTC] DataChannel error:",t),this.pc.ontrack=t=>{const r=t.track,s=t.streams[0];console.log(`đĨ [WebRTC] Received ${r.kind} track`),r.kind==="audio"?(console.log("đ [WebRTC] Received audio track from server"),this.audioElement=new Audio,this.audioElement.srcObject=s,this.audioElement.play().catch(g=>console.warn("Audio autoplay blocked:",g)),this.audioElement.onended=()=>{this.sendEvent("playedStream"),console.log("â
[WebRTC] TTS playback complete")}):r.kind==="video"&&(console.log("đš [WebRTC] Video track received"),this.onRemoteTrack(r,s))},this.pc.onconnectionstatechange=()=>{var t,r,s,g,b;console.log("đ [WebRTC] State:",(t=this.pc)==null?void 0:t.connectionState),((r=this.pc)==null?void 0:r.connectionState)==="connected"?(this.connected=!0,this.onConnected()):(((s=this.pc)==null?void 0:s.connectionState)==="failed"||((g=this.pc)==null?void 0:g.connectionState)==="disconnected"||((b=this.pc)==null?void 0:b.connectionState)==="closed")&&(this.connected=!1,this.onDisconnected())};const e=await this.pc.createOffer();await this.pc.setLocalDescription(e),console.log("đ [WebRTC] Created offer, waiting for ICE gathering..."),await this.waitForIceGathering(),console.log("đ§ [WebRTC] ICE gathering complete"),console.log("đ¤ [WebRTC] Sending offer via HTTP...");const o=await fetch(`${this.serverUrl}/webrtc?agent=${this.agentId}_${this.callId}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({offer:this.pc.localDescription,agentId:this.agentId,callId:this.callId})});if(!o.ok){const t=await o.json();throw new Error(t.error||`HTTP ${o.status}`)}const{answer:i}=await o.json();console.log("đĨ [WebRTC] Received answer from server"),await this.pc.setRemoteDescription(i),console.log("â
[WebRTC] Connection established!")}catch(n){throw console.error("â [WebRTC] Connection failed:",n),this.disconnect(),this.onError(n.message||n),n}}waitForIceGathering(){return new Promise(n=>{if(!this.pc)return n();if(this.pc.iceGatheringState==="complete")n();else{const e=()=>{var o,i;((o=this.pc)==null?void 0:o.iceGatheringState)==="complete"&&((i=this.pc)==null||i.removeEventListener("icegatheringstatechange",e),n())};this.pc.addEventListener("icegatheringstatechange",e),setTimeout(()=>{var o;(o=this.pc)==null||o.removeEventListener("icegatheringstatechange",e),console.warn("â ī¸ [WebRTC] ICE gathering timeout, proceeding anyway"),n()},5e3)}})}sendEvent(n,e={}){var o;((o=this.dataChannel)==null?void 0:o.readyState)==="open"&&this.dataChannel.send(JSON.stringify({event:n,...e}))}handleControlEvent(n){switch(n.event){case"clearAudio":console.log("đ [WebRTC] Interrupt: stopping audio"),this.audioElement&&(this.audioElement.pause(),this.audioElement.currentTime=0);break;case"transcription":console.log("đ [WebRTC] Transcription:",n.text),this.onTranscription(n.text,n.isFinal);break;case"mark":console.log("đˇī¸ [WebRTC] Mark:",n.name);break;default:console.log("âšī¸ [WebRTC] Unknown event:",n.event)}}disconnect(){console.log("đ´ [WebRTC] Disconnecting..."),this.audioElement&&(this.audioElement.pause(),this.audioElement.srcObject=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.pc&&(this.pc.getSenders().forEach(n=>{n.track&&n.track.stop()}),this.pc.close(),this.pc=null),this.connected=!1,this.onDisconnected()}generateCallId(){return"web_"+Date.now()+"_"+Math.random().toString(36).substr(2,8)}}const c="https://coredb.travelr.club/v1/graphql";async function p(l){var e;const n=`
|
|
2
2
|
query GetWidgetConfig($id: uuid!) {
|
|
3
3
|
app_widget_by_pk(id: $id) {
|
|
4
4
|
agent_id
|
|
@@ -13,7 +13,13 @@ var y=Object.defineProperty;var x=(l,s,p)=>s in l?y(l,s,{enumerable:!0,configura
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
`;try{const
|
|
16
|
+
`;try{const t=(e=(await(await fetch(c,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:n,variables:{id:l}})})).json()).data)==null?void 0:e.app_widget_by_pk;if(!t)throw new Error(`Widget configuration not found for ID: ${l}`);return t}catch(o){throw console.error("[AvinAI] Failed to fetch widget config:",o),o}}async function w(l,n=!1){var i,t;const e=`
|
|
17
|
+
mutation CreateWebCall($object: calls_insert_input!) {
|
|
18
|
+
insert_calls_one(object: $object) {
|
|
19
|
+
id
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
`,o={object:{agent_id:l,status:"in-progress",type:"web_call",direction:"inbound",phone_to:"web_user",is_ai_avatar_enabled:n}};try{const s=await(await fetch(c,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:e,variables:o})})).json();if(s.errors)throw new Error(s.errors[0].message);return(t=(i=s.data)==null?void 0:i.insert_calls_one)==null?void 0:t.id}catch(r){throw console.error("[AvinAI] Failed to create call record:",r),r}}const u={phone:`
|
|
17
23
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
18
24
|
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/>
|
|
19
25
|
</svg>
|
|
@@ -41,7 +47,7 @@ var y=Object.defineProperty;var x=(l,s,p)=>s in l?y(l,s,{enumerable:!0,configura
|
|
|
41
47
|
<path d="M2 12c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 2.6 0 2.4 2 5 2 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/>
|
|
42
48
|
<path d="M2 18c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 2.6 0 2.4 2 5 2 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/>
|
|
43
49
|
</svg>
|
|
44
|
-
`},
|
|
50
|
+
`},v=`
|
|
45
51
|
* {
|
|
46
52
|
box-sizing: border-box;
|
|
47
53
|
}
|
|
@@ -298,7 +304,7 @@ var y=Object.defineProperty;var x=(l,s,p)=>s in l?y(l,s,{enumerable:!0,configura
|
|
|
298
304
|
border-radius: 0;
|
|
299
305
|
}
|
|
300
306
|
}
|
|
301
|
-
`;class f extends HTMLElement{constructor(){super();a(this,"isPanelOpen",!1);a(this,"callActive",!1);a(this,"transcript","");a(this,"client",null);a(this,"shadow");a(this,"widgetId","");a(this,"serverUrl","https://api.travelr.club");a(this,"agentId","");this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["widget-id","agent-id","position","primary-color","server-url"]}connectedCallback(){console.log("[AvinAI Widget] Initializing..."),this.widgetId=this.getAttribute("widget-id")||"",this.agentId=this.getAttribute("agent-id")||"",this.serverUrl=this.getAttribute("server-url")||"https://api.travelr.club";const
|
|
307
|
+
`;class f extends HTMLElement{constructor(){super();a(this,"isPanelOpen",!1);a(this,"callActive",!1);a(this,"transcript","");a(this,"client",null);a(this,"shadow");a(this,"widgetId","");a(this,"serverUrl","https://api.travelr.club");a(this,"agentId","");this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["widget-id","agent-id","position","primary-color","server-url"]}connectedCallback(){console.log("[AvinAI Widget] Initializing..."),this.widgetId=this.getAttribute("widget-id")||"",this.agentId=this.getAttribute("agent-id")||"",this.serverUrl=this.getAttribute("server-url")||"https://api.travelr.club";const e=this.getAttribute("position")||"bottom-right",o=this.getAttribute("primary-color")||"#6366f1";this.render(e,o),this.attachEventListeners(),this.widgetId&&!this.agentId&&this.initializeConfig()}async initializeConfig(){var e,o,i,t;try{console.log(`[AvinAI Widget] Fetching config for widget: ${this.widgetId}`);const r=await p(this.widgetId);this.agentId=r.agent_id,((t=(i=(o=(e=r.agent)==null?void 0:e.tts_voice)==null?void 0:o.provider)==null?void 0:i.root_name)==null?void 0:t.toLowerCase())==="premium"?this.serverUrl="https://godspeed.travelr.club":this.serverUrl="https://in-godspeed.travelr.club",console.log(`[AvinAI Widget] Configured for Agent ID: ${this.agentId}`),console.log(`[AvinAI Widget] Using Server URL: ${this.serverUrl}`)}catch(r){console.error("[AvinAI Widget] Configuration failed:",r),this.updateStatus("Configuration Failed","error")}}render(e,o){const i={"bottom-right":{bottom:"24px",right:"24px"},"bottom-left":{bottom:"24px",left:"24px"},"top-right":{top:"24px",right:"24px"},"top-left":{top:"24px",left:"24px"}},t=i[e]||i["bottom-right"],r=Object.entries(t).map(([m,y])=>`${m}: ${y}`).join("; "),s=e.includes("bottom")?"bottom: 100px;":"top: 100px;",g=e.includes("right")?"right: 24px;":"left: 24px;",b=v.replace("--primary: #6366f1",`--primary: ${o}`);this.shadow.innerHTML=`
|
|
302
308
|
<style>${b}</style>
|
|
303
309
|
|
|
304
310
|
<!-- Floating Action Button -->
|
|
@@ -307,7 +313,7 @@ var y=Object.defineProperty;var x=(l,s,p)=>s in l?y(l,s,{enumerable:!0,configura
|
|
|
307
313
|
</button>
|
|
308
314
|
|
|
309
315
|
<!-- Voice Panel -->
|
|
310
|
-
<div class="widget-panel hidden" style="width: 380px; height: 480px; ${
|
|
316
|
+
<div class="widget-panel hidden" style="width: 380px; height: 480px; ${s} ${g}">
|
|
311
317
|
<div class="widget-header">
|
|
312
318
|
<h3 class="widget-title">Voice Assistant</h3>
|
|
313
319
|
<button class="close-btn" id="close-panel">
|
|
@@ -333,5 +339,5 @@ var y=Object.defineProperty;var x=(l,s,p)=>s in l?y(l,s,{enumerable:!0,configura
|
|
|
333
339
|
</div>
|
|
334
340
|
</div>
|
|
335
341
|
</div>
|
|
336
|
-
`}attachEventListeners(){const
|
|
337
|
-
`:"")+o
|
|
342
|
+
`}attachEventListeners(){const e=this.shadow.querySelector(".widget-fab"),o=this.shadow.querySelector(".widget-panel"),i=this.shadow.querySelector("#close-panel"),t=this.shadow.querySelector("#start-btn");e==null||e.addEventListener("click",()=>{this.isPanelOpen=!this.isPanelOpen,o==null||o.classList.toggle("hidden",!this.isPanelOpen)}),i==null||i.addEventListener("click",()=>{this.isPanelOpen=!1,o==null||o.classList.add("hidden")}),t==null||t.addEventListener("click",()=>{this.callActive?this.stopCall():this.startCall()})}updateStatus(e,o){const i=this.shadow.querySelector("#status-text"),t=this.shadow.querySelector("#status-dot");i&&(i.textContent=e),t&&(o==="idle"&&(t.style.background="#ef4444"),o==="connecting"&&(t.style.background="#f59e0b"),o==="connected"&&(t.style.background="#10b981"),o==="error"&&(t.style.background="#ef4444"))}async startCall(){if(!this.agentId){this.updateStatus("Error: Agent ID not configured","error");return}const e=this.shadow.querySelector("#start-btn"),o=this.shadow.querySelector("#transcript");try{this.updateStatus("Connecting...","connecting"),e&&(e.disabled=!0),console.log("[AvinAI Widget] Creating call record...");const i=await w(this.agentId);console.log(`[AvinAI Widget] Call created with ID: ${i}`),this.client=new d({serverUrl:this.serverUrl,agentId:this.agentId,callId:i,onConnected:()=>{this.callActive=!0,this.updateStatus("Connected - Listening...","connected"),e&&(e.innerHTML=`${u.close}<span>End Call</span>`,e.className="control-btn danger",e.disabled=!1)},onDisconnected:()=>{this.stopCall()},onError:t=>{this.updateStatus(`Error: ${t.message||"Connection failed"}`,"error"),e&&(e.disabled=!1)},onRemoteTrack:(t,r)=>{console.log("[AvinAI Widget] Remote track received:",t.kind)},onTranscription:(t,r)=>{r&&(this.transcript+=(this.transcript?`
|
|
343
|
+
`:"")+t,o&&(o.innerHTML=this.transcript,o.scrollTop=o.scrollHeight))}}),await this.client.connect()}catch(i){console.error("[AvinAI Widget] Start call failed:",i),this.updateStatus(`Connection failed: ${i.message}`,"error"),e&&(e.disabled=!1)}}stopCall(){this.client&&(this.client.disconnect(),this.client=null),this.callActive=!1,this.updateStatus("Click Start to begin conversation","idle");const e=this.shadow.querySelector("#start-btn");e&&(e.innerHTML=`${u.mic}<span>Start Call</span>`,e.className="control-btn primary",e.disabled=!1)}disconnectedCallback(){this.client&&this.client.disconnect()}}customElements.get("avin-convai")||customElements.define("avin-convai",f),typeof window<"u"&&(window.AvinConvAI=f);const h=document.currentScript;if(h){const l=h.getAttribute("data-widget-id")||h.getAttribute("widget-id"),n=h.getAttribute("data-agent-id")||h.getAttribute("agent-id");if(l||n){const e=h.getAttribute("data-position")||"bottom-right",o=h.getAttribute("data-primary-color")||"#6366f1",i=document.createElement("avin-convai");l&&i.setAttribute("widget-id",l),n&&i.setAttribute("agent-id",n),i.setAttribute("position",e),i.setAttribute("primary-color",o),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>document.body.appendChild(i)):document.body.appendChild(i)}}})();
|
package/dist/avin-ai.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(s,c){typeof exports=="object"&&typeof module<"u"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(s=typeof globalThis<"u"?globalThis:s||self,c(s.AvinAI={}))})(this,function(s){"use strict";var
|
|
1
|
+
(function(s,c){typeof exports=="object"&&typeof module<"u"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(s=typeof globalThis<"u"?globalThis:s||self,c(s.AvinAI={}))})(this,function(s){"use strict";var x=Object.defineProperty;var C=(s,c,d)=>c in s?x(s,c,{enumerable:!0,configurable:!0,writable:!0,value:d}):s[c]=d;var a=(s,c,d)=>C(s,typeof c!="symbol"?c+"":c,d);class c{constructor(o){a(this,"serverUrl");a(this,"agentId");a(this,"callId");a(this,"onConnected");a(this,"onDisconnected");a(this,"onError");a(this,"onTranscription");a(this,"onRemoteTrack");a(this,"pc",null);a(this,"dataChannel",null);a(this,"audioElement",null);a(this,"connected",!1);if(!o.serverUrl)throw new Error("serverUrl is required");if(!o.agentId)throw new Error("agentId is required");this.serverUrl=o.serverUrl.replace(/\/$/,""),this.agentId=o.agentId,this.callId=o.callId||this.generateCallId(),this.onConnected=o.onConnected||(()=>{}),this.onDisconnected=o.onDisconnected||(()=>{}),this.onError=o.onError||(e=>console.error("[WebRTC]",e)),this.onTranscription=o.onTranscription||(()=>{}),this.onRemoteTrack=o.onRemoteTrack||(()=>{})}async connect(){console.log("đĩ [WebRTC] Starting connection...");try{this.pc=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]}),this.pc.addTransceiver("video",{direction:"recvonly"});const o=await navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0,sampleRate:{ideal:16e3},channelCount:1}});if(console.log("đ¤ [WebRTC] Microphone access granted"),!this.pc){console.log("[WebRTC] Connection aborted: peer connection closed during setup"),o.getTracks().forEach(t=>t.stop());return}if(o.getTracks().forEach(t=>{var i;(i=this.pc)==null||i.addTrack(t,o)}),!this.pc)throw new Error("RTCPeerConnection was closed unexpectedly");this.dataChannel=this.pc.createDataChannel("control"),this.dataChannel.onopen=()=>console.log("đĄ [WebRTC] DataChannel opened"),this.dataChannel.onmessage=t=>{if(typeof t.data=="string")try{this.handleControlEvent(JSON.parse(t.data))}catch{console.warn("[WebRTC] Failed to parse message:",t.data)}else t.data instanceof ArrayBuffer?console.log("[WebRTC] Received binary data:",t.data.byteLength,"bytes"):t.data instanceof Blob&&t.data.text().then(i=>{try{this.handleControlEvent(JSON.parse(i))}catch{console.warn("[WebRTC] Failed to parse blob data:",i)}})},this.dataChannel.onerror=t=>console.error("â [WebRTC] DataChannel error:",t),this.pc.ontrack=t=>{const i=t.track,l=t.streams[0];console.log(`đĨ [WebRTC] Received ${i.kind} track`),i.kind==="audio"?(console.log("đ [WebRTC] Received audio track from server"),this.audioElement=new Audio,this.audioElement.srcObject=l,this.audioElement.play().catch(p=>console.warn("Audio autoplay blocked:",p)),this.audioElement.onended=()=>{this.sendEvent("playedStream"),console.log("â
[WebRTC] TTS playback complete")}):i.kind==="video"&&(console.log("đš [WebRTC] Video track received"),this.onRemoteTrack(i,l))},this.pc.onconnectionstatechange=()=>{var t,i,l,p,u;console.log("đ [WebRTC] State:",(t=this.pc)==null?void 0:t.connectionState),((i=this.pc)==null?void 0:i.connectionState)==="connected"?(this.connected=!0,this.onConnected()):(((l=this.pc)==null?void 0:l.connectionState)==="failed"||((p=this.pc)==null?void 0:p.connectionState)==="disconnected"||((u=this.pc)==null?void 0:u.connectionState)==="closed")&&(this.connected=!1,this.onDisconnected())};const e=await this.pc.createOffer();await this.pc.setLocalDescription(e),console.log("đ [WebRTC] Created offer, waiting for ICE gathering..."),await this.waitForIceGathering(),console.log("đ§ [WebRTC] ICE gathering complete"),console.log("đ¤ [WebRTC] Sending offer via HTTP...");const n=await fetch(`${this.serverUrl}/webrtc?agent=${this.agentId}_${this.callId}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({offer:this.pc.localDescription,agentId:this.agentId,callId:this.callId})});if(!n.ok){const t=await n.json();throw new Error(t.error||`HTTP ${n.status}`)}const{answer:r}=await n.json();console.log("đĨ [WebRTC] Received answer from server"),await this.pc.setRemoteDescription(r),console.log("â
[WebRTC] Connection established!")}catch(o){throw console.error("â [WebRTC] Connection failed:",o),this.disconnect(),this.onError(o.message||o),o}}waitForIceGathering(){return new Promise(o=>{if(!this.pc)return o();if(this.pc.iceGatheringState==="complete")o();else{const e=()=>{var n,r;((n=this.pc)==null?void 0:n.iceGatheringState)==="complete"&&((r=this.pc)==null||r.removeEventListener("icegatheringstatechange",e),o())};this.pc.addEventListener("icegatheringstatechange",e),setTimeout(()=>{var n;(n=this.pc)==null||n.removeEventListener("icegatheringstatechange",e),console.warn("â ī¸ [WebRTC] ICE gathering timeout, proceeding anyway"),o()},5e3)}})}sendEvent(o,e={}){var n;((n=this.dataChannel)==null?void 0:n.readyState)==="open"&&this.dataChannel.send(JSON.stringify({event:o,...e}))}handleControlEvent(o){switch(o.event){case"clearAudio":console.log("đ [WebRTC] Interrupt: stopping audio"),this.audioElement&&(this.audioElement.pause(),this.audioElement.currentTime=0);break;case"transcription":console.log("đ [WebRTC] Transcription:",o.text),this.onTranscription(o.text,o.isFinal);break;case"mark":console.log("đˇī¸ [WebRTC] Mark:",o.name);break;default:console.log("âšī¸ [WebRTC] Unknown event:",o.event)}}disconnect(){console.log("đ´ [WebRTC] Disconnecting..."),this.audioElement&&(this.audioElement.pause(),this.audioElement.srcObject=null),this.dataChannel&&(this.dataChannel.close(),this.dataChannel=null),this.pc&&(this.pc.getSenders().forEach(o=>{o.track&&o.track.stop()}),this.pc.close(),this.pc=null),this.connected=!1,this.onDisconnected()}generateCallId(){return"web_"+Date.now()+"_"+Math.random().toString(36).substr(2,8)}}const d="https://coredb.travelr.club/v1/graphql";async function b(h){var e;const o=`
|
|
2
2
|
query GetWidgetConfig($id: uuid!) {
|
|
3
3
|
app_widget_by_pk(id: $id) {
|
|
4
4
|
agent_id
|
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
`;try{const
|
|
16
|
+
`;try{const t=(e=(await(await fetch(d,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:o,variables:{id:h}})})).json()).data)==null?void 0:e.app_widget_by_pk;if(!t)throw new Error(`Widget configuration not found for ID: ${h}`);return t}catch(n){throw console.error("[AvinAI] Failed to fetch widget config:",n),n}}async function f(h,o=!1){var r,t;const e=`
|
|
17
|
+
mutation CreateWebCall($object: calls_insert_input!) {
|
|
18
|
+
insert_calls_one(object: $object) {
|
|
19
|
+
id
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
`,n={object:{agent_id:h,status:"in-progress",type:"web_call",direction:"inbound",phone_to:"web_user",is_ai_avatar_enabled:o}};try{const l=await(await fetch(d,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({query:e,variables:n})})).json();if(l.errors)throw new Error(l.errors[0].message);return(t=(r=l.data)==null?void 0:r.insert_calls_one)==null?void 0:t.id}catch(i){throw console.error("[AvinAI] Failed to create call record:",i),i}}const g={phone:`
|
|
17
23
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
18
24
|
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/>
|
|
19
25
|
</svg>
|
|
@@ -41,7 +47,7 @@
|
|
|
41
47
|
<path d="M2 12c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 2.6 0 2.4 2 5 2 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/>
|
|
42
48
|
<path d="M2 18c.6.5 1.2 1 2.5 1 2.5 0 2.5-2 5-2 2.6 0 2.4 2 5 2 2.5 0 2.5-2 5-2 1.3 0 1.9.5 2.5 1"/>
|
|
43
49
|
</svg>
|
|
44
|
-
`},
|
|
50
|
+
`},w=`
|
|
45
51
|
* {
|
|
46
52
|
box-sizing: border-box;
|
|
47
53
|
}
|
|
@@ -298,20 +304,20 @@
|
|
|
298
304
|
border-radius: 0;
|
|
299
305
|
}
|
|
300
306
|
}
|
|
301
|
-
`;class v extends HTMLElement{constructor(){super();a(this,"isPanelOpen",!1);a(this,"callActive",!1);a(this,"transcript","");a(this,"client",null);a(this,"shadow");a(this,"widgetId","");a(this,"serverUrl","https://api.travelr.club");a(this,"agentId","");this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["widget-id","agent-id","position","primary-color","server-url"]}connectedCallback(){console.log("[AvinAI Widget] Initializing..."),this.widgetId=this.getAttribute("widget-id")||"",this.agentId=this.getAttribute("agent-id")||"",this.serverUrl=this.getAttribute("server-url")||"https://api.travelr.club";const
|
|
307
|
+
`;class v extends HTMLElement{constructor(){super();a(this,"isPanelOpen",!1);a(this,"callActive",!1);a(this,"transcript","");a(this,"client",null);a(this,"shadow");a(this,"widgetId","");a(this,"serverUrl","https://api.travelr.club");a(this,"agentId","");this.shadow=this.attachShadow({mode:"open"})}static get observedAttributes(){return["widget-id","agent-id","position","primary-color","server-url"]}connectedCallback(){console.log("[AvinAI Widget] Initializing..."),this.widgetId=this.getAttribute("widget-id")||"",this.agentId=this.getAttribute("agent-id")||"",this.serverUrl=this.getAttribute("server-url")||"https://api.travelr.club";const e=this.getAttribute("position")||"bottom-right",n=this.getAttribute("primary-color")||"#6366f1";this.render(e,n),this.attachEventListeners(),this.widgetId&&!this.agentId&&this.initializeConfig()}async initializeConfig(){var e,n,r,t;try{console.log(`[AvinAI Widget] Fetching config for widget: ${this.widgetId}`);const i=await b(this.widgetId);this.agentId=i.agent_id,((t=(r=(n=(e=i.agent)==null?void 0:e.tts_voice)==null?void 0:n.provider)==null?void 0:r.root_name)==null?void 0:t.toLowerCase())==="premium"?this.serverUrl="https://godspeed.travelr.club":this.serverUrl="https://in-godspeed.travelr.club",console.log(`[AvinAI Widget] Configured for Agent ID: ${this.agentId}`),console.log(`[AvinAI Widget] Using Server URL: ${this.serverUrl}`)}catch(i){console.error("[AvinAI Widget] Configuration failed:",i),this.updateStatus("Configuration Failed","error")}}render(e,n){const r={"bottom-right":{bottom:"24px",right:"24px"},"bottom-left":{bottom:"24px",left:"24px"},"top-right":{top:"24px",right:"24px"},"top-left":{top:"24px",left:"24px"}},t=r[e]||r["bottom-right"],i=Object.entries(t).map(([m,y])=>`${m}: ${y}`).join("; "),l=e.includes("bottom")?"bottom: 100px;":"top: 100px;",p=e.includes("right")?"right: 24px;":"left: 24px;",u=w.replace("--primary: #6366f1",`--primary: ${n}`);this.shadow.innerHTML=`
|
|
302
308
|
<style>${u}</style>
|
|
303
309
|
|
|
304
310
|
<!-- Floating Action Button -->
|
|
305
|
-
<button class="widget-fab" style="${
|
|
306
|
-
${
|
|
311
|
+
<button class="widget-fab" style="${i}">
|
|
312
|
+
${g.phone}
|
|
307
313
|
</button>
|
|
308
314
|
|
|
309
315
|
<!-- Voice Panel -->
|
|
310
|
-
<div class="widget-panel hidden" style="width: 380px; height: 480px; ${l} ${
|
|
316
|
+
<div class="widget-panel hidden" style="width: 380px; height: 480px; ${l} ${p}">
|
|
311
317
|
<div class="widget-header">
|
|
312
318
|
<h3 class="widget-title">Voice Assistant</h3>
|
|
313
319
|
<button class="close-btn" id="close-panel">
|
|
314
|
-
${
|
|
320
|
+
${g.close}
|
|
315
321
|
</button>
|
|
316
322
|
</div>
|
|
317
323
|
|
|
@@ -327,11 +333,11 @@
|
|
|
327
333
|
|
|
328
334
|
<div class="controls" id="controls">
|
|
329
335
|
<button class="control-btn primary" id="start-btn">
|
|
330
|
-
${
|
|
336
|
+
${g.mic}
|
|
331
337
|
<span>Start Call</span>
|
|
332
338
|
</button>
|
|
333
339
|
</div>
|
|
334
340
|
</div>
|
|
335
341
|
</div>
|
|
336
|
-
`}attachEventListeners(){const
|
|
337
|
-
`:"")+
|
|
342
|
+
`}attachEventListeners(){const e=this.shadow.querySelector(".widget-fab"),n=this.shadow.querySelector(".widget-panel"),r=this.shadow.querySelector("#close-panel"),t=this.shadow.querySelector("#start-btn");e==null||e.addEventListener("click",()=>{this.isPanelOpen=!this.isPanelOpen,n==null||n.classList.toggle("hidden",!this.isPanelOpen)}),r==null||r.addEventListener("click",()=>{this.isPanelOpen=!1,n==null||n.classList.add("hidden")}),t==null||t.addEventListener("click",()=>{this.callActive?this.stopCall():this.startCall()})}updateStatus(e,n){const r=this.shadow.querySelector("#status-text"),t=this.shadow.querySelector("#status-dot");r&&(r.textContent=e),t&&(n==="idle"&&(t.style.background="#ef4444"),n==="connecting"&&(t.style.background="#f59e0b"),n==="connected"&&(t.style.background="#10b981"),n==="error"&&(t.style.background="#ef4444"))}async startCall(){if(!this.agentId){this.updateStatus("Error: Agent ID not configured","error");return}const e=this.shadow.querySelector("#start-btn"),n=this.shadow.querySelector("#transcript");try{this.updateStatus("Connecting...","connecting"),e&&(e.disabled=!0),console.log("[AvinAI Widget] Creating call record...");const r=await f(this.agentId);console.log(`[AvinAI Widget] Call created with ID: ${r}`),this.client=new c({serverUrl:this.serverUrl,agentId:this.agentId,callId:r,onConnected:()=>{this.callActive=!0,this.updateStatus("Connected - Listening...","connected"),e&&(e.innerHTML=`${g.close}<span>End Call</span>`,e.className="control-btn danger",e.disabled=!1)},onDisconnected:()=>{this.stopCall()},onError:t=>{this.updateStatus(`Error: ${t.message||"Connection failed"}`,"error"),e&&(e.disabled=!1)},onRemoteTrack:(t,i)=>{console.log("[AvinAI Widget] Remote track received:",t.kind)},onTranscription:(t,i)=>{i&&(this.transcript+=(this.transcript?`
|
|
343
|
+
`:"")+t,n&&(n.innerHTML=this.transcript,n.scrollTop=n.scrollHeight))}}),await this.client.connect()}catch(r){console.error("[AvinAI Widget] Start call failed:",r),this.updateStatus(`Connection failed: ${r.message}`,"error"),e&&(e.disabled=!1)}}stopCall(){this.client&&(this.client.disconnect(),this.client=null),this.callActive=!1,this.updateStatus("Click Start to begin conversation","idle");const e=this.shadow.querySelector("#start-btn");e&&(e.innerHTML=`${g.mic}<span>Start Call</span>`,e.className="control-btn primary",e.disabled=!1)}disconnectedCallback(){this.client&&this.client.disconnect()}}s.AvinWidget=v,s.WebRTCClient=c,s.fetchWidgetConfig=b,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})});
|