@exotel-npm-dev/exotel-ai-assist 1.2.2 → 1.2.4
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/components/key-components/SuggestionTab.d.ts +2 -1
- package/dist/controller/index.d.ts +1 -0
- package/dist/controller/index.js +38 -9
- package/dist/hooks/useExotelAIAssist.d.ts +1 -0
- package/dist/index.js +190 -50
- package/dist/react/index.js +190 -50
- package/dist/types/index.d.ts +22 -3
- package/package.json +1 -1
- package/src/components/ExotelAIAssistApp.tsx +5 -5
- package/src/components/key-components/SuggestionTab.tsx +101 -15
- package/src/controller/index.ts +44 -23
- package/src/hooks/useExotelAIAssist.ts +17 -1
- package/src/styles/index.css +62 -3
- package/src/types/index.ts +24 -3
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Suggestion, BotConfig } from "../../types";
|
|
2
2
|
import "../../styles/index.css";
|
|
3
|
-
export declare function SuggestionsTab({ suggestions, connected, botConfig, }: {
|
|
3
|
+
export declare function SuggestionsTab({ suggestions, connected, botConfig, sendSuggestionFeedback, }: {
|
|
4
4
|
suggestions: Suggestion[];
|
|
5
5
|
connected: boolean;
|
|
6
6
|
botConfig: BotConfig | null;
|
|
7
|
+
sendSuggestionFeedback: (sequence: number, feedbackType: "good" | "bad" | null, badFeedbackReason?: string | null) => boolean;
|
|
7
8
|
}): JSX.Element;
|
|
@@ -19,6 +19,7 @@ export declare class ExotelAIAssistController extends EventEmitter<ControllerEve
|
|
|
19
19
|
destroy(): void;
|
|
20
20
|
getStatus(): ConnectionStatus;
|
|
21
21
|
getStreamState(): StreamState | null;
|
|
22
|
+
sendSuggestionFeedback(sequence: number, feedbackType: "good" | "bad" | null, badFeedbackReason?: string | null): boolean;
|
|
22
23
|
private _ensureTransport;
|
|
23
24
|
private _handleTransportMessage;
|
|
24
25
|
private _scheduleReconnect;
|
package/dist/controller/index.js
CHANGED
|
@@ -1667,6 +1667,25 @@ class ExotelAIAssistController extends EventEmitter {
|
|
|
1667
1667
|
getStreamState() {
|
|
1668
1668
|
return this._streamState;
|
|
1669
1669
|
}
|
|
1670
|
+
sendSuggestionFeedback(sequence, feedbackType, badFeedbackReason = null) {
|
|
1671
|
+
if (!this.transport || this.status !== "connected") {
|
|
1672
|
+
console.warn("[ExotelAIAssist] Cannot send feedback: not connected");
|
|
1673
|
+
return false;
|
|
1674
|
+
}
|
|
1675
|
+
const message = {
|
|
1676
|
+
type: "suggestion_feedback",
|
|
1677
|
+
sequence,
|
|
1678
|
+
feedback_type: feedbackType,
|
|
1679
|
+
bad_feedback_reason: badFeedbackReason
|
|
1680
|
+
};
|
|
1681
|
+
try {
|
|
1682
|
+
this.transport.send(JSON.stringify(message));
|
|
1683
|
+
return true;
|
|
1684
|
+
} catch (error) {
|
|
1685
|
+
console.error("[ExotelAIAssist] Failed to send feedback:", error);
|
|
1686
|
+
return false;
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1670
1689
|
_ensureTransport() {
|
|
1671
1690
|
if (this.transport) return;
|
|
1672
1691
|
this.transport = createTransport(Utils.hash(this.params));
|
|
@@ -1789,17 +1808,27 @@ class ExotelAIAssistController extends EventEmitter {
|
|
|
1789
1808
|
});
|
|
1790
1809
|
this.emit("transcript", lines);
|
|
1791
1810
|
}
|
|
1792
|
-
if (event.event_type === "suggestion"
|
|
1793
|
-
const
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1811
|
+
if (event.event_type === "suggestion") {
|
|
1812
|
+
const val = event.value;
|
|
1813
|
+
const text = typeof val === "object" && val !== null && "text" in val ? val.text : typeof val === "string" ? val : event.text;
|
|
1814
|
+
const sequence = typeof val === "object" && val !== null && "sequence" in val ? val.sequence : 0;
|
|
1815
|
+
if (text) {
|
|
1816
|
+
const suggestion = {
|
|
1817
|
+
id: Utils.getUniqueId(),
|
|
1818
|
+
text,
|
|
1819
|
+
value: text,
|
|
1820
|
+
timestamp: now,
|
|
1821
|
+
sequence,
|
|
1822
|
+
feedbackType: null,
|
|
1823
|
+
badFeedbackReason: null
|
|
1824
|
+
};
|
|
1825
|
+
this.emit("suggestion", suggestion);
|
|
1826
|
+
}
|
|
1799
1827
|
}
|
|
1800
1828
|
if (event.event_type === "sentiment" && event.value) {
|
|
1829
|
+
const sentimentValue = typeof event.value === "string" ? event.value : event.value.text;
|
|
1801
1830
|
const sentiment = {
|
|
1802
|
-
label:
|
|
1831
|
+
label: sentimentValue.toLowerCase(),
|
|
1803
1832
|
timestamp: now
|
|
1804
1833
|
};
|
|
1805
1834
|
this.emit("sentiment", sentiment);
|
|
@@ -1811,7 +1840,7 @@ class ExotelAIAssistController extends EventEmitter {
|
|
|
1811
1840
|
this.emit("streamState", state);
|
|
1812
1841
|
if (state === "connected" || state === "throttled") {
|
|
1813
1842
|
this._fireReady();
|
|
1814
|
-
} else if (state === "disconnected" && this.readyFired) {
|
|
1843
|
+
} else if ((state === "connection_timeout" || state === "disconnected") && this.readyFired) {
|
|
1815
1844
|
this.readyFired = false;
|
|
1816
1845
|
this.emit("onReady", false);
|
|
1817
1846
|
}
|
|
@@ -25,6 +25,7 @@ export interface UseExotelAIAssistReturn {
|
|
|
25
25
|
connect: () => void;
|
|
26
26
|
disconnect: () => void;
|
|
27
27
|
setParams: (patch: Partial<ExotelAIAssistParams>) => void;
|
|
28
|
+
sendSuggestionFeedback: (sequence: number, feedbackType: "good" | "bad" | null, badFeedbackReason?: string | null) => boolean;
|
|
28
29
|
}
|
|
29
30
|
/** Internal extended return — adds botConfig for the UI component only. */
|
|
30
31
|
export interface UseExotelAIAssistInternalReturn extends UseExotelAIAssistReturn {
|
package/dist/index.js
CHANGED
|
@@ -19294,6 +19294,30 @@ const Smile = createLucideIcon$1("Smile", [["circle", {
|
|
|
19294
19294
|
key: "1p4y9e"
|
|
19295
19295
|
}]]);
|
|
19296
19296
|
|
|
19297
|
+
/**
|
|
19298
|
+
* lucide-react v0.0.1 - ISC
|
|
19299
|
+
*/
|
|
19300
|
+
|
|
19301
|
+
const ThumbsDown = createLucideIcon$1("ThumbsDown", [["path", {
|
|
19302
|
+
d: "M17 14V2",
|
|
19303
|
+
key: "8ymqnk"
|
|
19304
|
+
}], ["path", {
|
|
19305
|
+
d: "M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22h0a3.13 3.13 0 0 1-3-3.88Z",
|
|
19306
|
+
key: "s6e0r"
|
|
19307
|
+
}]]);
|
|
19308
|
+
|
|
19309
|
+
/**
|
|
19310
|
+
* lucide-react v0.0.1 - ISC
|
|
19311
|
+
*/
|
|
19312
|
+
|
|
19313
|
+
const ThumbsUp = createLucideIcon$1("ThumbsUp", [["path", {
|
|
19314
|
+
d: "M7 10v12",
|
|
19315
|
+
key: "1qc93n"
|
|
19316
|
+
}], ["path", {
|
|
19317
|
+
d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2h0a3.13 3.13 0 0 1 3 3.88Z",
|
|
19318
|
+
key: "y3tblf"
|
|
19319
|
+
}]]);
|
|
19320
|
+
|
|
19297
19321
|
const MAX_VISIBLE_TOASTS = 5;
|
|
19298
19322
|
const AUTO_DISMISS_MS = 3000;
|
|
19299
19323
|
const ToastContext = reactExports.createContext(null);
|
|
@@ -21085,6 +21109,25 @@ class ExotelAIAssistController extends EventEmitter {
|
|
|
21085
21109
|
getStreamState() {
|
|
21086
21110
|
return this._streamState;
|
|
21087
21111
|
}
|
|
21112
|
+
sendSuggestionFeedback(sequence, feedbackType, badFeedbackReason = null) {
|
|
21113
|
+
if (!this.transport || this.status !== "connected") {
|
|
21114
|
+
console.warn("[ExotelAIAssist] Cannot send feedback: not connected");
|
|
21115
|
+
return false;
|
|
21116
|
+
}
|
|
21117
|
+
const message = {
|
|
21118
|
+
type: "suggestion_feedback",
|
|
21119
|
+
sequence,
|
|
21120
|
+
feedback_type: feedbackType,
|
|
21121
|
+
bad_feedback_reason: badFeedbackReason
|
|
21122
|
+
};
|
|
21123
|
+
try {
|
|
21124
|
+
this.transport.send(JSON.stringify(message));
|
|
21125
|
+
return true;
|
|
21126
|
+
} catch (error) {
|
|
21127
|
+
console.error("[ExotelAIAssist] Failed to send feedback:", error);
|
|
21128
|
+
return false;
|
|
21129
|
+
}
|
|
21130
|
+
}
|
|
21088
21131
|
_ensureTransport() {
|
|
21089
21132
|
if (this.transport) return;
|
|
21090
21133
|
this.transport = createTransport(Utils.hash(this.params));
|
|
@@ -21207,17 +21250,27 @@ class ExotelAIAssistController extends EventEmitter {
|
|
|
21207
21250
|
});
|
|
21208
21251
|
this.emit("transcript", lines);
|
|
21209
21252
|
}
|
|
21210
|
-
if (event.event_type === "suggestion"
|
|
21211
|
-
const
|
|
21212
|
-
|
|
21213
|
-
|
|
21214
|
-
|
|
21215
|
-
|
|
21216
|
-
|
|
21253
|
+
if (event.event_type === "suggestion") {
|
|
21254
|
+
const val = event.value;
|
|
21255
|
+
const text = typeof val === "object" && val !== null && "text" in val ? val.text : typeof val === "string" ? val : event.text;
|
|
21256
|
+
const sequence = typeof val === "object" && val !== null && "sequence" in val ? val.sequence : 0;
|
|
21257
|
+
if (text) {
|
|
21258
|
+
const suggestion = {
|
|
21259
|
+
id: Utils.getUniqueId(),
|
|
21260
|
+
text,
|
|
21261
|
+
value: text,
|
|
21262
|
+
timestamp: now,
|
|
21263
|
+
sequence,
|
|
21264
|
+
feedbackType: null,
|
|
21265
|
+
badFeedbackReason: null
|
|
21266
|
+
};
|
|
21267
|
+
this.emit("suggestion", suggestion);
|
|
21268
|
+
}
|
|
21217
21269
|
}
|
|
21218
21270
|
if (event.event_type === "sentiment" && event.value) {
|
|
21271
|
+
const sentimentValue = typeof event.value === "string" ? event.value : event.value.text;
|
|
21219
21272
|
const sentiment = {
|
|
21220
|
-
label:
|
|
21273
|
+
label: sentimentValue.toLowerCase(),
|
|
21221
21274
|
timestamp: now
|
|
21222
21275
|
};
|
|
21223
21276
|
this.emit("sentiment", sentiment);
|
|
@@ -21229,7 +21282,7 @@ class ExotelAIAssistController extends EventEmitter {
|
|
|
21229
21282
|
this.emit("streamState", state);
|
|
21230
21283
|
if (state === "connected" || state === "throttled") {
|
|
21231
21284
|
this._fireReady();
|
|
21232
|
-
} else if (state === "disconnected" && this.readyFired) {
|
|
21285
|
+
} else if ((state === "connection_timeout" || state === "disconnected") && this.readyFired) {
|
|
21233
21286
|
this.readyFired = false;
|
|
21234
21287
|
this.emit("onReady", false);
|
|
21235
21288
|
}
|
|
@@ -21293,9 +21346,20 @@ function useExotelAIAssist(params) {
|
|
|
21293
21346
|
var _a;
|
|
21294
21347
|
return (_a = controllerRef.current) === null || _a === void 0 ? void 0 : _a.setParams(patch);
|
|
21295
21348
|
}, []);
|
|
21349
|
+
const sendSuggestionFeedback = reactExports.useCallback((sequence, feedbackType, badFeedbackReason = null) => {
|
|
21350
|
+
var _a, _b;
|
|
21351
|
+
const sent = (_b = (_a = controllerRef.current) === null || _a === void 0 ? void 0 : _a.sendSuggestionFeedback(sequence, feedbackType, badFeedbackReason)) !== null && _b !== void 0 ? _b : false;
|
|
21352
|
+
if (sent) {
|
|
21353
|
+
setSuggestions(prev => prev.map(s => s.sequence === sequence ? Object.assign(Object.assign({}, s), {
|
|
21354
|
+
feedbackType,
|
|
21355
|
+
badFeedbackReason
|
|
21356
|
+
}) : s));
|
|
21357
|
+
}
|
|
21358
|
+
return sent;
|
|
21359
|
+
}, []);
|
|
21296
21360
|
return {
|
|
21297
|
-
isReady,
|
|
21298
21361
|
streamState,
|
|
21362
|
+
isReady,
|
|
21299
21363
|
suggestions,
|
|
21300
21364
|
transcripts,
|
|
21301
21365
|
sentiment,
|
|
@@ -21303,7 +21367,8 @@ function useExotelAIAssist(params) {
|
|
|
21303
21367
|
lastError,
|
|
21304
21368
|
connect,
|
|
21305
21369
|
disconnect,
|
|
21306
|
-
setParams
|
|
21370
|
+
setParams,
|
|
21371
|
+
sendSuggestionFeedback
|
|
21307
21372
|
};
|
|
21308
21373
|
}
|
|
21309
21374
|
|
|
@@ -21332,7 +21397,7 @@ function styleInject(css, ref) {
|
|
|
21332
21397
|
}
|
|
21333
21398
|
}
|
|
21334
21399
|
|
|
21335
|
-
var css_248z = ".oa-panel{background:#fff;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif}.oa-panel,.oa-theme-root{display:flex;flex-direction:column;height:100%;min-height:0;width:100%}.oa-theme-root{position:relative}.oa-header-title{color:#111827;font-size:16px;font-weight:600;line-height:20px;margin:0}.oa-tabs{width:100%}.oa-tabs-content{flex:1;min-height:0;overflow:hidden}.oa-tabs-content[data-state=inactive]{display:none!important}.oa-tabs-content[data-state=active]{display:flex;flex-direction:column}.oa-tabs-list{border-bottom:1px solid #e5e7eb;display:flex;gap:20px;padding:0}.oa-tabs-trigger{align-items:center;background:transparent;border:none;border-radius:0;color:#6b7280;cursor:pointer;display:inline-flex;font-size:15px;font-weight:500;gap:6px;outline:none;padding:10px 0;position:relative}.oa-tabs-trigger:hover{color:#374151}.oa-tabs-trigger[data-state=active]{color:#2563eb}.oa-tabs-trigger[data-state=active]:after{background:#2563eb;border-radius:2px;bottom:-1px;content:\"\";height:2px;left:0;position:absolute;right:0}.oa-suggestion-card{border:1px solid rgba(17,24,39,.04);border-radius:12px;padding:12px;text-align:left}.oa-suggestion-card--recent-wrapper{animation:oa-suggestion-enter .4s ease-out,oa-border-shimmer 3s ease-in-out .4s infinite;background:linear-gradient(90deg,#7c3aed,#e11d48,#7c3aed);background-size:200% 100%;border-radius:12px;padding:2px;text-align:left}.oa-suggestion-card--recent-wrapper .oa-suggestion-card--recent{border:none}.oa-suggestion-card--recent{animation:none;background:linear-gradient(90deg,#f5f3ff 0,#fef3f2 50%,#fff7ed);border-radius:9px}.oa-suggestion-card--older{background:#f5f5f5;border:1px solid #e5e7eb}.oa-suggestion-card--older .oa-suggestion-text{color:#252525}@keyframes oa-suggestion-enter{0%{opacity:.3;transform:scale(.97)}to{opacity:1;transform:scale(1)}}@keyframes oa-border-shimmer{0%,to{background-position:0 50%}50%{background-position:100% 50%}}.oa-suggestion-text{color:#111827;font-size:13px;line-height:18px;white-space:pre-wrap}.oa-copy-icon{align-items:center;background:#fff;border:1px solid #e5e7eb;border-radius:8px;color:#6b7280;cursor:pointer;display:inline-flex;height:32px;justify-content:center;min-height:32px;min-width:32px;padding:0;width:32px}.oa-copy-icon:hover{background:#f9fafb;color:#374151}@keyframes oa-toast-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.oa-stream-overlay{display:flex;flex:1;flex-direction:column;min-height:0}.oa-stream-banner{align-items:flex-start;background:#fef3c7;border:1px solid #fde68a;border-radius:8px;color:#92400e;display:flex;font-size:13px;gap:8px;line-height:1.4;padding:10px 12px}.oa-stream-banner-icon{align-items:center;display:inline-flex;flex-shrink:0;margin-top:1px}.oa-stream-banner-text{flex:1}.oa-stream-empty{flex:1;gap:16px;justify-content:center;min-height:0}.oa-stream-empty,.oa-stream-empty-text{align-items:center;display:flex;flex-direction:column}.oa-stream-empty-text{gap:6px;text-align:center}.oa-stream-empty-title{color:#111827;font-size:16px;font-weight:700;line-height:20px}.oa-stream-empty-subtitle{color:#6b7280;font-size:14px;line-height:20px}.oa-throttle-banner{align-items:flex-start;background:#fcefee;border:1px solid #e8cecb;border-radius:8px;color:#833d09;display:flex;font-size:13px;gap:8px;line-height:1.4;padding:10px 12px}.oa-throttle-banner-icon{align-items:center;display:inline-flex;flex-shrink:0;margin-top:1px}.oa-throttle-banner-text{flex:1}.oa-starting-loader{align-items:center;display:flex;flex:1;flex-direction:column;gap:16px;height:100%;justify-content:center;min-height:0}.oa-starting-spinner{animation:oa-spinner-rotate 1.4s linear infinite;height:48px;width:48px}.oa-starting-spinner-track{stroke:#e5e7eb}.oa-starting-spinner-arc{stroke:#2563eb;stroke-dasharray:80,126;stroke-dashoffset:0;animation:oa-spinner-dash 1.4s ease-in-out infinite}@keyframes oa-spinner-rotate{to{transform:rotate(1turn)}}@keyframes oa-spinner-dash{0%{stroke-dasharray:1,126;stroke-dashoffset:0}50%{stroke-dasharray:80,126;stroke-dashoffset:-35}to{stroke-dasharray:80,126;stroke-dashoffset:-124}}.oa-starting-loader-text{color:#111827;font-size:16px;font-weight:600;line-height:20px}.oa-muted{color:#6b7280}";
|
|
21400
|
+
var css_248z = ".oa-panel{background:#fff;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif}.oa-panel,.oa-theme-root{display:flex;flex-direction:column;height:100%;min-height:0;width:100%}.oa-theme-root{position:relative}.oa-header-title{color:#111827;font-size:16px;font-weight:600;line-height:20px;margin:0}.oa-tabs{width:100%}.oa-tabs-content{flex:1;min-height:0;overflow:hidden}.oa-tabs-content[data-state=inactive]{display:none!important}.oa-tabs-content[data-state=active]{display:flex;flex-direction:column}.oa-tabs-list{border-bottom:1px solid #e5e7eb;display:flex;gap:20px;padding:0}.oa-tabs-trigger{align-items:center;background:transparent;border:none;border-radius:0;color:#6b7280;cursor:pointer;display:inline-flex;font-size:15px;font-weight:500;gap:6px;outline:none;padding:10px 0;position:relative}.oa-tabs-trigger:hover{color:#374151}.oa-tabs-trigger[data-state=active]{color:#2563eb}.oa-tabs-trigger[data-state=active]:after{background:#2563eb;border-radius:2px;bottom:-1px;content:\"\";height:2px;left:0;position:absolute;right:0}.oa-suggestion-card{border:1px solid rgba(17,24,39,.04);border-radius:12px;padding:12px;text-align:left}.oa-suggestion-card--recent-wrapper{animation:oa-suggestion-enter .4s ease-out,oa-border-shimmer 3s ease-in-out .4s infinite;background:linear-gradient(90deg,#7c3aed,#e11d48,#7c3aed);background-size:200% 100%;border-radius:12px;padding:2px;text-align:left}.oa-suggestion-card--recent-wrapper .oa-suggestion-card--recent{border:none}.oa-suggestion-card--recent{animation:none;background:linear-gradient(90deg,#f5f3ff 0,#fef3f2 50%,#fff7ed);border-radius:9px}.oa-suggestion-card--older{background:#f5f5f5;border:1px solid #e5e7eb}.oa-suggestion-card--older .oa-suggestion-text{color:#252525}@keyframes oa-suggestion-enter{0%{opacity:.3;transform:scale(.97)}to{opacity:1;transform:scale(1)}}@keyframes oa-border-shimmer{0%,to{background-position:0 50%}50%{background-position:100% 50%}}.oa-suggestion-text{color:#111827;font-size:13px;line-height:18px;white-space:pre-wrap}.oa-copy-icon,.oa-feedback-icon{align-items:center;background:#fff;border:1px solid #e5e7eb;border-radius:8px;color:#6b7280;cursor:pointer;display:inline-flex;height:32px;justify-content:center;min-height:32px;min-width:32px;padding:0;width:32px}.oa-copy-icon:hover,.oa-feedback-icon:hover{background:#f9fafb;color:#374151}.oa-feedback-icon--positive{background:#dcfce7!important;border-color:#86efac!important;color:#16a34a!important}.oa-feedback-icon--negative{background:#fee2e2!important;border-color:#fca5a5!important;color:#dc2626!important}.oa-feedback-icon:disabled{cursor:default;opacity:.5}.oa-feedback-icon--negative:disabled,.oa-feedback-icon--positive:disabled{opacity:1}.oa-feedback-reason-btn{align-items:center;background:#fef2f2;border:1px solid #fecaca;border-radius:16px;color:#991b1b;cursor:pointer;display:inline-flex;font-family:inherit;font-size:12px;font-weight:500;line-height:18px;padding:4px 12px;transition:background .15s,border-color .15s}.oa-feedback-reason-btn:hover:not(:disabled){background:#fee2e2;border-color:#f87171}.oa-feedback-reason-btn--selected{background:#dc2626!important;border-color:#dc2626!important;color:#fff!important}.oa-feedback-reason-btn:disabled{cursor:default;opacity:.45}@keyframes oa-toast-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.oa-stream-overlay{display:flex;flex:1;flex-direction:column;min-height:0}.oa-stream-banner{align-items:flex-start;background:#fef3c7;border:1px solid #fde68a;border-radius:8px;color:#92400e;display:flex;font-size:13px;gap:8px;line-height:1.4;padding:10px 12px}.oa-stream-banner-icon{align-items:center;display:inline-flex;flex-shrink:0;margin-top:1px}.oa-stream-banner-text{flex:1}.oa-stream-empty{flex:1;gap:16px;justify-content:center;min-height:0}.oa-stream-empty,.oa-stream-empty-text{align-items:center;display:flex;flex-direction:column}.oa-stream-empty-text{gap:6px;text-align:center}.oa-stream-empty-title{color:#111827;font-size:16px;font-weight:700;line-height:20px}.oa-stream-empty-subtitle{color:#6b7280;font-size:14px;line-height:20px}.oa-throttle-banner{align-items:flex-start;background:#fcefee;border:1px solid #e8cecb;border-radius:8px;color:#833d09;display:flex;font-size:13px;gap:8px;line-height:1.4;padding:10px 12px}.oa-throttle-banner-icon{align-items:center;display:inline-flex;flex-shrink:0;margin-top:1px}.oa-throttle-banner-text{flex:1}.oa-starting-loader{align-items:center;display:flex;flex:1;flex-direction:column;gap:16px;height:100%;justify-content:center;min-height:0}.oa-starting-spinner{animation:oa-spinner-rotate 1.4s linear infinite;height:48px;width:48px}.oa-starting-spinner-track{stroke:#e5e7eb}.oa-starting-spinner-arc{stroke:#2563eb;stroke-dasharray:80,126;stroke-dashoffset:0;animation:oa-spinner-dash 1.4s ease-in-out infinite}@keyframes oa-spinner-rotate{to{transform:rotate(1turn)}}@keyframes oa-spinner-dash{0%{stroke-dasharray:1,126;stroke-dashoffset:0}50%{stroke-dasharray:80,126;stroke-dashoffset:-35}to{stroke-dasharray:80,126;stroke-dashoffset:-124}}.oa-starting-loader-text{color:#111827;font-size:16px;font-weight:600;line-height:20px}.oa-muted{color:#6b7280}";
|
|
21336
21401
|
styleInject(css_248z);
|
|
21337
21402
|
|
|
21338
21403
|
function Sparkle() {
|
|
@@ -21680,9 +21745,17 @@ const EmptyState = ({
|
|
|
21680
21745
|
function SuggestionsTab({
|
|
21681
21746
|
suggestions,
|
|
21682
21747
|
connected,
|
|
21683
|
-
botConfig
|
|
21748
|
+
botConfig,
|
|
21749
|
+
sendSuggestionFeedback
|
|
21684
21750
|
}) {
|
|
21751
|
+
var _a, _b, _c;
|
|
21685
21752
|
const toast = useToast();
|
|
21753
|
+
const [expandedSequence, setExpandedSequence] = reactExports.useState(null);
|
|
21754
|
+
const feedbackEnabled = ((_a = botConfig === null || botConfig === void 0 ? void 0 : botConfig.suggestion) === null || _a === void 0 ? void 0 : _a.feedback_enabled) === true;
|
|
21755
|
+
const badFeedbackOptions = reactExports.useMemo(() => {
|
|
21756
|
+
var _a, _b;
|
|
21757
|
+
return (_b = (_a = botConfig === null || botConfig === void 0 ? void 0 : botConfig.suggestion) === null || _a === void 0 ? void 0 : _a.bad_feedback_options) !== null && _b !== void 0 ? _b : [];
|
|
21758
|
+
}, [(_b = botConfig === null || botConfig === void 0 ? void 0 : botConfig.suggestion) === null || _b === void 0 ? void 0 : _b.bad_feedback_options]);
|
|
21686
21759
|
const handleCopy = async text => {
|
|
21687
21760
|
try {
|
|
21688
21761
|
await navigator.clipboard.writeText(text);
|
|
@@ -21691,13 +21764,36 @@ function SuggestionsTab({
|
|
|
21691
21764
|
toast.error("Failed to copy");
|
|
21692
21765
|
}
|
|
21693
21766
|
};
|
|
21767
|
+
const handleThumbsUp = reactExports.useCallback((sequence, currentFeedback) => {
|
|
21768
|
+
if (!feedbackEnabled) return;
|
|
21769
|
+
const newType = currentFeedback === "good" ? null : "good";
|
|
21770
|
+
sendSuggestionFeedback(sequence, newType, null);
|
|
21771
|
+
setExpandedSequence(null);
|
|
21772
|
+
}, [sendSuggestionFeedback, feedbackEnabled]);
|
|
21773
|
+
const handleThumbsDown = reactExports.useCallback((sequence, currentFeedback) => {
|
|
21774
|
+
if (!feedbackEnabled) return;
|
|
21775
|
+
if (currentFeedback === "bad") {
|
|
21776
|
+
sendSuggestionFeedback(sequence, null, null);
|
|
21777
|
+
setExpandedSequence(null);
|
|
21778
|
+
return;
|
|
21779
|
+
}
|
|
21780
|
+
sendSuggestionFeedback(sequence, "bad", null);
|
|
21781
|
+
if (badFeedbackOptions.length > 0) {
|
|
21782
|
+
setExpandedSequence(sequence);
|
|
21783
|
+
}
|
|
21784
|
+
}, [sendSuggestionFeedback, badFeedbackOptions, feedbackEnabled]);
|
|
21785
|
+
const handleBadFeedbackReason = reactExports.useCallback((sequence, reason) => {
|
|
21786
|
+
if (!feedbackEnabled) return;
|
|
21787
|
+
sendSuggestionFeedback(sequence, "bad", reason);
|
|
21788
|
+
setExpandedSequence(null);
|
|
21789
|
+
}, [sendSuggestionFeedback, feedbackEnabled]);
|
|
21694
21790
|
if (!connected) {
|
|
21695
21791
|
return jsxRuntimeExports.jsx(EmptyState, {
|
|
21696
21792
|
title: "Assistant is inactive",
|
|
21697
21793
|
subtitle: "Start a call to receive real-time suggestions."
|
|
21698
21794
|
});
|
|
21699
21795
|
}
|
|
21700
|
-
if ((botConfig === null || botConfig === void 0 ? void 0 : botConfig.
|
|
21796
|
+
if (((_c = botConfig === null || botConfig === void 0 ? void 0 : botConfig.suggestion) === null || _c === void 0 ? void 0 : _c.enabled) === false) {
|
|
21701
21797
|
return jsxRuntimeExports.jsx(EmptyState, {
|
|
21702
21798
|
title: "Suggestions are disabled",
|
|
21703
21799
|
subtitle: "Suggestions are disabled in the bot configuration. Please contact the administrator to enable it."
|
|
@@ -21731,21 +21827,37 @@ function SuggestionsTab({
|
|
|
21731
21827
|
children: displayed.map((suggestion, index) => {
|
|
21732
21828
|
const isRecent = index === 0;
|
|
21733
21829
|
const cardClass = isRecent ? "oa-suggestion-card oa-suggestion-card--recent" : "oa-suggestion-card oa-suggestion-card--older";
|
|
21830
|
+
const showReasons = suggestion.feedbackType === "bad" || expandedSequence === suggestion.sequence;
|
|
21734
21831
|
return jsxRuntimeExports.jsxs("div", {
|
|
21735
|
-
|
|
21736
|
-
display: "flex",
|
|
21737
|
-
flexDirection: "row",
|
|
21738
|
-
alignItems: "flex-start",
|
|
21739
|
-
gap: "8px"
|
|
21740
|
-
},
|
|
21741
|
-
children: [isRecent ? jsxRuntimeExports.jsx("div", {
|
|
21742
|
-
className: "oa-suggestion-card--recent-wrapper",
|
|
21832
|
+
children: [jsxRuntimeExports.jsxs("div", {
|
|
21743
21833
|
style: {
|
|
21744
|
-
|
|
21745
|
-
|
|
21834
|
+
display: "flex",
|
|
21835
|
+
flexDirection: "row",
|
|
21836
|
+
alignItems: "flex-start",
|
|
21837
|
+
gap: "8px"
|
|
21746
21838
|
},
|
|
21747
|
-
children: jsxRuntimeExports.jsx("div", {
|
|
21839
|
+
children: [isRecent ? jsxRuntimeExports.jsx("div", {
|
|
21840
|
+
className: "oa-suggestion-card--recent-wrapper",
|
|
21841
|
+
style: {
|
|
21842
|
+
flex: "1 1 auto",
|
|
21843
|
+
maxWidth: "72%"
|
|
21844
|
+
},
|
|
21845
|
+
children: jsxRuntimeExports.jsx("div", {
|
|
21846
|
+
className: cardClass,
|
|
21847
|
+
children: jsxRuntimeExports.jsx("span", {
|
|
21848
|
+
className: "oa-suggestion-text",
|
|
21849
|
+
style: {
|
|
21850
|
+
fontSize: "15px"
|
|
21851
|
+
},
|
|
21852
|
+
children: suggestion.text
|
|
21853
|
+
})
|
|
21854
|
+
})
|
|
21855
|
+
}) : jsxRuntimeExports.jsx("div", {
|
|
21748
21856
|
className: cardClass,
|
|
21857
|
+
style: {
|
|
21858
|
+
flex: "1 1 auto",
|
|
21859
|
+
maxWidth: "72%"
|
|
21860
|
+
},
|
|
21749
21861
|
children: jsxRuntimeExports.jsx("span", {
|
|
21750
21862
|
className: "oa-suggestion-text",
|
|
21751
21863
|
style: {
|
|
@@ -21753,31 +21865,57 @@ function SuggestionsTab({
|
|
|
21753
21865
|
},
|
|
21754
21866
|
children: suggestion.value
|
|
21755
21867
|
})
|
|
21756
|
-
})
|
|
21757
|
-
}) : jsxRuntimeExports.jsx("div", {
|
|
21758
|
-
className: cardClass,
|
|
21759
|
-
style: {
|
|
21760
|
-
flex: "1 1 auto",
|
|
21761
|
-
maxWidth: "80%"
|
|
21762
|
-
},
|
|
21763
|
-
children: jsxRuntimeExports.jsx("span", {
|
|
21764
|
-
className: "oa-suggestion-text",
|
|
21868
|
+
}), jsxRuntimeExports.jsxs("div", {
|
|
21765
21869
|
style: {
|
|
21766
|
-
|
|
21870
|
+
display: "flex",
|
|
21871
|
+
flexDirection: "column",
|
|
21872
|
+
gap: "4px",
|
|
21873
|
+
flexShrink: 0,
|
|
21874
|
+
marginTop: "10px"
|
|
21767
21875
|
},
|
|
21768
|
-
children:
|
|
21769
|
-
|
|
21770
|
-
|
|
21771
|
-
|
|
21772
|
-
|
|
21773
|
-
|
|
21876
|
+
children: [jsxRuntimeExports.jsx("button", {
|
|
21877
|
+
className: "oa-copy-icon",
|
|
21878
|
+
"aria-label": "Copy suggestion",
|
|
21879
|
+
onClick: () => handleCopy(suggestion.text),
|
|
21880
|
+
children: jsxRuntimeExports.jsx(Copy, {
|
|
21881
|
+
size: 14
|
|
21882
|
+
})
|
|
21883
|
+
}), feedbackEnabled && jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, {
|
|
21884
|
+
children: [jsxRuntimeExports.jsx("button", {
|
|
21885
|
+
className: `oa-feedback-icon ${suggestion.feedbackType === "good" ? "oa-feedback-icon--positive" : ""}`,
|
|
21886
|
+
"aria-label": "Mark as helpful",
|
|
21887
|
+
onClick: () => handleThumbsUp(suggestion.sequence, suggestion.feedbackType),
|
|
21888
|
+
style: {
|
|
21889
|
+
color: suggestion.feedbackType === "good" ? "#16a34a" : undefined
|
|
21890
|
+
},
|
|
21891
|
+
children: jsxRuntimeExports.jsx(ThumbsUp, {
|
|
21892
|
+
size: 14
|
|
21893
|
+
})
|
|
21894
|
+
}), jsxRuntimeExports.jsx("button", {
|
|
21895
|
+
className: `oa-feedback-icon ${suggestion.feedbackType === "bad" ? "oa-feedback-icon--negative" : ""}`,
|
|
21896
|
+
"aria-label": "Mark as not helpful",
|
|
21897
|
+
onClick: () => handleThumbsDown(suggestion.sequence, suggestion.feedbackType),
|
|
21898
|
+
style: {
|
|
21899
|
+
color: suggestion.feedbackType === "bad" ? "#dc2626" : undefined
|
|
21900
|
+
},
|
|
21901
|
+
children: jsxRuntimeExports.jsx(ThumbsDown, {
|
|
21902
|
+
size: 14
|
|
21903
|
+
})
|
|
21904
|
+
})]
|
|
21905
|
+
})]
|
|
21906
|
+
})]
|
|
21907
|
+
}), showReasons && badFeedbackOptions.length > 0 && jsxRuntimeExports.jsx("div", {
|
|
21774
21908
|
style: {
|
|
21775
|
-
|
|
21776
|
-
|
|
21909
|
+
display: "flex",
|
|
21910
|
+
gap: "8px",
|
|
21911
|
+
flexWrap: "wrap",
|
|
21912
|
+
marginTop: "8px"
|
|
21777
21913
|
},
|
|
21778
|
-
children: jsxRuntimeExports.jsx(
|
|
21779
|
-
|
|
21780
|
-
|
|
21914
|
+
children: badFeedbackOptions.map(reason => jsxRuntimeExports.jsx("button", {
|
|
21915
|
+
className: `oa-feedback-reason-btn ${suggestion.badFeedbackReason === reason ? "oa-feedback-reason-btn--selected" : ""}`,
|
|
21916
|
+
onClick: () => handleBadFeedbackReason(suggestion.sequence, reason),
|
|
21917
|
+
children: reason
|
|
21918
|
+
}, reason))
|
|
21781
21919
|
})]
|
|
21782
21920
|
}, suggestion.id);
|
|
21783
21921
|
})
|
|
@@ -21876,12 +22014,13 @@ function ExotelAIAssist(_a) {
|
|
|
21876
22014
|
} = _a,
|
|
21877
22015
|
params = __rest(_a, ["className", "onReady"]);
|
|
21878
22016
|
const {
|
|
21879
|
-
isReady,
|
|
21880
22017
|
streamState,
|
|
22018
|
+
isReady,
|
|
21881
22019
|
suggestions,
|
|
21882
22020
|
transcripts,
|
|
21883
22021
|
sentiment,
|
|
21884
|
-
botConfig
|
|
22022
|
+
botConfig,
|
|
22023
|
+
sendSuggestionFeedback
|
|
21885
22024
|
} = useExotelAIAssist(params);
|
|
21886
22025
|
const onReadyRef = reactExports.useRef(onReady);
|
|
21887
22026
|
onReadyRef.current = onReady;
|
|
@@ -21899,7 +22038,7 @@ function ExotelAIAssist(_a) {
|
|
|
21899
22038
|
warningBannerMessage: "AI Assist couldn't join this call \u2014 capacity is full. It should be ready for your next call."
|
|
21900
22039
|
});
|
|
21901
22040
|
}
|
|
21902
|
-
if (streamState === "
|
|
22041
|
+
if (streamState === "connection_timeout") {
|
|
21903
22042
|
return jsxRuntimeExports.jsx(EmptyState, {
|
|
21904
22043
|
title: "AI Assist is currently inactive",
|
|
21905
22044
|
subtitle: "we were unable to establish a connection."
|
|
@@ -21959,7 +22098,8 @@ function ExotelAIAssist(_a) {
|
|
|
21959
22098
|
children: jsxRuntimeExports.jsx(SuggestionsTab, {
|
|
21960
22099
|
suggestions: suggestions,
|
|
21961
22100
|
connected: connected,
|
|
21962
|
-
botConfig: botConfig
|
|
22101
|
+
botConfig: botConfig,
|
|
22102
|
+
sendSuggestionFeedback: sendSuggestionFeedback
|
|
21963
22103
|
})
|
|
21964
22104
|
}), jsxRuntimeExports.jsx(Content$1, {
|
|
21965
22105
|
value: "transcript",
|