sofia-cloud / src /app /api /generate /image /route.ts
Gmagl
feat: complete Telegram AI Girlfriend mechanics & deduplication
b8b98dd
Raw
History Blame Contribute Delete
4.58 kB
import { NextRequest, NextResponse } from "next/server";
import ZAI from "z-ai-web-dev-sdk";
import { db } from "@/lib/db";
import { validateUserCredit, logResourceUsage } from "@/lib/credits";
const CENSOR_RULES: Record<string, string> = {
youtube: "family friendly, no nudity, no violence",
tiktok: "age appropriate, no suggestive content",
instagram: "community guidelines, no graphic content",
twitter: "content warning if sensitive",
general: "safe for work"
};
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { prompt, optimizedPrompt, platform = "general", style = "realistic", size = "1024x1024", userId, tier = "free" } = body;
if (!prompt && !optimizedPrompt) {
return NextResponse.json({ success: false, error: "Se requiere un prompt" }, { status: 400 });
}
// Validar créditos
const creditCheck = await validateUserCredit(db, userId || "anonymous", "images_per_month", tier);
if (!creditCheck.allowed) {
return NextResponse.json({ success: false, error: creditCheck.reason, remaining: creditCheck.remaining }, { status: 429 });
}
let finalPrompt = optimizedPrompt || prompt;
// Inject Character Visual Persona
const character = await db.character.findFirst({ where: { isActive: true } });
if (character?.styleDescription || character?.referenceImage) {
finalPrompt = `${character.styleDescription || "AI Character"}. ${finalPrompt}`;
}
const censorRule = CENSOR_RULES[platform] || CENSOR_RULES.general;
// Skip censorship for private/exclusive monetization platforms
const uncensoredPlatforms = ["onlyfans", "fansly", "telegram-uncensored", "patreon-uncensored"];
if (!uncensoredPlatforms.includes(platform)) {
finalPrompt = finalPrompt + ", " + censorRule;
}
const styleMap: Record<string, string> = {
anime: "anime style, manga aesthetic",
realistic: "photorealistic, highly detailed",
artistic: "digital art, creative"
};
if (styleMap[style]) finalPrompt = finalPrompt + ", " + styleMap[style];
const contentRecord = await db.content.create({
data: {
type: "image",
title: prompt.substring(0, 50),
description: prompt,
prompt: prompt,
optimizedPrompt: finalPrompt,
platform: platform,
characterId: character?.id || null,
status: "processing"
}
});
try {
const zai = await ZAI.create();
const response = await zai.images.generations.create({
prompt: finalPrompt,
size: size as "1024x1024"
});
const imageBase64 = response.data[0]?.base64;
if (!imageBase64) throw new Error("No se recibio imagen");
await db.content.update({
where: { id: contentRecord.id },
data: { status: "completed", filePath: "generated" }
});
// Log del uso de crédito
await logResourceUsage(db, userId || "anonymous", "images_per_month", contentRecord.id);
await db.agentTask.create({
data: { type: "generate_image", status: "completed", input: prompt, output: "Imagen generada", completedAt: new Date() }
});
return NextResponse.json({
success: true,
image: { id: contentRecord.id, base64: imageBase64, prompt: finalPrompt, platform, size },
creditsRemaining: creditCheck.remaining ? creditCheck.remaining - 1 : 0
});
} catch (genError) {
await db.content.update({ where: { id: contentRecord.id }, data: { status: "failed" } });
const errorMessage = genError instanceof Error ? genError.message : "Error generando imagen";
return NextResponse.json({ success: false, error: errorMessage }, { status: 500 });
}
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : "Error interno";
return NextResponse.json({ success: false, error: errorMessage }, { status: 500 });
}
}
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const platform = searchParams.get("platform");
const limit = Number.parseInt(searchParams.get("limit") || "20", 10);
const where: Record<string, any> = { 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 {
return NextResponse.json({ success: false, error: "Error" }, { status: 500 });
}
}