plugin-knowledge-base 1.0.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/README.md +24 -0
- package/client.d.ts +2 -0
- package/client.js +1 -0
- package/dist/client/index.js +10 -0
- package/dist/externalVersion.js +22 -0
- package/dist/index.js +48 -0
- package/dist/locale/en-US.json +44 -0
- package/dist/locale/vi-VN.json +44 -0
- package/dist/node_modules/@langchain/textsplitters/LICENSE +21 -0
- package/dist/node_modules/@langchain/textsplitters/dist/_virtual/rolldown_runtime.cjs +25 -0
- package/dist/node_modules/@langchain/textsplitters/dist/index.cjs +7 -0
- package/dist/node_modules/@langchain/textsplitters/dist/index.d.cts +2 -0
- package/dist/node_modules/@langchain/textsplitters/dist/index.d.ts +2 -0
- package/dist/node_modules/@langchain/textsplitters/dist/index.js +3 -0
- package/dist/node_modules/@langchain/textsplitters/dist/text_splitter.cjs +539 -0
- package/dist/node_modules/@langchain/textsplitters/dist/text_splitter.d.cts +84 -0
- package/dist/node_modules/@langchain/textsplitters/dist/text_splitter.d.ts +84 -0
- package/dist/node_modules/@langchain/textsplitters/dist/text_splitter.js +532 -0
- package/dist/node_modules/@langchain/textsplitters/package.json +1 -0
- package/dist/server/collections/ai-knowledge-base-documents.js +88 -0
- package/dist/server/collections/ai-knowledge-bases.js +105 -0
- package/dist/server/collections/ai-vector-databases.js +63 -0
- package/dist/server/collections/ai-vector-stores.js +72 -0
- package/dist/server/features/knowledge-base-impl.js +94 -0
- package/dist/server/features/vector-database-impl.js +75 -0
- package/dist/server/features/vector-database-provider-impl.js +63 -0
- package/dist/server/features/vector-store-provider-impl.js +141 -0
- package/dist/server/index.js +49 -0
- package/dist/server/pipeline/text-splitter.js +69 -0
- package/dist/server/pipeline/vectorization.js +144 -0
- package/dist/server/plugin.js +131 -0
- package/dist/server/providers/pgvector.js +134 -0
- package/dist/server/resources/ai-knowledge-base-documents.js +134 -0
- package/dist/server/resources/ai-knowledge-base.js +168 -0
- package/dist/server/resources/ai-vector-databases.js +122 -0
- package/dist/server/resources/ai-vector-stores.js +95 -0
- package/package.json +40 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var text_splitter_exports = {};
|
|
28
|
+
__export(text_splitter_exports, {
|
|
29
|
+
DocumentTextSplitter: () => DocumentTextSplitter
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(text_splitter_exports);
|
|
32
|
+
var import_textsplitters = require("@langchain/textsplitters");
|
|
33
|
+
const DEFAULT_CHUNK_SIZE = 1e3;
|
|
34
|
+
const DEFAULT_CHUNK_OVERLAP = 200;
|
|
35
|
+
class DocumentTextSplitter {
|
|
36
|
+
splitter;
|
|
37
|
+
constructor(options) {
|
|
38
|
+
const {
|
|
39
|
+
chunkSize = DEFAULT_CHUNK_SIZE,
|
|
40
|
+
chunkOverlap = DEFAULT_CHUNK_OVERLAP,
|
|
41
|
+
separators
|
|
42
|
+
} = options ?? {};
|
|
43
|
+
this.splitter = new import_textsplitters.RecursiveCharacterTextSplitter({
|
|
44
|
+
chunkSize,
|
|
45
|
+
chunkOverlap,
|
|
46
|
+
...separators ? { separators } : {}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async splitText(text, metadata) {
|
|
50
|
+
if (!text || text.trim().length === 0) {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
const documents = await this.splitter.createDocuments(
|
|
54
|
+
[text],
|
|
55
|
+
[metadata ?? {}]
|
|
56
|
+
);
|
|
57
|
+
return documents;
|
|
58
|
+
}
|
|
59
|
+
async splitDocuments(documents) {
|
|
60
|
+
if (!documents || documents.length === 0) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
return this.splitter.splitDocuments(documents);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
67
|
+
0 && (module.exports = {
|
|
68
|
+
DocumentTextSplitter
|
|
69
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var vectorization_exports = {};
|
|
28
|
+
__export(vectorization_exports, {
|
|
29
|
+
VectorizationPipeline: () => VectorizationPipeline
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(vectorization_exports);
|
|
32
|
+
var import_text_splitter = require("./text-splitter");
|
|
33
|
+
class VectorizationPipeline {
|
|
34
|
+
constructor(plugin) {
|
|
35
|
+
this.plugin = plugin;
|
|
36
|
+
}
|
|
37
|
+
async processDocument(documentId, options) {
|
|
38
|
+
const docRepo = this.plugin.db.getRepository("aiKnowledgeBaseDocuments");
|
|
39
|
+
await docRepo.update({
|
|
40
|
+
filter: { id: documentId },
|
|
41
|
+
values: { status: "processing" }
|
|
42
|
+
});
|
|
43
|
+
try {
|
|
44
|
+
const docRecord = await docRepo.findOne({
|
|
45
|
+
filter: { id: documentId },
|
|
46
|
+
appends: ["file", "knowledgeBase", "knowledgeBase.vectorStore", "knowledgeBase.vectorStore.vectorDatabase"]
|
|
47
|
+
});
|
|
48
|
+
if (!docRecord) {
|
|
49
|
+
throw new Error(`Document "${documentId}" not found`);
|
|
50
|
+
}
|
|
51
|
+
const doc = docRecord.toJSON();
|
|
52
|
+
const file = doc.file;
|
|
53
|
+
const knowledgeBase = doc.knowledgeBase;
|
|
54
|
+
if (!file) {
|
|
55
|
+
throw new Error("Document has no associated file");
|
|
56
|
+
}
|
|
57
|
+
if (!(knowledgeBase == null ? void 0 : knowledgeBase.vectorStore)) {
|
|
58
|
+
throw new Error("Knowledge base has no vector store configured");
|
|
59
|
+
}
|
|
60
|
+
const aiPlugin = this.plugin.aiPlugin;
|
|
61
|
+
const parseResult = await aiPlugin.documentLoaders.cached.load(file);
|
|
62
|
+
if (!parseResult.supported) {
|
|
63
|
+
throw new Error(`File type not supported: ${file.filename}`);
|
|
64
|
+
}
|
|
65
|
+
if (!parseResult.text || parseResult.text.trim().length === 0) {
|
|
66
|
+
await docRepo.update({
|
|
67
|
+
filter: { id: documentId },
|
|
68
|
+
values: { status: "success", chunkCount: 0 }
|
|
69
|
+
});
|
|
70
|
+
return { success: true, chunkCount: 0 };
|
|
71
|
+
}
|
|
72
|
+
const splitter = new import_text_splitter.DocumentTextSplitter(options);
|
|
73
|
+
const chunks = await splitter.splitText(parseResult.text, {
|
|
74
|
+
knowledgeBaseId: knowledgeBase.id,
|
|
75
|
+
knowledgeBaseOuterId: knowledgeBase.id,
|
|
76
|
+
documentId,
|
|
77
|
+
source: file.filename,
|
|
78
|
+
// Permission metadata for vector-level filtering
|
|
79
|
+
userId: doc.uploadedById ?? null,
|
|
80
|
+
accessLevel: knowledgeBase.accessLevel ?? "PUBLIC"
|
|
81
|
+
});
|
|
82
|
+
if (chunks.length === 0) {
|
|
83
|
+
await docRepo.update({
|
|
84
|
+
filter: { id: documentId },
|
|
85
|
+
values: { status: "success", chunkCount: 0 }
|
|
86
|
+
});
|
|
87
|
+
return { success: true, chunkCount: 0 };
|
|
88
|
+
}
|
|
89
|
+
const vectorStore = knowledgeBase.vectorStore;
|
|
90
|
+
const vectorDatabase = vectorStore.vectorDatabase;
|
|
91
|
+
const llmServiceRecord = await this.plugin.db.getRepository("llmServices").findOne({
|
|
92
|
+
filter: { name: vectorStore.llmService }
|
|
93
|
+
});
|
|
94
|
+
if (!llmServiceRecord) {
|
|
95
|
+
throw new Error(`LLM service "${vectorStore.llmService}" not found`);
|
|
96
|
+
}
|
|
97
|
+
const llmService = llmServiceRecord.toJSON();
|
|
98
|
+
const providerMeta = aiPlugin.aiManager.llmProviders.get(llmService.provider);
|
|
99
|
+
if (!(providerMeta == null ? void 0 : providerMeta.embedding)) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
`LLM provider "${llmService.provider}" does not support embedding`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
const embeddingProvider = new providerMeta.embedding({
|
|
105
|
+
app: this.plugin.app,
|
|
106
|
+
serviceOptions: llmService.options,
|
|
107
|
+
modelOptions: { model: vectorStore.embeddingModel }
|
|
108
|
+
});
|
|
109
|
+
const embeddings = embeddingProvider.createEmbedding();
|
|
110
|
+
const vdbProvider = aiPlugin.features.vectorDatabaseProvider;
|
|
111
|
+
const vectorStoreInstance = await vdbProvider.createVectorStore(
|
|
112
|
+
vectorDatabase.provider,
|
|
113
|
+
embeddings,
|
|
114
|
+
vectorDatabase.connectParams
|
|
115
|
+
);
|
|
116
|
+
await vectorStoreInstance.addDocuments(chunks);
|
|
117
|
+
await docRepo.update({
|
|
118
|
+
filter: { id: documentId },
|
|
119
|
+
values: {
|
|
120
|
+
status: "success",
|
|
121
|
+
chunkCount: chunks.length
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
return { success: true, chunkCount: chunks.length };
|
|
125
|
+
} catch (error) {
|
|
126
|
+
await docRepo.update({
|
|
127
|
+
filter: { id: documentId },
|
|
128
|
+
values: {
|
|
129
|
+
status: "failed",
|
|
130
|
+
error: error.message ?? String(error)
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
chunkCount: 0,
|
|
136
|
+
error: error.message ?? String(error)
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
142
|
+
0 && (module.exports = {
|
|
143
|
+
VectorizationPipeline
|
|
144
|
+
});
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
var plugin_exports = {};
|
|
38
|
+
__export(plugin_exports, {
|
|
39
|
+
PluginKnowledgeBaseServer: () => PluginKnowledgeBaseServer,
|
|
40
|
+
default: () => plugin_default
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(plugin_exports);
|
|
43
|
+
var import_server = require("@nocobase/server");
|
|
44
|
+
var import_plugin_ai = __toESM(require("@nocobase/plugin-ai"));
|
|
45
|
+
var import_knowledge_base_impl = require("./features/knowledge-base-impl");
|
|
46
|
+
var import_vector_database_impl = require("./features/vector-database-impl");
|
|
47
|
+
var import_vector_database_provider_impl = require("./features/vector-database-provider-impl");
|
|
48
|
+
var import_vector_store_provider_impl = require("./features/vector-store-provider-impl");
|
|
49
|
+
var import_pgvector = require("./providers/pgvector");
|
|
50
|
+
var import_vectorization = require("./pipeline/vectorization");
|
|
51
|
+
var import_ai_knowledge_base = __toESM(require("./resources/ai-knowledge-base"));
|
|
52
|
+
var import_ai_knowledge_base_documents = __toESM(require("./resources/ai-knowledge-base-documents"));
|
|
53
|
+
var import_ai_vector_stores = __toESM(require("./resources/ai-vector-stores"));
|
|
54
|
+
var import_ai_vector_databases = __toESM(require("./resources/ai-vector-databases"));
|
|
55
|
+
class PluginKnowledgeBaseServer extends import_server.Plugin {
|
|
56
|
+
vectorizationPipeline;
|
|
57
|
+
_aiPlugin;
|
|
58
|
+
get aiPlugin() {
|
|
59
|
+
if (!this._aiPlugin) {
|
|
60
|
+
this._aiPlugin = this.pm.get(import_plugin_ai.default);
|
|
61
|
+
}
|
|
62
|
+
return this._aiPlugin;
|
|
63
|
+
}
|
|
64
|
+
async afterAdd() {
|
|
65
|
+
}
|
|
66
|
+
async beforeLoad() {
|
|
67
|
+
}
|
|
68
|
+
async load() {
|
|
69
|
+
const vdbProvider = new import_vector_database_provider_impl.VectorDatabaseProviderImpl();
|
|
70
|
+
vdbProvider.register(import_pgvector.pgVectorProviderInfo);
|
|
71
|
+
const vectorStoreProvider = new import_vector_store_provider_impl.VectorStoreProviderImpl(this, this.aiPlugin);
|
|
72
|
+
const vectorDatabase = new import_vector_database_impl.VectorDatabaseFeatureImpl(this);
|
|
73
|
+
const knowledgeBase = new import_knowledge_base_impl.KnowledgeBaseFeatureImpl(this);
|
|
74
|
+
this.aiPlugin.features.enableFeatures({
|
|
75
|
+
vectorDatabase,
|
|
76
|
+
vectorDatabaseProvider: vdbProvider,
|
|
77
|
+
vectorStoreProvider,
|
|
78
|
+
knowledgeBase
|
|
79
|
+
});
|
|
80
|
+
this.vectorizationPipeline = new import_vectorization.VectorizationPipeline(this);
|
|
81
|
+
this.defineResources();
|
|
82
|
+
this.setPermissions();
|
|
83
|
+
this.app.resourceManager.use(
|
|
84
|
+
async (ctx, next) => {
|
|
85
|
+
var _a;
|
|
86
|
+
const { resourceName, actionName } = ctx.action;
|
|
87
|
+
if (resourceName === "aiFiles" && actionName === "create") {
|
|
88
|
+
const storageName = (_a = ctx.action.params) == null ? void 0 : _a.storageRule;
|
|
89
|
+
if (storageName) {
|
|
90
|
+
const collection = ctx.db.getCollection("aiFiles");
|
|
91
|
+
collection.options.storage = storageName;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
await next();
|
|
95
|
+
},
|
|
96
|
+
{ before: "createMiddleware" }
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
defineResources() {
|
|
100
|
+
this.app.resourceManager.define(import_ai_knowledge_base.default);
|
|
101
|
+
this.app.resourceManager.define(import_ai_knowledge_base_documents.default);
|
|
102
|
+
this.app.resourceManager.define(import_ai_vector_stores.default);
|
|
103
|
+
this.app.resourceManager.define(import_ai_vector_databases.default);
|
|
104
|
+
}
|
|
105
|
+
setPermissions() {
|
|
106
|
+
this.app.acl.registerSnippet({
|
|
107
|
+
name: `pm.${this.name}.knowledge-base`,
|
|
108
|
+
actions: [
|
|
109
|
+
"aiKnowledgeBase:*",
|
|
110
|
+
"aiKnowledgeBaseDoc:*",
|
|
111
|
+
"aiVectorStore:*",
|
|
112
|
+
"aiVectorDatabase:*"
|
|
113
|
+
]
|
|
114
|
+
});
|
|
115
|
+
this.app.acl.allow("aiKnowledgeBase", "list", "loggedIn");
|
|
116
|
+
this.app.acl.allow("aiKnowledgeBase", "get", "loggedIn");
|
|
117
|
+
}
|
|
118
|
+
async install() {
|
|
119
|
+
}
|
|
120
|
+
async afterEnable() {
|
|
121
|
+
}
|
|
122
|
+
async afterDisable() {
|
|
123
|
+
}
|
|
124
|
+
async remove() {
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
var plugin_default = PluginKnowledgeBaseServer;
|
|
128
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
129
|
+
0 && (module.exports = {
|
|
130
|
+
PluginKnowledgeBaseServer
|
|
131
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __create = Object.create;
|
|
11
|
+
var __defProp = Object.defineProperty;
|
|
12
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
13
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
14
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
15
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
var pgvector_exports = {};
|
|
38
|
+
__export(pgvector_exports, {
|
|
39
|
+
PGVectorDatabaseProvider: () => PGVectorDatabaseProvider,
|
|
40
|
+
pgVectorProviderInfo: () => pgVectorProviderInfo
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(pgvector_exports);
|
|
43
|
+
class PGVectorDatabaseProvider {
|
|
44
|
+
validateConnectParams(connectParams) {
|
|
45
|
+
const { host, port, username, password, database, tableName } = connectParams || {};
|
|
46
|
+
if (!host) {
|
|
47
|
+
throw new Error("Host is required");
|
|
48
|
+
}
|
|
49
|
+
if (!port) {
|
|
50
|
+
throw new Error("Port is required");
|
|
51
|
+
}
|
|
52
|
+
if (!username) {
|
|
53
|
+
throw new Error("Username is required");
|
|
54
|
+
}
|
|
55
|
+
if (!password) {
|
|
56
|
+
throw new Error("Password is required");
|
|
57
|
+
}
|
|
58
|
+
if (!database) {
|
|
59
|
+
throw new Error("Database is required");
|
|
60
|
+
}
|
|
61
|
+
if (!tableName) {
|
|
62
|
+
throw new Error("Table name is required");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async testConnection(connectParams) {
|
|
66
|
+
this.validateConnectParams(connectParams);
|
|
67
|
+
let client;
|
|
68
|
+
try {
|
|
69
|
+
const { Client } = await import("pg");
|
|
70
|
+
client = new Client({
|
|
71
|
+
host: connectParams.host,
|
|
72
|
+
port: connectParams.port,
|
|
73
|
+
user: connectParams.username,
|
|
74
|
+
password: connectParams.password,
|
|
75
|
+
database: connectParams.database
|
|
76
|
+
});
|
|
77
|
+
await client.connect();
|
|
78
|
+
const result = await client.query(
|
|
79
|
+
"SELECT 1 FROM pg_extension WHERE extname = 'vector'"
|
|
80
|
+
);
|
|
81
|
+
if (result.rows.length === 0) {
|
|
82
|
+
return {
|
|
83
|
+
success: false,
|
|
84
|
+
error: "pgvector extension is not installed. Run: CREATE EXTENSION vector;"
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return { success: true };
|
|
88
|
+
} catch (error) {
|
|
89
|
+
return {
|
|
90
|
+
success: false,
|
|
91
|
+
error: error.message ?? "Failed to connect to PostgreSQL"
|
|
92
|
+
};
|
|
93
|
+
} finally {
|
|
94
|
+
if (client) {
|
|
95
|
+
try {
|
|
96
|
+
await client.end();
|
|
97
|
+
} catch {
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async createVectorStore(embeddings, connectParams) {
|
|
103
|
+
this.validateConnectParams(connectParams);
|
|
104
|
+
const { PGVectorStore } = await import("@langchain/community/vectorstores/pgvector");
|
|
105
|
+
const config = {
|
|
106
|
+
postgresConnectionOptions: {
|
|
107
|
+
host: connectParams.host,
|
|
108
|
+
port: connectParams.port,
|
|
109
|
+
user: connectParams.username,
|
|
110
|
+
password: connectParams.password,
|
|
111
|
+
database: connectParams.database
|
|
112
|
+
},
|
|
113
|
+
tableName: connectParams.tableName,
|
|
114
|
+
columns: {
|
|
115
|
+
idColumnName: "id",
|
|
116
|
+
vectorColumnName: "embedding",
|
|
117
|
+
contentColumnName: "content",
|
|
118
|
+
metadataColumnName: "metadata"
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
const vectorStore = await PGVectorStore.initialize(embeddings, config);
|
|
122
|
+
return vectorStore;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const pgVectorProviderInfo = {
|
|
126
|
+
name: "pgvector",
|
|
127
|
+
spec: "PGVector",
|
|
128
|
+
provider: new PGVectorDatabaseProvider()
|
|
129
|
+
};
|
|
130
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
131
|
+
0 && (module.exports = {
|
|
132
|
+
PGVectorDatabaseProvider,
|
|
133
|
+
pgVectorProviderInfo
|
|
134
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
|
+
var ai_knowledge_base_documents_exports = {};
|
|
28
|
+
__export(ai_knowledge_base_documents_exports, {
|
|
29
|
+
default: () => ai_knowledge_base_documents_default
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(ai_knowledge_base_documents_exports);
|
|
32
|
+
var ai_knowledge_base_documents_default = {
|
|
33
|
+
// IMPORTANT: resource name must differ from collection name 'aiKnowledgeBaseDocuments'
|
|
34
|
+
// otherwise NocoBase's auto-registered collection CRUD overrides our custom handlers.
|
|
35
|
+
name: "aiKnowledgeBaseDoc",
|
|
36
|
+
actions: {
|
|
37
|
+
async list(ctx, next) {
|
|
38
|
+
const { filter, sort, page, pageSize } = ctx.action.params;
|
|
39
|
+
const repo = ctx.db.getRepository("aiKnowledgeBaseDocuments");
|
|
40
|
+
ctx.body = await repo.find({
|
|
41
|
+
filter,
|
|
42
|
+
sort: sort ?? ["-createdAt"],
|
|
43
|
+
limit: pageSize,
|
|
44
|
+
offset: page ? (page - 1) * (pageSize || 20) : 0,
|
|
45
|
+
appends: ["file"]
|
|
46
|
+
});
|
|
47
|
+
await next();
|
|
48
|
+
},
|
|
49
|
+
async create(ctx, next) {
|
|
50
|
+
var _a, _b, _c;
|
|
51
|
+
const rawValues = ctx.action.params.values || {};
|
|
52
|
+
const values = rawValues.values || rawValues;
|
|
53
|
+
const repo = ctx.db.getRepository("aiKnowledgeBaseDocuments");
|
|
54
|
+
const userId = (_b = (_a = ctx.auth) == null ? void 0 : _a.user) == null ? void 0 : _b.id;
|
|
55
|
+
const roles = ctx.state.currentRoles ?? [];
|
|
56
|
+
const isRoot = roles.includes("root");
|
|
57
|
+
if (values.knowledgeBaseId) {
|
|
58
|
+
const kbRepo = ctx.db.getRepository("aiKnowledgeBases");
|
|
59
|
+
const kb = await kbRepo.findOne({ filter: { id: values.knowledgeBaseId } });
|
|
60
|
+
if (kb) {
|
|
61
|
+
const kbData = kb.toJSON();
|
|
62
|
+
if (kbData.accessLevel === "BASIC" && kbData.ownerId !== userId) {
|
|
63
|
+
ctx.throw(403, "Only the owner can upload documents to a personal knowledge base");
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (kbData.accessLevel === "PUBLIC" && !isRoot) {
|
|
67
|
+
ctx.throw(403, "Only administrators can upload documents to a public knowledge base");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (kbData.accessLevel === "SHARED") {
|
|
71
|
+
const canUpload = isRoot || ((_c = kbData.uploadRoles) == null ? void 0 : _c.some((r) => roles.includes(r)));
|
|
72
|
+
if (!canUpload) {
|
|
73
|
+
ctx.throw(403, "You do not have permission to upload documents to this knowledge base");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
values.uploadedById = userId;
|
|
80
|
+
const doc = await repo.create({ values });
|
|
81
|
+
const setClauses = [];
|
|
82
|
+
const bindValues = [];
|
|
83
|
+
let paramIdx = 1;
|
|
84
|
+
if (values.knowledgeBaseId) {
|
|
85
|
+
setClauses.push(`"knowledgeBaseId" = $${paramIdx++}`);
|
|
86
|
+
bindValues.push(values.knowledgeBaseId);
|
|
87
|
+
}
|
|
88
|
+
if (values.fileId) {
|
|
89
|
+
setClauses.push(`"fileId" = $${paramIdx++}`);
|
|
90
|
+
bindValues.push(values.fileId);
|
|
91
|
+
}
|
|
92
|
+
if (setClauses.length > 0) {
|
|
93
|
+
bindValues.push(doc.get("id"));
|
|
94
|
+
await ctx.db.sequelize.query(
|
|
95
|
+
`UPDATE "aiKnowledgeBaseDocuments" SET ${setClauses.join(", ")} WHERE id = $${paramIdx}`,
|
|
96
|
+
{ bind: bindValues }
|
|
97
|
+
);
|
|
98
|
+
if (values.knowledgeBaseId) doc.set("knowledgeBaseId", values.knowledgeBaseId);
|
|
99
|
+
if (values.fileId) doc.set("fileId", values.fileId);
|
|
100
|
+
}
|
|
101
|
+
const plugin = ctx.app.pm.get("@nocobase/plugin-knowledge-base");
|
|
102
|
+
if (plugin == null ? void 0 : plugin.vectorizationPipeline) {
|
|
103
|
+
plugin.vectorizationPipeline.processDocument(doc.id).catch((err) => {
|
|
104
|
+
ctx.logger.error(`Vectorization failed for document ${doc.id}:`, err);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
ctx.body = doc;
|
|
108
|
+
await next();
|
|
109
|
+
},
|
|
110
|
+
async destroy(ctx, next) {
|
|
111
|
+
const { filterByTk } = ctx.action.params;
|
|
112
|
+
const repo = ctx.db.getRepository("aiKnowledgeBaseDocuments");
|
|
113
|
+
await repo.destroy({ filterByTk });
|
|
114
|
+
ctx.body = { success: true };
|
|
115
|
+
await next();
|
|
116
|
+
},
|
|
117
|
+
async reprocess(ctx, next) {
|
|
118
|
+
const { filterByTk } = ctx.action.params;
|
|
119
|
+
const repo = ctx.db.getRepository("aiKnowledgeBaseDocuments");
|
|
120
|
+
await repo.update({
|
|
121
|
+
filterByTk,
|
|
122
|
+
values: { status: "pending", error: null, chunkCount: 0 }
|
|
123
|
+
});
|
|
124
|
+
const plugin = ctx.app.pm.get("@nocobase/plugin-knowledge-base");
|
|
125
|
+
if (plugin == null ? void 0 : plugin.vectorizationPipeline) {
|
|
126
|
+
plugin.vectorizationPipeline.processDocument(filterByTk).catch((err) => {
|
|
127
|
+
ctx.logger.error(`Re-vectorization failed for document ${filterByTk}:`, err);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
ctx.body = { success: true };
|
|
131
|
+
await next();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|