Spaces:
Build error
Build error
File size: 8,077 Bytes
eeb9657 359c092 6630c3d 574df02 eeb9657 574df02 eeb9657 574df02 eeb9657 574df02 6630c3d 99dcc77 6630c3d 99dcc77 50eeaa1 00d41a8 99dcc77 6630c3d 7b8522b 00d41a8 f3d6819 7b8522b 365ad0f 7b8522b 50eeaa1 f3d6819 00d41a8 7b8522b 50eeaa1 7b8522b 50eeaa1 5d8dd38 50eeaa1 365ad0f 7b8522b 365ad0f 7b8522b 365ad0f b9be0c8 7b8522b 9735639 365ad0f 7b8522b 9735639 00d41a8 7b8522b 00d41a8 7b8522b 00d41a8 7b8522b 00d41a8 7b8522b 00d41a8 365ad0f 00d41a8 7b8522b 00d41a8 365ad0f 00d41a8 7b8522b 00d41a8 50eeaa1 b9be0c8 f3d6819 f4ab502 7b8522b 50eeaa1 b9be0c8 50eeaa1 23fe54d 50eeaa1 23fe54d 50eeaa1 f3d6819 6630c3d 00d41a8 7b8522b 6630c3d 99dcc77 6630c3d | 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 | export default async function handler(req, res) {
res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
if (req.method !== 'GET') {
return res.status(405).json({ error: 'Método no permitido' });
}
try {
let jobId = req.query?.job_id;
if (!jobId && req.url) {
try {
const parsedUrl = new URL(req.url, 'https://localhost');
jobId = parsedUrl.searchParams.get('job_id');
} catch (e) {}
}
if (!jobId) {
return res.status(400).json({ error: 'El parámetro job_id es requerido.' });
}
const hfToken = process.env.HF_TOKEN;
if (jobId.startsWith('hf:')) {
const parts = jobId.split(':');
const spaceHost = parts[1] || 'logicaltrue-trellis-2';
const sessionHash = parts[2];
const eventId = parts[3];
const decimationTarget = parseInt(parts[4]) || 300000;
const textureSize = parseInt(parts[5]) || 1024;
const spaceUrl = `https://${spaceHost}.hf.space`;
// Cabecera obligatoria Accept: text/event-stream para endpoints SSE de Gradio v4
const sseHeaders = {
'Accept': 'text/event-stream',
'Cache-Control': 'no-cache',
...(hfToken ? { 'Authorization': `Bearer ${hfToken}` } : {})
};
const jsonHeaders = {
'Content-Type': 'application/json',
...(hfToken ? { 'Authorization': `Bearer ${hfToken}` } : {})
};
// ─── 1. Verificar estado del Paso 1 (/image_to_3d) ────────────────────
const step1Urls = [
`${spaceUrl}/gradio_api/call/image_to_3d/${eventId}`,
`${spaceUrl}/call/image_to_3d/${eventId}`,
`${spaceUrl}/gradio_api/queue/data?session_hash=${sessionHash}`,
`${spaceUrl}/queue/data?session_hash=${sessionHash}`
];
let isStep1Complete = false;
for (const statusUrl of step1Urls) {
try {
const qRes = await fetch(statusUrl, {
headers: sseHeaders,
signal: AbortSignal.timeout(9000)
}).catch(() => null);
if (qRes && qRes.ok) {
const txt = await qRes.text().catch(() => '');
console.log(`[Paso 1 Stream SSE ${eventId}]`, txt.slice(0, 300));
// Validar si el evento complete o process_completed fue emitido con éxito
if (txt.includes('event: complete') || txt.includes('process_completed') || txt.includes('event: generating')) {
if (txt.includes('"success":false')) {
continue;
}
isStep1Complete = true;
break;
}
if (txt.includes('process_starts') || txt.includes('estimation') || txt.includes('event: heartbeat')) {
return res.status(200).json({
status: 'processing',
progress: 65,
message: 'Inferencia 3D en progreso en la GPU A100 (Sparse & SLaT)...'
});
}
}
} catch (e) {}
}
// Si la GPU aún está calculando el volumen 3D
if (!isStep1Complete) {
return res.status(200).json({
status: 'processing',
progress: 60,
message: 'Calculando volumen 3D en la GPU A100...'
});
}
// ─── 2. Paso 1 completado! Ejecutar Extracción GLB (/extract_glb) ─────
console.log(`[Paso 1 completado] Iniciando Paso 2 (/extract_glb) decimation=${decimationTarget}...`);
let extractEventId = null;
try {
const extractRes = await fetch(`${spaceUrl}/gradio_api/call/extract_glb`, {
method: 'POST',
headers: jsonHeaders,
body: JSON.stringify({
data: [decimationTarget, textureSize],
session_hash: sessionHash
}),
signal: AbortSignal.timeout(10000)
}).catch(() => null);
if (extractRes && extractRes.ok) {
const extractJson = await extractRes.json().catch(() => ({}));
extractEventId = extractJson.event_id;
console.log(`[Paso 2 /extract_glb Iniciado] event_id: ${extractEventId}`);
}
} catch (e) {}
// Consultar resultado de /extract_glb
const extractCheckUrls = [
extractEventId ? `${spaceUrl}/gradio_api/call/extract_glb/${extractEventId}` : null,
extractEventId ? `${spaceUrl}/call/extract_glb/${extractEventId}` : null,
`${spaceUrl}/gradio_api/queue/data?session_hash=${sessionHash}`,
`${spaceUrl}/queue/data?session_hash=${sessionHash}`
].filter(Boolean);
for (const extUrl of extractCheckUrls) {
try {
const extRes = await fetch(extUrl, {
headers: sseHeaders,
signal: AbortSignal.timeout(9000)
}).catch(() => null);
if (extRes && extRes.ok) {
const extTxt = await extRes.text().catch(() => '');
const glbMatch = extTxt.match(/"([^"]+\.glb)"/i);
if (glbMatch && glbMatch[1]) {
let rawGlb = glbMatch[1];
let fullGlbUrl = rawGlb;
if (!rawGlb.startsWith('http')) {
if (rawGlb.startsWith('/tmp/') || rawGlb.startsWith('tmp/')) {
fullGlbUrl = `${spaceUrl}/file=${rawGlb.startsWith('/') ? '' : '/'}${rawGlb}`;
} else if (rawGlb.startsWith('/file=') || rawGlb.startsWith('file=')) {
fullGlbUrl = `${spaceUrl}${rawGlb.startsWith('/') ? '' : '/'}${rawGlb}`;
} else {
fullGlbUrl = `${spaceUrl}/file=${rawGlb}`;
}
}
console.log(`[GLB EXTRACCION EXITOSA 100%] ${fullGlbUrl}`);
return res.status(200).json({
status: 'completed',
progress: 100,
result: {
gltfUrl: fullGlbUrl,
glbUrl: fullGlbUrl,
fbxUrl: fullGlbUrl,
detectedCategory: 'objeto'
}
});
}
}
} catch (e) {}
}
return res.status(200).json({
status: 'processing',
progress: 85,
message: 'Extrayendo texturas PBR y generando archivo GLB...'
});
}
return res.status(200).json({
status: 'processing',
progress: 50,
message: 'Procesando modelo 3D en la nube...'
});
} catch (err) {
console.error('[Vercel Job-Status Error]', err);
return res.status(500).json({ error: err.message || 'Error verificando el estado de la tarea.' });
}
}
|