@pindai-ai/chat-widget 2.0.4 → 3.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 +364 -426
- package/dist/pindai-chat-widget.css +1 -1
- package/dist/pindai-chat-widget.js +797 -22
- package/dist/pindai-chat-widget.js.map +1 -1
- package/dist/pindai-chat-widget.umd.js +46 -0
- package/dist/pindai-chat-widget.umd.js.map +1 -0
- package/package.json +10 -2
- package/src/i18n.js +18 -0
- package/src/main.js +731 -325
- package/src/style.css +272 -5
package/README.md
CHANGED
|
@@ -1,48 +1,73 @@
|
|
|
1
1
|
# Pindai Chat Widget
|
|
2
2
|
|
|
3
|
-
> Modern, accessible chat widget
|
|
3
|
+
> Modern, accessible, embeddable chat widget — seamlessly integrated with **Pindai Agent-API** or any generic HTTP backend.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@pindai-ai/chat-widget)
|
|
6
6
|
[](https://www.npmjs.com/package/@pindai-ai/chat-widget)
|
|
7
7
|
[](https://opensource.org/licenses/MIT)
|
|
8
|
-
[](https://www.jsdelivr.com/package/npm/@pindai-ai/chat-widget)
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### Option A — Pindai Agent-API (recommended)
|
|
14
|
+
|
|
15
|
+
Get your `agentId`, `embedSecret`, and `apiBaseUrl` from the Pindai dashboard (Chatbot → Embed tab).
|
|
11
16
|
|
|
12
17
|
```html
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
18
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@3/dist/pindai-chat-widget.css">
|
|
19
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@3/dist/pindai-chat-widget.js"></script>
|
|
20
|
+
|
|
21
|
+
<script>
|
|
22
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
23
|
+
window.PindaiChatWidget.init({
|
|
24
|
+
agentId: 'YOUR_AGENT_UUID',
|
|
25
|
+
embedSecret: 'YOUR_EMBED_SECRET_HEX',
|
|
26
|
+
apiBaseUrl: 'https://api.yourcompany.com',
|
|
27
|
+
title: 'Customer Support',
|
|
28
|
+
showLogo: false,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Option B — Generic Webhook (n8n, Dify, Express, FastAPI, etc.)
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@3/dist/pindai-chat-widget.css">
|
|
38
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@3/dist/pindai-chat-widget.js"></script>
|
|
16
39
|
|
|
17
40
|
<script>
|
|
18
41
|
document.addEventListener('DOMContentLoaded', () => {
|
|
19
42
|
window.PindaiChatWidget.init({
|
|
20
43
|
webhookUrl: 'https://your-backend.com/webhook/chat',
|
|
21
|
-
showLogo: false
|
|
44
|
+
showLogo: false,
|
|
22
45
|
});
|
|
23
46
|
});
|
|
24
47
|
</script>
|
|
25
48
|
```
|
|
26
49
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
- **Pindai Agent-API integration** — HMAC-SHA256 auth, SSE streaming, human-agent handoff
|
|
55
|
+
- **Modern UI** — smooth animations, mobile-first responsive design
|
|
56
|
+
- **Fully customizable** — avatar, bubble text, colors, dark/light/auto theme, button alignment, custom footer
|
|
57
|
+
- **Bilingual** — Indonesian (default) and English
|
|
58
|
+
- **File uploads** — PDF, images, Office docs (up to 10 MB, 5 files)
|
|
59
|
+
- **Message history** — localStorage persistence
|
|
60
|
+
- **Notification badge** — unread message count
|
|
61
|
+
- **Quick replies** — configurable suggested responses
|
|
62
|
+
- **Offline detection** — graceful network status handling
|
|
63
|
+
- **Retry logic** — exponential backoff on network errors
|
|
64
|
+
- **WCAG 2.2 AA** — full keyboard navigation, ARIA, 4.5:1 contrast
|
|
65
|
+
- **Zero runtime dependencies** — ~14 KB gzipped
|
|
66
|
+
- **Backward compatible** — existing `webhookUrl` integrations work unchanged
|
|
42
67
|
|
|
43
68
|
---
|
|
44
69
|
|
|
45
|
-
##
|
|
70
|
+
## Installation
|
|
46
71
|
|
|
47
72
|
### Via npm
|
|
48
73
|
|
|
@@ -52,574 +77,487 @@ npm install @pindai-ai/chat-widget
|
|
|
52
77
|
|
|
53
78
|
### Via CDN (jsDelivr)
|
|
54
79
|
|
|
55
|
-
**Latest 2.x version (recommended):**
|
|
56
80
|
```html
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
<script type="module"
|
|
60
|
-
src="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@2/dist/pindai-chat-widget.js"></script>
|
|
61
|
-
```
|
|
81
|
+
<!-- Latest 3.x -->
|
|
82
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@3/dist/pindai-chat-widget.css">
|
|
83
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@3/dist/pindai-chat-widget.js"></script>
|
|
62
84
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<
|
|
66
|
-
href="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@2.0.1/dist/pindai-chat-widget.css">
|
|
67
|
-
<script type="module"
|
|
68
|
-
src="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@2.0.1/dist/pindai-chat-widget.js"></script>
|
|
85
|
+
<!-- Specific version -->
|
|
86
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@3.0.0/dist/pindai-chat-widget.css">
|
|
87
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@3.0.0/dist/pindai-chat-widget.js"></script>
|
|
69
88
|
```
|
|
70
89
|
|
|
71
|
-
|
|
90
|
+
---
|
|
72
91
|
|
|
73
|
-
|
|
92
|
+
## Configuration Options
|
|
74
93
|
|
|
75
|
-
|
|
76
|
-
# Clone repository
|
|
77
|
-
git clone https://github.com/PindaiAI/pindai-chat-widget.git
|
|
78
|
-
cd pindai-chat-widget
|
|
94
|
+
### Required (one of two modes)
|
|
79
95
|
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
| Option | Mode | Type | Description |
|
|
97
|
+
|--------|------|------|-------------|
|
|
98
|
+
| `agentId` | Agent-API | string | Agent UUID from Pindai dashboard |
|
|
99
|
+
| `embedSecret` | Agent-API | string | 32-byte hex embed secret from dashboard |
|
|
100
|
+
| `apiBaseUrl` | Agent-API | string | Base URL of your agent-api (no trailing slash) |
|
|
101
|
+
| `webhookUrl` | Legacy | string | Any HTTP POST endpoint |
|
|
82
102
|
|
|
83
|
-
|
|
84
|
-
npm run dev
|
|
103
|
+
### Display
|
|
85
104
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
105
|
+
| Option | Type | Default | Description |
|
|
106
|
+
|--------|------|---------|-------------|
|
|
107
|
+
| `mode` | string | `'widget'` | `'widget'` (floating button) or `'fullscreen'` |
|
|
108
|
+
| `locale` | string | `'id'` | `'id'` (Indonesian) or `'en'` (English) |
|
|
109
|
+
| `title` | string | Localized | Chat header title |
|
|
110
|
+
| `initialMessage` | string | Localized | First AI message |
|
|
89
111
|
|
|
90
|
-
|
|
112
|
+
### Branding
|
|
91
113
|
|
|
92
|
-
|
|
114
|
+
| Option | Type | Default | Description |
|
|
115
|
+
|--------|------|---------|-------------|
|
|
116
|
+
| `logoUrl` | string | Pindai logo | Header logo URL or data URI |
|
|
117
|
+
| `showLogo` | boolean | `true` | Show/hide header logo. **Recommended: `false`** unless you have a custom logo |
|
|
118
|
+
| `avatarUrl` | string | `null` | Circular avatar image in header (overrides logo) |
|
|
119
|
+
| `launcherIconUrl` | string | Chat SVG | Custom launcher button icon URL |
|
|
120
|
+
| `launcherColor` | string | `'#2563eb'` | Launcher button color |
|
|
121
|
+
| `sendButtonColor` | string | `'#2563eb'` | Send button color |
|
|
122
|
+
| `accentColor` | string | `'#2563eb'` | Accent color for UI elements |
|
|
93
123
|
|
|
94
|
-
###
|
|
124
|
+
### Theme & Layout
|
|
95
125
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<meta charset="UTF-8">
|
|
101
|
-
<title>Your Website</title>
|
|
102
|
-
</head>
|
|
103
|
-
<body>
|
|
104
|
-
<h1>Welcome to My Website</h1>
|
|
105
|
-
<p>Your content here...</p>
|
|
106
|
-
|
|
107
|
-
<!-- Pindai Chat Widget -->
|
|
108
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@2/dist/pindai-chat-widget.css">
|
|
109
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@pindai-ai/chat-widget@2/dist/pindai-chat-widget.js"></script>
|
|
110
|
-
<script>
|
|
111
|
-
document.addEventListener('DOMContentLoaded', function () {
|
|
112
|
-
window.PindaiChatWidget.init({
|
|
113
|
-
webhookUrl: 'https://your-backend.com/webhook/chat',
|
|
114
|
-
mode: 'widget',
|
|
115
|
-
locale: 'id', // 'id' for Indonesian, 'en' for English
|
|
116
|
-
title: 'Customer Support',
|
|
117
|
-
showLogo: false // Hide logo by default (recommended)
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
</script>
|
|
121
|
-
</body>
|
|
122
|
-
</html>
|
|
123
|
-
```
|
|
126
|
+
| Option | Type | Default | Description |
|
|
127
|
+
|--------|------|---------|-------------|
|
|
128
|
+
| `theme` | string | `'light'` | `'light'`, `'dark'`, or `'auto'` (follows system preference) |
|
|
129
|
+
| `buttonAlignment` | string | `'bottom-right'` | `'bottom-right'` or `'bottom-left'` |
|
|
124
130
|
|
|
125
|
-
###
|
|
131
|
+
### Footer / Branding Strip
|
|
126
132
|
|
|
127
|
-
|
|
133
|
+
| Option | Type | Default | Description |
|
|
134
|
+
|--------|------|---------|-------------|
|
|
135
|
+
| `showBranding` | boolean | `true` | Show "Powered by Pindai.ai" in footer |
|
|
136
|
+
| `customFooter` | string | `null` | Additional footer text (supports `[text](url)` links). Appended after branding |
|
|
128
137
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
138
|
+
**Footer examples:**
|
|
139
|
+
- `showBranding: true, customFooter: null` → `Powered by Pindai.ai`
|
|
140
|
+
- `showBranding: true, customFooter: 'Daniel'` → `Powered by Pindai.ai | Daniel`
|
|
141
|
+
- `showBranding: false, customFooter: '[My Company](https://myco.com)'` → `My Company` (linked)
|
|
142
|
+
- `showBranding: false, customFooter: null` → no footer
|
|
133
143
|
|
|
134
|
-
|
|
144
|
+
### Bubble
|
|
135
145
|
|
|
136
|
-
|
|
146
|
+
| Option | Type | Default | Description |
|
|
147
|
+
|--------|------|---------|-------------|
|
|
148
|
+
| `bubbleText` | string | `null` | Shorthand for a single bubble message. Equivalent to `bubbleMessages: ['your text']` |
|
|
149
|
+
| `bubbleMessages` | string[] | `null` | One or more messages shown in the speech bubble above the launcher. When multiple messages are provided, they rotate automatically |
|
|
150
|
+
| `bubbleDelay` | number | `3000` | Milliseconds to wait before the bubble first appears |
|
|
151
|
+
| `bubbleInterval` | number | `5000` | Milliseconds between rotating messages (only used when `bubbleMessages` has more than one entry) |
|
|
152
|
+
| `showBubbleOnce` | boolean | `true` | If `true`, the bubble is permanently hidden after the user dismisses it (stored in localStorage). Set to `false` to always show on page load |
|
|
137
153
|
|
|
138
|
-
|
|
154
|
+
### Visitor Info (Agent-API mode)
|
|
139
155
|
|
|
140
156
|
| Option | Type | Default | Description |
|
|
141
157
|
|--------|------|---------|-------------|
|
|
142
|
-
|
|
|
143
|
-
| `
|
|
144
|
-
| **Display** |
|
|
145
|
-
| `mode` | string | `'widget'` | Display mode: `'widget'` or `'fullscreen'` |
|
|
146
|
-
| `locale` | string | `'id'` | Language: `'id'` (Indonesian) or `'en'` (English) |
|
|
147
|
-
| `title` | string | Localized | Chat header title |
|
|
148
|
-
| `initialMessage` | string | Localized | First AI message |
|
|
149
|
-
| **Branding** |
|
|
150
|
-
| `logoUrl` | string | `'https://pindai.ai/logo.png'` | Header logo URL (use data URI for custom logo) |
|
|
151
|
-
| `showLogo` | boolean | `true` | Show/hide logo. **Recommended: `false`** if you don't have a custom logo |
|
|
152
|
-
| `launcherColor` | string | `'#0066FF'` | Launcher button background color |
|
|
153
|
-
| `launcherIconUrl` | string | Default icon | Custom launcher icon URL |
|
|
154
|
-
| `sendButtonColor` | string | `'#0066FF'` | Send button background color |
|
|
155
|
-
| `accentColor` | string | `'#00C896'` | Accent color for UI elements |
|
|
156
|
-
| **File Upload** |
|
|
157
|
-
| `enableFileUpload` | boolean | `true` | Enable file attachments |
|
|
158
|
-
| `allowedFileTypes` | array | See below | Accepted MIME types |
|
|
159
|
-
| `maxFileSize` | number | `10485760` | Max file size in bytes (10MB default) |
|
|
160
|
-
| `maxFiles` | number | `5` | Max files per message |
|
|
161
|
-
| **Features** |
|
|
162
|
-
| `enableNotifications` | boolean | `true` | Show unread badges |
|
|
163
|
-
| `enableSound` | boolean | `false` | Play notification sound |
|
|
164
|
-
| `enableHistory` | boolean | `true` | Persist message history |
|
|
165
|
-
| `maxHistoryItems` | number | `50` | Max messages to store |
|
|
166
|
-
| `showQuickReplies` | boolean | `true` | Show quick reply buttons |
|
|
167
|
-
| `quickReplies` | array | Localized | Custom suggested responses |
|
|
168
|
-
| **Technical** |
|
|
169
|
-
| `maxRetries` | number | `3` | API retry attempts |
|
|
170
|
-
| `retryDelay` | number | `1000` | Retry delay in ms |
|
|
171
|
-
| `requestTimeout` | number | `30000` | Request timeout in ms (30s) |
|
|
172
|
-
| `rateLimit` | number | `5` | Messages per minute |
|
|
173
|
-
| `rateLimitWindow` | number | `60000` | Rate limit window in ms |
|
|
158
|
+
| `visitorName` | string | `null` | Visitor name forwarded to the API |
|
|
159
|
+
| `visitorEmail` | string | `null` | Visitor email forwarded to the API |
|
|
174
160
|
|
|
175
|
-
###
|
|
161
|
+
### Streaming (Agent-API mode)
|
|
176
162
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
'application/pdf',
|
|
181
|
-
'application/msword',
|
|
182
|
-
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
183
|
-
'application/vnd.ms-excel',
|
|
184
|
-
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
185
|
-
]
|
|
186
|
-
```
|
|
163
|
+
| Option | Type | Default | Description |
|
|
164
|
+
|--------|------|---------|-------------|
|
|
165
|
+
| `enableStreaming` | boolean | `true` | Use SSE streaming for real-time response rendering. Falls back to POST when files are attached |
|
|
187
166
|
|
|
188
|
-
|
|
167
|
+
### Action Indicators
|
|
189
168
|
|
|
190
|
-
|
|
169
|
+
| Option | Type | Default | Description |
|
|
170
|
+
|--------|------|---------|-------------|
|
|
171
|
+
| `showActionIndicators` | boolean | `true` | Show "Thinking..." label in typing indicator |
|
|
191
172
|
|
|
192
|
-
###
|
|
173
|
+
### File Upload
|
|
193
174
|
|
|
194
|
-
|
|
175
|
+
| Option | Type | Default | Description |
|
|
176
|
+
|--------|------|---------|-------------|
|
|
177
|
+
| `enableFileUpload` | boolean | `true` | Enable file attachments |
|
|
178
|
+
| `allowedFileTypes` | array | See below | Accepted MIME types |
|
|
179
|
+
| `maxFileSize` | number | `10485760` | Max file size in bytes (10 MB) |
|
|
180
|
+
| `maxFiles` | number | `5` | Max files per message |
|
|
195
181
|
|
|
182
|
+
**Default allowed file types:**
|
|
196
183
|
```javascript
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
// ...
|
|
203
|
-
}
|
|
184
|
+
['image/jpeg', 'image/png', 'image/gif', 'image/webp',
|
|
185
|
+
'application/pdf', 'application/msword',
|
|
186
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
187
|
+
'application/vnd.ms-excel',
|
|
188
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']
|
|
204
189
|
```
|
|
205
190
|
|
|
206
|
-
###
|
|
207
|
-
|
|
208
|
-
Your backend should respond with JSON:
|
|
209
|
-
|
|
210
|
-
```json
|
|
211
|
-
{
|
|
212
|
-
"response": "AI response text"
|
|
213
|
-
}
|
|
214
|
-
```
|
|
191
|
+
### Features
|
|
215
192
|
|
|
216
|
-
|
|
193
|
+
| Option | Type | Default | Description |
|
|
194
|
+
|--------|------|---------|-------------|
|
|
195
|
+
| `enableNotifications` | boolean | `true` | Show unread message badge |
|
|
196
|
+
| `enableSound` | boolean | `false` | Notification sound (not yet implemented) |
|
|
197
|
+
| `enableHistory` | boolean | `true` | Persist messages to localStorage |
|
|
198
|
+
| `maxHistoryItems` | number | `50` | Max stored messages |
|
|
199
|
+
| `showQuickReplies` | boolean | `true` | Show quick reply buttons |
|
|
200
|
+
| `quickReplies` | array | Localized | Custom suggested responses |
|
|
217
201
|
|
|
218
|
-
|
|
219
|
-
<summary><strong>n8n Workflow (Recommended)</strong></summary>
|
|
202
|
+
### Technical
|
|
220
203
|
|
|
221
|
-
|
|
204
|
+
| Option | Type | Default | Description |
|
|
205
|
+
|--------|------|---------|-------------|
|
|
206
|
+
| `maxRetries` | number | `3` | Retry attempts on 5xx errors |
|
|
207
|
+
| `retryDelay` | number | `1000` | Base retry delay in ms (multiplied per attempt) |
|
|
208
|
+
| `requestTimeout` | number | `30000` | Request timeout in ms |
|
|
209
|
+
| `rateLimit` | number | `5` | Max messages per `rateLimitWindow` |
|
|
210
|
+
| `rateLimitWindow` | number | `60000` | Rate limit window in ms |
|
|
222
211
|
|
|
223
|
-
|
|
212
|
+
### Polling (human-agent handoff)
|
|
224
213
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
214
|
+
| Option | Type | Default | Description |
|
|
215
|
+
|--------|------|---------|-------------|
|
|
216
|
+
| `pollingInterval` | number | `3000` | Polling interval in ms |
|
|
217
|
+
| `pollingUrl` | string | `null` | **Legacy only.** In Agent-API mode, polling URL is auto-derived |
|
|
229
218
|
|
|
230
|
-
|
|
231
|
-
- AI Agent with Indonesian system prompt
|
|
232
|
-
- Chat memory (remembers last 10 messages per session)
|
|
233
|
-
- Automatic response formatting
|
|
234
|
-
- Ready for production use
|
|
219
|
+
---
|
|
235
220
|
|
|
236
|
-
|
|
221
|
+
## Agent-API Authentication
|
|
237
222
|
|
|
238
|
-
**
|
|
223
|
+
The widget uses **HMAC-SHA256** to sign each request, ensuring only authorized widgets can send messages to your agents.
|
|
239
224
|
|
|
240
|
-
|
|
225
|
+
**How it works:**
|
|
241
226
|
|
|
242
|
-
|
|
227
|
+
1. The dashboard generates a per-agent `embedSecret` (32-byte hex string)
|
|
228
|
+
2. On each browser session, the widget generates a random `sessionId`
|
|
229
|
+
3. The widget computes:
|
|
230
|
+
```
|
|
231
|
+
embedToken = HMAC-SHA256(embedSecret, "{agentId}:{sessionId}")
|
|
232
|
+
```
|
|
233
|
+
using native `crypto.subtle` — no external libraries needed
|
|
234
|
+
4. The token is sent with every request as `embedToken` in FormData
|
|
235
|
+
5. The agent-api server verifies it using the same formula
|
|
243
236
|
|
|
244
|
-
|
|
245
|
-
<summary><strong>Express.js Server</strong></summary>
|
|
237
|
+
**To rotate the secret** (invalidates all existing tokens): use the "Rotate Secret" button in your dashboard or call `POST /v1/agents/{agentId}/rotate-secret`.
|
|
246
238
|
|
|
247
|
-
|
|
248
|
-
const express = require('express');
|
|
249
|
-
const app = express();
|
|
239
|
+
---
|
|
250
240
|
|
|
251
|
-
|
|
252
|
-
const { sessionId, message } = req.body;
|
|
241
|
+
## SSE Streaming
|
|
253
242
|
|
|
254
|
-
|
|
255
|
-
const aiResponse = await processWithAI(message);
|
|
243
|
+
When `enableStreaming: true` (default in Agent-API mode), the widget connects to the SSE endpoint and renders the response incrementally as it arrives — similar to ChatGPT's streaming UI.
|
|
256
244
|
|
|
257
|
-
|
|
258
|
-
}
|
|
245
|
+
```
|
|
246
|
+
GET /v1/chat/{agentId}/stream?message=...&sessionId=...&embedToken=...
|
|
259
247
|
```
|
|
260
248
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
```
|
|
267
|
-
from flask import Flask, request, jsonify
|
|
249
|
+
**SSE event format:**
|
|
250
|
+
```
|
|
251
|
+
data: {"delta": "Hello"}
|
|
252
|
+
data: {"delta": " there!"}
|
|
253
|
+
data: {"type": "done", "status": "active"}
|
|
254
|
+
```
|
|
268
255
|
|
|
269
|
-
|
|
256
|
+
**Note:** When files are attached, streaming is automatically disabled and a regular POST is used instead (SSE does not support request bodies).
|
|
270
257
|
|
|
271
|
-
|
|
272
|
-
def chat():
|
|
273
|
-
data = request.get_json()
|
|
274
|
-
session_id = data.get('sessionId')
|
|
275
|
-
message = data.get('message')
|
|
258
|
+
---
|
|
276
259
|
|
|
277
|
-
|
|
278
|
-
ai_response = process_with_ai(message)
|
|
260
|
+
## Human-Agent Handoff
|
|
279
261
|
|
|
280
|
-
|
|
281
|
-
```
|
|
262
|
+
When your agent triggers a handoff (e.g., via `handoff_condition` in the dashboard), the conversation status changes from `active` to `pending` or `assigned`. The widget automatically:
|
|
282
263
|
|
|
283
|
-
|
|
264
|
+
1. Starts polling `GET /v1/chat/{agentId}/messages?since=...` every 3 seconds
|
|
265
|
+
2. Displays messages from human agents in the chat window
|
|
266
|
+
3. Shows a "A team member has joined the conversation." notification
|
|
267
|
+
4. Stops polling when status returns to `active` or `resolved`
|
|
284
268
|
|
|
285
269
|
---
|
|
286
270
|
|
|
287
|
-
##
|
|
271
|
+
## Customization Examples
|
|
288
272
|
|
|
289
|
-
### Custom Branding
|
|
273
|
+
### Custom Branding + Dark Theme
|
|
290
274
|
|
|
291
|
-
**Option 1: No Logo (Recommended)**
|
|
292
275
|
```javascript
|
|
293
276
|
window.PindaiChatWidget.init({
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
277
|
+
agentId: 'YOUR_AGENT_UUID',
|
|
278
|
+
embedSecret: 'YOUR_SECRET',
|
|
279
|
+
apiBaseUrl: 'https://api.yourcompany.com',
|
|
280
|
+
title: 'Support Center',
|
|
281
|
+
avatarUrl: 'https://yourcompany.com/avatar.png',
|
|
282
|
+
launcherColor: '#7c3aed',
|
|
283
|
+
sendButtonColor: '#7c3aed',
|
|
284
|
+
theme: 'dark',
|
|
285
|
+
showBranding: false,
|
|
286
|
+
customFooter: 'Powered by Acme Corp',
|
|
301
287
|
});
|
|
302
288
|
```
|
|
303
289
|
|
|
304
|
-
|
|
290
|
+
### Bubble + Left Alignment
|
|
291
|
+
|
|
305
292
|
```javascript
|
|
293
|
+
// Single static message
|
|
306
294
|
window.PindaiChatWidget.init({
|
|
307
295
|
webhookUrl: 'https://your-backend.com/webhook/chat',
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
sendButtonColor: '#4CAF50',
|
|
314
|
-
accentColor: '#FFC107',
|
|
296
|
+
bubbleText: 'Hey! Need help? Ask us anything 👋',
|
|
297
|
+
bubbleDelay: 3000, // appears after 3 seconds
|
|
298
|
+
showBubbleOnce: true, // won't show again after user dismisses
|
|
299
|
+
buttonAlignment: 'bottom-left',
|
|
300
|
+
showLogo: false,
|
|
315
301
|
});
|
|
316
|
-
```
|
|
317
302
|
|
|
318
|
-
|
|
319
|
-
```javascript
|
|
303
|
+
// Rotating messages — great for product tours or proactive outreach
|
|
320
304
|
window.PindaiChatWidget.init({
|
|
321
305
|
webhookUrl: 'https://your-backend.com/webhook/chat',
|
|
322
|
-
|
|
323
|
-
|
|
306
|
+
bubbleMessages: [
|
|
307
|
+
'Need help? We reply instantly! 👋',
|
|
308
|
+
'Ask me anything about our products!',
|
|
309
|
+
'Get support 24/7 — no waiting.',
|
|
310
|
+
],
|
|
311
|
+
bubbleDelay: 2000, // first message after 2s
|
|
312
|
+
bubbleInterval: 5000, // rotate every 5s
|
|
313
|
+
showBubbleOnce: false, // always show on page load
|
|
314
|
+
showLogo: false,
|
|
324
315
|
});
|
|
325
316
|
```
|
|
326
317
|
|
|
327
|
-
###
|
|
318
|
+
### Auto Dark/Light Theme
|
|
328
319
|
|
|
329
320
|
```javascript
|
|
330
321
|
window.PindaiChatWidget.init({
|
|
331
322
|
webhookUrl: 'https://your-backend.com/webhook/chat',
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
'Lupa password',
|
|
335
|
-
'Hubungi customer service',
|
|
336
|
-
'Lihat demo produk'
|
|
337
|
-
],
|
|
323
|
+
theme: 'auto', // Follows system prefers-color-scheme
|
|
324
|
+
showLogo: false,
|
|
338
325
|
});
|
|
339
326
|
```
|
|
340
327
|
|
|
341
|
-
###
|
|
328
|
+
### Minimal (no uploads, no quick replies, no branding)
|
|
342
329
|
|
|
343
330
|
```javascript
|
|
344
331
|
window.PindaiChatWidget.init({
|
|
345
332
|
webhookUrl: 'https://your-backend.com/webhook/chat',
|
|
346
|
-
|
|
347
|
-
|
|
333
|
+
enableFileUpload: false,
|
|
334
|
+
showQuickReplies: false,
|
|
335
|
+
showBranding: false,
|
|
336
|
+
showLogo: false,
|
|
348
337
|
});
|
|
349
338
|
```
|
|
350
339
|
|
|
351
|
-
###
|
|
340
|
+
### Custom Quick Replies
|
|
352
341
|
|
|
353
342
|
```javascript
|
|
354
343
|
window.PindaiChatWidget.init({
|
|
355
344
|
webhookUrl: 'https://your-backend.com/webhook/chat',
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
345
|
+
quickReplies: [
|
|
346
|
+
'How do I reset my password?',
|
|
347
|
+
'Track my order',
|
|
348
|
+
'Contact sales',
|
|
349
|
+
'View documentation',
|
|
350
|
+
],
|
|
359
351
|
});
|
|
360
352
|
```
|
|
361
353
|
|
|
362
354
|
---
|
|
363
355
|
|
|
364
|
-
##
|
|
365
|
-
|
|
366
|
-
This widget meets **WCAG 2.2 Level AA** compliance:
|
|
367
|
-
|
|
368
|
-
✅ Full keyboard navigation (Tab, Enter, ESC)
|
|
369
|
-
✅ ARIA labels and landmarks
|
|
370
|
-
✅ Screen reader compatible
|
|
371
|
-
✅ 4.5:1 color contrast ratios
|
|
372
|
-
✅ Focus indicators
|
|
373
|
-
✅ Text resizable to 200%
|
|
374
|
-
✅ Touch targets ≥ 44×44px
|
|
375
|
-
|
|
376
|
-
### Keyboard Shortcuts
|
|
377
|
-
|
|
378
|
-
| Key | Action |
|
|
379
|
-
|-----|--------|
|
|
380
|
-
| `Tab` | Navigate between elements |
|
|
381
|
-
| `Enter` | Send message / Activate button |
|
|
382
|
-
| `ESC` | Close widget |
|
|
383
|
-
| `Space` | Activate launcher |
|
|
384
|
-
|
|
385
|
-
---
|
|
356
|
+
## Backend API Reference
|
|
386
357
|
|
|
387
|
-
|
|
358
|
+
### Agent-API endpoints (auto-used in agent-api mode)
|
|
388
359
|
|
|
389
|
-
|
|
360
|
+
| Endpoint | Method | Purpose |
|
|
361
|
+
|----------|--------|---------|
|
|
362
|
+
| `/v1/chat/{agentId}/message` | POST | Send a user message |
|
|
363
|
+
| `/v1/chat/{agentId}/stream` | GET (SSE) | Stream AI response |
|
|
364
|
+
| `/v1/chat/{agentId}/messages` | GET | Poll for human-agent replies |
|
|
390
365
|
|
|
391
|
-
**
|
|
366
|
+
**POST /v1/chat/{agentId}/message** — FormData fields:
|
|
392
367
|
|
|
393
|
-
|
|
368
|
+
| Field | Required | Description |
|
|
369
|
+
|-------|----------|-------------|
|
|
370
|
+
| `sessionId` | Yes | Widget-generated session identifier |
|
|
371
|
+
| `message` | Yes | User message text |
|
|
372
|
+
| `embedToken` | Yes | HMAC-SHA256 embed token |
|
|
373
|
+
| `visitor_name` | No | Pre-filled visitor name |
|
|
374
|
+
| `visitor_email` | No | Pre-filled visitor email |
|
|
375
|
+
| `file0`...`fileN` | No | Uploaded files |
|
|
394
376
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
377
|
+
**Response:**
|
|
378
|
+
```json
|
|
379
|
+
{
|
|
380
|
+
"response": "AI response text",
|
|
381
|
+
"conversation_id": "uuid",
|
|
382
|
+
"status": "active"
|
|
383
|
+
}
|
|
400
384
|
```
|
|
401
385
|
|
|
402
|
-
|
|
386
|
+
### Generic webhook (legacy mode)
|
|
403
387
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
logoUrl: 'https://your-domain.com/your-logo.png',
|
|
408
|
-
showLogo: true
|
|
409
|
-
});
|
|
388
|
+
**Request** (FormData POST):
|
|
389
|
+
```
|
|
390
|
+
sessionId=web-session-...&message=Hello&file0=<File>
|
|
410
391
|
```
|
|
411
392
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
393
|
+
**Response** (JSON):
|
|
394
|
+
```json
|
|
395
|
+
{ "response": "AI response text" }
|
|
396
|
+
```
|
|
415
397
|
|
|
416
|
-
|
|
417
|
-
1. Check browser console for errors (F12)
|
|
418
|
-
2. Verify the `webhookUrl` is correct
|
|
419
|
-
3. Make sure the script loads after the DOM is ready
|
|
420
|
-
4. Check if there are CSP (Content Security Policy) restrictions
|
|
421
|
-
|
|
422
|
-
### Webhook Returns Error
|
|
423
|
-
|
|
424
|
-
**Problem:** Messages fail to send or you get errors.
|
|
425
|
-
|
|
426
|
-
**Solutions:**
|
|
427
|
-
1. Verify your n8n/backend workflow is active
|
|
428
|
-
2. Check the webhook URL is correct and accessible
|
|
429
|
-
3. Test the webhook with curl:
|
|
430
|
-
```bash
|
|
431
|
-
curl -X POST https://your-webhook-url \
|
|
432
|
-
-H "Content-Type: application/json" \
|
|
433
|
-
-d '{"sessionId":"test","message":"Hello"}'
|
|
434
|
-
```
|
|
435
|
-
4. Check CORS settings on your backend
|
|
398
|
+
---
|
|
436
399
|
|
|
437
|
-
|
|
400
|
+
## Accessibility
|
|
438
401
|
|
|
439
|
-
|
|
402
|
+
WCAG 2.2 Level AA compliant:
|
|
440
403
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
4.
|
|
404
|
+
- Full keyboard navigation (Tab, Shift+Tab, Enter, ESC)
|
|
405
|
+
- ARIA labels on all interactive elements
|
|
406
|
+
- `aria-live` region for chat messages
|
|
407
|
+
- Focus trap within the chat dialog
|
|
408
|
+
- 4.5:1 minimum color contrast ratios
|
|
409
|
+
- 44×44 px minimum touch targets
|
|
410
|
+
- Respects `prefers-reduced-motion`
|
|
411
|
+
- Screen reader compatible
|
|
446
412
|
|
|
447
413
|
---
|
|
448
414
|
|
|
449
|
-
##
|
|
415
|
+
## Browser Support
|
|
450
416
|
|
|
451
|
-
| Browser | Version |
|
|
452
|
-
|
|
417
|
+
| Browser | Minimum Version |
|
|
418
|
+
|---------|----------------|
|
|
453
419
|
| Chrome/Edge | 90+ |
|
|
454
420
|
| Firefox | 88+ |
|
|
455
421
|
| Safari | 14+ |
|
|
456
422
|
| iOS Safari | 14+ |
|
|
457
423
|
| Android Chrome | 90+ |
|
|
458
424
|
|
|
425
|
+
**Required APIs:** `fetch`, `EventSource`, `crypto.subtle`, `FormData`, `localStorage`
|
|
426
|
+
|
|
459
427
|
---
|
|
460
428
|
|
|
461
|
-
##
|
|
429
|
+
## Development
|
|
462
430
|
|
|
463
|
-
|
|
431
|
+
```bash
|
|
432
|
+
git clone https://github.com/PindaiAI/pindai-chat-widget.git
|
|
433
|
+
cd pindai-chat-widget
|
|
434
|
+
npm install
|
|
435
|
+
npm run dev # Dev server at http://localhost:5173
|
|
436
|
+
npm run build # Production build → dist/
|
|
437
|
+
npm run preview # Preview production build
|
|
438
|
+
```
|
|
464
439
|
|
|
440
|
+
**Project structure:**
|
|
465
441
|
```
|
|
466
|
-
pindai-chat/
|
|
442
|
+
pindai-chat-widget/
|
|
467
443
|
├── src/
|
|
468
|
-
│ ├── main.js
|
|
469
|
-
│ ├── style.css
|
|
470
|
-
│ └── i18n.js
|
|
471
|
-
├── dist/
|
|
472
|
-
├──
|
|
473
|
-
├──
|
|
474
|
-
|
|
475
|
-
├── package.json # Package metadata
|
|
476
|
-
└── README.md # Documentation
|
|
444
|
+
│ ├── main.js # Widget class (all logic)
|
|
445
|
+
│ ├── style.css # All styles (design system + components)
|
|
446
|
+
│ └── i18n.js # Indonesian + English translations
|
|
447
|
+
├── dist/ # Built assets (committed for CDN)
|
|
448
|
+
├── index.html # Interactive demo page
|
|
449
|
+
├── vite.config.js # Build config
|
|
450
|
+
└── package.json
|
|
477
451
|
```
|
|
478
452
|
|
|
479
|
-
|
|
453
|
+
---
|
|
480
454
|
|
|
481
|
-
|
|
482
|
-
# Development server with hot reload
|
|
483
|
-
npm run dev
|
|
455
|
+
## Troubleshooting
|
|
484
456
|
|
|
485
|
-
|
|
486
|
-
npm run build
|
|
457
|
+
### Logo shows broken image
|
|
487
458
|
|
|
488
|
-
|
|
489
|
-
|
|
459
|
+
Set `showLogo: false` (recommended) or provide a valid `logoUrl`:
|
|
460
|
+
```javascript
|
|
461
|
+
window.PindaiChatWidget.init({ webhookUrl: '...', showLogo: false });
|
|
490
462
|
```
|
|
491
463
|
|
|
492
|
-
###
|
|
493
|
-
|
|
494
|
-
1. **Start dev server:**
|
|
495
|
-
```bash
|
|
496
|
-
npm run dev
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
2. **Open browser:** `http://localhost:5173`
|
|
464
|
+
### Widget not appearing
|
|
500
465
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
- Test quick replies
|
|
506
|
-
- Try keyboard navigation (Tab, ESC)
|
|
507
|
-
- Test offline mode (DevTools > Network > Offline)
|
|
508
|
-
- Check mobile responsiveness (DevTools > Device Toolbar)
|
|
466
|
+
1. Check browser console for errors (F12)
|
|
467
|
+
2. Verify `agentId`/`embedSecret`/`apiBaseUrl` or `webhookUrl` is correct
|
|
468
|
+
3. Ensure script loads after DOM is ready (`DOMContentLoaded`)
|
|
469
|
+
4. Check for CSP (Content Security Policy) restrictions
|
|
509
470
|
|
|
510
|
-
|
|
511
|
-
- Open DevTools > Lighthouse
|
|
512
|
-
- Run Accessibility audit
|
|
513
|
-
- Should score 100
|
|
471
|
+
### CORS errors
|
|
514
472
|
|
|
515
|
-
|
|
473
|
+
Add the widget origin to your API's CORS `allow_origins`. In development, allow `http://localhost:5173`.
|
|
516
474
|
|
|
517
|
-
|
|
475
|
+
### Streaming not working
|
|
518
476
|
|
|
519
|
-
|
|
477
|
+
1. Verify your agent-api version supports SSE (`GET /v1/chat/{agentId}/stream`)
|
|
478
|
+
2. Check browser support: all modern browsers support `EventSource`
|
|
479
|
+
3. NGINX/proxy: ensure SSE headers are not buffered — add `proxy_buffering off;`
|
|
480
|
+
4. Disable streaming: `enableStreaming: false` to fall back to POST
|
|
520
481
|
|
|
521
|
-
|
|
522
|
-
- Added comprehensive troubleshooting section
|
|
523
|
-
- Clarified `showLogo: false` recommendation in Quick Start
|
|
524
|
-
- Added multiple logo customization options (no logo, URL, data URI)
|
|
525
|
-
- Improved configuration examples with best practices
|
|
482
|
+
### CDN cache stale after publish
|
|
526
483
|
|
|
527
|
-
|
|
484
|
+
```bash
|
|
485
|
+
# Force purge jsDelivr cache
|
|
486
|
+
curl https://purge.jsdelivr.net/npm/@pindai-ai/chat-widget@3/dist/pindai-chat-widget.js
|
|
487
|
+
```
|
|
528
488
|
|
|
529
|
-
|
|
530
|
-
- Published with watermark feature to npm
|
|
531
|
-
- CDN distribution updated
|
|
489
|
+
Or use a version-pinned URL: `@pindai-ai/chat-widget@3.0.0`
|
|
532
490
|
|
|
533
|
-
|
|
491
|
+
---
|
|
534
492
|
|
|
535
|
-
|
|
536
|
-
- Vendor-agnostic API: Changed `n8nUrl` to `webhookUrl` parameter
|
|
537
|
-
- Added backward compatibility for `n8nUrl`
|
|
538
|
-
- Added "Powered by Pindai.ai" watermark in widget footer
|
|
539
|
-
- Updated documentation with n8n workflow examples
|
|
540
|
-
- Included ready-to-use n8n workflow JSON files
|
|
493
|
+
## Changelog
|
|
541
494
|
|
|
542
|
-
### Version
|
|
495
|
+
### Version 3.0.0
|
|
543
496
|
|
|
544
|
-
**
|
|
545
|
-
-
|
|
546
|
-
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
-
|
|
550
|
-
-
|
|
551
|
-
-
|
|
552
|
-
-
|
|
553
|
-
-
|
|
554
|
-
-
|
|
555
|
-
-
|
|
556
|
-
-
|
|
497
|
+
**Breaking Changes:**
|
|
498
|
+
- CDN paths use `@3` tag (old `@2` still works for 2.x users)
|
|
499
|
+
- Launcher is now inside `.n8n-chat-launcher-wrapper` (affects custom CSS targeting `.n8n-chat-launcher` for positioning)
|
|
500
|
+
|
|
501
|
+
**New Features:**
|
|
502
|
+
- **Pindai Agent-API integration**: `agentId`, `embedSecret`, `apiBaseUrl` props
|
|
503
|
+
- **HMAC-SHA256 auth**: per-session embed tokens via native `crypto.subtle`
|
|
504
|
+
- **SSE streaming**: real-time incremental response rendering with blinking cursor
|
|
505
|
+
- **Human-agent polling**: auto-derived from `apiBaseUrl` in agent mode
|
|
506
|
+
- **Dark theme**: `theme: 'dark'` or `theme: 'auto'`
|
|
507
|
+
- **Avatar**: `avatarUrl` prop for circular header avatar
|
|
508
|
+
- **Bubble text**: `bubbleText` speech bubble above launcher with dismiss button
|
|
509
|
+
- **Button alignment**: `buttonAlignment: 'bottom-left'` support
|
|
510
|
+
- **Custom footer**: `customFooter` prop with safe Markdown link rendering
|
|
511
|
+
- **Show branding toggle**: `showBranding: false` hides "Powered by Pindai.ai"
|
|
512
|
+
- **Visitor info**: `visitorName`, `visitorEmail` forwarded to API
|
|
513
|
+
- **Action indicators**: `showActionIndicators` with "Thinking..." typing label
|
|
514
|
+
- **Exports field**: proper `package.json` `exports` map for Node.js
|
|
557
515
|
|
|
558
516
|
**Technical:**
|
|
559
|
-
-
|
|
560
|
-
-
|
|
561
|
-
-
|
|
562
|
-
- FormData for file uploads
|
|
563
|
-
- localStorage for history/state
|
|
564
|
-
- Backward compatibility maintained
|
|
517
|
+
- `package.json` version → `3.0.0`
|
|
518
|
+
- All private methods prefixed with `_` (public aliases kept for compatibility)
|
|
519
|
+
- `historyKey`/`stateKey` now uses `agentId` in agent mode (prevents cross-agent history collisions)
|
|
565
520
|
|
|
566
|
-
|
|
567
|
-
- Default locale changed to Indonesian (`'id'`)
|
|
568
|
-
- File uploads now use FormData instead of JSON
|
|
569
|
-
- Some CSS class names updated
|
|
521
|
+
### Version 2.0.4
|
|
570
522
|
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
- Initial release
|
|
574
|
-
- Basic chat functionality
|
|
575
|
-
- n8n integration
|
|
523
|
+
- Bug fixes and stability improvements
|
|
576
524
|
|
|
577
|
-
|
|
525
|
+
### Version 2.0.3
|
|
578
526
|
|
|
579
|
-
|
|
527
|
+
- Documentation: `showLogo` best practices, troubleshooting guide
|
|
580
528
|
|
|
581
|
-
|
|
529
|
+
### Version 2.0.2
|
|
582
530
|
|
|
583
|
-
|
|
584
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
585
|
-
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
586
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
587
|
-
5. Open a Pull Request
|
|
531
|
+
- Published watermark to npm/CDN
|
|
588
532
|
|
|
589
|
-
|
|
533
|
+
### Version 2.0.1
|
|
590
534
|
|
|
591
|
-
|
|
535
|
+
- Renamed `n8nUrl` → `webhookUrl` (backward compatible)
|
|
536
|
+
- Added "Powered by Pindai.ai" watermark
|
|
592
537
|
|
|
593
|
-
|
|
538
|
+
### Version 2.0.0
|
|
594
539
|
|
|
595
|
-
|
|
540
|
+
- Complete UI/UX redesign
|
|
541
|
+
- Indonesian localization (default)
|
|
542
|
+
- File upload, WCAG 2.2 AA, mobile-first
|
|
543
|
+
- Quick replies, notification badge, retry logic, offline detection
|
|
596
544
|
|
|
597
|
-
|
|
545
|
+
### Version 1.0.0
|
|
598
546
|
|
|
599
|
-
-
|
|
600
|
-
- **jsDelivr CDN:** [jsdelivr.com/package/npm/@pindai-ai/chat-widget](https://www.jsdelivr.com/package/npm/@pindai-ai/chat-widget)
|
|
601
|
-
- **GitHub Repository:** [github.com/pindai-ai/pindai-chat-widget](https://github.com/PindaiAI/pindai-chat-widget)
|
|
602
|
-
- **Issues & Bugs:** [github.com/pindai-ai/pindai-chat-widget/issues](https://github.com/PindaiAI/pindai-chat-widget/issues)
|
|
603
|
-
- **Pindai.ai Website:** [pindai.ai](https://pindai.ai)
|
|
547
|
+
- Initial release
|
|
604
548
|
|
|
605
549
|
---
|
|
606
550
|
|
|
607
|
-
##
|
|
551
|
+
## License
|
|
608
552
|
|
|
609
|
-
|
|
610
|
-
- **Issues:** [GitHub Issues](https://github.com/PindaiAI/pindai-chat-widget/issues)
|
|
611
|
-
- **Email:** support@pindai.ai
|
|
612
|
-
- **Website:** [pindai.ai](https://pindai.ai)
|
|
553
|
+
MIT © [Pindai.ai](https://pindai.ai)
|
|
613
554
|
|
|
614
555
|
---
|
|
615
556
|
|
|
616
|
-
##
|
|
617
|
-
|
|
618
|
-
- Inspired by HubSpot chat widget design patterns
|
|
619
|
-
- Built with modern web standards and accessibility best practices
|
|
620
|
-
- Designed for Indonesian enterprises
|
|
621
|
-
- Powered by Pindai.ai's AI document extraction technology
|
|
622
|
-
|
|
623
|
-
---
|
|
557
|
+
## Links
|
|
624
558
|
|
|
625
|
-
**
|
|
559
|
+
- **npm:** [npmjs.com/package/@pindai-ai/chat-widget](https://www.npmjs.com/package/@pindai-ai/chat-widget)
|
|
560
|
+
- **CDN:** [jsdelivr.com/package/npm/@pindai-ai/chat-widget](https://www.jsdelivr.com/package/npm/@pindai-ai/chat-widget)
|
|
561
|
+
- **GitHub:** [github.com/PindaiAI/pindai-chat-widget](https://github.com/PindaiAI/pindai-chat-widget)
|
|
562
|
+
- **Issues:** [github.com/PindaiAI/pindai-chat-widget/issues](https://github.com/PindaiAI/pindai-chat-widget/issues)
|
|
563
|
+
- **Pindai.ai:** [pindai.ai](https://pindai.ai)
|