File size: 6,170 Bytes
333c51a
 
 
625d2ed
333c51a
625d2ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333c51a
 
625d2ed
 
 
 
 
 
 
333c51a
 
 
 
625d2ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333c51a
 
625d2ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333c51a
625d2ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333c51a
 
 
625d2ed
333c51a
 
625d2ed
 
 
 
 
 
 
 
333c51a
 
625d2ed
333c51a
625d2ed
 
 
333c51a
625d2ed
 
333c51a
625d2ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333c51a
625d2ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333c51a
 
625d2ed
 
 
 
 
333c51a
 
 
625d2ed
333c51a
 
 
 
 
625d2ed
333c51a
 
625d2ed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333c51a
625d2ed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
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<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;

    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<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]}`;
      }
    }

    // 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<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 }
    );
  }
}