import { NextRequest, NextResponse } from "next/server"; import { db } from "@/lib/db"; import ZAI from "z-ai-web-dev-sdk"; import { generateSocialPost } from "@/lib/content-generator"; export const maxDuration = 60; // 1 min timeout to allow generation to kick off export async function POST(request: NextRequest) { // Basic Security: Protect this route from public abuse via a secret key from n8n const authHeader = request.headers.get("authorization"); const secret = process.env.CRON_SECRET || "default_cron_secret_replace_me"; // Set CRON_SECRET in Vercel/VPS if (authHeader !== `Bearer ${secret}`) { return NextResponse.json({ success: false, error: "Unauthorized" }, { status: 401 }); } try { const character = await db.character.findFirst({ where: { isActive: true } }); if (!character) return NextResponse.json({ success: false, error: "No active character" }, { status: 400 }); // Generate the idea for today's episode const zai = await ZAI.create(); const storyPrompt = `Actúa como ${character.name}. Biografía: ${character.shortBio}. Genera una pequeña actualización de estado sobre tu día de hoy. Debe ser natural, interesante, como si fuera un diario personal breve. Max 1-2 párrafos.`; const completion = await zai.chat.completions.create({ messages: [{ role: "user", content: storyPrompt }] }); const storyText = completion.choices[0]?.message?.content || "Hoy fue un día normal."; // 1. Create a Post (Text) const socialPost = await generateSocialPost({ character, platform: "instagram", topic: storyText }); const post = await db.post.create({ data: { caption: socialPost.caption, hashtags: socialPost.hashtags ? socialPost.hashtags.join(",") : null, type: "text", status: "draft" } }); // 2. Generate a corresponding Daily Image for Instagram const imgPrompt = `${character.styleDescription}. ${storyText} selfie, photorealistic.`; const contentRecord = await db.content.create({ data: { type: "image", title: `Daily Gen: ${new Date().toISOString()}`, description: storyText, prompt: imgPrompt, optimizedPrompt: imgPrompt, platform: "instagram", characterId: character.id, status: "processing" } }); // Fire and Forget Image Generation (Run in background so Vercel doesn't timeout the webhook) zai.images.generations.create({ prompt: imgPrompt, size: "1024x1024" }) .then(async (res) => { const base64 = res.data?.[0]?.base64; if (base64) { await db.content.update({ where: { id: contentRecord.id }, data: { status: "completed", filePath: "base64-generated" } // In a real storage scenario, upload to S3/Cloudinary here }); // Potentially notify n8n here that the generation FINISHED so it can grab it const webhookUrl = process.env.N8N_WEBHOOK_URL; if (webhookUrl) { fetch(webhookUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ event: "daily_content_ready", contentId: contentRecord.id }) }).catch(e => console.error("n8n notify error", e)); } } }).catch(async (e) => { console.error("Cron image gen error:", e); await db.content.update({ where: { id: contentRecord.id }, data: { status: "failed" } }); }); return NextResponse.json({ success: true, message: "Daily generation started", story: storyText, postId: post.id, contentId: contentRecord.id }); } catch (error) { console.error("Cron Error:", error); return NextResponse.json({ success: false, error: "Server Error" }, { status: 500 }); } }