@nodetool-ai/base-nodes 0.7.0-rc.11
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.d.ts +72 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +270 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/audio-wav.d.ts +66 -0
- package/dist/lib/audio-wav.d.ts.map +1 -0
- package/dist/lib/audio-wav.js +215 -0
- package/dist/lib/audio-wav.js.map +1 -0
- package/dist/nodes/agents.d.ts +253 -0
- package/dist/nodes/agents.d.ts.map +1 -0
- package/dist/nodes/agents.js +2784 -0
- package/dist/nodes/agents.js.map +1 -0
- package/dist/nodes/anthropic.d.ts +26 -0
- package/dist/nodes/anthropic.d.ts.map +1 -0
- package/dist/nodes/anthropic.js +133 -0
- package/dist/nodes/anthropic.js.map +1 -0
- package/dist/nodes/apify.d.ts +120 -0
- package/dist/nodes/apify.d.ts.map +1 -0
- package/dist/nodes/apify.js +618 -0
- package/dist/nodes/apify.js.map +1 -0
- package/dist/nodes/audio.d.ts +301 -0
- package/dist/nodes/audio.d.ts.map +1 -0
- package/dist/nodes/audio.js +1274 -0
- package/dist/nodes/audio.js.map +1 -0
- package/dist/nodes/code-node.d.ts +34 -0
- package/dist/nodes/code-node.d.ts.map +1 -0
- package/dist/nodes/code-node.js +343 -0
- package/dist/nodes/code-node.js.map +1 -0
- package/dist/nodes/code.d.ts +301 -0
- package/dist/nodes/code.d.ts.map +1 -0
- package/dist/nodes/code.js +850 -0
- package/dist/nodes/code.js.map +1 -0
- package/dist/nodes/compare.d.ts +18 -0
- package/dist/nodes/compare.d.ts.map +1 -0
- package/dist/nodes/compare.js +122 -0
- package/dist/nodes/compare.js.map +1 -0
- package/dist/nodes/constant.d.ts +315 -0
- package/dist/nodes/constant.d.ts.map +1 -0
- package/dist/nodes/constant.js +715 -0
- package/dist/nodes/constant.js.map +1 -0
- package/dist/nodes/control.d.ts +83 -0
- package/dist/nodes/control.d.ts.map +1 -0
- package/dist/nodes/control.js +212 -0
- package/dist/nodes/control.js.map +1 -0
- package/dist/nodes/data.d.ts +369 -0
- package/dist/nodes/data.d.ts.map +1 -0
- package/dist/nodes/data.js +1590 -0
- package/dist/nodes/data.js.map +1 -0
- package/dist/nodes/document.d.ts +134 -0
- package/dist/nodes/document.d.ts.map +1 -0
- package/dist/nodes/document.js +984 -0
- package/dist/nodes/document.js.map +1 -0
- package/dist/nodes/extended-placeholders.d.ts +6 -0
- package/dist/nodes/extended-placeholders.d.ts.map +1 -0
- package/dist/nodes/extended-placeholders.js +19 -0
- package/dist/nodes/extended-placeholders.js.map +1 -0
- package/dist/nodes/gemini.d.ts +109 -0
- package/dist/nodes/gemini.d.ts.map +1 -0
- package/dist/nodes/gemini.js +861 -0
- package/dist/nodes/gemini.js.map +1 -0
- package/dist/nodes/generators.d.ts +84 -0
- package/dist/nodes/generators.d.ts.map +1 -0
- package/dist/nodes/generators.js +937 -0
- package/dist/nodes/generators.js.map +1 -0
- package/dist/nodes/image.d.ts +232 -0
- package/dist/nodes/image.d.ts.map +1 -0
- package/dist/nodes/image.js +1395 -0
- package/dist/nodes/image.js.map +1 -0
- package/dist/nodes/input.d.ts +445 -0
- package/dist/nodes/input.d.ts.map +1 -0
- package/dist/nodes/input.js +1459 -0
- package/dist/nodes/input.js.map +1 -0
- package/dist/nodes/kie-dynamic.d.ts +31 -0
- package/dist/nodes/kie-dynamic.d.ts.map +1 -0
- package/dist/nodes/kie-dynamic.js +270 -0
- package/dist/nodes/kie-dynamic.js.map +1 -0
- package/dist/nodes/lib-audio-dsp.d.ts +85 -0
- package/dist/nodes/lib-audio-dsp.d.ts.map +1 -0
- package/dist/nodes/lib-audio-dsp.js +450 -0
- package/dist/nodes/lib-audio-dsp.js.map +1 -0
- package/dist/nodes/lib-audio-effects.d.ts +116 -0
- package/dist/nodes/lib-audio-effects.d.ts.map +1 -0
- package/dist/nodes/lib-audio-effects.js +905 -0
- package/dist/nodes/lib-audio-effects.js.map +1 -0
- package/dist/nodes/lib-browser.d.ts +99 -0
- package/dist/nodes/lib-browser.d.ts.map +1 -0
- package/dist/nodes/lib-browser.js +692 -0
- package/dist/nodes/lib-browser.js.map +1 -0
- package/dist/nodes/lib-charts.d.ts +20 -0
- package/dist/nodes/lib-charts.d.ts.map +1 -0
- package/dist/nodes/lib-charts.js +245 -0
- package/dist/nodes/lib-charts.js.map +1 -0
- package/dist/nodes/lib-datetime.d.ts +108 -0
- package/dist/nodes/lib-datetime.d.ts.map +1 -0
- package/dist/nodes/lib-datetime.js +421 -0
- package/dist/nodes/lib-datetime.js.map +1 -0
- package/dist/nodes/lib-doc-convert.d.ts +19 -0
- package/dist/nodes/lib-doc-convert.d.ts.map +1 -0
- package/dist/nodes/lib-doc-convert.js +257 -0
- package/dist/nodes/lib-doc-convert.js.map +1 -0
- package/dist/nodes/lib-doc-transform.d.ts +39 -0
- package/dist/nodes/lib-doc-transform.d.ts.map +1 -0
- package/dist/nodes/lib-doc-transform.js +335 -0
- package/dist/nodes/lib-doc-transform.js.map +1 -0
- package/dist/nodes/lib-docx.d.ts +106 -0
- package/dist/nodes/lib-docx.d.ts.map +1 -0
- package/dist/nodes/lib-docx.js +595 -0
- package/dist/nodes/lib-docx.js.map +1 -0
- package/dist/nodes/lib-epub.d.ts +55 -0
- package/dist/nodes/lib-epub.d.ts.map +1 -0
- package/dist/nodes/lib-epub.js +220 -0
- package/dist/nodes/lib-epub.js.map +1 -0
- package/dist/nodes/lib-excel.d.ts +74 -0
- package/dist/nodes/lib-excel.d.ts.map +1 -0
- package/dist/nodes/lib-excel.js +448 -0
- package/dist/nodes/lib-excel.js.map +1 -0
- package/dist/nodes/lib-graphql.d.ts +66 -0
- package/dist/nodes/lib-graphql.d.ts.map +1 -0
- package/dist/nodes/lib-graphql.js +333 -0
- package/dist/nodes/lib-graphql.js.map +1 -0
- package/dist/nodes/lib-grid.d.ts +27 -0
- package/dist/nodes/lib-grid.d.ts.map +1 -0
- package/dist/nodes/lib-grid.js +172 -0
- package/dist/nodes/lib-grid.js.map +1 -0
- package/dist/nodes/lib-html-parse.d.ts +108 -0
- package/dist/nodes/lib-html-parse.d.ts.map +1 -0
- package/dist/nodes/lib-html-parse.js +365 -0
- package/dist/nodes/lib-html-parse.js.map +1 -0
- package/dist/nodes/lib-http.d.ts +98 -0
- package/dist/nodes/lib-http.d.ts.map +1 -0
- package/dist/nodes/lib-http.js +267 -0
- package/dist/nodes/lib-http.js.map +1 -0
- package/dist/nodes/lib-image-color-grading.d.ts +3 -0
- package/dist/nodes/lib-image-color-grading.d.ts.map +1 -0
- package/dist/nodes/lib-image-color-grading.js +1386 -0
- package/dist/nodes/lib-image-color-grading.js.map +1 -0
- package/dist/nodes/lib-image-draw.d.ts +3 -0
- package/dist/nodes/lib-image-draw.d.ts.map +1 -0
- package/dist/nodes/lib-image-draw.js +470 -0
- package/dist/nodes/lib-image-draw.js.map +1 -0
- package/dist/nodes/lib-image-enhance.d.ts +3 -0
- package/dist/nodes/lib-image-enhance.d.ts.map +1 -0
- package/dist/nodes/lib-image-enhance.js +731 -0
- package/dist/nodes/lib-image-enhance.js.map +1 -0
- package/dist/nodes/lib-image-filter.d.ts +3 -0
- package/dist/nodes/lib-image-filter.d.ts.map +1 -0
- package/dist/nodes/lib-image-filter.js +684 -0
- package/dist/nodes/lib-image-filter.js.map +1 -0
- package/dist/nodes/lib-image-utils.d.ts +24 -0
- package/dist/nodes/lib-image-utils.d.ts.map +1 -0
- package/dist/nodes/lib-image-utils.js +150 -0
- package/dist/nodes/lib-image-utils.js.map +1 -0
- package/dist/nodes/lib-mail.d.ts +74 -0
- package/dist/nodes/lib-mail.d.ts.map +1 -0
- package/dist/nodes/lib-mail.js +452 -0
- package/dist/nodes/lib-mail.js.map +1 -0
- package/dist/nodes/lib-markdown.d.ts +70 -0
- package/dist/nodes/lib-markdown.d.ts.map +1 -0
- package/dist/nodes/lib-markdown.js +236 -0
- package/dist/nodes/lib-markdown.js.map +1 -0
- package/dist/nodes/lib-nlp.d.ts +98 -0
- package/dist/nodes/lib-nlp.d.ts.map +1 -0
- package/dist/nodes/lib-nlp.js +374 -0
- package/dist/nodes/lib-nlp.js.map +1 -0
- package/dist/nodes/lib-notion.d.ts +99 -0
- package/dist/nodes/lib-notion.d.ts.map +1 -0
- package/dist/nodes/lib-notion.js +601 -0
- package/dist/nodes/lib-notion.js.map +1 -0
- package/dist/nodes/lib-ocr.d.ts +31 -0
- package/dist/nodes/lib-ocr.d.ts.map +1 -0
- package/dist/nodes/lib-ocr.js +143 -0
- package/dist/nodes/lib-ocr.js.map +1 -0
- package/dist/nodes/lib-os.d.ts +312 -0
- package/dist/nodes/lib-os.d.ts.map +1 -0
- package/dist/nodes/lib-os.js +909 -0
- package/dist/nodes/lib-os.js.map +1 -0
- package/dist/nodes/lib-pdf.d.ts +142 -0
- package/dist/nodes/lib-pdf.d.ts.map +1 -0
- package/dist/nodes/lib-pdf.js +871 -0
- package/dist/nodes/lib-pdf.js.map +1 -0
- package/dist/nodes/lib-pptx.d.ts +29 -0
- package/dist/nodes/lib-pptx.d.ts.map +1 -0
- package/dist/nodes/lib-pptx.js +122 -0
- package/dist/nodes/lib-pptx.js.map +1 -0
- package/dist/nodes/lib-rss.d.ts +31 -0
- package/dist/nodes/lib-rss.d.ts.map +1 -0
- package/dist/nodes/lib-rss.js +163 -0
- package/dist/nodes/lib-rss.js.map +1 -0
- package/dist/nodes/lib-s3.d.ts +112 -0
- package/dist/nodes/lib-s3.d.ts.map +1 -0
- package/dist/nodes/lib-s3.js +521 -0
- package/dist/nodes/lib-s3.js.map +1 -0
- package/dist/nodes/lib-secret.d.ts +15 -0
- package/dist/nodes/lib-secret.d.ts.map +1 -0
- package/dist/nodes/lib-secret.js +42 -0
- package/dist/nodes/lib-secret.js.map +1 -0
- package/dist/nodes/lib-sqlite.d.ts +102 -0
- package/dist/nodes/lib-sqlite.d.ts.map +1 -0
- package/dist/nodes/lib-sqlite.js +532 -0
- package/dist/nodes/lib-sqlite.js.map +1 -0
- package/dist/nodes/lib-supabase.d.ts +86 -0
- package/dist/nodes/lib-supabase.d.ts.map +1 -0
- package/dist/nodes/lib-supabase.js +425 -0
- package/dist/nodes/lib-supabase.js.map +1 -0
- package/dist/nodes/lib-svg.d.ts +199 -0
- package/dist/nodes/lib-svg.d.ts.map +1 -0
- package/dist/nodes/lib-svg.js +1027 -0
- package/dist/nodes/lib-svg.js.map +1 -0
- package/dist/nodes/lib-tensorflow.d.ts +71 -0
- package/dist/nodes/lib-tensorflow.d.ts.map +1 -0
- package/dist/nodes/lib-tensorflow.js +351 -0
- package/dist/nodes/lib-tensorflow.js.map +1 -0
- package/dist/nodes/lib-twilio.d.ts +71 -0
- package/dist/nodes/lib-twilio.d.ts.map +1 -0
- package/dist/nodes/lib-twilio.js +469 -0
- package/dist/nodes/lib-twilio.js.map +1 -0
- package/dist/nodes/lib-validate.d.ts +84 -0
- package/dist/nodes/lib-validate.d.ts.map +1 -0
- package/dist/nodes/lib-validate.js +215 -0
- package/dist/nodes/lib-validate.js.map +1 -0
- package/dist/nodes/lib-video-download.d.ts +26 -0
- package/dist/nodes/lib-video-download.d.ts.map +1 -0
- package/dist/nodes/lib-video-download.js +299 -0
- package/dist/nodes/lib-video-download.js.map +1 -0
- package/dist/nodes/messaging.d.ts +88 -0
- package/dist/nodes/messaging.d.ts.map +1 -0
- package/dist/nodes/messaging.js +418 -0
- package/dist/nodes/messaging.js.map +1 -0
- package/dist/nodes/mistral.d.ts +83 -0
- package/dist/nodes/mistral.d.ts.map +1 -0
- package/dist/nodes/mistral.js +450 -0
- package/dist/nodes/mistral.js.map +1 -0
- package/dist/nodes/model3d/analysis.d.ts +13 -0
- package/dist/nodes/model3d/analysis.d.ts.map +1 -0
- package/dist/nodes/model3d/analysis.js +36 -0
- package/dist/nodes/model3d/analysis.js.map +1 -0
- package/dist/nodes/model3d/base.d.ts +11 -0
- package/dist/nodes/model3d/base.d.ts.map +1 -0
- package/dist/nodes/model3d/base.js +20 -0
- package/dist/nodes/model3d/base.js.map +1 -0
- package/dist/nodes/model3d/boolean-ops.d.ts +2 -0
- package/dist/nodes/model3d/boolean-ops.d.ts.map +1 -0
- package/dist/nodes/model3d/boolean-ops.js +172 -0
- package/dist/nodes/model3d/boolean-ops.js.map +1 -0
- package/dist/nodes/model3d/cleanup.d.ts +47 -0
- package/dist/nodes/model3d/cleanup.d.ts.map +1 -0
- package/dist/nodes/model3d/cleanup.js +136 -0
- package/dist/nodes/model3d/cleanup.js.map +1 -0
- package/dist/nodes/model3d/convert.d.ts +14 -0
- package/dist/nodes/model3d/convert.d.ts.map +1 -0
- package/dist/nodes/model3d/convert.js +64 -0
- package/dist/nodes/model3d/convert.js.map +1 -0
- package/dist/nodes/model3d/defaults.d.ts +34 -0
- package/dist/nodes/model3d/defaults.d.ts.map +1 -0
- package/dist/nodes/model3d/defaults.js +28 -0
- package/dist/nodes/model3d/defaults.js.map +1 -0
- package/dist/nodes/model3d/document-ops.d.ts +4 -0
- package/dist/nodes/model3d/document-ops.d.ts.map +1 -0
- package/dist/nodes/model3d/document-ops.js +40 -0
- package/dist/nodes/model3d/document-ops.js.map +1 -0
- package/dist/nodes/model3d/generation.d.ts +39 -0
- package/dist/nodes/model3d/generation.d.ts.map +1 -0
- package/dist/nodes/model3d/generation.js +179 -0
- package/dist/nodes/model3d/generation.js.map +1 -0
- package/dist/nodes/model3d/glb.d.ts +29 -0
- package/dist/nodes/model3d/glb.d.ts.map +1 -0
- package/dist/nodes/model3d/glb.js +255 -0
- package/dist/nodes/model3d/glb.js.map +1 -0
- package/dist/nodes/model3d/index.d.ts +20 -0
- package/dist/nodes/model3d/index.d.ts.map +1 -0
- package/dist/nodes/model3d/index.js +38 -0
- package/dist/nodes/model3d/index.js.map +1 -0
- package/dist/nodes/model3d/io.d.ts +38 -0
- package/dist/nodes/model3d/io.d.ts.map +1 -0
- package/dist/nodes/model3d/io.js +162 -0
- package/dist/nodes/model3d/io.js.map +1 -0
- package/dist/nodes/model3d/mesh-ops.d.ts +40 -0
- package/dist/nodes/model3d/mesh-ops.d.ts.map +1 -0
- package/dist/nodes/model3d/mesh-ops.js +775 -0
- package/dist/nodes/model3d/mesh-ops.js.map +1 -0
- package/dist/nodes/model3d/nodes.d.ts +2 -0
- package/dist/nodes/model3d/nodes.d.ts.map +1 -0
- package/dist/nodes/model3d/nodes.js +2 -0
- package/dist/nodes/model3d/nodes.js.map +1 -0
- package/dist/nodes/model3d/ops.d.ts +37 -0
- package/dist/nodes/model3d/ops.d.ts.map +1 -0
- package/dist/nodes/model3d/ops.js +137 -0
- package/dist/nodes/model3d/ops.js.map +1 -0
- package/dist/nodes/model3d/transforms.d.ts +49 -0
- package/dist/nodes/model3d/transforms.d.ts.map +1 -0
- package/dist/nodes/model3d/transforms.js +142 -0
- package/dist/nodes/model3d/transforms.js.map +1 -0
- package/dist/nodes/model3d/types.d.ts +81 -0
- package/dist/nodes/model3d/types.d.ts.map +1 -0
- package/dist/nodes/model3d/types.js +2 -0
- package/dist/nodes/model3d/types.js.map +1 -0
- package/dist/nodes/model3d/utils.d.ts +34 -0
- package/dist/nodes/model3d/utils.d.ts.map +1 -0
- package/dist/nodes/model3d/utils.js +185 -0
- package/dist/nodes/model3d/utils.js.map +1 -0
- package/dist/nodes/model3d.d.ts +2 -0
- package/dist/nodes/model3d.d.ts.map +1 -0
- package/dist/nodes/model3d.js +2 -0
- package/dist/nodes/model3d.js.map +1 -0
- package/dist/nodes/openai.d.ts +172 -0
- package/dist/nodes/openai.d.ts.map +1 -0
- package/dist/nodes/openai.js +1294 -0
- package/dist/nodes/openai.js.map +1 -0
- package/dist/nodes/output.d.ts +29 -0
- package/dist/nodes/output.d.ts.map +1 -0
- package/dist/nodes/output.js +87 -0
- package/dist/nodes/output.js.map +1 -0
- package/dist/nodes/sandbox.d.ts +67 -0
- package/dist/nodes/sandbox.d.ts.map +1 -0
- package/dist/nodes/sandbox.js +681 -0
- package/dist/nodes/sandbox.js.map +1 -0
- package/dist/nodes/search.d.ts +117 -0
- package/dist/nodes/search.d.ts.map +1 -0
- package/dist/nodes/search.js +607 -0
- package/dist/nodes/search.js.map +1 -0
- package/dist/nodes/team.d.ts +74 -0
- package/dist/nodes/team.d.ts.map +1 -0
- package/dist/nodes/team.js +304 -0
- package/dist/nodes/team.js.map +1 -0
- package/dist/nodes/text-extra.d.ts +633 -0
- package/dist/nodes/text-extra.d.ts.map +1 -0
- package/dist/nodes/text-extra.js +2226 -0
- package/dist/nodes/text-extra.js.map +1 -0
- package/dist/nodes/tool-agents.d.ts +334 -0
- package/dist/nodes/tool-agents.d.ts.map +1 -0
- package/dist/nodes/tool-agents.js +1861 -0
- package/dist/nodes/tool-agents.js.map +1 -0
- package/dist/nodes/triggers.d.ts +107 -0
- package/dist/nodes/triggers.d.ts.map +1 -0
- package/dist/nodes/triggers.js +706 -0
- package/dist/nodes/triggers.js.map +1 -0
- package/dist/nodes/vector.d.ts +168 -0
- package/dist/nodes/vector.d.ts.map +1 -0
- package/dist/nodes/vector.js +1121 -0
- package/dist/nodes/vector.js.map +1 -0
- package/dist/nodes/video.d.ts +387 -0
- package/dist/nodes/video.d.ts.map +1 -0
- package/dist/nodes/video.js +2361 -0
- package/dist/nodes/video.js.map +1 -0
- package/dist/nodes/workflow.d.ts +24 -0
- package/dist/nodes/workflow.d.ts.map +1 -0
- package/dist/nodes/workflow.js +146 -0
- package/dist/nodes/workflow.js.map +1 -0
- package/dist/nodes/workspace.d.ts +203 -0
- package/dist/nodes/workspace.d.ts.map +1 -0
- package/dist/nodes/workspace.js +795 -0
- package/dist/nodes/workspace.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,984 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { BaseNode, prop } from "@nodetool-ai/node-sdk";
|
|
8
|
+
import { promises as fs } from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
function documentSourceId(refOrPath) {
|
|
11
|
+
if (typeof refOrPath === "string" && refOrPath) {
|
|
12
|
+
return refOrPath;
|
|
13
|
+
}
|
|
14
|
+
if (refOrPath && typeof refOrPath === "object") {
|
|
15
|
+
const ref = refOrPath;
|
|
16
|
+
if (typeof ref.uri === "string" && ref.uri)
|
|
17
|
+
return ref.uri;
|
|
18
|
+
}
|
|
19
|
+
return "document";
|
|
20
|
+
}
|
|
21
|
+
function asBytes(data) {
|
|
22
|
+
if (!data)
|
|
23
|
+
return new Uint8Array();
|
|
24
|
+
if (data instanceof Uint8Array)
|
|
25
|
+
return data;
|
|
26
|
+
return Uint8Array.from(Buffer.from(data, "base64"));
|
|
27
|
+
}
|
|
28
|
+
function toFilePath(uriOrPath) {
|
|
29
|
+
if (uriOrPath.startsWith("file://")) {
|
|
30
|
+
return uriOrPath.slice("file://".length);
|
|
31
|
+
}
|
|
32
|
+
return uriOrPath;
|
|
33
|
+
}
|
|
34
|
+
function wildcardToRegExp(pattern) {
|
|
35
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
36
|
+
return new RegExp(`^${escaped.replaceAll("*", ".*")}$`);
|
|
37
|
+
}
|
|
38
|
+
function textChunk(text, sourceId, startIndex) {
|
|
39
|
+
return {
|
|
40
|
+
chunk: text,
|
|
41
|
+
text,
|
|
42
|
+
source_id: sourceId,
|
|
43
|
+
start_index: startIndex
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function splitByChunk(text, chunkSize, overlap) {
|
|
47
|
+
if (!text)
|
|
48
|
+
return [];
|
|
49
|
+
const size = Math.max(1, chunkSize);
|
|
50
|
+
const step = Math.max(1, size - Math.max(0, overlap));
|
|
51
|
+
const out = [];
|
|
52
|
+
for (let i = 0; i < text.length; i += step) {
|
|
53
|
+
out.push(text.slice(i, i + size));
|
|
54
|
+
if (i + size >= text.length)
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
async function readDocumentText(refOrPath, context) {
|
|
60
|
+
if (typeof refOrPath === "string" && refOrPath) {
|
|
61
|
+
if (context?.storage) {
|
|
62
|
+
const stored = await context.storage.retrieve(refOrPath);
|
|
63
|
+
if (stored !== null)
|
|
64
|
+
return Buffer.from(stored).toString("utf8");
|
|
65
|
+
}
|
|
66
|
+
return fs.readFile(toFilePath(refOrPath), "utf8");
|
|
67
|
+
}
|
|
68
|
+
if (refOrPath && typeof refOrPath === "object") {
|
|
69
|
+
const ref = refOrPath;
|
|
70
|
+
if (typeof ref.text === "string")
|
|
71
|
+
return ref.text;
|
|
72
|
+
if (ref.data) {
|
|
73
|
+
const bytes = asBytes(ref.data);
|
|
74
|
+
return Buffer.from(bytes).toString("utf8");
|
|
75
|
+
}
|
|
76
|
+
if (typeof ref.uri === "string" && ref.uri) {
|
|
77
|
+
if (context?.storage) {
|
|
78
|
+
const stored = await context.storage.retrieve(ref.uri);
|
|
79
|
+
if (stored !== null)
|
|
80
|
+
return Buffer.from(stored).toString("utf8");
|
|
81
|
+
}
|
|
82
|
+
if (ref.uri.startsWith("file://") || !ref.uri.startsWith("http")) {
|
|
83
|
+
return fs.readFile(toFilePath(ref.uri), "utf8");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return "";
|
|
88
|
+
}
|
|
89
|
+
export class LoadDocumentFileNode extends BaseNode {
|
|
90
|
+
static nodeType = "nodetool.document.LoadDocumentFile";
|
|
91
|
+
static title = "Load Document File";
|
|
92
|
+
static description = "Read a document from disk.\n files, document, read, input, load, file";
|
|
93
|
+
static metadataOutputTypes = {
|
|
94
|
+
output: "document"
|
|
95
|
+
};
|
|
96
|
+
async process() {
|
|
97
|
+
const p = String(this.path ?? this.path ?? "");
|
|
98
|
+
const full = toFilePath(p);
|
|
99
|
+
const bytes = new Uint8Array(await fs.readFile(full));
|
|
100
|
+
return {
|
|
101
|
+
output: {
|
|
102
|
+
uri: `file://${full}`,
|
|
103
|
+
data: Buffer.from(bytes).toString("base64")
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
__decorate([
|
|
109
|
+
prop({
|
|
110
|
+
type: "str",
|
|
111
|
+
default: "",
|
|
112
|
+
title: "Path",
|
|
113
|
+
description: "Path to the document to read"
|
|
114
|
+
})
|
|
115
|
+
], LoadDocumentFileNode.prototype, "path", void 0);
|
|
116
|
+
export class SaveDocumentFileNode extends BaseNode {
|
|
117
|
+
static nodeType = "nodetool.document.SaveDocumentFile";
|
|
118
|
+
static title = "Save Document File";
|
|
119
|
+
static description = "Write a document to disk.\n files, document, write, output, save, file\n\n The filename can include time and date variables:\n %Y - Year, %m - Month, %d - Day\n %H - Hour, %M - Minute, %S - Second";
|
|
120
|
+
async process() {
|
|
121
|
+
const document = (this.document ?? this.document ?? {});
|
|
122
|
+
const p = String(this.path ?? "");
|
|
123
|
+
const full = toFilePath(p);
|
|
124
|
+
await fs.mkdir(path.dirname(full), { recursive: true });
|
|
125
|
+
if (document.data) {
|
|
126
|
+
await fs.writeFile(full, asBytes(document.data));
|
|
127
|
+
}
|
|
128
|
+
else if (typeof document.text === "string") {
|
|
129
|
+
await fs.writeFile(full, document.text, "utf8");
|
|
130
|
+
}
|
|
131
|
+
else if (document.uri) {
|
|
132
|
+
await fs.copyFile(toFilePath(document.uri), full);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
await fs.writeFile(full, "", "utf8");
|
|
136
|
+
}
|
|
137
|
+
return { output: full };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
__decorate([
|
|
141
|
+
prop({
|
|
142
|
+
type: "document",
|
|
143
|
+
default: {
|
|
144
|
+
type: "document",
|
|
145
|
+
uri: "",
|
|
146
|
+
asset_id: null,
|
|
147
|
+
data: null,
|
|
148
|
+
metadata: null
|
|
149
|
+
},
|
|
150
|
+
title: "Document",
|
|
151
|
+
description: "The document to save"
|
|
152
|
+
})
|
|
153
|
+
], SaveDocumentFileNode.prototype, "document", void 0);
|
|
154
|
+
__decorate([
|
|
155
|
+
prop({
|
|
156
|
+
type: "str",
|
|
157
|
+
default: "",
|
|
158
|
+
title: "Folder",
|
|
159
|
+
description: "Folder where the file will be saved"
|
|
160
|
+
})
|
|
161
|
+
], SaveDocumentFileNode.prototype, "folder", void 0);
|
|
162
|
+
__decorate([
|
|
163
|
+
prop({
|
|
164
|
+
type: "str",
|
|
165
|
+
default: "",
|
|
166
|
+
title: "Filename",
|
|
167
|
+
description: "Name of the file to save. Supports strftime format codes."
|
|
168
|
+
})
|
|
169
|
+
], SaveDocumentFileNode.prototype, "filename", void 0);
|
|
170
|
+
export class ListDocumentsNode extends BaseNode {
|
|
171
|
+
static nodeType = "nodetool.document.ListDocuments";
|
|
172
|
+
static title = "List Documents";
|
|
173
|
+
static description = "List documents in a directory.\n files, list, directory";
|
|
174
|
+
static metadataOutputTypes = {
|
|
175
|
+
document: "document",
|
|
176
|
+
documents: "list"
|
|
177
|
+
};
|
|
178
|
+
static isStreamingOutput = true;
|
|
179
|
+
async process() {
|
|
180
|
+
const collected = [];
|
|
181
|
+
for await (const item of this._listDocuments()) {
|
|
182
|
+
collected.push(item.document);
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
document: collected[0] ?? { uri: "" },
|
|
186
|
+
documents: collected
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
async *_listDocuments() {
|
|
190
|
+
const folder = String(this.folder ?? this.folder ?? ".");
|
|
191
|
+
const pattern = String(this.pattern ?? this.pattern ?? "*");
|
|
192
|
+
const recursive = Boolean(this.recursive ?? this.recursive ?? false);
|
|
193
|
+
const allowed = new Set([
|
|
194
|
+
".txt",
|
|
195
|
+
".md",
|
|
196
|
+
".markdown",
|
|
197
|
+
".json",
|
|
198
|
+
".html",
|
|
199
|
+
".pdf",
|
|
200
|
+
".docx"
|
|
201
|
+
]);
|
|
202
|
+
const matches = wildcardToRegExp(pattern);
|
|
203
|
+
const visit = async function* (dir) {
|
|
204
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
205
|
+
for (const entry of entries) {
|
|
206
|
+
const full = path.join(dir, entry.name);
|
|
207
|
+
if (entry.isDirectory()) {
|
|
208
|
+
if (recursive) {
|
|
209
|
+
yield* visit(full);
|
|
210
|
+
}
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
yield full;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
for await (const full of visit(folder)) {
|
|
217
|
+
if (allowed.has(path.extname(full).toLowerCase()) &&
|
|
218
|
+
matches.test(path.basename(full))) {
|
|
219
|
+
yield { document: { uri: `file://${full}` } };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
async *genProcess() {
|
|
224
|
+
const collected = [];
|
|
225
|
+
for await (const item of this._listDocuments()) {
|
|
226
|
+
collected.push(item.document);
|
|
227
|
+
yield { document: item.document };
|
|
228
|
+
}
|
|
229
|
+
yield { documents: collected };
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
__decorate([
|
|
233
|
+
prop({
|
|
234
|
+
type: "str",
|
|
235
|
+
default: "~",
|
|
236
|
+
title: "Folder",
|
|
237
|
+
description: "Directory to scan"
|
|
238
|
+
})
|
|
239
|
+
], ListDocumentsNode.prototype, "folder", void 0);
|
|
240
|
+
__decorate([
|
|
241
|
+
prop({
|
|
242
|
+
type: "str",
|
|
243
|
+
default: "*",
|
|
244
|
+
title: "Pattern",
|
|
245
|
+
description: "File pattern to match (e.g. *.txt)"
|
|
246
|
+
})
|
|
247
|
+
], ListDocumentsNode.prototype, "pattern", void 0);
|
|
248
|
+
__decorate([
|
|
249
|
+
prop({
|
|
250
|
+
type: "bool",
|
|
251
|
+
default: false,
|
|
252
|
+
title: "Recursive",
|
|
253
|
+
description: "Search subdirectories"
|
|
254
|
+
})
|
|
255
|
+
], ListDocumentsNode.prototype, "recursive", void 0);
|
|
256
|
+
export class SplitDocumentNode extends BaseNode {
|
|
257
|
+
static nodeType = "nodetool.document.SplitDocument";
|
|
258
|
+
static title = "Split Document";
|
|
259
|
+
static description = "Split text semantically.\n chroma, embedding, collection, RAG, index, text, markdown, semantic";
|
|
260
|
+
static metadataOutputTypes = {
|
|
261
|
+
text: "str",
|
|
262
|
+
source_id: "str",
|
|
263
|
+
start_index: "int",
|
|
264
|
+
chunks: "list"
|
|
265
|
+
};
|
|
266
|
+
static recommendedModels = [
|
|
267
|
+
{
|
|
268
|
+
id: "embeddinggemma",
|
|
269
|
+
type: "embedding_model",
|
|
270
|
+
name: "Embedding Gemma",
|
|
271
|
+
repo_id: "embeddinggemma",
|
|
272
|
+
description: "Embedding model for semantic splitting"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
id: "nomic-embed-text",
|
|
276
|
+
type: "embedding_model",
|
|
277
|
+
name: "Nomic Embed Text",
|
|
278
|
+
repo_id: "nomic-embed-text",
|
|
279
|
+
description: "Embedding model for semantic splitting"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
id: "mxbai-embed-large",
|
|
283
|
+
type: "embedding_model",
|
|
284
|
+
name: "MXBai Embed Large",
|
|
285
|
+
repo_id: "mxbai-embed-large",
|
|
286
|
+
description: "Embedding model for semantic splitting"
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
id: "bge-m3",
|
|
290
|
+
type: "embedding_model",
|
|
291
|
+
name: "BGE M3",
|
|
292
|
+
repo_id: "bge-m3",
|
|
293
|
+
description: "Embedding model for semantic splitting"
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
id: "all-minilm",
|
|
297
|
+
type: "embedding_model",
|
|
298
|
+
name: "All Minilm",
|
|
299
|
+
repo_id: "all-minilm",
|
|
300
|
+
description: "Embedding model for semantic splitting"
|
|
301
|
+
}
|
|
302
|
+
];
|
|
303
|
+
static isStreamingOutput = true;
|
|
304
|
+
async process(context) {
|
|
305
|
+
const collected = [];
|
|
306
|
+
for await (const item of this.genProcess(context)) {
|
|
307
|
+
if ("chunks" in item)
|
|
308
|
+
continue;
|
|
309
|
+
collected.push(item);
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
text: collected[0]?.text ?? "",
|
|
313
|
+
source_id: collected[0]?.source_id ?? "",
|
|
314
|
+
start_index: collected[0]?.start_index ?? 0,
|
|
315
|
+
chunks: collected
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
async *genProcess(context) {
|
|
319
|
+
const document = this.document ?? this.document;
|
|
320
|
+
const text = await readDocumentText(document, context);
|
|
321
|
+
const sourceId = documentSourceId(document);
|
|
322
|
+
const chunkSize = Number(this.chunk_size ?? 1200);
|
|
323
|
+
const overlap = Number(this.chunk_overlap ?? 100);
|
|
324
|
+
const collected = [];
|
|
325
|
+
let startIndex = 0;
|
|
326
|
+
for (const chunk of splitByChunk(text, chunkSize, overlap)) {
|
|
327
|
+
const idx = text.indexOf(chunk, startIndex);
|
|
328
|
+
const resolvedIndex = idx >= 0 ? idx : startIndex;
|
|
329
|
+
const item = textChunk(chunk, sourceId, resolvedIndex);
|
|
330
|
+
collected.push(item);
|
|
331
|
+
yield item;
|
|
332
|
+
startIndex = resolvedIndex + Math.max(chunk.length - overlap, 1);
|
|
333
|
+
}
|
|
334
|
+
yield { chunks: collected };
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
__decorate([
|
|
338
|
+
prop({
|
|
339
|
+
type: "language_model",
|
|
340
|
+
default: {
|
|
341
|
+
type: "language_model",
|
|
342
|
+
provider: "ollama",
|
|
343
|
+
id: "embeddinggemma",
|
|
344
|
+
name: "",
|
|
345
|
+
path: null,
|
|
346
|
+
supported_tasks: []
|
|
347
|
+
},
|
|
348
|
+
title: "Embed Model",
|
|
349
|
+
description: "Embedding model to use"
|
|
350
|
+
})
|
|
351
|
+
], SplitDocumentNode.prototype, "embed_model", void 0);
|
|
352
|
+
__decorate([
|
|
353
|
+
prop({
|
|
354
|
+
type: "document",
|
|
355
|
+
default: {
|
|
356
|
+
type: "document",
|
|
357
|
+
uri: "",
|
|
358
|
+
asset_id: null,
|
|
359
|
+
data: null,
|
|
360
|
+
metadata: null
|
|
361
|
+
},
|
|
362
|
+
title: "Document",
|
|
363
|
+
description: "Document ID to associate with the text content"
|
|
364
|
+
})
|
|
365
|
+
], SplitDocumentNode.prototype, "document", void 0);
|
|
366
|
+
__decorate([
|
|
367
|
+
prop({
|
|
368
|
+
type: "int",
|
|
369
|
+
default: 1,
|
|
370
|
+
title: "Buffer Size",
|
|
371
|
+
description: "Buffer size for semantic splitting",
|
|
372
|
+
min: 1,
|
|
373
|
+
max: 100
|
|
374
|
+
})
|
|
375
|
+
], SplitDocumentNode.prototype, "buffer_size", void 0);
|
|
376
|
+
__decorate([
|
|
377
|
+
prop({
|
|
378
|
+
type: "int",
|
|
379
|
+
default: 95,
|
|
380
|
+
title: "Threshold",
|
|
381
|
+
description: "Breakpoint percentile threshold for semantic splitting",
|
|
382
|
+
min: 0,
|
|
383
|
+
max: 100
|
|
384
|
+
})
|
|
385
|
+
], SplitDocumentNode.prototype, "threshold", void 0);
|
|
386
|
+
export class SplitHTMLNode extends BaseNode {
|
|
387
|
+
static nodeType = "nodetool.document.SplitHTML";
|
|
388
|
+
static title = "Split HTML";
|
|
389
|
+
static description = "Split HTML content into semantic chunks based on HTML tags.\n html, text, semantic, tags, parsing";
|
|
390
|
+
static metadataOutputTypes = {
|
|
391
|
+
text: "str",
|
|
392
|
+
source_id: "str",
|
|
393
|
+
start_index: "int",
|
|
394
|
+
chunks: "list"
|
|
395
|
+
};
|
|
396
|
+
static isStreamingOutput = true;
|
|
397
|
+
async process(context) {
|
|
398
|
+
const collected = [];
|
|
399
|
+
for await (const item of this.genProcess(context)) {
|
|
400
|
+
if ("chunks" in item)
|
|
401
|
+
continue;
|
|
402
|
+
collected.push(item);
|
|
403
|
+
}
|
|
404
|
+
return {
|
|
405
|
+
text: collected[0]?.text ?? "",
|
|
406
|
+
source_id: collected[0]?.source_id ?? "",
|
|
407
|
+
start_index: collected[0]?.start_index ?? 0,
|
|
408
|
+
chunks: collected
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
async *genProcess(context) {
|
|
412
|
+
const document = this.document ?? this.document;
|
|
413
|
+
const html = await readDocumentText(document, context);
|
|
414
|
+
const sourceId = documentSourceId(document);
|
|
415
|
+
const chunkSize = Number(this.chunk_size ?? 1200);
|
|
416
|
+
const overlap = Number(this.chunk_overlap ?? 100);
|
|
417
|
+
// Split on block-level HTML tags
|
|
418
|
+
const blockTags = "p|div|h[1-6]|li|section|article|blockquote|tr|pre|header|footer|nav|main|aside";
|
|
419
|
+
const blockPattern = new RegExp(`<(?:${blockTags})(?:\\s[^>]*)?>([\\s\\S]*?)<\\/(?:${blockTags})>`, "gi");
|
|
420
|
+
const sections = [];
|
|
421
|
+
let lastIndex = 0;
|
|
422
|
+
let match;
|
|
423
|
+
while ((match = blockPattern.exec(html)) !== null) {
|
|
424
|
+
// Capture any text between block elements
|
|
425
|
+
if (match.index > lastIndex) {
|
|
426
|
+
const between = html
|
|
427
|
+
.slice(lastIndex, match.index)
|
|
428
|
+
.replace(/<[^>]+>/g, " ")
|
|
429
|
+
.replace(/\s+/g, " ")
|
|
430
|
+
.trim();
|
|
431
|
+
if (between)
|
|
432
|
+
sections.push(between);
|
|
433
|
+
}
|
|
434
|
+
// Extract text content from the block element
|
|
435
|
+
const content = match[1]
|
|
436
|
+
.replace(/<[^>]+>/g, " ")
|
|
437
|
+
.replace(/\s+/g, " ")
|
|
438
|
+
.trim();
|
|
439
|
+
if (content)
|
|
440
|
+
sections.push(content);
|
|
441
|
+
lastIndex = match.index + match[0].length;
|
|
442
|
+
}
|
|
443
|
+
// Any remaining text after the last block element
|
|
444
|
+
if (lastIndex < html.length) {
|
|
445
|
+
const remaining = html
|
|
446
|
+
.slice(lastIndex)
|
|
447
|
+
.replace(/<[^>]+>/g, " ")
|
|
448
|
+
.replace(/\s+/g, " ")
|
|
449
|
+
.trim();
|
|
450
|
+
if (remaining)
|
|
451
|
+
sections.push(remaining);
|
|
452
|
+
}
|
|
453
|
+
// If no block elements found, fall back to stripping all tags
|
|
454
|
+
if (sections.length === 0) {
|
|
455
|
+
const text = html
|
|
456
|
+
.replace(/<[^>]+>/g, " ")
|
|
457
|
+
.replace(/\s+/g, " ")
|
|
458
|
+
.trim();
|
|
459
|
+
if (text)
|
|
460
|
+
sections.push(text);
|
|
461
|
+
}
|
|
462
|
+
// Merge small sections and split large ones respecting chunk_size
|
|
463
|
+
const collected = [];
|
|
464
|
+
let startIndex = 0;
|
|
465
|
+
let chunkIdx = 0;
|
|
466
|
+
let buffer = "";
|
|
467
|
+
for (const section of sections) {
|
|
468
|
+
if (buffer && (buffer.length + 1 + section.length) > chunkSize) {
|
|
469
|
+
// Emit buffer
|
|
470
|
+
for (const chunk of splitByChunk(buffer, chunkSize, overlap)) {
|
|
471
|
+
const item = textChunk(chunk, `${sourceId}:${chunkIdx}`, startIndex);
|
|
472
|
+
collected.push(item);
|
|
473
|
+
yield item;
|
|
474
|
+
startIndex += Math.max(chunk.length - overlap, 1);
|
|
475
|
+
chunkIdx++;
|
|
476
|
+
}
|
|
477
|
+
buffer = "";
|
|
478
|
+
}
|
|
479
|
+
buffer = buffer ? buffer + "\n" + section : section;
|
|
480
|
+
}
|
|
481
|
+
// Emit remaining buffer
|
|
482
|
+
if (buffer) {
|
|
483
|
+
for (const chunk of splitByChunk(buffer, chunkSize, overlap)) {
|
|
484
|
+
const item = textChunk(chunk, `${sourceId}:${chunkIdx}`, startIndex);
|
|
485
|
+
collected.push(item);
|
|
486
|
+
yield item;
|
|
487
|
+
startIndex += Math.max(chunk.length - overlap, 1);
|
|
488
|
+
chunkIdx++;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
yield { chunks: collected };
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
__decorate([
|
|
495
|
+
prop({
|
|
496
|
+
type: "document",
|
|
497
|
+
default: {
|
|
498
|
+
type: "document",
|
|
499
|
+
uri: "",
|
|
500
|
+
asset_id: null,
|
|
501
|
+
data: null,
|
|
502
|
+
metadata: null
|
|
503
|
+
},
|
|
504
|
+
title: "Document",
|
|
505
|
+
description: "Document ID to associate with the HTML content"
|
|
506
|
+
})
|
|
507
|
+
], SplitHTMLNode.prototype, "document", void 0);
|
|
508
|
+
export class SplitJSONNode extends BaseNode {
|
|
509
|
+
static nodeType = "nodetool.document.SplitJSON";
|
|
510
|
+
static title = "Split JSON";
|
|
511
|
+
static description = "Split JSON content into semantic chunks.\n json, parsing, semantic, structured";
|
|
512
|
+
static metadataOutputTypes = {
|
|
513
|
+
text: "str",
|
|
514
|
+
source_id: "str",
|
|
515
|
+
start_index: "int",
|
|
516
|
+
chunks: "list"
|
|
517
|
+
};
|
|
518
|
+
static isStreamingOutput = true;
|
|
519
|
+
async process(context) {
|
|
520
|
+
const collected = [];
|
|
521
|
+
for await (const item of this.genProcess(context)) {
|
|
522
|
+
if ("chunks" in item)
|
|
523
|
+
continue;
|
|
524
|
+
collected.push(item);
|
|
525
|
+
}
|
|
526
|
+
return {
|
|
527
|
+
text: collected[0]?.text ?? "",
|
|
528
|
+
source_id: collected[0]?.source_id ?? "",
|
|
529
|
+
start_index: collected[0]?.start_index ?? 0,
|
|
530
|
+
chunks: collected
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
async *genProcess(context) {
|
|
534
|
+
const document = this.document ?? this.document;
|
|
535
|
+
const raw = await readDocumentText(document, context);
|
|
536
|
+
const sourceId = documentSourceId(document);
|
|
537
|
+
const chunkSize = Number(this.chunk_size ?? 1200);
|
|
538
|
+
const overlap = Number(this.chunk_overlap ?? 100);
|
|
539
|
+
const collected = [];
|
|
540
|
+
let parsed;
|
|
541
|
+
try {
|
|
542
|
+
parsed = JSON.parse(raw);
|
|
543
|
+
}
|
|
544
|
+
catch {
|
|
545
|
+
// Fallback to character-based splitting for invalid JSON
|
|
546
|
+
let startIndex = 0;
|
|
547
|
+
for (const chunk of splitByChunk(raw, chunkSize, overlap)) {
|
|
548
|
+
const idx = raw.indexOf(chunk, startIndex);
|
|
549
|
+
const resolvedIndex = idx >= 0 ? idx : startIndex;
|
|
550
|
+
const item = textChunk(chunk, sourceId, resolvedIndex);
|
|
551
|
+
collected.push(item);
|
|
552
|
+
yield item;
|
|
553
|
+
startIndex = resolvedIndex + Math.max(chunk.length - overlap, 1);
|
|
554
|
+
}
|
|
555
|
+
yield { chunks: collected };
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
// Split by JSON structure
|
|
559
|
+
let elements;
|
|
560
|
+
if (Array.isArray(parsed)) {
|
|
561
|
+
// Top-level array: split into individual elements
|
|
562
|
+
elements = parsed.map((item) => JSON.stringify(item, null, 2));
|
|
563
|
+
}
|
|
564
|
+
else if (parsed && typeof parsed === "object") {
|
|
565
|
+
// Top-level object: split by top-level keys
|
|
566
|
+
elements = Object.entries(parsed).map(([key, value]) => JSON.stringify({ [key]: value }, null, 2));
|
|
567
|
+
}
|
|
568
|
+
else {
|
|
569
|
+
elements = [JSON.stringify(parsed, null, 2)];
|
|
570
|
+
}
|
|
571
|
+
// Merge small elements and split large ones respecting chunk_size
|
|
572
|
+
let chunkIdx = 0;
|
|
573
|
+
let buffer = "";
|
|
574
|
+
for (const element of elements) {
|
|
575
|
+
if (element.length > chunkSize) {
|
|
576
|
+
// Emit buffer first if any
|
|
577
|
+
if (buffer) {
|
|
578
|
+
const item = textChunk(buffer, `${sourceId}:${chunkIdx}`, chunkIdx);
|
|
579
|
+
collected.push(item);
|
|
580
|
+
yield item;
|
|
581
|
+
chunkIdx++;
|
|
582
|
+
buffer = "";
|
|
583
|
+
}
|
|
584
|
+
// Split large element by characters
|
|
585
|
+
for (const chunk of splitByChunk(element, chunkSize, overlap)) {
|
|
586
|
+
const item = textChunk(chunk, `${sourceId}:${chunkIdx}`, chunkIdx);
|
|
587
|
+
collected.push(item);
|
|
588
|
+
yield item;
|
|
589
|
+
chunkIdx++;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
else if (buffer && (buffer.length + 2 + element.length) > chunkSize) {
|
|
593
|
+
// Buffer would exceed chunk_size, emit it
|
|
594
|
+
const item = textChunk(buffer, `${sourceId}:${chunkIdx}`, chunkIdx);
|
|
595
|
+
collected.push(item);
|
|
596
|
+
yield item;
|
|
597
|
+
chunkIdx++;
|
|
598
|
+
buffer = element;
|
|
599
|
+
}
|
|
600
|
+
else {
|
|
601
|
+
buffer = buffer ? buffer + ",\n" + element : element;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
if (buffer) {
|
|
605
|
+
const item = textChunk(buffer, `${sourceId}:${chunkIdx}`, chunkIdx);
|
|
606
|
+
collected.push(item);
|
|
607
|
+
yield item;
|
|
608
|
+
}
|
|
609
|
+
yield { chunks: collected };
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
__decorate([
|
|
613
|
+
prop({
|
|
614
|
+
type: "document",
|
|
615
|
+
default: {
|
|
616
|
+
type: "document",
|
|
617
|
+
uri: "",
|
|
618
|
+
asset_id: null,
|
|
619
|
+
data: null,
|
|
620
|
+
metadata: null
|
|
621
|
+
},
|
|
622
|
+
title: "Document",
|
|
623
|
+
description: "Document ID to associate with the JSON content"
|
|
624
|
+
})
|
|
625
|
+
], SplitJSONNode.prototype, "document", void 0);
|
|
626
|
+
__decorate([
|
|
627
|
+
prop({
|
|
628
|
+
type: "bool",
|
|
629
|
+
default: true,
|
|
630
|
+
title: "Include Metadata",
|
|
631
|
+
description: "Whether to include metadata in nodes"
|
|
632
|
+
})
|
|
633
|
+
], SplitJSONNode.prototype, "include_metadata", void 0);
|
|
634
|
+
__decorate([
|
|
635
|
+
prop({
|
|
636
|
+
type: "bool",
|
|
637
|
+
default: true,
|
|
638
|
+
title: "Include Prev Next Rel",
|
|
639
|
+
description: "Whether to include prev/next relationships"
|
|
640
|
+
})
|
|
641
|
+
], SplitJSONNode.prototype, "include_prev_next_rel", void 0);
|
|
642
|
+
export class SplitRecursivelyNode extends BaseNode {
|
|
643
|
+
static nodeType = "nodetool.document.SplitRecursively";
|
|
644
|
+
static title = "Split Recursively";
|
|
645
|
+
static description = "Splits text recursively using LangChain's RecursiveCharacterTextSplitter.\n text, split, chunks\n\n Use cases:\n - Splitting documents while preserving semantic relationships\n - Creating chunks for language model processing\n - Handling text in languages with/without word boundaries";
|
|
646
|
+
static metadataOutputTypes = {
|
|
647
|
+
text: "str",
|
|
648
|
+
source_id: "str",
|
|
649
|
+
start_index: "int",
|
|
650
|
+
chunks: "list"
|
|
651
|
+
};
|
|
652
|
+
static isStreamingOutput = true;
|
|
653
|
+
async process(context) {
|
|
654
|
+
const collected = [];
|
|
655
|
+
for await (const item of this.genProcess(context)) {
|
|
656
|
+
if ("chunks" in item)
|
|
657
|
+
continue;
|
|
658
|
+
collected.push(item);
|
|
659
|
+
}
|
|
660
|
+
return {
|
|
661
|
+
text: collected[0]?.text ?? "",
|
|
662
|
+
source_id: collected[0]?.source_id ?? "",
|
|
663
|
+
start_index: collected[0]?.start_index ?? 0,
|
|
664
|
+
chunks: collected
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
async *genProcess(context) {
|
|
668
|
+
const document = this.document ?? this.document;
|
|
669
|
+
const text = await readDocumentText(document, context);
|
|
670
|
+
const sourceId = documentSourceId(document);
|
|
671
|
+
const chunkSize = Number(this.chunk_size ?? this.chunk_size ?? 1000);
|
|
672
|
+
const overlap = Number(this.chunk_overlap ?? this.chunk_overlap ?? 200);
|
|
673
|
+
const separators = Array.isArray(this.separators ?? this.separators)
|
|
674
|
+
? (this.separators ?? this.separators).map((s) => String(s))
|
|
675
|
+
: ["\n\n", "\n", "."];
|
|
676
|
+
// Truly recursive splitting: for each separator in order,
|
|
677
|
+
// split text and recursively split chunks that are too large
|
|
678
|
+
// using the next separator.
|
|
679
|
+
function recursiveSplit(input, sepIndex) {
|
|
680
|
+
if (input.length <= chunkSize)
|
|
681
|
+
return [input];
|
|
682
|
+
if (sepIndex >= separators.length) {
|
|
683
|
+
// No more separators — fall back to character splitting
|
|
684
|
+
return splitByChunk(input, chunkSize, overlap);
|
|
685
|
+
}
|
|
686
|
+
const sep = separators[sepIndex];
|
|
687
|
+
if (!input.includes(sep)) {
|
|
688
|
+
// This separator doesn't exist in the text, try next
|
|
689
|
+
return recursiveSplit(input, sepIndex + 1);
|
|
690
|
+
}
|
|
691
|
+
const rawParts = input.split(sep);
|
|
692
|
+
const merged = [];
|
|
693
|
+
let current = "";
|
|
694
|
+
for (let i = 0; i < rawParts.length; i++) {
|
|
695
|
+
const part = rawParts[i];
|
|
696
|
+
const candidate = current ? current + sep + part : part;
|
|
697
|
+
if (candidate.length <= chunkSize) {
|
|
698
|
+
current = candidate;
|
|
699
|
+
}
|
|
700
|
+
else {
|
|
701
|
+
if (current)
|
|
702
|
+
merged.push(current);
|
|
703
|
+
if (part.length <= chunkSize) {
|
|
704
|
+
current = part;
|
|
705
|
+
}
|
|
706
|
+
else {
|
|
707
|
+
// Part is still too large — recurse with next separator
|
|
708
|
+
const subChunks = recursiveSplit(part, sepIndex + 1);
|
|
709
|
+
for (let j = 0; j < subChunks.length - 1; j++) {
|
|
710
|
+
merged.push(subChunks[j]);
|
|
711
|
+
}
|
|
712
|
+
current = subChunks[subChunks.length - 1];
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
if (current)
|
|
717
|
+
merged.push(current);
|
|
718
|
+
// Apply overlap by prepending end of previous chunk
|
|
719
|
+
if (overlap > 0 && merged.length > 1) {
|
|
720
|
+
const withOverlap = [merged[0]];
|
|
721
|
+
for (let i = 1; i < merged.length; i++) {
|
|
722
|
+
const prev = merged[i - 1];
|
|
723
|
+
const overlapText = prev.slice(-overlap);
|
|
724
|
+
withOverlap.push(overlapText + merged[i]);
|
|
725
|
+
}
|
|
726
|
+
return withOverlap;
|
|
727
|
+
}
|
|
728
|
+
return merged;
|
|
729
|
+
}
|
|
730
|
+
const chunks = recursiveSplit(text, 0);
|
|
731
|
+
const collected = [];
|
|
732
|
+
let chunkIndex = 0;
|
|
733
|
+
let searchFrom = 0;
|
|
734
|
+
for (const chunk of chunks) {
|
|
735
|
+
// Find position accounting for overlap (search from where we expect)
|
|
736
|
+
const idx = text.indexOf(chunk, searchFrom);
|
|
737
|
+
const resolvedIndex = idx >= 0 ? idx : searchFrom;
|
|
738
|
+
const item = textChunk(chunk, `${sourceId}:${chunkIndex}`, resolvedIndex);
|
|
739
|
+
collected.push(item);
|
|
740
|
+
yield item;
|
|
741
|
+
// Move search forward, but not past the overlap region
|
|
742
|
+
searchFrom = resolvedIndex + Math.max(chunk.length - overlap, 1);
|
|
743
|
+
chunkIndex++;
|
|
744
|
+
}
|
|
745
|
+
yield { chunks: collected };
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
__decorate([
|
|
749
|
+
prop({
|
|
750
|
+
type: "document",
|
|
751
|
+
default: {
|
|
752
|
+
type: "document",
|
|
753
|
+
uri: "",
|
|
754
|
+
asset_id: null,
|
|
755
|
+
data: null,
|
|
756
|
+
metadata: null
|
|
757
|
+
},
|
|
758
|
+
title: "Document"
|
|
759
|
+
})
|
|
760
|
+
], SplitRecursivelyNode.prototype, "document", void 0);
|
|
761
|
+
__decorate([
|
|
762
|
+
prop({
|
|
763
|
+
type: "int",
|
|
764
|
+
default: 1000,
|
|
765
|
+
title: "Chunk Size",
|
|
766
|
+
description: "Maximum size of each chunk in characters"
|
|
767
|
+
})
|
|
768
|
+
], SplitRecursivelyNode.prototype, "chunk_size", void 0);
|
|
769
|
+
__decorate([
|
|
770
|
+
prop({
|
|
771
|
+
type: "int",
|
|
772
|
+
default: 200,
|
|
773
|
+
title: "Chunk Overlap",
|
|
774
|
+
description: "Number of characters to overlap between chunks"
|
|
775
|
+
})
|
|
776
|
+
], SplitRecursivelyNode.prototype, "chunk_overlap", void 0);
|
|
777
|
+
__decorate([
|
|
778
|
+
prop({
|
|
779
|
+
type: "list[str]",
|
|
780
|
+
default: ["\n\n", "\n", "."],
|
|
781
|
+
title: "Separators",
|
|
782
|
+
description: "List of separators to use for splitting, in order of preference"
|
|
783
|
+
})
|
|
784
|
+
], SplitRecursivelyNode.prototype, "separators", void 0);
|
|
785
|
+
export class SplitMarkdownNode extends BaseNode {
|
|
786
|
+
static nodeType = "nodetool.document.SplitMarkdown";
|
|
787
|
+
static title = "Split Markdown";
|
|
788
|
+
static description = "Splits markdown text by headers while preserving header hierarchy in metadata.\n markdown, split, headers\n\n Use cases:\n - Splitting markdown documentation while preserving structure\n - Processing markdown files for semantic search\n - Creating context-aware chunks from markdown content";
|
|
789
|
+
static metadataOutputTypes = {
|
|
790
|
+
text: "str",
|
|
791
|
+
source_id: "str",
|
|
792
|
+
start_index: "int",
|
|
793
|
+
chunks: "list"
|
|
794
|
+
};
|
|
795
|
+
static isStreamingOutput = true;
|
|
796
|
+
async process(context) {
|
|
797
|
+
const collected = [];
|
|
798
|
+
for await (const item of this.genProcess(context)) {
|
|
799
|
+
if ("chunks" in item)
|
|
800
|
+
continue;
|
|
801
|
+
collected.push(item);
|
|
802
|
+
}
|
|
803
|
+
return {
|
|
804
|
+
text: collected[0]?.text ?? "",
|
|
805
|
+
source_id: collected[0]?.source_id ?? "",
|
|
806
|
+
start_index: collected[0]?.start_index ?? 0,
|
|
807
|
+
chunks: collected
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
async *genProcess(context) {
|
|
811
|
+
const document = this.document ?? this.document;
|
|
812
|
+
const markdown = await readDocumentText(document, context);
|
|
813
|
+
const sourceId = documentSourceId(document);
|
|
814
|
+
const stripHeaders = Boolean(this.strip_headers ?? this.strip_headers ?? true);
|
|
815
|
+
const returnEachLine = Boolean(this.return_each_line ?? this.return_each_line ?? false);
|
|
816
|
+
const chunkSize = Number(this.chunk_size ?? this.chunk_size ?? 1000);
|
|
817
|
+
const overlap = Number(this.chunk_overlap ?? this.chunk_overlap ?? 30);
|
|
818
|
+
// Parse headers_to_split_on config
|
|
819
|
+
const headersConfig = Array.isArray(this.headers_to_split_on)
|
|
820
|
+
? this.headers_to_split_on
|
|
821
|
+
: [["#", "Header 1"], ["##", "Header 2"], ["###", "Header 3"]];
|
|
822
|
+
// Build header patterns sorted by level (longest first so ## matches before #)
|
|
823
|
+
const headerPatterns = headersConfig
|
|
824
|
+
.map(([symbol, name]) => ({ symbol, name, level: symbol.length }))
|
|
825
|
+
.sort((a, b) => b.level - a.level);
|
|
826
|
+
const sections = [];
|
|
827
|
+
let currentContent = [];
|
|
828
|
+
const activeHeaders = {};
|
|
829
|
+
for (const line of markdown.split("\n")) {
|
|
830
|
+
const trimmedLine = line.trim();
|
|
831
|
+
// Check if this line is a header we care about
|
|
832
|
+
let matchedHeader = null;
|
|
833
|
+
for (const hp of headerPatterns) {
|
|
834
|
+
if (trimmedLine.startsWith(hp.symbol + " ") && !trimmedLine.startsWith(hp.symbol + "#")) {
|
|
835
|
+
matchedHeader = hp;
|
|
836
|
+
break;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
if (matchedHeader) {
|
|
840
|
+
// Emit previous section
|
|
841
|
+
if (currentContent.length > 0) {
|
|
842
|
+
sections.push({
|
|
843
|
+
content: [...currentContent],
|
|
844
|
+
metadata: { ...activeHeaders }
|
|
845
|
+
});
|
|
846
|
+
currentContent = [];
|
|
847
|
+
}
|
|
848
|
+
// Update header hierarchy: set this header and clear deeper levels
|
|
849
|
+
const headerText = trimmedLine.slice(matchedHeader.symbol.length).trim();
|
|
850
|
+
activeHeaders[matchedHeader.name] = headerText;
|
|
851
|
+
// Clear any deeper headers
|
|
852
|
+
for (const hp of headerPatterns) {
|
|
853
|
+
if (hp.level > matchedHeader.level) {
|
|
854
|
+
delete activeHeaders[hp.name];
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
if (!stripHeaders) {
|
|
858
|
+
currentContent.push(line);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
else {
|
|
862
|
+
currentContent.push(line);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
// Emit final section
|
|
866
|
+
if (currentContent.length > 0) {
|
|
867
|
+
sections.push({
|
|
868
|
+
content: [...currentContent],
|
|
869
|
+
metadata: { ...activeHeaders }
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
// Yield sections
|
|
873
|
+
const collected = [];
|
|
874
|
+
let chunkIdx = 0;
|
|
875
|
+
for (const section of sections) {
|
|
876
|
+
const sectionText = section.content.join("\n").trim();
|
|
877
|
+
if (!sectionText)
|
|
878
|
+
continue;
|
|
879
|
+
if (returnEachLine) {
|
|
880
|
+
for (const line of section.content) {
|
|
881
|
+
const trimmed = line.trim();
|
|
882
|
+
if (trimmed) {
|
|
883
|
+
const result = textChunk(trimmed, sourceId, chunkIdx);
|
|
884
|
+
result.metadata = section.metadata;
|
|
885
|
+
collected.push(result);
|
|
886
|
+
yield result;
|
|
887
|
+
chunkIdx++;
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
const sectionChunks = splitByChunk(sectionText, chunkSize, overlap);
|
|
893
|
+
for (const chunk of sectionChunks) {
|
|
894
|
+
const result = textChunk(chunk, sourceId, chunkIdx);
|
|
895
|
+
result.metadata = section.metadata;
|
|
896
|
+
collected.push(result);
|
|
897
|
+
yield result;
|
|
898
|
+
chunkIdx++;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
// Fallback if no sections were created
|
|
903
|
+
if (sections.length === 0) {
|
|
904
|
+
let startIndex = 0;
|
|
905
|
+
for (const chunk of splitByChunk(markdown, chunkSize, overlap)) {
|
|
906
|
+
const idx = markdown.indexOf(chunk, startIndex);
|
|
907
|
+
const resolvedIndex = idx >= 0 ? idx : startIndex;
|
|
908
|
+
const item = textChunk(chunk, sourceId, resolvedIndex);
|
|
909
|
+
collected.push(item);
|
|
910
|
+
yield item;
|
|
911
|
+
startIndex = resolvedIndex + Math.max(chunk.length - overlap, 1);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
yield { chunks: collected };
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
__decorate([
|
|
918
|
+
prop({
|
|
919
|
+
type: "document",
|
|
920
|
+
default: {
|
|
921
|
+
type: "document",
|
|
922
|
+
uri: "",
|
|
923
|
+
asset_id: null,
|
|
924
|
+
data: null,
|
|
925
|
+
metadata: null
|
|
926
|
+
},
|
|
927
|
+
title: "Document"
|
|
928
|
+
})
|
|
929
|
+
], SplitMarkdownNode.prototype, "document", void 0);
|
|
930
|
+
__decorate([
|
|
931
|
+
prop({
|
|
932
|
+
type: "list[tuple[str, str]]",
|
|
933
|
+
default: [
|
|
934
|
+
["#", "Header 1"],
|
|
935
|
+
["##", "Header 2"],
|
|
936
|
+
["###", "Header 3"]
|
|
937
|
+
],
|
|
938
|
+
title: "Headers To Split On",
|
|
939
|
+
description: "List of tuples containing (header_symbol, header_name)"
|
|
940
|
+
})
|
|
941
|
+
], SplitMarkdownNode.prototype, "headers_to_split_on", void 0);
|
|
942
|
+
__decorate([
|
|
943
|
+
prop({
|
|
944
|
+
type: "bool",
|
|
945
|
+
default: true,
|
|
946
|
+
title: "Strip Headers",
|
|
947
|
+
description: "Whether to remove headers from the output content"
|
|
948
|
+
})
|
|
949
|
+
], SplitMarkdownNode.prototype, "strip_headers", void 0);
|
|
950
|
+
__decorate([
|
|
951
|
+
prop({
|
|
952
|
+
type: "bool",
|
|
953
|
+
default: false,
|
|
954
|
+
title: "Return Each Line",
|
|
955
|
+
description: "Whether to split into individual lines instead of header sections"
|
|
956
|
+
})
|
|
957
|
+
], SplitMarkdownNode.prototype, "return_each_line", void 0);
|
|
958
|
+
__decorate([
|
|
959
|
+
prop({
|
|
960
|
+
type: "int",
|
|
961
|
+
default: 1000,
|
|
962
|
+
title: "Chunk Size",
|
|
963
|
+
description: "Optional maximum chunk size for further splitting"
|
|
964
|
+
})
|
|
965
|
+
], SplitMarkdownNode.prototype, "chunk_size", void 0);
|
|
966
|
+
__decorate([
|
|
967
|
+
prop({
|
|
968
|
+
type: "int",
|
|
969
|
+
default: 30,
|
|
970
|
+
title: "Chunk Overlap",
|
|
971
|
+
description: "Overlap size when using chunk_size"
|
|
972
|
+
})
|
|
973
|
+
], SplitMarkdownNode.prototype, "chunk_overlap", void 0);
|
|
974
|
+
export const DOCUMENT_NODES = [
|
|
975
|
+
LoadDocumentFileNode,
|
|
976
|
+
SaveDocumentFileNode,
|
|
977
|
+
ListDocumentsNode,
|
|
978
|
+
SplitDocumentNode,
|
|
979
|
+
SplitHTMLNode,
|
|
980
|
+
SplitJSONNode,
|
|
981
|
+
SplitRecursivelyNode,
|
|
982
|
+
SplitMarkdownNode
|
|
983
|
+
];
|
|
984
|
+
//# sourceMappingURL=document.js.map
|