@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,861 @@
|
|
|
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
|
+
const GEMINI_API_BASE = "https://generativelanguage.googleapis.com/v1beta";
|
|
9
|
+
function getGeminiApiKey(secrets) {
|
|
10
|
+
const key = secrets.GEMINI_API_KEY || process.env.GEMINI_API_KEY || "";
|
|
11
|
+
if (!key)
|
|
12
|
+
throw new Error("GEMINI_API_KEY is not configured");
|
|
13
|
+
return key;
|
|
14
|
+
}
|
|
15
|
+
function getAudioBytes(audio) {
|
|
16
|
+
if (typeof audio.data === "string") {
|
|
17
|
+
return Uint8Array.from(Buffer.from(audio.data, "base64"));
|
|
18
|
+
}
|
|
19
|
+
if (audio.data instanceof Uint8Array) {
|
|
20
|
+
return audio.data;
|
|
21
|
+
}
|
|
22
|
+
throw new Error("Audio data is required");
|
|
23
|
+
}
|
|
24
|
+
function getImageBytes(image) {
|
|
25
|
+
if (typeof image.data === "string" && image.data.length > 0) {
|
|
26
|
+
return Uint8Array.from(Buffer.from(image.data, "base64"));
|
|
27
|
+
}
|
|
28
|
+
if (image.data instanceof Uint8Array) {
|
|
29
|
+
return image.data;
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
function isRefSet(ref) {
|
|
34
|
+
if (!ref || typeof ref !== "object")
|
|
35
|
+
return false;
|
|
36
|
+
const r = ref;
|
|
37
|
+
return Boolean(r.data || r.uri || r.asset_id);
|
|
38
|
+
}
|
|
39
|
+
// ── Text nodes ──────────────────────────────────────────────────────────────
|
|
40
|
+
export class GroundedSearchNode extends BaseNode {
|
|
41
|
+
static nodeType = "gemini.text.GroundedSearch";
|
|
42
|
+
static title = "Grounded Search";
|
|
43
|
+
static description = "Search the web using Google's Gemini API with grounding capabilities.\n google, search, grounded, web, gemini, ai\n\n This node uses Google's Gemini API to perform web searches and return structured results\n with source information. Requires a Gemini API key.\n\n Use cases:\n - Research current events and latest information\n - Find reliable sources for fact-checking\n - Gather web-based information with citations\n - Get up-to-date information beyond the model's training data";
|
|
44
|
+
static metadataOutputTypes = {
|
|
45
|
+
results: "list[str]",
|
|
46
|
+
sources: "list[source]"
|
|
47
|
+
};
|
|
48
|
+
static requiredSettings = ["GEMINI_API_KEY"];
|
|
49
|
+
static exposeAsTool = true;
|
|
50
|
+
async process() {
|
|
51
|
+
const apiKey = getGeminiApiKey(this._secrets);
|
|
52
|
+
const query = String(this.query ?? "");
|
|
53
|
+
const model = String(this.model ?? "gemini-2.0-flash");
|
|
54
|
+
if (!query)
|
|
55
|
+
throw new Error("Search query is required");
|
|
56
|
+
const url = `${GEMINI_API_BASE}/models/${model}:generateContent?key=${apiKey}`;
|
|
57
|
+
const body = {
|
|
58
|
+
contents: [{ parts: [{ text: query }] }],
|
|
59
|
+
tools: [{ google_search: {} }],
|
|
60
|
+
generationConfig: {
|
|
61
|
+
responseMimeType: "text/plain"
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const res = await fetch(url, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: { "Content-Type": "application/json" },
|
|
67
|
+
body: JSON.stringify(body)
|
|
68
|
+
});
|
|
69
|
+
if (!res.ok) {
|
|
70
|
+
const errText = await res.text();
|
|
71
|
+
throw new Error(`Gemini API error ${res.status}: ${errText}`);
|
|
72
|
+
}
|
|
73
|
+
const data = (await res.json());
|
|
74
|
+
const candidates = data.candidates;
|
|
75
|
+
if (!candidates || candidates.length === 0) {
|
|
76
|
+
throw new Error("No response received from Gemini API");
|
|
77
|
+
}
|
|
78
|
+
const candidate = candidates[0];
|
|
79
|
+
const content = candidate.content;
|
|
80
|
+
if (!content)
|
|
81
|
+
throw new Error("Invalid response format from Gemini API");
|
|
82
|
+
const parts = content.parts;
|
|
83
|
+
const results = [];
|
|
84
|
+
if (parts) {
|
|
85
|
+
for (const part of parts) {
|
|
86
|
+
if (typeof part.text === "string") {
|
|
87
|
+
results.push(part.text);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const sources = [];
|
|
92
|
+
const groundingMetadata = candidate.groundingMetadata;
|
|
93
|
+
if (groundingMetadata) {
|
|
94
|
+
const chunks = groundingMetadata.groundingChunks;
|
|
95
|
+
if (chunks) {
|
|
96
|
+
for (const chunk of chunks) {
|
|
97
|
+
const web = chunk.web;
|
|
98
|
+
if (web) {
|
|
99
|
+
const source = {
|
|
100
|
+
title: String(web.title ?? ""),
|
|
101
|
+
url: String(web.uri ?? "")
|
|
102
|
+
};
|
|
103
|
+
if (source.url && !sources.some((s) => s.url === source.url)) {
|
|
104
|
+
sources.push(source);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return { results, sources };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
__decorate([
|
|
114
|
+
prop({
|
|
115
|
+
type: "str",
|
|
116
|
+
default: "",
|
|
117
|
+
title: "Query",
|
|
118
|
+
description: "The search query to execute"
|
|
119
|
+
})
|
|
120
|
+
], GroundedSearchNode.prototype, "query", void 0);
|
|
121
|
+
__decorate([
|
|
122
|
+
prop({
|
|
123
|
+
type: "enum",
|
|
124
|
+
default: "gemini-2.0-flash",
|
|
125
|
+
title: "Model",
|
|
126
|
+
description: "The Gemini model to use for search",
|
|
127
|
+
values: ["gemini-2.5-pro", "gemini-2.5-flash", "gemini-2.0-flash"]
|
|
128
|
+
})
|
|
129
|
+
], GroundedSearchNode.prototype, "model", void 0);
|
|
130
|
+
export class EmbeddingNode extends BaseNode {
|
|
131
|
+
static nodeType = "gemini.text.Embedding";
|
|
132
|
+
static title = "Embedding";
|
|
133
|
+
static description = "Generate vector representations of text for semantic analysis using Google's Gemini API.\n embeddings, similarity, search, clustering, classification, gemini\n\n Uses Google's text embedding models to create dense vector representations of text.\n These vectors capture semantic meaning, enabling:\n - Semantic search\n - Text clustering\n - Document classification\n - Recommendation systems\n - Anomaly detection\n - Measuring text similarity and diversity";
|
|
134
|
+
static metadataOutputTypes = {
|
|
135
|
+
output: "list"
|
|
136
|
+
};
|
|
137
|
+
static requiredSettings = ["GEMINI_API_KEY"];
|
|
138
|
+
static exposeAsTool = true;
|
|
139
|
+
async process() {
|
|
140
|
+
const apiKey = getGeminiApiKey(this._secrets);
|
|
141
|
+
const input = String(this.input ?? "");
|
|
142
|
+
const model = String(this.model ?? "text-embedding-004");
|
|
143
|
+
if (!input)
|
|
144
|
+
throw new Error("Input text is required for embedding generation");
|
|
145
|
+
const url = `${GEMINI_API_BASE}/models/${model}:embedContent?key=${apiKey}`;
|
|
146
|
+
const body = {
|
|
147
|
+
content: { parts: [{ text: input }] }
|
|
148
|
+
};
|
|
149
|
+
const res = await fetch(url, {
|
|
150
|
+
method: "POST",
|
|
151
|
+
headers: { "Content-Type": "application/json" },
|
|
152
|
+
body: JSON.stringify(body)
|
|
153
|
+
});
|
|
154
|
+
if (!res.ok) {
|
|
155
|
+
const errText = await res.text();
|
|
156
|
+
throw new Error(`Gemini API error ${res.status}: ${errText}`);
|
|
157
|
+
}
|
|
158
|
+
const data = (await res.json());
|
|
159
|
+
const embedding = data.embedding;
|
|
160
|
+
if (!embedding || !embedding.values) {
|
|
161
|
+
throw new Error("No embedding generated from the input text");
|
|
162
|
+
}
|
|
163
|
+
return { output: embedding.values };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
__decorate([
|
|
167
|
+
prop({
|
|
168
|
+
type: "str",
|
|
169
|
+
default: "",
|
|
170
|
+
title: "Input",
|
|
171
|
+
description: "The text to embed."
|
|
172
|
+
})
|
|
173
|
+
], EmbeddingNode.prototype, "input", void 0);
|
|
174
|
+
__decorate([
|
|
175
|
+
prop({
|
|
176
|
+
type: "enum",
|
|
177
|
+
default: "text-embedding-004",
|
|
178
|
+
title: "Model",
|
|
179
|
+
description: "The embedding model to use",
|
|
180
|
+
values: ["text-embedding-004", "gemini-embedding-001"]
|
|
181
|
+
})
|
|
182
|
+
], EmbeddingNode.prototype, "model", void 0);
|
|
183
|
+
// ── Image nodes ─────────────────────────────────────────────────────────────
|
|
184
|
+
export class ImageGenerationNode extends BaseNode {
|
|
185
|
+
static nodeType = "gemini.image.ImageGeneration";
|
|
186
|
+
static title = "Image Generation";
|
|
187
|
+
static description = "Generate an image using Google's Imagen model via the Gemini API.\n google, image generation, ai, imagen\n\n Use cases:\n - Create images from text descriptions\n - Generate assets for creative projects\n - Explore AI-powered image synthesis";
|
|
188
|
+
static metadataOutputTypes = {
|
|
189
|
+
output: "image"
|
|
190
|
+
};
|
|
191
|
+
static requiredSettings = ["GEMINI_API_KEY"];
|
|
192
|
+
static exposeAsTool = true;
|
|
193
|
+
static autoSaveAsset = true;
|
|
194
|
+
async process() {
|
|
195
|
+
const apiKey = getGeminiApiKey(this._secrets);
|
|
196
|
+
const prompt = String(this.prompt ?? "");
|
|
197
|
+
const model = String(this.model ?? "imagen-3.0-generate-002");
|
|
198
|
+
const image = (this.image ?? {});
|
|
199
|
+
if (!prompt)
|
|
200
|
+
throw new Error("The input prompt cannot be empty.");
|
|
201
|
+
// Gemini image-capable models use generateContent with IMAGE+TEXT modalities
|
|
202
|
+
if (model.startsWith("gemini-")) {
|
|
203
|
+
const contentParts = [{ text: prompt }];
|
|
204
|
+
// Add optional input image
|
|
205
|
+
const imageBytes = getImageBytes(image);
|
|
206
|
+
if (imageBytes) {
|
|
207
|
+
contentParts.push({
|
|
208
|
+
inline_data: {
|
|
209
|
+
mime_type: "image/png",
|
|
210
|
+
data: Buffer.from(imageBytes).toString("base64")
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const url = `${GEMINI_API_BASE}/models/${model}:generateContent?key=${apiKey}`;
|
|
215
|
+
const body = {
|
|
216
|
+
contents: [{ parts: contentParts }],
|
|
217
|
+
generationConfig: {
|
|
218
|
+
responseModalities: ["IMAGE", "TEXT"]
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const res = await fetch(url, {
|
|
222
|
+
method: "POST",
|
|
223
|
+
headers: { "Content-Type": "application/json" },
|
|
224
|
+
body: JSON.stringify(body)
|
|
225
|
+
});
|
|
226
|
+
if (!res.ok) {
|
|
227
|
+
const errText = await res.text();
|
|
228
|
+
throw new Error(`Gemini API error ${res.status}: ${errText}`);
|
|
229
|
+
}
|
|
230
|
+
const data = (await res.json());
|
|
231
|
+
const candidates = data.candidates;
|
|
232
|
+
if (!candidates || candidates.length === 0) {
|
|
233
|
+
throw new Error("No response received from Gemini API");
|
|
234
|
+
}
|
|
235
|
+
const candidate = candidates[0];
|
|
236
|
+
if (candidate.finishReason === "PROHIBITED_CONTENT") {
|
|
237
|
+
throw new Error("Prohibited content in the input prompt");
|
|
238
|
+
}
|
|
239
|
+
const content = candidate.content;
|
|
240
|
+
const parts = content?.parts;
|
|
241
|
+
if (!parts)
|
|
242
|
+
throw new Error("Invalid response format from Gemini API");
|
|
243
|
+
for (const part of parts) {
|
|
244
|
+
const inlineData = part.inlineData;
|
|
245
|
+
// Also check snake_case variant from API
|
|
246
|
+
const inlineData2 = part.inline_data;
|
|
247
|
+
const d = inlineData ?? inlineData2;
|
|
248
|
+
if (d && typeof d.data === "string") {
|
|
249
|
+
return { output: { type: "image", data: d.data } };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
throw new Error("No image bytes returned in response");
|
|
253
|
+
}
|
|
254
|
+
// Imagen models use the generateImages endpoint
|
|
255
|
+
const url = `${GEMINI_API_BASE}/models/${model}:generateImages?key=${apiKey}`;
|
|
256
|
+
const body = {
|
|
257
|
+
prompt,
|
|
258
|
+
config: { numberOfImages: 1 }
|
|
259
|
+
};
|
|
260
|
+
const res = await fetch(url, {
|
|
261
|
+
method: "POST",
|
|
262
|
+
headers: { "Content-Type": "application/json" },
|
|
263
|
+
body: JSON.stringify(body)
|
|
264
|
+
});
|
|
265
|
+
if (!res.ok) {
|
|
266
|
+
const errText = await res.text();
|
|
267
|
+
throw new Error(`Gemini API error ${res.status}: ${errText}`);
|
|
268
|
+
}
|
|
269
|
+
const data = (await res.json());
|
|
270
|
+
const generatedImages = data.generatedImages;
|
|
271
|
+
if (!generatedImages || generatedImages.length === 0) {
|
|
272
|
+
throw new Error("No images generated");
|
|
273
|
+
}
|
|
274
|
+
const imgObj = generatedImages[0].image;
|
|
275
|
+
if (!imgObj)
|
|
276
|
+
throw new Error("No image in response");
|
|
277
|
+
const imageBytes = imgObj.imageBytes;
|
|
278
|
+
if (!imageBytes)
|
|
279
|
+
throw new Error("No image bytes in response");
|
|
280
|
+
return { output: { type: "image", data: imageBytes } };
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
__decorate([
|
|
284
|
+
prop({
|
|
285
|
+
type: "str",
|
|
286
|
+
default: "",
|
|
287
|
+
title: "Prompt",
|
|
288
|
+
description: "The text prompt describing the image to generate."
|
|
289
|
+
})
|
|
290
|
+
], ImageGenerationNode.prototype, "prompt", void 0);
|
|
291
|
+
__decorate([
|
|
292
|
+
prop({
|
|
293
|
+
type: "enum",
|
|
294
|
+
default: "imagen-3.0-generate-002",
|
|
295
|
+
title: "Model",
|
|
296
|
+
description: "The image generation model to use",
|
|
297
|
+
values: [
|
|
298
|
+
"gemini-2.0-flash-preview-image-generation",
|
|
299
|
+
"gemini-2.5-flash-image-preview",
|
|
300
|
+
"gemini-3-pro-image-preview",
|
|
301
|
+
"imagen-3.0-generate-001",
|
|
302
|
+
"imagen-3.0-generate-002",
|
|
303
|
+
"imagen-4.0-generate-001"
|
|
304
|
+
]
|
|
305
|
+
})
|
|
306
|
+
], ImageGenerationNode.prototype, "model", void 0);
|
|
307
|
+
__decorate([
|
|
308
|
+
prop({
|
|
309
|
+
type: "image",
|
|
310
|
+
default: {
|
|
311
|
+
type: "image",
|
|
312
|
+
uri: "",
|
|
313
|
+
asset_id: null,
|
|
314
|
+
data: null,
|
|
315
|
+
metadata: null
|
|
316
|
+
},
|
|
317
|
+
title: "Image",
|
|
318
|
+
description: "The image to use as a base for the generation."
|
|
319
|
+
})
|
|
320
|
+
], ImageGenerationNode.prototype, "image", void 0);
|
|
321
|
+
// ── Video nodes ─────────────────────────────────────────────────────────────
|
|
322
|
+
export class TextToVideoGeminiNode extends BaseNode {
|
|
323
|
+
static nodeType = "gemini.video.TextToVideo";
|
|
324
|
+
static title = "Text To Video";
|
|
325
|
+
static description = "Generate videos from text prompts using Google's Veo models.\n google, video, generation, text-to-video, veo, ai\n\n This node uses Google's Veo models to generate high-quality videos from text descriptions.\n Supports 720p resolution at 24fps with 8-second duration and native audio generation.";
|
|
326
|
+
static metadataOutputTypes = {
|
|
327
|
+
output: "video"
|
|
328
|
+
};
|
|
329
|
+
static requiredSettings = ["GEMINI_API_KEY"];
|
|
330
|
+
static exposeAsTool = true;
|
|
331
|
+
static autoSaveAsset = true;
|
|
332
|
+
async process() {
|
|
333
|
+
const apiKey = getGeminiApiKey(this._secrets);
|
|
334
|
+
const prompt = String(this.prompt ?? "");
|
|
335
|
+
const model = String(this.model ?? "veo-3.1-generate-preview");
|
|
336
|
+
const aspectRatio = String(this.aspect_ratio ?? "16:9");
|
|
337
|
+
const negativePrompt = String(this.negative_prompt ?? "");
|
|
338
|
+
if (!prompt)
|
|
339
|
+
throw new Error("Video generation prompt is required");
|
|
340
|
+
// Start the long-running video generation operation
|
|
341
|
+
const url = `${GEMINI_API_BASE}/models/${model}:generateVideos?key=${apiKey}`;
|
|
342
|
+
const config = {};
|
|
343
|
+
if (aspectRatio)
|
|
344
|
+
config.aspectRatio = aspectRatio;
|
|
345
|
+
if (negativePrompt)
|
|
346
|
+
config.negativePrompt = negativePrompt;
|
|
347
|
+
const body = {
|
|
348
|
+
prompt
|
|
349
|
+
};
|
|
350
|
+
if (Object.keys(config).length > 0)
|
|
351
|
+
body.config = config;
|
|
352
|
+
const res = await fetch(url, {
|
|
353
|
+
method: "POST",
|
|
354
|
+
headers: { "Content-Type": "application/json" },
|
|
355
|
+
body: JSON.stringify(body)
|
|
356
|
+
});
|
|
357
|
+
if (!res.ok) {
|
|
358
|
+
const errText = await res.text();
|
|
359
|
+
throw new Error(`Gemini API error ${res.status}: ${errText}`);
|
|
360
|
+
}
|
|
361
|
+
const operation = (await res.json());
|
|
362
|
+
const videoData = await pollVideoOperation(apiKey, operation);
|
|
363
|
+
return { output: { type: "video", data: videoData } };
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
__decorate([
|
|
367
|
+
prop({
|
|
368
|
+
type: "str",
|
|
369
|
+
default: "",
|
|
370
|
+
title: "Prompt",
|
|
371
|
+
description: "The text prompt describing the video to generate"
|
|
372
|
+
})
|
|
373
|
+
], TextToVideoGeminiNode.prototype, "prompt", void 0);
|
|
374
|
+
__decorate([
|
|
375
|
+
prop({
|
|
376
|
+
type: "enum",
|
|
377
|
+
default: "veo-3.1-generate-preview",
|
|
378
|
+
title: "Model",
|
|
379
|
+
description: "The Veo model to use for video generation",
|
|
380
|
+
values: ["veo-3.1-generate-preview", "veo-2.0-generate-001"]
|
|
381
|
+
})
|
|
382
|
+
], TextToVideoGeminiNode.prototype, "model", void 0);
|
|
383
|
+
__decorate([
|
|
384
|
+
prop({
|
|
385
|
+
type: "enum",
|
|
386
|
+
default: "16:9",
|
|
387
|
+
title: "Aspect Ratio",
|
|
388
|
+
description: "The aspect ratio of the generated video",
|
|
389
|
+
values: ["16:9", "9:16"]
|
|
390
|
+
})
|
|
391
|
+
], TextToVideoGeminiNode.prototype, "aspect_ratio", void 0);
|
|
392
|
+
__decorate([
|
|
393
|
+
prop({
|
|
394
|
+
type: "str",
|
|
395
|
+
default: "",
|
|
396
|
+
title: "Negative Prompt",
|
|
397
|
+
description: "Negative prompt to guide what to avoid in the video"
|
|
398
|
+
})
|
|
399
|
+
], TextToVideoGeminiNode.prototype, "negative_prompt", void 0);
|
|
400
|
+
export class ImageToVideoGeminiNode extends BaseNode {
|
|
401
|
+
static nodeType = "gemini.video.ImageToVideo";
|
|
402
|
+
static title = "Image To Video";
|
|
403
|
+
static description = "Generate videos from images using Google's Veo models.\n google, video, generation, image-to-video, veo, ai, animation\n\n This node uses Google's Veo models to animate static images into dynamic videos.\n Supports 720p resolution at 24fps with 8-second duration and native audio generation.";
|
|
404
|
+
static metadataOutputTypes = {
|
|
405
|
+
output: "video"
|
|
406
|
+
};
|
|
407
|
+
static requiredSettings = ["GEMINI_API_KEY"];
|
|
408
|
+
static exposeAsTool = true;
|
|
409
|
+
static autoSaveAsset = true;
|
|
410
|
+
async process() {
|
|
411
|
+
const apiKey = getGeminiApiKey(this._secrets);
|
|
412
|
+
const image = (this.image ?? {});
|
|
413
|
+
const prompt = String(this.prompt ?? "Animate this image");
|
|
414
|
+
const model = String(this.model ?? "veo-3.1-generate-preview");
|
|
415
|
+
const aspectRatio = String(this.aspect_ratio ?? "16:9");
|
|
416
|
+
const negativePrompt = String(this.negative_prompt ?? "");
|
|
417
|
+
if (!isRefSet(image))
|
|
418
|
+
throw new Error("Input image is required");
|
|
419
|
+
const imageBytes = getImageBytes(image);
|
|
420
|
+
if (!imageBytes)
|
|
421
|
+
throw new Error("Image data is required");
|
|
422
|
+
const config = {};
|
|
423
|
+
if (aspectRatio)
|
|
424
|
+
config.aspectRatio = aspectRatio;
|
|
425
|
+
if (negativePrompt)
|
|
426
|
+
config.negativePrompt = negativePrompt;
|
|
427
|
+
const url = `${GEMINI_API_BASE}/models/${model}:generateVideos?key=${apiKey}`;
|
|
428
|
+
const body = {
|
|
429
|
+
prompt: prompt || "Animate this image",
|
|
430
|
+
image: {
|
|
431
|
+
imageBytes: Buffer.from(imageBytes).toString("base64"),
|
|
432
|
+
mimeType: "image/png"
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
if (Object.keys(config).length > 0)
|
|
436
|
+
body.config = config;
|
|
437
|
+
const res = await fetch(url, {
|
|
438
|
+
method: "POST",
|
|
439
|
+
headers: { "Content-Type": "application/json" },
|
|
440
|
+
body: JSON.stringify(body)
|
|
441
|
+
});
|
|
442
|
+
if (!res.ok) {
|
|
443
|
+
const errText = await res.text();
|
|
444
|
+
throw new Error(`Gemini API error ${res.status}: ${errText}`);
|
|
445
|
+
}
|
|
446
|
+
const operation = (await res.json());
|
|
447
|
+
const videoData = await pollVideoOperation(apiKey, operation);
|
|
448
|
+
return { output: { type: "video", data: videoData } };
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
__decorate([
|
|
452
|
+
prop({
|
|
453
|
+
type: "image",
|
|
454
|
+
default: {
|
|
455
|
+
type: "image",
|
|
456
|
+
uri: "",
|
|
457
|
+
asset_id: null,
|
|
458
|
+
data: null,
|
|
459
|
+
metadata: null
|
|
460
|
+
},
|
|
461
|
+
title: "Image",
|
|
462
|
+
description: "The image to animate into a video"
|
|
463
|
+
})
|
|
464
|
+
], ImageToVideoGeminiNode.prototype, "image", void 0);
|
|
465
|
+
__decorate([
|
|
466
|
+
prop({
|
|
467
|
+
type: "str",
|
|
468
|
+
default: "",
|
|
469
|
+
title: "Prompt",
|
|
470
|
+
description: "Optional text prompt describing the desired animation"
|
|
471
|
+
})
|
|
472
|
+
], ImageToVideoGeminiNode.prototype, "prompt", void 0);
|
|
473
|
+
__decorate([
|
|
474
|
+
prop({
|
|
475
|
+
type: "enum",
|
|
476
|
+
default: "veo-3.1-generate-preview",
|
|
477
|
+
title: "Model",
|
|
478
|
+
description: "The Veo model to use for video generation",
|
|
479
|
+
values: ["veo-3.1-generate-preview", "veo-2.0-generate-001"]
|
|
480
|
+
})
|
|
481
|
+
], ImageToVideoGeminiNode.prototype, "model", void 0);
|
|
482
|
+
__decorate([
|
|
483
|
+
prop({
|
|
484
|
+
type: "enum",
|
|
485
|
+
default: "16:9",
|
|
486
|
+
title: "Aspect Ratio",
|
|
487
|
+
description: "The aspect ratio of the generated video",
|
|
488
|
+
values: ["16:9", "9:16"]
|
|
489
|
+
})
|
|
490
|
+
], ImageToVideoGeminiNode.prototype, "aspect_ratio", void 0);
|
|
491
|
+
__decorate([
|
|
492
|
+
prop({
|
|
493
|
+
type: "str",
|
|
494
|
+
default: "",
|
|
495
|
+
title: "Negative Prompt",
|
|
496
|
+
description: "Negative prompt to guide what to avoid in the video"
|
|
497
|
+
})
|
|
498
|
+
], ImageToVideoGeminiNode.prototype, "negative_prompt", void 0);
|
|
499
|
+
async function pollVideoOperation(apiKey, operation) {
|
|
500
|
+
// If the operation already has the result, return it
|
|
501
|
+
if (operation.done) {
|
|
502
|
+
return extractVideoFromResponse(operation);
|
|
503
|
+
}
|
|
504
|
+
// Otherwise poll the operation
|
|
505
|
+
const opName = operation.name;
|
|
506
|
+
if (!opName)
|
|
507
|
+
throw new Error("No operation name in response");
|
|
508
|
+
const maxAttempts = 120; // 10 minutes at 5s intervals
|
|
509
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
510
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
511
|
+
const pollUrl = `https://generativelanguage.googleapis.com/v1beta/${opName}?key=${apiKey}`;
|
|
512
|
+
const pollRes = await fetch(pollUrl);
|
|
513
|
+
if (!pollRes.ok) {
|
|
514
|
+
const errText = await pollRes.text();
|
|
515
|
+
throw new Error(`Gemini poll error ${pollRes.status}: ${errText}`);
|
|
516
|
+
}
|
|
517
|
+
const pollData = (await pollRes.json());
|
|
518
|
+
if (pollData.done) {
|
|
519
|
+
return extractVideoFromResponse(pollData);
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
throw new Error("Video generation timed out");
|
|
523
|
+
}
|
|
524
|
+
function extractVideoFromResponse(data) {
|
|
525
|
+
const response = (data.response ?? data);
|
|
526
|
+
const generatedVideos = response.generatedVideos;
|
|
527
|
+
if (!generatedVideos || generatedVideos.length === 0) {
|
|
528
|
+
throw new Error("No video generated");
|
|
529
|
+
}
|
|
530
|
+
const video = generatedVideos[0].video;
|
|
531
|
+
if (!video)
|
|
532
|
+
throw new Error("No video in response");
|
|
533
|
+
const videoBytes = video.videoBytes;
|
|
534
|
+
if (!videoBytes)
|
|
535
|
+
throw new Error("No video bytes in response");
|
|
536
|
+
return videoBytes;
|
|
537
|
+
}
|
|
538
|
+
// ── Audio nodes ─────────────────────────────────────────────────────────────
|
|
539
|
+
export class TextToSpeechGeminiNode extends BaseNode {
|
|
540
|
+
static nodeType = "gemini.audio.TextToSpeech";
|
|
541
|
+
static title = "Text To Speech";
|
|
542
|
+
static description = "Generate speech audio from text using Google's Gemini text-to-speech models.\n google, text-to-speech, tts, audio, speech, voice, ai\n\n This node converts text input into natural-sounding speech audio using Google's\n advanced text-to-speech models with support for multiple voices and speech styles.\n\n Supported voices:\n - achernar, achird, algenib, algieba, alnilam\n - aoede, autonoe, callirrhoe, charon, despina\n - enceladus, erinome, fenrir, gacrux, iapetus\n - kore, laomedeia, leda, orus, puck\n - pulcherrima, rasalgethi, sadachbia, sadaltager, schedar\n - sulafat, umbriel, vindemiatrix, zephyr, zubenelgenubi\n\n Use cases:\n - Create voiceovers for videos and presentations\n - Generate audio content for podcasts and audiobooks\n - Add voice narration to applications\n - Create accessibility features with speech output\n - Generate multilingual audio content";
|
|
543
|
+
static metadataOutputTypes = {
|
|
544
|
+
output: "audio"
|
|
545
|
+
};
|
|
546
|
+
static requiredSettings = ["GEMINI_API_KEY"];
|
|
547
|
+
static exposeAsTool = true;
|
|
548
|
+
static autoSaveAsset = true;
|
|
549
|
+
async process() {
|
|
550
|
+
const apiKey = getGeminiApiKey(this._secrets);
|
|
551
|
+
const text = String(this.text ?? "");
|
|
552
|
+
const model = String(this.model ?? "gemini-2.5-pro-preview-tts");
|
|
553
|
+
const stylePrompt = String(this.style_prompt ?? "");
|
|
554
|
+
const VALID_VOICES = [
|
|
555
|
+
"achernar", "achird", "algenib", "algieba", "alnilam",
|
|
556
|
+
"aoede", "autonoe", "callirrhoe", "charon", "despina",
|
|
557
|
+
"enceladus", "erinome", "fenrir", "gacrux", "iapetus",
|
|
558
|
+
"kore", "laomedeia", "leda", "orus", "puck",
|
|
559
|
+
"pulcherrima", "rasalgethi", "sadachbia", "sadaltager", "schedar",
|
|
560
|
+
"sulafat", "umbriel", "vindemiatrix", "zephyr", "zubenelgenubi"
|
|
561
|
+
];
|
|
562
|
+
const rawVoice = String(this.voice_name ?? "kore").toLowerCase();
|
|
563
|
+
const voiceName = VALID_VOICES.includes(rawVoice) ? rawVoice : "kore";
|
|
564
|
+
if (!text)
|
|
565
|
+
throw new Error("The input text cannot be empty.");
|
|
566
|
+
let content = text;
|
|
567
|
+
if (stylePrompt) {
|
|
568
|
+
content = `${stylePrompt}: ${text}`;
|
|
569
|
+
}
|
|
570
|
+
const url = `${GEMINI_API_BASE}/models/${model}:generateContent?key=${apiKey}`;
|
|
571
|
+
const body = {
|
|
572
|
+
contents: [{ parts: [{ text: content }] }],
|
|
573
|
+
generationConfig: {
|
|
574
|
+
responseModalities: ["AUDIO"],
|
|
575
|
+
speechConfig: {
|
|
576
|
+
voiceConfig: {
|
|
577
|
+
prebuiltVoiceConfig: {
|
|
578
|
+
voiceName: voiceName
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
const res = await fetch(url, {
|
|
585
|
+
method: "POST",
|
|
586
|
+
headers: { "Content-Type": "application/json" },
|
|
587
|
+
body: JSON.stringify(body)
|
|
588
|
+
});
|
|
589
|
+
if (!res.ok) {
|
|
590
|
+
const errText = await res.text();
|
|
591
|
+
throw new Error(`Gemini API error ${res.status}: ${errText}`);
|
|
592
|
+
}
|
|
593
|
+
const data = (await res.json());
|
|
594
|
+
const candidates = data.candidates;
|
|
595
|
+
if (!candidates || candidates.length === 0) {
|
|
596
|
+
throw new Error("No audio generated from the text-to-speech request");
|
|
597
|
+
}
|
|
598
|
+
const candidate = candidates[0];
|
|
599
|
+
const contentObj = candidate.content;
|
|
600
|
+
const parts = contentObj?.parts;
|
|
601
|
+
if (!parts)
|
|
602
|
+
throw new Error("No audio generated from the text-to-speech request");
|
|
603
|
+
for (const part of parts) {
|
|
604
|
+
const inlineData = part.inlineData ??
|
|
605
|
+
part.inline_data;
|
|
606
|
+
if (inlineData && typeof inlineData.data === "string") {
|
|
607
|
+
// The API returns raw PCM audio at 24kHz, 16-bit mono
|
|
608
|
+
// Encode as WAV for the audio ref
|
|
609
|
+
const pcmBase64 = inlineData.data;
|
|
610
|
+
const pcmBytes = Buffer.from(pcmBase64, "base64");
|
|
611
|
+
const wavBytes = encodeWav(pcmBytes, 24000, 1, 16);
|
|
612
|
+
return {
|
|
613
|
+
output: {
|
|
614
|
+
uri: "",
|
|
615
|
+
data: Buffer.from(wavBytes).toString("base64")
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
throw new Error("No audio data found in the response");
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
__decorate([
|
|
624
|
+
prop({
|
|
625
|
+
type: "str",
|
|
626
|
+
default: "",
|
|
627
|
+
title: "Text",
|
|
628
|
+
description: "The text to convert to speech."
|
|
629
|
+
})
|
|
630
|
+
], TextToSpeechGeminiNode.prototype, "text", void 0);
|
|
631
|
+
__decorate([
|
|
632
|
+
prop({
|
|
633
|
+
type: "enum",
|
|
634
|
+
default: "gemini-2.5-pro-preview-tts",
|
|
635
|
+
title: "Model",
|
|
636
|
+
description: "The text-to-speech model to use",
|
|
637
|
+
values: ["gemini-2.5-pro-preview-tts"]
|
|
638
|
+
})
|
|
639
|
+
], TextToSpeechGeminiNode.prototype, "model", void 0);
|
|
640
|
+
__decorate([
|
|
641
|
+
prop({
|
|
642
|
+
type: "enum",
|
|
643
|
+
default: "kore",
|
|
644
|
+
title: "Voice Name",
|
|
645
|
+
description: "The voice to use for speech generation",
|
|
646
|
+
values: [
|
|
647
|
+
"achernar",
|
|
648
|
+
"achird",
|
|
649
|
+
"algenib",
|
|
650
|
+
"algieba",
|
|
651
|
+
"alnilam",
|
|
652
|
+
"aoede",
|
|
653
|
+
"autonoe",
|
|
654
|
+
"callirrhoe",
|
|
655
|
+
"charon",
|
|
656
|
+
"despina",
|
|
657
|
+
"enceladus",
|
|
658
|
+
"erinome",
|
|
659
|
+
"fenrir",
|
|
660
|
+
"gacrux",
|
|
661
|
+
"iapetus",
|
|
662
|
+
"kore",
|
|
663
|
+
"laomedeia",
|
|
664
|
+
"leda",
|
|
665
|
+
"orus",
|
|
666
|
+
"puck",
|
|
667
|
+
"pulcherrima",
|
|
668
|
+
"rasalgethi",
|
|
669
|
+
"sadachbia",
|
|
670
|
+
"sadaltager",
|
|
671
|
+
"schedar",
|
|
672
|
+
"sulafat",
|
|
673
|
+
"umbriel",
|
|
674
|
+
"vindemiatrix",
|
|
675
|
+
"zephyr",
|
|
676
|
+
"zubenelgenubi"
|
|
677
|
+
]
|
|
678
|
+
})
|
|
679
|
+
], TextToSpeechGeminiNode.prototype, "voice_name", void 0);
|
|
680
|
+
__decorate([
|
|
681
|
+
prop({
|
|
682
|
+
type: "str",
|
|
683
|
+
default: "",
|
|
684
|
+
title: "Style Prompt",
|
|
685
|
+
description: "Optional style prompt to control speech characteristics (e.g., 'Say cheerfully', 'Speak with excitement')"
|
|
686
|
+
})
|
|
687
|
+
], TextToSpeechGeminiNode.prototype, "style_prompt", void 0);
|
|
688
|
+
export class TranscribeGeminiNode extends BaseNode {
|
|
689
|
+
static nodeType = "gemini.audio.Transcribe";
|
|
690
|
+
static title = "Transcribe";
|
|
691
|
+
static description = "Transcribe audio to text using Google's Gemini models.\n google, transcription, speech-to-text, audio, whisper, ai\n\n This node converts audio input into text using Google's multimodal Gemini models.\n Supports various audio formats and provides accurate speech-to-text transcription.\n\n Use cases:\n - Convert recorded audio to text\n - Transcribe podcasts and interviews\n - Generate subtitles from audio tracks\n - Create meeting notes from audio recordings\n - Analyze speech content in audio files";
|
|
692
|
+
static metadataOutputTypes = {
|
|
693
|
+
output: "str"
|
|
694
|
+
};
|
|
695
|
+
static requiredSettings = ["GEMINI_API_KEY"];
|
|
696
|
+
static exposeAsTool = true;
|
|
697
|
+
async process() {
|
|
698
|
+
const apiKey = getGeminiApiKey(this._secrets);
|
|
699
|
+
const audio = (this.audio ?? {});
|
|
700
|
+
const model = String(this.model ?? "gemini-2.5-flash");
|
|
701
|
+
const prompt = String(this.prompt ??
|
|
702
|
+
this.prompt ??
|
|
703
|
+
"Transcribe the following audio accurately. Return only the transcription text without any additional commentary.");
|
|
704
|
+
if (!isRefSet(audio))
|
|
705
|
+
throw new Error("Audio file is required for transcription");
|
|
706
|
+
const audioBytes = getAudioBytes(audio);
|
|
707
|
+
// Detect MIME type from first bytes (simple magic-number check)
|
|
708
|
+
const mimeType = detectAudioMime(audioBytes);
|
|
709
|
+
const url = `${GEMINI_API_BASE}/models/${model}:generateContent?key=${apiKey}`;
|
|
710
|
+
const body = {
|
|
711
|
+
contents: [
|
|
712
|
+
{
|
|
713
|
+
parts: [
|
|
714
|
+
{ text: prompt },
|
|
715
|
+
{
|
|
716
|
+
inline_data: {
|
|
717
|
+
mime_type: mimeType,
|
|
718
|
+
data: Buffer.from(audioBytes).toString("base64")
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
]
|
|
722
|
+
}
|
|
723
|
+
],
|
|
724
|
+
generationConfig: {
|
|
725
|
+
responseModalities: ["TEXT"]
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
const res = await fetch(url, {
|
|
729
|
+
method: "POST",
|
|
730
|
+
headers: { "Content-Type": "application/json" },
|
|
731
|
+
body: JSON.stringify(body)
|
|
732
|
+
});
|
|
733
|
+
if (!res.ok) {
|
|
734
|
+
const errText = await res.text();
|
|
735
|
+
throw new Error(`Gemini API error ${res.status}: ${errText}`);
|
|
736
|
+
}
|
|
737
|
+
const data = (await res.json());
|
|
738
|
+
const candidates = data.candidates;
|
|
739
|
+
if (!candidates || candidates.length === 0) {
|
|
740
|
+
throw new Error("No transcription generated from the audio");
|
|
741
|
+
}
|
|
742
|
+
const candidate = candidates[0];
|
|
743
|
+
const content = candidate.content;
|
|
744
|
+
const parts = content?.parts;
|
|
745
|
+
if (!parts)
|
|
746
|
+
throw new Error("No transcription generated from the audio");
|
|
747
|
+
const transcriptionParts = [];
|
|
748
|
+
for (const part of parts) {
|
|
749
|
+
if (typeof part.text === "string") {
|
|
750
|
+
transcriptionParts.push(part.text);
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
return { output: transcriptionParts.join("") };
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
__decorate([
|
|
757
|
+
prop({
|
|
758
|
+
type: "audio",
|
|
759
|
+
default: {
|
|
760
|
+
type: "audio",
|
|
761
|
+
uri: "",
|
|
762
|
+
asset_id: null,
|
|
763
|
+
data: null,
|
|
764
|
+
metadata: null
|
|
765
|
+
},
|
|
766
|
+
title: "Audio",
|
|
767
|
+
description: "The audio file to transcribe."
|
|
768
|
+
})
|
|
769
|
+
], TranscribeGeminiNode.prototype, "audio", void 0);
|
|
770
|
+
__decorate([
|
|
771
|
+
prop({
|
|
772
|
+
type: "enum",
|
|
773
|
+
default: "gemini-2.5-flash",
|
|
774
|
+
title: "Model",
|
|
775
|
+
description: "The Gemini model to use for transcription",
|
|
776
|
+
values: ["gemini-2.5-flash", "gemini-2.0-flash"]
|
|
777
|
+
})
|
|
778
|
+
], TranscribeGeminiNode.prototype, "model", void 0);
|
|
779
|
+
__decorate([
|
|
780
|
+
prop({
|
|
781
|
+
type: "str",
|
|
782
|
+
default: "Transcribe the following audio accurately. Return only the transcription text without any additional commentary.",
|
|
783
|
+
title: "Prompt",
|
|
784
|
+
description: "Instructions for the transcription. You can customize this to request specific formatting or focus."
|
|
785
|
+
})
|
|
786
|
+
], TranscribeGeminiNode.prototype, "prompt", void 0);
|
|
787
|
+
// ── Utility functions ───────────────────────────────────────────────────────
|
|
788
|
+
function detectAudioMime(bytes) {
|
|
789
|
+
if (bytes.length < 4)
|
|
790
|
+
return "audio/mpeg";
|
|
791
|
+
// WAV: RIFF header
|
|
792
|
+
if (bytes[0] === 0x52 &&
|
|
793
|
+
bytes[1] === 0x49 &&
|
|
794
|
+
bytes[2] === 0x46 &&
|
|
795
|
+
bytes[3] === 0x46) {
|
|
796
|
+
return "audio/wav";
|
|
797
|
+
}
|
|
798
|
+
// FLAC
|
|
799
|
+
if (bytes[0] === 0x66 &&
|
|
800
|
+
bytes[1] === 0x4c &&
|
|
801
|
+
bytes[2] === 0x61 &&
|
|
802
|
+
bytes[3] === 0x43) {
|
|
803
|
+
return "audio/flac";
|
|
804
|
+
}
|
|
805
|
+
// OGG
|
|
806
|
+
if (bytes[0] === 0x4f &&
|
|
807
|
+
bytes[1] === 0x67 &&
|
|
808
|
+
bytes[2] === 0x67 &&
|
|
809
|
+
bytes[3] === 0x53) {
|
|
810
|
+
return "audio/ogg";
|
|
811
|
+
}
|
|
812
|
+
// MP3 frame sync or ID3 tag
|
|
813
|
+
if ((bytes[0] === 0xff && (bytes[1] & 0xe0) === 0xe0) ||
|
|
814
|
+
(bytes[0] === 0x49 && bytes[1] === 0x44 && bytes[2] === 0x33)) {
|
|
815
|
+
return "audio/mpeg";
|
|
816
|
+
}
|
|
817
|
+
return "audio/mpeg";
|
|
818
|
+
}
|
|
819
|
+
function encodeWav(pcmData, sampleRate, channels, bitsPerSample) {
|
|
820
|
+
const byteRate = (sampleRate * channels * bitsPerSample) / 8;
|
|
821
|
+
const blockAlign = (channels * bitsPerSample) / 8;
|
|
822
|
+
const dataSize = pcmData.length;
|
|
823
|
+
const headerSize = 44;
|
|
824
|
+
const buffer = new ArrayBuffer(headerSize + dataSize);
|
|
825
|
+
const view = new DataView(buffer);
|
|
826
|
+
const out = new Uint8Array(buffer);
|
|
827
|
+
// RIFF header
|
|
828
|
+
writeString(view, 0, "RIFF");
|
|
829
|
+
view.setUint32(4, 36 + dataSize, true);
|
|
830
|
+
writeString(view, 8, "WAVE");
|
|
831
|
+
// fmt chunk
|
|
832
|
+
writeString(view, 12, "fmt ");
|
|
833
|
+
view.setUint32(16, 16, true); // chunk size
|
|
834
|
+
view.setUint16(20, 1, true); // PCM format
|
|
835
|
+
view.setUint16(22, channels, true);
|
|
836
|
+
view.setUint32(24, sampleRate, true);
|
|
837
|
+
view.setUint32(28, byteRate, true);
|
|
838
|
+
view.setUint16(32, blockAlign, true);
|
|
839
|
+
view.setUint16(34, bitsPerSample, true);
|
|
840
|
+
// data chunk
|
|
841
|
+
writeString(view, 36, "data");
|
|
842
|
+
view.setUint32(40, dataSize, true);
|
|
843
|
+
out.set(pcmData instanceof Buffer ? new Uint8Array(pcmData) : pcmData, headerSize);
|
|
844
|
+
return out;
|
|
845
|
+
}
|
|
846
|
+
function writeString(view, offset, str) {
|
|
847
|
+
for (let i = 0; i < str.length; i++) {
|
|
848
|
+
view.setUint8(offset + i, str.charCodeAt(i));
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
// ── Exports ─────────────────────────────────────────────────────────────────
|
|
852
|
+
export const GEMINI_NODES = [
|
|
853
|
+
GroundedSearchNode,
|
|
854
|
+
EmbeddingNode,
|
|
855
|
+
ImageGenerationNode,
|
|
856
|
+
TextToVideoGeminiNode,
|
|
857
|
+
ImageToVideoGeminiNode,
|
|
858
|
+
TextToSpeechGeminiNode,
|
|
859
|
+
TranscribeGeminiNode
|
|
860
|
+
];
|
|
861
|
+
//# sourceMappingURL=gemini.js.map
|