@aj-archipelago/cortex 1.3.66 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.js +27 -0
- package/helper-apps/cortex-autogen2/Dockerfile +88 -21
- package/helper-apps/cortex-autogen2/docker-compose.yml +15 -8
- package/helper-apps/cortex-autogen2/host.json +5 -0
- package/helper-apps/cortex-autogen2/pyproject.toml +82 -25
- package/helper-apps/cortex-autogen2/requirements.txt +84 -14
- package/helper-apps/cortex-autogen2/services/redis_publisher.py +129 -3
- package/helper-apps/cortex-autogen2/task_processor.py +432 -116
- package/helper-apps/cortex-autogen2/tools/__init__.py +2 -0
- package/helper-apps/cortex-autogen2/tools/azure_blob_tools.py +32 -0
- package/helper-apps/cortex-autogen2/tools/azure_foundry_agents.py +50 -14
- package/helper-apps/cortex-autogen2/tools/file_tools.py +169 -44
- package/helper-apps/cortex-autogen2/tools/google_cse.py +117 -0
- package/helper-apps/cortex-autogen2/tools/search_tools.py +655 -98
- package/helper-apps/cortex-doc-to-pdf/DocToPdfFunction/__init__.py +3 -0
- package/helper-apps/cortex-doc-to-pdf/DocToPdfFunction/function.json +20 -0
- package/helper-apps/cortex-doc-to-pdf/Dockerfile +46 -0
- package/helper-apps/cortex-doc-to-pdf/README.md +408 -0
- package/helper-apps/cortex-doc-to-pdf/converter.py +157 -0
- package/helper-apps/cortex-doc-to-pdf/docker-compose.yml +23 -0
- package/helper-apps/cortex-doc-to-pdf/document_converter.py +181 -0
- package/helper-apps/cortex-doc-to-pdf/examples/README.md +252 -0
- package/helper-apps/cortex-doc-to-pdf/examples/nodejs-client.js +266 -0
- package/helper-apps/cortex-doc-to-pdf/examples/package-lock.json +297 -0
- package/helper-apps/cortex-doc-to-pdf/examples/package.json +23 -0
- package/helper-apps/cortex-doc-to-pdf/function_app.py +85 -0
- package/helper-apps/cortex-doc-to-pdf/host.json +16 -0
- package/helper-apps/cortex-doc-to-pdf/request_handlers.py +193 -0
- package/helper-apps/cortex-doc-to-pdf/requirements.txt +3 -0
- package/helper-apps/cortex-doc-to-pdf/tests/run_tests.sh +26 -0
- package/helper-apps/cortex-doc-to-pdf/tests/test_conversion.py +320 -0
- package/helper-apps/cortex-doc-to-pdf/tests/test_streaming.py +419 -0
- package/helper-apps/cortex-file-handler/package-lock.json +1 -0
- package/helper-apps/cortex-file-handler/package.json +1 -0
- package/helper-apps/cortex-file-handler/src/services/ConversionService.js +81 -8
- package/helper-apps/cortex-file-handler/tests/FileConversionService.test.js +54 -7
- package/helper-apps/cortex-file-handler/tests/getOperations.test.js +19 -7
- package/lib/encodeCache.js +5 -0
- package/lib/keyValueStorageClient.js +5 -0
- package/lib/logger.js +1 -1
- package/lib/pathwayManager.js +42 -8
- package/lib/pathwayTools.js +8 -1
- package/lib/redisSubscription.js +6 -0
- package/lib/requestExecutor.js +4 -0
- package/lib/util.js +145 -1
- package/package.json +1 -1
- package/pathways/basePathway.js +3 -3
- package/pathways/bing_afagent.js +1 -0
- package/pathways/gemini_15_vision.js +1 -1
- package/pathways/google_cse.js +2 -2
- package/pathways/image_gemini_25.js +85 -0
- package/pathways/image_prompt_optimizer_gemini_25.js +149 -0
- package/pathways/image_qwen.js +28 -0
- package/pathways/image_seedream4.js +26 -0
- package/pathways/rag.js +1 -1
- package/pathways/rag_jarvis.js +1 -1
- package/pathways/system/entity/sys_entity_continue.js +1 -1
- package/pathways/system/entity/sys_generator_results.js +1 -1
- package/pathways/system/entity/tools/sys_tool_google_search.js +15 -2
- package/pathways/system/entity/tools/sys_tool_grok_x_search.js +3 -3
- package/pathways/system/entity/tools/sys_tool_image.js +28 -23
- package/pathways/system/entity/tools/sys_tool_image_gemini.js +135 -0
- package/pathways/system/workspaces/run_workspace_prompt.js +0 -3
- package/server/executeWorkspace.js +381 -0
- package/server/graphql.js +14 -182
- package/server/modelExecutor.js +4 -0
- package/server/pathwayResolver.js +19 -18
- package/server/plugins/claude3VertexPlugin.js +13 -8
- package/server/plugins/gemini15ChatPlugin.js +15 -10
- package/server/plugins/gemini15VisionPlugin.js +2 -23
- package/server/plugins/gemini25ImagePlugin.js +155 -0
- package/server/plugins/modelPlugin.js +3 -2
- package/server/plugins/openAiChatPlugin.js +6 -6
- package/server/plugins/replicateApiPlugin.js +268 -12
- package/server/plugins/veoVideoPlugin.js +15 -1
- package/server/rest.js +2 -0
- package/server/typeDef.js +96 -10
- package/tests/integration/apptekTranslatePlugin.integration.test.js +1 -1
- package/tests/unit/core/parser.test.js +0 -1
- package/tests/unit/core/pathwayManager.test.js +2 -4
- package/tests/unit/core/pathwayManagerWithFiles.test.js +256 -0
- package/tests/unit/graphql_executeWorkspace_transformation.test.js +244 -0
- package/tests/unit/plugins/gemini25ImagePlugin.test.js +294 -0
- package/tests/unit/server/graphql.test.js +122 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// replicateApiPlugin.js
|
|
2
2
|
import ModelPlugin from "./modelPlugin.js";
|
|
3
|
+
import CortexResponse from "../../lib/cortexResponse.js";
|
|
3
4
|
import logger from "../../lib/logger.js";
|
|
4
5
|
import axios from "axios";
|
|
5
6
|
|
|
@@ -92,6 +93,122 @@ class ReplicateApiPlugin extends ModelPlugin {
|
|
|
92
93
|
};
|
|
93
94
|
break;
|
|
94
95
|
}
|
|
96
|
+
case "replicate-qwen-image": {
|
|
97
|
+
const aspectRatio = combinedParameters.aspect_ratio ?? combinedParameters.aspectRatio ?? "16:9";
|
|
98
|
+
const imageSize = combinedParameters.image_size ?? combinedParameters.imageSize ?? "optimize_for_quality";
|
|
99
|
+
const outputFormat = combinedParameters.output_format ?? combinedParameters.outputFormat ?? "webp";
|
|
100
|
+
const outputQuality = combinedParameters.output_quality ?? combinedParameters.outputQuality ?? 80;
|
|
101
|
+
const loraScale = combinedParameters.lora_scale ?? combinedParameters.loraScale ?? 1;
|
|
102
|
+
const enhancePrompt = combinedParameters.enhance_prompt ?? combinedParameters.enhancePrompt ?? false;
|
|
103
|
+
const negativePrompt = combinedParameters.negative_prompt ?? combinedParameters.negativePrompt ?? " ";
|
|
104
|
+
const numInferenceSteps = combinedParameters.num_inference_steps ?? combinedParameters.steps ?? 50;
|
|
105
|
+
const goFast = combinedParameters.go_fast ?? combinedParameters.goFast ?? true;
|
|
106
|
+
const guidance = combinedParameters.guidance ?? 4;
|
|
107
|
+
const strength = combinedParameters.strength ?? 0.9;
|
|
108
|
+
const numOutputs = combinedParameters.num_outputs ?? combinedParameters.numberResults;
|
|
109
|
+
const disableSafetyChecker = combinedParameters.disable_safety_checker ?? combinedParameters.disableSafetyChecker ?? false;
|
|
110
|
+
|
|
111
|
+
requestParameters = {
|
|
112
|
+
input: {
|
|
113
|
+
prompt: modelPromptText,
|
|
114
|
+
go_fast: goFast,
|
|
115
|
+
guidance,
|
|
116
|
+
strength,
|
|
117
|
+
image_size: imageSize,
|
|
118
|
+
lora_scale: loraScale,
|
|
119
|
+
aspect_ratio: aspectRatio,
|
|
120
|
+
output_format: outputFormat,
|
|
121
|
+
enhance_prompt: enhancePrompt,
|
|
122
|
+
output_quality: outputQuality,
|
|
123
|
+
negative_prompt: negativePrompt,
|
|
124
|
+
num_inference_steps: numInferenceSteps,
|
|
125
|
+
disable_safety_checker: disableSafetyChecker,
|
|
126
|
+
...(numOutputs ? { num_outputs: numOutputs } : {}),
|
|
127
|
+
...(combinedParameters.seed && Number.isInteger(combinedParameters.seed) ? { seed: combinedParameters.seed } : {}),
|
|
128
|
+
...(combinedParameters.image ? { image: combinedParameters.image } : {}),
|
|
129
|
+
...(combinedParameters.input_image ? { input_image: combinedParameters.input_image } : {}),
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case "replicate-qwen-image-edit-plus": {
|
|
135
|
+
const aspectRatio = combinedParameters.aspect_ratio ?? combinedParameters.aspectRatio ?? "match_input_image";
|
|
136
|
+
const outputFormat = combinedParameters.output_format ?? combinedParameters.outputFormat ?? "webp";
|
|
137
|
+
const outputQuality = combinedParameters.output_quality ?? combinedParameters.outputQuality ?? 95;
|
|
138
|
+
const goFast = combinedParameters.go_fast ?? combinedParameters.goFast ?? true;
|
|
139
|
+
const disableSafetyChecker = combinedParameters.disable_safety_checker ?? combinedParameters.disableSafetyChecker ?? false;
|
|
140
|
+
|
|
141
|
+
const collectImages = (candidate, accumulator) => {
|
|
142
|
+
if (!candidate) return;
|
|
143
|
+
if (Array.isArray(candidate)) {
|
|
144
|
+
candidate.forEach((item) => collectImages(item, accumulator));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
accumulator.push(candidate);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const imageCandidates = [];
|
|
151
|
+
collectImages(combinedParameters.image, imageCandidates);
|
|
152
|
+
collectImages(combinedParameters.images, imageCandidates);
|
|
153
|
+
collectImages(combinedParameters.input_image, imageCandidates);
|
|
154
|
+
collectImages(combinedParameters.input_images, imageCandidates);
|
|
155
|
+
collectImages(combinedParameters.input_image_1, imageCandidates);
|
|
156
|
+
collectImages(combinedParameters.input_image_2, imageCandidates);
|
|
157
|
+
collectImages(combinedParameters.input_image_3, imageCandidates);
|
|
158
|
+
collectImages(combinedParameters.image_1, imageCandidates);
|
|
159
|
+
collectImages(combinedParameters.image_2, imageCandidates);
|
|
160
|
+
|
|
161
|
+
const normalizeImageEntry = (entry) => {
|
|
162
|
+
if (!entry) return null;
|
|
163
|
+
if (typeof entry === "string") {
|
|
164
|
+
return entry; // Return the URL string directly
|
|
165
|
+
}
|
|
166
|
+
if (typeof entry === "object") {
|
|
167
|
+
if (Array.isArray(entry)) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
if (entry.value) {
|
|
171
|
+
return entry.value; // Return the value as a string
|
|
172
|
+
}
|
|
173
|
+
if (entry.url) {
|
|
174
|
+
return entry.url; // Return the URL as a string
|
|
175
|
+
}
|
|
176
|
+
if (entry.path) {
|
|
177
|
+
return entry.path; // Return the path as a string
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
const normalizedImages = imageCandidates
|
|
184
|
+
.map((candidate) => normalizeImageEntry(candidate))
|
|
185
|
+
.filter((candidate) => candidate && typeof candidate === 'string');
|
|
186
|
+
|
|
187
|
+
const omitUndefined = (obj) =>
|
|
188
|
+
Object.fromEntries(
|
|
189
|
+
Object.entries(obj).filter(([, value]) => value !== undefined && value !== null),
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
const basePayload = omitUndefined({
|
|
193
|
+
prompt: modelPromptText,
|
|
194
|
+
go_fast: goFast,
|
|
195
|
+
aspect_ratio: aspectRatio,
|
|
196
|
+
output_format: outputFormat,
|
|
197
|
+
output_quality: outputQuality,
|
|
198
|
+
disable_safety_checker: disableSafetyChecker,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// For qwen-image-edit-plus, always include the image array if we have images
|
|
202
|
+
const inputPayload = {
|
|
203
|
+
...basePayload,
|
|
204
|
+
...(normalizedImages.length > 0 ? { image: normalizedImages } : {})
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
requestParameters = {
|
|
208
|
+
input: inputPayload,
|
|
209
|
+
};
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
95
212
|
case "replicate-flux-kontext-pro":
|
|
96
213
|
case "replicate-flux-kontext-max": {
|
|
97
214
|
const validRatios = [
|
|
@@ -110,7 +227,7 @@ class ReplicateApiPlugin extends ModelPlugin {
|
|
|
110
227
|
input_image: combinedParameters.input_image,
|
|
111
228
|
aspect_ratio: validRatios.includes(combinedParameters.aspectRatio) ? combinedParameters.aspectRatio : "1:1",
|
|
112
229
|
safety_tolerance: safetyTolerance,
|
|
113
|
-
...(combinedParameters.seed && Number.isInteger(combinedParameters.seed && combinedParameters.seed > 0
|
|
230
|
+
...(combinedParameters.seed && Number.isInteger(combinedParameters.seed) && combinedParameters.seed > 0 ? { seed: combinedParameters.seed } : {}),
|
|
114
231
|
},
|
|
115
232
|
};
|
|
116
233
|
break;
|
|
@@ -133,7 +250,7 @@ class ReplicateApiPlugin extends ModelPlugin {
|
|
|
133
250
|
input_image_2: combinedParameters.input_image_2,
|
|
134
251
|
aspect_ratio: validRatios.includes(combinedParameters.aspectRatio) ? combinedParameters.aspectRatio : "1:1",
|
|
135
252
|
safety_tolerance: safetyTolerance,
|
|
136
|
-
...(combinedParameters.seed && Number.isInteger(combinedParameters.seed && combinedParameters.seed > 0
|
|
253
|
+
...(combinedParameters.seed && Number.isInteger(combinedParameters.seed) && combinedParameters.seed > 0 ? { seed: combinedParameters.seed } : {}),
|
|
137
254
|
},
|
|
138
255
|
};
|
|
139
256
|
break;
|
|
@@ -148,7 +265,7 @@ class ReplicateApiPlugin extends ModelPlugin {
|
|
|
148
265
|
prompt: modelPromptText,
|
|
149
266
|
resolution: validResolutions.includes(combinedParameters.resolution) ? combinedParameters.resolution : "1080p",
|
|
150
267
|
aspect_ratio: validRatios.includes(combinedParameters.aspectRatio) ? combinedParameters.aspectRatio : "16:9",
|
|
151
|
-
...(combinedParameters.seed && Number.isInteger(combinedParameters.seed && combinedParameters.seed > 0
|
|
268
|
+
...(combinedParameters.seed && Number.isInteger(combinedParameters.seed) && combinedParameters.seed > 0 ? { seed: combinedParameters.seed } : {}),
|
|
152
269
|
fps: validFps.includes(combinedParameters.fps) ? combinedParameters.fps : 24,
|
|
153
270
|
camera_fixed: combinedParameters.camera_fixed || false,
|
|
154
271
|
duration: combinedParameters.duration || 5,
|
|
@@ -157,6 +274,86 @@ class ReplicateApiPlugin extends ModelPlugin {
|
|
|
157
274
|
};
|
|
158
275
|
break;
|
|
159
276
|
}
|
|
277
|
+
case "replicate-seedream-4": {
|
|
278
|
+
const validSizes = ["1K", "2K", "4K", "custom"];
|
|
279
|
+
const validRatios = ["1:1", "4:3", "3:4", "16:9", "9:16", "match_input_image"];
|
|
280
|
+
const validSequentialModes = ["disabled", "auto"];
|
|
281
|
+
|
|
282
|
+
// Collect input images from multiple parameter sources (same pattern as qwen-image-edit-plus)
|
|
283
|
+
const collectImages = (candidate, accumulator) => {
|
|
284
|
+
if (!candidate) return;
|
|
285
|
+
if (Array.isArray(candidate)) {
|
|
286
|
+
candidate.forEach((item) => collectImages(item, accumulator));
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
accumulator.push(candidate);
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const imageCandidates = [];
|
|
293
|
+
collectImages(combinedParameters.image, imageCandidates);
|
|
294
|
+
collectImages(combinedParameters.images, imageCandidates);
|
|
295
|
+
collectImages(combinedParameters.input_image, imageCandidates);
|
|
296
|
+
collectImages(combinedParameters.input_images, imageCandidates);
|
|
297
|
+
collectImages(combinedParameters.input_image_1, imageCandidates);
|
|
298
|
+
collectImages(combinedParameters.input_image_2, imageCandidates);
|
|
299
|
+
collectImages(combinedParameters.input_image_3, imageCandidates);
|
|
300
|
+
collectImages(combinedParameters.image_1, imageCandidates);
|
|
301
|
+
collectImages(combinedParameters.image_2, imageCandidates);
|
|
302
|
+
collectImages(combinedParameters.imageInput, imageCandidates);
|
|
303
|
+
|
|
304
|
+
const normalizeImageEntry = (entry) => {
|
|
305
|
+
if (!entry) return null;
|
|
306
|
+
if (typeof entry === "string") {
|
|
307
|
+
return entry; // Return the URL string directly
|
|
308
|
+
}
|
|
309
|
+
if (typeof entry === "object") {
|
|
310
|
+
if (Array.isArray(entry)) {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
if (entry.value) {
|
|
314
|
+
return entry.value; // Return the value as a string
|
|
315
|
+
}
|
|
316
|
+
if (entry.url) {
|
|
317
|
+
return entry.url; // Return the URL as a string
|
|
318
|
+
}
|
|
319
|
+
if (entry.path) {
|
|
320
|
+
return entry.path; // Return the path as a string
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return null;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const normalizedImages = imageCandidates
|
|
327
|
+
.map((candidate) => normalizeImageEntry(candidate))
|
|
328
|
+
.filter((candidate) => candidate && typeof candidate === 'string');
|
|
329
|
+
|
|
330
|
+
const omitUndefined = (obj) =>
|
|
331
|
+
Object.fromEntries(
|
|
332
|
+
Object.entries(obj).filter(([, value]) => value !== undefined && value !== null),
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
const basePayload = omitUndefined({
|
|
336
|
+
prompt: modelPromptText,
|
|
337
|
+
size: validSizes.includes(combinedParameters.size) ? combinedParameters.size : "2K",
|
|
338
|
+
width: combinedParameters.width || 2048,
|
|
339
|
+
height: combinedParameters.height || 2048,
|
|
340
|
+
max_images: combinedParameters.maxImages || combinedParameters.numberResults || 1,
|
|
341
|
+
aspect_ratio: validRatios.includes(combinedParameters.aspectRatio) ? combinedParameters.aspectRatio : "4:3",
|
|
342
|
+
sequential_image_generation: validSequentialModes.includes(combinedParameters.sequentialImageGeneration) ? combinedParameters.sequentialImageGeneration : "disabled",
|
|
343
|
+
...(combinedParameters.seed && Number.isInteger(combinedParameters.seed) && combinedParameters.seed > 0 ? { seed: combinedParameters.seed } : {}),
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// For seedream-4, include the image_input array if we have images
|
|
347
|
+
const inputPayload = {
|
|
348
|
+
...basePayload,
|
|
349
|
+
...(normalizedImages.length > 0 ? { image_input: normalizedImages } : {})
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
requestParameters = {
|
|
353
|
+
input: inputPayload,
|
|
354
|
+
};
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
160
357
|
}
|
|
161
358
|
|
|
162
359
|
return requestParameters;
|
|
@@ -174,12 +371,14 @@ class ReplicateApiPlugin extends ModelPlugin {
|
|
|
174
371
|
cortexRequest.params = requestParameters.params;
|
|
175
372
|
|
|
176
373
|
// Make initial request to start prediction
|
|
177
|
-
const
|
|
178
|
-
|
|
374
|
+
const response = await this.executeRequest(cortexRequest);
|
|
375
|
+
|
|
376
|
+
// Parse the response to get the actual Replicate data
|
|
377
|
+
const parsedResponse = JSON.parse(response.output_text);
|
|
179
378
|
|
|
180
|
-
// If we got a completed response, return it
|
|
379
|
+
// If we got a completed response, return it as CortexResponse
|
|
181
380
|
if (parsedResponse?.status === "succeeded") {
|
|
182
|
-
return
|
|
381
|
+
return this.createCortexResponse(response);
|
|
183
382
|
}
|
|
184
383
|
|
|
185
384
|
logger.info("Replicate API returned a non-completed response.");
|
|
@@ -211,7 +410,9 @@ class ReplicateApiPlugin extends ModelPlugin {
|
|
|
211
410
|
|
|
212
411
|
if (status === "succeeded") {
|
|
213
412
|
logger.info("Replicate API returned a completed response after polling");
|
|
214
|
-
|
|
413
|
+
// Parse the polled response to extract artifacts
|
|
414
|
+
const parsedResponse = this.parseResponse(pollResponse.data);
|
|
415
|
+
return this.createCortexResponse(parsedResponse);
|
|
215
416
|
} else if (status === "failed" || status === "canceled") {
|
|
216
417
|
throw new Error(`Prediction ${status}: ${pollResponse.data?.error || "Unknown error"}`);
|
|
217
418
|
}
|
|
@@ -227,12 +428,67 @@ class ReplicateApiPlugin extends ModelPlugin {
|
|
|
227
428
|
throw new Error(`Prediction ${predictionId} timed out after ${maxAttempts * pollInterval / 1000} seconds`);
|
|
228
429
|
}
|
|
229
430
|
|
|
230
|
-
//
|
|
431
|
+
// Parse the response from the Replicate API and extract image artifacts
|
|
231
432
|
parseResponse(data) {
|
|
232
|
-
|
|
233
|
-
|
|
433
|
+
const responseData = data.data || data;
|
|
434
|
+
const stringifiedResponse = JSON.stringify(responseData);
|
|
435
|
+
|
|
436
|
+
// Extract image URLs from Replicate response for artifacts
|
|
437
|
+
const imageArtifacts = [];
|
|
438
|
+
if (responseData?.output && Array.isArray(responseData.output)) {
|
|
439
|
+
for (const outputItem of responseData.output) {
|
|
440
|
+
if (typeof outputItem === 'string' && outputItem.match(/\.(jpg|jpeg|png|gif|webp)$/i)) {
|
|
441
|
+
// This is an image URL from Replicate
|
|
442
|
+
imageArtifacts.push({
|
|
443
|
+
type: "image",
|
|
444
|
+
url: outputItem,
|
|
445
|
+
mimeType: this.getMimeTypeFromUrl(outputItem)
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return {
|
|
452
|
+
output_text: stringifiedResponse,
|
|
453
|
+
artifacts: imageArtifacts
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Create a CortexResponse from parsed response data
|
|
458
|
+
createCortexResponse(parsedResponse) {
|
|
459
|
+
if (typeof parsedResponse === 'string') {
|
|
460
|
+
// Handle string response (backward compatibility)
|
|
461
|
+
return new CortexResponse({
|
|
462
|
+
output_text: parsedResponse,
|
|
463
|
+
artifacts: []
|
|
464
|
+
});
|
|
465
|
+
} else if (parsedResponse && typeof parsedResponse === 'object') {
|
|
466
|
+
// Handle object response with artifacts
|
|
467
|
+
return new CortexResponse({
|
|
468
|
+
output_text: parsedResponse.output_text,
|
|
469
|
+
artifacts: parsedResponse.artifacts || []
|
|
470
|
+
});
|
|
471
|
+
} else {
|
|
472
|
+
throw new Error('Unexpected response format');
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Helper method to determine MIME type from URL extension
|
|
477
|
+
getMimeTypeFromUrl(url) {
|
|
478
|
+
const extension = url.split('.').pop().toLowerCase();
|
|
479
|
+
switch (extension) {
|
|
480
|
+
case 'jpg':
|
|
481
|
+
case 'jpeg':
|
|
482
|
+
return 'image/jpeg';
|
|
483
|
+
case 'png':
|
|
484
|
+
return 'image/png';
|
|
485
|
+
case 'gif':
|
|
486
|
+
return 'image/gif';
|
|
487
|
+
case 'webp':
|
|
488
|
+
return 'image/webp';
|
|
489
|
+
default:
|
|
490
|
+
return 'image/jpeg'; // Default fallback
|
|
234
491
|
}
|
|
235
|
-
return JSON.stringify(data);
|
|
236
492
|
}
|
|
237
493
|
|
|
238
494
|
// Override the logging function to display the request and response
|
|
@@ -19,7 +19,8 @@ class VeoVideoPlugin extends ModelPlugin {
|
|
|
19
19
|
// Available Veo models
|
|
20
20
|
const availableModels = {
|
|
21
21
|
'veo-2.0-generate': 'GA',
|
|
22
|
-
'veo-3.0-generate': 'Preview'
|
|
22
|
+
'veo-3.0-generate': 'Preview',
|
|
23
|
+
'veo-3.0-fast-generate': 'Preview'
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
// Get the model ID from the pathway or use default
|
|
@@ -51,6 +52,7 @@ class VeoVideoPlugin extends ModelPlugin {
|
|
|
51
52
|
...(combinedParameters.enhancePrompt !== undefined && { enhancePrompt: combinedParameters.enhancePrompt }),
|
|
52
53
|
// generateAudio is required for 3.0 and not supported by 2.0
|
|
53
54
|
...(model === 'veo-3.0-generate' && { generateAudio: combinedParameters.generateAudio !== undefined ? combinedParameters.generateAudio : true }),
|
|
55
|
+
...(model === 'veo-3.0-fast-generate' && { generateAudio: combinedParameters.generateAudio !== undefined ? combinedParameters.generateAudio : true }),
|
|
54
56
|
...(combinedParameters.negativePrompt && { negativePrompt: combinedParameters.negativePrompt }),
|
|
55
57
|
...(combinedParameters.personGeneration && { personGeneration: combinedParameters.personGeneration }),
|
|
56
58
|
...(combinedParameters.sampleCount && { sampleCount: combinedParameters.sampleCount }),
|
|
@@ -69,6 +71,9 @@ class VeoVideoPlugin extends ModelPlugin {
|
|
|
69
71
|
if (model === 'veo-3.0-generate' && parameters.durationSeconds !== 8) {
|
|
70
72
|
throw new Error(`Veo 3.0 only supports durationSeconds: 8, got: ${parameters.durationSeconds}`);
|
|
71
73
|
}
|
|
74
|
+
if (model === 'veo-3.0-fast-generate' && parameters.durationSeconds !== 8) {
|
|
75
|
+
throw new Error(`Veo 3.0 only supports durationSeconds: 8, got: ${parameters.durationSeconds}`);
|
|
76
|
+
}
|
|
72
77
|
if (model === 'veo-2.0-generate' && (parameters.durationSeconds < 5 || parameters.durationSeconds > 8)) {
|
|
73
78
|
throw new Error(`Veo 2.0 supports durationSeconds between 5-8, got: ${parameters.durationSeconds}`);
|
|
74
79
|
}
|
|
@@ -82,6 +87,12 @@ class VeoVideoPlugin extends ModelPlugin {
|
|
|
82
87
|
if (parameters.video) {
|
|
83
88
|
throw new Error('video parameter is not supported in Veo 3.0');
|
|
84
89
|
}
|
|
90
|
+
if (model === 'veo-3.0-fast-generate' && parameters.lastFrame) {
|
|
91
|
+
throw new Error('lastFrame parameter is not supported in Veo 3.0');
|
|
92
|
+
}
|
|
93
|
+
if (model === 'veo-3.0-fast-generate' && parameters.video) {
|
|
94
|
+
throw new Error('video parameter is not supported in Veo 3.0');
|
|
95
|
+
}
|
|
85
96
|
}
|
|
86
97
|
|
|
87
98
|
// generateAudio constraints
|
|
@@ -91,6 +102,9 @@ class VeoVideoPlugin extends ModelPlugin {
|
|
|
91
102
|
if (model === 'veo-3.0-generate' && parameters.generateAudio === undefined) {
|
|
92
103
|
logger.warn('generateAudio is required for Veo 3.0, defaulting to true');
|
|
93
104
|
}
|
|
105
|
+
if (model === 'veo-3.0-fast-generate' && parameters.generateAudio === undefined) {
|
|
106
|
+
logger.warn('generateAudio is required for Veo 3.0, defaulting to true');
|
|
107
|
+
}
|
|
94
108
|
}
|
|
95
109
|
|
|
96
110
|
// Execute the request to the Veo API
|
package/server/rest.js
CHANGED
|
@@ -139,6 +139,8 @@ const processRestRequest = async (server, req, pathway, name, parameterMap = {})
|
|
|
139
139
|
return Boolean(value);
|
|
140
140
|
} else if (type === 'Int') {
|
|
141
141
|
return parseInt(value, 10);
|
|
142
|
+
} else if (type === 'Float') {
|
|
143
|
+
return parseFloat(value);
|
|
142
144
|
} else if (type === '[MultiMessage]' && Array.isArray(value)) {
|
|
143
145
|
return value.map(msg => ({
|
|
144
146
|
...msg,
|
package/server/typeDef.js
CHANGED
|
@@ -1,30 +1,113 @@
|
|
|
1
|
+
// Check if a value is a JSON Schema object for parameter typing
|
|
2
|
+
const isJsonSchemaObject = (value) => {
|
|
3
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;
|
|
4
|
+
// Basic JSON Schema indicators
|
|
5
|
+
return (
|
|
6
|
+
typeof value.type === 'string' ||
|
|
7
|
+
value.$ref !== undefined ||
|
|
8
|
+
value.oneOf !== undefined ||
|
|
9
|
+
value.anyOf !== undefined ||
|
|
10
|
+
value.allOf !== undefined ||
|
|
11
|
+
value.enum !== undefined ||
|
|
12
|
+
value.properties !== undefined ||
|
|
13
|
+
value.items !== undefined
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// Extract the default value from a JSON Schema object or return the value as-is
|
|
18
|
+
const extractValueFromTypeSpec = (value) => {
|
|
19
|
+
if (isJsonSchemaObject(value)) {
|
|
20
|
+
return value.hasOwnProperty('default') ? value.default : undefined;
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Process parameters to convert any type specification objects to their actual values
|
|
26
|
+
const processPathwayParameters = (params) => {
|
|
27
|
+
if (!params || typeof params !== 'object') {
|
|
28
|
+
return params;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const processed = {};
|
|
32
|
+
for (const [key, value] of Object.entries(params)) {
|
|
33
|
+
processed[key] = extractValueFromTypeSpec(value);
|
|
34
|
+
}
|
|
35
|
+
return processed;
|
|
36
|
+
};
|
|
37
|
+
|
|
1
38
|
const getGraphQlType = (value) => {
|
|
39
|
+
// The value might be an object with JSON Schema type specification
|
|
40
|
+
if (isJsonSchemaObject(value)) {
|
|
41
|
+
const schema = value;
|
|
42
|
+
// Map JSON Schema to GraphQL
|
|
43
|
+
if (schema.type === 'boolean') {
|
|
44
|
+
return { type: 'Boolean', defaultValue: schema.default === undefined ? undefined : schema.default };
|
|
45
|
+
}
|
|
46
|
+
if (schema.type === 'string') {
|
|
47
|
+
return { type: 'String', defaultValue: schema.default === undefined ? undefined : `"${schema.default}"` };
|
|
48
|
+
}
|
|
49
|
+
if (schema.type === 'integer') {
|
|
50
|
+
return { type: 'Int', defaultValue: schema.default };
|
|
51
|
+
}
|
|
52
|
+
if (schema.type === 'number') {
|
|
53
|
+
const def = schema.default;
|
|
54
|
+
return { type: 'Float', defaultValue: def };
|
|
55
|
+
}
|
|
56
|
+
if (schema.type === 'array') {
|
|
57
|
+
// Support arrays of primitive types; fall back to JSON string for complex types
|
|
58
|
+
const items = schema.items || {};
|
|
59
|
+
const def = schema.default;
|
|
60
|
+
const defaultArray = Array.isArray(def) ? JSON.stringify(def) : '[]';
|
|
61
|
+
if (items.type === 'string') {
|
|
62
|
+
return { type: '[String]', defaultValue: defaultArray };
|
|
63
|
+
}
|
|
64
|
+
if (items.type === 'integer') {
|
|
65
|
+
return { type: '[Int]', defaultValue: defaultArray };
|
|
66
|
+
}
|
|
67
|
+
if (items.type === 'number') {
|
|
68
|
+
return { type: '[Float]', defaultValue: defaultArray };
|
|
69
|
+
}
|
|
70
|
+
if (items.type === 'boolean') {
|
|
71
|
+
return { type: '[Boolean]', defaultValue: defaultArray };
|
|
72
|
+
}
|
|
73
|
+
// Unknown item type: pass as serialized JSON string argument
|
|
74
|
+
return { type: 'String', defaultValue: def === undefined ? '"[]"' : `"${JSON.stringify(def).replace(/"/g, '\\"')}"` };
|
|
75
|
+
}
|
|
76
|
+
if (schema.type === 'object' || schema.properties) {
|
|
77
|
+
// Until explicit input types are defined, accept as stringified JSON
|
|
78
|
+
const def = schema.default;
|
|
79
|
+
return { type: 'String', defaultValue: def === undefined ? '"{}"' : `"${JSON.stringify(def).replace(/"/g, '\\"')}"` };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Otherwise, autodetect the type
|
|
2
84
|
switch (typeof value) {
|
|
3
85
|
case 'boolean':
|
|
4
|
-
return {type: 'Boolean'};
|
|
86
|
+
return {type: 'Boolean', defaultValue: value};
|
|
5
87
|
case 'string':
|
|
6
|
-
return {type: 'String'};
|
|
88
|
+
return {type: 'String', defaultValue: `"${value}"`};
|
|
7
89
|
case 'number':
|
|
8
|
-
|
|
90
|
+
// Check if it's an integer or float
|
|
91
|
+
return Number.isInteger(value) ? {type: 'Int', defaultValue: value} : {type: 'Float', defaultValue: value};
|
|
9
92
|
case 'object':
|
|
10
93
|
if (Array.isArray(value)) {
|
|
11
94
|
if (value.length > 0 && typeof(value[0]) === 'string') {
|
|
12
|
-
return {type: '[String]'};
|
|
95
|
+
return {type: '[String]', defaultValue: JSON.stringify(value)};
|
|
13
96
|
}
|
|
14
97
|
else {
|
|
15
|
-
//
|
|
98
|
+
// Check if it's MultiMessage (content is array) or Message (content is string)
|
|
16
99
|
if (Array.isArray(value[0]?.content)) {
|
|
17
|
-
return {type: '[MultiMessage]'};
|
|
100
|
+
return {type: '[MultiMessage]', defaultValue: `"${JSON.stringify(value).replace(/"/g, '\\"')}"`};
|
|
18
101
|
}
|
|
19
102
|
else {
|
|
20
|
-
return {type: '[Message]'};
|
|
103
|
+
return {type: '[Message]', defaultValue: `"${JSON.stringify(value).replace(/"/g, '\\"')}"`};
|
|
21
104
|
}
|
|
22
105
|
}
|
|
23
106
|
} else {
|
|
24
|
-
return {type: `[${value.objName}]
|
|
107
|
+
return {type: `[${value.objName}]`, defaultValue: JSON.stringify(value)};
|
|
25
108
|
}
|
|
26
109
|
default:
|
|
27
|
-
return {type: 'String'};
|
|
110
|
+
return {type: 'String', defaultValue: `"${value}"`};
|
|
28
111
|
}
|
|
29
112
|
};
|
|
30
113
|
|
|
@@ -80,7 +163,7 @@ const getPathwayTypeDefAndExtendQuery = (pathway) => {
|
|
|
80
163
|
};
|
|
81
164
|
});
|
|
82
165
|
|
|
83
|
-
const gqlDefinition = `${type}\n\n${responseType}\n\nextend type Query {${name}(${paramsStr}): ${objName}}`;
|
|
166
|
+
const gqlDefinition = `${type}\n\n${responseType}\n\nextend type Query {${name}${paramsStr ? `(${paramsStr})` : ''}: ${objName}}`;
|
|
84
167
|
|
|
85
168
|
return {
|
|
86
169
|
gqlDefinition,
|
|
@@ -100,4 +183,7 @@ export {
|
|
|
100
183
|
getMessageTypeDefs,
|
|
101
184
|
getPathwayTypeDef,
|
|
102
185
|
userPathwayInputParameters,
|
|
186
|
+
isJsonSchemaObject,
|
|
187
|
+
extractValueFromTypeSpec,
|
|
188
|
+
processPathwayParameters,
|
|
103
189
|
};
|
|
@@ -155,7 +155,7 @@ test.serial('AppTek Plugin: Force failure and test GPT-4 Omni fallback', async (
|
|
|
155
155
|
});
|
|
156
156
|
|
|
157
157
|
// Test AppTek failure with default fallback (translate_groq)
|
|
158
|
-
test
|
|
158
|
+
test('AppTek Plugin: Force failure and test default fallback', async (t) => {
|
|
159
159
|
// Set a longer timeout for this test since Groq might be slower
|
|
160
160
|
t.timeout(180000); // 3 minutes
|
|
161
161
|
|
|
@@ -193,8 +193,7 @@ test('_createPromptObject handles empty system prompt', t => {
|
|
|
193
193
|
|
|
194
194
|
t.true(result instanceof Prompt);
|
|
195
195
|
t.is(result.name, 'test_prompt');
|
|
196
|
-
t.is(result.messages[0].content, '');
|
|
197
|
-
t.is(result.messages[1].content, '{{text}}\n\nTest prompt text');
|
|
196
|
+
t.is(result.messages[0].content, '{{text}}\n\nTest prompt text');
|
|
198
197
|
});
|
|
199
198
|
|
|
200
199
|
test('_createPromptObject handles null system prompt', t => {
|
|
@@ -206,8 +205,7 @@ test('_createPromptObject handles null system prompt', t => {
|
|
|
206
205
|
|
|
207
206
|
t.true(result instanceof Prompt);
|
|
208
207
|
t.is(result.name, 'test_prompt');
|
|
209
|
-
t.is(result.messages[0].content, '');
|
|
210
|
-
t.is(result.messages[1].content, '{{text}}\n\nTest prompt text');
|
|
208
|
+
t.is(result.messages[0].content, '{{text}}\n\nTest prompt text');
|
|
211
209
|
});
|
|
212
210
|
|
|
213
211
|
test('putPathway requires userId and secret', async t => {
|