Files
element-call/scripts/setup-noise-suppression-assets.js
2026-03-26 15:51:46 +01:00

157 lines
4.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Setup script to download DeepFilterNet3 assets for local bundling.
* This downloads the WASM binary and AI model from Mezon's CDN
* and places them in public/assets/deepfilternet3/ for bundling.
*
* Usage:
* node scripts/setup-noise-suppression-assets.js
*
* Environment variables:
* DEEPFILTERNET3_CDN_URL: Override the default CDN URL (optional)
*/
import fs from "fs";
import path from "path";
import https from "https";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.join(__dirname, "..");
const CDN_URL =
process.env.DEEPFILTERNET3_CDN_URL ||
"https://cdn.mezon.ai/AI/models/datas/noise_suppression/deepfilternet3";
const ASSETS_DIR = path.join(projectRoot, "public", "assets", "deepfilternet3");
const V2_DIR = path.join(ASSETS_DIR, "v2");
const PKG_DIR = path.join(V2_DIR, "pkg");
const MODELS_DIR = path.join(V2_DIR, "models");
const FILES_TO_DOWNLOAD = [
{
url: `${CDN_URL}/v2/pkg/df_bg.wasm`,
path: path.join(PKG_DIR, "df_bg.wasm"),
description: "WASM binary",
},
{
url: `${CDN_URL}/v2/pkg/df_bg.wasm.d.ts`,
path: path.join(PKG_DIR, "df_bg.wasm.d.ts"),
description: "WASM TypeScript definitions",
optional: true,
},
{
url: `${CDN_URL}/v2/models/DeepFilterNet3_onnx.tar.gz`,
path: path.join(MODELS_DIR, "DeepFilterNet3_onnx.tar.gz"),
description: "AI Model (ONNX format)",
},
];
function ensureDir(dir) {
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
console.log(`✓ Created directory: ${dir}`);
}
}
function downloadFile(fileUrl, filePath, isOptional = false) {
return new Promise((resolve, reject) => {
const fileName = path.basename(filePath);
// Skip if already exists
if (fs.existsSync(filePath)) {
console.log(`✓ Already exists: ${fileName}`);
resolve();
return;
}
console.log(`⏳ Downloading ${fileName}...`);
https
.get(fileUrl, (response) => {
// Handle redirects
if (
response.statusCode === 301 ||
response.statusCode === 302 ||
response.statusCode === 307
) {
const redirectUrl = response.headers.location;
console.log(` Redirected to: ${redirectUrl}`);
downloadFile(redirectUrl, filePath, isOptional)
.then(resolve)
.catch(reject);
return;
}
if (response.statusCode !== 200) {
const error = new Error(
`Download failed: HTTP ${response.statusCode} for ${fileName}`,
);
if (isOptional) {
console.warn(`⚠ Optional file skipped: ${fileName}`);
resolve();
} else {
reject(error);
}
return;
}
const fileStream = fs.createWriteStream(filePath);
response.pipe(fileStream);
fileStream.on("finish", () => {
fileStream.close();
const sizeMB = (fs.statSync(filePath).size / 1024 / 1024).toFixed(2);
console.log(`✓ Downloaded: ${fileName} (${sizeMB} MB)`);
resolve();
});
fileStream.on("error", (err) => {
fs.unlink(filePath, () => {}); // Clean up partial file
reject(err);
});
})
.on("error", (err) => {
if (isOptional) {
console.warn(`⚠ Optional file skipped: ${fileName} (${err.message})`);
resolve();
} else {
reject(err);
}
});
});
}
async function main() {
try {
console.log("\n🚀 Setting up DeepFilterNet3 assets for bundling...\n");
console.log(`📦 CDN URL: ${CDN_URL}`);
console.log(`📁 Asset directory: ${ASSETS_DIR}\n`);
// Ensure directories exist
ensureDir(ASSETS_DIR);
ensureDir(V2_DIR);
ensureDir(PKG_DIR);
ensureDir(MODELS_DIR);
// Download files
for (const file of FILES_TO_DOWNLOAD) {
await downloadFile(file.url, file.path, file.optional);
}
console.log("\n✅ Asset setup complete!");
console.log(
"\nAssets are ready for bundling. Next build will include them.\n",
);
process.exit(0);
} catch (error) {
console.error("\n❌ Asset setup failed:", error.message);
process.exit(1);
}
}
main();