advaisor-chatbot 1.7.0 → 1.7.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/testchatbot.js +348 -215
- package/package.json +1 -1
package/dist/testchatbot.js
CHANGED
|
@@ -1390,6 +1390,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1390
1390
|
this.attachShadow({ mode: "open" });
|
|
1391
1391
|
this.isOpen = false;
|
|
1392
1392
|
this.activeSessionId = null;
|
|
1393
|
+
this.abortController = null;
|
|
1393
1394
|
}
|
|
1394
1395
|
connectedCallback() {
|
|
1395
1396
|
this.apiEndpoint = this.getAttribute("api_endpoint") || "https://silicore.ai:2002/cds_bookshelves/ask_all_bookshelves";
|
|
@@ -1399,216 +1400,243 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1399
1400
|
}
|
|
1400
1401
|
render() {
|
|
1401
1402
|
this.shadowRoot.innerHTML = `
|
|
1402
|
-
<
|
|
1403
|
-
|
|
1404
|
-
:
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
.chat-trigger {
|
|
1412
|
-
position: fixed;
|
|
1413
|
-
bottom: 20px;
|
|
1414
|
-
right: 20px;
|
|
1415
|
-
z-index: 9999;
|
|
1416
|
-
height: 56px;
|
|
1417
|
-
width: 56px;
|
|
1418
|
-
border-radius: 50%;
|
|
1419
|
-
background: var(--primary-color);
|
|
1420
|
-
color: white;
|
|
1421
|
-
display: flex;
|
|
1422
|
-
align-items: center;
|
|
1423
|
-
justify-content: center;
|
|
1424
|
-
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
1425
|
-
font-size: 24px;
|
|
1426
|
-
cursor: pointer;
|
|
1427
|
-
transition: transform 0.2s;
|
|
1428
|
-
border: none;
|
|
1429
|
-
}
|
|
1430
|
-
|
|
1431
|
-
.chat-trigger:hover { transform: scale(1.05); }
|
|
1432
|
-
|
|
1433
|
-
.chat-window {
|
|
1434
|
-
position: fixed;
|
|
1435
|
-
bottom: 20px;
|
|
1436
|
-
right: 20px;
|
|
1437
|
-
z-index: 10000;
|
|
1438
|
-
|
|
1439
|
-
display: none;
|
|
1440
|
-
flex-direction: column;
|
|
1441
|
-
|
|
1442
|
-
background: #ffffff;
|
|
1443
|
-
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
|
|
1403
|
+
<style>
|
|
1404
|
+
:host {
|
|
1405
|
+
--primary-color: #EC9588;
|
|
1406
|
+
--user-bubble: #f29b8c;
|
|
1407
|
+
--bot-bubble: #e5e7eb;
|
|
1408
|
+
font-family: system-ui, -apple-system, sans-serif;
|
|
1409
|
+
}
|
|
1444
1410
|
|
|
1445
|
-
|
|
1446
|
-
|
|
1411
|
+
.chat-trigger {
|
|
1412
|
+
position: fixed;
|
|
1413
|
+
bottom: 20px;
|
|
1414
|
+
right: 20px;
|
|
1415
|
+
z-index: 9999;
|
|
1416
|
+
height: 56px;
|
|
1417
|
+
width: 56px;
|
|
1418
|
+
border-radius: 50%;
|
|
1419
|
+
background: var(--primary-color);
|
|
1420
|
+
color: white;
|
|
1421
|
+
display: flex;
|
|
1422
|
+
align-items: center;
|
|
1423
|
+
justify-content: center;
|
|
1424
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
1425
|
+
font-size: 24px;
|
|
1426
|
+
cursor: pointer;
|
|
1427
|
+
transition: transform 0.2s;
|
|
1428
|
+
border: none;
|
|
1429
|
+
}
|
|
1447
1430
|
|
|
1448
|
-
|
|
1449
|
-
overflow: hidden;
|
|
1431
|
+
.chat-trigger:hover { transform: scale(1.05); }
|
|
1450
1432
|
|
|
1451
|
-
|
|
1433
|
+
.chat-window {
|
|
1434
|
+
position: fixed;
|
|
1435
|
+
bottom: 20px;
|
|
1436
|
+
right: 20px;
|
|
1437
|
+
z-index: 10000;
|
|
1438
|
+
display: none;
|
|
1439
|
+
flex-direction: column;
|
|
1440
|
+
background: #ffffff;
|
|
1441
|
+
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
|
|
1442
|
+
width: min(30vw, 420px);
|
|
1443
|
+
height: 90vh;
|
|
1444
|
+
border-radius: 16px;
|
|
1445
|
+
overflow: hidden;
|
|
1446
|
+
transition: all 0.25s ease;
|
|
1447
|
+
resize: both;
|
|
1448
|
+
min-width: 300px;
|
|
1449
|
+
min-height: 450px;
|
|
1450
|
+
}
|
|
1452
1451
|
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1452
|
+
.chat-window.expanded {
|
|
1453
|
+
width: min(700px, 95vw);
|
|
1454
|
+
height: 90vh;
|
|
1455
|
+
}
|
|
1457
1456
|
|
|
1458
|
-
|
|
1457
|
+
@media (max-width: 768px) {
|
|
1458
|
+
.chat-window,
|
|
1459
1459
|
.chat-window.expanded {
|
|
1460
|
-
width:
|
|
1461
|
-
|
|
1462
|
-
|
|
1460
|
+
width: 100vw !important;
|
|
1461
|
+
max-width: 100vw !important;
|
|
1462
|
+
height: 85vh !important;
|
|
1463
|
+
bottom: 0;
|
|
1464
|
+
right: 0;
|
|
1465
|
+
border-radius: 16px 16px 0 0;
|
|
1463
1466
|
}
|
|
1467
|
+
}
|
|
1464
1468
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1469
|
+
.header {
|
|
1470
|
+
background: var(--primary-color);
|
|
1471
|
+
padding: 12px 16px;
|
|
1472
|
+
color: white;
|
|
1473
|
+
display: flex;
|
|
1474
|
+
justify-content: space-between;
|
|
1475
|
+
align-items: center;
|
|
1476
|
+
cursor: move;
|
|
1477
|
+
user-select: none;
|
|
1478
|
+
touch-action: none;
|
|
1479
|
+
}
|
|
1471
1480
|
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
.typing {
|
|
1480
|
-
display: flex;
|
|
1481
|
-
gap: 4px;
|
|
1482
|
-
align-items: center;
|
|
1483
|
-
}
|
|
1481
|
+
.close-btn, .resize-btn, .history-btn {
|
|
1482
|
+
background: none;
|
|
1483
|
+
border: none;
|
|
1484
|
+
color: white;
|
|
1485
|
+
cursor: pointer;
|
|
1486
|
+
font-size: 16px;
|
|
1487
|
+
}
|
|
1484
1488
|
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1489
|
+
.history-btn {
|
|
1490
|
+
height: 32px;
|
|
1491
|
+
width: 32px;
|
|
1492
|
+
border-radius: 50%;
|
|
1493
|
+
font-size: 14px;
|
|
1494
|
+
display: flex;
|
|
1495
|
+
align-items: center;
|
|
1496
|
+
justify-content: center;
|
|
1497
|
+
margin-top: 4px;
|
|
1498
|
+
}
|
|
1490
1499
|
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1500
|
+
.chat-body {
|
|
1501
|
+
flex: 1;
|
|
1502
|
+
padding: 16px;
|
|
1503
|
+
overflow-y: auto;
|
|
1504
|
+
background: #f9fafb;
|
|
1505
|
+
display: flex;
|
|
1506
|
+
flex-direction: column;
|
|
1507
|
+
gap: 12px;
|
|
1508
|
+
}
|
|
1495
1509
|
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1510
|
+
/* Base message styles */
|
|
1511
|
+
.message {
|
|
1512
|
+
max-width: 75%;
|
|
1513
|
+
font-size: 15px;
|
|
1514
|
+
line-height: 1.5;
|
|
1515
|
+
word-wrap: break-word;
|
|
1516
|
+
overflow-wrap: break-word;
|
|
1517
|
+
}
|
|
1501
1518
|
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1519
|
+
.message.bot {
|
|
1520
|
+
align-self: flex-start;
|
|
1521
|
+
display: flex;
|
|
1522
|
+
flex-direction: column;
|
|
1523
|
+
align-items: flex-start;
|
|
1524
|
+
padding: 8px 16px;
|
|
1525
|
+
border-radius: 12px;
|
|
1526
|
+
font-size: 15px;
|
|
1527
|
+
line-height: 1.5;
|
|
1528
|
+
gap: 4px;
|
|
1529
|
+
}
|
|
1510
1530
|
|
|
1511
|
-
|
|
1531
|
+
.message.user {
|
|
1532
|
+
align-self: flex-end;
|
|
1533
|
+
background: var(--user-bubble);
|
|
1534
|
+
color: white;
|
|
1535
|
+
padding: 8px 16px;
|
|
1536
|
+
border-radius: 18px 18px 4px 18px;
|
|
1537
|
+
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
|
1538
|
+
}
|
|
1512
1539
|
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
}
|
|
1540
|
+
/* Bot message content bubble */
|
|
1541
|
+
.message.bot .content {
|
|
1542
|
+
background: var(--bot-bubble);
|
|
1543
|
+
color: #1f2937;
|
|
1544
|
+
border-radius: 18px 18px 18px 4px;
|
|
1545
|
+
word-wrap: break-word;
|
|
1546
|
+
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
|
1547
|
+
}
|
|
1522
1548
|
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
border-radius: 12px;
|
|
1527
|
-
font-size: 15px;
|
|
1528
|
-
line-height: 1.5;
|
|
1529
|
-
}
|
|
1549
|
+
.message.bot .content p {
|
|
1550
|
+
margin: 4px 0;
|
|
1551
|
+
}
|
|
1530
1552
|
|
|
1531
|
-
|
|
1532
|
-
|
|
1553
|
+
.message.bot .content p:first-child { margin-top: 0; }
|
|
1554
|
+
.message.bot .content p:last-child { margin-bottom: 0; }
|
|
1533
1555
|
|
|
1534
|
-
|
|
1535
|
-
border-top: 1px solid #e5e7eb;
|
|
1536
|
-
padding: 12px;
|
|
1537
|
-
display: flex;
|
|
1538
|
-
gap: 8px;
|
|
1539
|
-
}
|
|
1556
|
+
.bot { align-self: flex-start; background: var(--bot-bubble); color: #1f2937; }
|
|
1540
1557
|
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
padding: 8px 12px;
|
|
1546
|
-
outline: none;
|
|
1547
|
-
}
|
|
1558
|
+
.message pre, .message code {
|
|
1559
|
+
white-space: pre-wrap;
|
|
1560
|
+
word-break: break-word;
|
|
1561
|
+
}
|
|
1548
1562
|
|
|
1549
|
-
|
|
1563
|
+
/* Status message (outside bubble) */
|
|
1564
|
+
.status-message {
|
|
1565
|
+
font-style: italic;
|
|
1566
|
+
color: #888;
|
|
1567
|
+
font-size: 0.85em;
|
|
1568
|
+
padding: 4px 12px;
|
|
1569
|
+
margin: 2px 0;
|
|
1570
|
+
background: transparent;
|
|
1571
|
+
border-radius: 12px;
|
|
1572
|
+
display: inline-block;
|
|
1573
|
+
max-width: 80%;
|
|
1574
|
+
}
|
|
1550
1575
|
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1576
|
+
/* Typing indicator as message bubble */
|
|
1577
|
+
.typing-indicator {
|
|
1578
|
+
display: inline-flex;
|
|
1579
|
+
align-items: center;
|
|
1580
|
+
gap: 4px;
|
|
1581
|
+
padding: 8px 16px;
|
|
1582
|
+
background: var(--bot-bubble);
|
|
1583
|
+
border-radius: 18px 18px 18px 4px;
|
|
1584
|
+
margin: 4px 0;
|
|
1585
|
+
max-width: fit-content;
|
|
1586
|
+
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
|
1587
|
+
}
|
|
1560
1588
|
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1589
|
+
.typing-indicator span {
|
|
1590
|
+
width: 8px;
|
|
1591
|
+
height: 8px;
|
|
1592
|
+
background: #666;
|
|
1593
|
+
border-radius: 50%;
|
|
1594
|
+
display: inline-block;
|
|
1595
|
+
animation: typingBounce 1.4s infinite ease-in-out both;
|
|
1596
|
+
}
|
|
1568
1597
|
|
|
1598
|
+
.typing-indicator span:nth-child(1) { animation-delay: -0.32s; }
|
|
1599
|
+
.typing-indicator span:nth-child(2) { animation-delay: -0.16s; }
|
|
1600
|
+
.typing-indicator span:nth-child(3) { animation-delay: 0; }
|
|
1569
1601
|
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
border-radius: 50%;
|
|
1575
|
-
animation: blink 1.4s infinite;
|
|
1576
|
-
}
|
|
1602
|
+
@keyframes typingBounce {
|
|
1603
|
+
0%, 80%, 100% { transform: scale(0.6); opacity: 0.6; }
|
|
1604
|
+
40% { transform: scale(1); opacity: 1; }
|
|
1605
|
+
}
|
|
1577
1606
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1607
|
+
.input-area {
|
|
1608
|
+
border-top: 1px solid #e5e7eb;
|
|
1609
|
+
padding: 12px;
|
|
1610
|
+
display: flex;
|
|
1611
|
+
gap: 8px;
|
|
1612
|
+
}
|
|
1580
1613
|
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1614
|
+
input {
|
|
1615
|
+
flex: 1;
|
|
1616
|
+
border: 1px solid #e5e7eb;
|
|
1617
|
+
border-radius: 6px;
|
|
1618
|
+
padding: 8px 12px;
|
|
1619
|
+
outline: none;
|
|
1620
|
+
}
|
|
1585
1621
|
|
|
1586
|
-
|
|
1587
|
-
opacity: 0.6;
|
|
1588
|
-
cursor: not-allowed;
|
|
1589
|
-
}
|
|
1622
|
+
input:focus { border-color: var(--primary-color); }
|
|
1590
1623
|
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1624
|
+
.send-btn {
|
|
1625
|
+
background: var(--user-bubble);
|
|
1626
|
+
color: white;
|
|
1627
|
+
border: none;
|
|
1628
|
+
padding: 0 16px;
|
|
1629
|
+
border-radius: 6px;
|
|
1630
|
+
cursor: pointer;
|
|
1631
|
+
}
|
|
1596
1632
|
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
color: white;
|
|
1605
|
-
font-size: 14px;
|
|
1606
|
-
display: flex;
|
|
1607
|
-
align-items: center;
|
|
1608
|
-
justify-content: center;
|
|
1609
|
-
margin-top: 4px;
|
|
1610
|
-
}
|
|
1611
|
-
</style>
|
|
1633
|
+
.send-btn:disabled {
|
|
1634
|
+
opacity: 0.6;
|
|
1635
|
+
cursor: not-allowed;
|
|
1636
|
+
}
|
|
1637
|
+
</style>
|
|
1638
|
+
|
|
1639
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
|
|
1612
1640
|
|
|
1613
1641
|
<button class="chat-trigger" id="trigger">\u{1F4AC}</button>
|
|
1614
1642
|
|
|
@@ -1652,6 +1680,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1652
1680
|
const historyBtn = this.shadowRoot.getElementById("history");
|
|
1653
1681
|
const sidebar = this.shadowRoot.getElementById("sidebar");
|
|
1654
1682
|
sidebar.addEventListener("new-chat", () => {
|
|
1683
|
+
if (this.abortController) {
|
|
1684
|
+
this.abortController.abort();
|
|
1685
|
+
this.abortController = null;
|
|
1686
|
+
}
|
|
1655
1687
|
this.activeSessionId = null;
|
|
1656
1688
|
const body2 = this.shadowRoot.getElementById("body");
|
|
1657
1689
|
body2.innerHTML = `<div class="message bot">Hi ${this.userName}! How can I help?</div>`;
|
|
@@ -1680,6 +1712,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1680
1712
|
body.scrollTop = body.scrollHeight;
|
|
1681
1713
|
};
|
|
1682
1714
|
closeBtn.onclick = () => {
|
|
1715
|
+
if (this.abortController) {
|
|
1716
|
+
this.abortController.abort();
|
|
1717
|
+
this.abortController = null;
|
|
1718
|
+
}
|
|
1683
1719
|
windowEl.style.display = "none";
|
|
1684
1720
|
trigger.style.display = "flex";
|
|
1685
1721
|
};
|
|
@@ -1693,6 +1729,10 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1693
1729
|
const sendMessage = async () => {
|
|
1694
1730
|
const text = input.value.trim();
|
|
1695
1731
|
if (!text) return;
|
|
1732
|
+
if (this.abortController) {
|
|
1733
|
+
this.abortController.abort();
|
|
1734
|
+
this.abortController = null;
|
|
1735
|
+
}
|
|
1696
1736
|
input.disabled = true;
|
|
1697
1737
|
sendBtn.disabled = true;
|
|
1698
1738
|
const userMsg = document.createElement("div");
|
|
@@ -1701,21 +1741,39 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1701
1741
|
body.appendChild(userMsg);
|
|
1702
1742
|
input.value = "";
|
|
1703
1743
|
body.scrollTop = body.scrollHeight;
|
|
1744
|
+
const botMessageContainer = document.createElement("div");
|
|
1745
|
+
botMessageContainer.className = "message bot";
|
|
1746
|
+
const contentDiv = document.createElement("div");
|
|
1747
|
+
contentDiv.className = "content";
|
|
1748
|
+
contentDiv.id = "answer-content";
|
|
1704
1749
|
const typingDiv = document.createElement("div");
|
|
1705
|
-
typingDiv.className = "
|
|
1750
|
+
typingDiv.className = "typing-indicator";
|
|
1706
1751
|
typingDiv.id = "typing-indicator";
|
|
1707
1752
|
typingDiv.innerHTML = `
|
|
1708
|
-
<
|
|
1709
|
-
<span></span><span></span><span></span>
|
|
1710
|
-
</div>
|
|
1753
|
+
<span></span><span></span><span></span>
|
|
1711
1754
|
`;
|
|
1712
|
-
|
|
1755
|
+
const statusDiv = document.createElement("div");
|
|
1756
|
+
statusDiv.className = "status-message";
|
|
1757
|
+
statusDiv.id = "status-message";
|
|
1758
|
+
botMessageContainer.appendChild(contentDiv);
|
|
1759
|
+
botMessageContainer.appendChild(typingDiv);
|
|
1760
|
+
botMessageContainer.appendChild(statusDiv);
|
|
1761
|
+
body.appendChild(botMessageContainer);
|
|
1713
1762
|
body.scrollTop = body.scrollHeight;
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1763
|
+
const timeoutId = setTimeout(() => {
|
|
1764
|
+
if (this.abortController) {
|
|
1765
|
+
this.abortController.abort();
|
|
1766
|
+
this.abortController = null;
|
|
1767
|
+
this.showErrorMessage(body, "Request timed out after 30 seconds. Please try again.");
|
|
1768
|
+
botMessageContainer.remove();
|
|
1769
|
+
input.disabled = false;
|
|
1770
|
+
sendBtn.disabled = false;
|
|
1771
|
+
input.focus();
|
|
1772
|
+
}
|
|
1773
|
+
}, 3e4);
|
|
1717
1774
|
try {
|
|
1718
|
-
|
|
1775
|
+
this.abortController = new AbortController();
|
|
1776
|
+
const response = await fetch(this.apiEndpoint, {
|
|
1719
1777
|
method: "POST",
|
|
1720
1778
|
headers: {
|
|
1721
1779
|
"Content-Type": "application/json",
|
|
@@ -1728,36 +1786,90 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1728
1786
|
bookshelf_name: "All Bookshelves",
|
|
1729
1787
|
package_id: 30,
|
|
1730
1788
|
user_timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
1731
|
-
})
|
|
1789
|
+
}),
|
|
1790
|
+
signal: this.abortController.signal
|
|
1732
1791
|
});
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1792
|
+
clearTimeout(timeoutId);
|
|
1793
|
+
if (!response.ok) {
|
|
1794
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
1795
|
+
}
|
|
1796
|
+
const reader = response.body.getReader();
|
|
1797
|
+
const decoder = new TextDecoder("utf-8");
|
|
1798
|
+
let buffer = "";
|
|
1799
|
+
let accumulatedAnswer = "";
|
|
1800
|
+
let lastStatusMessage = "";
|
|
1801
|
+
while (true) {
|
|
1802
|
+
const { value, done } = await reader.read();
|
|
1803
|
+
if (done) break;
|
|
1804
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1805
|
+
const events = buffer.split("\n\n");
|
|
1806
|
+
buffer = events.pop();
|
|
1807
|
+
for (const event of events) {
|
|
1808
|
+
const match = event.match(/^data: (.+)$/m);
|
|
1809
|
+
if (!match) continue;
|
|
1810
|
+
const jsonStr = match[1].trim();
|
|
1811
|
+
try {
|
|
1812
|
+
const data = JSON.parse(jsonStr);
|
|
1813
|
+
if (data.type === "message") {
|
|
1814
|
+
lastStatusMessage = data.text;
|
|
1815
|
+
statusDiv.textContent = data.text;
|
|
1816
|
+
typingDiv.style.display = "none";
|
|
1817
|
+
}
|
|
1818
|
+
if (data.type === "answer") {
|
|
1819
|
+
typingDiv.style.display = "none";
|
|
1820
|
+
if (data.session_id) {
|
|
1821
|
+
this.activeSessionId = data.session_id;
|
|
1822
|
+
}
|
|
1823
|
+
if (accumulatedAnswer && !accumulatedAnswer.endsWith("\n\n")) {
|
|
1824
|
+
accumulatedAnswer += "\n\n";
|
|
1825
|
+
}
|
|
1826
|
+
const newText = data.text;
|
|
1827
|
+
accumulatedAnswer += newText;
|
|
1828
|
+
const words = newText.split(" ");
|
|
1829
|
+
let currentDisplayText = accumulatedAnswer.substring(0, accumulatedAnswer.length - newText.length);
|
|
1830
|
+
if (currentDisplayText) {
|
|
1831
|
+
const cleanExisting = this.fixMarkdown(currentDisplayText);
|
|
1832
|
+
const htmlExisting = d.parse(cleanExisting);
|
|
1833
|
+
contentDiv.innerHTML = htmlExisting;
|
|
1834
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
1835
|
+
}
|
|
1836
|
+
for (let i = 0; i < words.length; i++) {
|
|
1837
|
+
currentDisplayText += (i > 0 || currentDisplayText ? " " : "") + words[i];
|
|
1838
|
+
const cleanReply = this.fixMarkdown(currentDisplayText + (i < words.length - 1 ? " ..." : ""));
|
|
1839
|
+
const htmlReply = d.parse(cleanReply);
|
|
1840
|
+
contentDiv.innerHTML = htmlReply;
|
|
1841
|
+
if (i < words.length - 1) {
|
|
1842
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
if (data.is_last) {
|
|
1847
|
+
statusDiv.remove();
|
|
1848
|
+
typingDiv.style.display = "none";
|
|
1849
|
+
const cleanReply = this.fixMarkdown(accumulatedAnswer);
|
|
1850
|
+
const htmlReply = d.parse(cleanReply);
|
|
1851
|
+
contentDiv.innerHTML = htmlReply;
|
|
1852
|
+
break;
|
|
1853
|
+
}
|
|
1854
|
+
} catch (parseError) {
|
|
1855
|
+
console.error("Error parsing JSON:", jsonStr, parseError);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1737
1858
|
}
|
|
1738
|
-
const botReply = response?.answer || "No response received.";
|
|
1739
|
-
d.setOptions({
|
|
1740
|
-
breaks: true,
|
|
1741
|
-
gfm: true
|
|
1742
|
-
});
|
|
1743
|
-
const cleanReply = fixMarkdown(botReply);
|
|
1744
|
-
const htmlReply = d.parse(cleanReply);
|
|
1745
|
-
const wrapper = document.createElement("div");
|
|
1746
|
-
wrapper.className = "message bot";
|
|
1747
|
-
wrapper.innerHTML = htmlReply;
|
|
1748
|
-
body.appendChild(wrapper);
|
|
1749
|
-
body.scrollTop = body.scrollHeight;
|
|
1750
1859
|
} catch (error) {
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1860
|
+
clearTimeout(timeoutId);
|
|
1861
|
+
botMessageContainer.remove();
|
|
1862
|
+
if (error.name === "AbortError") {
|
|
1863
|
+
console.log("Stream aborted");
|
|
1864
|
+
} else {
|
|
1865
|
+
this.showErrorMessage(body, "Sorry, something went wrong. Please try again.");
|
|
1866
|
+
console.error("Stream error:", error);
|
|
1867
|
+
}
|
|
1757
1868
|
} finally {
|
|
1758
1869
|
input.disabled = false;
|
|
1759
1870
|
sendBtn.disabled = false;
|
|
1760
1871
|
input.focus();
|
|
1872
|
+
this.abortController = null;
|
|
1761
1873
|
}
|
|
1762
1874
|
};
|
|
1763
1875
|
sendBtn.onclick = sendMessage;
|
|
@@ -1824,7 +1936,21 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1824
1936
|
}
|
|
1825
1937
|
});
|
|
1826
1938
|
}
|
|
1939
|
+
fixMarkdown(text) {
|
|
1940
|
+
return text.replace(/}```/g, "}\n```").replace(/```(\S)/g, "```\n$1");
|
|
1941
|
+
}
|
|
1942
|
+
showErrorMessage(body, message) {
|
|
1943
|
+
const errorMsg = document.createElement("div");
|
|
1944
|
+
errorMsg.className = "message bot error-message";
|
|
1945
|
+
errorMsg.textContent = message;
|
|
1946
|
+
body.appendChild(errorMsg);
|
|
1947
|
+
body.scrollTop = body.scrollHeight;
|
|
1948
|
+
}
|
|
1827
1949
|
async loadSession(sessionId) {
|
|
1950
|
+
if (this.abortController) {
|
|
1951
|
+
this.abortController.abort();
|
|
1952
|
+
this.abortController = null;
|
|
1953
|
+
}
|
|
1828
1954
|
this.activeSessionId = sessionId;
|
|
1829
1955
|
const body = this.shadowRoot.getElementById("body");
|
|
1830
1956
|
body.innerHTML = `<div class="message bot">Loading conversation...</div>`;
|
|
@@ -1842,6 +1968,9 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1842
1968
|
})
|
|
1843
1969
|
}
|
|
1844
1970
|
);
|
|
1971
|
+
if (!res.ok) {
|
|
1972
|
+
throw new Error(`HTTP error! status: ${res.status}`);
|
|
1973
|
+
}
|
|
1845
1974
|
const data = await res.json();
|
|
1846
1975
|
const history = data?.body?.chat_history || [];
|
|
1847
1976
|
body.innerHTML = "";
|
|
@@ -1851,6 +1980,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1851
1980
|
});
|
|
1852
1981
|
} catch (err) {
|
|
1853
1982
|
console.error("Failed to load session", err);
|
|
1983
|
+
body.innerHTML = `<div class="message bot error-message">Failed to load conversation. Please try again.</div>`;
|
|
1854
1984
|
}
|
|
1855
1985
|
}
|
|
1856
1986
|
renderMessage(content, type, isMarkdown = false) {
|
|
@@ -1858,8 +1988,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
1858
1988
|
const wrapper = document.createElement("div");
|
|
1859
1989
|
wrapper.className = `message ${type}`;
|
|
1860
1990
|
if (isMarkdown) {
|
|
1861
|
-
const cleanReply =
|
|
1862
|
-
|
|
1991
|
+
const cleanReply = this.fixMarkdown(content);
|
|
1992
|
+
const contentDiv = document.createElement("div");
|
|
1993
|
+
contentDiv.className = "content";
|
|
1994
|
+
contentDiv.innerHTML = d.parse(cleanReply);
|
|
1995
|
+
wrapper.appendChild(contentDiv);
|
|
1863
1996
|
} else {
|
|
1864
1997
|
wrapper.textContent = content;
|
|
1865
1998
|
}
|