import { NextRequest, NextResponse } from "next/server"; import ZAI from "z-ai-web-dev-sdk"; import { db } from "@/lib/db"; import type { Content } from "@prisma/client"; // Reglas de censura por plataforma const CENSOR_RULES: Record = { youtube: [ "no nudity", "no sexual content", "no graphic violence", "family friendly" ], tiktok: [ "no nudity", "no sexual suggestiveness", "no graphic violence", "no self-harm content", "age appropriate" ], instagram: [ "no nudity", "no graphic violence", "artistic content acceptable with moderation", "no self-harm imagery" ], twitter: [ "content warning if sensitive", "no illegal content" ], general: [ "safe for work", "no explicit content" ] }; // Aplicar filtros de censura al prompt function applyCensorFilter(prompt: string, platform: string): string { const rules = CENSOR_RULES[platform] || CENSOR_RULES.general; const censorAdditions = rules.map(rule => `(${rule})`).join(", "); return `${prompt}, ${censorAdditions}`; } export async function POST(request: NextRequest) { try { const body = await request.json(); const { prompt, optimizedPrompt, platform = "general", character, style = "realistic", size = "1024x1024", saveToDb = true, projectId } = body; const basePrompt: string | undefined = optimizedPrompt || prompt; if (!basePrompt) { return NextResponse.json( { success: false, error: "Se requiere un prompt" }, { status: 400 } ); } let finalPrompt = applyCensorFilter(basePrompt, platform); // Estilos if (style && style !== "realistic") { const styleAdditions: Record = { anime: "anime style, manga aesthetic, vibrant colors, cel shading", realistic: "photorealistic, highly detailed, 8K, professional photography", artistic: "digital art, artistic style, creative interpretation, masterpiece", "oil-painting": "oil painting style, classical art, brush strokes, museum quality", sketch: "pencil sketch, hand drawn, artistic lines, detailed shading", "3d": "3D render, octane render, cinema 4D, volumetric lighting" }; if (styleAdditions[style]) { finalPrompt = `${finalPrompt}, ${styleAdditions[style]}`; } } // Personaje if (character) { finalPrompt = `${finalPrompt}, character: ${character}`; } console.log( "🖼️ Generando imagen:", finalPrompt.substring(0, 100) + "..." ); // ✅ Crear registro en BD let contentRecord: Content | null = null; if (saveToDb) { contentRecord = await db.content.create({ data: { type: "image", title: basePrompt.substring(0, 50), description: basePrompt, prompt: basePrompt, optimizedPrompt: finalPrompt, platform, status: "processing", projectId: projectId || null } }); } try { const zai = await ZAI.create(); const response = await zai.images.generations.create({ prompt: finalPrompt, size: size as | "1024x1024" | "768x1344" | "864x1152" | "1344x768" | "1152x864" | "1440x720" | "720x1440" }); const imageBase64 = (response as any)?.data?.[0]?.base64; if (!imageBase64) { throw new Error("No se recibió imagen del generador"); } const filename = `image_${Date.now()}.png`; const imageUrl = `/download/images/${filename}`; // ✅ actualizar BD if (contentRecord) { await db.content.update({ where: { id: contentRecord.id }, data: { status: "completed", filePath: imageUrl, thumbnail: imageUrl, metadata: JSON.stringify({ base64: imageBase64 }) } }); } // ✅ tarea agente (no romper si falla) try { await db.agentTask.create({ data: { type: "generate_image", status: "completed", input: basePrompt, output: `Imagen generada: ${filename}`, completedAt: new Date() } }); } catch (e) { console.warn("agentTask warning:", e); } return NextResponse.json({ success: true, image: { id: contentRecord?.id ?? null, filename, url: imageUrl, base64: imageBase64, prompt: finalPrompt, platform, size } }); } catch (genError) { console.error("Error generando imagen:", genError); if (contentRecord) { await db.content.update({ where: { id: contentRecord.id }, data: { status: "failed", metadata: JSON.stringify({ error: String(genError) }) } }); } return NextResponse.json( { success: false, error: "Error al generar imagen: " + String(genError) }, { status: 500 } ); } } catch (error) { console.error("Error en generate image:", error); return NextResponse.json( { success: false, error: "Error interno del servidor" }, { status: 500 } ); } } // ✅ LISTAR IMÁGENES export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url); const platform = searchParams.get("platform"); const limit = parseInt(searchParams.get("limit") || "20"); const where: Record = { type: "image" }; if (platform) where.platform = platform; const images = await db.content.findMany({ where, orderBy: { createdAt: "desc" }, take: limit }); return NextResponse.json({ success: true, images, total: images.length }); } catch (error) { console.error("Error listing images:", error); return NextResponse.json( { success: false, error: "Error al listar imágenes" }, { status: 500 } ); } }