| import fs from 'fs'; |
| import path from 'path'; |
| import os from 'os'; |
| import https from 'https'; |
| import yauzl from 'yauzl'; |
| import { fileURLToPath } from 'url'; |
|
|
| const __filename = fileURLToPath(import.meta.url); |
| const __dirname = path.dirname(__filename); |
|
|
| const URL = "https://alphacephei.com/vosk/models/vosk-model-small-en-us-0.15.zip"; |
| const MODEL_DIR = path.resolve(__dirname, "model"); |
|
|
| async function main() { |
| if (!fs.existsSync(MODEL_DIR)) { |
| fs.mkdirSync(MODEL_DIR, { recursive: true }); |
| } |
|
|
| if (fs.existsSync(path.resolve(MODEL_DIR, "DONE"))) { |
| console.log("Model already downloaded"); |
| return; |
| } |
|
|
| const zip = path.resolve(os.tmpdir(), path.basename(URL)); |
| await download(URL, zip); |
| console.log("Downloaded model to", zip); |
|
|
| await unzip(zip, MODEL_DIR); |
| fs.unlinkSync(zip); |
| } |
|
|
| function download(url, to, redirect = 0) { |
| if (redirect === 0) { |
| console.log(`Downloading ${url} to ${to}`); |
| } else { |
| console.log(`Redirecting to ${url}`); |
| } |
|
|
| return new Promise((resolve, reject) => { |
| if (!fs.existsSync(path.dirname(to))) { |
| fs.mkdirSync(path.dirname(to), { recursive: true }); |
| } |
|
|
| let done = true; |
| const file = fs.createWriteStream(to); |
| const request = https.get(url, (res) => { |
| if (res.statusCode === 302 && res.headers.location !== undefined) { |
| done = false; |
| file.close(); |
| resolve(download(res.headers.location, to, redirect + 1)); |
| return; |
| } |
| res.pipe(file); |
| }); |
|
|
| file.on("finish", () => { |
| if (done) { |
| resolve(to); |
| } |
| }); |
|
|
| request.on("error", (err) => { |
| fs.unlink(to, () => reject(err)); |
| }); |
|
|
| file.on("error", (err) => { |
| fs.unlink(to, () => reject(err)); |
| }); |
|
|
| request.end(); |
| }); |
| } |
|
|
| function unzip(zip, dest) { |
| const dir = path.basename(zip, ".zip"); |
| return new Promise((resolve, reject) => { |
| yauzl.open(zip, { lazyEntries: true }, (err, zipfile) => { |
| if (err) { |
| reject(err); |
| } |
| zipfile.readEntry(); |
| zipfile |
| .on("entry", (entry) => { |
| if (/\/$/.test(entry.fileName)) { |
| zipfile.readEntry(); |
| } else { |
| zipfile.openReadStream(entry, (err, stream) => { |
| if (err) { |
| reject(err); |
| } |
| const f = path.resolve(dest, entry.fileName.replace(`${dir}/`, "")); |
| if (!fs.existsSync(path.dirname(f))) { |
| fs.mkdirSync(path.dirname(f), { recursive: true }); |
| console.log("Created directory", path.dirname(f)); |
| } |
| stream.pipe(fs.createWriteStream(f)); |
| stream |
| .on("end", () => { |
| console.log("Extracted", f); |
| zipfile.readEntry(); |
| }) |
| .on("error", (err) => { |
| reject(err); |
| }); |
| }); |
| } |
| }) |
| .on("error", (err) => { |
| reject(err); |
| }) |
| .on("end", () => { |
| console.log("Extracted all files"); |
| fs.writeFileSync(path.resolve(dest, "DONE"), ""); |
| }) |
| .on("close", () => { |
| resolve(); |
| }); |
| }); |
| }); |
| } |
|
|
| main().catch(console.error); |