sofia-cloud / src /app /api /generate /image /route.ts
Gmagl
Add Sofia Cloud complete files
333c51a
Raw
History Blame
6.61 kB
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 }
);
}
}