advaisor-chatbot 1.0.0 → 1.3.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.
Binary file
@@ -1176,12 +1176,220 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1176
1176
  var Ft = b.parse;
1177
1177
  var jt = x.lex;
1178
1178
 
1179
+ // src/sidebar.js
1180
+ var ChatSidebar = class extends HTMLElement {
1181
+ constructor() {
1182
+ super();
1183
+ this.attachShadow({ mode: "open" });
1184
+ this.isOpen = false;
1185
+ this.token = null;
1186
+ this.packageId = null;
1187
+ }
1188
+ setConfig(config) {
1189
+ this.token = config.token;
1190
+ this.packageId = config.packageId;
1191
+ }
1192
+ connectedCallback() {
1193
+ this.render();
1194
+ }
1195
+ async toggle() {
1196
+ this.isOpen = !this.isOpen;
1197
+ this.shadowRoot.querySelector(".sidebar").classList.toggle("open");
1198
+ if (this.isOpen) {
1199
+ await this.loadRecentChats();
1200
+ }
1201
+ }
1202
+ async loadRecentChats() {
1203
+ if (!this.token || !this.packageId) return;
1204
+ try {
1205
+ const res = await fetch("https://silicore.ai:2002/customer/recent_chats", {
1206
+ method: "POST",
1207
+ headers: {
1208
+ "Content-Type": "application/json",
1209
+ "Authorization": `Bearer ${this.token}`
1210
+ },
1211
+ body: JSON.stringify({
1212
+ package_id: this.packageId
1213
+ })
1214
+ });
1215
+ const data = await res.json();
1216
+ this.renderChats(data?.body);
1217
+ } catch (err) {
1218
+ console.error("Failed to load recent chats", err);
1219
+ }
1220
+ }
1221
+ renderChats(chats) {
1222
+ const container = this.shadowRoot.getElementById("recent-container");
1223
+ const newChatBtn = this.shadowRoot.getElementById("newChatBtn");
1224
+ newChatBtn.onclick = () => {
1225
+ this.selectedSessionId = null;
1226
+ container.querySelectorAll(".chat-item").forEach((item) => {
1227
+ item.classList.remove("active");
1228
+ });
1229
+ this.dispatchEvent(new CustomEvent("new-chat", {
1230
+ bubbles: true,
1231
+ composed: true
1232
+ }));
1233
+ };
1234
+ if (!chats || chats.length === 0) {
1235
+ container.innerHTML = `<div>No recent chats</div>`;
1236
+ return;
1237
+ }
1238
+ container.innerHTML = chats.map((chat) => {
1239
+ const title = chat?.chat_title || "No title";
1240
+ const shortTitle = title.length > 25 ? title.substring(0, 25) + "..." : title;
1241
+ const activeClass = String(chat.session_id) === String(this.selectedSessionId) ? "active" : "";
1242
+ return `
1243
+ <div class="chat-item ${activeClass}"
1244
+ data-id="${chat.session_id}"
1245
+ title="${title}">
1246
+
1247
+ <div class="chat-title">${shortTitle}</div>
1248
+
1249
+ <div class="chat-date">
1250
+ ${chat?.created_at || ""}
1251
+ </div>
1252
+
1253
+ </div>
1254
+ `;
1255
+ }).join("");
1256
+ container.querySelectorAll(".chat-item").forEach((el) => {
1257
+ el.onclick = () => {
1258
+ const sessionId = el.dataset.id;
1259
+ this.selectedSessionId = String(sessionId);
1260
+ this.dispatchEvent(new CustomEvent("chat-selected", {
1261
+ detail: { sessionId },
1262
+ bubbles: true,
1263
+ composed: true
1264
+ }));
1265
+ this.renderChats(chats);
1266
+ };
1267
+ });
1268
+ }
1269
+ render() {
1270
+ this.shadowRoot.innerHTML = `
1271
+ <style>
1272
+ .sidebar {
1273
+ position: absolute;
1274
+ left: -280px;
1275
+ top: 64.5px;
1276
+ width: 280px;
1277
+ height: calc(100% - 64.5px);
1278
+ background: white;
1279
+ border-right: 1px solid #eee;
1280
+ box-shadow: 2px 0 10px rgba(0,0,0,0.05);
1281
+ transition: left 0.3s ease;
1282
+ padding: 16px;
1283
+ box-sizing: border-box;
1284
+ border-radius: 0 12px 12px 0;
1285
+
1286
+ display: flex;
1287
+ flex-direction: column;
1288
+ }
1289
+
1290
+ .recent-wrapper {
1291
+ flex: 1;
1292
+ overflow-y: auto;
1293
+ margin-top: 10px;
1294
+ }
1295
+
1296
+ #recent-container {
1297
+ display: flex;
1298
+ flex-direction: column;
1299
+ gap: 6px;
1300
+ }
1301
+
1302
+ .sidebar.open {
1303
+ left: 0;
1304
+ }
1305
+
1306
+ h3 {
1307
+ margin-top: 0;
1308
+ font-size: 16px;
1309
+ margin-bottom: 0px;
1310
+ }
1311
+
1312
+ .chat-item {
1313
+ padding: 8px;
1314
+ border-radius: 6px;
1315
+ cursor: pointer;
1316
+ }
1317
+
1318
+ .chat-item:hover {
1319
+ background: #f3f4f6;
1320
+ }
1321
+
1322
+ .chat-title {
1323
+ font-size: 14px;
1324
+ }
1325
+
1326
+ .chat-date {
1327
+ font-size: 12px;
1328
+ color: rgba(0,0,0,0.38);
1329
+ white-space: nowrap;
1330
+ margin-top: 2px;
1331
+ }
1332
+
1333
+ .recent-wrapper::-webkit-scrollbar {
1334
+ width: 6px;
1335
+ }
1336
+
1337
+ .recent-wrapper::-webkit-scrollbar-thumb {
1338
+ background: #ddd;
1339
+ border-radius: 6px;
1340
+ }
1341
+
1342
+ .recent-wrapper::-webkit-scrollbar-thumb:hover {
1343
+ background: #ccc;
1344
+ }
1345
+
1346
+ .new-chat-btn {
1347
+ width: 100%;
1348
+ padding: 8px;
1349
+ border: none;
1350
+ background: var(--primary-color);
1351
+ color: white;
1352
+ border-radius: 6px;
1353
+ cursor: pointer;
1354
+ font-size: 14px;
1355
+ margin-bottom: 8px;
1356
+ }
1357
+
1358
+ .chat-item.active {
1359
+ background: rgba(0,0,0,0.08);
1360
+ font-weight: 500;
1361
+ }
1362
+ </style>
1363
+
1364
+ <div class="sidebar">
1365
+
1366
+ <div class="sidebar-header">
1367
+ <button id="newChatBtn" class="new-chat-btn">+ Start New Chat</button>
1368
+ </div>
1369
+
1370
+ <h3>Recent Chats</h3>
1371
+ <div class="recent-wrapper">
1372
+ <div id="recent-container">
1373
+ <div>Loading...</div>
1374
+ </div>
1375
+ </div>
1376
+ </div>
1377
+
1378
+ `;
1379
+ }
1380
+ };
1381
+ customElements.define("chat-sidebar", ChatSidebar);
1382
+
1383
+ // src/assets/chats.png
1384
+ var chats_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAdElEQVR4nO2UQQqAMAwE8zzrhzzqW9uHjCAKHhrolkYQnXO6A9lQs59WgBkotFOApAiU8IusCA6i5u27gubyBwrq5Y9aEV7OYwKRHCnIwNQjWCNWZ7Xw0YJNeuCgzlvnJygJ0llojEABWEIFd4lFgnMw72QHf/xl9mYG+AwAAAAASUVORK5CYII=";
1385
+
1179
1386
  // src/chatbot.js
1180
1387
  var AdvaisorChatBot = class extends HTMLElement {
1181
1388
  constructor() {
1182
1389
  super();
1183
1390
  this.attachShadow({ mode: "open" });
1184
1391
  this.isOpen = false;
1392
+ this.activeSessionId = null;
1185
1393
  }
1186
1394
  connectedCallback() {
1187
1395
  this.apiEndpoint = this.getAttribute("api_endpoint") || "https://silicore.ai:2002/cds_bookshelves/ask_all_bookshelves";
@@ -1191,6 +1399,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1191
1399
  }
1192
1400
  render() {
1193
1401
  this.shadowRoot.innerHTML = `
1402
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
1194
1403
  <style>
1195
1404
  :host {
1196
1405
  --primary-color: #EC9588;
@@ -1234,10 +1443,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1234
1443
  border-radius: 12px;
1235
1444
  width: 400px;
1236
1445
  max-width: 90vw;
1237
- height: 600px;
1446
+ height: 85vh;
1238
1447
  overflow: hidden;
1239
- min-width: 280px;
1240
- min-height: 350px;
1448
+ min-width: min(300px, 85vw);
1449
+ min-height: min(450px, 85vw);
1241
1450
  transition: width 0.2s ease, height 0.2s ease;
1242
1451
  }
1243
1452
 
@@ -1267,7 +1476,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1267
1476
  align-items: center;
1268
1477
  }
1269
1478
 
1270
- .close-btn { background: none; border: none; color: white; cursor: pointer; font-size: 18px; }
1479
+ .close-btn { background: none; border: none; color: white; cursor: pointer; font-size: 16px; }
1271
1480
 
1272
1481
  .chat-body {
1273
1482
  flex: 1;
@@ -1361,12 +1570,29 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1361
1570
  .header {
1362
1571
  cursor: move;
1363
1572
  user-select: none;
1573
+ touch-action: none;
1574
+ }
1575
+
1576
+ .history-btn {
1577
+ height: 32px;
1578
+ width: 32px;
1579
+ border-radius: 50%;
1580
+ border: none;
1581
+ cursor: pointer;
1582
+ background: rgba(255,255,255,0.0);
1583
+ color: white;
1584
+ font-size: 14px;
1585
+ display: flex;
1586
+ align-items: center;
1587
+ justify-content: center;
1588
+ margin-top: 4px;
1364
1589
  }
1365
1590
  </style>
1366
1591
 
1367
1592
  <button class="chat-trigger" id="trigger">\u{1F4AC}</button>
1368
1593
 
1369
1594
  <div class="chat-window" id="window">
1595
+ <chat-sidebar id="sidebar"></chat-sidebar>
1370
1596
  <div class="header">
1371
1597
  <div>
1372
1598
  <div style="font-weight: 600;">advAIsor</div>
@@ -1374,8 +1600,12 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1374
1600
  </div>
1375
1601
 
1376
1602
  <div style="display:flex; gap:8px;">
1377
- <button class="resize-btn" id="resize">\u26F6</button>
1378
- <button class="close-btn" id="close">\u2715</button>
1603
+ <button title="Chat History" class="history-btn" id="history">
1604
+ <img src="${chats_default}" alt="History"
1605
+ style="width:18px; height:16px;">
1606
+ </button>
1607
+ <button title="Resize" class="resize-btn" id="resize">\u26F6</button>
1608
+ <button title="Close" class="close-btn" id="close">\u2715</button>
1379
1609
  </div>
1380
1610
  </div>
1381
1611
 
@@ -1398,6 +1628,31 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1398
1628
  const sendBtn = this.shadowRoot.getElementById("send");
1399
1629
  const input = this.shadowRoot.getElementById("input");
1400
1630
  const body = this.shadowRoot.getElementById("body");
1631
+ const historyBtn = this.shadowRoot.getElementById("history");
1632
+ const sidebar = this.shadowRoot.getElementById("sidebar");
1633
+ sidebar.addEventListener("new-chat", () => {
1634
+ this.activeSessionId = null;
1635
+ const body2 = this.shadowRoot.getElementById("body");
1636
+ body2.innerHTML = `<div class="message bot">Hi ${this.userName}! How can I help?</div>`;
1637
+ if (sidebar.isOpen) {
1638
+ sidebar.toggle();
1639
+ }
1640
+ });
1641
+ sidebar.setConfig({
1642
+ token: this.token,
1643
+ packageId: 30
1644
+ // or this.packageId if dynamic
1645
+ });
1646
+ historyBtn.onclick = () => {
1647
+ sidebar.toggle();
1648
+ };
1649
+ sidebar.addEventListener("chat-selected", (e) => {
1650
+ const sessionId = e.detail.sessionId;
1651
+ this.loadSession(sessionId);
1652
+ if (sidebar.isOpen) {
1653
+ sidebar.toggle();
1654
+ }
1655
+ });
1401
1656
  trigger.onclick = () => {
1402
1657
  windowEl.style.display = "flex";
1403
1658
  trigger.style.display = "none";
@@ -1448,7 +1703,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1448
1703
  body: JSON.stringify({
1449
1704
  question: text,
1450
1705
  pdf_name: "All Bookshelves",
1451
- session_id: null,
1706
+ session_id: this.activeSessionId,
1452
1707
  bookshelf_name: "All Bookshelves",
1453
1708
  package_id: 30,
1454
1709
  user_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
@@ -1456,6 +1711,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1456
1711
  });
1457
1712
  const response = await res.json();
1458
1713
  typingDiv.remove();
1714
+ if (response?.session_id) {
1715
+ this.activeSessionId = response.session_id;
1716
+ }
1459
1717
  const botReply = response?.answer || "No response received.";
1460
1718
  d.setOptions({
1461
1719
  breaks: true,
@@ -1489,31 +1747,104 @@ Please report this to https://github.com/markedjs/marked.`, e) {
1489
1747
  let isDragging = false;
1490
1748
  let offsetX = 0;
1491
1749
  let offsetY = 0;
1492
- header.addEventListener("mousedown", (e) => {
1750
+ function getEventPosition(e) {
1751
+ if (e.touches && e.touches.length > 0) {
1752
+ return {
1753
+ x: e.touches[0].clientX,
1754
+ y: e.touches[0].clientY
1755
+ };
1756
+ }
1757
+ return {
1758
+ x: e.clientX,
1759
+ y: e.clientY
1760
+ };
1761
+ }
1762
+ function startDrag(e) {
1493
1763
  isDragging = true;
1764
+ const pos = getEventPosition(e);
1494
1765
  const rect = windowEl.getBoundingClientRect();
1495
- offsetX = e.clientX - rect.left;
1496
- offsetY = e.clientY - rect.top;
1766
+ offsetX = pos.x - rect.left;
1767
+ offsetY = pos.y - rect.top;
1497
1768
  windowEl.style.right = "auto";
1498
1769
  windowEl.style.bottom = "auto";
1499
1770
  windowEl.style.left = rect.left + "px";
1500
1771
  windowEl.style.top = rect.top + "px";
1501
- });
1502
- document.addEventListener("mousemove", (e) => {
1772
+ }
1773
+ header.addEventListener("mousedown", startDrag);
1774
+ header.addEventListener("touchstart", startDrag);
1775
+ function onDrag(e) {
1503
1776
  if (!isDragging) return;
1504
- let x2 = e.clientX - offsetX;
1505
- let y2 = e.clientY - offsetY;
1777
+ const pos = getEventPosition(e);
1778
+ let x2 = pos.x - offsetX;
1779
+ let y2 = pos.y - offsetY;
1506
1780
  const maxX = window.innerWidth - windowEl.offsetWidth;
1507
1781
  const maxY = window.innerHeight - windowEl.offsetHeight;
1508
1782
  x2 = Math.max(0, Math.min(x2, maxX));
1509
1783
  y2 = Math.max(0, Math.min(y2, maxY));
1510
1784
  windowEl.style.left = x2 + "px";
1511
1785
  windowEl.style.top = y2 + "px";
1512
- });
1513
- document.addEventListener("mouseup", () => {
1786
+ }
1787
+ document.addEventListener("mousemove", onDrag);
1788
+ document.addEventListener("touchmove", onDrag);
1789
+ function stopDrag() {
1514
1790
  isDragging = false;
1791
+ }
1792
+ document.addEventListener("mouseup", stopDrag);
1793
+ document.addEventListener("touchend", stopDrag);
1794
+ windowEl.addEventListener("click", (e) => {
1795
+ const sidebar2 = this.shadowRoot.getElementById("sidebar");
1796
+ const historyBtn2 = this.shadowRoot.getElementById("history");
1797
+ if (!sidebar2.isOpen) return;
1798
+ const path = e.composedPath();
1799
+ const clickedInsideSidebar = path.includes(sidebar2);
1800
+ const clickedHistoryBtn = path.includes(historyBtn2);
1801
+ if (!clickedInsideSidebar && !clickedHistoryBtn) {
1802
+ sidebar2.toggle();
1803
+ }
1515
1804
  });
1516
1805
  }
1806
+ async loadSession(sessionId) {
1807
+ this.activeSessionId = sessionId;
1808
+ const body = this.shadowRoot.getElementById("body");
1809
+ body.innerHTML = `<div class="message bot">Loading conversation...</div>`;
1810
+ try {
1811
+ const res = await fetch(
1812
+ "https://silicore.ai:2002/customer/user_session_chats",
1813
+ {
1814
+ method: "POST",
1815
+ headers: {
1816
+ "Content-Type": "application/json",
1817
+ "Authorization": `Bearer ${this.token}`
1818
+ },
1819
+ body: JSON.stringify({
1820
+ session_id: sessionId
1821
+ })
1822
+ }
1823
+ );
1824
+ const data = await res.json();
1825
+ const history = data?.body?.chat_history || [];
1826
+ body.innerHTML = "";
1827
+ history.forEach((chat) => {
1828
+ this.renderMessage(chat.question, "user");
1829
+ this.renderMessage(chat.answer, "bot", true);
1830
+ });
1831
+ } catch (err) {
1832
+ console.error("Failed to load session", err);
1833
+ }
1834
+ }
1835
+ renderMessage(content, type, isMarkdown = false) {
1836
+ const body = this.shadowRoot.getElementById("body");
1837
+ const wrapper = document.createElement("div");
1838
+ wrapper.className = `message ${type}`;
1839
+ if (isMarkdown) {
1840
+ const cleanReply = content.replace(/}```/g, "}\n```").replace(/```(\S)/g, "```\n$1");
1841
+ wrapper.innerHTML = d.parse(cleanReply);
1842
+ } else {
1843
+ wrapper.textContent = content;
1844
+ }
1845
+ body.appendChild(wrapper);
1846
+ body.scrollTop = body.scrollHeight;
1847
+ }
1517
1848
  };
1518
1849
  customElements.define("advaisor-chatbot", AdvaisorChatBot);
1519
1850
  })();
package/package.json CHANGED
@@ -1,12 +1,16 @@
1
1
  {
2
2
  "name": "advaisor-chatbot",
3
- "version": "1.0.0",
3
+ "version": "1.3.0",
4
4
  "description": "Embeddable chatbot component",
5
5
  "main": "dist/testchatbot.js",
6
6
  "scripts": {
7
7
  "build": "node build.js"
8
8
  },
9
- "keywords": ["chatbot", "web-component", "ai"],
9
+ "keywords": [
10
+ "chatbot",
11
+ "web-component",
12
+ "ai"
13
+ ],
10
14
  "author": "Echno Technologies",
11
15
  "license": "ISC",
12
16
  "files": [