diff --git a/modules/rsocials/lib/image-gen.ts b/modules/rsocials/lib/image-gen.ts index 7a2ae82..d5b1c1c 100644 --- a/modules/rsocials/lib/image-gen.ts +++ b/modules/rsocials/lib/image-gen.ts @@ -21,22 +21,29 @@ export async function generateImageFromPrompt(prompt: string): Promise "unknown"); + console.error(`[image-gen] fal.ai error (${falRes.status}):`, errText); return null; } diff --git a/modules/rsocials/mod.ts b/modules/rsocials/mod.ts index 9d5eb55..1410007 100644 --- a/modules/rsocials/mod.ts +++ b/modules/rsocials/mod.ts @@ -187,14 +187,26 @@ routes.post("/api/threads/:id/image", async (c) => { if (!process.env.FAL_KEY) return c.json({ error: "FAL_KEY not configured" }, 503); - const summary = thread.tweets.slice(0, 3).join(" ").substring(0, 200); - const prompt = `Social media thread preview card about: ${summary}. Dark themed, modern, minimal style with abstract shapes.`; + const summary = thread.tweets.slice(0, 3).join(" ").substring(0, 300); + const prompt = `Create a bold, visually striking infographic-style image that captures the core message of this social media thread: "${summary}". Style: dark background (#0f172a to #1e293b gradient), bold typography with key phrases as large text overlays, iconic symbols and geometric shapes that represent the concepts, data visualization elements where relevant, modern flat illustration style with vibrant accent colors (electric blue, purple, teal). The image should work as a standalone visual summary — memetic, shareable, and instantly communicating the thread's main insight. No lorem ipsum or placeholder text.`; - const cdnUrl = await generateImageFromPrompt(prompt); + let cdnUrl: string | null; + try { + cdnUrl = await generateImageFromPrompt(prompt); + } catch (e: any) { + console.error("[rSocials] Thread image generation error:", e.message); + return c.json({ error: "Image generation failed: " + (e.message || "unknown error") }, 502); + } if (!cdnUrl) return c.json({ error: "Image generation failed" }, 502); const filename = `thread-${id}.png`; - const imageUrl = await downloadAndSaveImage(cdnUrl, filename); + let imageUrl: string | null; + try { + imageUrl = await downloadAndSaveImage(cdnUrl, filename); + } catch (e: any) { + console.error("[rSocials] Image download error:", e.message); + return c.json({ error: "Failed to download image: " + (e.message || "unknown error") }, 502); + } if (!imageUrl) return c.json({ error: "Failed to download image" }, 502); // Update Automerge doc with image URL @@ -302,10 +314,16 @@ routes.post("/api/threads/:id/tweet/:index/image", async (c) => { if (!process.env.FAL_KEY) return c.json({ error: "FAL_KEY not configured" }, 503); - const tweetText = thread.tweets[tweetIndex].substring(0, 200); - const prompt = `Social media post image about: ${tweetText}. Dark themed, modern, minimal style with abstract shapes.`; + const tweetText = thread.tweets[tweetIndex].substring(0, 300); + const prompt = `Create a high-impact memetic infographic for this social media post: "${tweetText}". Style: dark background (#0f172a), bold statement typography with the key insight as large readable text, iconic flat-design symbols representing the core concept, subtle data-viz or diagram elements if the content references numbers/processes/systems, vibrant accent colors (electric blue #38bdf8, violet #a78bfa, teal #2dd4bf) on dark. The image should be instantly understandable, shareable, and visually distill the tweet's message into a single powerful graphic. No lorem ipsum or placeholder text. Landscape 4:3 ratio.`; - const cdnUrl = await generateImageFromPrompt(prompt); + let cdnUrl: string | null; + try { + cdnUrl = await generateImageFromPrompt(prompt); + } catch (e: any) { + console.error("[rSocials] Tweet image generation error:", e.message); + return c.json({ error: "Image generation failed: " + (e.message || "unknown error") }, 502); + } if (!cdnUrl) return c.json({ error: "Image generation failed" }, 502); const filename = `thread-${id}-tweet-${index}.png`; @@ -313,7 +331,13 @@ routes.post("/api/threads/:id/tweet/:index/image", async (c) => { const oldUrl = thread.tweetImages?.[index]; if (oldUrl) await deleteOldImage(oldUrl, filename); - const imageUrl = await downloadAndSaveImage(cdnUrl, filename); + let imageUrl: string | null; + try { + imageUrl = await downloadAndSaveImage(cdnUrl, filename); + } catch (e: any) { + console.error("[rSocials] Image download error:", e.message); + return c.json({ error: "Failed to download image: " + (e.message || "unknown error") }, 502); + } if (!imageUrl) return c.json({ error: "Failed to download image" }, 502); const docId = socialsDocId(space);