@mixio-pro/kalaasetu-mcp 1.0.11 → 1.0.13
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/package.json +1 -1
- package/src/tools/gemini.ts +7 -14
- package/src/tools/image-to-video.ts +43 -9
- package/src/utils/filename.ts +19 -3
package/package.json
CHANGED
package/src/tools/gemini.ts
CHANGED
|
@@ -245,16 +245,13 @@ export const geminiTextToImage = {
|
|
|
245
245
|
const imageData = part.inlineData.data;
|
|
246
246
|
if (args.output_path) {
|
|
247
247
|
const storage = getStorage();
|
|
248
|
-
const timestampedPath = generateTimestampedFilename(
|
|
249
|
-
args.output_path
|
|
250
|
-
);
|
|
251
248
|
const url = await storage.writeFile(
|
|
252
|
-
|
|
249
|
+
args.output_path,
|
|
253
250
|
Buffer.from(imageData, "base64")
|
|
254
251
|
);
|
|
255
252
|
images.push({
|
|
256
253
|
url,
|
|
257
|
-
filename:
|
|
254
|
+
filename: args.output_path,
|
|
258
255
|
mimeType: "image/png",
|
|
259
256
|
});
|
|
260
257
|
}
|
|
@@ -326,16 +323,13 @@ export const geminiEditImage = {
|
|
|
326
323
|
const imageData = part.inlineData.data;
|
|
327
324
|
if (args.output_path) {
|
|
328
325
|
const storage = getStorage();
|
|
329
|
-
const timestampedPath = generateTimestampedFilename(
|
|
330
|
-
args.output_path
|
|
331
|
-
);
|
|
332
326
|
const url = await storage.writeFile(
|
|
333
|
-
|
|
327
|
+
args.output_path,
|
|
334
328
|
Buffer.from(imageData, "base64")
|
|
335
329
|
);
|
|
336
330
|
images.push({
|
|
337
331
|
url,
|
|
338
|
-
filename:
|
|
332
|
+
filename: args.output_path,
|
|
339
333
|
mimeType: "image/png",
|
|
340
334
|
});
|
|
341
335
|
}
|
|
@@ -470,12 +464,11 @@ export const geminiSingleSpeakerTts = {
|
|
|
470
464
|
|
|
471
465
|
const audioBuffer = Buffer.from(data, "base64");
|
|
472
466
|
|
|
473
|
-
//
|
|
474
|
-
const outputPath = args.output_path || "voice_output.wav";
|
|
475
|
-
const timestampedPath = generateTimestampedFilename(outputPath);
|
|
467
|
+
// Use provided output path or generate default with timestamp
|
|
468
|
+
const outputPath = args.output_path || generateTimestampedFilename("voice_output.wav");
|
|
476
469
|
|
|
477
470
|
const storage = getStorage();
|
|
478
|
-
const url = await storage.writeFile(
|
|
471
|
+
const url = await storage.writeFile(outputPath, audioBuffer);
|
|
479
472
|
|
|
480
473
|
return JSON.stringify({
|
|
481
474
|
audio: {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
1
|
import { GoogleAuth } from "google-auth-library";
|
|
3
2
|
import { exec } from "child_process";
|
|
4
3
|
import * as path from "path";
|
|
@@ -99,7 +98,9 @@ export const imageToVideo = {
|
|
|
99
98
|
duration_seconds: z
|
|
100
99
|
.string()
|
|
101
100
|
.optional()
|
|
102
|
-
.describe(
|
|
101
|
+
.describe(
|
|
102
|
+
"Video duration in seconds. MUST be one of: '4', '6', or '8' (default: '6'). Other values will be rejected by Vertex AI."
|
|
103
|
+
),
|
|
103
104
|
resolution: z
|
|
104
105
|
.string()
|
|
105
106
|
.optional()
|
|
@@ -164,6 +165,32 @@ export const imageToVideo = {
|
|
|
164
165
|
const location = args.location_id || "us-central1";
|
|
165
166
|
const modelId = args.model_id || "veo-3.1-fast-generate-preview";
|
|
166
167
|
|
|
168
|
+
// Validate and parse duration_seconds - snap to nearest 4, 6, or 8
|
|
169
|
+
let durationSeconds = parseInt(args.duration_seconds || "6");
|
|
170
|
+
if (isNaN(durationSeconds)) durationSeconds = 6;
|
|
171
|
+
|
|
172
|
+
const validDurations = [4, 6, 8];
|
|
173
|
+
// Find nearest valid duration
|
|
174
|
+
durationSeconds = validDurations.reduce((prev, curr) => {
|
|
175
|
+
return Math.abs(curr - durationSeconds) < Math.abs(prev - durationSeconds)
|
|
176
|
+
? curr
|
|
177
|
+
: prev;
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Tie-breaking: if equidistant (e.g. 5), the reduce above keeps the first one (4) because < is strict.
|
|
181
|
+
// However, user requested "nearest duration with the ceil", effectively meaning round up if equidistant.
|
|
182
|
+
// Let's explicitly handle the equidistant cases or just use a custom finder.
|
|
183
|
+
// 5 -> equidistant to 4 and 6. "With ceil" implies 6.
|
|
184
|
+
// 7 -> equidistant to 6 and 8. "With ceil" implies 8.
|
|
185
|
+
|
|
186
|
+
// Simpler logic for these specific values:
|
|
187
|
+
if (durationSeconds === 4 && parseInt(args.duration_seconds || "6") === 5) {
|
|
188
|
+
durationSeconds = 6;
|
|
189
|
+
}
|
|
190
|
+
if (durationSeconds === 6 && parseInt(args.duration_seconds || "6") === 7) {
|
|
191
|
+
durationSeconds = 8;
|
|
192
|
+
}
|
|
193
|
+
|
|
167
194
|
const token = await fetchAccessToken();
|
|
168
195
|
|
|
169
196
|
const url = `https://${location}-aiplatform.googleapis.com/v1/projects/${projectId}/locations/${location}/publishers/google/models/${modelId}:predictLongRunning`;
|
|
@@ -242,7 +269,7 @@ export const imageToVideo = {
|
|
|
242
269
|
|
|
243
270
|
const parameters: any = {
|
|
244
271
|
aspectRatio: args.aspect_ratio || "9:16",
|
|
245
|
-
durationSeconds:
|
|
272
|
+
durationSeconds: durationSeconds,
|
|
246
273
|
resolution: args.resolution || "720p",
|
|
247
274
|
negativePrompt: args.negative_prompt,
|
|
248
275
|
generateAudio: args.generate_audio || false,
|
|
@@ -302,13 +329,20 @@ export const imageToVideo = {
|
|
|
302
329
|
[];
|
|
303
330
|
const saveVideo = async (base64: string, index: number) => {
|
|
304
331
|
if (!base64) return;
|
|
305
|
-
const baseFilename = args.output_path
|
|
306
|
-
? index === 0
|
|
307
|
-
? args.output_path
|
|
308
|
-
: args.output_path.replace(/\.mp4$/i, `_${index}.mp4`)
|
|
309
|
-
: `video_output${index > 0 ? `_${index}` : ""}.mp4`;
|
|
310
332
|
|
|
311
|
-
|
|
333
|
+
// Use provided output path or generate default with timestamp
|
|
334
|
+
let filePath: string;
|
|
335
|
+
if (args.output_path) {
|
|
336
|
+
// User provided path - use as-is for first video, add index for subsequent
|
|
337
|
+
filePath =
|
|
338
|
+
index === 0
|
|
339
|
+
? args.output_path
|
|
340
|
+
: args.output_path.replace(/\.mp4$/i, `_${index}.mp4`);
|
|
341
|
+
} else {
|
|
342
|
+
// No path provided - generate timestamped default
|
|
343
|
+
const defaultName = `video_output${index > 0 ? `_${index}` : ""}.mp4`;
|
|
344
|
+
filePath = generateTimestampedFilename(defaultName);
|
|
345
|
+
}
|
|
312
346
|
|
|
313
347
|
const buf = Buffer.from(base64, "base64");
|
|
314
348
|
const storage = getStorage();
|
package/src/utils/filename.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import * as path from "path";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Generate a timestamped filename to avoid conflicts
|
|
3
5
|
* Format: YYYYMMDD_HHmmss_filename.ext
|
|
6
|
+
* Preserves directory structure if present in the input path
|
|
4
7
|
*/
|
|
5
|
-
export function generateTimestampedFilename(
|
|
8
|
+
export function generateTimestampedFilename(filePath: string): string {
|
|
6
9
|
const now = new Date();
|
|
7
10
|
const timestamp = now
|
|
8
11
|
.toISOString()
|
|
@@ -10,13 +13,26 @@ export function generateTimestampedFilename(basename: string): string {
|
|
|
10
13
|
.replace(/\.\d{3}Z$/, "")
|
|
11
14
|
.replace("T", "_");
|
|
12
15
|
|
|
16
|
+
// Split into directory and filename
|
|
17
|
+
const dir = path.dirname(filePath);
|
|
18
|
+
const basename = path.basename(filePath);
|
|
19
|
+
|
|
13
20
|
// Extract extension if present
|
|
14
21
|
const lastDot = basename.lastIndexOf(".");
|
|
22
|
+
let timestampedFilename: string;
|
|
23
|
+
|
|
15
24
|
if (lastDot > 0) {
|
|
16
25
|
const name = basename.substring(0, lastDot);
|
|
17
26
|
const ext = basename.substring(lastDot);
|
|
18
|
-
|
|
27
|
+
timestampedFilename = `${timestamp}_${name}${ext}`;
|
|
28
|
+
} else {
|
|
29
|
+
timestampedFilename = `${timestamp}_${basename}`;
|
|
19
30
|
}
|
|
20
31
|
|
|
21
|
-
|
|
32
|
+
// Reconstruct the full path
|
|
33
|
+
if (dir === ".") {
|
|
34
|
+
return timestampedFilename;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return path.join(dir, timestampedFilename);
|
|
22
38
|
}
|