Spaces:
Build error
Build error
| 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<string, string[]> = { | |
| 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<string, string> = { | |
| 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<string, unknown> = { 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 } | |
| ); | |
| } | |
| } | |