@modochats/widget 0.1.0 → 0.1.1

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.
Files changed (94) hide show
  1. package/dist/src/models/conversation.js +1 -1
  2. package/dist/src/types/app.js +1 -0
  3. package/package.json +1 -1
  4. package/temp/app.dev.js +5101 -0
  5. package/temp/app.dev.js.map +1 -0
  6. package/temp/app.js +3570 -0
  7. package/.vscode/settings.json +0 -3
  8. package/dist/types/src/app.d.ts +0 -30
  9. package/dist/types/src/app.d.ts.map +0 -1
  10. package/dist/types/src/constants/index.d.ts +0 -10
  11. package/dist/types/src/constants/index.d.ts.map +0 -1
  12. package/dist/types/src/constants/regex.d.ts +0 -3
  13. package/dist/types/src/constants/regex.d.ts.map +0 -1
  14. package/dist/types/src/index.d.ts +0 -10
  15. package/dist/types/src/index.d.ts.map +0 -1
  16. package/dist/types/src/models/chatbot.d.ts +0 -24
  17. package/dist/types/src/models/chatbot.d.ts.map +0 -1
  18. package/dist/types/src/models/conversation.d.ts +0 -23
  19. package/dist/types/src/models/conversation.d.ts.map +0 -1
  20. package/dist/types/src/models/customer-data.d.ts +0 -32
  21. package/dist/types/src/models/customer-data.d.ts.map +0 -1
  22. package/dist/types/src/models/message-utils.d.ts +0 -13
  23. package/dist/types/src/models/message-utils.d.ts.map +0 -1
  24. package/dist/types/src/services/chat/conversation.d.ts +0 -23
  25. package/dist/types/src/services/chat/conversation.d.ts.map +0 -1
  26. package/dist/types/src/services/chat/message-utils.d.ts +0 -13
  27. package/dist/types/src/services/chat/message-utils.d.ts.map +0 -1
  28. package/dist/types/src/services/chat/model.d.ts +0 -28
  29. package/dist/types/src/services/chat/model.d.ts.map +0 -1
  30. package/dist/types/src/services/chatbot/chatbot.d.ts +0 -24
  31. package/dist/types/src/services/chatbot/chatbot.d.ts.map +0 -1
  32. package/dist/types/src/services/checker.d.ts +0 -4
  33. package/dist/types/src/services/checker.d.ts.map +0 -1
  34. package/dist/types/src/services/listeners/adders.d.ts +0 -4
  35. package/dist/types/src/services/listeners/adders.d.ts.map +0 -1
  36. package/dist/types/src/services/listeners/fn.d.ts +0 -4
  37. package/dist/types/src/services/listeners/fn.d.ts.map +0 -1
  38. package/dist/types/src/services/socket/utils.d.ts +0 -3
  39. package/dist/types/src/services/socket/utils.d.ts.map +0 -1
  40. package/dist/types/src/services/ui/fn.d.ts +0 -14
  41. package/dist/types/src/services/ui/fn.d.ts.map +0 -1
  42. package/dist/types/src/services/ui/html.d.ts +0 -4
  43. package/dist/types/src/services/ui/html.d.ts.map +0 -1
  44. package/dist/types/src/services/user/customer-data.d.ts +0 -32
  45. package/dist/types/src/services/user/customer-data.d.ts.map +0 -1
  46. package/dist/types/src/services/voice-chat/model.d.ts +0 -13
  47. package/dist/types/src/services/voice-chat/model.d.ts.map +0 -1
  48. package/dist/types/src/services/voice-chat/utils.d.ts +0 -10
  49. package/dist/types/src/services/voice-chat/utils.d.ts.map +0 -1
  50. package/dist/types/src/tools/fetch.d.ts +0 -3
  51. package/dist/types/src/tools/fetch.d.ts.map +0 -1
  52. package/dist/types/src/types/app.d.ts +0 -18
  53. package/dist/types/src/types/app.d.ts.map +0 -1
  54. package/dist/types/src/types/conversation.d.ts +0 -15
  55. package/dist/types/src/types/conversation.d.ts.map +0 -1
  56. package/dist/types/src/types/socket.d.ts +0 -7
  57. package/dist/types/src/types/socket.d.ts.map +0 -1
  58. package/dist/types/src/types/window.d.ts +0 -10
  59. package/dist/types/src/types/window.d.ts.map +0 -1
  60. package/dist/types/src/utils/audio.d.ts +0 -4
  61. package/dist/types/src/utils/audio.d.ts.map +0 -1
  62. package/dist/types/src/utils/browser.d.ts +0 -3
  63. package/dist/types/src/utils/browser.d.ts.map +0 -1
  64. package/dist/types/src/utils/fetch.d.ts +0 -19
  65. package/dist/types/src/utils/fetch.d.ts.map +0 -1
  66. package/dist/types/src/utils/uuid.d.ts +0 -7
  67. package/dist/types/src/utils/uuid.d.ts.map +0 -1
  68. package/src/app.ts +0 -117
  69. package/src/constants/index.ts +0 -21
  70. package/src/constants/regex.ts +0 -2
  71. package/src/index.ts +0 -16
  72. package/src/services/chat/conversation.ts +0 -135
  73. package/src/services/chat/message-utils.ts +0 -221
  74. package/src/services/chat/model.ts +0 -139
  75. package/src/services/chatbot/chatbot.ts +0 -66
  76. package/src/services/checker.ts +0 -10
  77. package/src/services/listeners/adders.ts +0 -178
  78. package/src/services/listeners/fn.ts +0 -77
  79. package/src/services/socket/utils.ts +0 -9
  80. package/src/services/ui/fn.ts +0 -254
  81. package/src/services/ui/html.ts +0 -192
  82. package/src/services/user/customer-data.ts +0 -78
  83. package/src/services/voice-chat/model.ts +0 -79
  84. package/src/services/voice-chat/utils.ts +0 -137
  85. package/src/tools/fetch.ts +0 -7
  86. package/src/types/app.ts +0 -17
  87. package/src/types/conversation.ts +0 -14
  88. package/src/types/socket.ts +0 -7
  89. package/src/types/window.ts +0 -12
  90. package/src/utils/audio.ts +0 -67
  91. package/src/utils/browser.ts +0 -4
  92. package/src/utils/fetch.ts +0 -98
  93. package/src/utils/uuid.ts +0 -13
  94. package/tsconfig.json +0 -119
@@ -1,192 +0,0 @@
1
- import {Widget} from "#src/app.js";
2
- import {registerListeners} from "../listeners/adders.js";
3
-
4
- const createChatContainer = (widget: Widget) => {
5
- widget.container = document.createElement("div");
6
- widget.container.textContent = "Start Chat";
7
- widget.container.classList.add("modo-widget");
8
-
9
- // Add fullscreen class if fullscreen mode is enabled
10
- if (widget.options.fullScreen) {
11
- widget.container.classList.add("mw-fullscreen");
12
- }
13
-
14
- document.body.appendChild(widget.container);
15
- let conBody = document.createElement("div");
16
- widget.container.appendChild(conBody);
17
- widget.container.innerHTML = `
18
- <div dir="rtl" class="mw-chat-inner">
19
- <div class="mw-chat-body ${widget.options.fullScreen ? "mw-active" : "mw-hidden"}">
20
- <div class="mw-chat-container">
21
- <!-- Chat Header -->
22
- <div class="mw-chat-header">
23
- <div style="display: flex; align-items: center; gap: 8px;">
24
- <h3 class="mw-chat-title">پشتیبانی چت</h3>
25
- <div class="mw-conversation-status-icon mw-hidden">
26
- <!-- Clean AI/Bot icon -->
27
- <svg class="mw-ai-chat-icon" style="width: 14px; height: 14px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><!-- Icon from Material Design Icons by Pictogrammers - https://github.com/Templarian/MaterialDesign/blob/master/LICENSE --><path fill="currentColor" d="M22 14h-1c0-3.87-3.13-7-7-7h-1V5.73A2 2 0 1 0 10 4c0 .74.4 1.39 1 1.73V7h-1c-3.87 0-7 3.13-7 7H2c-.55 0-1 .45-1 1v3c0 .55.45 1 1 1h1v1a2 2 0 0 0 2 2h14c1.11 0 2-.89 2-2v-1h1c.55 0 1-.45 1-1v-3c0-.55-.45-1-1-1m-1 3h-2v3H5v-3H3v-1h2v-2c0-2.76 2.24-5 5-5h4c2.76 0 5 2.24 5 5v2h2zM8.5 13.5l2.36 2.36l-1.18 1.18l-1.18-1.18l-1.18 1.18l-1.18-1.18zm7 0l2.36 2.36l-1.18 1.18l-1.18-1.18l-1.18 1.18l-1.18-1.18z"/></svg>
28
- <!-- Clean Human/Person icon -->
29
- <svg class="mw-human-chat-icon" viewBox="0 0 24 24" width="18" height="18">
30
- <path fill="currentColor" d="M12 4C13.66 4 15 5.34 15 7C15 8.66 13.66 10 12 10C10.34 10 9 8.66 9 7C9 5.34 10.34 4 12 4ZM12 12C15.31 12 18 13.34 18 15V18H6V15C6 13.34 8.69 12 12 12Z"/>
31
- </svg>
32
- <div class="mw-tooltip">
33
- <span class="mw-tooltip-text-ai">چت بات هوشمند</span>
34
- <span class="mw-tooltip-text-human">پشتیبان انسانی</span>
35
- </div>
36
- </div>
37
- <div class="mw-connection-status mw-disconnected"></div>
38
- </div>
39
- <div style="display: flex; align-items: center; gap: 8px;">
40
- <button class="mw-new-conversation-btn mw-hidden">
41
- +
42
- </button>
43
- <button class="mw-voice-call-btn mw-hidden">
44
- <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Google Material Icons by Material Design Authors - https://github.com/material-icons/material-icons/blob/master/LICENSE --><path fill="currentColor" d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24c1.12.37 2.33.57 3.57.57c.55 0 1 .45 1 1V20c0 .55-.45 1-1 1c-9.39 0-17-7.61-17-17c0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1c0 1.25.2 2.45.57 3.57c.11.35.03.74-.25 1.02z"/></svg>
45
- <div class="mw-voice-call-tooltip mw-hidden">
46
- <div class="mw-voice-call-tooltip-text">مکالمه با هوش مصنوعی</div>
47
- </div>
48
- </button>
49
- </div>
50
- </div>
51
-
52
- <div class="mw-chat-messages-con">
53
- </div>
54
- <div class="mw-starters-con">
55
- <div class="mw-starter-welcome">
56
- <img class="mw-starter-logo" src="" alt="لوگو چت بات" style="display: none;">
57
- <h2 class="mw-starter-title">پشتیبانی چت</h2>
58
- </div>
59
- <div class="mw-starter-items">
60
- </div>
61
- </div>
62
-
63
- <div class="mw-reply-preview mw-hidden">
64
- <div class="mw-reply-preview-content">
65
- <div class="mw-reply-preview-info">
66
- <span class="mw-reply-preview-label">پاسخ به:</span>
67
- <span class="mw-reply-preview-text"></span>
68
- </div>
69
- <button class="mw-reply-preview-close" title="لغو پاسخ">
70
- <svg viewBox="0 0 24 24" width="16" height="16">
71
- <path fill="currentColor" d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z"/>
72
- </svg>
73
- </button>
74
- </div>
75
- </div>
76
-
77
- <div class="mw-chat-input-area">
78
- <input type="text" placeholder="پیام خود را تایپ کنید..." class="mw-chat-input">
79
- <button class="mw-file-upload-btn" title="آپلود فایل">
80
- <input type="file" class="mw-file-input" hidden />
81
- <svg class="mw-file-upload-icon" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols Light by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M16.346 11.385V6.769h1v4.616zm-5.538 5.457q-.452-.269-.726-.734q-.274-.466-.274-1.031V6.769h1zM11.96 21q-2.271 0-3.846-1.595t-1.575-3.867v-8.73q0-1.587 1.09-2.697Q8.722 3 10.309 3t2.678 1.11t1.091 2.698V14h-1V6.789q-.006-1.166-.802-1.977T10.308 4q-1.163 0-1.966.821q-.804.821-.804 1.987v8.73q-.005 1.853 1.283 3.157Q10.11 20 11.961 20q.556 0 1.056-.124t.945-.372v1.11q-.468.2-.972.293q-.505.093-1.03.093m4.386-1v-2.616h-2.615v-1h2.615V13.77h1v2.615h2.616v1h-2.616V20z"/></svg>
82
- <svg class="mw-file-remove-icon mw-hidden" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><!-- Icon from Material Symbols Light by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><path fill="currentColor" d="M11.962 21q-2.273 0-3.848-1.594t-1.575-3.867V7.954L2.091 3.508L2.8 2.8l18.4 18.4l-.708.708l-3.805-3.806q-.664 1.298-1.913 2.098t-2.812.8M7.539 8.954v6.584q-.006 1.852 1.282 3.157T11.961 20q1.356 0 2.413-.727t1.574-1.91l-1.98-1.98q-.087.742-.656 1.295q-.568.553-1.35.553q-.881 0-1.518-.627q-.636-.627-.636-1.527v-3.854zm3.269 3.269v2.854q0 .479.328.816q.328.338.806.338q.474 0 .801-.335t.334-.808v-.596zm5.538 1.33V6.77h1v7.804zm-3.269-3.307V6.79q-.006-1.166-.805-1.977T10.308 4q-.708 0-1.281.32q-.573.319-.961.857l-.714-.713q.529-.68 1.285-1.072T10.307 3q1.587 0 2.679 1.11t1.091 2.698v4.458zm-2.27-3.477v1.189l-1-1.02V6.77z"/></svg>
83
- </button>
84
- <button class="mw-send-message-btn" data-is-loading="false">
85
- <svg class="mw-send-icon" viewBox="0 0 24 24">
86
- <path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
87
- </svg>
88
- <span class="mw-btn-loading">
89
- <svg class="mw-loading-spinner" viewBox="0 0 24 24">
90
- <circle class="mw-spinner-circle" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" fill="none"></circle>
91
- <path class="mw-spinner-path" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
92
- </svg>
93
- </span>
94
- </button>
95
- </div>
96
-
97
- <div class="mw-form-overlay mw-hidden">
98
- <div class="mw-form-content">
99
- <h3 class="mw-form-title">اطلاعات تماس</h3>
100
- <p class="mw-form-subtitle">لطفا برای اطلاع رسانی بهتر پیام ها شماره خود را وارد کنید (اختیاری)</p>
101
- <div class="mw-form-input-area">
102
- <input type="tel" placeholder="شماره تلفن (اختیاری)" class="mw-phone-input">
103
- </div>
104
- <div class="mw-form-buttons">
105
- <button class="mw-form-submit-btn">
106
- ارسال
107
- </button>
108
- <button class="mw-form-cancel-btn">
109
- لغو
110
- </button>
111
- </div>
112
- </div>
113
- </div>
114
-
115
- <!-- Chat Footer -->
116
- <div class="mw-chat-footer">
117
- <span class="mw-footer-text">ساخته شده با </span>
118
- <a href="" class="mw-footer-link" target="_blank" rel="noopener noreferrer" title="">مودوچت</a>
119
- </div>
120
-
121
- <!-- Voice Agent Overlay -->
122
- <div class="mw-voice-agent-overlay mw-hidden">
123
- <div class="mw-voice-agent-content">
124
- <button class="mw-voice-close-btn">
125
- <svg viewBox="0 0 24 24" width="24" height="24">
126
- <path fill="currentColor" d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z"/>
127
- </svg>
128
- </button>
129
-
130
- <div class="mw-voice-agent-center">
131
- <img class="mw-voice-agent-logo" src="" alt="چت بات" />
132
- <h2 class="mw-voice-agent-title">تماس صوتی</h2>
133
- <p class="mw-voice-agent-status">درحال اتصال...</p>
134
- </div>
135
-
136
- <div class="mw-voice-agent-controls">
137
- <button class="mw-voice-disconnect-btn" title="قطع تماس">
138
- <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE --><path fill="currentColor" d="M231.59 90.13C175.44 34 80.56 34 24.41 90.13c-20 20-21.92 49.49-4.69 71.71A16 16 0 0 0 32.35 168a15.8 15.8 0 0 0 5.75-1.08l49-17.37l.29-.11a16 16 0 0 0 9.75-11.73l5.9-29.52a76.52 76.52 0 0 1 49.68-.11l6.21 29.75a16 16 0 0 0 9.72 11.59l.29.11l49 17.39a16 16 0 0 0 18.38-5.06c17.19-22.24 15.26-51.73-4.73-71.73M223.67 152l-.3-.12l-48.82-17.33l-6.21-29.74A16 16 0 0 0 158 93a92.56 92.56 0 0 0-60.34.13a16 16 0 0 0-10.32 12l-5.9 29.51l-48.81 17.22c-.1 0-.17.13-.27.17c-12.33-15.91-11-36.23 3.36-50.58c25-25 58.65-37.53 92.28-37.53s67.27 12.51 92.28 37.53c14.33 14.35 15.72 34.67 3.39 50.55m.32 48a8 8 0 0 1-8 8H40a8 8 0 0 1 0-16h176a8 8 0 0 1 8 8Z"/></svg>
139
- </button>
140
- </div>
141
- </div>
142
- </div>
143
- </div>
144
- </div>
145
- ${
146
- !widget.options.fullScreen
147
- ? `
148
- <button class="mw-toggle-chat-btn">
149
- <img
150
- class="mw-chat-toggle-image"
151
- src=""
152
- alt="شروع گفتگو" />
153
- <svg
154
- class="mw-chat-toggle-close"
155
- viewBox="0 0 24 24"
156
- width="24"
157
- height="24">
158
- <path
159
- fill="currentColor"
160
- d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z" />
161
- </svg>
162
- <!-- Badge for unread messages -->
163
- <div class="mw-badge mw-hidden">
164
- <span class="mw-badge-text">0</span>
165
- </div>
166
- <!-- Tooltip for toggle button -->
167
- <div class="mw-toggle-tooltip mw-hidden">
168
- <div class="mw-tooltip-inner">
169
- <div
170
- class="mw-toggle-tooltip-close"
171
- title="بستن">
172
- <svg
173
- viewBox="0 0 24 24"
174
- width="16"
175
- height="16">
176
- <path
177
- fill="currentColor"
178
- d="M19 6.41L17.59 5L12 10.59L6.41 5L5 6.41L10.59 12L5 17.59L6.41 19L12 13.41L17.59 19L19 17.59L13.41 12L19 6.41Z" />
179
- </svg>
180
- </div>
181
- <span class="mw-toggle-tooltip-text">شروع گفتگو</span>
182
- </div>
183
- </div>
184
- </button>
185
- `
186
- : ""
187
- }
188
- </div>
189
- `;
190
- registerListeners(widget.container);
191
- };
192
- export {createChatContainer};
@@ -1,78 +0,0 @@
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 +0,0 @@
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 +0,0 @@
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,7 +0,0 @@
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 DELETED
@@ -1,17 +0,0 @@
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 +0,0 @@
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,7 +0,0 @@
1
- interface SocketMessage {
2
- type: "new_message" | "ai_response" | "conversation_status_change";
3
- message: any;
4
- status: string;
5
- }
6
-
7
- export type {SocketMessage};
@@ -1,12 +0,0 @@
1
- import {Widget} from "../app.js";
2
-
3
- declare global {
4
- interface Window {
5
- ModoChat: typeof Widget;
6
- ModoWidget: typeof Widget;
7
- getMWidget?: () => Widget;
8
- }
9
- }
10
-
11
- // This is needed to make this file a module
12
- export {};
@@ -1,67 +0,0 @@
1
- // Cache for preloaded audio elements
2
- const audioCache = new Map<string, HTMLAudioElement>();
3
-
4
- const preloadAudio = (audioPath: string): Promise<HTMLAudioElement> => {
5
- return new Promise((resolve, reject) => {
6
- if (audioCache.has(audioPath)) {
7
- resolve(audioCache.get(audioPath)!);
8
- return;
9
- }
10
-
11
- const audioElement = new Audio(audioPath);
12
- audioElement.volume = 0.5;
13
- audioElement.preload = "auto";
14
-
15
- audioElement.addEventListener("canplaythrough", () => {
16
- audioCache.set(audioPath, audioElement);
17
- resolve(audioElement);
18
- });
19
-
20
- audioElement.addEventListener("error", error => {
21
- reject(error);
22
- });
23
-
24
- // Start loading
25
- audioElement.load();
26
- });
27
- };
28
-
29
- const playAudio = async (audioPath: string) => {
30
- try {
31
- // Try to get preloaded audio or create new one
32
- let audioElement = audioCache.get(audioPath);
33
-
34
- if (!audioElement) {
35
- audioElement = new Audio(audioPath);
36
- audioElement.volume = 0.5;
37
- audioElement.preload = "auto";
38
- }
39
-
40
- // Play the audio
41
- await audioElement.play();
42
- } catch (error) {
43
- console.warn("Failed to play audio:", error);
44
- // Fallback: try to play a simple beep sound using Web Audio API
45
- try {
46
- const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)();
47
- const oscillator = audioContext.createOscillator();
48
- const gainNode = audioContext.createGain();
49
-
50
- oscillator.connect(gainNode);
51
- gainNode.connect(audioContext.destination);
52
-
53
- oscillator.frequency.setValueAtTime(800, audioContext.currentTime);
54
- oscillator.type = "sine";
55
-
56
- gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
57
- gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);
58
-
59
- oscillator.start(audioContext.currentTime);
60
- oscillator.stop(audioContext.currentTime + 0.5);
61
- } catch (fallbackError) {
62
- console.warn("Audio fallback also failed:", fallbackError);
63
- }
64
- }
65
- };
66
-
67
- export {playAudio, preloadAudio};
@@ -1,4 +0,0 @@
1
- let getDocumentHead = () => {
2
- return document.getElementsByTagName("HEAD")[0];
3
- };
4
- export {getDocumentHead};