89 lines
2.8 KiB
JavaScript
89 lines
2.8 KiB
JavaScript
/**
|
|
* Self-host the @imgly/background-removal model + wasm assets.
|
|
*
|
|
* @imgly/background-removal is AGPL-3.0. By default it streams its ONNX model
|
|
* and onnxruntime-web wasm binaries from staticimgly.com at runtime. To keep
|
|
* Plimi's privacy promise (nothing leaves the user's browser, no third-party
|
|
* fetches), we mirror the *version-matched* asset bundle into `public/imgly/`
|
|
* and point the library at our own origin via `config.publicPath`.
|
|
*
|
|
* The assets are large (~300MB across all model variants) so they are NOT
|
|
* committed to git — this script is run on `predev` / `prebuild` and is
|
|
* idempotent: it only downloads chunks that are missing.
|
|
*/
|
|
import { mkdir, readFile, writeFile, stat } from "node:fs/promises";
|
|
import { fileURLToPath } from "node:url";
|
|
import path from "node:path";
|
|
|
|
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
const OUT_DIR = path.join(ROOT, "public", "imgly");
|
|
|
|
// Keep the data version in lock-step with the installed library version,
|
|
// otherwise the resources.json format / model keys won't match the runtime.
|
|
const { version } = JSON.parse(
|
|
await readFile(
|
|
path.join(ROOT, "node_modules/@imgly/background-removal/package.json"),
|
|
"utf8"
|
|
)
|
|
);
|
|
const BASE = `https://staticimgly.com/@imgly/background-removal-data/${version}/dist/`;
|
|
|
|
async function exists(p) {
|
|
try {
|
|
await stat(p);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function download(url, dest) {
|
|
const res = await fetch(url);
|
|
if (!res.ok) {
|
|
throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
}
|
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
await writeFile(dest, buf);
|
|
return buf.length;
|
|
}
|
|
|
|
async function main() {
|
|
await mkdir(OUT_DIR, { recursive: true });
|
|
|
|
console.log(`[imgly] Mirroring background-removal assets v${version}`);
|
|
const resourcesPath = path.join(OUT_DIR, "resources.json");
|
|
await download(new URL("resources.json", BASE).toString(), resourcesPath);
|
|
|
|
const resources = JSON.parse(await readFile(resourcesPath, "utf8"));
|
|
const chunkNames = new Set();
|
|
for (const entry of Object.values(resources)) {
|
|
for (const chunk of entry.chunks ?? []) chunkNames.add(chunk.name);
|
|
}
|
|
|
|
let downloaded = 0;
|
|
let skipped = 0;
|
|
let bytes = 0;
|
|
for (const name of chunkNames) {
|
|
const dest = path.join(OUT_DIR, name);
|
|
if (await exists(dest)) {
|
|
skipped++;
|
|
continue;
|
|
}
|
|
bytes += await download(new URL(name, BASE).toString(), dest);
|
|
downloaded++;
|
|
if (downloaded % 10 === 0) {
|
|
console.log(`[imgly] ${downloaded} chunks downloaded...`);
|
|
}
|
|
}
|
|
|
|
console.log(
|
|
`[imgly] Done: ${downloaded} downloaded, ${skipped} cached ` +
|
|
`(${(bytes / 1024 / 1024).toFixed(1)} MB new) → public/imgly/`
|
|
);
|
|
}
|
|
|
|
main().catch((err) => {
|
|
console.error("[imgly] Asset mirror failed:", err);
|
|
process.exit(1);
|
|
});
|