Add local background removal and mask tools
This commit is contained in:
88
scripts/fetch-imgly-assets.mjs
Normal file
88
scripts/fetch-imgly-assets.mjs
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* 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);
|
||||
});
|
||||
Reference in New Issue
Block a user