n8n-nodes-local-ai-stack-dev 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/nodes/AIHub.node.d.ts +7 -0
- package/dist/nodes/AIHub.node.d.ts.map +1 -0
- package/dist/nodes/AIHub.node.js +237 -0
- package/dist/nodes/VoiceStudioStt.node.d.ts +7 -0
- package/dist/nodes/VoiceStudioStt.node.d.ts.map +1 -0
- package/dist/nodes/VoiceStudioStt.node.js +132 -0
- package/dist/nodes/localAIStack.node.d.ts +7 -0
- package/dist/nodes/localAIStack.node.d.ts.map +1 -0
- package/dist/nodes/localAIStack.node.js +205 -0
- package/dist/nodes/local_ai_stack.jpg +0 -0
- package/dist/nodes/local_ai_stack.png +0 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# n8n-nodes-ai-hub
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
Ce package n8n permet d'intégrer le produit **AI-Hub** dans n8n avec des nœuds personnalisés.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install n8n-nodes-ai-hub
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Configuration
|
|
16
|
+
|
|
17
|
+
Dans n8n, allez dans **Settings** > **Community Nodes** et ajoutez "n8n-nodes-ai-hub".
|
|
18
|
+
|
|
19
|
+
## Prérequis
|
|
20
|
+
|
|
21
|
+
- Service AI-Hub en fonctionnement
|
|
22
|
+
- n8n (auto-hébergé ou sur le même réseau que AI-Hub)
|
|
23
|
+
|
|
24
|
+
## License
|
|
25
|
+
NC-SA-4.0 License
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VoiceStudioStt = exports.AIHub = void 0;
|
|
4
|
+
var AIHub_node_1 = require("./nodes/AIHub.node");
|
|
5
|
+
Object.defineProperty(exports, "AIHub", { enumerable: true, get: function () { return AIHub_node_1.AIHub; } });
|
|
6
|
+
var VoiceStudioStt_node_1 = require("./nodes/VoiceStudioStt.node");
|
|
7
|
+
Object.defineProperty(exports, "VoiceStudioStt", { enumerable: true, get: function () { return VoiceStudioStt_node_1.VoiceStudioStt; } });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IExecuteFunctions } from "n8n-core";
|
|
2
|
+
import { INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
|
|
3
|
+
export declare class AIHub implements INodeType {
|
|
4
|
+
description: INodeTypeDescription;
|
|
5
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=AIHub.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AIHub.node.d.ts","sourceRoot":"","sources":["../../nodes/AIHub.node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEnF,qBAAa,KAAM,YAAW,SAAS;IACrC,WAAW,EAAE,oBAAoB,CAwI/B;IAEI,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CA0GxE"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AIHub = void 0;
|
|
4
|
+
class AIHub {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.description = {
|
|
7
|
+
displayName: "Local AI Stack",
|
|
8
|
+
name: "localAIStack",
|
|
9
|
+
icon: "file:local_ai_stack.png",
|
|
10
|
+
group: ["transform"],
|
|
11
|
+
version: 1,
|
|
12
|
+
description: "Local AI Stack services",
|
|
13
|
+
subtitle: '={{ $parameter["services"] && $parameter["services"].length > 0 ' + '? $parameter["services"].join(", ") ' + ': "[Aucun service sélectionné]" }}',
|
|
14
|
+
defaults: {
|
|
15
|
+
name: "Local AI Stack",
|
|
16
|
+
},
|
|
17
|
+
inputs: ["main"],
|
|
18
|
+
outputs: ["main"],
|
|
19
|
+
properties: [
|
|
20
|
+
{
|
|
21
|
+
displayName: "🚀 Débloquez des fonctionnalités Premium : Audio Transcription, Vision LLM, Text-to-Speech, traitement d'images/vidéos avancé, Embeddings multimodaux, Vector DB et plus encore. <a href='https://tally.so/r/w76z7A' target='_blank'>Rejoignez la liste d'attente ici</a>",
|
|
22
|
+
name: "premiumNotice",
|
|
23
|
+
type: "notice",
|
|
24
|
+
default: "",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
displayName: "Services",
|
|
28
|
+
name: "services",
|
|
29
|
+
type: "multiOptions",
|
|
30
|
+
options: [
|
|
31
|
+
{
|
|
32
|
+
name: "Extract Text from an image",
|
|
33
|
+
value: "ocr",
|
|
34
|
+
description: "Extract text from images using OCR",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "Describe an image",
|
|
38
|
+
value: "image_caption",
|
|
39
|
+
description: "Generate a caption describing the content of an image",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "Detect Faces from an image",
|
|
43
|
+
value: "faces",
|
|
44
|
+
description: "Detect and analyze faces in images",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: "💎 Audio Transcription (Speech-to-Text)",
|
|
48
|
+
value: "audio_transcription",
|
|
49
|
+
description: "Premium feature - Not available in free tier",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "💎 Visual Question Answering (Vision LLM)",
|
|
53
|
+
value: "visual_qa",
|
|
54
|
+
description: "Premium feature - Not available in free tier",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "💎 Text-to-Speech",
|
|
58
|
+
value: "text_to_speech",
|
|
59
|
+
description: "Premium feature - Not available in free tier",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "💎 Image Utils (Upscale, Edit...)",
|
|
63
|
+
value: "image_utils",
|
|
64
|
+
description: "Premium feature - Not available in free tier",
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "💎 Video Utils (Trim, Edit...)",
|
|
68
|
+
value: "video_utils",
|
|
69
|
+
description: "Premium feature - Not available in free tier",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: "💎 Multimodal Embeddings (Text-Image Similarity...)",
|
|
73
|
+
value: "multimodal_embeddings",
|
|
74
|
+
description: "Premium feature - Not available in free tier",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "💎 Vector DB",
|
|
78
|
+
value: "vector_db",
|
|
79
|
+
description: "Premium feature - Not available in free tier",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
default: ["ocr"],
|
|
83
|
+
required: true,
|
|
84
|
+
description: "Select one or more AI services to use (they will run in parallel)",
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
displayName: "Image Source",
|
|
88
|
+
name: "imageSource",
|
|
89
|
+
type: "options",
|
|
90
|
+
options: [
|
|
91
|
+
{
|
|
92
|
+
name: "URL",
|
|
93
|
+
value: "url",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: "Upload File",
|
|
97
|
+
value: "file",
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
default: "url",
|
|
101
|
+
description: "Choose whether to provide an image URL or upload a file",
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
displayName: "Image URL",
|
|
105
|
+
name: "imageUrl",
|
|
106
|
+
type: "string",
|
|
107
|
+
default: "",
|
|
108
|
+
placeholder: "https://example.com/image.jpg",
|
|
109
|
+
required: true,
|
|
110
|
+
description: "URL of the image to send to the AI service",
|
|
111
|
+
displayOptions: {
|
|
112
|
+
show: {
|
|
113
|
+
imageSource: ["url"],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
displayName: "Image File",
|
|
119
|
+
name: "imageFile",
|
|
120
|
+
type: "string",
|
|
121
|
+
default: "data",
|
|
122
|
+
required: true,
|
|
123
|
+
description: "The input binary field containing the image file to process",
|
|
124
|
+
displayOptions: {
|
|
125
|
+
show: {
|
|
126
|
+
imageSource: ["file"],
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
hint: "The name of the binary property that contains the image data",
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
displayName: "Server URL",
|
|
133
|
+
name: "serverUrl",
|
|
134
|
+
type: "string",
|
|
135
|
+
default: "http://127.0.0.1:9454",
|
|
136
|
+
placeholder: "http://127.0.0.1:9454",
|
|
137
|
+
required: false,
|
|
138
|
+
description: "AI-Hub server URL (optional)",
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
async execute() {
|
|
144
|
+
const items = this.getInputData();
|
|
145
|
+
const returnData = [];
|
|
146
|
+
// Liste des services premium
|
|
147
|
+
const premiumServices = ["audio_transcription", "visual_qa", "text_to_speech", "image_utils", "video_utils", "multimodal_embeddings", "vector_db"];
|
|
148
|
+
for (let i = 0; i < items.length; i++) {
|
|
149
|
+
try {
|
|
150
|
+
const serverUrl = this.getNodeParameter("serverUrl", i, "http://localhost:9454");
|
|
151
|
+
const services = this.getNodeParameter("services", i);
|
|
152
|
+
const imageSource = this.getNodeParameter("imageSource", i);
|
|
153
|
+
// Vérifier si des services premium sont sélectionnés
|
|
154
|
+
const selectedPremiumServices = services.filter((service) => premiumServices.includes(service));
|
|
155
|
+
if (selectedPremiumServices.length > 0) {
|
|
156
|
+
throw new Error("⚠️ Les services suivants ne sont disponibles qu'en version Premium : " +
|
|
157
|
+
selectedPremiumServices.join(", ") +
|
|
158
|
+
". " +
|
|
159
|
+
"Rejoignez notre liste d'attente pour être parmi les premiers à bénéficier de ces fonctionnalités : https://tally.so/r/w76z7A");
|
|
160
|
+
}
|
|
161
|
+
// Build the base URL
|
|
162
|
+
const baseUrl = serverUrl.endsWith("/") ? serverUrl.slice(0, -1) : serverUrl;
|
|
163
|
+
// Fonction pour exécuter un service
|
|
164
|
+
const executeService = async (service) => {
|
|
165
|
+
const fullUrl = `${baseUrl}/${service}/detect`;
|
|
166
|
+
if (imageSource === "url") {
|
|
167
|
+
// Use image URL
|
|
168
|
+
const imageUrl = this.getNodeParameter("imageUrl", i);
|
|
169
|
+
return await this.helpers.request({
|
|
170
|
+
method: "POST",
|
|
171
|
+
uri: fullUrl,
|
|
172
|
+
body: { image_url: imageUrl },
|
|
173
|
+
json: true,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
// Use uploaded file
|
|
178
|
+
const binaryPropertyName = this.getNodeParameter("imageFile", i);
|
|
179
|
+
const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
|
|
180
|
+
const buffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
181
|
+
return await this.helpers.request({
|
|
182
|
+
method: "POST",
|
|
183
|
+
uri: fullUrl,
|
|
184
|
+
formData: {
|
|
185
|
+
image_file: {
|
|
186
|
+
value: buffer,
|
|
187
|
+
options: {
|
|
188
|
+
filename: binaryData.fileName || "image.jpg",
|
|
189
|
+
contentType: binaryData.mimeType || "image/jpeg",
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
json: true,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
// Exécuter tous les services en parallèle
|
|
198
|
+
const results = await Promise.all(services.map(async (service) => {
|
|
199
|
+
try {
|
|
200
|
+
const result = await executeService(service);
|
|
201
|
+
return { service, result, error: null };
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
return { service, result: null, error: error.message };
|
|
205
|
+
}
|
|
206
|
+
}));
|
|
207
|
+
// Si une erreur est présente dans un service, arrêter et lancer une exception
|
|
208
|
+
for (const { service, error } of results) {
|
|
209
|
+
if (error) {
|
|
210
|
+
throw new Error(`Erreur lors de l'exécution du service '${service}': ${error}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// Si tout est OK, merger les résultats normalement
|
|
214
|
+
const mergedResults = {};
|
|
215
|
+
for (const { service, result } of results) {
|
|
216
|
+
mergedResults[service] = result;
|
|
217
|
+
}
|
|
218
|
+
returnData.push({
|
|
219
|
+
json: mergedResults,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
if (this.continueOnFail()) {
|
|
224
|
+
returnData.push({
|
|
225
|
+
json: {
|
|
226
|
+
error: error.message,
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return [returnData];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
exports.AIHub = AIHub;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IExecuteFunctions } from "n8n-core";
|
|
2
|
+
import { INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
|
|
3
|
+
export declare class VoiceStudioStt implements INodeType {
|
|
4
|
+
description: INodeTypeDescription;
|
|
5
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=VoiceStudioStt.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoiceStudioStt.node.d.ts","sourceRoot":"","sources":["../../nodes/VoiceStudioStt.node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEnF,qBAAa,cAAe,YAAW,SAAS;IAC9C,WAAW,EAAE,oBAAoB,CA4E/B;IAEI,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CAmDxE"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.VoiceStudioStt = void 0;
|
|
4
|
+
class VoiceStudioStt {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.description = {
|
|
7
|
+
displayName: "Voice Studio STT",
|
|
8
|
+
name: "voiceStudioStt",
|
|
9
|
+
icon: "file:local_ai_stack.png",
|
|
10
|
+
group: ["transform"],
|
|
11
|
+
version: 1,
|
|
12
|
+
description: "Transcribe audio using the local Voice Studio FastAPI service",
|
|
13
|
+
defaults: {
|
|
14
|
+
name: "Voice Studio STT",
|
|
15
|
+
},
|
|
16
|
+
inputs: ["main"],
|
|
17
|
+
outputs: ["main"],
|
|
18
|
+
properties: [
|
|
19
|
+
{
|
|
20
|
+
displayName: "Audio Source",
|
|
21
|
+
name: "audioSource",
|
|
22
|
+
type: "options",
|
|
23
|
+
options: [
|
|
24
|
+
{
|
|
25
|
+
name: "Binary",
|
|
26
|
+
value: "binary",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "Base64",
|
|
30
|
+
value: "base64",
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
default: "binary",
|
|
34
|
+
description: "Choose how the audio is provided",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
displayName: "Audio Binary Property",
|
|
38
|
+
name: "audioBinary",
|
|
39
|
+
type: "string",
|
|
40
|
+
default: "data",
|
|
41
|
+
required: true,
|
|
42
|
+
description: "The input binary field containing the audio file",
|
|
43
|
+
displayOptions: {
|
|
44
|
+
show: {
|
|
45
|
+
audioSource: ["binary"],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
hint: "The name of the binary property that contains the audio data",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
displayName: "Audio Base64",
|
|
52
|
+
name: "audioBase64",
|
|
53
|
+
type: "string",
|
|
54
|
+
default: "",
|
|
55
|
+
required: true,
|
|
56
|
+
description: "Base64-encoded audio content",
|
|
57
|
+
displayOptions: {
|
|
58
|
+
show: {
|
|
59
|
+
audioSource: ["base64"],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
displayName: "Language",
|
|
65
|
+
name: "language",
|
|
66
|
+
type: "string",
|
|
67
|
+
default: "",
|
|
68
|
+
placeholder: "fr",
|
|
69
|
+
required: false,
|
|
70
|
+
description: "Optional language code (leave empty for auto-detect)",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
displayName: "Server URL",
|
|
74
|
+
name: "serverUrl",
|
|
75
|
+
type: "string",
|
|
76
|
+
default: "http://localhost:8000/stt/transcribe",
|
|
77
|
+
placeholder: "http://localhost:8000/stt/transcribe",
|
|
78
|
+
required: true,
|
|
79
|
+
description: "Voice Studio STT endpoint URL",
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
async execute() {
|
|
85
|
+
const items = this.getInputData();
|
|
86
|
+
const returnData = [];
|
|
87
|
+
for (let i = 0; i < items.length; i++) {
|
|
88
|
+
try {
|
|
89
|
+
const serverUrl = this.getNodeParameter("serverUrl", i);
|
|
90
|
+
const audioSource = this.getNodeParameter("audioSource", i);
|
|
91
|
+
let audioBase64;
|
|
92
|
+
if (audioSource === "binary") {
|
|
93
|
+
const binaryPropertyName = this.getNodeParameter("audioBinary", i);
|
|
94
|
+
this.helpers.assertBinaryData(i, binaryPropertyName);
|
|
95
|
+
const buffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
96
|
+
audioBase64 = buffer.toString("base64");
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
audioBase64 = this.getNodeParameter("audioBase64", i);
|
|
100
|
+
}
|
|
101
|
+
const languageRaw = this.getNodeParameter("language", i, "");
|
|
102
|
+
const body = {
|
|
103
|
+
audio_base64: audioBase64,
|
|
104
|
+
};
|
|
105
|
+
const language = languageRaw.trim();
|
|
106
|
+
if (language) {
|
|
107
|
+
body.language = language;
|
|
108
|
+
}
|
|
109
|
+
const response = await this.helpers.request({
|
|
110
|
+
method: "POST",
|
|
111
|
+
uri: serverUrl,
|
|
112
|
+
body,
|
|
113
|
+
json: true,
|
|
114
|
+
});
|
|
115
|
+
returnData.push({ json: response });
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (this.continueOnFail()) {
|
|
119
|
+
returnData.push({
|
|
120
|
+
json: {
|
|
121
|
+
error: error.message,
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return [returnData];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
exports.VoiceStudioStt = VoiceStudioStt;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IExecuteFunctions } from "n8n-core";
|
|
2
|
+
import { INodeExecutionData, INodeType, INodeTypeDescription } from "n8n-workflow";
|
|
3
|
+
export declare class LocalAIStack implements INodeType {
|
|
4
|
+
description: INodeTypeDescription;
|
|
5
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=localAIStack.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localAIStack.node.d.ts","sourceRoot":"","sources":["../../nodes/localAIStack.node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEnF,qBAAa,YAAa,YAAW,SAAS;IAC5C,WAAW,EAAE,oBAAoB,CAkI/B;IAEI,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CA6ExE"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LocalAIStack = void 0;
|
|
4
|
+
class LocalAIStack {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.description = {
|
|
7
|
+
displayName: "Local AI Stack",
|
|
8
|
+
name: "localAIStack",
|
|
9
|
+
icon: "file:local_ai_stack.jpg",
|
|
10
|
+
group: ["transform"],
|
|
11
|
+
version: 1,
|
|
12
|
+
description: "Local AI Stack services for image processing and analysis",
|
|
13
|
+
defaults: {
|
|
14
|
+
name: "Local AI Stack",
|
|
15
|
+
},
|
|
16
|
+
inputs: ["main"],
|
|
17
|
+
outputs: ["main"],
|
|
18
|
+
properties: [
|
|
19
|
+
{
|
|
20
|
+
displayName: "🚀 Débloquez des fonctionnalités Premium : Audio Transcription, Vision LLM, Text-to-Speech, traitement d'images/vidéos avancé, Embeddings multimodaux, Vector DB et plus encore. <a href='https://tally.so/r/w76z7A' target='_blank'>Rejoignez la liste d'attente ici</a>",
|
|
21
|
+
name: "premiumNotice",
|
|
22
|
+
type: "notice",
|
|
23
|
+
default: "",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
displayName: "Service",
|
|
27
|
+
name: "service",
|
|
28
|
+
type: "options",
|
|
29
|
+
options: [
|
|
30
|
+
{
|
|
31
|
+
name: "Extract Text from Image",
|
|
32
|
+
value: "ocr",
|
|
33
|
+
description: "Extract text from images using OCR",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "Detect Faces from Image",
|
|
37
|
+
value: "faces",
|
|
38
|
+
description: "Detect and analyze faces in images",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "💎 Audio Transcription (Speech-to-Text)",
|
|
42
|
+
value: "audio_transcription",
|
|
43
|
+
description: "⚠️ Premium feature - Not available in free tier",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "💎 Visual Question Answering (Vision LLM)",
|
|
47
|
+
value: "visual_qa",
|
|
48
|
+
description: "⚠️ Premium feature - Not available in free tier",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "💎 Text-to-Speech",
|
|
52
|
+
value: "text_to_speech",
|
|
53
|
+
description: "⚠️ Premium feature - Not available in free tier",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "💎 Image Utils (Crop, Blur, Upscale...)",
|
|
57
|
+
value: "image_utils",
|
|
58
|
+
description: "⚠️ Premium feature - Not available in free tier",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "💎 Video Utils (Trim, Edit...)",
|
|
62
|
+
value: "video_utils",
|
|
63
|
+
description: "⚠️ Premium feature - Not available in free tier",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "💎 Multimodal Embeddings (Text-Image Similarity...)",
|
|
67
|
+
value: "multimodal_embeddings",
|
|
68
|
+
description: "⚠️ Premium feature - Not available in free tier",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "💎 Vector DB",
|
|
72
|
+
value: "vector_db",
|
|
73
|
+
description: "⚠️ Premium feature - Not available in free tier",
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
default: "ocr",
|
|
77
|
+
required: true,
|
|
78
|
+
description: "Select the AI service to use",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
displayName: "Image Source",
|
|
82
|
+
name: "imageSource",
|
|
83
|
+
type: "options",
|
|
84
|
+
options: [
|
|
85
|
+
{
|
|
86
|
+
name: "URL",
|
|
87
|
+
value: "url",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "Upload File",
|
|
91
|
+
value: "file",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
default: "url",
|
|
95
|
+
description: "Choose whether to provide an image URL or upload a file",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
displayName: "Image URL",
|
|
99
|
+
name: "imageUrl",
|
|
100
|
+
type: "string",
|
|
101
|
+
default: "",
|
|
102
|
+
placeholder: "https://example.com/image.jpg",
|
|
103
|
+
required: true,
|
|
104
|
+
description: "URL of the image to send to the AI service",
|
|
105
|
+
displayOptions: {
|
|
106
|
+
show: {
|
|
107
|
+
imageSource: ["url"],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
displayName: "Image File",
|
|
113
|
+
name: "imageFile",
|
|
114
|
+
type: "string",
|
|
115
|
+
default: "data",
|
|
116
|
+
required: true,
|
|
117
|
+
description: "The input binary field containing the image file to process",
|
|
118
|
+
displayOptions: {
|
|
119
|
+
show: {
|
|
120
|
+
imageSource: ["file"],
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
hint: "The name of the binary property that contains the image data",
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
displayName: "Server URL",
|
|
127
|
+
name: "serverUrl",
|
|
128
|
+
type: "string",
|
|
129
|
+
default: "http://localhost:9454",
|
|
130
|
+
placeholder: "http://localhost:9454",
|
|
131
|
+
required: false,
|
|
132
|
+
description: "AI-Hub server URL (optional)",
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
async execute() {
|
|
138
|
+
const items = this.getInputData();
|
|
139
|
+
const returnData = [];
|
|
140
|
+
// Liste des services premium
|
|
141
|
+
const premiumServices = ["audio_transcription", "visual_qa", "text_to_speech", "image_utils", "video_utils", "multimodal_embeddings", "vector_db"];
|
|
142
|
+
for (let i = 0; i < items.length; i++) {
|
|
143
|
+
try {
|
|
144
|
+
const serverUrl = this.getNodeParameter("serverUrl", i, "http://localhost:9454");
|
|
145
|
+
const service = this.getNodeParameter("service", i);
|
|
146
|
+
const imageSource = this.getNodeParameter("imageSource", i);
|
|
147
|
+
// Vérifier si c'est un service premium
|
|
148
|
+
if (premiumServices.includes(service)) {
|
|
149
|
+
throw new Error("⚠️ Cette option n'est disponible qu'en version Premium. " +
|
|
150
|
+
"Rejoignez notre liste d'attente pour être parmi les premiers à bénéficier de cette fonctionnalité : https://tally.so/r/w76z7A");
|
|
151
|
+
}
|
|
152
|
+
// Build the complete URL ensuring there are no double slashes
|
|
153
|
+
const baseUrl = serverUrl.endsWith("/") ? serverUrl.slice(0, -1) : serverUrl;
|
|
154
|
+
const fullUrl = `${baseUrl}/${service}/`;
|
|
155
|
+
let response;
|
|
156
|
+
if (imageSource === "url") {
|
|
157
|
+
// Use image URL
|
|
158
|
+
const imageUrl = this.getNodeParameter("imageUrl", i);
|
|
159
|
+
response = await this.helpers.request({
|
|
160
|
+
method: "POST",
|
|
161
|
+
uri: fullUrl,
|
|
162
|
+
body: { image_url: imageUrl },
|
|
163
|
+
json: true,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
// Use uploaded file
|
|
168
|
+
const binaryPropertyName = this.getNodeParameter("imageFile", i);
|
|
169
|
+
const binaryData = this.helpers.assertBinaryData(i, binaryPropertyName);
|
|
170
|
+
const buffer = await this.helpers.getBinaryDataBuffer(i, binaryPropertyName);
|
|
171
|
+
response = await this.helpers.request({
|
|
172
|
+
method: "POST",
|
|
173
|
+
uri: fullUrl,
|
|
174
|
+
formData: {
|
|
175
|
+
image_file: {
|
|
176
|
+
value: buffer,
|
|
177
|
+
options: {
|
|
178
|
+
filename: binaryData.fileName || "image.jpg",
|
|
179
|
+
contentType: binaryData.mimeType || "image/jpeg",
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
json: true,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
returnData.push({
|
|
187
|
+
json: response,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
if (this.continueOnFail()) {
|
|
192
|
+
returnData.push({
|
|
193
|
+
json: {
|
|
194
|
+
error: error.message,
|
|
195
|
+
},
|
|
196
|
+
});
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return [returnData];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
exports.LocalAIStack = LocalAIStack;
|
|
Binary file
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "n8n-nodes-local-ai-stack-dev",
|
|
3
|
+
"version": "1.1.7",
|
|
4
|
+
"description": "n8n custom nodes for AI services including image captionning, OCR, face detection, and more AI-powered features",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"n8n",
|
|
7
|
+
"node",
|
|
8
|
+
"custom",
|
|
9
|
+
"ai",
|
|
10
|
+
"ocr",
|
|
11
|
+
"image-captioning",
|
|
12
|
+
"text-extraction",
|
|
13
|
+
"face-detection",
|
|
14
|
+
"image-processing",
|
|
15
|
+
"machine-learning",
|
|
16
|
+
"artificial-intelligence",
|
|
17
|
+
"llm",
|
|
18
|
+
"local-ai-stack"
|
|
19
|
+
],
|
|
20
|
+
"license": "NC-SA-4.0",
|
|
21
|
+
"author": {
|
|
22
|
+
"name": "raphaelandremy"
|
|
23
|
+
},
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc && cp nodes/*.png dist/nodes/ 2>/dev/null || true",
|
|
27
|
+
"dev": "tsc --watch",
|
|
28
|
+
"format": "prettier --write .",
|
|
29
|
+
"lint": "eslint .",
|
|
30
|
+
"lintfix": "eslint . --fix",
|
|
31
|
+
"prepublishOnly": "npm run build",
|
|
32
|
+
"publish-npm": "npm publish --access public"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist/**/*",
|
|
36
|
+
"credentials/**/*"
|
|
37
|
+
],
|
|
38
|
+
"n8n": {
|
|
39
|
+
"n8nNodesApiVersion": 1,
|
|
40
|
+
"credentials": [],
|
|
41
|
+
"nodes": [
|
|
42
|
+
"dist/nodes/AIHub.node.js",
|
|
43
|
+
"dist/nodes/VoiceStudioStt.node.js"
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "^18.16.1",
|
|
48
|
+
"n8n-core": "~1.0.0",
|
|
49
|
+
"n8n-workflow": "~1.0.0",
|
|
50
|
+
"typescript": "~5.1.6"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"n8n-workflow": "*"
|
|
54
|
+
}
|
|
55
|
+
}
|