@flowengage/react-chatbot 8.0.52 → 8.0.54
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.
|
@@ -8876,76 +8876,78 @@ async function Em(e, t, n) {
|
|
|
8876
8876
|
}
|
|
8877
8877
|
if (!i.ok) throw Error("Could not start a voice session.");
|
|
8878
8878
|
let a = await i.json();
|
|
8879
|
-
if (!a?.success || !a.
|
|
8879
|
+
if (!a?.success || !a.wsUrl) throw Error(a?.error || "Voice session was refused.");
|
|
8880
8880
|
return a;
|
|
8881
8881
|
}
|
|
8882
8882
|
async function Dm(e) {
|
|
8883
8883
|
let { apiBaseUrl: t, siteId: n, chatId: r, clientTools: i = {}, onConnect: a, onDisconnect: o, onMessage: s, onModeChange: c, onError: l, onUnhandledClientToolCall: u, onAgentTurnEnd: d, onSessionInfo: f } = e, p = await Em(t, n, r);
|
|
8884
|
-
f?.({ emailOnFile: !!p.emailOnFile })
|
|
8885
|
-
let m =
|
|
8884
|
+
f?.({ emailOnFile: !!p.emailOnFile });
|
|
8885
|
+
let m = { type: "Start" };
|
|
8886
|
+
e.greeting !== void 0 && (m.greeting = e.greeting || null);
|
|
8887
|
+
let h = await navigator.mediaDevices.getUserMedia({ audio: {
|
|
8886
8888
|
channelCount: 1,
|
|
8887
8889
|
echoCancellation: !0,
|
|
8888
8890
|
noiseSuppression: !0,
|
|
8889
8891
|
autoGainControl: !0
|
|
8890
|
-
} }),
|
|
8891
|
-
|
|
8892
|
-
let
|
|
8893
|
-
|
|
8894
|
-
let
|
|
8892
|
+
} }), g = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: bm });
|
|
8893
|
+
g.state === "suspended" && await g.resume();
|
|
8894
|
+
let _ = new WebSocket(p.wsUrl);
|
|
8895
|
+
_.binaryType = "arraybuffer";
|
|
8896
|
+
let v = /* @__PURE__ */ new Set(), y = {
|
|
8895
8897
|
role: null,
|
|
8896
8898
|
text: "",
|
|
8897
8899
|
timer: null
|
|
8898
|
-
},
|
|
8899
|
-
|
|
8900
|
-
let e =
|
|
8901
|
-
if (
|
|
8900
|
+
}, b = "", x = () => {
|
|
8901
|
+
y.timer &&= (clearTimeout(y.timer), null);
|
|
8902
|
+
let e = y.text.trim(), t = y.role;
|
|
8903
|
+
if (y.text = "", y.role = null, !(!e || !t)) {
|
|
8902
8904
|
if (t === "agent") {
|
|
8903
|
-
if (e ===
|
|
8905
|
+
if (e === b) {
|
|
8904
8906
|
console.debug("[FlowEngage] duplicate agent turn suppressed");
|
|
8905
8907
|
return;
|
|
8906
8908
|
}
|
|
8907
|
-
|
|
8909
|
+
b = e;
|
|
8908
8910
|
}
|
|
8909
8911
|
s?.({
|
|
8910
8912
|
role: t,
|
|
8911
8913
|
message: e
|
|
8912
8914
|
});
|
|
8913
8915
|
}
|
|
8914
|
-
},
|
|
8915
|
-
t && (
|
|
8916
|
-
},
|
|
8917
|
-
|
|
8916
|
+
}, S = (e, t) => {
|
|
8917
|
+
t && (y.role && y.role !== e && x(), y.role = e, y.text = y.text ? `${y.text} ${t}`.replace(/\s+/g, " ") : t, y.timer && clearTimeout(y.timer), y.timer = setTimeout(x, Sm));
|
|
8918
|
+
}, C = !1, w = !1, T = !1, E = !1, D = !0, O = null, k = () => {
|
|
8919
|
+
O && clearTimeout(O);
|
|
8918
8920
|
let e = () => {
|
|
8919
|
-
if (!
|
|
8920
|
-
if (
|
|
8921
|
-
|
|
8921
|
+
if (!C) {
|
|
8922
|
+
if (A.isPlaying()) {
|
|
8923
|
+
O = setTimeout(e, 150);
|
|
8922
8924
|
return;
|
|
8923
8925
|
}
|
|
8924
|
-
|
|
8926
|
+
O = null, d?.();
|
|
8925
8927
|
}
|
|
8926
8928
|
};
|
|
8927
|
-
|
|
8928
|
-
},
|
|
8929
|
-
|
|
8930
|
-
}),
|
|
8931
|
-
|
|
8932
|
-
if (
|
|
8929
|
+
O = setTimeout(e, 150);
|
|
8930
|
+
}, A = Tm(g, () => {
|
|
8931
|
+
E && (E = !1, c?.({ mode: "listening" }));
|
|
8932
|
+
}), ee = g.createMediaStreamSource(h), te = g.createScriptProcessor(xm, 1, 1);
|
|
8933
|
+
te.onaudioprocess = (e) => {
|
|
8934
|
+
if (C || _.readyState !== WebSocket.OPEN) return;
|
|
8933
8935
|
let t = e.inputBuffer.getChannelData(0);
|
|
8934
|
-
if (
|
|
8935
|
-
|
|
8936
|
+
if (w) {
|
|
8937
|
+
T || (T = !0, console.debug("[FlowEngage] mic held — streaming silence to keep socket alive")), _.send(new Int16Array(t.length).buffer);
|
|
8936
8938
|
return;
|
|
8937
8939
|
}
|
|
8938
|
-
|
|
8939
|
-
},
|
|
8940
|
-
let
|
|
8941
|
-
if (!
|
|
8942
|
-
|
|
8940
|
+
_.send(Cm(t).buffer);
|
|
8941
|
+
}, ee.connect(te), te.connect(g.destination);
|
|
8942
|
+
let ne = () => {
|
|
8943
|
+
if (!C) {
|
|
8944
|
+
C = !0, O &&= (clearTimeout(O), null), x(), A.stop();
|
|
8943
8945
|
try {
|
|
8944
|
-
|
|
8946
|
+
te.disconnect(), ee.disconnect();
|
|
8945
8947
|
} catch {}
|
|
8946
|
-
|
|
8948
|
+
h.getTracks().forEach((e) => e.stop()), g.close().catch(() => {}), (_.readyState === WebSocket.OPEN || _.readyState === WebSocket.CONNECTING) && _.close();
|
|
8947
8949
|
}
|
|
8948
|
-
},
|
|
8950
|
+
}, j = async (e) => {
|
|
8949
8951
|
let t = i[e.name];
|
|
8950
8952
|
if (!t) return u?.({ tool_name: e.name }), { error: `Unknown tool ${e.name}` };
|
|
8951
8953
|
let n = {};
|
|
@@ -8957,29 +8959,29 @@ async function Dm(e) {
|
|
|
8957
8959
|
} catch (e) {
|
|
8958
8960
|
return { error: e?.message || "Tool execution failed" };
|
|
8959
8961
|
}
|
|
8960
|
-
},
|
|
8962
|
+
}, re = async (e) => {
|
|
8961
8963
|
for (let t of e.functions || []) {
|
|
8962
8964
|
if (!t.client_side) continue;
|
|
8963
|
-
let e = await
|
|
8964
|
-
if (
|
|
8965
|
-
|
|
8965
|
+
let e = await j(t);
|
|
8966
|
+
if (C || _.readyState !== WebSocket.OPEN) return;
|
|
8967
|
+
_.send(JSON.stringify({
|
|
8966
8968
|
type: "FunctionCallResponse",
|
|
8967
8969
|
id: t.id,
|
|
8968
8970
|
name: t.name,
|
|
8969
8971
|
content: typeof e == "string" ? e : JSON.stringify(e ?? {})
|
|
8970
8972
|
}));
|
|
8971
8973
|
}
|
|
8972
|
-
},
|
|
8974
|
+
}, ie = (e) => {
|
|
8973
8975
|
switch (e.type) {
|
|
8974
8976
|
case "Welcome":
|
|
8975
|
-
a?.({ conversationId: e.
|
|
8977
|
+
a?.({ conversationId: e.session_id || r || n });
|
|
8976
8978
|
break;
|
|
8977
8979
|
case "ConversationText": {
|
|
8978
8980
|
let t = String(e.content || "");
|
|
8979
8981
|
if (e.role === "user") {
|
|
8980
8982
|
let e = t.trim();
|
|
8981
|
-
if (
|
|
8982
|
-
|
|
8983
|
+
if (v.has(e)) {
|
|
8984
|
+
v.delete(e);
|
|
8983
8985
|
break;
|
|
8984
8986
|
}
|
|
8985
8987
|
if (/^\[SYSTEM:/i.test(e) || /^Continue (now )?to the next section/i.test(e) || /^That was the last section/i.test(e)) {
|
|
@@ -8987,68 +8989,68 @@ async function Dm(e) {
|
|
|
8987
8989
|
break;
|
|
8988
8990
|
}
|
|
8989
8991
|
}
|
|
8990
|
-
|
|
8992
|
+
S(e.role === "user" ? "user" : "agent", t);
|
|
8991
8993
|
break;
|
|
8992
8994
|
}
|
|
8993
8995
|
case "UserStartedSpeaking":
|
|
8994
|
-
|
|
8996
|
+
x(), A.stop(), D = !1, E = !1, c?.({ mode: "listening" });
|
|
8995
8997
|
break;
|
|
8996
8998
|
case "AgentStartedSpeaking":
|
|
8997
|
-
|
|
8999
|
+
D = !0, E = !0, c?.({ mode: "speaking" });
|
|
8998
9000
|
break;
|
|
8999
9001
|
case "AgentAudioDone":
|
|
9000
|
-
|
|
9002
|
+
x(), k(), A.isPlaying() || (E = !1, c?.({ mode: "listening" }));
|
|
9001
9003
|
break;
|
|
9002
9004
|
case "FunctionCallRequest":
|
|
9003
|
-
|
|
9005
|
+
re(e);
|
|
9004
9006
|
break;
|
|
9005
9007
|
case "PromptUpdated":
|
|
9006
9008
|
case "AgentThinking": break;
|
|
9007
9009
|
case "Error":
|
|
9008
|
-
console.error("[FlowEngage:
|
|
9010
|
+
console.error("[FlowEngage:Voice]", e.code || "", e.description || e), l?.(Error(e.description || "Voice service error"));
|
|
9009
9011
|
break;
|
|
9010
9012
|
case "Warning":
|
|
9011
|
-
console.warn("[FlowEngage:
|
|
9013
|
+
console.warn("[FlowEngage:Voice]", e.code || "", e.description || "");
|
|
9012
9014
|
break;
|
|
9013
9015
|
default: break;
|
|
9014
9016
|
}
|
|
9015
9017
|
};
|
|
9016
|
-
return
|
|
9018
|
+
return _.onopen = () => _.send(JSON.stringify(m)), _.onmessage = (e) => {
|
|
9017
9019
|
if (e.data instanceof ArrayBuffer) {
|
|
9018
|
-
|
|
9020
|
+
D && A.enqueue(new Int16Array(e.data));
|
|
9019
9021
|
return;
|
|
9020
9022
|
}
|
|
9021
9023
|
try {
|
|
9022
|
-
|
|
9024
|
+
ie(JSON.parse(e.data));
|
|
9023
9025
|
} catch {}
|
|
9024
|
-
},
|
|
9025
|
-
|
|
9026
|
+
}, _.onerror = () => l?.(/* @__PURE__ */ Error("Voice connection failed")), _.onclose = () => {
|
|
9027
|
+
ne(), o?.();
|
|
9026
9028
|
}, {
|
|
9027
|
-
endSession: async () =>
|
|
9029
|
+
endSession: async () => ne(),
|
|
9028
9030
|
sendContextualUpdate: (e) => {
|
|
9029
|
-
|
|
9031
|
+
C || _.readyState !== WebSocket.OPEN || !e || _.send(JSON.stringify({
|
|
9030
9032
|
type: "UpdatePrompt",
|
|
9031
9033
|
prompt: e
|
|
9032
9034
|
}));
|
|
9033
9035
|
},
|
|
9034
9036
|
sendUserMessage: (e, { silent: t = !0 } = {}) => {
|
|
9035
|
-
|
|
9037
|
+
C || _.readyState !== WebSocket.OPEN || !e || (t && v.add(e.trim()), _.send(JSON.stringify({
|
|
9036
9038
|
type: "InjectUserMessage",
|
|
9037
9039
|
content: e
|
|
9038
9040
|
})));
|
|
9039
9041
|
},
|
|
9040
9042
|
injectAgentSpeech: (e, t = "interrupt") => {
|
|
9041
|
-
|
|
9043
|
+
C || _.readyState !== WebSocket.OPEN || !e || _.send(JSON.stringify({
|
|
9042
9044
|
type: "InjectAgentMessage",
|
|
9043
9045
|
message: e,
|
|
9044
9046
|
behavior: t
|
|
9045
9047
|
}));
|
|
9046
9048
|
},
|
|
9047
9049
|
setMicMuted: (e) => {
|
|
9048
|
-
|
|
9050
|
+
w = !!e;
|
|
9049
9051
|
},
|
|
9050
9052
|
get status() {
|
|
9051
|
-
return
|
|
9053
|
+
return C ? "disconnected" : "connected";
|
|
9052
9054
|
}
|
|
9053
9055
|
};
|
|
9054
9056
|
}
|
|
@@ -12817,7 +12819,7 @@ function Tg({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
|
|
|
12817
12819
|
headers: { "Content-Type": "application/json" },
|
|
12818
12820
|
body: JSON.stringify({
|
|
12819
12821
|
chatId: s,
|
|
12820
|
-
|
|
12822
|
+
voiceSessionId: t,
|
|
12821
12823
|
duration: e,
|
|
12822
12824
|
siteId: i
|
|
12823
12825
|
})
|
|
@@ -12857,7 +12859,7 @@ function Tg({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
|
|
|
12857
12859
|
if (e && s && a) try {
|
|
12858
12860
|
let n = t ? Math.round((Date.now() - t) / 1e3) : 0, r = JSON.stringify({
|
|
12859
12861
|
chatId: s,
|
|
12860
|
-
|
|
12862
|
+
voiceSessionId: e,
|
|
12861
12863
|
duration: n,
|
|
12862
12864
|
siteId: i
|
|
12863
12865
|
}), o = `${a}/api/voice/save-chat-recording`;
|
|
@@ -13095,7 +13097,7 @@ function Tg({ orbColors: e, onEnterChat: t, onEndChat: n, agentId: r, siteId: i,
|
|
|
13095
13097
|
if (t?.endSession?.().catch(() => {}), n && s && a) {
|
|
13096
13098
|
let e = f ? Math.round((Date.now() - f) / 1e3) : 0, t = JSON.stringify({
|
|
13097
13099
|
chatId: s,
|
|
13098
|
-
|
|
13100
|
+
voiceSessionId: n,
|
|
13099
13101
|
duration: e,
|
|
13100
13102
|
siteId: i
|
|
13101
13103
|
}), r = `${a}/api/voice/save-chat-recording`;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowengage/react-chatbot",
|
|
3
|
-
"version": "8.0.
|
|
4
|
-
"description": "Embeddable AI chat widget for React
|
|
3
|
+
"version": "8.0.54",
|
|
4
|
+
"description": "Embeddable AI chat widget for React — powered by FlowEngage. Drop it in with a single siteId.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"chatbot",
|
|
7
7
|
"customer-support",
|
|
@@ -63,4 +63,4 @@
|
|
|
63
63
|
"vite": "^8.0.1",
|
|
64
64
|
"vite-plugin-css-injected-by-js": "^4.0.1"
|
|
65
65
|
}
|
|
66
|
-
}
|
|
66
|
+
}
|