UNPKG

@snahrup/notion-hero-image-mcp

Version:

AI-powered animated hero banner generator for Notion pages. Integrates DALL-E 3, Google Veo 3, Cloudinary CDN, and Notion API.

102 lines 4.67 kB
import OpenAI from 'openai'; import fetch from 'node-fetch'; import { writeFileSync } from 'fs'; import { join } from 'path'; import { tmpdir } from 'os'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); const definition = { name: 'generate_image', description: 'Generate a hero still image using DALL-E 3 with detailed Veo animation script', inputSchema: { type: 'object', properties: { prompt: { type: 'string', description: 'Visual description for the hero image' }, style: { type: 'string', description: 'Art style (cinematic, illustration, photorealistic)', default: 'cinematic' } }, required: ['prompt'] } }; const generateAnimationBeats = (prompt, style) => { // Generate timestamped animation beats for 8-second Veo video const beats = [ { timeRange: "00:00 – 00:15", description: "Ambient low-light, subtle atmospheric introduction" }, { timeRange: "00:16 – 02:00", description: "Primary elements begin gentle movement, energy builds" }, { timeRange: "02:01 – 04:00", description: "Peak animation moment, focal point pulses or glows" }, { timeRange: "04:01 – 06:00", description: "Secondary elements respond, energy flows outward" }, { timeRange: "06:01 – 07:15", description: "Movement gradually settles, returning to rest state" }, { timeRange: "07:16 – 08:00", description: "Final frames match opening for seamless loop" } ]; return beats; }; const handler = { 'tools/call': async (request) => { if (request.params.name !== 'generate_image') return null; const { prompt, style = 'cinematic' } = request.params.arguments; // Generate detailed animation script with GPT-4 const scriptResponse = await openai.chat.completions.create({ model: 'gpt-4-turbo-preview', messages: [{ role: 'system', content: `Create a detailed 8-second animation plan for a Notion hero banner. Format your response as JSON with these fields: - title: Creative title for the animation - scene_description: Detailed static scene description (no movement) - animation_beats: Array of {timeRange, description} for 6 key moments - style_tags: Comma-separated style descriptors Focus on subtle, elegant movement suitable for a professional banner.` }, { role: 'user', content: `Create animation plan for: "${prompt}". Visual style: ${style}` }], response_format: { type: "json_object" }, max_tokens: 500 }); const animationPlan = JSON.parse(scriptResponse.choices[0].message.content || '{}'); // Generate image with DALL-E 3 const imageResponse = await openai.images.generate({ model: 'dall-e-3', prompt: `${style} style: ${prompt}. High quality, 16:9 aspect ratio, suitable for animation. ${animationPlan.scene_description || ''}`, size: '1792x1024', quality: 'hd', n: 1 }); if (!imageResponse.data || !imageResponse.data[0]?.url) { throw new Error('Failed to generate image'); } const imageUrl = imageResponse.data[0].url; // Download image locally for processing const response = await fetch(imageUrl); const buffer = await response.buffer(); const imagePath = join(tmpdir(), `hero-${Date.now()}.png`); writeFileSync(imagePath, buffer); // Prepare animation beats if not properly generated const animationBeats = animationPlan.animation_beats || generateAnimationBeats(prompt, style); return { content: [{ type: 'text', text: JSON.stringify({ image_url: imageUrl, local_path: imagePath, title: animationPlan.title || `${style} Banner Animation`, scene_description: animationPlan.scene_description || prompt, animation_beats: animationBeats, style_tags: animationPlan.style_tags || `${style}, banner-friendly, seamless-loop, subtle-motion`, prompt: prompt, style: style }) }] }; } }; export default { definition, handler }; //# sourceMappingURL=generate-image.js.map