choephix's picture
fix predict API using supported Gradio endpoint
69a3974
#!/usr/bin/env node
import { readFile, readdir, mkdir, writeFile } from "node:fs/promises";
import { basename, extname, join } from "node:path";
import { fileURLToPath } from "node:url";
const scriptDir = fileURLToPath(new URL(".", import.meta.url));
const inputDir = join(scriptDir, "inputs");
const outputDir = join(scriptDir, "outputs");
const apiUrl =
process.env.ORIENT_ANYTHING_API_URL ??
"https://choephix-orient-anything-v2.hf.space/gradio_api/run/predict";
const removeBackground = (process.env.ORIENT_ANYTHING_REMOVE_BG ?? "true") !== "false";
const mimeTypes = {
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".webp": "image/webp",
};
const supportedExtensions = new Set(Object.keys(mimeTypes));
const getMimeType = (filePath) =>
mimeTypes[extname(filePath).toLowerCase()] ?? "application/octet-stream";
const getOutputPath = (filePath) =>
join(outputDir, `${basename(filePath, extname(filePath))}.json`);
const serializeError = (error) => ({
message: error instanceof Error ? error.message : String(error),
});
const listInputFiles = async () => {
const entries = await readdir(inputDir, { withFileTypes: true });
return entries
.filter((entry) => entry.isFile())
.map((entry) => join(inputDir, entry.name))
.filter((filePath) => supportedExtensions.has(extname(filePath).toLowerCase()))
.sort((left, right) => left.localeCompare(right));
};
const toDataUrl = async (filePath) => {
const fileBuffer = await readFile(filePath);
return `data:${getMimeType(filePath)};base64,${fileBuffer.toString("base64")}`;
};
const callApi = async (filePath) => {
const imageRef = await toDataUrl(filePath);
const response = await fetch(apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
data: [imageRef, null, removeBackground],
}),
});
const responseText = await response.text();
const responseBody = (() => {
try {
return JSON.parse(responseText);
} catch {
return responseText;
}
})();
if (!response.ok) {
throw new Error(
typeof responseBody === "string"
? `HTTP ${response.status}: ${responseBody}`
: `HTTP ${response.status}: ${JSON.stringify(responseBody)}`,
);
}
return responseBody;
};
const processFile = async (filePath) => {
const inputName = basename(filePath);
try {
console.log(`🛰️ processing ${inputName}`);
const result = await callApi(filePath);
const payload = {
input: inputName,
ok: true,
result,
};
await writeFile(getOutputPath(filePath), JSON.stringify(payload, null, 2) + "\n");
console.log(`✅ saved ${basename(getOutputPath(filePath))}`);
return payload;
} catch (error) {
const payload = {
input: inputName,
ok: false,
error: serializeError(error),
};
await writeFile(getOutputPath(filePath), JSON.stringify(payload, null, 2) + "\n");
console.log(`⚠️ failed ${inputName}`);
return payload;
}
};
const main = async () => {
await mkdir(outputDir, { recursive: true });
const inputFiles = await listInputFiles();
if (inputFiles.length === 0) {
console.log(`📭 no supported images found in ${inputDir}`);
return;
}
console.log(`🚀 using ${apiUrl}`);
console.log(`🧼 remove background: ${removeBackground}`);
const results = [];
for (const filePath of inputFiles) {
results.push(await processFile(filePath));
}
const summary = {
apiUrl,
removeBackground,
total: results.length,
succeeded: results.filter((result) => result.ok).length,
failed: results.filter((result) => !result.ok).length,
results,
};
await writeFile(join(outputDir, "summary.json"), JSON.stringify(summary, null, 2) + "\n");
console.log(`📦 wrote ${results.length} result files + summary.json`);
};
await main();