Files
iNaturalistReactNative/scripts/add-example-model.js
Corey Farwell 77c3eee481 feat(build): Unify JS config for i18n and scripts
This change introduces `babel-node` to the development workflow, allowing the project to use modern JavaScript features like ES modules (`import`/`export`) in our build scripts and i18n command-line interface.

Previously, scripts in the `i18n` directory and the `scripts` directory were executed directly with `node`, which required them to use CommonJS (`require`/`module.exports`) and prevented the use of other Babel transformations that are standard across the rest of the project.

By switching to `babel-node`, this project now has unified JavaScript tooling, and now developers are no longer required to know which files need to use CommonJS (none anymore!).
2025-10-30 11:01:00 -04:00

139 lines
4.3 KiB
JavaScript

import fs from "fs/promises";
import { DownloaderHelper } from "node-downloader-helper";
import path from "path";
import yargs from "yargs";
const binariesBaseDir
= "https://github.com/inaturalist/model-files/releases/download/v25.01.15";
const androidExt = "tflite";
const iosExt = "mlmodel";
const cvModelFilename = "INatVision_Small_2_fact256_8bit";
const geomodelFilename = "INatGeomodel_Small_2_8bit";
const androidCV = `${binariesBaseDir}/${cvModelFilename}.${androidExt}`;
const iosCV = `${binariesBaseDir}/${cvModelFilename}.${iosExt}`;
const androidGeo = `${binariesBaseDir}/${geomodelFilename}.${androidExt}`;
const iosGeo = `${binariesBaseDir}/${geomodelFilename}.${iosExt}`;
const taxonomyCSV = `${binariesBaseDir}/taxonomy.csv`;
const taxonomyJSON = `${binariesBaseDir}/taxonomy.json`;
const downloadAndroid = async argv => {
const androidFlavor = argv.androidFlavor || "debug";
const androidDestination = path.join(
__dirname,
"..",
"android",
"app",
"src",
androidFlavor,
"assets",
"camera"
);
const androidModel = path.join(
androidDestination,
`${cvModelFilename}.${androidExt}`
);
console.log( "Checking android model files..." );
let exist = true;
try {
await fs.access( androidModel );
} catch ( _ ) {
exist = false;
}
if ( exist ) {
console.log( "Android model exist!" );
return;
}
console.log(
`Android model files missing, downloading from '${binariesBaseDir}'...`
);
await fs.mkdir( androidDestination, { recursive: true } );
const dl = new DownloaderHelper( androidCV, androidDestination );
dl.on( "end", () => console.log( "Download Completed" ) );
dl.on( "error", err => console.log( "Download Failed", err ) );
await dl.start().catch( err => console.error( err ) );
console.log( "Downloaded!" );
const dl2 = new DownloaderHelper( androidGeo, androidDestination );
dl2.on( "end", () => console.log( "Download Completed" ) );
dl2.on( "error", err => console.log( "Download Failed", err ) );
await dl2.start().catch( err => console.error( err ) );
console.log( "Downloaded!" );
const dl3 = new DownloaderHelper( taxonomyCSV, androidDestination );
dl3.on( "end", () => console.log( "Download Completed" ) );
dl3.on( "error", err => console.log( "Download Failed", err ) );
await dl3.start().catch( err => console.error( err ) );
console.log( "Downloaded!" );
console.log( "Android done!" );
};
const downloadIOS = async () => {
const iosDestination = path.join( __dirname, "..", "ios" );
const iosModel = path.join( iosDestination, `${cvModelFilename}.${iosExt}` );
console.log( "Checking ios model files..." );
let exist = true;
try {
await fs.access( iosModel );
} catch ( _ ) {
exist = false;
}
if ( exist ) {
console.log( "ios model exist!" );
return;
}
console.log(
`iOS Model files missing, downloading from '${binariesBaseDir}'...`
);
await fs.mkdir( iosDestination, { recursive: true } );
const dl = new DownloaderHelper( iosCV, iosDestination );
dl.on( "end", () => console.log( "Download Completed" ) );
dl.on( "error", err => console.log( "Download Failed", err ) );
await dl.start().catch( err => console.error( err ) );
console.log( "Downloaded!" );
const dl2 = new DownloaderHelper( iosGeo, iosDestination );
dl2.on( "end", () => console.log( "Download Completed" ) );
dl2.on( "error", err => console.log( "Download Failed", err ) );
await dl2.start().catch( err => console.error( err ) );
console.log( "Downloaded!" );
const dl3 = new DownloaderHelper( taxonomyJSON, iosDestination );
dl3.on( "end", () => console.log( "Download Completed" ) );
dl3.on( "error", err => console.log( "Download Failed", err ) );
await dl3.start().catch( err => console.error( err ) );
console.log( "Downloaded!" );
console.log( "iOS done!" );
};
// eslint-disable-next-line no-unused-expressions, @typescript-eslint/no-unused-expressions
yargs
.usage( "Usage: $0 [args]" )
.option( "androidFlavor", {
alias: "f",
type: "string",
description: "Android flavor to download model files into"
} )
.command(
"$0",
"Download example model files if not present",
// eslint-disable-next-line @typescript-eslint/no-empty-function
() => {},
async argv => {
await downloadAndroid( argv );
await downloadIOS();
}
)
.help().argv;