@informedai/react 0.4.13 → 0.4.15

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/index.mjs CHANGED
@@ -725,14 +725,15 @@ function AssistantWidget({ className, theme, position = "inline", defaultCollaps
725
725
  streamingContent,
726
726
  sendMessage,
727
727
  sendQuickAction,
728
- applyPendingValue,
729
- skipTask
728
+ applyPendingValue
730
729
  } = useInformedAI();
731
730
  const [isCollapsed, setIsCollapsed] = useState2(defaultCollapsed);
732
731
  const [inputValue, setInputValue] = useState2("");
732
+ const [showPendingActions, setShowPendingActions] = useState2(true);
733
733
  const messagesEndRef = useRef2(null);
734
734
  const inputRef = useRef2(null);
735
735
  const wasStreamingRef = useRef2(false);
736
+ const lastPendingValueRef = useRef2(void 0);
736
737
  useEffect2(() => {
737
738
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
738
739
  }, [session?.widgetMessages, streamingContent]);
@@ -742,6 +743,15 @@ function AssistantWidget({ className, theme, position = "inline", defaultCollaps
742
743
  }
743
744
  wasStreamingRef.current = isStreaming;
744
745
  }, [isStreaming]);
746
+ const activeTask = session?.activeTask;
747
+ const pendingValue = activeTask ? session?.taskStates[activeTask]?.pendingValue : void 0;
748
+ const hasPendingValue = pendingValue !== void 0 && pendingValue !== null;
749
+ useEffect2(() => {
750
+ if (hasPendingValue && pendingValue !== lastPendingValueRef.current) {
751
+ setShowPendingActions(true);
752
+ }
753
+ lastPendingValueRef.current = pendingValue;
754
+ }, [hasPendingValue, pendingValue]);
745
755
  const handleSubmit = async (e) => {
746
756
  e.preventDefault();
747
757
  if (!inputValue.trim() || isStreaming) return;
@@ -752,9 +762,6 @@ function AssistantWidget({ className, theme, position = "inline", defaultCollaps
752
762
  const handleQuickAction = async (action) => {
753
763
  await sendQuickAction(action.action, action.payload);
754
764
  };
755
- const activeTask = session?.activeTask;
756
- const pendingValue = activeTask ? session?.taskStates[activeTask]?.pendingValue : void 0;
757
- const hasPendingValue = pendingValue !== void 0 && pendingValue !== null;
758
765
  const cssVars = {
759
766
  "--ia-primary": theme.primaryColor,
760
767
  "--ia-bg": theme.backgroundColor,
@@ -951,7 +958,7 @@ function AssistantWidget({ className, theme, position = "inline", defaultCollaps
951
958
  ]
952
959
  }
953
960
  ),
954
- hasPendingValue && /* @__PURE__ */ jsxs(
961
+ hasPendingValue && showPendingActions ? /* @__PURE__ */ jsxs(
955
962
  "div",
956
963
  {
957
964
  style: {
@@ -985,7 +992,7 @@ function AssistantWidget({ className, theme, position = "inline", defaultCollaps
985
992
  /* @__PURE__ */ jsx2(
986
993
  "button",
987
994
  {
988
- onClick: skipTask,
995
+ onClick: () => setShowPendingActions(false),
989
996
  disabled: isStreaming,
990
997
  style: {
991
998
  padding: "10px 16px",
@@ -998,13 +1005,12 @@ function AssistantWidget({ className, theme, position = "inline", defaultCollaps
998
1005
  fontSize: "14px",
999
1006
  opacity: isStreaming ? 0.5 : 1
1000
1007
  },
1001
- children: "Skip"
1008
+ children: "Not yet"
1002
1009
  }
1003
1010
  )
1004
1011
  ]
1005
1012
  }
1006
- ),
1007
- /* @__PURE__ */ jsxs(
1013
+ ) : /* @__PURE__ */ jsxs(
1008
1014
  "form",
1009
1015
  {
1010
1016
  onSubmit: handleSubmit,
@@ -1265,19 +1271,765 @@ function LoadingSpinner({ size = 20 }) {
1265
1271
  );
1266
1272
  }
1267
1273
 
1274
+ // src/components/AdminChatbot.tsx
1275
+ import { useState as useState3, useRef as useRef3, useEffect as useEffect3 } from "react";
1276
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1277
+ var defaultTheme2 = {
1278
+ primaryColor: "#3b82f6",
1279
+ // Blue (different from widget's amber)
1280
+ backgroundColor: "#ffffff",
1281
+ textColor: "#1c1917",
1282
+ borderRadius: "12px",
1283
+ fontFamily: "system-ui, -apple-system, sans-serif"
1284
+ };
1285
+ function AdminChatbot({ className, ...config }) {
1286
+ const theme = { ...defaultTheme2, ...config.theme };
1287
+ const apiUrl = config.apiUrl || "https://api.informedai.app/api/v1";
1288
+ const [messages, setMessages] = useState3([]);
1289
+ const [inputValue, setInputValue] = useState3("");
1290
+ const [systemPrompt, setSystemPrompt] = useState3(config.systemPrompt || "");
1291
+ const [showSystemPromptEditor, setShowSystemPromptEditor] = useState3(false);
1292
+ const [isStreaming, setIsStreaming] = useState3(false);
1293
+ const [streamingContent, setStreamingContent] = useState3("");
1294
+ const [error, setError] = useState3(null);
1295
+ const [isCollapsed, setIsCollapsed] = useState3(config.defaultCollapsed ?? false);
1296
+ const messagesEndRef = useRef3(null);
1297
+ const inputRef = useRef3(null);
1298
+ useEffect3(() => {
1299
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1300
+ }, [messages, streamingContent]);
1301
+ const sendMessage = async (message) => {
1302
+ if (!message.trim() || isStreaming) return;
1303
+ setError(null);
1304
+ setIsStreaming(true);
1305
+ setStreamingContent("");
1306
+ const newMessages = [...messages, { role: "user", content: message }];
1307
+ setMessages(newMessages);
1308
+ try {
1309
+ const response = await fetch(`${apiUrl}/admin-chatbot/message`, {
1310
+ method: "POST",
1311
+ headers: {
1312
+ "Content-Type": "application/json",
1313
+ Authorization: `Bearer ${config.apiKey}`
1314
+ },
1315
+ body: JSON.stringify({
1316
+ message,
1317
+ history: messages,
1318
+ // Send previous messages (not including current)
1319
+ systemPrompt: systemPrompt || void 0
1320
+ })
1321
+ });
1322
+ if (!response.ok) {
1323
+ const err = await response.json().catch(() => ({ error: "Request failed" }));
1324
+ throw new Error(err.error || `HTTP ${response.status}`);
1325
+ }
1326
+ const reader = response.body?.getReader();
1327
+ if (!reader) throw new Error("No response body");
1328
+ const decoder = new TextDecoder();
1329
+ let buffer = "";
1330
+ let fullContent = "";
1331
+ while (true) {
1332
+ const { done, value } = await reader.read();
1333
+ if (done) break;
1334
+ buffer += decoder.decode(value, { stream: true });
1335
+ const lines = buffer.split("\n");
1336
+ buffer = lines.pop() || "";
1337
+ for (const line of lines) {
1338
+ if (line.startsWith("event:")) continue;
1339
+ if (line.startsWith("data:")) {
1340
+ const data = line.slice(5).trim();
1341
+ try {
1342
+ const parsed = JSON.parse(data);
1343
+ if (parsed.content) {
1344
+ fullContent += parsed.content;
1345
+ setStreamingContent(fullContent);
1346
+ }
1347
+ if (parsed.fullContent) {
1348
+ fullContent = parsed.fullContent;
1349
+ }
1350
+ } catch {
1351
+ }
1352
+ }
1353
+ }
1354
+ }
1355
+ setMessages([...newMessages, { role: "assistant", content: fullContent }]);
1356
+ setStreamingContent("");
1357
+ } catch (err) {
1358
+ setError(err instanceof Error ? err.message : "Failed to send message");
1359
+ } finally {
1360
+ setIsStreaming(false);
1361
+ }
1362
+ };
1363
+ const handleSubmit = (e) => {
1364
+ e.preventDefault();
1365
+ if (!inputValue.trim() || isStreaming) return;
1366
+ const message = inputValue.trim();
1367
+ setInputValue("");
1368
+ sendMessage(message);
1369
+ };
1370
+ const clearConversation = () => {
1371
+ setMessages([]);
1372
+ setStreamingContent("");
1373
+ setError(null);
1374
+ };
1375
+ const cssVars = {
1376
+ "--ac-primary": theme.primaryColor,
1377
+ "--ac-bg": theme.backgroundColor,
1378
+ "--ac-text": theme.textColor,
1379
+ "--ac-radius": theme.borderRadius,
1380
+ "--ac-font": theme.fontFamily
1381
+ };
1382
+ const positionStyles = config.position === "inline" ? {} : {
1383
+ position: "fixed",
1384
+ [config.position === "bottom-left" ? "left" : "right"]: "20px",
1385
+ bottom: "20px",
1386
+ zIndex: 9999
1387
+ };
1388
+ if (isCollapsed && config.position !== "inline") {
1389
+ return /* @__PURE__ */ jsx3(
1390
+ "button",
1391
+ {
1392
+ onClick: () => setIsCollapsed(false),
1393
+ className,
1394
+ style: {
1395
+ ...cssVars,
1396
+ ...positionStyles,
1397
+ width: "56px",
1398
+ height: "56px",
1399
+ borderRadius: "50%",
1400
+ backgroundColor: "var(--ac-primary)",
1401
+ color: "white",
1402
+ border: "none",
1403
+ cursor: "pointer",
1404
+ display: "flex",
1405
+ alignItems: "center",
1406
+ justifyContent: "center",
1407
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
1408
+ fontFamily: "var(--ac-font)"
1409
+ },
1410
+ children: /* @__PURE__ */ jsx3("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx3("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })
1411
+ }
1412
+ );
1413
+ }
1414
+ return /* @__PURE__ */ jsxs2(
1415
+ "div",
1416
+ {
1417
+ className,
1418
+ style: {
1419
+ ...cssVars,
1420
+ ...positionStyles,
1421
+ width: config.position === "inline" ? "100%" : "400px",
1422
+ maxHeight: config.position === "inline" ? "600px" : "80vh",
1423
+ backgroundColor: "var(--ac-bg)",
1424
+ borderRadius: "var(--ac-radius)",
1425
+ border: "1px solid #e5e5e5",
1426
+ fontFamily: "var(--ac-font)",
1427
+ display: "flex",
1428
+ flexDirection: "column",
1429
+ boxShadow: config.position === "inline" ? "none" : "0 4px 20px rgba(0,0,0,0.15)",
1430
+ overflow: "hidden"
1431
+ },
1432
+ children: [
1433
+ /* @__PURE__ */ jsxs2(
1434
+ "div",
1435
+ {
1436
+ style: {
1437
+ padding: "16px",
1438
+ borderBottom: "1px solid #e5e5e5",
1439
+ display: "flex",
1440
+ alignItems: "center",
1441
+ justifyContent: "space-between",
1442
+ backgroundColor: "var(--ac-primary)",
1443
+ color: "white"
1444
+ },
1445
+ children: [
1446
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1447
+ /* @__PURE__ */ jsxs2("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1448
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10" }),
1449
+ /* @__PURE__ */ jsx3("path", { d: "M12 16v-4M12 8h.01" })
1450
+ ] }),
1451
+ /* @__PURE__ */ jsx3("span", { style: { fontWeight: 600 }, children: config.title || "Knowledge Library" })
1452
+ ] }),
1453
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, children: [
1454
+ config.allowEditSystemPrompt && /* @__PURE__ */ jsx3(
1455
+ "button",
1456
+ {
1457
+ onClick: () => setShowSystemPromptEditor(!showSystemPromptEditor),
1458
+ style: {
1459
+ background: "rgba(255,255,255,0.2)",
1460
+ border: "none",
1461
+ borderRadius: "4px",
1462
+ padding: "4px 8px",
1463
+ color: "white",
1464
+ cursor: "pointer",
1465
+ fontSize: "12px"
1466
+ },
1467
+ children: showSystemPromptEditor ? "Hide Prompt" : "Edit Prompt"
1468
+ }
1469
+ ),
1470
+ /* @__PURE__ */ jsx3(
1471
+ "button",
1472
+ {
1473
+ onClick: clearConversation,
1474
+ style: {
1475
+ background: "rgba(255,255,255,0.2)",
1476
+ border: "none",
1477
+ borderRadius: "4px",
1478
+ padding: "4px 8px",
1479
+ color: "white",
1480
+ cursor: "pointer",
1481
+ fontSize: "12px"
1482
+ },
1483
+ children: "Clear"
1484
+ }
1485
+ ),
1486
+ config.position !== "inline" && /* @__PURE__ */ jsx3(
1487
+ "button",
1488
+ {
1489
+ onClick: () => setIsCollapsed(true),
1490
+ style: {
1491
+ background: "none",
1492
+ border: "none",
1493
+ color: "white",
1494
+ cursor: "pointer",
1495
+ padding: "4px"
1496
+ },
1497
+ children: /* @__PURE__ */ jsxs2("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1498
+ /* @__PURE__ */ jsx3("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1499
+ /* @__PURE__ */ jsx3("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1500
+ ] })
1501
+ }
1502
+ )
1503
+ ] })
1504
+ ]
1505
+ }
1506
+ ),
1507
+ showSystemPromptEditor && /* @__PURE__ */ jsxs2("div", { style: { padding: "12px", borderBottom: "1px solid #e5e5e5", backgroundColor: "#f9fafb" }, children: [
1508
+ /* @__PURE__ */ jsx3("label", { style: { display: "block", fontSize: "12px", fontWeight: 500, marginBottom: "4px", color: "#6b7280" }, children: "System Prompt" }),
1509
+ /* @__PURE__ */ jsx3(
1510
+ "textarea",
1511
+ {
1512
+ value: systemPrompt,
1513
+ onChange: (e) => setSystemPrompt(e.target.value),
1514
+ placeholder: "Enter a system prompt to guide the chatbot's behavior...",
1515
+ style: {
1516
+ width: "100%",
1517
+ minHeight: "80px",
1518
+ padding: "8px",
1519
+ borderRadius: "6px",
1520
+ border: "1px solid #d1d5db",
1521
+ fontSize: "13px",
1522
+ fontFamily: "var(--ac-font)",
1523
+ resize: "vertical"
1524
+ }
1525
+ }
1526
+ )
1527
+ ] }),
1528
+ /* @__PURE__ */ jsxs2(
1529
+ "div",
1530
+ {
1531
+ style: {
1532
+ flex: 1,
1533
+ overflowY: "auto",
1534
+ padding: "16px",
1535
+ display: "flex",
1536
+ flexDirection: "column",
1537
+ gap: "12px",
1538
+ minHeight: "200px"
1539
+ },
1540
+ children: [
1541
+ messages.length === 0 && !streamingContent && /* @__PURE__ */ jsxs2("div", { style: { textAlign: "center", color: "#9ca3af", padding: "40px 20px" }, children: [
1542
+ /* @__PURE__ */ jsx3(
1543
+ "svg",
1544
+ {
1545
+ width: "48",
1546
+ height: "48",
1547
+ viewBox: "0 0 24 24",
1548
+ fill: "none",
1549
+ stroke: "currentColor",
1550
+ strokeWidth: "1.5",
1551
+ style: { margin: "0 auto 16px" },
1552
+ children: /* @__PURE__ */ jsx3("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
1553
+ }
1554
+ ),
1555
+ /* @__PURE__ */ jsx3("p", { style: { margin: 0, fontSize: "14px" }, children: "Ask a question about your knowledge library" })
1556
+ ] }),
1557
+ messages.map((msg, i) => /* @__PURE__ */ jsx3(
1558
+ "div",
1559
+ {
1560
+ style: {
1561
+ alignSelf: msg.role === "user" ? "flex-end" : "flex-start",
1562
+ maxWidth: "85%"
1563
+ },
1564
+ children: /* @__PURE__ */ jsx3(
1565
+ "div",
1566
+ {
1567
+ style: {
1568
+ padding: "10px 14px",
1569
+ borderRadius: "12px",
1570
+ backgroundColor: msg.role === "user" ? "var(--ac-primary)" : "#f3f4f6",
1571
+ color: msg.role === "user" ? "white" : "var(--ac-text)",
1572
+ fontSize: "14px",
1573
+ lineHeight: "1.5",
1574
+ whiteSpace: "pre-wrap"
1575
+ },
1576
+ children: msg.content
1577
+ }
1578
+ )
1579
+ },
1580
+ i
1581
+ )),
1582
+ streamingContent && /* @__PURE__ */ jsx3("div", { style: { alignSelf: "flex-start", maxWidth: "85%" }, children: /* @__PURE__ */ jsxs2(
1583
+ "div",
1584
+ {
1585
+ style: {
1586
+ padding: "10px 14px",
1587
+ borderRadius: "12px",
1588
+ backgroundColor: "#f3f4f6",
1589
+ color: "var(--ac-text)",
1590
+ fontSize: "14px",
1591
+ lineHeight: "1.5",
1592
+ whiteSpace: "pre-wrap"
1593
+ },
1594
+ children: [
1595
+ streamingContent,
1596
+ /* @__PURE__ */ jsx3("span", { style: { opacity: 0.5, animation: "blink 1s infinite" }, children: "|" })
1597
+ ]
1598
+ }
1599
+ ) }),
1600
+ error && /* @__PURE__ */ jsx3(
1601
+ "div",
1602
+ {
1603
+ style: {
1604
+ padding: "10px 14px",
1605
+ borderRadius: "8px",
1606
+ backgroundColor: "#fef2f2",
1607
+ color: "#dc2626",
1608
+ fontSize: "13px"
1609
+ },
1610
+ children: error
1611
+ }
1612
+ ),
1613
+ /* @__PURE__ */ jsx3("div", { ref: messagesEndRef })
1614
+ ]
1615
+ }
1616
+ ),
1617
+ /* @__PURE__ */ jsx3("form", { onSubmit: handleSubmit, style: { padding: "12px", borderTop: "1px solid #e5e5e5" }, children: /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, children: [
1618
+ /* @__PURE__ */ jsx3(
1619
+ "input",
1620
+ {
1621
+ ref: inputRef,
1622
+ type: "text",
1623
+ value: inputValue,
1624
+ onChange: (e) => setInputValue(e.target.value),
1625
+ placeholder: config.placeholder || "Ask a question...",
1626
+ disabled: isStreaming,
1627
+ style: {
1628
+ flex: 1,
1629
+ padding: "10px 14px",
1630
+ borderRadius: "8px",
1631
+ border: "1px solid #d1d5db",
1632
+ fontSize: "14px",
1633
+ fontFamily: "var(--ac-font)",
1634
+ outline: "none"
1635
+ }
1636
+ }
1637
+ ),
1638
+ /* @__PURE__ */ jsx3(
1639
+ "button",
1640
+ {
1641
+ type: "submit",
1642
+ disabled: isStreaming || !inputValue.trim(),
1643
+ style: {
1644
+ padding: "10px 16px",
1645
+ borderRadius: "8px",
1646
+ backgroundColor: isStreaming || !inputValue.trim() ? "#d1d5db" : "var(--ac-primary)",
1647
+ color: "white",
1648
+ border: "none",
1649
+ cursor: isStreaming || !inputValue.trim() ? "not-allowed" : "pointer",
1650
+ fontWeight: 500,
1651
+ fontSize: "14px"
1652
+ },
1653
+ children: isStreaming ? "..." : "Send"
1654
+ }
1655
+ )
1656
+ ] }) }),
1657
+ /* @__PURE__ */ jsx3("style", { children: `
1658
+ @keyframes blink {
1659
+ 0%, 50% { opacity: 1; }
1660
+ 51%, 100% { opacity: 0; }
1661
+ }
1662
+ ` })
1663
+ ]
1664
+ }
1665
+ );
1666
+ }
1667
+
1668
+ // src/components/WebsiteChatbot.tsx
1669
+ import { useState as useState4, useRef as useRef4, useEffect as useEffect4 } from "react";
1670
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1671
+ var defaultTheme3 = {
1672
+ primaryColor: "#f59e0b",
1673
+ // Amber
1674
+ backgroundColor: "#ffffff",
1675
+ textColor: "#1c1917",
1676
+ borderRadius: "12px",
1677
+ fontFamily: "system-ui, -apple-system, sans-serif"
1678
+ };
1679
+ function WebsiteChatbot({ className, ...config }) {
1680
+ const theme = { ...defaultTheme3, ...config.theme };
1681
+ const apiUrl = config.apiUrl || "https://api.informedai.app/api/v1";
1682
+ const [messages, setMessages] = useState4([]);
1683
+ const [inputValue, setInputValue] = useState4("");
1684
+ const [isStreaming, setIsStreaming] = useState4(false);
1685
+ const [streamingContent, setStreamingContent] = useState4("");
1686
+ const [error, setError] = useState4(null);
1687
+ const [isCollapsed, setIsCollapsed] = useState4(config.defaultCollapsed ?? false);
1688
+ const messagesEndRef = useRef4(null);
1689
+ useEffect4(() => {
1690
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1691
+ }, [messages, streamingContent]);
1692
+ const sendMessage = async (message) => {
1693
+ if (!message.trim() || isStreaming) return;
1694
+ setError(null);
1695
+ setIsStreaming(true);
1696
+ setStreamingContent("");
1697
+ const newMessages = [...messages, { role: "user", content: message }];
1698
+ setMessages(newMessages);
1699
+ try {
1700
+ const response = await fetch(`${apiUrl}/website-agent/message`, {
1701
+ method: "POST",
1702
+ headers: {
1703
+ "Content-Type": "application/json"
1704
+ },
1705
+ body: JSON.stringify({
1706
+ agentId: config.agentId,
1707
+ message,
1708
+ history: messages
1709
+ })
1710
+ });
1711
+ if (!response.ok) {
1712
+ const err = await response.json().catch(() => ({ error: "Request failed" }));
1713
+ throw new Error(err.error || `HTTP ${response.status}`);
1714
+ }
1715
+ const reader = response.body?.getReader();
1716
+ if (!reader) throw new Error("No response body");
1717
+ const decoder = new TextDecoder();
1718
+ let buffer = "";
1719
+ let fullContent = "";
1720
+ while (true) {
1721
+ const { done, value } = await reader.read();
1722
+ if (done) break;
1723
+ buffer += decoder.decode(value, { stream: true });
1724
+ const lines = buffer.split("\n");
1725
+ buffer = lines.pop() || "";
1726
+ for (const line of lines) {
1727
+ if (line.startsWith("event:")) continue;
1728
+ if (line.startsWith("data:")) {
1729
+ const data = line.slice(5).trim();
1730
+ try {
1731
+ const parsed = JSON.parse(data);
1732
+ if (parsed.content) {
1733
+ fullContent += parsed.content;
1734
+ setStreamingContent(fullContent);
1735
+ }
1736
+ if (parsed.fullContent) {
1737
+ fullContent = parsed.fullContent;
1738
+ }
1739
+ } catch {
1740
+ }
1741
+ }
1742
+ }
1743
+ }
1744
+ setMessages([...newMessages, { role: "assistant", content: fullContent }]);
1745
+ setStreamingContent("");
1746
+ } catch (err) {
1747
+ setError(err instanceof Error ? err.message : "Failed to send message");
1748
+ } finally {
1749
+ setIsStreaming(false);
1750
+ }
1751
+ };
1752
+ const handleSubmit = (e) => {
1753
+ e.preventDefault();
1754
+ if (!inputValue.trim() || isStreaming) return;
1755
+ const message = inputValue.trim();
1756
+ setInputValue("");
1757
+ sendMessage(message);
1758
+ };
1759
+ const clearConversation = () => {
1760
+ setMessages([]);
1761
+ setStreamingContent("");
1762
+ setError(null);
1763
+ };
1764
+ const cssVars = {
1765
+ "--wc-primary": theme.primaryColor,
1766
+ "--wc-bg": theme.backgroundColor,
1767
+ "--wc-text": theme.textColor,
1768
+ "--wc-radius": theme.borderRadius,
1769
+ "--wc-font": theme.fontFamily
1770
+ };
1771
+ const positionStyles = config.position === "inline" ? {} : {
1772
+ position: "fixed",
1773
+ [config.position === "bottom-left" ? "left" : "right"]: "20px",
1774
+ bottom: "20px",
1775
+ zIndex: 9999
1776
+ };
1777
+ if (isCollapsed && config.position !== "inline") {
1778
+ return /* @__PURE__ */ jsx4(
1779
+ "button",
1780
+ {
1781
+ onClick: () => setIsCollapsed(false),
1782
+ className,
1783
+ style: {
1784
+ ...cssVars,
1785
+ ...positionStyles,
1786
+ width: "56px",
1787
+ height: "56px",
1788
+ borderRadius: "50%",
1789
+ backgroundColor: "var(--wc-primary)",
1790
+ color: "white",
1791
+ border: "none",
1792
+ cursor: "pointer",
1793
+ display: "flex",
1794
+ alignItems: "center",
1795
+ justifyContent: "center",
1796
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
1797
+ fontFamily: "var(--wc-font)"
1798
+ },
1799
+ children: /* @__PURE__ */ jsx4("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx4("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })
1800
+ }
1801
+ );
1802
+ }
1803
+ return /* @__PURE__ */ jsxs3(
1804
+ "div",
1805
+ {
1806
+ className,
1807
+ style: {
1808
+ ...cssVars,
1809
+ ...positionStyles,
1810
+ width: config.position === "inline" ? "100%" : "400px",
1811
+ maxHeight: config.position === "inline" ? "600px" : "80vh",
1812
+ backgroundColor: "var(--wc-bg)",
1813
+ borderRadius: "var(--wc-radius)",
1814
+ border: "1px solid #e5e5e5",
1815
+ fontFamily: "var(--wc-font)",
1816
+ display: "flex",
1817
+ flexDirection: "column",
1818
+ boxShadow: config.position === "inline" ? "none" : "0 4px 20px rgba(0,0,0,0.15)",
1819
+ overflow: "hidden"
1820
+ },
1821
+ children: [
1822
+ /* @__PURE__ */ jsxs3(
1823
+ "div",
1824
+ {
1825
+ style: {
1826
+ padding: "16px",
1827
+ borderBottom: "1px solid #e5e5e5",
1828
+ display: "flex",
1829
+ alignItems: "center",
1830
+ justifyContent: "space-between",
1831
+ backgroundColor: "var(--wc-primary)",
1832
+ color: "white"
1833
+ },
1834
+ children: [
1835
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1836
+ /* @__PURE__ */ jsxs3("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1837
+ /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "10" }),
1838
+ /* @__PURE__ */ jsx4("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
1839
+ /* @__PURE__ */ jsx4("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" })
1840
+ ] }),
1841
+ /* @__PURE__ */ jsx4("span", { style: { fontWeight: 600 }, children: config.title || "Chat" })
1842
+ ] }),
1843
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px" }, children: [
1844
+ /* @__PURE__ */ jsx4(
1845
+ "button",
1846
+ {
1847
+ onClick: clearConversation,
1848
+ style: {
1849
+ background: "rgba(255,255,255,0.2)",
1850
+ border: "none",
1851
+ borderRadius: "4px",
1852
+ padding: "4px 8px",
1853
+ color: "white",
1854
+ cursor: "pointer",
1855
+ fontSize: "12px"
1856
+ },
1857
+ children: "Clear"
1858
+ }
1859
+ ),
1860
+ config.position !== "inline" && /* @__PURE__ */ jsx4(
1861
+ "button",
1862
+ {
1863
+ onClick: () => setIsCollapsed(true),
1864
+ style: {
1865
+ background: "none",
1866
+ border: "none",
1867
+ color: "white",
1868
+ cursor: "pointer",
1869
+ padding: "4px"
1870
+ },
1871
+ children: /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1872
+ /* @__PURE__ */ jsx4("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1873
+ /* @__PURE__ */ jsx4("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1874
+ ] })
1875
+ }
1876
+ )
1877
+ ] })
1878
+ ]
1879
+ }
1880
+ ),
1881
+ /* @__PURE__ */ jsxs3(
1882
+ "div",
1883
+ {
1884
+ style: {
1885
+ flex: 1,
1886
+ overflowY: "auto",
1887
+ padding: "16px",
1888
+ display: "flex",
1889
+ flexDirection: "column",
1890
+ gap: "12px",
1891
+ minHeight: "200px"
1892
+ },
1893
+ children: [
1894
+ messages.length === 0 && !streamingContent && /* @__PURE__ */ jsxs3("div", { style: { textAlign: "center", color: "#9ca3af", padding: "40px 20px" }, children: [
1895
+ /* @__PURE__ */ jsx4(
1896
+ "svg",
1897
+ {
1898
+ width: "48",
1899
+ height: "48",
1900
+ viewBox: "0 0 24 24",
1901
+ fill: "none",
1902
+ stroke: "currentColor",
1903
+ strokeWidth: "1.5",
1904
+ style: { margin: "0 auto 16px" },
1905
+ children: /* @__PURE__ */ jsx4("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
1906
+ }
1907
+ ),
1908
+ /* @__PURE__ */ jsx4("p", { style: { margin: 0, fontSize: "14px" }, children: "How can I help you today?" })
1909
+ ] }),
1910
+ messages.map((msg, i) => /* @__PURE__ */ jsx4(
1911
+ "div",
1912
+ {
1913
+ style: {
1914
+ alignSelf: msg.role === "user" ? "flex-end" : "flex-start",
1915
+ maxWidth: "85%"
1916
+ },
1917
+ children: /* @__PURE__ */ jsx4(
1918
+ "div",
1919
+ {
1920
+ style: {
1921
+ padding: "10px 14px",
1922
+ borderRadius: "12px",
1923
+ backgroundColor: msg.role === "user" ? "var(--wc-primary)" : "#f3f4f6",
1924
+ color: msg.role === "user" ? "white" : "var(--wc-text)",
1925
+ fontSize: "14px",
1926
+ lineHeight: "1.5",
1927
+ whiteSpace: "pre-wrap"
1928
+ },
1929
+ children: msg.content
1930
+ }
1931
+ )
1932
+ },
1933
+ i
1934
+ )),
1935
+ streamingContent && /* @__PURE__ */ jsx4("div", { style: { alignSelf: "flex-start", maxWidth: "85%" }, children: /* @__PURE__ */ jsxs3(
1936
+ "div",
1937
+ {
1938
+ style: {
1939
+ padding: "10px 14px",
1940
+ borderRadius: "12px",
1941
+ backgroundColor: "#f3f4f6",
1942
+ color: "var(--wc-text)",
1943
+ fontSize: "14px",
1944
+ lineHeight: "1.5",
1945
+ whiteSpace: "pre-wrap"
1946
+ },
1947
+ children: [
1948
+ streamingContent,
1949
+ /* @__PURE__ */ jsx4("span", { style: { opacity: 0.5, animation: "blink 1s infinite" }, children: "|" })
1950
+ ]
1951
+ }
1952
+ ) }),
1953
+ error && /* @__PURE__ */ jsx4(
1954
+ "div",
1955
+ {
1956
+ style: {
1957
+ padding: "10px 14px",
1958
+ borderRadius: "8px",
1959
+ backgroundColor: "#fef2f2",
1960
+ color: "#dc2626",
1961
+ fontSize: "13px"
1962
+ },
1963
+ children: error
1964
+ }
1965
+ ),
1966
+ /* @__PURE__ */ jsx4("div", { ref: messagesEndRef })
1967
+ ]
1968
+ }
1969
+ ),
1970
+ /* @__PURE__ */ jsx4("form", { onSubmit: handleSubmit, style: { padding: "12px", borderTop: "1px solid #e5e5e5" }, children: /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px" }, children: [
1971
+ /* @__PURE__ */ jsx4(
1972
+ "input",
1973
+ {
1974
+ type: "text",
1975
+ value: inputValue,
1976
+ onChange: (e) => setInputValue(e.target.value),
1977
+ placeholder: config.placeholder || "Type a message...",
1978
+ disabled: isStreaming,
1979
+ style: {
1980
+ flex: 1,
1981
+ padding: "10px 14px",
1982
+ borderRadius: "8px",
1983
+ border: "1px solid #d1d5db",
1984
+ fontSize: "14px",
1985
+ fontFamily: "var(--wc-font)",
1986
+ outline: "none"
1987
+ }
1988
+ }
1989
+ ),
1990
+ /* @__PURE__ */ jsx4(
1991
+ "button",
1992
+ {
1993
+ type: "submit",
1994
+ disabled: isStreaming || !inputValue.trim(),
1995
+ style: {
1996
+ padding: "10px 16px",
1997
+ borderRadius: "8px",
1998
+ backgroundColor: isStreaming || !inputValue.trim() ? "#d1d5db" : "var(--wc-primary)",
1999
+ color: "white",
2000
+ border: "none",
2001
+ cursor: isStreaming || !inputValue.trim() ? "not-allowed" : "pointer",
2002
+ fontWeight: 500,
2003
+ fontSize: "14px"
2004
+ },
2005
+ children: isStreaming ? "..." : "Send"
2006
+ }
2007
+ )
2008
+ ] }) }),
2009
+ /* @__PURE__ */ jsx4("style", { children: `
2010
+ @keyframes blink {
2011
+ 0%, 50% { opacity: 1; }
2012
+ 51%, 100% { opacity: 0; }
2013
+ }
2014
+ ` })
2015
+ ]
2016
+ }
2017
+ );
2018
+ }
2019
+
1268
2020
  // src/hooks/useSession.ts
1269
- import { useState as useState3, useEffect as useEffect3, useCallback as useCallback2, useRef as useRef3 } from "react";
2021
+ import { useState as useState5, useEffect as useEffect5, useCallback as useCallback2, useRef as useRef5 } from "react";
1270
2022
  function useSession(options) {
1271
2023
  const { apiUrl, documentTypeId, sessionId, onSessionChange, onError } = options;
1272
- const [session, setSession] = useState3(null);
1273
- const [isLoading, setIsLoading] = useState3(true);
1274
- const [error, setError] = useState3(null);
1275
- const clientRef = useRef3(null);
1276
- const isStreamingRef = useRef3(false);
1277
- useEffect3(() => {
2024
+ const [session, setSession] = useState5(null);
2025
+ const [isLoading, setIsLoading] = useState5(true);
2026
+ const [error, setError] = useState5(null);
2027
+ const clientRef = useRef5(null);
2028
+ const isStreamingRef = useRef5(false);
2029
+ useEffect5(() => {
1278
2030
  clientRef.current = new InformedAIClient(apiUrl);
1279
2031
  }, [apiUrl]);
1280
- useEffect3(() => {
2032
+ useEffect5(() => {
1281
2033
  async function initialize() {
1282
2034
  if (!clientRef.current) return;
1283
2035
  try {
@@ -1387,9 +2139,11 @@ function useSession(options) {
1387
2139
  };
1388
2140
  }
1389
2141
  export {
2142
+ AdminChatbot,
1390
2143
  InformedAIClient,
1391
2144
  InformedAIProvider,
1392
2145
  InformedAssistant,
2146
+ WebsiteChatbot,
1393
2147
  useInformedAI,
1394
2148
  useSession
1395
2149
  };