ragged-chat-sdk 1.0.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/README.md +39 -0
- package/index.js +783 -0
- package/package.json +19 -0
- package/ragged-chat-sdk-1.0.0.tgz +0 -0
- package/test-import.js +28 -0
- package/test-simple.js +2 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Ragged Chatbot SDK
|
|
2
|
+
|
|
3
|
+
The official SDK for integrating Ragged Chatbots into your website.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install ragged-chat-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Import the SDK and initialize it with your chatbot's subdomain.
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import { init } from 'ragged-chat-sdk';
|
|
17
|
+
|
|
18
|
+
init({
|
|
19
|
+
subdomain: 'your-chatbot-subdomain'
|
|
20
|
+
});
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Configuration Options
|
|
24
|
+
|
|
25
|
+
| Option | Type | Description |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| `subdomain` | `string` | **Required**. The unique subdomain of your chatbot. |
|
|
28
|
+
| `apiUrl` | `string` | Optional. The base URL of the Ragged API. Defaults to `https://ragflowdb.onrender.com/api`. |
|
|
29
|
+
|
|
30
|
+
## Example
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
import { init } from 'ragged-chat-sdk';
|
|
34
|
+
|
|
35
|
+
// Initialize the chatbot
|
|
36
|
+
init({
|
|
37
|
+
subdomain: 'my-awesome-bot'
|
|
38
|
+
});
|
|
39
|
+
```
|
package/index.js
ADDED
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
export function init(config = {}) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Configuration
|
|
5
|
+
const API_URL = config.apiUrl || 'https://ragflowdb.onrender.com/api';
|
|
6
|
+
const subdomain = config.subdomain;
|
|
7
|
+
|
|
8
|
+
if (!subdomain) {
|
|
9
|
+
console.error('[Ragged SDK] Error: subdomain is required. Usage: Ragged.init({ subdomain: "your-subdomain" })');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// State
|
|
14
|
+
let isOpen = false;
|
|
15
|
+
let initialized = false;
|
|
16
|
+
let chatConfig = null;
|
|
17
|
+
let messages = [];
|
|
18
|
+
let isLoading = false;
|
|
19
|
+
|
|
20
|
+
// Fetch chatbot configuration
|
|
21
|
+
async function fetchConfig() {
|
|
22
|
+
try {
|
|
23
|
+
const response = await fetch(`${API_URL}/chat/${subdomain}/config`);
|
|
24
|
+
chatConfig = await response.json();
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error('[Ragged SDK] Failed to fetch config:', error);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Send message to chatbot
|
|
31
|
+
async function sendMessage(message) {
|
|
32
|
+
try {
|
|
33
|
+
const response = await fetch(`${API_URL}/chat/${subdomain}`, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: { 'Content-Type': 'application/json' },
|
|
36
|
+
body: JSON.stringify({ message, history: messages })
|
|
37
|
+
});
|
|
38
|
+
const data = await response.json();
|
|
39
|
+
return data.response;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
console.error('[Ragged SDK] Failed to send message:', error);
|
|
42
|
+
return "Sorry, I'm having trouble connecting right now.";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Format message content (bold and tables)
|
|
47
|
+
function formatMessage(content) {
|
|
48
|
+
if (!content) return '';
|
|
49
|
+
|
|
50
|
+
let formatted = content;
|
|
51
|
+
|
|
52
|
+
// 1. Bold: **text** -> <strong>text</strong>
|
|
53
|
+
formatted = formatted.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
|
|
54
|
+
|
|
55
|
+
// 2. Tables: | col1 | col2 |
|
|
56
|
+
const lines = formatted.split('\n');
|
|
57
|
+
let inTable = false;
|
|
58
|
+
let tableHTML = '';
|
|
59
|
+
let result = [];
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < lines.length; i++) {
|
|
62
|
+
const line = lines[i].trim();
|
|
63
|
+
if (line.startsWith('|') && line.endsWith('|')) {
|
|
64
|
+
if (!inTable) {
|
|
65
|
+
inTable = true;
|
|
66
|
+
tableHTML = '<div class="ragged-table-container"><table>';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const cells = line.split('|').filter(c => c.trim() !== '' || (line.indexOf('|' + c + '|') !== -1));
|
|
70
|
+
// Handle header/separator
|
|
71
|
+
if (line.includes('---')) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const isHeader = !tableHTML.includes('</thead>') && !tableHTML.includes('<tbody>');
|
|
76
|
+
if (isHeader) {
|
|
77
|
+
tableHTML += '<thead><tr>';
|
|
78
|
+
cells.forEach(cell => {
|
|
79
|
+
tableHTML += `<th>${cell.trim()}</th>`;
|
|
80
|
+
});
|
|
81
|
+
tableHTML += '</tr></thead><tbody>';
|
|
82
|
+
} else {
|
|
83
|
+
tableHTML += '<tr>';
|
|
84
|
+
cells.forEach(cell => {
|
|
85
|
+
tableHTML += `<td>${cell.trim()}</td>`;
|
|
86
|
+
});
|
|
87
|
+
tableHTML += '</tr>';
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
if (inTable) {
|
|
91
|
+
inTable = false;
|
|
92
|
+
tableHTML += '</tbody></table></div>';
|
|
93
|
+
result.push(tableHTML);
|
|
94
|
+
tableHTML = '';
|
|
95
|
+
}
|
|
96
|
+
result.push(line);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (inTable) {
|
|
101
|
+
tableHTML += '</tbody></table></div>';
|
|
102
|
+
result.push(tableHTML);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return result.join('\n');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Create widget HTML
|
|
109
|
+
function createWidget() {
|
|
110
|
+
const container = document.createElement('div');
|
|
111
|
+
container.id = 'ragged-chat-widget';
|
|
112
|
+
container.innerHTML = `
|
|
113
|
+
<style>
|
|
114
|
+
#ragged-chat-widget * {
|
|
115
|
+
box-sizing: border-box;
|
|
116
|
+
margin: 0;
|
|
117
|
+
padding: 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
#ragged-widget-container {
|
|
121
|
+
position: fixed;
|
|
122
|
+
bottom: 24px;
|
|
123
|
+
right: 24px;
|
|
124
|
+
z-index: 999999;
|
|
125
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
126
|
+
display: flex;
|
|
127
|
+
flex-direction: column;
|
|
128
|
+
align-items: flex-end;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
#ragged-chat-window {
|
|
132
|
+
position: fixed;
|
|
133
|
+
bottom: 96px;
|
|
134
|
+
right: 24px;
|
|
135
|
+
width: calc(100% - 48px);
|
|
136
|
+
height: calc(100% - 140px);
|
|
137
|
+
max-width: 380px;
|
|
138
|
+
max-height: 540px;
|
|
139
|
+
background: rgba(9, 9, 11, 0.8);
|
|
140
|
+
backdrop-filter: blur(48px);
|
|
141
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
142
|
+
display: flex;
|
|
143
|
+
flex-direction: column;
|
|
144
|
+
overflow: hidden;
|
|
145
|
+
transition: all 0.3s ease;
|
|
146
|
+
border-radius: 24px;
|
|
147
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.4);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@media (min-width: 640px) {
|
|
151
|
+
#ragged-chat-window {
|
|
152
|
+
position: static;
|
|
153
|
+
width: 380px;
|
|
154
|
+
height: 540px;
|
|
155
|
+
margin-bottom: 20px;
|
|
156
|
+
border-radius: 32px;
|
|
157
|
+
box-shadow: 0 32px 64px -12px rgba(0, 0, 0, 0.6);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
#ragged-chat-header {
|
|
162
|
+
padding: 16px;
|
|
163
|
+
background: white;
|
|
164
|
+
color: black;
|
|
165
|
+
display: flex;
|
|
166
|
+
justify-content: space-between;
|
|
167
|
+
align-items: center;
|
|
168
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
|
169
|
+
flex-shrink: 0;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
@media (min-width: 640px) {
|
|
173
|
+
#ragged-chat-header {
|
|
174
|
+
padding: 24px;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
#ragged-chat-header-left {
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
gap: 16px;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
#ragged-chat-avatar {
|
|
185
|
+
width: 32px;
|
|
186
|
+
height: 32px;
|
|
187
|
+
background: black;
|
|
188
|
+
color: white;
|
|
189
|
+
border-radius: 50%;
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
justify-content: center;
|
|
193
|
+
box-shadow: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
|
|
194
|
+
overflow: hidden;
|
|
195
|
+
flex-shrink: 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
@media (min-width: 640px) {
|
|
199
|
+
#ragged-chat-avatar {
|
|
200
|
+
width: 40px;
|
|
201
|
+
height: 40px;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
#ragged-chat-avatar img {
|
|
206
|
+
width: 100%;
|
|
207
|
+
height: 100%;
|
|
208
|
+
object-fit: cover;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#ragged-chat-title {
|
|
212
|
+
font-weight: 700;
|
|
213
|
+
font-size: 13px;
|
|
214
|
+
letter-spacing: -0.05em;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
@media (min-width: 640px) {
|
|
218
|
+
#ragged-chat-title {
|
|
219
|
+
font-size: 14px;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
#ragged-chat-status {
|
|
224
|
+
font-size: 9px;
|
|
225
|
+
font-weight: 700;
|
|
226
|
+
text-transform: uppercase;
|
|
227
|
+
letter-spacing: 0.1em;
|
|
228
|
+
color: #71717a;
|
|
229
|
+
margin-top: 2px;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
@media (min-width: 640px) {
|
|
233
|
+
#ragged-chat-status {
|
|
234
|
+
font-size: 10px;
|
|
235
|
+
margin-top: 4px;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
#ragged-close-btn {
|
|
240
|
+
background: transparent;
|
|
241
|
+
border: none;
|
|
242
|
+
cursor: pointer;
|
|
243
|
+
padding: 12px;
|
|
244
|
+
border-radius: 50%;
|
|
245
|
+
transition: background 0.2s;
|
|
246
|
+
min-width: 44px;
|
|
247
|
+
min-height: 44px;
|
|
248
|
+
display: flex;
|
|
249
|
+
align-items: center;
|
|
250
|
+
justify-content: center;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
@media (min-width: 640px) {
|
|
254
|
+
#ragged-close-btn {
|
|
255
|
+
padding: 8px;
|
|
256
|
+
min-width: auto;
|
|
257
|
+
min-height: auto;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#ragged-close-btn:hover {
|
|
262
|
+
background: rgba(0, 0, 0, 0.05);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
#ragged-messages {
|
|
266
|
+
flex: 1;
|
|
267
|
+
overflow-y: auto;
|
|
268
|
+
padding: 16px 24px;
|
|
269
|
+
display: flex;
|
|
270
|
+
flex-direction: column;
|
|
271
|
+
gap: 24px;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@media (min-width: 768px) {
|
|
275
|
+
#ragged-messages {
|
|
276
|
+
padding: 24px;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
#ragged-empty-state {
|
|
281
|
+
text-align: center;
|
|
282
|
+
padding: 40px 20px;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
@media (min-width: 640px) {
|
|
286
|
+
#ragged-empty-state {
|
|
287
|
+
padding: 80px 20px;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
#ragged-empty-icon {
|
|
292
|
+
width: 64px;
|
|
293
|
+
height: 64px;
|
|
294
|
+
background: rgba(255, 255, 255, 0.05);
|
|
295
|
+
border-radius: 16px;
|
|
296
|
+
display: flex;
|
|
297
|
+
align-items: center;
|
|
298
|
+
justify-content: center;
|
|
299
|
+
margin: 0 auto 16px;
|
|
300
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
#ragged-empty-title {
|
|
304
|
+
font-size: 18px;
|
|
305
|
+
font-weight: 600;
|
|
306
|
+
color: #e4e4e7;
|
|
307
|
+
margin-bottom: 8px;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
@media (min-width: 640px) {
|
|
311
|
+
#ragged-empty-title {
|
|
312
|
+
font-size: 20px;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
#ragged-empty-text {
|
|
317
|
+
color: #71717a;
|
|
318
|
+
font-size: 14px;
|
|
319
|
+
max-width: 300px;
|
|
320
|
+
margin: 0 auto;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.ragged-message {
|
|
324
|
+
display: flex;
|
|
325
|
+
animation: fadeIn 0.3s ease;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
@keyframes fadeIn {
|
|
329
|
+
from { opacity: 0; transform: translateY(8px); }
|
|
330
|
+
to { opacity: 1; transform: translateY(0); }
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
.ragged-message.user {
|
|
334
|
+
justify-content: flex-end;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.ragged-message-content {
|
|
338
|
+
max-width: 85%;
|
|
339
|
+
padding: 12px 16px;
|
|
340
|
+
border-radius: 16px;
|
|
341
|
+
font-size: 14px;
|
|
342
|
+
line-height: 1.5;
|
|
343
|
+
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.ragged-message-content strong {
|
|
347
|
+
font-weight: 700;
|
|
348
|
+
color: inherit;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.ragged-table-container {
|
|
352
|
+
width: 100%;
|
|
353
|
+
overflow-x: auto;
|
|
354
|
+
margin: 12px 0;
|
|
355
|
+
border-radius: 8px;
|
|
356
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
357
|
+
background: rgba(255, 255, 255, 0.02);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.ragged-message.user .ragged-table-container {
|
|
361
|
+
border-color: rgba(255, 255, 255, 0.2);
|
|
362
|
+
background: rgba(0, 0, 0, 0.1);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
table {
|
|
366
|
+
width: 100%;
|
|
367
|
+
border-collapse: collapse;
|
|
368
|
+
font-size: 11px;
|
|
369
|
+
line-height: 1.4;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
th, td {
|
|
373
|
+
padding: 8px 12px;
|
|
374
|
+
text-align: left;
|
|
375
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
th {
|
|
379
|
+
font-weight: 700;
|
|
380
|
+
color: #a1a1aa;
|
|
381
|
+
background: rgba(255, 255, 255, 0.03);
|
|
382
|
+
text-transform: uppercase;
|
|
383
|
+
letter-spacing: 0.05em;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
tr:last-child td {
|
|
387
|
+
border-bottom: none;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.ragged-message.user td, .ragged-message.user th {
|
|
391
|
+
border-bottom-color: rgba(255, 255, 255, 0.1);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.ragged-message.user .ragged-message-content {
|
|
395
|
+
color: white;
|
|
396
|
+
border-top-right-radius: 4px;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.ragged-message.assistant .ragged-message-content {
|
|
400
|
+
background: rgba(39, 39, 42, 0.8);
|
|
401
|
+
color: #fafafa;
|
|
402
|
+
border-top-left-radius: 4px;
|
|
403
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.ragged-loading {
|
|
407
|
+
display: flex;
|
|
408
|
+
gap: 4px;
|
|
409
|
+
padding: 16px;
|
|
410
|
+
background: rgba(39, 39, 42, 0.8);
|
|
411
|
+
border-radius: 16px;
|
|
412
|
+
border-top-left-radius: 4px;
|
|
413
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
414
|
+
width: fit-content;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.ragged-loading-dot {
|
|
418
|
+
width: 8px;
|
|
419
|
+
height: 8px;
|
|
420
|
+
border-radius: 50%;
|
|
421
|
+
animation: bounce 1.4s infinite ease-in-out both;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.ragged-loading-dot:nth-child(1) { animation-delay: -0.32s; }
|
|
425
|
+
.ragged-loading-dot:nth-child(2) { animation-delay: -0.16s; }
|
|
426
|
+
|
|
427
|
+
@keyframes bounce {
|
|
428
|
+
0%, 80%, 100% { transform: scale(0); }
|
|
429
|
+
40% { transform: scale(1); }
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
#ragged-input-container {
|
|
433
|
+
padding: 16px 24px;
|
|
434
|
+
background: rgba(24, 24, 27, 0.5);
|
|
435
|
+
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
|
436
|
+
flex-shrink: 0;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
@media (min-width: 768px) {
|
|
440
|
+
#ragged-input-container {
|
|
441
|
+
padding: 24px;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
#ragged-input-form {
|
|
446
|
+
display: flex;
|
|
447
|
+
gap: 12px;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
#ragged-input {
|
|
451
|
+
flex: 1;
|
|
452
|
+
background: rgba(39, 39, 42, 0.5);
|
|
453
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
454
|
+
border-radius: 16px;
|
|
455
|
+
padding: 12px 20px;
|
|
456
|
+
font-size: 14px;
|
|
457
|
+
color: white;
|
|
458
|
+
outline: none;
|
|
459
|
+
transition: all 0.2s;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
#ragged-input::placeholder {
|
|
463
|
+
color: #52525b;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
#ragged-input:focus {
|
|
467
|
+
border-color: rgba(59, 130, 246, 0.5);
|
|
468
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
#ragged-send-btn {
|
|
472
|
+
padding: 12px 16px;
|
|
473
|
+
border: none;
|
|
474
|
+
border-radius: 16px;
|
|
475
|
+
font-weight: 500;
|
|
476
|
+
font-size: 14px;
|
|
477
|
+
cursor: pointer;
|
|
478
|
+
transition: all 0.2s;
|
|
479
|
+
display: flex;
|
|
480
|
+
align-items: center;
|
|
481
|
+
gap: 6px;
|
|
482
|
+
color: white;
|
|
483
|
+
min-height: 44px;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
@media (min-width: 640px) {
|
|
487
|
+
#ragged-send-btn {
|
|
488
|
+
padding: 12px 24px;
|
|
489
|
+
gap: 8px;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
#ragged-send-btn:hover {
|
|
494
|
+
transform: scale(1.05);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
#ragged-send-btn:active {
|
|
498
|
+
transform: scale(0.95);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
#ragged-send-btn:disabled {
|
|
502
|
+
opacity: 0.5;
|
|
503
|
+
cursor: not-allowed;
|
|
504
|
+
transform: none;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
#ragged-toggle-btn {
|
|
508
|
+
width: 56px;
|
|
509
|
+
height: 56px;
|
|
510
|
+
border: none;
|
|
511
|
+
border-radius: 50%;
|
|
512
|
+
color: white;
|
|
513
|
+
cursor: pointer;
|
|
514
|
+
display: flex;
|
|
515
|
+
align-items: center;
|
|
516
|
+
justify-content: center;
|
|
517
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
518
|
+
transition: all 0.2s;
|
|
519
|
+
position: relative;
|
|
520
|
+
overflow: hidden;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
#ragged-toggle-btn:hover {
|
|
524
|
+
transform: scale(1.1);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
#ragged-toggle-btn:active {
|
|
528
|
+
transform: scale(0.9);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.ragged-toggle-icon {
|
|
532
|
+
position: absolute;
|
|
533
|
+
transition: all 0.3s;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.ragged-toggle-icon.hidden {
|
|
537
|
+
opacity: 0;
|
|
538
|
+
transform: scale(0);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
#ragged-toggle-logo {
|
|
542
|
+
position: absolute;
|
|
543
|
+
inset: 0;
|
|
544
|
+
transition: all 0.3s;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
#ragged-toggle-logo img {
|
|
548
|
+
width: 100%;
|
|
549
|
+
height: 100%;
|
|
550
|
+
object-fit: cover;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
#ragged-toggle-logo.hidden {
|
|
554
|
+
opacity: 0;
|
|
555
|
+
transform: scale(0);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.ragged-hidden {
|
|
559
|
+
visibility: hidden !important;
|
|
560
|
+
opacity: 0 !important;
|
|
561
|
+
pointer-events: none !important;
|
|
562
|
+
}
|
|
563
|
+
</style>
|
|
564
|
+
|
|
565
|
+
<div id="ragged-widget-container">
|
|
566
|
+
<div id="ragged-chat-window" class="ragged-hidden">
|
|
567
|
+
<div id="ragged-chat-header">
|
|
568
|
+
<div id="ragged-chat-header-left">
|
|
569
|
+
<div id="ragged-chat-avatar">
|
|
570
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
571
|
+
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
|
572
|
+
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
|
573
|
+
</svg>
|
|
574
|
+
</div>
|
|
575
|
+
<div>
|
|
576
|
+
<div id="ragged-chat-title">AI Agent</div>
|
|
577
|
+
<div id="ragged-chat-status">Online</div>
|
|
578
|
+
</div>
|
|
579
|
+
</div>
|
|
580
|
+
<button id="ragged-close-btn">
|
|
581
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
582
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
583
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
584
|
+
</svg>
|
|
585
|
+
</button>
|
|
586
|
+
</div>
|
|
587
|
+
|
|
588
|
+
<div id="ragged-messages">
|
|
589
|
+
<div id="ragged-empty-state">
|
|
590
|
+
<div id="ragged-empty-icon">
|
|
591
|
+
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#71717a" stroke-width="2">
|
|
592
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
593
|
+
</svg>
|
|
594
|
+
</div>
|
|
595
|
+
<div id="ragged-empty-title">How can I help you?</div>
|
|
596
|
+
<div id="ragged-empty-text">Ask anything about our services, products, or pricing. I'm here to help!</div>
|
|
597
|
+
</div>
|
|
598
|
+
</div>
|
|
599
|
+
|
|
600
|
+
<div id="ragged-input-container">
|
|
601
|
+
<form id="ragged-input-form">
|
|
602
|
+
<input
|
|
603
|
+
type="text"
|
|
604
|
+
id="ragged-input"
|
|
605
|
+
placeholder="Type your message here..."
|
|
606
|
+
autocomplete="off"
|
|
607
|
+
/>
|
|
608
|
+
<button type="submit" id="ragged-send-btn">
|
|
609
|
+
<span>Send</span>
|
|
610
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
611
|
+
<line x1="22" y1="2" x2="11" y2="13"></line>
|
|
612
|
+
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
|
|
613
|
+
</svg>
|
|
614
|
+
</button>
|
|
615
|
+
</form>
|
|
616
|
+
</div>
|
|
617
|
+
</div>
|
|
618
|
+
|
|
619
|
+
<button id="ragged-toggle-btn">
|
|
620
|
+
<div id="ragged-toggle-logo" class="hidden"></div>
|
|
621
|
+
<svg class="ragged-toggle-icon" id="ragged-icon-message" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
622
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
623
|
+
</svg>
|
|
624
|
+
<svg class="ragged-toggle-icon hidden" id="ragged-icon-close" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
625
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
626
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
627
|
+
</svg>
|
|
628
|
+
</button>
|
|
629
|
+
</div>
|
|
630
|
+
`;
|
|
631
|
+
|
|
632
|
+
document.body.appendChild(container);
|
|
633
|
+
return container;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// Render messages
|
|
637
|
+
function renderMessages() {
|
|
638
|
+
const messagesContainer = document.getElementById('ragged-messages');
|
|
639
|
+
const emptyState = document.getElementById('ragged-empty-state');
|
|
640
|
+
|
|
641
|
+
if (!messagesContainer) {
|
|
642
|
+
console.error('[Ragged SDK] Messages container not found. Widget might not be fully initialized.');
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (!emptyState) {
|
|
647
|
+
console.warn('[Ragged SDK] Empty state container not found.');
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if (messages.length === 0) {
|
|
651
|
+
if (emptyState) emptyState.classList.remove('ragged-hidden');
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (emptyState) emptyState.classList.add('ragged-hidden');
|
|
656
|
+
|
|
657
|
+
const messagesHTML = messages.map(msg => `
|
|
658
|
+
<div class="ragged-message ${msg.role}">
|
|
659
|
+
<div class="ragged-message-content" style="${msg.role === 'user' ? `background-color: ${chatConfig?.settings?.primaryColor || '#3b82f6'}` : ''}">${formatMessage(msg.content)}</div>
|
|
660
|
+
</div>
|
|
661
|
+
`).join('');
|
|
662
|
+
|
|
663
|
+
const loadingHTML = isLoading ? `
|
|
664
|
+
<div class="ragged-message assistant">
|
|
665
|
+
<div class="ragged-loading">
|
|
666
|
+
<div class="ragged-loading-dot" style="background-color: ${chatConfig?.settings?.primaryColor || '#3b82f6'}"></div>
|
|
667
|
+
<div class="ragged-loading-dot" style="background-color: ${chatConfig?.settings?.primaryColor || '#3b82f6'}"></div>
|
|
668
|
+
<div class="ragged-loading-dot" style="background-color: ${chatConfig?.settings?.primaryColor || '#3b82f6'}"></div>
|
|
669
|
+
</div>
|
|
670
|
+
</div>
|
|
671
|
+
` : '';
|
|
672
|
+
|
|
673
|
+
messagesContainer.innerHTML = messagesHTML + loadingHTML;
|
|
674
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Toggle widget
|
|
678
|
+
function toggleWidget() {
|
|
679
|
+
isOpen = !isOpen;
|
|
680
|
+
const chatWindow = document.getElementById('ragged-chat-window');
|
|
681
|
+
const toggleBtn = document.getElementById('ragged-toggle-btn');
|
|
682
|
+
const iconMessage = document.getElementById('ragged-icon-message');
|
|
683
|
+
const iconClose = document.getElementById('ragged-icon-close');
|
|
684
|
+
const toggleLogo = document.getElementById('ragged-toggle-logo');
|
|
685
|
+
|
|
686
|
+
if (isOpen) {
|
|
687
|
+
chatWindow.classList.remove('ragged-hidden');
|
|
688
|
+
iconMessage.classList.add('hidden');
|
|
689
|
+
iconClose.classList.remove('hidden');
|
|
690
|
+
if (chatConfig?.settings?.brandLogo) {
|
|
691
|
+
toggleLogo.classList.add('hidden');
|
|
692
|
+
}
|
|
693
|
+
toggleBtn.style.backgroundColor = '#000000';
|
|
694
|
+
} else {
|
|
695
|
+
chatWindow.classList.add('ragged-hidden');
|
|
696
|
+
if (!chatConfig?.settings?.brandLogo) {
|
|
697
|
+
iconMessage.classList.remove('hidden');
|
|
698
|
+
}
|
|
699
|
+
iconClose.classList.add('hidden');
|
|
700
|
+
if (chatConfig?.settings?.brandLogo) {
|
|
701
|
+
toggleLogo.classList.remove('hidden');
|
|
702
|
+
}
|
|
703
|
+
toggleBtn.style.backgroundColor = chatConfig?.settings?.primaryColor || '#000000';
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Handle message send
|
|
708
|
+
async function handleSend(e) {
|
|
709
|
+
e.preventDefault();
|
|
710
|
+
|
|
711
|
+
const input = document.getElementById('ragged-input');
|
|
712
|
+
if (!input) {
|
|
713
|
+
console.error('[Ragged SDK] Input element not found');
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const message = input.value.trim();
|
|
718
|
+
|
|
719
|
+
if (!message || isLoading) return;
|
|
720
|
+
|
|
721
|
+
messages.push({ role: 'user', content: message });
|
|
722
|
+
input.value = '';
|
|
723
|
+
isLoading = true;
|
|
724
|
+
renderMessages();
|
|
725
|
+
|
|
726
|
+
const response = await sendMessage(message);
|
|
727
|
+
messages.push({ role: 'assistant', content: response });
|
|
728
|
+
isLoading = false;
|
|
729
|
+
renderMessages();
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Initialize widget
|
|
733
|
+
async function initializeWidget() {
|
|
734
|
+
// Prevent double initialization
|
|
735
|
+
if (initialized) return;
|
|
736
|
+
initialized = true;
|
|
737
|
+
|
|
738
|
+
await fetchConfig();
|
|
739
|
+
|
|
740
|
+
const widget = createWidget();
|
|
741
|
+
|
|
742
|
+
if (chatConfig) {
|
|
743
|
+
const toggleBtn = document.getElementById('ragged-toggle-btn');
|
|
744
|
+
const sendBtn = document.getElementById('ragged-send-btn');
|
|
745
|
+
const chatTitle = document.getElementById('ragged-chat-title');
|
|
746
|
+
const input = document.getElementById('ragged-input');
|
|
747
|
+
const emptyTitle = document.getElementById('ragged-empty-title');
|
|
748
|
+
const avatar = document.getElementById('ragged-chat-avatar');
|
|
749
|
+
const toggleLogo = document.getElementById('ragged-toggle-logo');
|
|
750
|
+
|
|
751
|
+
toggleBtn.style.backgroundColor = chatConfig.settings?.primaryColor || '#000000';
|
|
752
|
+
sendBtn.style.backgroundColor = chatConfig.settings?.primaryColor || '#3b82f6';
|
|
753
|
+
chatTitle.textContent = chatConfig.name || 'AI Agent';
|
|
754
|
+
input.placeholder = chatConfig.settings?.placeholder || 'Type your message here...';
|
|
755
|
+
emptyTitle.textContent = chatConfig.settings?.welcomeMessage || 'How can I help you?';
|
|
756
|
+
|
|
757
|
+
// Set custom logo for all users (free platform)
|
|
758
|
+
if (chatConfig.settings?.brandLogo) {
|
|
759
|
+
const logoUrl = chatConfig.settings.brandLogo;
|
|
760
|
+
if (avatar) {
|
|
761
|
+
avatar.innerHTML = `<img src="${logoUrl}" alt="Logo" style="width:100%; height:100%; object-fit:cover;" />`;
|
|
762
|
+
}
|
|
763
|
+
if (toggleLogo) {
|
|
764
|
+
toggleLogo.innerHTML = `<img src="${logoUrl}" alt="Chat" style="width:100%; height:100%; object-fit:cover;" />`;
|
|
765
|
+
toggleLogo.classList.remove('hidden');
|
|
766
|
+
// Hide the default message icon if logo is present
|
|
767
|
+
const iconMessage = document.getElementById('ragged-icon-message');
|
|
768
|
+
if (iconMessage) iconMessage.classList.add('hidden');
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
document.getElementById('ragged-toggle-btn').addEventListener('click', toggleWidget);
|
|
774
|
+
document.getElementById('ragged-close-btn').addEventListener('click', toggleWidget);
|
|
775
|
+
document.getElementById('ragged-input-form').addEventListener('submit', handleSend);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
if (document.readyState === 'loading') {
|
|
779
|
+
document.addEventListener('DOMContentLoaded', initializeWidget);
|
|
780
|
+
} else {
|
|
781
|
+
initializeWidget();
|
|
782
|
+
}
|
|
783
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ragged-chat-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official SDK for integrating Ragged Chatbots into your website.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"ragged",
|
|
12
|
+
"chatbot",
|
|
13
|
+
"sdk",
|
|
14
|
+
"ai",
|
|
15
|
+
"chat"
|
|
16
|
+
],
|
|
17
|
+
"author": "Ragged",
|
|
18
|
+
"license": "ISC"
|
|
19
|
+
}
|
|
Binary file
|
package/test-import.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { init } from './index.js';
|
|
2
|
+
|
|
3
|
+
if (typeof init === 'function') {
|
|
4
|
+
console.log('SDK exports init function successfully.');
|
|
5
|
+
} else {
|
|
6
|
+
console.error('SDK failed to export init function.');
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
global.window = {
|
|
11
|
+
RAGGED_CONFIG: {}
|
|
12
|
+
};
|
|
13
|
+
global.document = {
|
|
14
|
+
readyState: 'complete',
|
|
15
|
+
addEventListener: () => { },
|
|
16
|
+
createElement: () => ({ style: {}, classList: { add: () => { }, remove: () => { } }, addEventListener: () => { } }),
|
|
17
|
+
body: { appendChild: () => { } },
|
|
18
|
+
getElementById: () => ({ addEventListener: () => { } })
|
|
19
|
+
};
|
|
20
|
+
global.fetch = async () => ({ json: async () => ({}) });
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
init({ subdomain: 'test-bot' });
|
|
24
|
+
console.log('SDK init function runs without immediate crashing.');
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.error('SDK init function crashed:', e);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
package/test-simple.js
ADDED