@nabeh/chat-widget 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +452 -0
- package/dist/browser.cjs +872 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +12 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.iife.js +872 -0
- package/dist/browser.iife.js.map +1 -0
- package/dist/browser.js +2 -0
- package/dist/browser.js.map +1 -0
- package/dist/chunk-T4LQIVBI.js +872 -0
- package/dist/chunk-T4LQIVBI.js.map +1 -0
- package/dist/index.cjs +872 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +111 -0
- package/dist/index.d.ts +111 -0
- package/dist/index.iife.js +872 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
# Chat Widget Library
|
|
2
|
+
|
|
3
|
+
Production-oriented TypeScript library for embedding an AI chat assistant into an Angular website or any browser-based application.
|
|
4
|
+
|
|
5
|
+
## Publish to npm
|
|
6
|
+
|
|
7
|
+
This package is configured for the npm organization scope `@nabeh` and for public publishing.
|
|
8
|
+
|
|
9
|
+
### 1. Sign in with the CTO npm account
|
|
10
|
+
|
|
11
|
+
If the CTO does not already have an npm account, create one first at `https://www.npmjs.com/signup`, then sign in.
|
|
12
|
+
|
|
13
|
+
### 2. Create the npm organization
|
|
14
|
+
|
|
15
|
+
While signed in to npm with the CTO account:
|
|
16
|
+
|
|
17
|
+
- open `https://www.npmjs.com/`
|
|
18
|
+
- click the profile menu in the top-right
|
|
19
|
+
- click `Add an Organization`
|
|
20
|
+
- enter the organization name `nabeh`
|
|
21
|
+
|
|
22
|
+
The npm scope will be `@nabeh`.
|
|
23
|
+
|
|
24
|
+
### 3. Log in on the publish machine
|
|
25
|
+
|
|
26
|
+
Use the CTO account in the terminal:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm logout
|
|
30
|
+
npm login
|
|
31
|
+
npm whoami
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 4. Build and verify the package
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm run clean
|
|
38
|
+
npm run check
|
|
39
|
+
npm run build
|
|
40
|
+
npm pack --dry-run
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 5. Publish the package publicly
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm publish
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
For the next release:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm version patch
|
|
53
|
+
npm publish
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Use `patch` for fixes, `minor` for new backward-compatible features, and `major` for breaking changes.
|
|
57
|
+
|
|
58
|
+
Notes:
|
|
59
|
+
|
|
60
|
+
- this package uses `"publishConfig": { "access": "public" }`
|
|
61
|
+
- public org-scoped packages still use the scoped package name
|
|
62
|
+
- npm docs for this flow:
|
|
63
|
+
- https://docs.npmjs.com/creating-an-organization
|
|
64
|
+
- https://docs.npmjs.com/creating-and-publishing-an-organization-scoped-package/
|
|
65
|
+
|
|
66
|
+
## Project layout
|
|
67
|
+
|
|
68
|
+
- `src/` - production TypeScript source
|
|
69
|
+
- `docs/implementation-plan.md` - architecture and rollout notes
|
|
70
|
+
- `local-test/mock-ai-server.js` - local mock backend
|
|
71
|
+
- `local-test/chat-widget.js` - original quick prototype
|
|
72
|
+
- `local-test/angular-usage-example.ts` - Angular init example
|
|
73
|
+
|
|
74
|
+
## Library API
|
|
75
|
+
|
|
76
|
+
Package usage:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { createChatWidget } from "@nabeh/chat-widget";
|
|
80
|
+
|
|
81
|
+
const widget = createChatWidget({
|
|
82
|
+
apiBaseUrl: "https://api.example.com",
|
|
83
|
+
endpoints: {
|
|
84
|
+
ask: "/knowledge_rag/ask",
|
|
85
|
+
history: "/knowledge_rag/get_chat_history",
|
|
86
|
+
deleteChat: "/knowledge_rag/delete_chat",
|
|
87
|
+
deleteLastQa: "/knowledge_rag/delete_last_qa_pair"
|
|
88
|
+
},
|
|
89
|
+
rag: {
|
|
90
|
+
chatId: "customer-portal-session-123",
|
|
91
|
+
knowledgeNames: ["employee-handbook", "policies"],
|
|
92
|
+
enableReferences: true
|
|
93
|
+
},
|
|
94
|
+
getAccessToken: async () => authService.getAccessToken(),
|
|
95
|
+
getUserContext: async () => ({
|
|
96
|
+
userId: currentUser.id,
|
|
97
|
+
displayName: currentUser.name
|
|
98
|
+
})
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Browser-global usage after loading the browser bundle:
|
|
103
|
+
|
|
104
|
+
```html
|
|
105
|
+
<script src="https://your-cdn.example.com/browser.iife.js"></script>
|
|
106
|
+
<script>
|
|
107
|
+
window.ChatWidget.init({
|
|
108
|
+
apiBaseUrl: "https://api.example.com",
|
|
109
|
+
endpoints: {
|
|
110
|
+
ask: "/knowledge_rag/ask",
|
|
111
|
+
history: "/knowledge_rag/get_chat_history"
|
|
112
|
+
},
|
|
113
|
+
rag: {
|
|
114
|
+
chatId: "external-client-user-42",
|
|
115
|
+
knowledgeNames: ["client-kb-public", "client-kb-private"]
|
|
116
|
+
},
|
|
117
|
+
getAccessToken: async function () {
|
|
118
|
+
return window.appAccessToken;
|
|
119
|
+
},
|
|
120
|
+
getUserContext: async function () {
|
|
121
|
+
return {
|
|
122
|
+
userId: window.currentUser?.id,
|
|
123
|
+
displayName: window.currentUser?.name
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
</script>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The browser bundle exposes:
|
|
131
|
+
|
|
132
|
+
- `window.ChatWidget.init(config)`
|
|
133
|
+
- `window.ChatWidget.createChatWidget(config)`
|
|
134
|
+
|
|
135
|
+
`init()` returns a widget instance with methods like `open()`, `close()`, `toggle()`, `destroy()`, `loadChats()`, and `loadHistory()`.
|
|
136
|
+
|
|
137
|
+
## Angular integration
|
|
138
|
+
|
|
139
|
+
There are two supported ways to use this widget in Angular:
|
|
140
|
+
|
|
141
|
+
1. load the browser bundle and call `window.ChatWidget.init(...)`
|
|
142
|
+
2. install the npm package and import `createChatWidget(...)`
|
|
143
|
+
|
|
144
|
+
### Option 1: Script-based Angular integration
|
|
145
|
+
|
|
146
|
+
This is the closest match to your current setup.
|
|
147
|
+
|
|
148
|
+
#### 1. Install or host the built bundle
|
|
149
|
+
|
|
150
|
+
After `npm run build`, use:
|
|
151
|
+
|
|
152
|
+
- `dist/browser.iife.js`
|
|
153
|
+
|
|
154
|
+
Copy it into your Angular app assets folder, for example:
|
|
155
|
+
|
|
156
|
+
- `src/assets/chat-widget/browser.iife.js`
|
|
157
|
+
|
|
158
|
+
#### 2. Add the script in Angular
|
|
159
|
+
|
|
160
|
+
In `angular.json`, add the built file under `architect > build > options > scripts`:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
[
|
|
164
|
+
"src/assets/chat-widget/browser.iife.js"
|
|
165
|
+
]
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Or add it directly in `src/index.html`:
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
<script src="assets/chat-widget/browser.iife.js"></script>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### 3. Initialize it after login
|
|
175
|
+
|
|
176
|
+
Call it from a component or auth-ready service after the user session is available:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
declare global {
|
|
180
|
+
interface Window {
|
|
181
|
+
ChatWidget?: {
|
|
182
|
+
init: (config: any) => any;
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
window.ChatWidget?.init({
|
|
188
|
+
apiBaseUrl: "http://192.168.0.126:8788",
|
|
189
|
+
endpoints: {
|
|
190
|
+
ask: "/my-chats/:chatId/messages",
|
|
191
|
+
history: "/my-chats/:chatId/messages",
|
|
192
|
+
listChats: "/my-chats",
|
|
193
|
+
createChat: "/my-chats",
|
|
194
|
+
updateChat: "/my-chats/:chatId",
|
|
195
|
+
deleteChat: "/my-chats/:chatId"
|
|
196
|
+
},
|
|
197
|
+
rag: {
|
|
198
|
+
knowledgeNames: ["sample-kb"],
|
|
199
|
+
loadHistoryOnOpen: true
|
|
200
|
+
},
|
|
201
|
+
getUserContext: async () => ({
|
|
202
|
+
userId: "demo-user-8",
|
|
203
|
+
email: "demo@example.com"
|
|
204
|
+
})
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Important:
|
|
209
|
+
|
|
210
|
+
- `apiBaseUrl` must be your backend base URL, not the Angular frontend URL
|
|
211
|
+
- if your backend runs on port `8788`, use `http://192.168.0.126:8788`
|
|
212
|
+
- if authentication is required, also pass `getAccessToken`
|
|
213
|
+
|
|
214
|
+
Example with token:
|
|
215
|
+
|
|
216
|
+
```ts
|
|
217
|
+
window.ChatWidget?.init({
|
|
218
|
+
apiBaseUrl: "http://192.168.0.126:8788",
|
|
219
|
+
endpoints: {
|
|
220
|
+
ask: "/my-chats/:chatId/messages",
|
|
221
|
+
history: "/my-chats/:chatId/messages",
|
|
222
|
+
listChats: "/my-chats",
|
|
223
|
+
createChat: "/my-chats",
|
|
224
|
+
updateChat: "/my-chats/:chatId",
|
|
225
|
+
deleteChat: "/my-chats/:chatId"
|
|
226
|
+
},
|
|
227
|
+
rag: {
|
|
228
|
+
knowledgeNames: ["sample-kb"],
|
|
229
|
+
loadHistoryOnOpen: true
|
|
230
|
+
},
|
|
231
|
+
getAccessToken: async () => localStorage.getItem("access_token"),
|
|
232
|
+
getUserContext: async () => ({
|
|
233
|
+
userId: "demo-user-8",
|
|
234
|
+
email: "demo@example.com"
|
|
235
|
+
})
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Option 2: Install from npm in Angular
|
|
240
|
+
|
|
241
|
+
Install the package:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
npm install @nabeh/chat-widget
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
Then use it in Angular:
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
import { AfterViewInit, Component, OnDestroy } from "@angular/core";
|
|
251
|
+
import { createChatWidget } from "@nabeh/chat-widget";
|
|
252
|
+
|
|
253
|
+
@Component({
|
|
254
|
+
selector: "app-root",
|
|
255
|
+
template: ""
|
|
256
|
+
})
|
|
257
|
+
export class AppComponent implements AfterViewInit, OnDestroy {
|
|
258
|
+
private widget?: ReturnType<typeof createChatWidget>;
|
|
259
|
+
|
|
260
|
+
ngAfterViewInit(): void {
|
|
261
|
+
this.widget = createChatWidget({
|
|
262
|
+
apiBaseUrl: "http://192.168.0.126:8788",
|
|
263
|
+
endpoints: {
|
|
264
|
+
ask: "/my-chats/:chatId/messages",
|
|
265
|
+
history: "/my-chats/:chatId/messages",
|
|
266
|
+
listChats: "/my-chats",
|
|
267
|
+
createChat: "/my-chats",
|
|
268
|
+
updateChat: "/my-chats/:chatId",
|
|
269
|
+
deleteChat: "/my-chats/:chatId"
|
|
270
|
+
},
|
|
271
|
+
rag: {
|
|
272
|
+
knowledgeNames: ["sample-kb"],
|
|
273
|
+
loadHistoryOnOpen: true
|
|
274
|
+
},
|
|
275
|
+
getUserContext: async () => ({
|
|
276
|
+
userId: "demo-user-8",
|
|
277
|
+
email: "demo@example.com"
|
|
278
|
+
})
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
ngOnDestroy(): void {
|
|
283
|
+
this.widget?.destroy();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Configuration reference
|
|
289
|
+
|
|
290
|
+
These are the main fields you should pass from Angular:
|
|
291
|
+
|
|
292
|
+
- `apiBaseUrl`: backend base URL, for example `http://192.168.0.126:8788`
|
|
293
|
+
- `endpoints.ask`: send-message endpoint
|
|
294
|
+
- `endpoints.history`: fetch-history endpoint
|
|
295
|
+
- `endpoints.listChats`: list sidebar chats
|
|
296
|
+
- `endpoints.createChat`: create a new chat
|
|
297
|
+
- `endpoints.updateChat`: update chat metadata like pin state
|
|
298
|
+
- `endpoints.deleteChat`: delete a chat
|
|
299
|
+
- `rag.knowledgeNames`: knowledge bases to query
|
|
300
|
+
- `rag.loadHistoryOnOpen`: whether to load chat history automatically when opened
|
|
301
|
+
- `getAccessToken`: function returning bearer token
|
|
302
|
+
- `getUserContext`: function returning user identity information
|
|
303
|
+
|
|
304
|
+
Example user context:
|
|
305
|
+
|
|
306
|
+
```ts
|
|
307
|
+
getUserContext: async () => ({
|
|
308
|
+
userId: "demo-user-8",
|
|
309
|
+
displayName: "Demo User",
|
|
310
|
+
email: "demo@example.com",
|
|
311
|
+
roles: ["researcher"]
|
|
312
|
+
})
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Recommended Angular timing
|
|
316
|
+
|
|
317
|
+
Initialize the widget:
|
|
318
|
+
|
|
319
|
+
- after the user logs in
|
|
320
|
+
- after token/user information is available
|
|
321
|
+
- once per page/app shell, not on every route change
|
|
322
|
+
|
|
323
|
+
Destroy the widget when the hosting Angular component is destroyed if you are using the npm import approach.
|
|
324
|
+
|
|
325
|
+
## Knowledge RAG integration
|
|
326
|
+
|
|
327
|
+
The widget is now aligned to the `knowledge_rag` endpoints:
|
|
328
|
+
|
|
329
|
+
- `POST /knowledge_rag/ask`
|
|
330
|
+
- `GET /knowledge_rag/get_chat_history`
|
|
331
|
+
|
|
332
|
+
Production guidance:
|
|
333
|
+
|
|
334
|
+
- pass the bearer token with `getAccessToken()`
|
|
335
|
+
- do not hardcode tokens into the shipped widget
|
|
336
|
+
- use a stable `rag.chatId` per user/session if you want conversation continuity
|
|
337
|
+
- provide `rag.knowledgeNames` from the host application, not from the widget bundle
|
|
338
|
+
- version your hosted script URL, for example:
|
|
339
|
+
- `/chat-widget/v1.0.0/browser.iife.js`
|
|
340
|
+
- `/chat-widget/latest/browser.iife.js`
|
|
341
|
+
|
|
342
|
+
## Backend adapter integration
|
|
343
|
+
|
|
344
|
+
When using the Postgres-backed adapter added in `backend/`, point the widget to the adapter endpoints instead of the raw RAG endpoints:
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
createChatWidget({
|
|
348
|
+
apiBaseUrl: "http://localhost:8788",
|
|
349
|
+
endpoints: {
|
|
350
|
+
ask: "/my-chats/:chatId/messages",
|
|
351
|
+
history: "/my-chats/:chatId/messages",
|
|
352
|
+
listChats: "/my-chats",
|
|
353
|
+
createChat: "/my-chats",
|
|
354
|
+
updateChat: "/my-chats/:chatId"
|
|
355
|
+
},
|
|
356
|
+
rag: {
|
|
357
|
+
knowledgeNames: ["sample-kb"],
|
|
358
|
+
loadHistoryOnOpen: false
|
|
359
|
+
},
|
|
360
|
+
getAccessToken: async () => authService.getAccessToken(),
|
|
361
|
+
getUserContext: async () => ({
|
|
362
|
+
userId: "demo-user-1",
|
|
363
|
+
displayName: "Demo User",
|
|
364
|
+
email: "demo@example.com",
|
|
365
|
+
roles: ["researcher"]
|
|
366
|
+
})
|
|
367
|
+
});
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
The widget forwards `getUserContext()` to the adapter in the `X-Chat-User-Context` header. In your dummy site you can hardcode that object for testing; in the real client integration they should populate it from their logged-in user/session data.
|
|
371
|
+
|
|
372
|
+
In the hybrid adapter flow, Postgres stores chat sidebar metadata only. Full message history and chat deletion are proxied to the AI backend.
|
|
373
|
+
|
|
374
|
+
## Build outputs
|
|
375
|
+
|
|
376
|
+
The library is configured to build:
|
|
377
|
+
|
|
378
|
+
- `esm` for app imports
|
|
379
|
+
- `cjs` for Node/CommonJS consumers
|
|
380
|
+
- `iife` for script injection into an already deployed website
|
|
381
|
+
|
|
382
|
+
Build tooling:
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
npm install
|
|
386
|
+
npm run build
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Output will be generated in `dist/`.
|
|
390
|
+
|
|
391
|
+
## Local test flow
|
|
392
|
+
|
|
393
|
+
### 1. Start the mock backend
|
|
394
|
+
|
|
395
|
+
```bash
|
|
396
|
+
node local-test/mock-ai-server.js
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### 2. Build the browser bundle
|
|
400
|
+
|
|
401
|
+
```bash
|
|
402
|
+
npm install
|
|
403
|
+
npm run build
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### 3. Inject the built script into an Angular dummy app
|
|
407
|
+
|
|
408
|
+
Copy the built browser file from `dist/` into Angular `src/assets/`, then add:
|
|
409
|
+
|
|
410
|
+
```html
|
|
411
|
+
<script src="/assets/browser.iife.js"></script>
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### 4. Initialize after authentication
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
window.ChatWidget?.init({
|
|
418
|
+
apiBaseUrl: "http://localhost:8787",
|
|
419
|
+
endpoints: {
|
|
420
|
+
ask: "/knowledge_rag/ask",
|
|
421
|
+
history: "/knowledge_rag/get_chat_history"
|
|
422
|
+
},
|
|
423
|
+
rag: {
|
|
424
|
+
chatId: "angular-local-test-user-123",
|
|
425
|
+
knowledgeNames: ["sample-kb"]
|
|
426
|
+
},
|
|
427
|
+
getAccessToken: async () => "dummy-sso-token",
|
|
428
|
+
getUserContext: async () => ({
|
|
429
|
+
userId: "u-1001",
|
|
430
|
+
displayName: "Angular Test User"
|
|
431
|
+
})
|
|
432
|
+
});
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
## Production integration guidance
|
|
436
|
+
|
|
437
|
+
For the live Angular site:
|
|
438
|
+
|
|
439
|
+
- host the built `iife` bundle on your CDN or app server
|
|
440
|
+
- load it only after the user is authenticated
|
|
441
|
+
- pass access token and user context from the host Angular app
|
|
442
|
+
- keep RBAC validation in the AI backend
|
|
443
|
+
|
|
444
|
+
Do not embed a separate login flow inside the widget.
|
|
445
|
+
|
|
446
|
+
## Chat persistence adapter
|
|
447
|
+
|
|
448
|
+
This repo now also includes a starter backend adapter in `backend/` for storing chat metadata in Postgres and wrapping the existing RAG APIs.
|
|
449
|
+
|
|
450
|
+
Setup guide:
|
|
451
|
+
|
|
452
|
+
- [docs/chat-backend-setup.md](/home/tarun/learnings/knowledge-platform-cb/docs/chat-backend-setup.md)
|