@tiledesk/tiledesk-server 2.15.7 → 2.16.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/routes/kb.js CHANGED
@@ -13,6 +13,7 @@ const faq = require('../models/faq');
13
13
  const faq_kb = require('../models/faq_kb');
14
14
 
15
15
  const { MODELS_MULTIPLIER } = require('../utils/aiUtils');
16
+ const { parseStringArrayField } = require('../utils/arrayUtil');
16
17
  const { kbTypes } = require('../models/kbConstants');
17
18
  const Sitemapper = require('sitemapper');
18
19
 
@@ -80,6 +81,13 @@ const default_engine = require('../config/kb/engine');
80
81
  const default_engine_hybrid = require('../config/kb/engine.hybrid');
81
82
  const default_embedding = require('../config/kb/embedding');
82
83
 
84
+ function normalizeEmbedding(embedding) {
85
+ const normalizedEmbedding = (embedding && typeof embedding.toObject === 'function')
86
+ ? embedding.toObject()
87
+ : (embedding || default_embedding);
88
+ return { ...normalizedEmbedding };
89
+ }
90
+
83
91
  let contexts = {
84
92
  "gpt-3.5-turbo": process.env.GPT_3_5_CONTEXT || "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### and the chat history to answer the question.\nIf you don't know the answer, just say: \"I don't know<NOANS>\"\n\n####{context}####",
85
93
  "gpt-4": process.env.GPT_4_CONTEXT || "You are an helpful assistant for question-answering tasks.\nUse ONLY the pieces of retrieved context delimited by #### and the chat history to answer the question.\nIf you don't know the answer, just say that you don't know.\nIf and only if none of the retrieved context is useful for your task, add this word to the end <NOANS>\n\n####{context}####",
@@ -170,7 +178,8 @@ router.post('/scrape/single', async (req, res) => {
170
178
  sitemap_origin: sitemapKb.source,
171
179
  scrape_type: sitemapKb.scrape_type,
172
180
  scrape_options: sitemapKb.scrape_options,
173
- refresh_rate: sitemapKb.refresh_rate
181
+ refresh_rate: sitemapKb.refresh_rate,
182
+ tags: sitemapKb.tags
174
183
  }
175
184
  aiManager.addMultipleUrls(namespace, addedUrls, options).catch((err) => {
176
185
  winston.error("(webhook) error adding multiple urls contents: ", err);
@@ -215,8 +224,12 @@ router.post('/scrape/single', async (req, res) => {
215
224
  }
216
225
  }
217
226
 
227
+ if (kb.tags) {
228
+ json.tags = kb.tags;
229
+ }
230
+
218
231
  json.engine = namespace.engine || default_engine;
219
- json.embedding = namespace.embedding || default_embedding;
232
+ json.embedding = normalizeEmbedding(namespace.embedding);
220
233
  json.embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
221
234
 
222
235
  if (namespace.hybrid === true) {
@@ -357,7 +370,7 @@ router.post('/qa', async (req, res) => {
357
370
  }
358
371
 
359
372
  data.engine = namespace.engine || default_engine;
360
- data.embedding = namespace.embedding || default_embedding;
373
+ data.embedding = normalizeEmbedding(namespace.embedding);
361
374
  data.embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
362
375
 
363
376
  if (namespace.hybrid === true) {
@@ -989,7 +1002,8 @@ router.post('/namespace/import/:id', upload.single('uploadFile'), async (req, re
989
1002
  type: e.type,
990
1003
  content: e.content,
991
1004
  namespace: namespace_id,
992
- status: -1
1005
+ status: -1,
1006
+ ...(e.tags && { tags: e.tags })
993
1007
  }
994
1008
 
995
1009
  const optionalFields = ['scrape_type', 'scrape_options', 'refresh_rate'];
@@ -1022,7 +1036,7 @@ router.post('/namespace/import/:id', upload.single('uploadFile'), async (req, re
1022
1036
  // import operation the content's limit is respected
1023
1037
  let ns = namespaces.find(n => n.id === namespace_id);
1024
1038
  let engine = ns.engine || default_engine;
1025
- let embedding = ns.embedding || default_embedding;
1039
+ let embedding = normalizeEmbedding(ns.embedding);
1026
1040
  embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
1027
1041
  let hybrid = ns.hybrid;
1028
1042
 
@@ -1044,10 +1058,13 @@ router.post('/namespace/import/:id', upload.single('uploadFile'), async (req, re
1044
1058
 
1045
1059
  winston.verbose("Content deletetion response: ", deleteResponse);
1046
1060
 
1047
- await KB.insertMany(addingContents).catch((err) => {
1061
+ try {
1062
+ let addedContents = await KB.insertMany(addingContents);
1063
+ winston.debug("addedContents: ", addedContents);
1064
+ } catch (err) {
1048
1065
  winston.error("Error adding contents with insertMany: ", err);
1049
1066
  return res.status(500).send({ success: true, error: "Error importing contents" });
1050
- })
1067
+ }
1051
1068
 
1052
1069
  let new_contents;
1053
1070
  try {
@@ -1362,59 +1379,63 @@ router.get('/:kb_id', async (req, res) => {
1362
1379
 
1363
1380
  router.post('/', async (req, res) => {
1364
1381
 
1365
- let project_id = req.projectid;
1366
- let body = req.body;
1367
- let namespace_id = body.namespace;
1382
+ const id_project = req.projectid;
1383
+ const project = req.project
1368
1384
 
1369
- if (!body.namespace) {
1385
+ const { name, type, source, content, refresh_rate, scrape_type, scrape_options, tags } = req.body;
1386
+ const namespace_id = req.body?.namespace;
1387
+
1388
+ if (!namespace_id) {
1370
1389
  return res.status(400).send({ success: false, error: "parameter 'namespace' is not defined" });
1371
1390
  }
1372
1391
 
1373
1392
  let namespace;
1374
1393
  try {
1375
- namespace = await aiManager.checkNamespace(project_id, namespace_id);
1394
+ namespace = await aiManager.checkNamespace(id_project, namespace_id);
1376
1395
  } catch (err) {
1377
1396
  let errorCode = err?.errorCode ?? 500;
1378
1397
  return res.status(errorCode).send({ success: false, error: err.error });
1379
1398
  }
1380
1399
 
1381
- let quoteManager = req.app.get('quote_manager');
1400
+ const quoteManager = req.app.get('quote_manager');
1382
1401
  try {
1383
- await aiManager.checkQuotaAvailability(quoteManager, req.project, 1)
1402
+ await aiManager.checkQuotaAvailability(quoteManager, project, 1)
1384
1403
  } catch(err) {
1385
1404
  let errorCode = err?.errorCode ?? 500;
1386
1405
  return res.status(errorCode).send({ success: false, error: err.error, plan_limit: err.plan_limit })
1387
1406
  }
1388
1407
 
1389
1408
  let new_kb = {
1390
- id_project: project_id,
1391
- name: body.name,
1392
- type: body.type,
1393
- source: body.source,
1394
- content: body.content,
1395
- namespace: body.namespace,
1409
+ id_project,
1410
+ name,
1411
+ type,
1412
+ source,
1413
+ content,
1414
+ namespace: namespace_id,
1396
1415
  status: -1
1397
1416
  }
1398
- if (!new_kb.namespace) {
1399
- new_kb.namespace = project_id;
1400
- }
1401
- if (new_kb.type === 'txt') {
1417
+
1418
+ if (type === 'txt') {
1402
1419
  new_kb.scrape_type = 1;
1403
1420
  }
1404
- if (new_kb.type === 'url') {
1405
- new_kb.refresh_rate = body.refresh_rate;
1406
- if (!body.scrape_type || body.scrape_type === 2) {
1421
+ if (type === 'url') {
1422
+ new_kb.refresh_rate = refresh_rate || 'never';
1423
+ if (!scrape_type || scrape_type === 2) {
1407
1424
  new_kb.scrape_type = 2;
1408
1425
  new_kb.scrape_options = aiManager.setDefaultScrapeOptions();
1409
1426
  } else {
1410
- new_kb.scrape_type = body.scrape_type;
1411
- new_kb.scrape_options = body.scrape_options;
1427
+ new_kb.scrape_type = scrape_type;
1428
+ new_kb.scrape_options = scrape_options;
1412
1429
  }
1413
1430
  }
1414
1431
 
1432
+ if (tags && Array.isArray(tags) && tags.every(tag => typeof tag === "string")) {
1433
+ new_kb.tags = tags;
1434
+ }
1435
+
1415
1436
  winston.debug("adding kb: ", new_kb);
1416
1437
 
1417
- KB.findOneAndUpdate({ id_project: project_id, type: 'url', source: new_kb.source }, new_kb, { upsert: true, new: true, rawResult: true }, async (err, raw_content) => {
1438
+ KB.findOneAndUpdate({ id_project, type, source }, new_kb, { upsert: true, new: true, rawResult: true }, async (err, raw_content) => {
1418
1439
  if (err) {
1419
1440
  winston.error("findOneAndUpdate with upsert error: ", err);
1420
1441
  res.status(500).send({ success: false, error: err });
@@ -1425,44 +1446,33 @@ router.post('/', async (req, res) => {
1425
1446
  delete raw_content.$clusterTime;
1426
1447
  delete raw_content.operationTime;
1427
1448
 
1428
- let saved_kb = raw_content.value;
1429
- let webhook = apiUrl + '/webhook/kb/status?token=' + KB_WEBHOOK_TOKEN;
1449
+ const saved_kb = raw_content.value;
1450
+ const webhook = apiUrl + '/webhook/kb/status?token=' + KB_WEBHOOK_TOKEN;
1451
+ const embedding = normalizeEmbedding(namespace.embedding);
1452
+ embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
1430
1453
 
1431
- let json = {
1454
+ const json = {
1432
1455
  id: saved_kb._id,
1433
1456
  type: saved_kb.type,
1434
1457
  source: saved_kb.source,
1435
- content: "",
1458
+ content: saved_kb.content || "",
1436
1459
  namespace: saved_kb.namespace,
1437
- webhook: webhook
1460
+ webhook: webhook,
1461
+ hybrid: namespace.hybrid,
1462
+ engine: namespace.engine || default_engine,
1463
+ embedding: embedding,
1464
+ ...(saved_kb.scrape_type && { scrape_type: saved_kb.scrape_type }),
1465
+ ...(saved_kb.scrape_options && { parameters_scrape_type_4: saved_kb.scrape_options }),
1466
+ ...(saved_kb.tags && { tags: saved_kb.tags }),
1438
1467
  }
1439
- winston.debug("json: ", json);
1440
1468
 
1441
- if (saved_kb.content) {
1442
- json.content = saved_kb.content;
1443
- }
1444
- if (saved_kb.scrape_type) {
1445
- json.scrape_type = saved_kb.scrape_type;
1446
- }
1447
- if (saved_kb.scrape_options) {
1448
- json.parameters_scrape_type_4 = saved_kb.scrape_options;
1449
- }
1450
- json.engine = namespace.engine || default_engine;
1451
- json.hybrid = namespace.hybrid;
1452
-
1453
- let embedding = namespace.embedding || default_embedding;
1454
- embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
1455
- json.embedding = embedding;
1456
-
1457
- let resources = [];
1469
+ winston.debug("json: ", json);
1458
1470
 
1459
- resources.push(json);
1460
-
1461
1471
  if (process.env.NODE_ENV === 'test') {
1462
1472
  return res.status(200).send({ success: true, message: "Schedule scrape skipped in test environment", data: raw_content, schedule_json: json });
1463
1473
  }
1464
1474
 
1465
- aiManager.scheduleScrape(resources, namespace.hybrid);
1475
+ aiManager.scheduleScrape([json], namespace.hybrid);
1466
1476
  return res.status(200).send(raw_content);
1467
1477
 
1468
1478
  }
@@ -1480,30 +1490,37 @@ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
1480
1490
  list = req.body.list;
1481
1491
  }
1482
1492
 
1483
- let project_id = req.projectid;
1484
- let refresh_rate = req.body.refresh_rate;
1485
- let scrape_type = req.body.scrape_type ?? 2;
1486
- let scrape_options = req.body.scrape_options;
1487
- if (scrape_type === 2 && scrape_options == null) {
1488
- scrape_options = aiManager.setDefaultScrapeOptions();
1493
+ const id_project = req.projectid;
1494
+ const project = req.project;
1495
+ let { refresh_rate = 'never', scrape_type = 2, scrape_options } = req.body;
1496
+ let tags = parseStringArrayField(req.body.tags);
1497
+
1498
+
1499
+ if (scrape_type === 2 && !scrape_options) {
1500
+ try {
1501
+ scrape_options = aiManager.setDefaultScrapeOptions();
1502
+ } catch (err) {
1503
+ winston.error("Error setting default scrape options: ", err);
1504
+ return res.status(500).send({ success: false, error: err.error });
1505
+ }
1489
1506
  }
1490
1507
 
1491
- let namespace_id = req.query.namespace;
1508
+ const namespace_id = req.query.namespace;
1492
1509
  if (!namespace_id) {
1493
1510
  return res.status(400).send({ success: false, error: "queryParam 'namespace' is not defined" })
1494
1511
  }
1495
-
1496
1512
  let namespace;
1497
1513
  try {
1498
- namespace = await aiManager.checkNamespace(project_id, namespace_id);
1514
+ namespace = await aiManager.checkNamespace(id_project, namespace_id);
1499
1515
  } catch (err) {
1516
+ winston.error("Error checking namespace: ", err);
1500
1517
  let errorCode = err?.errorCode ?? 500;
1501
1518
  return res.status(errorCode).send({ success: false, error: err.error });
1502
1519
  }
1503
1520
 
1504
- let quoteManager = req.app.get('quote_manager');
1521
+ const quoteManager = req.app.get('quote_manager');
1505
1522
  try {
1506
- await aiManager.checkQuotaAvailability(quoteManager, req.project, list.length)
1523
+ await aiManager.checkQuotaAvailability(quoteManager, project, list.length)
1507
1524
  } catch(err) {
1508
1525
  let errorCode = err?.errorCode ?? 500;
1509
1526
  return res.status(errorCode).send({ success: false, error: err.error, plan_limit: err.plan_limit })
@@ -1515,14 +1532,14 @@ router.post('/multi', upload.single('uploadFile'), async (req, res) => {
1515
1532
  }
1516
1533
 
1517
1534
  const options = {
1518
- scrape_type: scrape_type,
1519
- scrape_options: scrape_options,
1520
- refresh_rate: refresh_rate
1535
+ scrape_type,
1536
+ scrape_options,
1537
+ refresh_rate,
1538
+ ...(Array.isArray(tags) && tags.length > 0 ? { tags } : {})
1521
1539
  }
1522
1540
 
1523
- let result;
1524
1541
  try {
1525
- result = await aiManager.addMultipleUrls(namespace, list, options);
1542
+ const result = await aiManager.addMultipleUrls(namespace, list, options);
1526
1543
  return res.status(200).send(result);
1527
1544
  } catch (err) {
1528
1545
  winston.error("addMultipleUrls error: ", err)
@@ -1539,8 +1556,9 @@ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
1539
1556
  let csv = req.file.buffer.toString('utf8');
1540
1557
  winston.debug("csv: ", csv);
1541
1558
 
1542
- let delimiter = req.body.delimiter || ";";
1543
- winston.debug("delimiter: ", delimiter);
1559
+ const { delimiter = ';' } = req.body;
1560
+ let tags = parseStringArrayField(req.body.tags);
1561
+
1544
1562
 
1545
1563
  let namespace;
1546
1564
  try {
@@ -1567,14 +1585,15 @@ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
1567
1585
  type: 'faq',
1568
1586
  content: question + "\n" + answer,
1569
1587
  namespace: namespace_id,
1570
- status: -1
1588
+ status: -1,
1589
+ ...(Array.isArray(tags) && tags.length > 0 ? { tags } : {})
1571
1590
  })
1572
1591
  })
1573
1592
  .on("end", async () => {
1574
1593
  winston.debug("kbs after CSV parsing: ", kbs);
1575
1594
 
1595
+ const quoteManager = req.app.get('quote_manager');
1576
1596
  try {
1577
- let quoteManager = req.app.get('quote_manager');
1578
1597
  await aiManager.checkQuotaAvailability(quoteManager, req.project, kbs.length)
1579
1598
  } catch(err) {
1580
1599
  let errorCode = err?.errorCode ?? 500;
@@ -1595,7 +1614,7 @@ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
1595
1614
  aiManager.saveBulk(operations, kbs, project_id, namespace_id).then((result) => {
1596
1615
 
1597
1616
  let engine = namespace.engine || default_engine;
1598
- let embedding = namespace.embedding || default_embedding;
1617
+ let embedding = normalizeEmbedding(namespace.embedding);
1599
1618
  embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
1600
1619
  let hybrid = namespace.hybrid;
1601
1620
 
@@ -1648,11 +1667,15 @@ router.post('/sitemap', async (req, res) => {
1648
1667
 
1649
1668
  router.post('/sitemap/import', async (req, res) => {
1650
1669
 
1651
- let project_id = req.projectid;
1652
- let namespace_id = req.query.namespace;
1653
- let content = req.body;
1670
+ const id_project = req.projectid;
1671
+ const namespace_id = req.query.namespace;
1654
1672
 
1655
- if (content.type !== "sitemap") {
1673
+ let { type, source, refresh_rate = 'never', scrape_type = 2, scrape_options, tags } = req.body;
1674
+ if (scrape_type === 2 && !scrape_options) {
1675
+ scrape_options = aiManager.setDefaultScrapeOptions();
1676
+ }
1677
+
1678
+ if (type !== "sitemap") {
1656
1679
  return res.status(403).send({success: false, error: "Endpoint available for sitemap type only." });
1657
1680
  }
1658
1681
 
@@ -1662,13 +1685,12 @@ router.post('/sitemap/import', async (req, res) => {
1662
1685
 
1663
1686
  let namespace;
1664
1687
  try {
1665
- namespace = await aiManager.checkNamespace(project_id, namespace_id);
1688
+ namespace = await aiManager.checkNamespace(id_project, namespace_id);
1666
1689
  } catch (err) {
1667
1690
  let errorCode = err?.errorCode ?? 500;
1668
1691
  return res.status(errorCode).send({ success: false, error: err.error });
1669
1692
  }
1670
1693
 
1671
- let sitemap_url = req.body.source;
1672
1694
 
1673
1695
  // let quoteManager = req.app.get('quote_manager');
1674
1696
  // let limits = await quoteManager.getPlanLimits(req.project);
@@ -1679,7 +1701,7 @@ router.post('/sitemap/import', async (req, res) => {
1679
1701
  // winston.verbose("Kbs count: " + kbs_count);
1680
1702
 
1681
1703
  const sitemap = new Sitemapper({
1682
- url: sitemap_url,
1704
+ url: source,
1683
1705
  timeout: 15000,
1684
1706
  debug: false
1685
1707
  });
@@ -1704,41 +1726,34 @@ router.post('/sitemap/import', async (req, res) => {
1704
1726
  // return res.status(403).send({ success: false, error: "Cannot exceed the number of resources in the current plan", plan_limit: kbs_limit })
1705
1727
  // }
1706
1728
 
1707
- let refresh_rate = req.body.refresh_rate;
1708
- let scrape_type = req.body.scrape_type ?? 2;
1709
- let scrape_options = req.body.scrape_options;
1710
- if (scrape_type === 2 && scrape_options == null) {
1711
- scrape_options = aiManager.setDefaultScrapeOptions();
1712
- }
1713
-
1714
1729
  let sitemap_content = {
1715
- id_project: project_id,
1716
- name: sitemap_url,
1717
- source: sitemap_url,
1730
+ id_project,
1731
+ name: source,
1732
+ source: source,
1718
1733
  type: 'sitemap',
1719
1734
  content: "",
1720
1735
  namespace: namespace_id,
1721
- scrape_type: scrape_type,
1722
- scrape_options: scrape_options,
1723
- refresh_rate: refresh_rate
1736
+ scrape_type,
1737
+ scrape_options,
1738
+ refresh_rate,
1739
+ ...(Array.isArray(tags) && tags.length > 0 ? { tags } : {})
1724
1740
  }
1725
1741
 
1726
1742
  let saved_content;
1727
1743
  try {
1728
- saved_content = await KB.findOneAndUpdate({ id_project: project_id, type: 'sitemap', source: sitemap_url, namespace: namespace_id }, sitemap_content, { upsert: true, new: true }).lean().exec();
1744
+ saved_content = await KB.findOneAndUpdate({ id_project, type: 'sitemap', source, namespace: namespace_id }, sitemap_content, { upsert: true, new: true }).lean().exec();
1729
1745
  } catch (err) {
1730
1746
  winston.error("Error saving content: ", err);
1731
1747
  return res.status(500).send({ success: false, error: err });
1732
1748
  }
1733
1749
 
1734
-
1735
-
1736
1750
  const options = {
1737
1751
  sitemap_origin_id: saved_content._id,
1738
1752
  sitemap_origin: saved_content.source,
1739
- scrape_type: saved_content.scrape_type,
1740
- scrape_options: saved_content.scrape_options,
1741
- refresh_rate: saved_content.refresh_rate
1753
+ scrape_type,
1754
+ scrape_options,
1755
+ refresh_rate,
1756
+ ...(Array.isArray(tags) && tags.length > 0 ? { tags } : {})
1742
1757
  }
1743
1758
 
1744
1759
  try {
@@ -1758,38 +1773,181 @@ router.post('/sitemap/import', async (req, res) => {
1758
1773
 
1759
1774
  router.put('/:kb_id', async (req, res) => {
1760
1775
 
1761
- let kb_id = req.params.kb_id;
1762
- winston.verbose("update kb_id " + kb_id);
1776
+ const id_project = req.projectid;
1777
+ const project = req.project;
1778
+ const kb_id = req.params.kb_id;
1779
+
1780
+ const { name, type, source, content, refresh_rate, scrape_type, scrape_options, tags } = req.body;
1781
+ const namespace_id = req.body.namespace;
1763
1782
 
1764
- let update = {};
1783
+ if (!namespace_id) {
1784
+ return res.status(400).send({ success: false, error: "Missing 'namespace' body parameter" })
1785
+ }
1765
1786
 
1766
- if (req.body.name != undefined) {
1767
- update.name = req.body.name;
1787
+ let namespace;
1788
+ try {
1789
+ namespace = await aiManager.checkNamespace(id_project, namespace_id);
1790
+ } catch (err) {
1791
+ let errorCode = err?.errorCode ?? 500;
1792
+ return res.status(errorCode).send({ success: false, error: err.error });
1768
1793
  }
1769
1794
 
1770
- if (req.body.status != undefined) {
1771
- update.status = req.body.status;
1795
+ let kb = await KB.findOne({ id_project, namespace: namespace_id, _id: kb_id }).lean().exec();
1796
+
1797
+ if (!kb) {
1798
+ return res.status(404).send({ success: false, error: "Content not found. Unable to update a non-existing content" })
1772
1799
  }
1773
1800
 
1774
- winston.debug("kb update: ", update);
1801
+ let data = {
1802
+ id: kb._id,
1803
+ namespace: namespace_id,
1804
+ engine: namespace.engine || default_engine
1805
+ }
1775
1806
 
1776
- KB.findByIdAndUpdate(kb_id, update, { new: true }, (err, savedKb) => {
1807
+ // if (kb.type === 'sitemap') {
1808
+ // let new_sitemap = {
1809
+ // id_project,
1810
+ // name,
1811
+ // source,
1812
+ // type: 'sitemap',
1813
+ // content: "",
1814
+ // namespace: namespace_id,
1815
+ // status: -1,
1816
+ // scrape_type,
1817
+ // scrape_options,
1818
+ // refresh_rate,
1819
+ // ...(Array.isArray(tags) && tags.length > 0 ? { tags } : {})
1820
+ // }
1777
1821
 
1778
- if (err) {
1779
- winston.error("KB findByIdAndUpdate error: ", err);
1780
- return res.status(500).send({ success: false, error: err });
1822
+ // try {
1823
+ // let result = await aiManager.updateSitemap(id_project, namespace, kb, new_sitemap);
1824
+ // return res.status(200).send(result);
1825
+ // } catch (err) {
1826
+ // winston.error("Error updating sitemap: ", err);
1827
+ // return res.status(500).send({ success: false, error: err });
1828
+ // }
1829
+ // }
1830
+
1831
+ try {
1832
+ let delete_response = await aiService.deleteIndex(data);
1833
+
1834
+ if (delete_response.data.success === true) {
1835
+ await KB.findOneAndDelete({ id_project, namespace: namespace_id, source }).lean().exec();
1836
+ // continue the flow
1837
+ } else {
1838
+ winston.error("Unable to update content due to an error: ", delete_response.data.error);
1839
+ return res.status(500).send({ success: false, error: delete_response.data.error });
1781
1840
  }
1782
1841
 
1783
- if (!savedKb) {
1784
- winston.debug("Try to updating a non-existing kb");
1785
- return res.status(400).send({ success: false, message: "Content not found" })
1842
+ } catch (err) {
1843
+ winston.error("Error updating content: ", err);
1844
+ return res.status(500).send({ success: false, error: err });
1845
+ }
1846
+
1847
+ let new_content = {
1848
+ id_project,
1849
+ name,
1850
+ type,
1851
+ source,
1852
+ content,
1853
+ namespace: namespace_id,
1854
+ status: -1,
1855
+ }
1856
+
1857
+ if (new_content.type === 'url') {
1858
+ new_content.refresh_rate = refresh_rate || 'never';
1859
+ if (!scrape_type || scrape_type === 2) {
1860
+ new_content.scrape_type = 2;
1861
+ new_content.scrape_options = aiManager.setDefaultScrapeOptions();
1862
+ } else {
1863
+ new_content.scrape_type = scrape_type;
1864
+ new_content.scrape_options = scrape_options;
1786
1865
  }
1866
+ }
1787
1867
 
1788
- res.status(200).send(savedKb)
1789
- })
1868
+ if (kb.sitemap_origin_id) {
1869
+ new_content.sitemap_origin_id = kb.sitemap_origin_id;
1870
+ new_content.sitemap_origin = kb.sitemap_origin;
1871
+ }
1872
+
1873
+ if (tags && Array.isArray(tags) && tags.every(tag => typeof tag === "string")) {
1874
+ new_content.tags = tags;
1875
+ }
1876
+
1877
+ winston.debug("Update content. New content: ", new_content);
1878
+
1879
+ let updated_content;
1880
+ try {
1881
+ updated_content = await KB.findOneAndUpdate({ id_project, namespace: namespace_id, source }, new_content, { upsert: true, new: true }).lean().exec();
1882
+ } catch (err) {
1883
+ winston.error("Error updating content: ", err);
1884
+ return res.status(500).send({ success: false, error: err });
1885
+ }
1886
+
1887
+ const embedding = normalizeEmbedding(namespace.embedding);
1888
+ embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
1889
+ let webhook = apiUrl + '/webhook/kb/status?token=' + KB_WEBHOOK_TOKEN;
1890
+
1891
+ const json = {
1892
+ id: updated_content._id,
1893
+ type: updated_content.type,
1894
+ source: updated_content.source,
1895
+ content: updated_content.content || "",
1896
+ namespace: updated_content.namespace,
1897
+ webhook: webhook,
1898
+ hybrid: namespace.hybrid,
1899
+ engine: namespace.engine || default_engine,
1900
+ embedding: embedding,
1901
+ ...(updated_content.scrape_type && { scrape_type: updated_content.scrape_type }),
1902
+ ...(updated_content.scrape_options && { parameters_scrape_type_4: updated_content.scrape_options }),
1903
+ ...(updated_content.tags && { tags: updated_content.tags }),
1904
+ }
1905
+
1906
+ winston.debug("json: ", json);
1907
+
1908
+ if (process.env.NODE_ENV === 'test') {
1909
+ return res.status(200).send({ success: true, message: "Schedule scrape skipped in test environment", data: updated_content, schedule_json: json });
1910
+ }
1911
+
1912
+ aiManager.scheduleScrape([json], namespace.hybrid);
1913
+ return res.status(200).send(updated_content);
1790
1914
 
1791
1915
  })
1792
1916
 
1917
+ // router.put('/:kb_id', async (req, res) => {
1918
+
1919
+ // let kb_id = req.params.kb_id;
1920
+ // winston.verbose("update kb_id " + kb_id);
1921
+
1922
+ // let update = {};
1923
+
1924
+ // if (req.body.name != undefined) {
1925
+ // update.name = req.body.name;
1926
+ // }
1927
+
1928
+ // if (req.body.status != undefined) {
1929
+ // update.status = req.body.status;
1930
+ // }
1931
+
1932
+ // winston.debug("kb update: ", update);
1933
+
1934
+ // KB.findByIdAndUpdate(kb_id, update, { new: true }, (err, savedKb) => {
1935
+
1936
+ // if (err) {
1937
+ // winston.error("KB findByIdAndUpdate error: ", err);
1938
+ // return res.status(500).send({ success: false, error: err });
1939
+ // }
1940
+
1941
+ // if (!savedKb) {
1942
+ // winston.debug("Try to updating a non-existing kb");
1943
+ // return res.status(400).send({ success: false, message: "Content not found" })
1944
+ // }
1945
+
1946
+ // res.status(200).send(savedKb)
1947
+ // })
1948
+
1949
+ // })
1950
+
1793
1951
  router.delete('/:kb_id', async (req, res) => {
1794
1952
 
1795
1953
  let project_id = req.projectid;