@mixio-pro/kalaasetu-mcp 1.0.8 → 1.0.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mixio-pro/kalaasetu-mcp",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "A powerful Model Context Protocol server providing AI tools for content generation and analysis",
5
5
  "type": "module",
6
6
  "module": "src/index.ts",
@@ -10,6 +10,7 @@ import * as os from "os";
10
10
  import * as wav from "wav";
11
11
  import { PassThrough } from "stream";
12
12
  import { getStorage } from "../storage";
13
+ import { generateTimestampedFilename } from "../utils/filename";
13
14
 
14
15
  const ai = new GoogleGenAI({
15
16
  apiKey: process.env.GEMINI_API_KEY || "",
@@ -166,30 +167,44 @@ async function processVideoInput(
166
167
  export const geminiTextToImage = {
167
168
  name: "generateImage",
168
169
  description:
169
- "Generate images from text prompts using Gemini 2.5 Flash Image model",
170
+ "Generate images from text prompts using Gemini image models with optional reference images",
170
171
  parameters: z.object({
171
172
  prompt: z.string().describe("Text description of the image to generate"),
172
173
  aspect_ratio: z
173
174
  .string()
174
175
  .optional()
175
- .describe("Aspect ratio: 1:1, 3:4, 4:3, 9:16, or 16:9"),
176
+ .describe("Aspect ratio: 1:1, 3:4, 4:3, 9:16, or 16:9 (default 9:16)"),
176
177
  output_path: z
177
178
  .string()
178
179
  .optional()
179
180
  .describe("File path to save the generated image"),
181
+ reference_images: z
182
+ .array(z.string())
183
+ .optional()
184
+ .describe("Optional reference image file paths to guide generation"),
180
185
  }),
181
186
  execute: async (args: {
182
187
  prompt: string;
183
188
  aspect_ratio?: string;
184
189
  output_path?: string;
190
+ reference_images?: string[];
185
191
  }) => {
186
192
  try {
193
+ const contents: any[] = [args.prompt];
194
+
195
+ if (args.reference_images && Array.isArray(args.reference_images)) {
196
+ for (const refPath of args.reference_images) {
197
+ contents.push(await fileToGenerativePart(refPath));
198
+ }
199
+ }
200
+
187
201
  const response = await ai.models.generateContent({
188
- model: "gemini-2.5-flash-image",
189
- contents: args.prompt,
202
+ model: "gemini-3-pro-image-preview",
203
+ contents: contents,
190
204
  config: {
205
+ responseModalities: ["TEXT", "IMAGE"],
191
206
  imageConfig: {
192
- aspectRatio: args.aspect_ratio || "1:1",
207
+ aspectRatio: args.aspect_ratio || "9:16",
193
208
  },
194
209
  },
195
210
  });
@@ -205,13 +220,16 @@ export const geminiTextToImage = {
205
220
  const imageData = part.inlineData.data;
206
221
  if (args.output_path) {
207
222
  const storage = getStorage();
223
+ const timestampedPath = generateTimestampedFilename(
224
+ args.output_path
225
+ );
208
226
  const url = await storage.writeFile(
209
- args.output_path,
227
+ timestampedPath,
210
228
  Buffer.from(imageData, "base64")
211
229
  );
212
230
  images.push({
213
231
  url,
214
- filename: args.output_path,
232
+ filename: timestampedPath,
215
233
  mimeType: "image/png",
216
234
  });
217
235
  }
@@ -238,7 +256,7 @@ export const geminiTextToImage = {
238
256
  export const geminiEditImage = {
239
257
  name: "editImage",
240
258
  description:
241
- "Edit existing images with text instructions using Gemini 2.5 Flash Image Preview",
259
+ "Edit existing images with text instructions using Gemini 3 Pro Image Preview",
242
260
  parameters: z.object({
243
261
  image_path: z.string().describe("Path to the source image file"),
244
262
  prompt: z.string().describe("Text instructions for editing the image"),
@@ -268,7 +286,7 @@ export const geminiEditImage = {
268
286
  }
269
287
 
270
288
  const response = await ai.models.generateContent({
271
- model: "gemini-2.5-flash-image-preview",
289
+ model: "gemini-3-pro-image-preview",
272
290
  contents: contents,
273
291
  });
274
292
 
@@ -283,13 +301,16 @@ export const geminiEditImage = {
283
301
  const imageData = part.inlineData.data;
284
302
  if (args.output_path) {
285
303
  const storage = getStorage();
304
+ const timestampedPath = generateTimestampedFilename(
305
+ args.output_path
306
+ );
286
307
  const url = await storage.writeFile(
287
- args.output_path,
308
+ timestampedPath,
288
309
  Buffer.from(imageData, "base64")
289
310
  );
290
311
  images.push({
291
312
  url,
292
- filename: args.output_path,
313
+ filename: timestampedPath,
293
314
  mimeType: "image/png",
294
315
  });
295
316
  }
@@ -425,10 +446,11 @@ export const geminiSingleSpeakerTts = {
425
446
  const audioBuffer = Buffer.from(data, "base64");
426
447
 
427
448
  // Generate output filename if not provided
428
- const outputPath = args.output_path || `voice_output_${Date.now()}.wav`;
449
+ const outputPath = args.output_path || "voice_output.wav";
450
+ const timestampedPath = generateTimestampedFilename(outputPath);
429
451
 
430
452
  const storage = getStorage();
431
- const url = await storage.writeFile(outputPath, audioBuffer);
453
+ const url = await storage.writeFile(timestampedPath, audioBuffer);
432
454
 
433
455
  return JSON.stringify({
434
456
  audio: {
@@ -4,6 +4,7 @@ import { exec } from "child_process";
4
4
  import * as path from "path";
5
5
  import { z } from "zod";
6
6
  import { getStorage } from "../storage";
7
+ import { generateTimestampedFilename } from "../utils/filename";
7
8
 
8
9
  async function wait(ms: number): Promise<void> {
9
10
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -287,11 +288,13 @@ export const imageToVideo = {
287
288
  [];
288
289
  const saveVideo = async (base64: string, index: number) => {
289
290
  if (!base64) return;
290
- const filePath = args.output_path
291
+ const baseFilename = args.output_path
291
292
  ? index === 0
292
293
  ? args.output_path
293
294
  : args.output_path.replace(/\.mp4$/i, `_${index}.mp4`)
294
- : `video_output_${Date.now()}${index === 0 ? "" : "_" + index}.mp4`;
295
+ : `video_output${index > 0 ? `_${index}` : ""}.mp4`;
296
+
297
+ const filePath = generateTimestampedFilename(baseFilename);
295
298
 
296
299
  const buf = Buffer.from(base64, "base64");
297
300
  const storage = getStorage();
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Generate a timestamped filename to avoid conflicts
3
+ * Format: YYYYMMDD_HHmmss_filename.ext
4
+ */
5
+ export function generateTimestampedFilename(basename: string): string {
6
+ const now = new Date();
7
+ const timestamp = now
8
+ .toISOString()
9
+ .replace(/[-:]/g, "")
10
+ .replace(/\.\d{3}Z$/, "")
11
+ .replace("T", "_");
12
+
13
+ // Extract extension if present
14
+ const lastDot = basename.lastIndexOf(".");
15
+ if (lastDot > 0) {
16
+ const name = basename.substring(0, lastDot);
17
+ const ext = basename.substring(lastDot);
18
+ return `${timestamp}_${name}${ext}`;
19
+ }
20
+
21
+ return `${timestamp}_${basename}`;
22
+ }