Skip to main content
Glama

generate_and_upload_image

Generate and upload custom images using AI by providing a text prompt, file name, and optional parameters like dimensions, aspect ratio, and output format. Integrates with Printify MCP Server for print-on-demand product design.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
aspectRatioNoAspect ratio (e.g., '16:9', '4:3', '1:1'). If provided, overrides width and height
fileNameYesFile name for the uploaded image
guidanceScaleNoGuidance scale
heightNoImage height in pixels
imagePromptStrengthNoImage prompt strength 0-1 (Flux 1.1 Pro Ultra only)
modelNoOptional: Override the default model. Use get_defaults to see available models
negativePromptNoNegative promptlow quality, bad quality, sketches
numInferenceStepsNoNumber of inference steps
outputFormatNoOutput formatpng
outputQualityNoOutput quality 1-100 (Flux 1.1 Pro only)
promptYesText prompt for image generation
promptUpsamplingNoEnable prompt upsampling (Flux 1.1 Pro only)
rawNoGenerate less processed, more natural-looking images (Flux 1.1 Pro Ultra only)
safetyToleranceNoSafety tolerance (0-6)
seedNoRandom seed for reproducible generation
widthNoImage width in pixels

Implementation Reference

  • src/index.ts:859-1244 (registration)
    Tool registration including schema and inline handler function for generate_and_upload_image
    // Generate and upload image tool - combines Replicate image generation with Printify upload server.tool( "generate_and_upload_image", { prompt: z.string().describe("Text prompt for image generation"), fileName: z.string().describe("File name for the uploaded image"), // Optional model override model: z.string().optional() .describe("Optional: Override the default model. Use get_defaults to see available models"), // Common parameters for both models width: z.number().optional().default(1024).describe("Image width in pixels"), height: z.number().optional().default(1024).describe("Image height in pixels"), aspectRatio: z.string().optional().describe("Aspect ratio (e.g., '16:9', '4:3', '1:1'). If provided, overrides width and height"), outputFormat: z.enum(["jpeg", "png", "webp"]).optional().default("png").describe("Output format"), safetyTolerance: z.number().optional().default(2).describe("Safety tolerance (0-6)"), seed: z.number().optional().describe("Random seed for reproducible generation"), numInferenceSteps: z.number().optional().default(25).describe("Number of inference steps"), guidanceScale: z.number().optional().default(7.5).describe("Guidance scale"), negativePrompt: z.string().optional().default("low quality, bad quality, sketches").describe("Negative prompt"), // Flux 1.1 Pro specific parameters promptUpsampling: z.boolean().optional() .describe("Enable prompt upsampling (Flux 1.1 Pro only)"), outputQuality: z.number().optional() .describe("Output quality 1-100 (Flux 1.1 Pro only)"), // Flux 1.1 Pro Ultra specific parameters raw: z.boolean().optional() .describe("Generate less processed, more natural-looking images (Flux 1.1 Pro Ultra only)"), imagePromptStrength: z.number().optional() .describe("Image prompt strength 0-1 (Flux 1.1 Pro Ultra only)") }, async ({ prompt, fileName, model, width, height, aspectRatio, outputFormat, safetyTolerance, seed, numInferenceSteps, guidanceScale, negativePrompt, promptUpsampling, outputQuality, raw, imagePromptStrength }): Promise<{ content: any[], isError?: boolean }> => { // Import the services const { generateImage } = await import('./services/image-generator.js'); const { formatSuccessResponse } = await import('./utils/error-handler.js'); // Check if clients are initialized if (!replicateClient) { return { content: [{ type: "text", text: "Replicate API client is not initialized. The REPLICATE_API_TOKEN environment variable may not be set." }], isError: true }; } if (!printifyClient) { return { content: [{ type: "text", text: "Printify API client is not initialized. The PRINTIFY_API_KEY environment variable may not be set." }], isError: true }; } // Check if we're using the Ultra model which requires ImgBB // Determine which model to use (user-specified or default) const modelToUse = model || replicateClient.getDefaultModel(); // Check if ImgBB API key is set when using Ultra model if (modelToUse.includes('flux-1.1-pro-ultra') && (!process.env.IMGBB_API_KEY || process.env.IMGBB_API_KEY === 'your-imgbb-api-key')) { return { content: [{ type: "text", text: `ERROR: The Flux 1.1 Pro Ultra model generates high-resolution images that are too large for direct base64 upload.\n\n` + `You MUST set the IMGBB_API_KEY environment variable when using this model.\n\n` + `Get a free API key from https://api.imgbb.com/ and add it to your .env file:\n` + `IMGBB_API_KEY=your_api_key_here` }], isError: true }; } // Check if a shop is selected const currentShop = printifyClient.getCurrentShop(); if (!currentShop) { return { content: [{ type: "text", text: "No shop is currently selected. Use the list_shops and switch_shop tools to select a shop." }], isError: true }; } console.log(`Starting generate_and_upload_image with prompt: ${prompt}`); // Get default parameters first const defaults = replicateClient.getAllDefaults(); // STEP 1: Generate the image with Replicate and process with Sharp // Start with defaults, then override with parameters from the tool call const generationResult = await generateImage( replicateClient, prompt, fileName, { // Start with defaults model: defaults.model, width: defaults.width, height: defaults.height, aspectRatio: defaults.aspectRatio, outputFormat: defaults.outputFormat, safetyTolerance: defaults.safetyTolerance, numInferenceSteps: defaults.numInferenceSteps, guidanceScale: defaults.guidanceScale, negativePrompt: defaults.negativePrompt, raw: defaults.raw, promptUpsampling: defaults.promptUpsampling, outputQuality: defaults.outputQuality, // Override with parameters from the tool call (if provided) ...(model !== undefined && { model }), ...(width !== undefined && { width }), ...(height !== undefined && { height }), ...(aspectRatio !== undefined && { aspectRatio }), ...(outputFormat !== undefined && { outputFormat }), ...(safetyTolerance !== undefined && { safetyTolerance }), ...(seed !== undefined && { seed }), ...(numInferenceSteps !== undefined && { numInferenceSteps }), ...(guidanceScale !== undefined && { guidanceScale }), ...(negativePrompt !== undefined && { negativePrompt }), ...(promptUpsampling !== undefined && { promptUpsampling }), ...(outputQuality !== undefined && { outputQuality }), ...(raw !== undefined && { raw }), ...(imagePromptStrength !== undefined && { imagePromptStrength }) } ); // If image generation failed, return the error if (!generationResult.success) { return generationResult.errorResponse as { content: any[], isError: boolean }; } const imageBuffer = generationResult.buffer; const mimeType = generationResult.mimeType; const finalFileName = generationResult.fileName; const usingModel = generationResult.model; // Make sure we have valid image data if (!imageBuffer) { return { content: [{ type: "text", text: "Failed to get valid image data from the image generator." }], isError: true }; } // STEP 2: Upload the processed image to Printify console.log(`Uploading processed image to Printify`); console.log(`Image buffer size: ${imageBuffer.length} bytes`); console.log(`MIME type: ${mimeType}`); console.log(`File name: ${finalFileName}`); // Prepare for upload to Printify const uploadDetails = [ `Preparing to upload image to Printify:`, `- File name: ${finalFileName}`, `- Image buffer size: ${imageBuffer?.length || 0} bytes`, `- MIME type: ${mimeType}`, `- Model used: ${usingModel}` ].join('\n'); // Save the base64 data to a debug file for inspection try { const fs = await import('fs'); const path = await import('path'); // Create a debug directory if it doesn't exist const debugDir = path.join(process.cwd(), 'debug'); if (!fs.existsSync(debugDir)) { fs.mkdirSync(debugDir, { recursive: true }); } // Save the base64 data to a file for debugging const debugFilePath = path.join(debugDir, `debug_${Date.now()}_${finalFileName}`); // Save buffer directly to debug file if (imageBuffer) { fs.writeFileSync(debugFilePath, imageBuffer); console.log(`Saved image data to debug file: ${debugFilePath}`); console.log(`Debug file size: ${imageBuffer.length} bytes`); } else { console.error('No image data to save for debugging'); } } catch (debugError) { console.error('Error saving debug file:', debugError); } // Validate input data if (!imageBuffer) { return { content: [{ type: "text", text: "Error: No image data available for upload" }], isError: true }; } if (!finalFileName) { return { content: [{ type: "text", text: "Error: No filename available for upload" }], isError: true }; } // STEP 1: Import required modules let axios; let FormData; try { axios = (await import('axios')).default; FormData = (await import('form-data')).default; } catch (importError: any) { return { content: [{ type: "text", text: `Error importing required modules: ${importError.message || String(importError)}` }], isError: true }; } // STEP 2: Prepare image for upload (either via ImgBB or direct base64) let imageUrl; let uploadMethod = "direct"; // Check if we're using the Ultra model const isUsingUltraModel = usingModel.includes('flux-1.1-pro-ultra'); // Check if ImgBB API key is set const imgbbApiKey = process.env.IMGBB_API_KEY; if (imgbbApiKey && imgbbApiKey !== 'your-imgbb-api-key') { // If ImgBB API key is set, use ImgBB to get a URL try { // Create form data for ImgBB const formData = new FormData(); // Convert buffer to base64 for ImgBB upload const base64Data = imageBuffer.toString('base64'); formData.append('image', base64Data); // Upload to ImgBB with the key as a query parameter const imgbbResponse = await axios.post( `https://api.imgbb.com/1/upload?key=${imgbbApiKey}`, formData ); // Get the image URL from ImgBB response imageUrl = imgbbResponse.data.data.url; uploadMethod = "imgbb"; // Log success console.log(`Successfully uploaded image to ImgBB. URL: ${imageUrl}`); } catch (imgbbError: any) { // Only fall back to direct upload if not using Ultra model if (isUsingUltraModel) { return { content: [{ type: "text", text: `Error uploading to ImgBB: ${imgbbError.message || String(imgbbError)}\n\n` + `When using the Ultra model, ImgBB upload is required and cannot be bypassed.\n\n` + `Response data: ${JSON.stringify(imgbbError.response?.data || {}, null, 2)}` }], isError: true }; } console.log(`Error uploading to ImgBB: ${imgbbError.message || String(imgbbError)}. Falling back to direct base64 upload.`); // Fall back to direct base64 upload for non-Ultra models uploadMethod = "direct"; } } else if (!isUsingUltraModel) { console.log("No ImgBB API key found. Using direct base64 upload."); } // STEP 4: Import Printify SDK let Printify; try { Printify = (await import('printify-sdk-js')).default; } catch (importError: any) { return { content: [{ type: "text", text: `Error importing Printify SDK: ${importError.message || String(importError)}\n\n` + `ImgBB URL: ${imageUrl}` }], isError: true }; } // STEP 5: Create Printify client let printifySDK; try { printifySDK = new Printify({ accessToken: process.env.PRINTIFY_API_KEY || '', shopId: printifyClient ? printifyClient.getCurrentShopId() || undefined : undefined }); // Log client creation console.log(`Created Printify client with shop ID: ${printifyClient?.getCurrentShopId() || 'undefined'}`); } catch (clientError: any) { return { content: [{ type: "text", text: `Error creating Printify client: ${clientError.message || String(clientError)}\n\n` + `ImgBB URL: ${imageUrl}` }], isError: true }; } // STEP 6: Upload the image to Printify let image; try { if (uploadMethod === "imgbb" && imageUrl) { // Upload using the URL from ImgBB image = await printifySDK.uploads.uploadImage({ file_name: finalFileName, url: imageUrl }); console.log(`Successfully uploaded image to Printify using ImgBB URL. Image ID: ${image.id}`); } else { // Direct base64 upload // Convert buffer to base64 for Printify direct upload const base64Data = imageBuffer.toString('base64'); image = await printifySDK.uploads.uploadImage({ file_name: finalFileName, contents: base64Data }); console.log(`Successfully uploaded image to Printify using direct base64. Image ID: ${image.id}`); } } catch (uploadError: any) { return { content: [{ type: "text", text: `Error uploading to Printify: ${uploadError.message || String(uploadError)}\n\n` + `Upload method: ${uploadMethod}${imageUrl ? `\nImgBB URL: ${imageUrl}` : ''}\n\n` + `Response data: ${JSON.stringify(uploadError.response?.data || {}, null, 2)}` }], isError: true }; } // STEP 7: Return success response const response = formatSuccessResponse( 'Image Generated and Uploaded Successfully', { Prompt: prompt, Model: usingModel.split('/')[1], 'Image ID': image.id, 'File Name': image.file_name, Dimensions: `${image.width}x${image.height}`, 'Preview URL': image.preview_url, 'Upload Method': uploadMethod === "imgbb" ? "ImgBB URL" : "Direct base64", ...(imageUrl ? { 'ImgBB URL': imageUrl } : {}), 'Upload Details': uploadDetails }, `You can now use this image ID (${image.id}) when creating a product.\n\n` + `**Example:**\n` + `\`\`\`json\n` + `"print_areas": {\n` + ` "front": { "position": "front", "imageId": "${image.id}" }\n` + `}\n` + `\`\`\`` ) as { content: any[], isError?: boolean }; return response; } );
  • The core handler function that orchestrates image generation using Replicate (via generateImage helper) and uploads the resulting image to Printify, handling model-specific logic and upload methods (direct base64 or via ImgBB for large images).
    async ({ prompt, fileName, model, width, height, aspectRatio, outputFormat, safetyTolerance, seed, numInferenceSteps, guidanceScale, negativePrompt, promptUpsampling, outputQuality, raw, imagePromptStrength }): Promise<{ content: any[], isError?: boolean }> => { // Import the services const { generateImage } = await import('./services/image-generator.js'); const { formatSuccessResponse } = await import('./utils/error-handler.js'); // Check if clients are initialized if (!replicateClient) { return { content: [{ type: "text", text: "Replicate API client is not initialized. The REPLICATE_API_TOKEN environment variable may not be set." }], isError: true }; } if (!printifyClient) { return { content: [{ type: "text", text: "Printify API client is not initialized. The PRINTIFY_API_KEY environment variable may not be set." }], isError: true }; } // Check if we're using the Ultra model which requires ImgBB // Determine which model to use (user-specified or default) const modelToUse = model || replicateClient.getDefaultModel(); // Check if ImgBB API key is set when using Ultra model if (modelToUse.includes('flux-1.1-pro-ultra') && (!process.env.IMGBB_API_KEY || process.env.IMGBB_API_KEY === 'your-imgbb-api-key')) { return { content: [{ type: "text", text: `ERROR: The Flux 1.1 Pro Ultra model generates high-resolution images that are too large for direct base64 upload.\n\n` + `You MUST set the IMGBB_API_KEY environment variable when using this model.\n\n` + `Get a free API key from https://api.imgbb.com/ and add it to your .env file:\n` + `IMGBB_API_KEY=your_api_key_here` }], isError: true }; } // Check if a shop is selected const currentShop = printifyClient.getCurrentShop(); if (!currentShop) { return { content: [{ type: "text", text: "No shop is currently selected. Use the list_shops and switch_shop tools to select a shop." }], isError: true }; } console.log(`Starting generate_and_upload_image with prompt: ${prompt}`); // Get default parameters first const defaults = replicateClient.getAllDefaults(); // STEP 1: Generate the image with Replicate and process with Sharp // Start with defaults, then override with parameters from the tool call const generationResult = await generateImage( replicateClient, prompt, fileName, { // Start with defaults model: defaults.model, width: defaults.width, height: defaults.height, aspectRatio: defaults.aspectRatio, outputFormat: defaults.outputFormat, safetyTolerance: defaults.safetyTolerance, numInferenceSteps: defaults.numInferenceSteps, guidanceScale: defaults.guidanceScale, negativePrompt: defaults.negativePrompt, raw: defaults.raw, promptUpsampling: defaults.promptUpsampling, outputQuality: defaults.outputQuality, // Override with parameters from the tool call (if provided) ...(model !== undefined && { model }), ...(width !== undefined && { width }), ...(height !== undefined && { height }), ...(aspectRatio !== undefined && { aspectRatio }), ...(outputFormat !== undefined && { outputFormat }), ...(safetyTolerance !== undefined && { safetyTolerance }), ...(seed !== undefined && { seed }), ...(numInferenceSteps !== undefined && { numInferenceSteps }), ...(guidanceScale !== undefined && { guidanceScale }), ...(negativePrompt !== undefined && { negativePrompt }), ...(promptUpsampling !== undefined && { promptUpsampling }), ...(outputQuality !== undefined && { outputQuality }), ...(raw !== undefined && { raw }), ...(imagePromptStrength !== undefined && { imagePromptStrength }) } ); // If image generation failed, return the error if (!generationResult.success) { return generationResult.errorResponse as { content: any[], isError: boolean }; } const imageBuffer = generationResult.buffer; const mimeType = generationResult.mimeType; const finalFileName = generationResult.fileName; const usingModel = generationResult.model; // Make sure we have valid image data if (!imageBuffer) { return { content: [{ type: "text", text: "Failed to get valid image data from the image generator." }], isError: true }; } // STEP 2: Upload the processed image to Printify console.log(`Uploading processed image to Printify`); console.log(`Image buffer size: ${imageBuffer.length} bytes`); console.log(`MIME type: ${mimeType}`); console.log(`File name: ${finalFileName}`); // Prepare for upload to Printify const uploadDetails = [ `Preparing to upload image to Printify:`, `- File name: ${finalFileName}`, `- Image buffer size: ${imageBuffer?.length || 0} bytes`, `- MIME type: ${mimeType}`, `- Model used: ${usingModel}` ].join('\n'); // Save the base64 data to a debug file for inspection try { const fs = await import('fs'); const path = await import('path'); // Create a debug directory if it doesn't exist const debugDir = path.join(process.cwd(), 'debug'); if (!fs.existsSync(debugDir)) { fs.mkdirSync(debugDir, { recursive: true }); } // Save the base64 data to a file for debugging const debugFilePath = path.join(debugDir, `debug_${Date.now()}_${finalFileName}`); // Save buffer directly to debug file if (imageBuffer) { fs.writeFileSync(debugFilePath, imageBuffer); console.log(`Saved image data to debug file: ${debugFilePath}`); console.log(`Debug file size: ${imageBuffer.length} bytes`); } else { console.error('No image data to save for debugging'); } } catch (debugError) { console.error('Error saving debug file:', debugError); } // Validate input data if (!imageBuffer) { return { content: [{ type: "text", text: "Error: No image data available for upload" }], isError: true }; } if (!finalFileName) { return { content: [{ type: "text", text: "Error: No filename available for upload" }], isError: true }; } // STEP 1: Import required modules let axios; let FormData; try { axios = (await import('axios')).default; FormData = (await import('form-data')).default; } catch (importError: any) { return { content: [{ type: "text", text: `Error importing required modules: ${importError.message || String(importError)}` }], isError: true }; } // STEP 2: Prepare image for upload (either via ImgBB or direct base64) let imageUrl; let uploadMethod = "direct"; // Check if we're using the Ultra model const isUsingUltraModel = usingModel.includes('flux-1.1-pro-ultra'); // Check if ImgBB API key is set const imgbbApiKey = process.env.IMGBB_API_KEY; if (imgbbApiKey && imgbbApiKey !== 'your-imgbb-api-key') { // If ImgBB API key is set, use ImgBB to get a URL try { // Create form data for ImgBB const formData = new FormData(); // Convert buffer to base64 for ImgBB upload const base64Data = imageBuffer.toString('base64'); formData.append('image', base64Data); // Upload to ImgBB with the key as a query parameter const imgbbResponse = await axios.post( `https://api.imgbb.com/1/upload?key=${imgbbApiKey}`, formData ); // Get the image URL from ImgBB response imageUrl = imgbbResponse.data.data.url; uploadMethod = "imgbb"; // Log success console.log(`Successfully uploaded image to ImgBB. URL: ${imageUrl}`); } catch (imgbbError: any) { // Only fall back to direct upload if not using Ultra model if (isUsingUltraModel) { return { content: [{ type: "text", text: `Error uploading to ImgBB: ${imgbbError.message || String(imgbbError)}\n\n` + `When using the Ultra model, ImgBB upload is required and cannot be bypassed.\n\n` + `Response data: ${JSON.stringify(imgbbError.response?.data || {}, null, 2)}` }], isError: true }; } console.log(`Error uploading to ImgBB: ${imgbbError.message || String(imgbbError)}. Falling back to direct base64 upload.`); // Fall back to direct base64 upload for non-Ultra models uploadMethod = "direct"; } } else if (!isUsingUltraModel) { console.log("No ImgBB API key found. Using direct base64 upload."); } // STEP 4: Import Printify SDK let Printify; try { Printify = (await import('printify-sdk-js')).default; } catch (importError: any) { return { content: [{ type: "text", text: `Error importing Printify SDK: ${importError.message || String(importError)}\n\n` + `ImgBB URL: ${imageUrl}` }], isError: true }; } // STEP 5: Create Printify client let printifySDK; try { printifySDK = new Printify({ accessToken: process.env.PRINTIFY_API_KEY || '', shopId: printifyClient ? printifyClient.getCurrentShopId() || undefined : undefined }); // Log client creation console.log(`Created Printify client with shop ID: ${printifyClient?.getCurrentShopId() || 'undefined'}`); } catch (clientError: any) { return { content: [{ type: "text", text: `Error creating Printify client: ${clientError.message || String(clientError)}\n\n` + `ImgBB URL: ${imageUrl}` }], isError: true }; } // STEP 6: Upload the image to Printify let image; try { if (uploadMethod === "imgbb" && imageUrl) { // Upload using the URL from ImgBB image = await printifySDK.uploads.uploadImage({ file_name: finalFileName, url: imageUrl }); console.log(`Successfully uploaded image to Printify using ImgBB URL. Image ID: ${image.id}`); } else { // Direct base64 upload // Convert buffer to base64 for Printify direct upload const base64Data = imageBuffer.toString('base64'); image = await printifySDK.uploads.uploadImage({ file_name: finalFileName, contents: base64Data }); console.log(`Successfully uploaded image to Printify using direct base64. Image ID: ${image.id}`); } } catch (uploadError: any) { return { content: [{ type: "text", text: `Error uploading to Printify: ${uploadError.message || String(uploadError)}\n\n` + `Upload method: ${uploadMethod}${imageUrl ? `\nImgBB URL: ${imageUrl}` : ''}\n\n` + `Response data: ${JSON.stringify(uploadError.response?.data || {}, null, 2)}` }], isError: true }; } // STEP 7: Return success response const response = formatSuccessResponse( 'Image Generated and Uploaded Successfully', { Prompt: prompt, Model: usingModel.split('/')[1], 'Image ID': image.id, 'File Name': image.file_name, Dimensions: `${image.width}x${image.height}`, 'Preview URL': image.preview_url, 'Upload Method': uploadMethod === "imgbb" ? "ImgBB URL" : "Direct base64", ...(imageUrl ? { 'ImgBB URL': imageUrl } : {}), 'Upload Details': uploadDetails }, `You can now use this image ID (${image.id}) when creating a product.\n\n` + `**Example:**\n` + `\`\`\`json\n` + `"print_areas": {\n` + ` "front": { "position": "front", "imageId": "${image.id}" }\n` + `}\n` + `\`\`\`` ) as { content: any[], isError?: boolean }; return response; }
  • Zod input schema defining all parameters for image generation and upload, including prompt, fileName, model overrides, dimensions, format, and model-specific options.
    { prompt: z.string().describe("Text prompt for image generation"), fileName: z.string().describe("File name for the uploaded image"), // Optional model override model: z.string().optional() .describe("Optional: Override the default model. Use get_defaults to see available models"), // Common parameters for both models width: z.number().optional().default(1024).describe("Image width in pixels"), height: z.number().optional().default(1024).describe("Image height in pixels"), aspectRatio: z.string().optional().describe("Aspect ratio (e.g., '16:9', '4:3', '1:1'). If provided, overrides width and height"), outputFormat: z.enum(["jpeg", "png", "webp"]).optional().default("png").describe("Output format"), safetyTolerance: z.number().optional().default(2).describe("Safety tolerance (0-6)"), seed: z.number().optional().describe("Random seed for reproducible generation"), numInferenceSteps: z.number().optional().default(25).describe("Number of inference steps"), guidanceScale: z.number().optional().default(7.5).describe("Guidance scale"), negativePrompt: z.string().optional().default("low quality, bad quality, sketches").describe("Negative prompt"), // Flux 1.1 Pro specific parameters promptUpsampling: z.boolean().optional() .describe("Enable prompt upsampling (Flux 1.1 Pro only)"), outputQuality: z.number().optional() .describe("Output quality 1-100 (Flux 1.1 Pro only)"), // Flux 1.1 Pro Ultra specific parameters raw: z.boolean().optional() .describe("Generate less processed, more natural-looking images (Flux 1.1 Pro Ultra only)"), imagePromptStrength: z.number().optional() .describe("Image prompt strength 0-1 (Flux 1.1 Pro Ultra only)") },
  • Helper function that generates image buffer using ReplicateClient and Sharp image processing, called by the main handler.
    export async function generateImage( replicateClient: ReplicateClient, prompt: string, fileName: string, options: any = {} ) { // No need to track files anymore since we're keeping everything in memory try { // Prepare options with proper naming for the API const modelOptions: any = {}; // Set aspect ratio or dimensions if (options.aspectRatio) { modelOptions.aspectRatio = options.aspectRatio; } else { // If no aspect ratio is provided, use width and height // These will be overridden by the defaults in the DefaultsManager if not provided modelOptions.width = options.width || 1024; modelOptions.height = options.height || 1024; } // Add common parameters if (options.numInferenceSteps) modelOptions.numInferenceSteps = options.numInferenceSteps; if (options.guidanceScale) modelOptions.guidanceScale = options.guidanceScale; if (options.negativePrompt) modelOptions.negativePrompt = options.negativePrompt; if (options.seed !== undefined) modelOptions.seed = options.seed; // Always set outputFormat, defaulting to png unless explicitly specified modelOptions.outputFormat = options.outputFormat || "png"; if (options.safetyTolerance !== undefined) modelOptions.safetyTolerance = options.safetyTolerance; // Add model-specific parameters if provided if (options.promptUpsampling !== undefined) modelOptions.promptUpsampling = options.promptUpsampling; if (options.outputQuality !== undefined) modelOptions.outputQuality = options.outputQuality; if (options.raw !== undefined) modelOptions.raw = options.raw; if (options.imagePromptStrength !== undefined) modelOptions.imagePromptStrength = options.imagePromptStrength; // Add model override if provided if (options.model) modelOptions.model = options.model; // Get the current default model for informational purposes const defaultModel = replicateClient.getDefaultModel(); const usingModel = options.model || defaultModel; console.log(`Using model: ${usingModel} (${options.model ? 'override' : 'default'})`); console.log(`Prompt: ${prompt}`); // STEP 1: Generate the image with Replicate console.log('Generating image with Replicate...'); const imageBuffer = await replicateClient.generateImage(prompt, modelOptions); console.log(`Image generated successfully, buffer size: ${imageBuffer.length} bytes`); // STEP 2: Process the image with Sharp console.log('Processing image with Sharp...'); // Get the output format from options (already defaulted to png earlier) const outputFormat = modelOptions.outputFormat; let mimeType: string; if (outputFormat === 'jpeg' || outputFormat === 'jpg') { mimeType = 'image/jpeg'; } else if (outputFormat === 'webp') { mimeType = 'image/webp'; } else { // Default to PNG mimeType = 'image/png'; } // Process with Sharp and get buffer directly let sharpInstance = sharp(imageBuffer); // Apply format-specific options if (outputFormat === 'png') { sharpInstance = sharpInstance.png({ quality: 100 }); } else if (outputFormat === 'jpeg' || outputFormat === 'jpg') { sharpInstance = sharpInstance.jpeg({ quality: 100 }); } else if (outputFormat === 'webp') { sharpInstance = sharpInstance.webp({ quality: 100 }); } // Get the processed image as a buffer const processedBuffer = await sharpInstance.toBuffer(); console.log(`Image processed successfully, buffer size: ${processedBuffer.length} bytes`); // Determine the final filename with extension const fileExtension = outputFormat === 'jpeg' ? 'jpg' : outputFormat; const finalFileName = fileName.endsWith(`.${fileExtension}`) ? fileName : `${fileName}.${fileExtension}`; // No need to clean up files since we're keeping everything in memory // Get dimensions from the Sharp metadata const metadata = await sharpInstance.metadata(); const dimensions = `${metadata.width}x${metadata.height}`; return { success: true, buffer: processedBuffer, mimeType, fileName: finalFileName, model: usingModel, dimensions }; } catch (error: any) { console.error('Error generating or processing image:', error); // No need to clean up files since we're keeping everything in memory // Get the current default model for informational purposes const defaultModel = replicateClient.getDefaultModel(); const usingModel = options.model || defaultModel; // Determine which step failed const errorStep = error.message.includes('Sharp') ? 'Image Processing' : 'Image Generation'; return { success: false, error, errorResponse: formatErrorResponse( error, errorStep, { Prompt: prompt, Model: usingModel.split('/')[1], Step: errorStep }, [ 'Check that your REPLICATE_API_TOKEN is valid', 'Try a different model using set-model', 'Try a more descriptive prompt', 'Try a different aspect ratio', ...(errorStep === 'Image Processing' ? [ 'Make sure Sharp is properly installed' ] : []) ] ) }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TSavo/printify-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server