import { NextRequest, NextResponse } from "next/server"; import ZAI from "z-ai-web-dev-sdk"; import { db } from "@/lib/db"; import fs from "fs/promises"; import path from "path"; const DOWNLOAD_DIR = path.join(process.cwd(), "download", "images"); // Asegurar directorio existe async function ensureDir() { try { await fs.mkdir(DOWNLOAD_DIR, { recursive: true }); } catch { // ya existe } } // 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; if (!prompt && !optimizedPrompt) { return NextResponse.json( { success: false, error: "Se requiere un prompt" }, { status: 400 } ); } await ensureDir(); // Usar el prompt optimizado si está disponible let finalPrompt = optimizedPrompt || prompt; // Aplicar filtros de censura según plataforma finalPrompt = applyCensorFilter(finalPrompt, platform); // Añadir estilo si se especifica 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]}`; } } // Añadir referencia de personaje si existe if (character) { finalPrompt = `${finalPrompt}, character: ${character}`; } console.log("🖼️ Generando imagen con prompt:", finalPrompt.substring(0, 100) + "..."); // Crear registro en BD si se solicita let contentRecord = null; if (saveToDb) { contentRecord = await db.content.create({ data: { type: "image", title: prompt.substring(0, 50), description: prompt, prompt: prompt, optimizedPrompt: finalPrompt, platform: platform, status: "processing", projectId: projectId || null, } }); } try { // Generar imagen con z-ai-web-dev-sdk 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.data[0]?.base64; if (!imageBase64) { throw new Error("No se recibió imagen del generador"); } // Guardar imagen en disco const filename = `image_${Date.now()}.png`; const filepath = path.join(DOWNLOAD_DIR, filename); const buffer = Buffer.from(imageBase64, "base64"); await fs.writeFile(filepath, buffer); // Actualizar registro en BD if (contentRecord) { await db.content.update({ where: { id: contentRecord.id }, data: { status: "completed", filePath: `/download/images/${filename}`, thumbnail: `/download/images/${filename}`, } }); } // Crear tarea de agente await db.agentTask.create({ data: { type: "generate_image", status: "completed", input: prompt, output: `Imagen generada: ${filename}`, completedAt: new Date(), } }); return NextResponse.json({ success: true, image: { id: contentRecord?.id, filename, url: `/download/images/${filename}`, base64: imageBase64.substring(0, 50) + "...", // Preview del base64 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 generadas 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 } ); } }