@tiledesk/tiledesk-server 2.19.5 → 2.19.6
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/CHANGELOG.md +5 -1
- package/models/kb_setting.js +2 -99
- package/package.json +1 -1
- package/routes/kb.js +12 -21
- package/routes/unanswered.js +2 -2
- package/routes/webhook.js +1 -2
- package/services/aiManager.js +13 -4
- package/test/kbRoute.js +148 -7
package/CHANGELOG.md
CHANGED
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
|
7
7
|
|
|
8
|
-
# 2.19.
|
|
8
|
+
# 2.19.6
|
|
9
|
+
- Improved management of answered and unanswered questions, duration and token consumption
|
|
10
|
+
- Improved namespace embedding management
|
|
11
|
+
|
|
12
|
+
# 2.19.5 (aborted)
|
|
9
13
|
- Improved management of answered and unanswered questions, duration and token consumption
|
|
10
14
|
|
|
11
15
|
# 2.19.4
|
package/models/kb_setting.js
CHANGED
|
@@ -20,67 +20,6 @@ let expireAnsweredAfterSeconds = ttlSecondsFromEnv(
|
|
|
20
20
|
DEFAULT_ANSWERED_TTL_SEC
|
|
21
21
|
);
|
|
22
22
|
|
|
23
|
-
const EMPTY_EMBEDDING_API_KEY = '';
|
|
24
|
-
|
|
25
|
-
function logEmbeddingApiKeyWriteAttempt(source, attemptedValue, meta = {}) {
|
|
26
|
-
if (attemptedValue === EMPTY_EMBEDDING_API_KEY || attemptedValue == null) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
winston.warn('[Namespace.embedding.api_key] non-empty value blocked on ' + source, {
|
|
30
|
-
...meta,
|
|
31
|
-
attemptedValue,
|
|
32
|
-
stack: new Error().stack
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function sanitizeEmbeddingApiKeyObject(embedding, source, meta = {}) {
|
|
37
|
-
if (!embedding || typeof embedding !== 'object') {
|
|
38
|
-
return false;
|
|
39
|
-
}
|
|
40
|
-
if (!Object.prototype.hasOwnProperty.call(embedding, 'api_key')) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
if (embedding.api_key === EMPTY_EMBEDDING_API_KEY || embedding.api_key == null) {
|
|
44
|
-
embedding.api_key = EMPTY_EMBEDDING_API_KEY;
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
logEmbeddingApiKeyWriteAttempt(source, embedding.api_key, meta);
|
|
48
|
-
embedding.api_key = EMPTY_EMBEDDING_API_KEY;
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function sanitizeEmbeddingApiKeyUpdate(update, source, meta = {}) {
|
|
53
|
-
if (!update || typeof update !== 'object') {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let changed = false;
|
|
58
|
-
|
|
59
|
-
const sanitizeContainer = (container) => {
|
|
60
|
-
if (!container || typeof container !== 'object') {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
if (sanitizeEmbeddingApiKeyObject(container.embedding, source, meta)) {
|
|
64
|
-
changed = true;
|
|
65
|
-
}
|
|
66
|
-
if (Object.prototype.hasOwnProperty.call(container, 'embedding.api_key')
|
|
67
|
-
&& container['embedding.api_key'] !== EMPTY_EMBEDDING_API_KEY) {
|
|
68
|
-
logEmbeddingApiKeyWriteAttempt(source, container['embedding.api_key'], meta);
|
|
69
|
-
container['embedding.api_key'] = EMPTY_EMBEDDING_API_KEY;
|
|
70
|
-
changed = true;
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
sanitizeContainer(update);
|
|
75
|
-
['$set', '$setOnInsert'].forEach((key) => {
|
|
76
|
-
if (update[key]) {
|
|
77
|
-
sanitizeContainer(update[key]);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
return changed;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
23
|
|
|
85
24
|
const EngineSchema = new Schema({
|
|
86
25
|
name: {
|
|
@@ -139,11 +78,8 @@ const EmbeddingSchema = new Schema({
|
|
|
139
78
|
api_key: {
|
|
140
79
|
type: String,
|
|
141
80
|
required: false,
|
|
142
|
-
default:
|
|
143
|
-
set:
|
|
144
|
-
logEmbeddingApiKeyWriteAttempt('embedding.api_key setter', value);
|
|
145
|
-
return EMPTY_EMBEDDING_API_KEY;
|
|
146
|
-
}
|
|
81
|
+
default: '',
|
|
82
|
+
set: () => ''
|
|
147
83
|
}
|
|
148
84
|
}, {
|
|
149
85
|
_id: false // This is schema is always used as an embedded object inside NamespaceSchema
|
|
@@ -186,39 +122,6 @@ const NamespaceSchema = new Schema({
|
|
|
186
122
|
timestamps: true
|
|
187
123
|
})
|
|
188
124
|
|
|
189
|
-
NamespaceSchema.pre('save', function (next) {
|
|
190
|
-
if (this.isModified('embedding.api_key')) {
|
|
191
|
-
const attemptedValue = this.get('embedding.api_key');
|
|
192
|
-
logEmbeddingApiKeyWriteAttempt('save', attemptedValue, {
|
|
193
|
-
namespaceId: this.id,
|
|
194
|
-
id_project: this.id_project
|
|
195
|
-
});
|
|
196
|
-
this.set('embedding.api_key', EMPTY_EMBEDDING_API_KEY);
|
|
197
|
-
}
|
|
198
|
-
next();
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
['updateOne', 'updateMany', 'findOneAndUpdate'].forEach((hook) => {
|
|
202
|
-
NamespaceSchema.pre(hook, function (next) {
|
|
203
|
-
const update = this.getUpdate();
|
|
204
|
-
if (sanitizeEmbeddingApiKeyUpdate(update, hook, { query: this.getQuery() })) {
|
|
205
|
-
this.setUpdate(update);
|
|
206
|
-
}
|
|
207
|
-
next();
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
NamespaceSchema.pre('insertMany', function (next, docs) {
|
|
212
|
-
if (Array.isArray(docs)) {
|
|
213
|
-
docs.forEach((doc) => {
|
|
214
|
-
sanitizeEmbeddingApiKeyObject(doc.embedding, 'insertMany', {
|
|
215
|
-
namespaceId: doc.id,
|
|
216
|
-
id_project: doc.id_project
|
|
217
|
-
});
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
next();
|
|
221
|
-
});
|
|
222
125
|
|
|
223
126
|
var KBSchema = new Schema({
|
|
224
127
|
id_project: {
|
package/package.json
CHANGED
package/routes/kb.js
CHANGED
|
@@ -115,13 +115,6 @@ function getRagContextTemplate(modelName) {
|
|
|
115
115
|
return ragPromptManager.getPrompt(modelName);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
function normalizeEmbedding(embedding) {
|
|
119
|
-
const normalizedEmbedding = (embedding && typeof embedding.toObject === 'function')
|
|
120
|
-
? embedding.toObject()
|
|
121
|
-
: (embedding || default_embedding);
|
|
122
|
-
return { ...normalizedEmbedding };
|
|
123
|
-
}
|
|
124
|
-
|
|
125
118
|
function normalizeSituatedContext(enable = false) {
|
|
126
119
|
situatedContext.enable = enable;
|
|
127
120
|
return situatedContext.enable
|
|
@@ -264,8 +257,7 @@ router.post('/scrape/single', async (req, res) => {
|
|
|
264
257
|
}
|
|
265
258
|
|
|
266
259
|
json.engine = namespace.engine || default_engine;
|
|
267
|
-
json.embedding = normalizeEmbedding(namespace.embedding);
|
|
268
|
-
json.embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
260
|
+
json.embedding = aiManager.normalizeEmbedding(namespace.embedding);
|
|
269
261
|
|
|
270
262
|
if (namespace.hybrid === true) {
|
|
271
263
|
json.hybrid = true;
|
|
@@ -412,8 +404,7 @@ router.post('/qa', async (req, res) => {
|
|
|
412
404
|
}
|
|
413
405
|
|
|
414
406
|
data.engine = namespace.engine || default_engine;
|
|
415
|
-
data.embedding = normalizeEmbedding(namespace.embedding);
|
|
416
|
-
data.embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
407
|
+
data.embedding = aiManager.normalizeEmbedding(namespace.embedding);
|
|
417
408
|
|
|
418
409
|
if (namespace.hybrid === true) {
|
|
419
410
|
data.search_type = 'hybrid';
|
|
@@ -1298,8 +1289,7 @@ router.post('/namespace/import/:id', upload.single('uploadFile'), async (req, re
|
|
|
1298
1289
|
// import operation the content's limit is respected
|
|
1299
1290
|
let ns = namespaces.find(n => n.id === namespace_id);
|
|
1300
1291
|
let engine = ns.engine || default_engine;
|
|
1301
|
-
let embedding = normalizeEmbedding(ns.embedding);
|
|
1302
|
-
embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
1292
|
+
let embedding = aiManager.normalizeEmbedding(ns.embedding);
|
|
1303
1293
|
let hybrid = ns.hybrid;
|
|
1304
1294
|
const situated_context = normalizeSituatedContext();
|
|
1305
1295
|
|
|
@@ -1355,6 +1345,10 @@ router.post('/namespace/import/:id', upload.single('uploadFile'), async (req, re
|
|
|
1355
1345
|
aiManager.scheduleScrape(resources, hybrid);
|
|
1356
1346
|
}
|
|
1357
1347
|
|
|
1348
|
+
if (process.env.NODE_ENV === "test") {
|
|
1349
|
+
return res.status(200).send({ success: true, message: "Contents imported successfully", schedule_json: resources });
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1358
1352
|
res.status(200).send({ success: true, message: "Contents imported successfully" });
|
|
1359
1353
|
|
|
1360
1354
|
|
|
@@ -1731,8 +1725,7 @@ router.post('/', async (req, res) => {
|
|
|
1731
1725
|
|
|
1732
1726
|
const saved_kb = raw_content.value;
|
|
1733
1727
|
const webhook = apiUrl + '/webhook/kb/status?token=' + KB_WEBHOOK_TOKEN;
|
|
1734
|
-
const embedding = normalizeEmbedding(namespace.embedding);
|
|
1735
|
-
embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
1728
|
+
const embedding = aiManager.normalizeEmbedding(namespace.embedding);
|
|
1736
1729
|
|
|
1737
1730
|
const situated_context_obj = normalizeSituatedContext(saved_kb.situated_context);
|
|
1738
1731
|
|
|
@@ -1908,8 +1901,7 @@ router.post('/csv', upload.single('uploadFile'), async (req, res) => {
|
|
|
1908
1901
|
aiManager.saveBulk(operations, kbs, project_id, namespace_id).then((result) => {
|
|
1909
1902
|
|
|
1910
1903
|
let engine = namespace.engine || default_engine;
|
|
1911
|
-
let embedding = normalizeEmbedding(namespace.embedding);
|
|
1912
|
-
embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
1904
|
+
let embedding = aiManager.normalizeEmbedding(namespace.embedding);
|
|
1913
1905
|
let hybrid = namespace.hybrid;
|
|
1914
1906
|
|
|
1915
1907
|
let situated_context_obj;
|
|
@@ -1965,7 +1957,7 @@ router.post('/sitemap', async (req, res) => {
|
|
|
1965
1957
|
winston.debug("data: ", data);
|
|
1966
1958
|
res.status(200).send(data);
|
|
1967
1959
|
}).catch((err) => {
|
|
1968
|
-
|
|
1960
|
+
winston.error("Error fetching sitemap: ", err)
|
|
1969
1961
|
res.status(500).send({ success: false, error: err });
|
|
1970
1962
|
})
|
|
1971
1963
|
|
|
@@ -2202,8 +2194,7 @@ router.put('/:kb_id', async (req, res) => {
|
|
|
2202
2194
|
return res.status(500).send({ success: false, error: err });
|
|
2203
2195
|
}
|
|
2204
2196
|
|
|
2205
|
-
const embedding = normalizeEmbedding(namespace.embedding);
|
|
2206
|
-
embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
2197
|
+
const embedding = aiManager.normalizeEmbedding(namespace.embedding);
|
|
2207
2198
|
let webhook = apiUrl + '/webhook/kb/status?token=' + KB_WEBHOOK_TOKEN;
|
|
2208
2199
|
const situated_context_obj = normalizeSituatedContext(updated_content.situated_context);
|
|
2209
2200
|
|
|
@@ -2263,7 +2254,7 @@ router.delete('/:kb_id', async (req, res) => {
|
|
|
2263
2254
|
if (kb.type === 'sitemap') {
|
|
2264
2255
|
try {
|
|
2265
2256
|
await aiManager.deleteSitemap(kb, namespace);
|
|
2266
|
-
|
|
2257
|
+
winston.info("Scheduled jobs for deleting sitemap");
|
|
2267
2258
|
//return res.status(200).send({ success: true, message: "Scheduled jobs for deleting sitemap" });
|
|
2268
2259
|
} catch (err) {
|
|
2269
2260
|
winston.error("Error deleting sitemap: ", err);
|
package/routes/unanswered.js
CHANGED
|
@@ -3,7 +3,7 @@ const router = express.Router();
|
|
|
3
3
|
const { Namespace, UnansweredQuestion } = require('../models/kb_setting');
|
|
4
4
|
var winston = require('../config/winston');
|
|
5
5
|
var fastCsv = require('fast-csv');
|
|
6
|
-
const
|
|
6
|
+
const kbQuestionService = require('../services/kbQuestionService');
|
|
7
7
|
|
|
8
8
|
// Add a new unanswered question
|
|
9
9
|
router.post('/', async (req, res) => {
|
|
@@ -11,7 +11,7 @@ router.post('/', async (req, res) => {
|
|
|
11
11
|
const data = req.body;
|
|
12
12
|
const id_project = req.projectid;
|
|
13
13
|
|
|
14
|
-
const savedQuestion = await
|
|
14
|
+
const savedQuestion = await kbQuestionService.createUnansweredQuestion(
|
|
15
15
|
id_project,
|
|
16
16
|
data
|
|
17
17
|
);
|
package/routes/webhook.js
CHANGED
|
@@ -199,8 +199,7 @@ router.post('/kb/reindex', async (req, res) => {
|
|
|
199
199
|
json.engine = namespace.engine || (namespace.hybrid ? default_engine_hybrid : default_engine);
|
|
200
200
|
json.hybrid = namespace.hybrid;
|
|
201
201
|
|
|
202
|
-
let embedding = namespace.embedding
|
|
203
|
-
embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
202
|
+
let embedding = aiManager.normalizeEmbedding(namespace.embedding);
|
|
204
203
|
json.embedding = embedding;
|
|
205
204
|
|
|
206
205
|
const situated_context_obj = aiManager.normalizeSituatedContext(kb.situated_context);
|
package/services/aiManager.js
CHANGED
|
@@ -95,8 +95,7 @@ class AiManager {
|
|
|
95
95
|
this.saveBulk(operations, kbs, namespace.id_project, namespace.id).then( async (result) => {
|
|
96
96
|
let hybrid = namespace.hybrid;
|
|
97
97
|
let engine = namespace.engine || default_engine;
|
|
98
|
-
let embedding = namespace.embedding
|
|
99
|
-
embedding.api_key = process.env.EMBEDDING_API_KEY || process.env.GPTKEY;
|
|
98
|
+
let embedding = this.normalizeEmbedding(namespace.embedding);
|
|
100
99
|
|
|
101
100
|
let situated_context;
|
|
102
101
|
if (options.situated_context) {
|
|
@@ -146,7 +145,7 @@ class AiManager {
|
|
|
146
145
|
namespace: namespace.id,
|
|
147
146
|
refresh_rate: options.refresh_rate,
|
|
148
147
|
engine: namespace.engine,
|
|
149
|
-
embedding: namespace.embedding,
|
|
148
|
+
embedding: this.normalizeEmbedding(namespace.embedding),
|
|
150
149
|
hybrid: namespace.hybrid,
|
|
151
150
|
...(options.situated_context && { situated_context: options.situated_context }),
|
|
152
151
|
}
|
|
@@ -449,7 +448,7 @@ class AiManager {
|
|
|
449
448
|
if (err) {
|
|
450
449
|
winston.error("deleteSitemap: deleteSchedule error for kb " + kb._id, err);
|
|
451
450
|
}
|
|
452
|
-
|
|
451
|
+
winston.info("deleteSitemap: deleteSchedule result for kb " + kb._id, result);
|
|
453
452
|
resolve(result);
|
|
454
453
|
});
|
|
455
454
|
});
|
|
@@ -597,6 +596,16 @@ class AiManager {
|
|
|
597
596
|
})
|
|
598
597
|
}
|
|
599
598
|
|
|
599
|
+
normalizeEmbedding(embedding) {
|
|
600
|
+
const normalizedEmbedding = (embedding && typeof embedding.toObject === 'function')
|
|
601
|
+
? embedding.toObject()
|
|
602
|
+
: (embedding || default_embedding);
|
|
603
|
+
return {
|
|
604
|
+
...normalizedEmbedding,
|
|
605
|
+
api_key: process.env.EMBEDDING_API_KEY || process.env.GPTKEY
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
600
609
|
normalizeSituatedContext(enable = false) {
|
|
601
610
|
situatedContext.enable = enable;
|
|
602
611
|
return situatedContext.enable
|
package/test/kbRoute.js
CHANGED
|
@@ -8,6 +8,7 @@ process.env.PINECONE_TYPE = "serverless";
|
|
|
8
8
|
process.env.PINECONE_INDEX_HYBRID = "test-index-hybrid";
|
|
9
9
|
process.env.PINECONE_TYPE_HYBRID = "serverless";
|
|
10
10
|
process.env.ADMIN_EMAIL = "admin@tiledesk.com";
|
|
11
|
+
process.env.KB_ENDPOINT_TRAIN = "http://kb-train.test";
|
|
11
12
|
|
|
12
13
|
var userService = require('../services/userService');
|
|
13
14
|
var projectService = require('../services/projectService');
|
|
@@ -27,6 +28,8 @@ const path = require('path');
|
|
|
27
28
|
const mongoose = require('mongoose');
|
|
28
29
|
const nock = require('nock');
|
|
29
30
|
const faq = require('../models/faq');
|
|
31
|
+
const { Namespace } = require('../models/kb_setting');
|
|
32
|
+
const default_engine = require('../config/kb/engine');
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
// chai.config.includeStack = true;
|
|
@@ -85,6 +88,7 @@ describe('KbRoute', () => {
|
|
|
85
88
|
expect(res.body[0].embedding.provider).to.equal('openai')
|
|
86
89
|
expect(res.body[0].embedding.name).to.equal('text-embedding-ada-002')
|
|
87
90
|
expect(res.body[0].embedding.dimension).to.equal(1536)
|
|
91
|
+
expect(res.body[0].embedding.api_key).to.equal('')
|
|
88
92
|
|
|
89
93
|
done();
|
|
90
94
|
})
|
|
@@ -125,6 +129,7 @@ describe('KbRoute', () => {
|
|
|
125
129
|
expect(res.body.embedding.provider).to.equal('openai')
|
|
126
130
|
expect(res.body.embedding.name).to.equal('text-embedding-ada-002')
|
|
127
131
|
expect(res.body.embedding.dimension).to.equal(1536)
|
|
132
|
+
expect(res.body.embedding.api_key).to.equal('')
|
|
128
133
|
|
|
129
134
|
// Get again all namespace. A new default namespace should not be created.
|
|
130
135
|
chai.request(server)
|
|
@@ -140,6 +145,7 @@ describe('KbRoute', () => {
|
|
|
140
145
|
expect(res.body.length).to.equal(1);
|
|
141
146
|
should.not.exist(res.body[0]._id);
|
|
142
147
|
should.exist(res.body[0].id);
|
|
148
|
+
expect(res.body[0].embedding.api_key).to.equal('');
|
|
143
149
|
|
|
144
150
|
done();
|
|
145
151
|
})
|
|
@@ -237,6 +243,7 @@ describe('KbRoute', () => {
|
|
|
237
243
|
expect(res.body.embedding.provider).to.equal('openai')
|
|
238
244
|
expect(res.body.embedding.name).to.equal('text-embedding-ada-002')
|
|
239
245
|
expect(res.body.embedding.dimension).to.equal(1536)
|
|
246
|
+
expect(res.body.embedding.api_key).to.equal('')
|
|
240
247
|
|
|
241
248
|
done();
|
|
242
249
|
})
|
|
@@ -284,6 +291,9 @@ describe('KbRoute', () => {
|
|
|
284
291
|
res.body.should.be.a('object');
|
|
285
292
|
expect(res.body.success).to.equal(true);
|
|
286
293
|
expect(res.body.message).to.equal("Contents imported successfully");
|
|
294
|
+
res.body.schedule_json.should.be.a('array');
|
|
295
|
+
expect(res.body.schedule_json.length).to.equal(3);
|
|
296
|
+
expect(res.body.schedule_json[0].embedding.api_key).to.equal('fakegptkey');
|
|
287
297
|
|
|
288
298
|
chai.request(server)
|
|
289
299
|
.get('/' + savedProject._id + '/kb/?namespace=' + namespace_id)
|
|
@@ -305,7 +315,22 @@ describe('KbRoute', () => {
|
|
|
305
315
|
let content_without_tags = res.body.kbs.find(kb => kb.source !== 'Example content');
|
|
306
316
|
expect(content_without_tags.tags).to.equal(undefined);
|
|
307
317
|
|
|
308
|
-
|
|
318
|
+
chai.request(server)
|
|
319
|
+
.get('/' + savedProject._id + '/kb/namespace/all')
|
|
320
|
+
.auth(email, pwd)
|
|
321
|
+
.end((err, res) => {
|
|
322
|
+
if (err) { console.error("err: ", err); }
|
|
323
|
+
if (log) { console.log("get all namespaces res.body: ", res.body); }
|
|
324
|
+
|
|
325
|
+
res.should.have.status(200);
|
|
326
|
+
res.body.should.be.a('array');
|
|
327
|
+
expect(res.body.length).to.equal(1);
|
|
328
|
+
expect(res.body[0].id).to.equal(namespace_id);
|
|
329
|
+
expect(res.body[0].name).to.equal("Default");
|
|
330
|
+
expect(res.body[0].embedding.api_key).to.equal('');
|
|
331
|
+
|
|
332
|
+
done();
|
|
333
|
+
})
|
|
309
334
|
})
|
|
310
335
|
|
|
311
336
|
})
|
|
@@ -370,6 +395,7 @@ describe('KbRoute', () => {
|
|
|
370
395
|
expect(res.body.preview_settings.max_tokens).to.equal(256)
|
|
371
396
|
expect(res.body.preview_settings.temperature).to.equal(0.3)
|
|
372
397
|
expect(res.body.preview_settings.top_k).to.equal(6)
|
|
398
|
+
expect(res.body.embedding.api_key).to.equal('')
|
|
373
399
|
|
|
374
400
|
done();
|
|
375
401
|
|
|
@@ -379,6 +405,43 @@ describe('KbRoute', () => {
|
|
|
379
405
|
});
|
|
380
406
|
})
|
|
381
407
|
|
|
408
|
+
it('embedding-api-key-never-persisted', (done) => {
|
|
409
|
+
const namespaceId = new mongoose.Types.ObjectId().toString();
|
|
410
|
+
const projectId = new mongoose.Types.ObjectId().toString();
|
|
411
|
+
|
|
412
|
+
const ns = new Namespace({
|
|
413
|
+
id_project: projectId,
|
|
414
|
+
id: namespaceId,
|
|
415
|
+
name: 'ApiKeyTest',
|
|
416
|
+
preview_settings: {
|
|
417
|
+
model: 'gpt-4o',
|
|
418
|
+
max_tokens: 256,
|
|
419
|
+
temperature: 0.7,
|
|
420
|
+
top_k: 4,
|
|
421
|
+
context: null
|
|
422
|
+
},
|
|
423
|
+
engine: default_engine,
|
|
424
|
+
embedding: {
|
|
425
|
+
provider: 'openai',
|
|
426
|
+
name: 'text-embedding-ada-002',
|
|
427
|
+
dimension: 1536,
|
|
428
|
+
api_key: 'must-not-persist'
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
ns.save()
|
|
433
|
+
.then((saved) => {
|
|
434
|
+
expect(saved.embedding.api_key).to.equal('');
|
|
435
|
+
return Namespace.findOne({ id: namespaceId }).lean();
|
|
436
|
+
})
|
|
437
|
+
.then((doc) => {
|
|
438
|
+
expect(doc.embedding.api_key).to.equal('');
|
|
439
|
+
return Namespace.deleteOne({ _id: doc._id });
|
|
440
|
+
})
|
|
441
|
+
.then(() => done())
|
|
442
|
+
.catch(done);
|
|
443
|
+
})
|
|
444
|
+
|
|
382
445
|
/**
|
|
383
446
|
* Delete default namespace - Forbidden
|
|
384
447
|
*/
|
|
@@ -515,7 +578,6 @@ describe('KbRoute', () => {
|
|
|
515
578
|
|
|
516
579
|
userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
|
|
517
580
|
projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
|
|
518
|
-
|
|
519
581
|
chai.request(server)
|
|
520
582
|
.get('/' + savedProject._id + '/kb/namespace/all')
|
|
521
583
|
.auth(email, pwd)
|
|
@@ -579,6 +641,7 @@ describe('KbRoute', () => {
|
|
|
579
641
|
expect(scheduleJson.tags[1]).to.equal("example");
|
|
580
642
|
should.exist(scheduleJson.engine)
|
|
581
643
|
should.exist(scheduleJson.embedding)
|
|
644
|
+
expect(scheduleJson.embedding.api_key).to.equal('fakegptkey');
|
|
582
645
|
|
|
583
646
|
done();
|
|
584
647
|
})
|
|
@@ -632,7 +695,6 @@ describe('KbRoute', () => {
|
|
|
632
695
|
res.body.should.be.a('object');
|
|
633
696
|
|
|
634
697
|
let realResponse = res.body.data;
|
|
635
|
-
console.log("realResponse: ", realResponse);
|
|
636
698
|
expect(realResponse.value.id_project).to.equal(namespace_id)
|
|
637
699
|
expect(realResponse.value.name).to.equal("example_text1")
|
|
638
700
|
expect(realResponse.value.type).to.equal("text")
|
|
@@ -652,6 +714,83 @@ describe('KbRoute', () => {
|
|
|
652
714
|
|
|
653
715
|
})
|
|
654
716
|
|
|
717
|
+
it('update-content', (done) => {
|
|
718
|
+
const kbTrainUrl = process.env.KB_ENDPOINT_TRAIN;
|
|
719
|
+
|
|
720
|
+
const deleteScope = nock(kbTrainUrl)
|
|
721
|
+
.post('/delete/id')
|
|
722
|
+
.reply(200, { success: true });
|
|
723
|
+
|
|
724
|
+
var email = "test-signup-" + Date.now() + "@email.com";
|
|
725
|
+
var pwd = "pwd";
|
|
726
|
+
|
|
727
|
+
userService.signup(email, pwd, "Test Firstname", "Test lastname").then(function (savedUser) {
|
|
728
|
+
projectService.create("test-faqkb-create", savedUser._id).then(function (savedProject) {
|
|
729
|
+
|
|
730
|
+
chai.request(server)
|
|
731
|
+
.get('/' + savedProject._id + '/kb/namespace/all')
|
|
732
|
+
.auth(email, pwd)
|
|
733
|
+
.end((err, res) => {
|
|
734
|
+
if (err) { console.error("err: ", err); }
|
|
735
|
+
|
|
736
|
+
res.should.have.status(200);
|
|
737
|
+
let namespace_id = res.body[0].id;
|
|
738
|
+
|
|
739
|
+
let kb = {
|
|
740
|
+
name: "example_text_update",
|
|
741
|
+
type: "text",
|
|
742
|
+
source: "example_text_update",
|
|
743
|
+
content: "Original text",
|
|
744
|
+
namespace: namespace_id
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
chai.request(server)
|
|
748
|
+
.post('/' + savedProject._id + '/kb')
|
|
749
|
+
.auth(email, pwd)
|
|
750
|
+
.send(kb)
|
|
751
|
+
.end((err, res) => {
|
|
752
|
+
if (err) { console.error("err: ", err); }
|
|
753
|
+
|
|
754
|
+
res.should.have.status(200);
|
|
755
|
+
let kb_id = res.body.data.value._id;
|
|
756
|
+
|
|
757
|
+
chai.request(server)
|
|
758
|
+
.put('/' + savedProject._id + '/kb/' + kb_id)
|
|
759
|
+
.auth(email, pwd)
|
|
760
|
+
.send({
|
|
761
|
+
name: "example_text_update",
|
|
762
|
+
type: "text",
|
|
763
|
+
source: "example_text_update",
|
|
764
|
+
content: "Updated text",
|
|
765
|
+
namespace: namespace_id
|
|
766
|
+
})
|
|
767
|
+
.end((err, res) => {
|
|
768
|
+
if (err) { console.error("err: ", err); }
|
|
769
|
+
if (log) { console.log("update content res.body: ", res.body); }
|
|
770
|
+
|
|
771
|
+
res.should.have.status(200);
|
|
772
|
+
expect(res.body.success).to.equal(true);
|
|
773
|
+
expect(res.body.message).to.equal("Schedule scrape skipped in test environment");
|
|
774
|
+
expect(res.body.data.content).to.equal("Updated text");
|
|
775
|
+
should.exist(res.body.schedule_json.embedding);
|
|
776
|
+
expect(res.body.schedule_json.embedding.api_key).to.equal('fakegptkey');
|
|
777
|
+
|
|
778
|
+
chai.request(server)
|
|
779
|
+
.get('/' + savedProject._id + '/kb/namespace/all')
|
|
780
|
+
.auth(email, pwd)
|
|
781
|
+
.end((err, res) => {
|
|
782
|
+
expect(res.body[0].embedding.api_key).to.equal('');
|
|
783
|
+
expect(deleteScope.isDone()).to.equal(true);
|
|
784
|
+
nock.cleanAll();
|
|
785
|
+
done();
|
|
786
|
+
});
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
});
|
|
792
|
+
}).timeout(10000)
|
|
793
|
+
|
|
655
794
|
it('get-content-chunks', (done) => {
|
|
656
795
|
|
|
657
796
|
var email = "test-signup-" + Date.now() + "@email.com";
|
|
@@ -1018,7 +1157,6 @@ describe('KbRoute', () => {
|
|
|
1018
1157
|
|
|
1019
1158
|
if (err) { console.error("err: ", err); }
|
|
1020
1159
|
if (log) { console.log("res.body: ", res.body) }
|
|
1021
|
-
console.log("res.body: ", res.body)
|
|
1022
1160
|
res.should.have.status(200);
|
|
1023
1161
|
res.body.should.be.a('object');
|
|
1024
1162
|
expect(res.body.success).to.equal(true);
|
|
@@ -1026,7 +1164,6 @@ describe('KbRoute', () => {
|
|
|
1026
1164
|
|
|
1027
1165
|
let realResponse = res.body.data;
|
|
1028
1166
|
realResponse.should.be.a('array');
|
|
1029
|
-
console.log("realResponse: ", realResponse[0]);
|
|
1030
1167
|
expect(realResponse.length).to.equal(2);
|
|
1031
1168
|
expect(realResponse[0].namespace).to.equal(namespace_id);
|
|
1032
1169
|
expect(realResponse[0].type).to.equal('faq');
|
|
@@ -1050,6 +1187,7 @@ describe('KbRoute', () => {
|
|
|
1050
1187
|
expect(scheduleJson[0].engine.index_name).to.equal(namespace.engine.index_name);
|
|
1051
1188
|
expect(scheduleJson[0].embedding.provider).to.equal(namespace.embedding.provider);
|
|
1052
1189
|
expect(scheduleJson[0].embedding.name).to.equal(namespace.embedding.name);
|
|
1190
|
+
expect(scheduleJson[0].embedding.api_key).to.equal('fakegptkey');
|
|
1053
1191
|
|
|
1054
1192
|
expect(scheduleJson[1].namespace).to.equal(namespace_id);
|
|
1055
1193
|
expect(scheduleJson[1].type).to.equal('faq');
|
|
@@ -1215,6 +1353,7 @@ describe('KbRoute', () => {
|
|
|
1215
1353
|
expect(scheduleJson[0].engine.index_name).to.equal(namespace.engine.index_name);
|
|
1216
1354
|
expect(scheduleJson[0].embedding.provider).to.equal(namespace.embedding.provider);
|
|
1217
1355
|
expect(scheduleJson[0].embedding.name).to.equal(namespace.embedding.name);
|
|
1356
|
+
expect(scheduleJson[0].embedding.api_key).to.equal('fakegptkey');
|
|
1218
1357
|
|
|
1219
1358
|
expect(scheduleJson[1].namespace).to.equal(namespace_id);
|
|
1220
1359
|
expect(scheduleJson[1].source).to.equal('https://gethelp.tiledesk.com/articles/article2');
|
|
@@ -1407,6 +1546,7 @@ describe('KbRoute', () => {
|
|
|
1407
1546
|
scheduleJson.should.be.a('array');
|
|
1408
1547
|
should.exist(scheduleJson[0].engine)
|
|
1409
1548
|
should.exist(scheduleJson[0].embedding)
|
|
1549
|
+
expect(scheduleJson[0].embedding.api_key).to.equal('fakegptkey');
|
|
1410
1550
|
|
|
1411
1551
|
done();
|
|
1412
1552
|
})
|
|
@@ -1485,6 +1625,7 @@ describe('KbRoute', () => {
|
|
|
1485
1625
|
expect(res.body.data.embedding.provider).to.equal("openai");
|
|
1486
1626
|
expect(res.body.data.embedding.name).to.equal("text-embedding-ada-002");
|
|
1487
1627
|
expect(res.body.data.embedding.dimension).to.equal(1536);
|
|
1628
|
+
expect(res.body.data.embedding.api_key).to.equal('fakegptkey');
|
|
1488
1629
|
|
|
1489
1630
|
done();
|
|
1490
1631
|
|
|
@@ -1759,7 +1900,7 @@ describe('KbRoute', () => {
|
|
|
1759
1900
|
.get('/' + savedProject._id + '/kb/namespace/all')
|
|
1760
1901
|
.auth(email, pwd)
|
|
1761
1902
|
.end((err, res) => {
|
|
1762
|
-
|
|
1903
|
+
|
|
1763
1904
|
if (err) { console.error("err: ", err); }
|
|
1764
1905
|
if (log) { console.log("get namespaces res.body: ", res.body); }
|
|
1765
1906
|
|
|
@@ -1778,7 +1919,7 @@ describe('KbRoute', () => {
|
|
|
1778
1919
|
.auth(email, pwd)
|
|
1779
1920
|
.send(data)
|
|
1780
1921
|
.end((err, res) => {
|
|
1781
|
-
|
|
1922
|
+
|
|
1782
1923
|
if (err) { console.error("err: ", err); }
|
|
1783
1924
|
if (log) { console.log("create unanswered question res.body: ", res.body); }
|
|
1784
1925
|
|