Spaces:
Build error
Build error
| import { NextRequest, NextResponse } from "next/server"; | |
| import { db } from "@/lib/db"; | |
| import ZAI from "z-ai-web-dev-sdk"; | |
| import fs from "fs/promises"; | |
| import path from "path"; | |
| const CHARACTERS_DIR = path.join(process.cwd(), "download", "characters"); | |
| async function ensureDir() { | |
| try { | |
| await fs.mkdir(CHARACTERS_DIR, { recursive: true }); | |
| } catch { | |
| // ya existe | |
| } | |
| } | |
| // GET - Listar personajes | |
| export async function GET(request: NextRequest) { | |
| try { | |
| const characters = await db.character.findMany({ | |
| include: { | |
| contents: { | |
| take: 5, | |
| orderBy: { createdAt: "desc" } | |
| } | |
| }, | |
| orderBy: { createdAt: "desc" } | |
| }); | |
| return NextResponse.json({ | |
| success: true, | |
| characters, | |
| total: characters.length | |
| }); | |
| } catch (error) { | |
| console.error("Error fetching characters:", error); | |
| return NextResponse.json( | |
| { success: false, error: "Error al obtener personajes" }, | |
| { status: 500 } | |
| ); | |
| } | |
| } | |
| // POST - Crear personaje | |
| export async function POST(request: NextRequest) { | |
| try { | |
| const body = await request.json(); | |
| const { | |
| name, | |
| description, | |
| generateReference = false, | |
| traits | |
| } = body; | |
| if (!name) { | |
| return NextResponse.json( | |
| { success: false, error: "El nombre del personaje es requerido" }, | |
| { status: 400 } | |
| ); | |
| } | |
| await ensureDir(); | |
| let referenceImage = null; | |
| let characterTraits = traits; | |
| // Generar imagen de referencia si se solicita | |
| if (generateReference) { | |
| try { | |
| const zai = await ZAI.create(); | |
| // Crear prompt detallado para el personaje | |
| const characterPrompt = `Character reference sheet: ${name}. ${description || "Original character"}. Full body view, multiple angles (front, side, back), consistent character design, clear details, neutral pose, white background, character turnaround, reference sheet style. Professional character design, consistent facial features, consistent body proportions.`; | |
| const response = await zai.images.generations.create({ | |
| prompt: characterPrompt, | |
| size: "1344x768" // Horizontal para el reference sheet | |
| }); | |
| const imageBase64 = response.data[0]?.base64; | |
| if (imageBase64) { | |
| const filename = `character_${name.toLowerCase().replace(/\s+/g, "_")}_${Date.now()}.png`; | |
| const filepath = path.join(CHARACTERS_DIR, filename); | |
| const buffer = Buffer.from(imageBase64, "base64"); | |
| await fs.writeFile(filepath, buffer); | |
| referenceImage = `/download/characters/${filename}`; | |
| } | |
| // Si no se proporcionaron traits, extraerlos con IA | |
| if (!traits) { | |
| const traitsResponse = await zai.chat.completions.create({ | |
| messages: [ | |
| { | |
| role: "system", | |
| content: "Eres un experto en diseño de personajes. Extrae los rasgos físicos clave del personaje para mantener consistencia en futuras generaciones. Responde SOLO en formato JSON con: { \"face\": \"\", \"body\": \"\", \"hair\": \"\", \"clothing\": \"\", \"colors\": \"\", \"distinctive\": \"\" }" | |
| }, | |
| { | |
| role: "user", | |
| content: `Personaje: ${name}. Descripción: ${description || "Original character"}` | |
| } | |
| ] | |
| }); | |
| const traitsText = traitsResponse.choices[0]?.message?.content || ""; | |
| try { | |
| const jsonMatch = traitsText.match(/\{[\s\S]*\}/); | |
| if (jsonMatch) { | |
| characterTraits = jsonMatch[0]; | |
| } | |
| } catch { | |
| characterTraits = JSON.stringify({ description: description || "Original character" }); | |
| } | |
| } | |
| } catch (genError) { | |
| console.error("Error generando referencia:", genError); | |
| // Continuar sin imagen de referencia | |
| } | |
| } | |
| // Crear personaje en BD | |
| const character = await db.character.create({ | |
| data: { | |
| name, | |
| description: description || null, | |
| referenceImage, | |
| traits: characterTraits || JSON.stringify({ name, description }) | |
| } | |
| }); | |
| return NextResponse.json({ | |
| success: true, | |
| character, | |
| message: `Personaje "${name}" creado exitosamente` | |
| }); | |
| } catch (error) { | |
| console.error("Error creating character:", error); | |
| return NextResponse.json( | |
| { success: false, error: "Error al crear personaje" }, | |
| { status: 500 } | |
| ); | |
| } | |
| } | |
| // PUT - Actualizar personaje | |
| export async function PUT(request: NextRequest) { | |
| try { | |
| const body = await request.json(); | |
| const { id, name, description, traits } = body; | |
| if (!id) { | |
| return NextResponse.json( | |
| { success: false, error: "ID del personaje requerido" }, | |
| { status: 400 } | |
| ); | |
| } | |
| const character = await db.character.update({ | |
| where: { id }, | |
| data: { | |
| name: name || undefined, | |
| description: description || undefined, | |
| traits: traits || undefined, | |
| } | |
| }); | |
| return NextResponse.json({ | |
| success: true, | |
| character | |
| }); | |
| } catch (error) { | |
| console.error("Error updating character:", error); | |
| return NextResponse.json( | |
| { success: false, error: "Error al actualizar personaje" }, | |
| { status: 500 } | |
| ); | |
| } | |
| } | |
| // DELETE - Eliminar personaje | |
| export async function DELETE(request: NextRequest) { | |
| try { | |
| const { searchParams } = new URL(request.url); | |
| const id = searchParams.get("id"); | |
| if (!id) { | |
| return NextResponse.json( | |
| { success: false, error: "ID requerido" }, | |
| { status: 400 } | |
| ); | |
| } | |
| await db.character.delete({ | |
| where: { id } | |
| }); | |
| return NextResponse.json({ | |
| success: true, | |
| message: "Personaje eliminado" | |
| }); | |
| } catch (error) { | |
| console.error("Error deleting character:", error); | |
| return NextResponse.json( | |
| { success: false, error: "Error al eliminar personaje" }, | |
| { status: 500 } | |
| ); | |
| } | |
| } | |