import fs from "fs"; import randomstring from "randomstring"; const TEMP_DIR = "./temp-tts"; const sub_name = randomstring.generate({ length: 5, charset: 'alphanumeric' }); const HOST = "https://office4-chatterbox.wibudev.com"; async function fetchRetry(url: string, options: any = {}, retries = 3) { for (let i = 0; i < retries; i++) { try { return await fetch(url, options); } catch (err) { console.warn(`Fetch attempt ${i + 1} failed:`, err); if (i === retries - 1) throw err; await new Promise((r) => setTimeout(r, 1000 * (i + 1))); } } } async function fetchResult(jobId: string, partIndex: number) { const res = await fetchRetry(`${HOST}/result/${jobId}`); if (!res) { throw new Error("Failed to fetch result"); } const type = res.headers.get("content-type") || ""; if (type.includes("application/json")) { try { return await res.json(); } catch { throw new Error("Invalid JSON response on fetchResult"); } } // Audio response const buf = Buffer.from(await res.arrayBuffer()); if (buf.length < 44) { throw new Error("Invalid WAV: too small"); } const file = `${TEMP_DIR}/${jobId}_${sub_name}_${(partIndex + 1).toString().padStart(4, "0")}.wav`; fs.writeFileSync(file, buf); return { status: "done", filePath: file }; } export async function main() { const jobsPath = TEMP_DIR + "/jobs.json"; if (!fs.existsSync(jobsPath)) { console.error("❌ jobs.json not found"); process.exit(1); } // POLLING SEMUA const jobs = JSON.parse(fs.readFileSync(jobsPath, "utf-8")); console.log("⏳ Waiting for processing..."); const resultFiles: string[] = []; for (let i = 0; i < jobs.length; i++) { const jobId = jobs[i]; let status = "processing"; let delay = 5000; let attempts = 0; while (status === "processing" || status === "pending") { try { const res = await fetchResult(jobId as string, i); status = res.status; if (status === "done" && res.filePath) { resultFiles.push(res.filePath as string); console.log(` ✓ Job ${i + 1}/${jobs.length} completed: ${jobId}`); const resFile = await fetchRetry(`${HOST}/file/${jobId}`); if (!resFile) { throw new Error("Failed to fetch file"); } const buf = Buffer.from(await res.arrayBuffer()); if (buf.length < 44) { throw new Error("Invalid WAV: too small"); } const file = `${TEMP_DIR}/${jobId}_${sub_name}_${(i + 1).toString().padStart(4, "0")}.wav`; fs.writeFileSync(file, buf); break; } else if (status === "error") { console.error( ` ❌ Job ${i + 1}/${jobs.length} failed: ${res.error || "Unknown error"}` ); throw new Error(`Job ${jobId} failed`); } } catch (error) { console.error(`❌ Error fetching result for job ${i + 1}:`, error); process.exit(1); } attempts++; await new Promise((r) => setTimeout(r, delay)); delay = Math.min(delay * 1.2, 5000); // Timeout after 2 minutes if (attempts > 80) { console.error(`❌ Job ${jobId} timeout after 2 minutes`); process.exit(1); } } } console.log("🎉 DONE!"); return resultFiles; } if (import.meta.main) { main().then((resultFiles) => { console.log("Result files:", resultFiles); }); }