@modochats/widget 0.1.4 → 1.1.0
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/.github/workflows/build-and-publish.yml +116 -174
- package/.releaserc +59 -0
- package/CHANGELOG.md +16 -0
- package/README.md +191 -191
- package/package.json +79 -76
- package/src/app.ts +117 -117
- package/src/constants/index.ts +21 -21
- package/src/constants/regex.ts +2 -2
- package/src/constants/version.ts +2 -0
- package/src/index.ts +16 -16
- package/src/services/chat/conversation.ts +135 -135
- package/src/services/chat/message-utils.ts +221 -221
- package/src/services/chat/model.ts +139 -139
- package/src/services/chatbot/chatbot.ts +66 -66
- package/src/services/checker.ts +10 -10
- package/src/services/listeners/fn.ts +77 -77
- package/src/services/socket/utils.ts +9 -9
- package/src/services/user/customer-data.ts +78 -78
- package/src/services/voice-chat/model.ts +79 -79
- package/src/services/voice-chat/utils.ts +137 -137
- package/src/tools/fetch.ts +7 -7
- package/src/types/app.ts +17 -17
- package/src/types/conversation.ts +14 -14
- package/src/types/socket.ts +7 -7
- package/src/types/window.ts +12 -12
- package/src/utils/audio.ts +67 -67
- package/src/utils/browser.ts +4 -4
- package/src/utils/fetch.ts +98 -98
- package/src/utils/uuid.ts +13 -13
- package/dist/src/app.d.ts +0 -29
- package/dist/src/app.js +0 -1
- package/dist/src/app.js.map +0 -1
- package/dist/src/constants/index.d.ts +0 -9
- package/dist/src/constants/index.js +0 -1
- package/dist/src/constants/index.js.map +0 -1
- package/dist/src/constants/regex.d.ts +0 -2
- package/dist/src/constants/regex.js +0 -1
- package/dist/src/constants/regex.js.map +0 -1
- package/dist/src/index.d.ts +0 -9
- package/dist/src/index.js +0 -1
- package/dist/src/index.js.map +0 -1
- package/dist/src/models/chatbot.d.ts +0 -23
- package/dist/src/models/chatbot.js +0 -1
- package/dist/src/models/chatbot.js.map +0 -1
- package/dist/src/models/conversation.d.ts +0 -22
- package/dist/src/models/conversation.js +0 -1
- package/dist/src/models/conversation.js.map +0 -1
- package/dist/src/models/customer-data.d.ts +0 -31
- package/dist/src/models/customer-data.js +0 -1
- package/dist/src/models/customer-data.js.map +0 -1
- package/dist/src/models/message-utils.d.ts +0 -12
- package/dist/src/models/message-utils.js +0 -1
- package/dist/src/models/message-utils.js.map +0 -1
- package/dist/src/services/chat/conversation.d.ts +0 -22
- package/dist/src/services/chat/conversation.js +0 -1
- package/dist/src/services/chat/conversation.js.map +0 -1
- package/dist/src/services/chat/message-utils.d.ts +0 -12
- package/dist/src/services/chat/message-utils.js +0 -1
- package/dist/src/services/chat/message-utils.js.map +0 -1
- package/dist/src/services/chat/model.d.ts +0 -27
- package/dist/src/services/chat/model.js +0 -1
- package/dist/src/services/chat/model.js.map +0 -1
- package/dist/src/services/chatbot/chatbot.d.ts +0 -23
- package/dist/src/services/chatbot/chatbot.js +0 -1
- package/dist/src/services/chatbot/chatbot.js.map +0 -1
- package/dist/src/services/checker.d.ts +0 -3
- package/dist/src/services/checker.js +0 -1
- package/dist/src/services/checker.js.map +0 -1
- package/dist/src/services/listeners/adders.d.ts +0 -3
- package/dist/src/services/listeners/adders.js +0 -1
- package/dist/src/services/listeners/adders.js.map +0 -1
- package/dist/src/services/listeners/fn.d.ts +0 -3
- package/dist/src/services/listeners/fn.js +0 -1
- package/dist/src/services/listeners/fn.js.map +0 -1
- package/dist/src/services/socket/utils.d.ts +0 -2
- package/dist/src/services/socket/utils.js +0 -1
- package/dist/src/services/socket/utils.js.map +0 -1
- package/dist/src/services/ui/fn.d.ts +0 -13
- package/dist/src/services/ui/fn.js +0 -1
- package/dist/src/services/ui/fn.js.map +0 -1
- package/dist/src/services/ui/html.d.ts +0 -3
- package/dist/src/services/ui/html.js +0 -1
- package/dist/src/services/ui/html.js.map +0 -1
- package/dist/src/services/user/customer-data.d.ts +0 -31
- package/dist/src/services/user/customer-data.js +0 -1
- package/dist/src/services/user/customer-data.js.map +0 -1
- package/dist/src/services/voice-chat/model.d.ts +0 -12
- package/dist/src/services/voice-chat/model.js +0 -1
- package/dist/src/services/voice-chat/model.js.map +0 -1
- package/dist/src/services/voice-chat/utils.d.ts +0 -9
- package/dist/src/services/voice-chat/utils.js +0 -1
- package/dist/src/services/voice-chat/utils.js.map +0 -1
- package/dist/src/tools/fetch.d.ts +0 -2
- package/dist/src/tools/fetch.js +0 -1
- package/dist/src/tools/fetch.js.map +0 -1
- package/dist/src/types/app.d.ts +0 -17
- package/dist/src/types/app.js +0 -1
- package/dist/src/types/app.js.map +0 -1
- package/dist/src/types/conversation.d.ts +0 -14
- package/dist/src/types/conversation.js +0 -1
- package/dist/src/types/conversation.js.map +0 -1
- package/dist/src/types/socket.d.ts +0 -6
- package/dist/src/types/socket.js +0 -1
- package/dist/src/types/socket.js.map +0 -1
- package/dist/src/types/window.d.ts +0 -9
- package/dist/src/types/window.js +0 -1
- package/dist/src/types/window.js.map +0 -1
- package/dist/src/utils/audio.d.ts +0 -3
- package/dist/src/utils/audio.js +0 -1
- package/dist/src/utils/audio.js.map +0 -1
- package/dist/src/utils/browser.d.ts +0 -2
- package/dist/src/utils/browser.js +0 -1
- package/dist/src/utils/browser.js.map +0 -1
- package/dist/src/utils/fetch.d.ts +0 -18
- package/dist/src/utils/fetch.js +0 -1
- package/dist/src/utils/fetch.js.map +0 -1
- package/dist/src/utils/uuid.d.ts +0 -6
- package/dist/src/utils/uuid.js +0 -1
- package/dist/src/utils/uuid.js.map +0 -1
- package/dist/types/src/app.d.ts +0 -30
- package/dist/types/src/app.d.ts.map +0 -1
- package/dist/types/src/constants/index.d.ts +0 -10
- package/dist/types/src/constants/index.d.ts.map +0 -1
- package/dist/types/src/constants/regex.d.ts +0 -3
- package/dist/types/src/constants/regex.d.ts.map +0 -1
- package/dist/types/src/index.d.ts +0 -10
- package/dist/types/src/index.d.ts.map +0 -1
- package/dist/types/src/models/chatbot.d.ts +0 -24
- package/dist/types/src/models/chatbot.d.ts.map +0 -1
- package/dist/types/src/models/conversation.d.ts +0 -23
- package/dist/types/src/models/conversation.d.ts.map +0 -1
- package/dist/types/src/models/customer-data.d.ts +0 -32
- package/dist/types/src/models/customer-data.d.ts.map +0 -1
- package/dist/types/src/models/message-utils.d.ts +0 -13
- package/dist/types/src/models/message-utils.d.ts.map +0 -1
- package/dist/types/src/services/chat/conversation.d.ts +0 -23
- package/dist/types/src/services/chat/conversation.d.ts.map +0 -1
- package/dist/types/src/services/chat/message-utils.d.ts +0 -13
- package/dist/types/src/services/chat/message-utils.d.ts.map +0 -1
- package/dist/types/src/services/chat/model.d.ts +0 -28
- package/dist/types/src/services/chat/model.d.ts.map +0 -1
- package/dist/types/src/services/chatbot/chatbot.d.ts +0 -24
- package/dist/types/src/services/chatbot/chatbot.d.ts.map +0 -1
- package/dist/types/src/services/checker.d.ts +0 -4
- package/dist/types/src/services/checker.d.ts.map +0 -1
- package/dist/types/src/services/listeners/adders.d.ts +0 -4
- package/dist/types/src/services/listeners/adders.d.ts.map +0 -1
- package/dist/types/src/services/listeners/fn.d.ts +0 -4
- package/dist/types/src/services/listeners/fn.d.ts.map +0 -1
- package/dist/types/src/services/socket/utils.d.ts +0 -3
- package/dist/types/src/services/socket/utils.d.ts.map +0 -1
- package/dist/types/src/services/ui/fn.d.ts +0 -14
- package/dist/types/src/services/ui/fn.d.ts.map +0 -1
- package/dist/types/src/services/ui/html.d.ts +0 -4
- package/dist/types/src/services/ui/html.d.ts.map +0 -1
- package/dist/types/src/services/user/customer-data.d.ts +0 -32
- package/dist/types/src/services/user/customer-data.d.ts.map +0 -1
- package/dist/types/src/services/voice-chat/model.d.ts +0 -13
- package/dist/types/src/services/voice-chat/model.d.ts.map +0 -1
- package/dist/types/src/services/voice-chat/utils.d.ts +0 -10
- package/dist/types/src/services/voice-chat/utils.d.ts.map +0 -1
- package/dist/types/src/tools/fetch.d.ts +0 -3
- package/dist/types/src/tools/fetch.d.ts.map +0 -1
- package/dist/types/src/types/app.d.ts +0 -18
- package/dist/types/src/types/app.d.ts.map +0 -1
- package/dist/types/src/types/conversation.d.ts +0 -15
- package/dist/types/src/types/conversation.d.ts.map +0 -1
- package/dist/types/src/types/socket.d.ts +0 -7
- package/dist/types/src/types/socket.d.ts.map +0 -1
- package/dist/types/src/types/window.d.ts +0 -10
- package/dist/types/src/types/window.d.ts.map +0 -1
- package/dist/types/src/utils/audio.d.ts +0 -4
- package/dist/types/src/utils/audio.d.ts.map +0 -1
- package/dist/types/src/utils/browser.d.ts +0 -3
- package/dist/types/src/utils/browser.d.ts.map +0 -1
- package/dist/types/src/utils/fetch.d.ts +0 -19
- package/dist/types/src/utils/fetch.d.ts.map +0 -1
- package/dist/types/src/utils/uuid.d.ts +0 -7
- package/dist/types/src/utils/uuid.d.ts.map +0 -1
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
import {Widget} from "#src/app.js";
|
|
2
|
-
import {fetchUpdateUserData} from "#src/utils/fetch.js";
|
|
3
|
-
import {generateUUID} from "#src/utils/uuid.js";
|
|
4
|
-
|
|
5
|
-
class CustomerData {
|
|
6
|
-
private _uniqueId?: string;
|
|
7
|
-
private _userData?: Record<string, any>;
|
|
8
|
-
private widget: Widget;
|
|
9
|
-
phoneNumber?: string;
|
|
10
|
-
|
|
11
|
-
constructor(widget: Widget, userData?: Record<string, any>) {
|
|
12
|
-
this.widget = widget;
|
|
13
|
-
this.initializeUniqueId();
|
|
14
|
-
this.updateUserData(userData);
|
|
15
|
-
this.initializePhoneNumber();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
initializePhoneNumber() {
|
|
19
|
-
const savedPhoneNumber = localStorage.getItem(`modo-chat:${this.widget.publicKey}-user-phone-number`);
|
|
20
|
-
if (savedPhoneNumber) {
|
|
21
|
-
this.phoneNumber = savedPhoneNumber;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Initialize unique ID from localStorage or generate a new one
|
|
27
|
-
* Unique ID is independent of user key/data and is generated by ourselves
|
|
28
|
-
*/
|
|
29
|
-
private initializeUniqueId(): void {
|
|
30
|
-
const savedUniqueId = localStorage.getItem(`modo-chat:${this.widget.publicKey}-user-unique-id`);
|
|
31
|
-
|
|
32
|
-
if (savedUniqueId) {
|
|
33
|
-
this._uniqueId = savedUniqueId;
|
|
34
|
-
} else {
|
|
35
|
-
// Generate a new UUID if no saved unique ID exists
|
|
36
|
-
this._uniqueId = crypto.randomUUID ? crypto.randomUUID() : generateUUID();
|
|
37
|
-
localStorage.setItem(`modo-chat:${this.widget.publicKey}-user-unique-id`, this._uniqueId);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Get the current unique ID
|
|
43
|
-
*/
|
|
44
|
-
get uniqueId(): string {
|
|
45
|
-
return this._uniqueId!;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Get the current user data
|
|
50
|
-
*/
|
|
51
|
-
get userData(): Record<string, any> {
|
|
52
|
-
return this._userData || {};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Update user data with new values
|
|
57
|
-
* @param newUserData - Object containing new user data to merge
|
|
58
|
-
*/
|
|
59
|
-
async updateUserData(newUserData?: Record<string, any>): Promise<void> {
|
|
60
|
-
if (newUserData && typeof newUserData === "object") {
|
|
61
|
-
this._userData = newUserData;
|
|
62
|
-
} else if (newUserData) console.warn("Invalid user data");
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
hasSubmittedPhoneForm(): boolean {
|
|
66
|
-
return Boolean(this.phoneNumber);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
savePhoneNumber(phoneNumber?: string) {
|
|
70
|
-
this.phoneNumber = phoneNumber || "no phone number";
|
|
71
|
-
localStorage.setItem(`modo-chat:${this.widget.publicKey}-user-phone-number`, phoneNumber || "no phone number");
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async fetchUpdate() {
|
|
75
|
-
await fetchUpdateUserData(this.widget.chatbot?.uuid as string, this.uniqueId, this.userData);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
export {CustomerData};
|
|
1
|
+
import {Widget} from "#src/app.js";
|
|
2
|
+
import {fetchUpdateUserData} from "#src/utils/fetch.js";
|
|
3
|
+
import {generateUUID} from "#src/utils/uuid.js";
|
|
4
|
+
|
|
5
|
+
class CustomerData {
|
|
6
|
+
private _uniqueId?: string;
|
|
7
|
+
private _userData?: Record<string, any>;
|
|
8
|
+
private widget: Widget;
|
|
9
|
+
phoneNumber?: string;
|
|
10
|
+
|
|
11
|
+
constructor(widget: Widget, userData?: Record<string, any>) {
|
|
12
|
+
this.widget = widget;
|
|
13
|
+
this.initializeUniqueId();
|
|
14
|
+
this.updateUserData(userData);
|
|
15
|
+
this.initializePhoneNumber();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
initializePhoneNumber() {
|
|
19
|
+
const savedPhoneNumber = localStorage.getItem(`modo-chat:${this.widget.publicKey}-user-phone-number`);
|
|
20
|
+
if (savedPhoneNumber) {
|
|
21
|
+
this.phoneNumber = savedPhoneNumber;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Initialize unique ID from localStorage or generate a new one
|
|
27
|
+
* Unique ID is independent of user key/data and is generated by ourselves
|
|
28
|
+
*/
|
|
29
|
+
private initializeUniqueId(): void {
|
|
30
|
+
const savedUniqueId = localStorage.getItem(`modo-chat:${this.widget.publicKey}-user-unique-id`);
|
|
31
|
+
|
|
32
|
+
if (savedUniqueId) {
|
|
33
|
+
this._uniqueId = savedUniqueId;
|
|
34
|
+
} else {
|
|
35
|
+
// Generate a new UUID if no saved unique ID exists
|
|
36
|
+
this._uniqueId = crypto.randomUUID ? crypto.randomUUID() : generateUUID();
|
|
37
|
+
localStorage.setItem(`modo-chat:${this.widget.publicKey}-user-unique-id`, this._uniqueId);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Get the current unique ID
|
|
43
|
+
*/
|
|
44
|
+
get uniqueId(): string {
|
|
45
|
+
return this._uniqueId!;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get the current user data
|
|
50
|
+
*/
|
|
51
|
+
get userData(): Record<string, any> {
|
|
52
|
+
return this._userData || {};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Update user data with new values
|
|
57
|
+
* @param newUserData - Object containing new user data to merge
|
|
58
|
+
*/
|
|
59
|
+
async updateUserData(newUserData?: Record<string, any>): Promise<void> {
|
|
60
|
+
if (newUserData && typeof newUserData === "object") {
|
|
61
|
+
this._userData = newUserData;
|
|
62
|
+
} else if (newUserData) console.warn("Invalid user data");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
hasSubmittedPhoneForm(): boolean {
|
|
66
|
+
return Boolean(this.phoneNumber);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
savePhoneNumber(phoneNumber?: string) {
|
|
70
|
+
this.phoneNumber = phoneNumber || "no phone number";
|
|
71
|
+
localStorage.setItem(`modo-chat:${this.widget.publicKey}-user-phone-number`, phoneNumber || "no phone number");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async fetchUpdate() {
|
|
75
|
+
await fetchUpdateUserData(this.widget.chatbot?.uuid as string, this.uniqueId, this.userData);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export {CustomerData};
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
-
import {VoiceClient, EventType} from "@modochats/voice-client";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
initVoiceChatLayout,
|
|
5
|
-
handleVoiceConnected,
|
|
6
|
-
handleVoiceDisconnected,
|
|
7
|
-
handleVoiceConnectionError,
|
|
8
|
-
handleMicrophonePaused,
|
|
9
|
-
handleMicrophoneResumed
|
|
10
|
-
} from "./utils.js";
|
|
11
|
-
|
|
12
|
-
class VoiceChat {
|
|
13
|
-
instance?: VoiceClient;
|
|
14
|
-
isFirstInSession: boolean = true;
|
|
15
|
-
constructor() {
|
|
16
|
-
const widget = window.getMWidget?.();
|
|
17
|
-
this.instance = new VoiceClient({
|
|
18
|
-
apiBase: "https://live.modochats.com",
|
|
19
|
-
// apiBase: "http://localhost:8000",
|
|
20
|
-
chatbotUuid: widget?.chatbot?.uuid as string,
|
|
21
|
-
userUniqueId: widget?.customerData.uniqueId as string
|
|
22
|
-
});
|
|
23
|
-
this.instance.on(EventType.CONNECTED, (event: any) => {
|
|
24
|
-
handleVoiceConnected();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
this.instance.on(EventType.DISCONNECTED, (event: any) => {
|
|
28
|
-
if (event.reason) {
|
|
29
|
-
}
|
|
30
|
-
handleVoiceDisconnected(event.reason);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
this.instance.on(EventType.CONNECTION_ERROR, (event: any) => {
|
|
34
|
-
// console.error("🔴 Connection Error:", event.message);
|
|
35
|
-
handleVoiceConnectionError(event.message);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
this.instance.on(EventType.MICROPHONE_PAUSED, () => {
|
|
39
|
-
handleMicrophonePaused();
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
this.instance.on(EventType.MICROPHONE_RESUMED, () => {
|
|
43
|
-
handleMicrophoneResumed();
|
|
44
|
-
});
|
|
45
|
-
// Initialize the voice agent UI
|
|
46
|
-
this.initHtml();
|
|
47
|
-
|
|
48
|
-
// session check
|
|
49
|
-
const hasSeen = sessionStorage.getItem("modochats:voice-agent-seen") === "true";
|
|
50
|
-
if (hasSeen) this.isFirstInSession = false;
|
|
51
|
-
else sessionStorage.setItem("modochats:voice-agent-seen", "true");
|
|
52
|
-
if (this.isFirstInSession) this.showTooltip();
|
|
53
|
-
}
|
|
54
|
-
async connect() {
|
|
55
|
-
try {
|
|
56
|
-
await this.instance?.connect();
|
|
57
|
-
} catch (error) {
|
|
58
|
-
// console.error("Failed to connect:", error);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
async disconnect() {
|
|
62
|
-
await this.instance?.disconnect();
|
|
63
|
-
}
|
|
64
|
-
initHtml() {
|
|
65
|
-
initVoiceChatLayout();
|
|
66
|
-
}
|
|
67
|
-
toggleLayout() {
|
|
68
|
-
this.toggleLayout();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
showTooltip() {
|
|
72
|
-
const tooltip = document.querySelector(".mw-voice-call-tooltip");
|
|
73
|
-
tooltip?.classList.remove("mw-hidden");
|
|
74
|
-
setTimeout(() => {
|
|
75
|
-
tooltip?.classList.add("mw-hidden");
|
|
76
|
-
}, 6000);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
export {VoiceChat};
|
|
1
|
+
import {VoiceClient, EventType} from "@modochats/voice-client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
initVoiceChatLayout,
|
|
5
|
+
handleVoiceConnected,
|
|
6
|
+
handleVoiceDisconnected,
|
|
7
|
+
handleVoiceConnectionError,
|
|
8
|
+
handleMicrophonePaused,
|
|
9
|
+
handleMicrophoneResumed
|
|
10
|
+
} from "./utils.js";
|
|
11
|
+
|
|
12
|
+
class VoiceChat {
|
|
13
|
+
instance?: VoiceClient;
|
|
14
|
+
isFirstInSession: boolean = true;
|
|
15
|
+
constructor() {
|
|
16
|
+
const widget = window.getMWidget?.();
|
|
17
|
+
this.instance = new VoiceClient({
|
|
18
|
+
apiBase: "https://live.modochats.com",
|
|
19
|
+
// apiBase: "http://localhost:8000",
|
|
20
|
+
chatbotUuid: widget?.chatbot?.uuid as string,
|
|
21
|
+
userUniqueId: widget?.customerData.uniqueId as string
|
|
22
|
+
});
|
|
23
|
+
this.instance.on(EventType.CONNECTED, (event: any) => {
|
|
24
|
+
handleVoiceConnected();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
this.instance.on(EventType.DISCONNECTED, (event: any) => {
|
|
28
|
+
if (event.reason) {
|
|
29
|
+
}
|
|
30
|
+
handleVoiceDisconnected(event.reason);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
this.instance.on(EventType.CONNECTION_ERROR, (event: any) => {
|
|
34
|
+
// console.error("🔴 Connection Error:", event.message);
|
|
35
|
+
handleVoiceConnectionError(event.message);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
this.instance.on(EventType.MICROPHONE_PAUSED, () => {
|
|
39
|
+
handleMicrophonePaused();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
this.instance.on(EventType.MICROPHONE_RESUMED, () => {
|
|
43
|
+
handleMicrophoneResumed();
|
|
44
|
+
});
|
|
45
|
+
// Initialize the voice agent UI
|
|
46
|
+
this.initHtml();
|
|
47
|
+
|
|
48
|
+
// session check
|
|
49
|
+
const hasSeen = sessionStorage.getItem("modochats:voice-agent-seen") === "true";
|
|
50
|
+
if (hasSeen) this.isFirstInSession = false;
|
|
51
|
+
else sessionStorage.setItem("modochats:voice-agent-seen", "true");
|
|
52
|
+
if (this.isFirstInSession) this.showTooltip();
|
|
53
|
+
}
|
|
54
|
+
async connect() {
|
|
55
|
+
try {
|
|
56
|
+
await this.instance?.connect();
|
|
57
|
+
} catch (error) {
|
|
58
|
+
// console.error("Failed to connect:", error);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async disconnect() {
|
|
62
|
+
await this.instance?.disconnect();
|
|
63
|
+
}
|
|
64
|
+
initHtml() {
|
|
65
|
+
initVoiceChatLayout();
|
|
66
|
+
}
|
|
67
|
+
toggleLayout() {
|
|
68
|
+
this.toggleLayout();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
showTooltip() {
|
|
72
|
+
const tooltip = document.querySelector(".mw-voice-call-tooltip");
|
|
73
|
+
tooltip?.classList.remove("mw-hidden");
|
|
74
|
+
setTimeout(() => {
|
|
75
|
+
tooltip?.classList.add("mw-hidden");
|
|
76
|
+
}, 6000);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export {VoiceChat};
|
|
@@ -1,137 +1,137 @@
|
|
|
1
|
-
function toggleVoiceChatLayout() {
|
|
2
|
-
const widget = window.getMWidget?.();
|
|
3
|
-
const voiceOverlay = widget?.container?.querySelector(".mw-voice-agent-overlay");
|
|
4
|
-
|
|
5
|
-
if (voiceOverlay) {
|
|
6
|
-
voiceOverlay.classList.toggle("mw-active");
|
|
7
|
-
voiceOverlay.classList.toggle("mw-hidden");
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function initVoiceChatLayout() {
|
|
12
|
-
const widget = window.getMWidget?.();
|
|
13
|
-
const voiceOverlay = widget?.container?.querySelector(".mw-voice-agent-overlay");
|
|
14
|
-
const voiceCloseBtn = voiceOverlay?.querySelector(".mw-voice-close-btn");
|
|
15
|
-
const voiceDisconnectBtn = voiceOverlay?.querySelector(".mw-voice-disconnect-btn");
|
|
16
|
-
const voiceCallBtn = widget?.container?.querySelector(".mw-voice-call-btn");
|
|
17
|
-
|
|
18
|
-
// Show voice call button
|
|
19
|
-
if (voiceCallBtn) {
|
|
20
|
-
voiceCallBtn.classList.remove("mw-hidden");
|
|
21
|
-
voiceCallBtn.classList.add("mw-visible");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Set logo from chatbot data
|
|
25
|
-
const logoImg = voiceOverlay?.querySelector(".mw-voice-agent-logo") as HTMLImageElement;
|
|
26
|
-
if (logoImg && widget?.chatbot?.image) {
|
|
27
|
-
logoImg.src = widget.chatbot.image;
|
|
28
|
-
logoImg.alt = widget.chatbot.name || "چت بات";
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Set title
|
|
32
|
-
const titleEl = voiceOverlay?.querySelector(".mw-voice-agent-title") as HTMLElement;
|
|
33
|
-
if (titleEl) {
|
|
34
|
-
titleEl.textContent = widget?.chatbot?.name || "تماس صوتی";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Call button click handler
|
|
38
|
-
voiceCallBtn?.addEventListener("click", () => {
|
|
39
|
-
if (voiceOverlay) {
|
|
40
|
-
voiceOverlay.classList.remove("mw-hidden");
|
|
41
|
-
voiceOverlay.classList.add("mw-active");
|
|
42
|
-
// Connect to voice instance
|
|
43
|
-
widget?.voiceChat?.connect();
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
// Close button click handler
|
|
48
|
-
voiceCloseBtn?.addEventListener("click", () => {
|
|
49
|
-
if (voiceOverlay) {
|
|
50
|
-
voiceOverlay.classList.remove("mw-active");
|
|
51
|
-
voiceOverlay.classList.add("mw-hidden");
|
|
52
|
-
// Disconnect from voice instance
|
|
53
|
-
widget?.voiceChat?.disconnect();
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// Disconnect button click handler
|
|
58
|
-
voiceDisconnectBtn?.addEventListener("click", () => {
|
|
59
|
-
if (voiceOverlay) {
|
|
60
|
-
voiceOverlay.classList.remove("mw-active");
|
|
61
|
-
voiceOverlay.classList.add("mw-hidden");
|
|
62
|
-
// Disconnect from voice instance
|
|
63
|
-
widget?.voiceChat?.disconnect();
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function updateVoiceChatStatus(status: string, color?: string) {
|
|
69
|
-
const widget = window.getMWidget?.();
|
|
70
|
-
const statusEl = widget?.container?.querySelector(".mw-voice-agent-status") as HTMLElement;
|
|
71
|
-
|
|
72
|
-
if (statusEl) {
|
|
73
|
-
statusEl.textContent = status;
|
|
74
|
-
if (color) {
|
|
75
|
-
statusEl.style.color = color;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function handleVoiceConnected() {
|
|
81
|
-
const widget = window.getMWidget?.();
|
|
82
|
-
const logoEl = widget?.container?.querySelector(".mw-voice-agent-logo") as HTMLElement;
|
|
83
|
-
const statusEl = widget?.container?.querySelector(".mw-voice-agent-status") as HTMLElement;
|
|
84
|
-
|
|
85
|
-
// Add animation classes when connected
|
|
86
|
-
if (logoEl) {
|
|
87
|
-
logoEl.style.animation = "mw-voice-pulse 2s ease-in-out infinite";
|
|
88
|
-
}
|
|
89
|
-
if (statusEl) {
|
|
90
|
-
statusEl.style.animation = "mw-pulse 1.5s ease-in-out infinite";
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
updateVoiceChatStatus("متصل ✓", "#68d391"); // Green
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function handleVoiceDisconnected(reason?: string) {
|
|
97
|
-
const widget = window.getMWidget?.();
|
|
98
|
-
const logoEl = widget?.container?.querySelector(".mw-voice-agent-logo") as HTMLElement;
|
|
99
|
-
const statusEl = widget?.container?.querySelector(".mw-voice-agent-status") as HTMLElement;
|
|
100
|
-
|
|
101
|
-
// Remove animations when disconnected
|
|
102
|
-
if (logoEl) {
|
|
103
|
-
logoEl.style.animation = "none";
|
|
104
|
-
}
|
|
105
|
-
if (statusEl) {
|
|
106
|
-
statusEl.style.animation = "none";
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const statusText = reason ? `قطع شد: ${reason}` : "قطع شد";
|
|
110
|
-
updateVoiceChatStatus(statusText, "#fc8181"); // Red
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function handleVoiceConnectionError(message: string) {
|
|
114
|
-
updateVoiceChatStatus(`خطا: ${message}`, "#fbb040"); // Warning/Orange
|
|
115
|
-
|
|
116
|
-
// Also show error in console with better visibility
|
|
117
|
-
console.error("🔴 Voice Connection Error:", message);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function handleMicrophonePaused() {
|
|
121
|
-
updateVoiceChatStatus("⏸ میکروفن متوقف شد", "#fbb040"); // Orange
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function handleMicrophoneResumed() {
|
|
125
|
-
updateVoiceChatStatus("🎤 میکروفن فعال", "#68d391"); // Green
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export {
|
|
129
|
-
toggleVoiceChatLayout,
|
|
130
|
-
initVoiceChatLayout,
|
|
131
|
-
updateVoiceChatStatus,
|
|
132
|
-
handleVoiceConnected,
|
|
133
|
-
handleVoiceDisconnected,
|
|
134
|
-
handleVoiceConnectionError,
|
|
135
|
-
handleMicrophonePaused,
|
|
136
|
-
handleMicrophoneResumed
|
|
137
|
-
};
|
|
1
|
+
function toggleVoiceChatLayout() {
|
|
2
|
+
const widget = window.getMWidget?.();
|
|
3
|
+
const voiceOverlay = widget?.container?.querySelector(".mw-voice-agent-overlay");
|
|
4
|
+
|
|
5
|
+
if (voiceOverlay) {
|
|
6
|
+
voiceOverlay.classList.toggle("mw-active");
|
|
7
|
+
voiceOverlay.classList.toggle("mw-hidden");
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function initVoiceChatLayout() {
|
|
12
|
+
const widget = window.getMWidget?.();
|
|
13
|
+
const voiceOverlay = widget?.container?.querySelector(".mw-voice-agent-overlay");
|
|
14
|
+
const voiceCloseBtn = voiceOverlay?.querySelector(".mw-voice-close-btn");
|
|
15
|
+
const voiceDisconnectBtn = voiceOverlay?.querySelector(".mw-voice-disconnect-btn");
|
|
16
|
+
const voiceCallBtn = widget?.container?.querySelector(".mw-voice-call-btn");
|
|
17
|
+
|
|
18
|
+
// Show voice call button
|
|
19
|
+
if (voiceCallBtn) {
|
|
20
|
+
voiceCallBtn.classList.remove("mw-hidden");
|
|
21
|
+
voiceCallBtn.classList.add("mw-visible");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Set logo from chatbot data
|
|
25
|
+
const logoImg = voiceOverlay?.querySelector(".mw-voice-agent-logo") as HTMLImageElement;
|
|
26
|
+
if (logoImg && widget?.chatbot?.image) {
|
|
27
|
+
logoImg.src = widget.chatbot.image;
|
|
28
|
+
logoImg.alt = widget.chatbot.name || "چت بات";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Set title
|
|
32
|
+
const titleEl = voiceOverlay?.querySelector(".mw-voice-agent-title") as HTMLElement;
|
|
33
|
+
if (titleEl) {
|
|
34
|
+
titleEl.textContent = widget?.chatbot?.name || "تماس صوتی";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Call button click handler
|
|
38
|
+
voiceCallBtn?.addEventListener("click", () => {
|
|
39
|
+
if (voiceOverlay) {
|
|
40
|
+
voiceOverlay.classList.remove("mw-hidden");
|
|
41
|
+
voiceOverlay.classList.add("mw-active");
|
|
42
|
+
// Connect to voice instance
|
|
43
|
+
widget?.voiceChat?.connect();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// Close button click handler
|
|
48
|
+
voiceCloseBtn?.addEventListener("click", () => {
|
|
49
|
+
if (voiceOverlay) {
|
|
50
|
+
voiceOverlay.classList.remove("mw-active");
|
|
51
|
+
voiceOverlay.classList.add("mw-hidden");
|
|
52
|
+
// Disconnect from voice instance
|
|
53
|
+
widget?.voiceChat?.disconnect();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Disconnect button click handler
|
|
58
|
+
voiceDisconnectBtn?.addEventListener("click", () => {
|
|
59
|
+
if (voiceOverlay) {
|
|
60
|
+
voiceOverlay.classList.remove("mw-active");
|
|
61
|
+
voiceOverlay.classList.add("mw-hidden");
|
|
62
|
+
// Disconnect from voice instance
|
|
63
|
+
widget?.voiceChat?.disconnect();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function updateVoiceChatStatus(status: string, color?: string) {
|
|
69
|
+
const widget = window.getMWidget?.();
|
|
70
|
+
const statusEl = widget?.container?.querySelector(".mw-voice-agent-status") as HTMLElement;
|
|
71
|
+
|
|
72
|
+
if (statusEl) {
|
|
73
|
+
statusEl.textContent = status;
|
|
74
|
+
if (color) {
|
|
75
|
+
statusEl.style.color = color;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function handleVoiceConnected() {
|
|
81
|
+
const widget = window.getMWidget?.();
|
|
82
|
+
const logoEl = widget?.container?.querySelector(".mw-voice-agent-logo") as HTMLElement;
|
|
83
|
+
const statusEl = widget?.container?.querySelector(".mw-voice-agent-status") as HTMLElement;
|
|
84
|
+
|
|
85
|
+
// Add animation classes when connected
|
|
86
|
+
if (logoEl) {
|
|
87
|
+
logoEl.style.animation = "mw-voice-pulse 2s ease-in-out infinite";
|
|
88
|
+
}
|
|
89
|
+
if (statusEl) {
|
|
90
|
+
statusEl.style.animation = "mw-pulse 1.5s ease-in-out infinite";
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
updateVoiceChatStatus("متصل ✓", "#68d391"); // Green
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function handleVoiceDisconnected(reason?: string) {
|
|
97
|
+
const widget = window.getMWidget?.();
|
|
98
|
+
const logoEl = widget?.container?.querySelector(".mw-voice-agent-logo") as HTMLElement;
|
|
99
|
+
const statusEl = widget?.container?.querySelector(".mw-voice-agent-status") as HTMLElement;
|
|
100
|
+
|
|
101
|
+
// Remove animations when disconnected
|
|
102
|
+
if (logoEl) {
|
|
103
|
+
logoEl.style.animation = "none";
|
|
104
|
+
}
|
|
105
|
+
if (statusEl) {
|
|
106
|
+
statusEl.style.animation = "none";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const statusText = reason ? `قطع شد: ${reason}` : "قطع شد";
|
|
110
|
+
updateVoiceChatStatus(statusText, "#fc8181"); // Red
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function handleVoiceConnectionError(message: string) {
|
|
114
|
+
updateVoiceChatStatus(`خطا: ${message}`, "#fbb040"); // Warning/Orange
|
|
115
|
+
|
|
116
|
+
// Also show error in console with better visibility
|
|
117
|
+
console.error("🔴 Voice Connection Error:", message);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function handleMicrophonePaused() {
|
|
121
|
+
updateVoiceChatStatus("⏸ میکروفن متوقف شد", "#fbb040"); // Orange
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function handleMicrophoneResumed() {
|
|
125
|
+
updateVoiceChatStatus("🎤 میکروفن فعال", "#68d391"); // Green
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
toggleVoiceChatLayout,
|
|
130
|
+
initVoiceChatLayout,
|
|
131
|
+
updateVoiceChatStatus,
|
|
132
|
+
handleVoiceConnected,
|
|
133
|
+
handleVoiceDisconnected,
|
|
134
|
+
handleVoiceConnectionError,
|
|
135
|
+
handleMicrophonePaused,
|
|
136
|
+
handleMicrophoneResumed
|
|
137
|
+
};
|
package/src/tools/fetch.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {BASE_API_URL} from "#src/constants/index.js";
|
|
2
|
-
import {ofetch} from "ofetch";
|
|
3
|
-
|
|
4
|
-
const $fetch = ofetch.create({
|
|
5
|
-
baseURL: BASE_API_URL
|
|
6
|
-
});
|
|
7
|
-
export {$fetch};
|
|
1
|
+
import {BASE_API_URL} from "#src/constants/index.js";
|
|
2
|
+
import {ofetch} from "ofetch";
|
|
3
|
+
|
|
4
|
+
const $fetch = ofetch.create({
|
|
5
|
+
baseURL: BASE_API_URL
|
|
6
|
+
});
|
|
7
|
+
export {$fetch};
|
package/src/types/app.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
interface WidgetOptions {
|
|
2
|
-
position: "left" | "right";
|
|
3
|
-
theme: "dark" | "light";
|
|
4
|
-
primaryColor: string;
|
|
5
|
-
title: string;
|
|
6
|
-
foregroundColor: string;
|
|
7
|
-
userData?: Record<string, any>;
|
|
8
|
-
autoInit?: boolean;
|
|
9
|
-
fullScreen: boolean;
|
|
10
|
-
}
|
|
11
|
-
interface FetchPaginationRes<T = any> {
|
|
12
|
-
results: T[];
|
|
13
|
-
next: string | null;
|
|
14
|
-
prev: string | null;
|
|
15
|
-
count: number;
|
|
16
|
-
}
|
|
17
|
-
export {WidgetOptions, FetchPaginationRes};
|
|
1
|
+
interface WidgetOptions {
|
|
2
|
+
position: "left" | "right";
|
|
3
|
+
theme: "dark" | "light";
|
|
4
|
+
primaryColor: string;
|
|
5
|
+
title: string;
|
|
6
|
+
foregroundColor: string;
|
|
7
|
+
userData?: Record<string, any>;
|
|
8
|
+
autoInit?: boolean;
|
|
9
|
+
fullScreen: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface FetchPaginationRes<T = any> {
|
|
12
|
+
results: T[];
|
|
13
|
+
next: string | null;
|
|
14
|
+
prev: string | null;
|
|
15
|
+
count: number;
|
|
16
|
+
}
|
|
17
|
+
export {WidgetOptions, FetchPaginationRes};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
enum ConversationStatus {
|
|
2
|
-
AI_CHAT,
|
|
3
|
-
SUPPORTER_CHAT,
|
|
4
|
-
RESOLVED,
|
|
5
|
-
UNKNOWN
|
|
6
|
-
}
|
|
7
|
-
enum MessageType {
|
|
8
|
-
USER,
|
|
9
|
-
AI,
|
|
10
|
-
SUPPORTER,
|
|
11
|
-
SYSTEM,
|
|
12
|
-
UNKNOWN
|
|
13
|
-
}
|
|
14
|
-
export type {ConversationStatus, MessageType};
|
|
1
|
+
enum ConversationStatus {
|
|
2
|
+
AI_CHAT,
|
|
3
|
+
SUPPORTER_CHAT,
|
|
4
|
+
RESOLVED,
|
|
5
|
+
UNKNOWN
|
|
6
|
+
}
|
|
7
|
+
enum MessageType {
|
|
8
|
+
USER,
|
|
9
|
+
AI,
|
|
10
|
+
SUPPORTER,
|
|
11
|
+
SYSTEM,
|
|
12
|
+
UNKNOWN
|
|
13
|
+
}
|
|
14
|
+
export type {ConversationStatus, MessageType};
|