Spaces:
Build error
Build error
Gmagl commited on
Commit ·
acbcb20
1
Parent(s): 0119dec
Fix: All API routes corrected for HF Spaces
Browse files- src/app/api/automation/route.ts +25 -78
- src/app/api/content/route.ts +12 -60
- src/app/api/generate/image/route.ts +44 -195
- src/app/api/generate/video/route.ts +35 -182
src/app/api/automation/route.ts
CHANGED
|
@@ -2,13 +2,9 @@ import { NextRequest, NextResponse } from "next/server";
|
|
| 2 |
import { db } from "@/lib/db";
|
| 3 |
import ZAI from "z-ai-web-dev-sdk";
|
| 4 |
|
| 5 |
-
const AUTOMATION_TYPES = {
|
| 6 |
content_generation: { name: "Generacion de Contenido", triggers: ["schedule", "manual"] },
|
| 7 |
posting: { name: "Publicacion Automatica", triggers: ["schedule", "manual"] },
|
| 8 |
-
engagement: { name: "Engagement Automatico", triggers: ["schedule", "manual"] },
|
| 9 |
-
monetization: { name: "Optimizacion de Monetizacion", triggers: ["schedule", "manual"] },
|
| 10 |
-
storytelling: { name: "Storytelling Continuo", triggers: ["schedule", "manual"] },
|
| 11 |
-
cross_posting: { name: "Cross-Posting", triggers: ["schedule", "manual"] },
|
| 12 |
trend_tracking: { name: "Seguimiento de Tendencias", triggers: ["schedule", "manual"] }
|
| 13 |
};
|
| 14 |
|
|
@@ -16,111 +12,65 @@ export async function GET(request: NextRequest) {
|
|
| 16 |
try {
|
| 17 |
const { searchParams } = new URL(request.url);
|
| 18 |
const type = searchParams.get("type");
|
| 19 |
-
const isActive = searchParams.get("isActive");
|
| 20 |
-
|
| 21 |
const where: Record<string, unknown> = {};
|
| 22 |
if (type) where.type = type;
|
| 23 |
-
if (isActive !== null) where.isActive = isActive === "true";
|
| 24 |
-
|
| 25 |
-
const automations = await db.automation.findMany({
|
| 26 |
-
where,
|
| 27 |
-
orderBy: { createdAt: "desc" }
|
| 28 |
-
});
|
| 29 |
-
|
| 30 |
-
const recentLogs = await db.automationLog.findMany({
|
| 31 |
-
orderBy: { createdAt: "desc" },
|
| 32 |
-
take: 20,
|
| 33 |
-
});
|
| 34 |
|
|
|
|
| 35 |
const stats = {
|
| 36 |
total: await db.automation.count(),
|
| 37 |
-
active: await db.automation.count({ where: { isActive: true } })
|
| 38 |
-
runsToday: await db.automationLog.count({
|
| 39 |
-
where: { createdAt: { gte: new Date(new Date().setHours(0, 0, 0, 0)) } }
|
| 40 |
-
})
|
| 41 |
};
|
| 42 |
|
| 43 |
-
return NextResponse.json({ success: true, automations, automationTypes: AUTOMATION_TYPES,
|
| 44 |
-
} catch
|
| 45 |
-
|
| 46 |
-
return NextResponse.json({ success: false, error: "Error al obtener automatizaciones" }, { status: 500 });
|
| 47 |
}
|
| 48 |
}
|
| 49 |
|
| 50 |
export async function POST(request: NextRequest) {
|
| 51 |
try {
|
| 52 |
const body = await request.json();
|
| 53 |
-
const { name,
|
| 54 |
|
| 55 |
-
if (!name || !type || !
|
| 56 |
-
return NextResponse.json({ success: false, error: "Faltan campos
|
| 57 |
}
|
| 58 |
|
| 59 |
const automation = await db.automation.create({
|
| 60 |
-
data: {
|
| 61 |
-
name,
|
| 62 |
-
description: description || null,
|
| 63 |
-
type,
|
| 64 |
-
trigger,
|
| 65 |
-
triggerConfig: triggerConfig ? JSON.stringify(triggerConfig) : null,
|
| 66 |
-
actions: JSON.stringify(actions),
|
| 67 |
-
isActive: true,
|
| 68 |
-
}
|
| 69 |
});
|
| 70 |
|
| 71 |
return NextResponse.json({ success: true, automation });
|
| 72 |
-
} catch
|
| 73 |
-
|
| 74 |
-
return NextResponse.json({ success: false, error: "Error al crear automatizacion" }, { status: 500 });
|
| 75 |
}
|
| 76 |
}
|
| 77 |
|
| 78 |
export async function PUT(request: NextRequest) {
|
| 79 |
try {
|
| 80 |
const body = await request.json();
|
| 81 |
-
const { id,
|
| 82 |
|
| 83 |
-
if (!id) {
|
| 84 |
-
return NextResponse.json({ success: false, error: "ID requerido" }, { status: 400 });
|
| 85 |
-
}
|
| 86 |
|
| 87 |
if (action === "execute") {
|
| 88 |
const automation = await db.automation.findUnique({ where: { id } });
|
| 89 |
if (!automation) return NextResponse.json({ success: false, error: "No encontrada" }, { status: 404 });
|
| 90 |
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
if (act.type === "generate_content") {
|
| 96 |
-
await zai.chat.completions.create({
|
| 97 |
-
messages: [{ role: "user", content: String(act.prompt) }]
|
| 98 |
-
});
|
| 99 |
-
}
|
| 100 |
-
}
|
| 101 |
-
|
| 102 |
-
await db.automation.update({
|
| 103 |
-
where: { id },
|
| 104 |
-
data: { lastRunAt: new Date(), runCount: { increment: 1 } }
|
| 105 |
-
});
|
| 106 |
-
|
| 107 |
-
await db.automationLog.create({
|
| 108 |
-
data: { automationId: id, status: "success", duration: 100 }
|
| 109 |
-
});
|
| 110 |
|
|
|
|
|
|
|
| 111 |
return NextResponse.json({ success: true });
|
| 112 |
}
|
| 113 |
|
| 114 |
-
const
|
| 115 |
-
if (isActive !== undefined) updateData.isActive = isActive;
|
| 116 |
-
if (triggerConfig) updateData.triggerConfig = JSON.stringify(triggerConfig);
|
| 117 |
-
if (actions) updateData.actions = JSON.stringify(actions);
|
| 118 |
-
|
| 119 |
-
const automation = await db.automation.update({ where: { id }, data: updateData });
|
| 120 |
return NextResponse.json({ success: true, automation });
|
| 121 |
-
} catch
|
| 122 |
-
|
| 123 |
-
return NextResponse.json({ success: false, error: "Error al actualizar" }, { status: 500 });
|
| 124 |
}
|
| 125 |
}
|
| 126 |
|
|
@@ -128,15 +78,12 @@ export async function DELETE(request: NextRequest) {
|
|
| 128 |
try {
|
| 129 |
const { searchParams } = new URL(request.url);
|
| 130 |
const id = searchParams.get("id");
|
| 131 |
-
|
| 132 |
if (!id) return NextResponse.json({ success: false, error: "ID requerido" }, { status: 400 });
|
| 133 |
|
| 134 |
await db.automationLog.deleteMany({ where: { automationId: id } });
|
| 135 |
await db.automation.delete({ where: { id } });
|
| 136 |
-
|
| 137 |
return NextResponse.json({ success: true });
|
| 138 |
-
} catch
|
| 139 |
-
|
| 140 |
-
return NextResponse.json({ success: false, error: "Error al eliminar" }, { status: 500 });
|
| 141 |
}
|
| 142 |
}
|
|
|
|
| 2 |
import { db } from "@/lib/db";
|
| 3 |
import ZAI from "z-ai-web-dev-sdk";
|
| 4 |
|
| 5 |
+
const AUTOMATION_TYPES: Record<string, { name: string; triggers: string[] }> = {
|
| 6 |
content_generation: { name: "Generacion de Contenido", triggers: ["schedule", "manual"] },
|
| 7 |
posting: { name: "Publicacion Automatica", triggers: ["schedule", "manual"] },
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
trend_tracking: { name: "Seguimiento de Tendencias", triggers: ["schedule", "manual"] }
|
| 9 |
};
|
| 10 |
|
|
|
|
| 12 |
try {
|
| 13 |
const { searchParams } = new URL(request.url);
|
| 14 |
const type = searchParams.get("type");
|
|
|
|
|
|
|
| 15 |
const where: Record<string, unknown> = {};
|
| 16 |
if (type) where.type = type;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
+
const automations = await db.automation.findMany({ where, orderBy: { createdAt: "desc" } });
|
| 19 |
const stats = {
|
| 20 |
total: await db.automation.count(),
|
| 21 |
+
active: await db.automation.count({ where: { isActive: true } })
|
|
|
|
|
|
|
|
|
|
| 22 |
};
|
| 23 |
|
| 24 |
+
return NextResponse.json({ success: true, automations, automationTypes: AUTOMATION_TYPES, stats });
|
| 25 |
+
} catch {
|
| 26 |
+
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
|
|
|
|
| 27 |
}
|
| 28 |
}
|
| 29 |
|
| 30 |
export async function POST(request: NextRequest) {
|
| 31 |
try {
|
| 32 |
const body = await request.json();
|
| 33 |
+
const { name, type, trigger, actions } = body;
|
| 34 |
|
| 35 |
+
if (!name || !type || !actions) {
|
| 36 |
+
return NextResponse.json({ success: false, error: "Faltan campos" }, { status: 400 });
|
| 37 |
}
|
| 38 |
|
| 39 |
const automation = await db.automation.create({
|
| 40 |
+
data: { name, type, trigger: trigger || "manual", actions: JSON.stringify(actions), isActive: true }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
});
|
| 42 |
|
| 43 |
return NextResponse.json({ success: true, automation });
|
| 44 |
+
} catch {
|
| 45 |
+
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
|
|
|
|
| 46 |
}
|
| 47 |
}
|
| 48 |
|
| 49 |
export async function PUT(request: NextRequest) {
|
| 50 |
try {
|
| 51 |
const body = await request.json();
|
| 52 |
+
const { id, isActive, action } = body;
|
| 53 |
|
| 54 |
+
if (!id) return NextResponse.json({ success: false, error: "ID requerido" }, { status: 400 });
|
|
|
|
|
|
|
| 55 |
|
| 56 |
if (action === "execute") {
|
| 57 |
const automation = await db.automation.findUnique({ where: { id } });
|
| 58 |
if (!automation) return NextResponse.json({ success: false, error: "No encontrada" }, { status: 404 });
|
| 59 |
|
| 60 |
+
try {
|
| 61 |
+
const zai = await ZAI.create();
|
| 62 |
+
await zai.chat.completions.create({ messages: [{ role: "user", content: "test" }] });
|
| 63 |
+
} catch {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
|
| 65 |
+
await db.automation.update({ where: { id }, data: { lastRunAt: new Date(), runCount: { increment: 1 } } });
|
| 66 |
+
await db.automationLog.create({ data: { automationId: id, status: "success", duration: 100 } });
|
| 67 |
return NextResponse.json({ success: true });
|
| 68 |
}
|
| 69 |
|
| 70 |
+
const automation = await db.automation.update({ where: { id }, data: { isActive } });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
return NextResponse.json({ success: true, automation });
|
| 72 |
+
} catch {
|
| 73 |
+
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
|
|
|
|
| 74 |
}
|
| 75 |
}
|
| 76 |
|
|
|
|
| 78 |
try {
|
| 79 |
const { searchParams } = new URL(request.url);
|
| 80 |
const id = searchParams.get("id");
|
|
|
|
| 81 |
if (!id) return NextResponse.json({ success: false, error: "ID requerido" }, { status: 400 });
|
| 82 |
|
| 83 |
await db.automationLog.deleteMany({ where: { automationId: id } });
|
| 84 |
await db.automation.delete({ where: { id } });
|
|
|
|
| 85 |
return NextResponse.json({ success: true });
|
| 86 |
+
} catch {
|
| 87 |
+
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
|
|
|
|
| 88 |
}
|
| 89 |
}
|
src/app/api/content/route.ts
CHANGED
|
@@ -1,89 +1,41 @@
|
|
| 1 |
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
import { db } from "@/lib/db";
|
| 3 |
|
| 4 |
-
// GET - Listar todo el contenido
|
| 5 |
export async function GET(request: NextRequest) {
|
| 6 |
try {
|
| 7 |
const { searchParams } = new URL(request.url);
|
| 8 |
const type = searchParams.get("type");
|
| 9 |
const platform = searchParams.get("platform");
|
| 10 |
-
const status = searchParams.get("status");
|
| 11 |
const limit = parseInt(searchParams.get("limit") || "50");
|
| 12 |
|
| 13 |
const where: Record<string, unknown> = {};
|
| 14 |
if (type) where.type = type;
|
| 15 |
if (platform) where.platform = platform;
|
| 16 |
-
if (status) where.status = status;
|
| 17 |
|
| 18 |
-
const contents = await db.content.findMany({
|
| 19 |
-
where,
|
| 20 |
-
include: {
|
| 21 |
-
character: true,
|
| 22 |
-
censorFlags: true,
|
| 23 |
-
},
|
| 24 |
-
orderBy: { createdAt: "desc" },
|
| 25 |
-
take: limit,
|
| 26 |
-
});
|
| 27 |
|
| 28 |
-
// Estadísticas
|
| 29 |
const stats = {
|
| 30 |
total: await db.content.count(),
|
| 31 |
images: await db.content.count({ where: { type: "image" } }),
|
| 32 |
-
videos: await db.content.count({ where: { type: "video" } })
|
| 33 |
-
pending: await db.content.count({ where: { status: "pending" } }),
|
| 34 |
-
processing: await db.content.count({ where: { status: "processing" } }),
|
| 35 |
-
completed: await db.content.count({ where: { status: "completed" } }),
|
| 36 |
-
failed: await db.content.count({ where: { status: "failed" } }),
|
| 37 |
};
|
| 38 |
|
| 39 |
-
return NextResponse.json({
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
stats
|
| 43 |
-
});
|
| 44 |
-
|
| 45 |
-
} catch (error) {
|
| 46 |
-
console.error("Error fetching content:", error);
|
| 47 |
-
return NextResponse.json(
|
| 48 |
-
{ success: false, error: "Error al obtener contenido" },
|
| 49 |
-
{ status: 500 }
|
| 50 |
-
);
|
| 51 |
}
|
| 52 |
}
|
| 53 |
|
| 54 |
-
// DELETE - Eliminar contenido
|
| 55 |
export async function DELETE(request: NextRequest) {
|
| 56 |
try {
|
| 57 |
const { searchParams } = new URL(request.url);
|
| 58 |
const id = searchParams.get("id");
|
|
|
|
| 59 |
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
}
|
| 66 |
-
|
| 67 |
-
// Eliminar flags de censura asociados
|
| 68 |
-
await db.censorFlag.deleteMany({
|
| 69 |
-
where: { contentId: id }
|
| 70 |
-
});
|
| 71 |
-
|
| 72 |
-
// Eliminar contenido
|
| 73 |
-
await db.content.delete({
|
| 74 |
-
where: { id }
|
| 75 |
-
});
|
| 76 |
-
|
| 77 |
-
return NextResponse.json({
|
| 78 |
-
success: true,
|
| 79 |
-
message: "Contenido eliminado"
|
| 80 |
-
});
|
| 81 |
-
|
| 82 |
-
} catch (error) {
|
| 83 |
-
console.error("Error deleting content:", error);
|
| 84 |
-
return NextResponse.json(
|
| 85 |
-
{ success: false, error: "Error al eliminar contenido" },
|
| 86 |
-
{ status: 500 }
|
| 87 |
-
);
|
| 88 |
}
|
| 89 |
-
}
|
|
|
|
| 1 |
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
import { db } from "@/lib/db";
|
| 3 |
|
|
|
|
| 4 |
export async function GET(request: NextRequest) {
|
| 5 |
try {
|
| 6 |
const { searchParams } = new URL(request.url);
|
| 7 |
const type = searchParams.get("type");
|
| 8 |
const platform = searchParams.get("platform");
|
|
|
|
| 9 |
const limit = parseInt(searchParams.get("limit") || "50");
|
| 10 |
|
| 11 |
const where: Record<string, unknown> = {};
|
| 12 |
if (type) where.type = type;
|
| 13 |
if (platform) where.platform = platform;
|
|
|
|
| 14 |
|
| 15 |
+
const contents = await db.content.findMany({ where, orderBy: { createdAt: "desc" }, take: limit });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
|
|
|
| 17 |
const stats = {
|
| 18 |
total: await db.content.count(),
|
| 19 |
images: await db.content.count({ where: { type: "image" } }),
|
| 20 |
+
videos: await db.content.count({ where: { type: "video" } })
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
};
|
| 22 |
|
| 23 |
+
return NextResponse.json({ success: true, contents, stats });
|
| 24 |
+
} catch {
|
| 25 |
+
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
}
|
| 27 |
}
|
| 28 |
|
|
|
|
| 29 |
export async function DELETE(request: NextRequest) {
|
| 30 |
try {
|
| 31 |
const { searchParams } = new URL(request.url);
|
| 32 |
const id = searchParams.get("id");
|
| 33 |
+
if (!id) return NextResponse.json({ success: false, error: "ID requerido" }, { status: 400 });
|
| 34 |
|
| 35 |
+
await db.censorFlag.deleteMany({ where: { contentId: id } });
|
| 36 |
+
await db.content.delete({ where: { id } });
|
| 37 |
+
return NextResponse.json({ success: true });
|
| 38 |
+
} catch {
|
| 39 |
+
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
}
|
| 41 |
+
}
|
src/app/api/generate/image/route.ts
CHANGED
|
@@ -1,237 +1,86 @@
|
|
| 1 |
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
import ZAI from "z-ai-web-dev-sdk";
|
| 3 |
import { db } from "@/lib/db";
|
| 4 |
-
import fs from "fs/promises";
|
| 5 |
-
import path from "path";
|
| 6 |
|
| 7 |
-
const
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
} catch {
|
| 14 |
-
// ya existe
|
| 15 |
-
}
|
| 16 |
-
}
|
| 17 |
-
|
| 18 |
-
// Reglas de censura por plataforma
|
| 19 |
-
const CENSOR_RULES: Record<string, string[]> = {
|
| 20 |
-
youtube: [
|
| 21 |
-
"no nudity",
|
| 22 |
-
"no sexual content",
|
| 23 |
-
"no graphic violence",
|
| 24 |
-
"family friendly"
|
| 25 |
-
],
|
| 26 |
-
tiktok: [
|
| 27 |
-
"no nudity",
|
| 28 |
-
"no sexual suggestiveness",
|
| 29 |
-
"no graphic violence",
|
| 30 |
-
"no self-harm content",
|
| 31 |
-
"age appropriate"
|
| 32 |
-
],
|
| 33 |
-
instagram: [
|
| 34 |
-
"no nudity",
|
| 35 |
-
"no graphic violence",
|
| 36 |
-
"artistic content acceptable with moderation",
|
| 37 |
-
"no self-harm imagery"
|
| 38 |
-
],
|
| 39 |
-
twitter: [
|
| 40 |
-
"content warning if sensitive",
|
| 41 |
-
"no illegal content"
|
| 42 |
-
],
|
| 43 |
-
general: [
|
| 44 |
-
"safe for work",
|
| 45 |
-
"no explicit content"
|
| 46 |
-
]
|
| 47 |
};
|
| 48 |
|
| 49 |
-
// Aplicar filtros de censura al prompt
|
| 50 |
-
function applyCensorFilter(prompt: string, platform: string): string {
|
| 51 |
-
const rules = CENSOR_RULES[platform] || CENSOR_RULES.general;
|
| 52 |
-
const censorAdditions = rules.map(rule => `(${rule})`).join(", ");
|
| 53 |
-
return `${prompt}, ${censorAdditions}`;
|
| 54 |
-
}
|
| 55 |
-
|
| 56 |
export async function POST(request: NextRequest) {
|
| 57 |
try {
|
| 58 |
const body = await request.json();
|
| 59 |
-
const {
|
| 60 |
-
prompt,
|
| 61 |
-
optimizedPrompt,
|
| 62 |
-
platform = "general",
|
| 63 |
-
character,
|
| 64 |
-
style = "realistic",
|
| 65 |
-
size = "1024x1024",
|
| 66 |
-
saveToDb = true,
|
| 67 |
-
projectId
|
| 68 |
-
} = body;
|
| 69 |
|
| 70 |
if (!prompt && !optimizedPrompt) {
|
| 71 |
-
return NextResponse.json(
|
| 72 |
-
{ success: false, error: "Se requiere un prompt" },
|
| 73 |
-
{ status: 400 }
|
| 74 |
-
);
|
| 75 |
}
|
| 76 |
|
| 77 |
-
await ensureDir();
|
| 78 |
-
|
| 79 |
-
// Usar el prompt optimizado si está disponible
|
| 80 |
let finalPrompt = optimizedPrompt || prompt;
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
|
|
|
|
|
|
|
|
|
| 97 |
}
|
| 98 |
-
}
|
| 99 |
-
|
| 100 |
-
// Añadir referencia de personaje si existe
|
| 101 |
-
if (character) {
|
| 102 |
-
finalPrompt = `${finalPrompt}, character: ${character}`;
|
| 103 |
-
}
|
| 104 |
-
|
| 105 |
-
console.log("🖼️ Generando imagen con prompt:", finalPrompt.substring(0, 100) + "...");
|
| 106 |
-
|
| 107 |
-
// Crear registro en BD si se solicita
|
| 108 |
-
let contentRecord = null;
|
| 109 |
-
if (saveToDb) {
|
| 110 |
-
contentRecord = await db.content.create({
|
| 111 |
-
data: {
|
| 112 |
-
type: "image",
|
| 113 |
-
title: prompt.substring(0, 50),
|
| 114 |
-
description: prompt,
|
| 115 |
-
prompt: prompt,
|
| 116 |
-
optimizedPrompt: finalPrompt,
|
| 117 |
-
platform: platform,
|
| 118 |
-
status: "processing",
|
| 119 |
-
projectId: projectId || null,
|
| 120 |
-
}
|
| 121 |
-
});
|
| 122 |
-
}
|
| 123 |
|
| 124 |
try {
|
| 125 |
-
// Generar imagen con z-ai-web-dev-sdk
|
| 126 |
const zai = await ZAI.create();
|
| 127 |
const response = await zai.images.generations.create({
|
| 128 |
prompt: finalPrompt,
|
| 129 |
-
size: size as "1024x1024"
|
| 130 |
});
|
| 131 |
|
| 132 |
const imageBase64 = response.data[0]?.base64;
|
|
|
|
| 133 |
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
// Guardar imagen en disco
|
| 139 |
-
const filename = `image_${Date.now()}.png`;
|
| 140 |
-
const filepath = path.join(DOWNLOAD_DIR, filename);
|
| 141 |
-
const buffer = Buffer.from(imageBase64, "base64");
|
| 142 |
-
await fs.writeFile(filepath, buffer);
|
| 143 |
-
|
| 144 |
-
// Actualizar registro en BD
|
| 145 |
-
if (contentRecord) {
|
| 146 |
-
await db.content.update({
|
| 147 |
-
where: { id: contentRecord.id },
|
| 148 |
-
data: {
|
| 149 |
-
status: "completed",
|
| 150 |
-
filePath: `/download/images/${filename}`,
|
| 151 |
-
thumbnail: `/download/images/${filename}`,
|
| 152 |
-
}
|
| 153 |
-
});
|
| 154 |
-
}
|
| 155 |
-
|
| 156 |
-
// Crear tarea de agente
|
| 157 |
-
await db.agentTask.create({
|
| 158 |
-
data: {
|
| 159 |
-
type: "generate_image",
|
| 160 |
-
status: "completed",
|
| 161 |
-
input: prompt,
|
| 162 |
-
output: `Imagen generada: ${filename}`,
|
| 163 |
-
completedAt: new Date(),
|
| 164 |
-
}
|
| 165 |
});
|
| 166 |
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
image: {
|
| 170 |
-
id: contentRecord?.id,
|
| 171 |
-
filename,
|
| 172 |
-
url: `/download/images/${filename}`,
|
| 173 |
-
base64: imageBase64.substring(0, 50) + "...", // Preview del base64
|
| 174 |
-
prompt: finalPrompt,
|
| 175 |
-
platform,
|
| 176 |
-
size
|
| 177 |
-
}
|
| 178 |
});
|
| 179 |
|
|
|
|
| 180 |
} catch (genError) {
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
if (contentRecord) {
|
| 184 |
-
await db.content.update({
|
| 185 |
-
where: { id: contentRecord.id },
|
| 186 |
-
data: {
|
| 187 |
-
status: "failed",
|
| 188 |
-
metadata: JSON.stringify({ error: String(genError) })
|
| 189 |
-
}
|
| 190 |
-
});
|
| 191 |
-
}
|
| 192 |
-
|
| 193 |
-
return NextResponse.json(
|
| 194 |
-
{ success: false, error: "Error al generar imagen: " + String(genError) },
|
| 195 |
-
{ status: 500 }
|
| 196 |
-
);
|
| 197 |
}
|
| 198 |
-
|
| 199 |
} catch (error) {
|
| 200 |
-
|
| 201 |
-
return NextResponse.json(
|
| 202 |
-
{ success: false, error: "Error interno del servidor" },
|
| 203 |
-
{ status: 500 }
|
| 204 |
-
);
|
| 205 |
}
|
| 206 |
}
|
| 207 |
|
| 208 |
-
// Listar imágenes generadas
|
| 209 |
export async function GET(request: NextRequest) {
|
| 210 |
try {
|
| 211 |
const { searchParams } = new URL(request.url);
|
| 212 |
const platform = searchParams.get("platform");
|
| 213 |
const limit = parseInt(searchParams.get("limit") || "20");
|
| 214 |
-
|
| 215 |
const where: Record<string, unknown> = { type: "image" };
|
| 216 |
if (platform) where.platform = platform;
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
take: limit,
|
| 222 |
-
});
|
| 223 |
-
|
| 224 |
-
return NextResponse.json({
|
| 225 |
-
success: true,
|
| 226 |
-
images,
|
| 227 |
-
total: images.length
|
| 228 |
-
});
|
| 229 |
-
|
| 230 |
-
} catch (error) {
|
| 231 |
-
console.error("Error listing images:", error);
|
| 232 |
-
return NextResponse.json(
|
| 233 |
-
{ success: false, error: "Error al listar imágenes" },
|
| 234 |
-
{ status: 500 }
|
| 235 |
-
);
|
| 236 |
}
|
| 237 |
-
}
|
|
|
|
| 1 |
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
import ZAI from "z-ai-web-dev-sdk";
|
| 3 |
import { db } from "@/lib/db";
|
|
|
|
|
|
|
| 4 |
|
| 5 |
+
const CENSOR_RULES: Record<string, string> = {
|
| 6 |
+
youtube: "family friendly, no nudity, no violence",
|
| 7 |
+
tiktok: "age appropriate, no suggestive content",
|
| 8 |
+
instagram: "community guidelines, no graphic content",
|
| 9 |
+
twitter: "content warning if sensitive",
|
| 10 |
+
general: "safe for work"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
};
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
export async function POST(request: NextRequest) {
|
| 14 |
try {
|
| 15 |
const body = await request.json();
|
| 16 |
+
const { prompt, optimizedPrompt, platform = "general", style = "realistic", size = "1024x1024" } = body;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
if (!prompt && !optimizedPrompt) {
|
| 19 |
+
return NextResponse.json({ success: false, error: "Se requiere un prompt" }, { status: 400 });
|
|
|
|
|
|
|
|
|
|
| 20 |
}
|
| 21 |
|
|
|
|
|
|
|
|
|
|
| 22 |
let finalPrompt = optimizedPrompt || prompt;
|
| 23 |
+
const censorRule = CENSOR_RULES[platform] || CENSOR_RULES.general;
|
| 24 |
+
finalPrompt = finalPrompt + ", " + censorRule;
|
| 25 |
+
|
| 26 |
+
const styleMap: Record<string, string> = {
|
| 27 |
+
anime: "anime style, manga aesthetic",
|
| 28 |
+
realistic: "photorealistic, highly detailed",
|
| 29 |
+
artistic: "digital art, creative"
|
| 30 |
+
};
|
| 31 |
+
if (styleMap[style]) finalPrompt = finalPrompt + ", " + styleMap[style];
|
| 32 |
+
|
| 33 |
+
const contentRecord = await db.content.create({
|
| 34 |
+
data: {
|
| 35 |
+
type: "image",
|
| 36 |
+
title: prompt.substring(0, 50),
|
| 37 |
+
description: prompt,
|
| 38 |
+
prompt: prompt,
|
| 39 |
+
optimizedPrompt: finalPrompt,
|
| 40 |
+
platform: platform,
|
| 41 |
+
status: "processing"
|
| 42 |
}
|
| 43 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
try {
|
|
|
|
| 46 |
const zai = await ZAI.create();
|
| 47 |
const response = await zai.images.generations.create({
|
| 48 |
prompt: finalPrompt,
|
| 49 |
+
size: size as "1024x1024"
|
| 50 |
});
|
| 51 |
|
| 52 |
const imageBase64 = response.data[0]?.base64;
|
| 53 |
+
if (!imageBase64) throw new Error("No se recibio imagen");
|
| 54 |
|
| 55 |
+
await db.content.update({
|
| 56 |
+
where: { id: contentRecord.id },
|
| 57 |
+
data: { status: "completed", filePath: "generated" }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
});
|
| 59 |
|
| 60 |
+
await db.agentTask.create({
|
| 61 |
+
data: { type: "generate_image", status: "completed", input: prompt, output: "Imagen generada", completedAt: new Date() }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
});
|
| 63 |
|
| 64 |
+
return NextResponse.json({ success: true, image: { id: contentRecord.id, base64: imageBase64, prompt: finalPrompt, platform, size } });
|
| 65 |
} catch (genError) {
|
| 66 |
+
await db.content.update({ where: { id: contentRecord.id }, data: { status: "failed" } });
|
| 67 |
+
return NextResponse.json({ success: false, error: String(genError) }, { status: 500 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
}
|
|
|
|
| 69 |
} catch (error) {
|
| 70 |
+
return NextResponse.json({ success: false, error: "Error interno" }, { status: 500 });
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
}
|
| 72 |
}
|
| 73 |
|
|
|
|
| 74 |
export async function GET(request: NextRequest) {
|
| 75 |
try {
|
| 76 |
const { searchParams } = new URL(request.url);
|
| 77 |
const platform = searchParams.get("platform");
|
| 78 |
const limit = parseInt(searchParams.get("limit") || "20");
|
|
|
|
| 79 |
const where: Record<string, unknown> = { type: "image" };
|
| 80 |
if (platform) where.platform = platform;
|
| 81 |
+
const images = await db.content.findMany({ where, orderBy: { createdAt: "desc" }, take: limit });
|
| 82 |
+
return NextResponse.json({ success: true, images, total: images.length });
|
| 83 |
+
} catch {
|
| 84 |
+
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
}
|
| 86 |
+
}
|
src/app/api/generate/video/route.ts
CHANGED
|
@@ -1,221 +1,74 @@
|
|
| 1 |
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
import ZAI from "z-ai-web-dev-sdk";
|
| 3 |
import { db } from "@/lib/db";
|
| 4 |
-
import fs from "fs/promises";
|
| 5 |
-
import path from "path";
|
| 6 |
|
| 7 |
-
const DOWNLOAD_DIR = path.join(process.cwd(), "download", "videos");
|
| 8 |
-
|
| 9 |
-
async function ensureDir() {
|
| 10 |
-
try {
|
| 11 |
-
await fs.mkdir(DOWNLOAD_DIR, { recursive: true });
|
| 12 |
-
} catch {
|
| 13 |
-
// ya existe
|
| 14 |
-
}
|
| 15 |
-
}
|
| 16 |
-
|
| 17 |
-
// Reglas de censura para video
|
| 18 |
const VIDEO_CENSOR_RULES: Record<string, string> = {
|
| 19 |
-
youtube: "family friendly
|
| 20 |
-
tiktok: "age appropriate, no dangerous
|
| 21 |
-
instagram: "community guidelines compliant
|
| 22 |
-
|
| 23 |
-
general: "safe for work, appropriate content"
|
| 24 |
};
|
| 25 |
|
| 26 |
export async function POST(request: NextRequest) {
|
| 27 |
try {
|
| 28 |
const body = await request.json();
|
| 29 |
-
const {
|
| 30 |
-
prompt,
|
| 31 |
-
optimizedPrompt,
|
| 32 |
-
platform = "general",
|
| 33 |
-
style = "cinematic",
|
| 34 |
-
duration = "short",
|
| 35 |
-
aspectRatio = "16:9",
|
| 36 |
-
saveToDb = true,
|
| 37 |
-
projectId
|
| 38 |
-
} = body;
|
| 39 |
|
| 40 |
if (!prompt && !optimizedPrompt) {
|
| 41 |
-
return NextResponse.json(
|
| 42 |
-
{ success: false, error: "Se requiere un prompt para el video" },
|
| 43 |
-
{ status: 400 }
|
| 44 |
-
);
|
| 45 |
}
|
| 46 |
|
| 47 |
-
await ensureDir();
|
| 48 |
-
|
| 49 |
-
// Construir prompt final
|
| 50 |
let finalPrompt = optimizedPrompt || prompt;
|
| 51 |
-
|
| 52 |
-
// Añadir reglas de censura
|
| 53 |
const censorRule = VIDEO_CENSOR_RULES[platform] || VIDEO_CENSOR_RULES.general;
|
| 54 |
-
finalPrompt =
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
}
|
| 68 |
-
|
| 69 |
-
// Añadir duración
|
| 70 |
-
const durationAdditions: Record<string, string> = {
|
| 71 |
-
short: "short clip, 5-10 seconds",
|
| 72 |
-
medium: "medium length, 15-30 seconds",
|
| 73 |
-
long: "extended content, 1-2 minutes"
|
| 74 |
-
};
|
| 75 |
-
finalPrompt = `${finalPrompt}, ${durationAdditions[duration] || durationAdditions.short}`;
|
| 76 |
-
|
| 77 |
-
console.log("🎥 Generando video con prompt:", finalPrompt.substring(0, 100) + "...");
|
| 78 |
-
|
| 79 |
-
// Crear registro en BD
|
| 80 |
-
let contentRecord = null;
|
| 81 |
-
if (saveToDb) {
|
| 82 |
-
contentRecord = await db.content.create({
|
| 83 |
-
data: {
|
| 84 |
-
type: "video",
|
| 85 |
-
title: prompt.substring(0, 50),
|
| 86 |
-
description: prompt,
|
| 87 |
-
prompt: prompt,
|
| 88 |
-
optimizedPrompt: finalPrompt,
|
| 89 |
-
platform: platform,
|
| 90 |
-
status: "processing",
|
| 91 |
-
projectId: projectId || null,
|
| 92 |
-
metadata: JSON.stringify({ style, duration, aspectRatio })
|
| 93 |
-
}
|
| 94 |
-
});
|
| 95 |
-
}
|
| 96 |
|
| 97 |
try {
|
| 98 |
const zai = await ZAI.create();
|
| 99 |
-
|
| 100 |
-
// Generar video con z-ai-web-dev-sdk
|
| 101 |
-
const response = await zai.videos.generations.create({
|
| 102 |
-
prompt: finalPrompt,
|
| 103 |
-
});
|
| 104 |
-
|
| 105 |
-
// El SDK de video devuelve información del video generado
|
| 106 |
const videoData = response.data?.[0];
|
| 107 |
-
|
| 108 |
-
if (!videoData) {
|
| 109 |
-
throw new Error("No se recibió video del generador");
|
| 110 |
-
}
|
| 111 |
-
|
| 112 |
-
// Guardar video si viene en base64 o URL
|
| 113 |
-
let filename = `video_${Date.now()}.mp4`;
|
| 114 |
-
let filepath = path.join(DOWNLOAD_DIR, filename);
|
| 115 |
-
let videoUrl = "";
|
| 116 |
-
|
| 117 |
-
if (videoData.base64) {
|
| 118 |
-
const buffer = Buffer.from(videoData.base64, "base64");
|
| 119 |
-
await fs.writeFile(filepath, buffer);
|
| 120 |
-
videoUrl = `/download/videos/${filename}`;
|
| 121 |
-
} else if (videoData.url) {
|
| 122 |
-
videoUrl = videoData.url;
|
| 123 |
-
filename = videoData.url.split("/").pop() || filename;
|
| 124 |
-
}
|
| 125 |
-
|
| 126 |
-
// Actualizar registro
|
| 127 |
-
if (contentRecord) {
|
| 128 |
-
await db.content.update({
|
| 129 |
-
where: { id: contentRecord.id },
|
| 130 |
-
data: {
|
| 131 |
-
status: "completed",
|
| 132 |
-
filePath: videoUrl,
|
| 133 |
-
thumbnail: videoData.thumbnail || null,
|
| 134 |
-
}
|
| 135 |
-
});
|
| 136 |
-
}
|
| 137 |
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
data: {
|
| 141 |
-
type: "generate_video",
|
| 142 |
-
status: "completed",
|
| 143 |
-
input: prompt,
|
| 144 |
-
output: `Video generado: ${filename}`,
|
| 145 |
-
completedAt: new Date(),
|
| 146 |
-
}
|
| 147 |
});
|
| 148 |
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
video: {
|
| 152 |
-
id: contentRecord?.id,
|
| 153 |
-
filename,
|
| 154 |
-
url: videoUrl,
|
| 155 |
-
thumbnail: videoData.thumbnail,
|
| 156 |
-
prompt: finalPrompt,
|
| 157 |
-
platform,
|
| 158 |
-
style,
|
| 159 |
-
duration,
|
| 160 |
-
aspectRatio
|
| 161 |
-
}
|
| 162 |
});
|
| 163 |
|
|
|
|
| 164 |
} catch (genError) {
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
if (contentRecord) {
|
| 168 |
-
await db.content.update({
|
| 169 |
-
where: { id: contentRecord.id },
|
| 170 |
-
data: {
|
| 171 |
-
status: "failed",
|
| 172 |
-
metadata: JSON.stringify({ error: String(genError) })
|
| 173 |
-
}
|
| 174 |
-
});
|
| 175 |
-
}
|
| 176 |
-
|
| 177 |
-
return NextResponse.json(
|
| 178 |
-
{ success: false, error: "Error al generar video: " + String(genError) },
|
| 179 |
-
{ status: 500 }
|
| 180 |
-
);
|
| 181 |
}
|
| 182 |
-
|
| 183 |
} catch (error) {
|
| 184 |
-
|
| 185 |
-
return NextResponse.json(
|
| 186 |
-
{ success: false, error: "Error interno del servidor" },
|
| 187 |
-
{ status: 500 }
|
| 188 |
-
);
|
| 189 |
}
|
| 190 |
}
|
| 191 |
|
| 192 |
-
// Listar videos
|
| 193 |
export async function GET(request: NextRequest) {
|
| 194 |
try {
|
| 195 |
const { searchParams } = new URL(request.url);
|
| 196 |
const platform = searchParams.get("platform");
|
| 197 |
const limit = parseInt(searchParams.get("limit") || "20");
|
| 198 |
-
|
| 199 |
const where: Record<string, unknown> = { type: "video" };
|
| 200 |
if (platform) where.platform = platform;
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
take: limit,
|
| 206 |
-
});
|
| 207 |
-
|
| 208 |
-
return NextResponse.json({
|
| 209 |
-
success: true,
|
| 210 |
-
videos,
|
| 211 |
-
total: videos.length
|
| 212 |
-
});
|
| 213 |
-
|
| 214 |
-
} catch (error) {
|
| 215 |
-
console.error("Error listing videos:", error);
|
| 216 |
-
return NextResponse.json(
|
| 217 |
-
{ success: false, error: "Error al listar videos" },
|
| 218 |
-
{ status: 500 }
|
| 219 |
-
);
|
| 220 |
}
|
| 221 |
-
}
|
|
|
|
| 1 |
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
import ZAI from "z-ai-web-dev-sdk";
|
| 3 |
import { db } from "@/lib/db";
|
|
|
|
|
|
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
const VIDEO_CENSOR_RULES: Record<string, string> = {
|
| 6 |
+
youtube: "family friendly, no violence, no nudity",
|
| 7 |
+
tiktok: "age appropriate, no dangerous content",
|
| 8 |
+
instagram: "community guidelines compliant",
|
| 9 |
+
general: "safe for work"
|
|
|
|
| 10 |
};
|
| 11 |
|
| 12 |
export async function POST(request: NextRequest) {
|
| 13 |
try {
|
| 14 |
const body = await request.json();
|
| 15 |
+
const { prompt, optimizedPrompt, platform = "general", style = "cinematic" } = body;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
if (!prompt && !optimizedPrompt) {
|
| 18 |
+
return NextResponse.json({ success: false, error: "Se requiere un prompt" }, { status: 400 });
|
|
|
|
|
|
|
|
|
|
| 19 |
}
|
| 20 |
|
|
|
|
|
|
|
|
|
|
| 21 |
let finalPrompt = optimizedPrompt || prompt;
|
|
|
|
|
|
|
| 22 |
const censorRule = VIDEO_CENSOR_RULES[platform] || VIDEO_CENSOR_RULES.general;
|
| 23 |
+
finalPrompt = finalPrompt + ", " + censorRule + ", short clip";
|
| 24 |
+
|
| 25 |
+
const contentRecord = await db.content.create({
|
| 26 |
+
data: {
|
| 27 |
+
type: "video",
|
| 28 |
+
title: prompt.substring(0, 50),
|
| 29 |
+
description: prompt,
|
| 30 |
+
prompt: prompt,
|
| 31 |
+
optimizedPrompt: finalPrompt,
|
| 32 |
+
platform: platform,
|
| 33 |
+
status: "processing"
|
| 34 |
+
}
|
| 35 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
try {
|
| 38 |
const zai = await ZAI.create();
|
| 39 |
+
const response = await zai.videos.generations.create({ prompt: finalPrompt });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
const videoData = response.data?.[0];
|
| 41 |
+
if (!videoData) throw new Error("No se recibio video");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
|
| 43 |
+
await db.content.update({
|
| 44 |
+
where: { id: contentRecord.id },
|
| 45 |
+
data: { status: "completed", filePath: "generated" }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
});
|
| 47 |
|
| 48 |
+
await db.agentTask.create({
|
| 49 |
+
data: { type: "generate_video", status: "completed", input: prompt, output: "Video generado", completedAt: new Date() }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
});
|
| 51 |
|
| 52 |
+
return NextResponse.json({ success: true, video: { id: contentRecord.id, prompt: finalPrompt, platform, style } });
|
| 53 |
} catch (genError) {
|
| 54 |
+
await db.content.update({ where: { id: contentRecord.id }, data: { status: "failed" } });
|
| 55 |
+
return NextResponse.json({ success: false, error: String(genError) }, { status: 500 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
}
|
|
|
|
| 57 |
} catch (error) {
|
| 58 |
+
return NextResponse.json({ success: false, error: "Error interno" }, { status: 500 });
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
}
|
| 60 |
}
|
| 61 |
|
|
|
|
| 62 |
export async function GET(request: NextRequest) {
|
| 63 |
try {
|
| 64 |
const { searchParams } = new URL(request.url);
|
| 65 |
const platform = searchParams.get("platform");
|
| 66 |
const limit = parseInt(searchParams.get("limit") || "20");
|
|
|
|
| 67 |
const where: Record<string, unknown> = { type: "video" };
|
| 68 |
if (platform) where.platform = platform;
|
| 69 |
+
const videos = await db.content.findMany({ where, orderBy: { createdAt: "desc" }, take: limit });
|
| 70 |
+
return NextResponse.json({ success: true, videos, total: videos.length });
|
| 71 |
+
} catch {
|
| 72 |
+
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
}
|
| 74 |
+
}
|