UNPKG

image-dataset

Version:

Tool to build image dataset: collect, classify, review

336 lines (327 loc) 12.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.cli = cli; const fs_1 = require("fs"); const string_1 = require("@beenotung/tslib/string"); const file_1 = require("./file"); const config_1 = require("./config"); const env_1 = require("./env"); const setup_1 = require("./setup"); const child_process_1 = require("child_process"); const path_1 = require("path"); const db_1 = require("./db"); function parseArguments() { let keywords = []; let mode = null; let args = process.argv; if (args.length == 2) { showVersion(console.error); console.error('Error: missing arguments'); console.error('Run "npx image-dataset --help" to see help message'); process.exit(1); } for (let i = 2; i < args.length; i++) { let arg = args[i]; let next = args[i + 1]; switch (arg) { case '-h': case '--help': { showVersion(console.log); console.log(` Usage: npx image-dataset [options] Options: General: -h, --help Show this help message and exit. -v, --version Show the version number and exit. Download Mode: -l, --listFile <path> Specify a file containing a list of search terms. Each term should be on a new line. -s, --searchTerm "<term>" Add a single search term for processing. Use quotes if the term contains spaces. -d, --downloadDir <dir> Set the directory where downloads will be saved. Default is "./downloaded". Analysis Mode: -a, --analysis Run analysis mode instead of download mode. Benchmark Mode: -b, --benchmark Measure the time needed to classify images. Rename Mode: -r, --rename Rename image filenames by content hash. -u, --restore Restore unclassified images to downloaded directory. Web UI Mode: -w, --webUI Launch the web-based user interface. -p, --port <number> Set the port for the web UI. Default is 8100. -c, --complexity <number> Set the complexity for image classifier model. Over-complex setting may result in over-fitting. 1 for low complexity (default), 2-3 for moderate complexity, 4-5 for high complexity. Notes: - In download mode, at least one search term must be specified, either using --listFile or --searchTerm. - A mode is automatically selected when a mode-specific option is given. If none are selected, the help message will guide you. `.trim()); process.exit(0); } case '-v': case '--version': { showVersion(console.log); process.exit(0); } case '-l': case '--listFile': { if (!next) { showVersion(console.error); console.error('Error: missing file path after --listFile'); process.exit(1); } mode = 'download'; keywords.push(...readListFile(next)); i++; break; } case '-s': case '--searchTerm': { mode = 'download'; if (!next) { showVersion(console.error); console.error('Error: missing search term after --searchTerm'); process.exit(1); } keywords.push(next); i++; break; } case '-d': case '--downloadDir': { if (!next) { showVersion(console.error); console.error('Error: missing directory path after --downloadDir'); process.exit(1); } mode = 'download'; config_1.config.downloadedRootDir = next; i++; break; } case '-a': case '--analysis': { mode = 'analysis'; break; } case '-b': case '--benchmark': { mode = 'benchmark'; break; } case '-r': case '--rename': { mode = 'rename'; break; } case '-u': case '--restore': { mode = 'restore'; break; } case '-w': case '--webUI': { mode = 'webUI'; break; } case '-p': case '--port': { if (!next) { showVersion(console.error); console.error('Error: missing port number after --port'); process.exit(1); } env_1.env.PORT = +next; if (!env_1.env.PORT) { showVersion(console.error); console.error('Error: invalid port number after --port'); process.exit(1); } i++; break; } case '-c': case '--complexity': { if (!next) { showVersion(console.error); console.error('Error: missing complexity number after --complexity'); process.exit(1); } env_1.env.CLASSIFICATION_DIFFICULTY = +next; if (!(env_1.env.CLASSIFICATION_DIFFICULTY > 0)) { showVersion(console.error); console.error('Error: invalid complexity number after --complexity'); process.exit(1); } i++; break; } default: { showVersion(console.error); console.error('Error: unknown argument: ' + JSON.stringify(arg)); process.exit(1); } } } if (!mode) { console.error('Error: run mode not specified'); console.error('Run "npx image-dataset --help" to see help message'); process.exit(1); } if (mode == 'download' && keywords.length == 0) { showVersion(console.error); console.error('Error: missing keywords'); console.error('Either specify with --searchTerm or --listFile'); process.exit(1); } return { keywords, mode }; } function showVersion(log) { let pkg = require((0, file_1.resolveFile)('package.json')); log(`${pkg.name} v${pkg.version}`); } function readListFile(file) { if (!(0, fs_1.existsSync)(file)) { console.error('Error: missing file ' + JSON.stringify(file)); process.exit(1); } let text = (0, fs_1.readFileSync)(file).toString(); let lines = (0, string_1.extract_lines)(text); return lines; } async function cli() { let args = parseArguments(); await (0, setup_1.setupDB)(); if (args.mode == 'analysis') { let mod = await Promise.resolve().then(() => __importStar(require('./analysis'))); mod.analysis(); return; } if (args.mode == 'benchmark') { installPlaywright(); let mod = await Promise.resolve().then(() => __importStar(require('./benchmark'))); await mod.benchmark(); return; } if (args.mode == 'rename') { let mod = await Promise.resolve().then(() => __importStar(require('./rename-by-content-hash'))); mod.main(); return; } if (args.mode == 'restore') { let mod = await Promise.resolve().then(() => __importStar(require('./unclassify'))); mod.restoreUnclassified(); return; } if (args.mode == 'webUI') { setupGitIgnore([ ...gitIgnoreFiles.db, config_1.config.downloadedRootDir, config_1.config.datasetRootDir, config_1.config.classifiedRootDir, config_1.config.unclassifiedRootDir, config_1.config.baseModelDir, config_1.config.classifierModelDir, ]); installTensorflow(); let model = await Promise.resolve().then(() => __importStar(require('./model'))); await model.initClassNames(); let server = await Promise.resolve().then(() => __importStar(require('./server'))); server.startServer(env_1.env.PORT); return; } if (args.mode == 'download') { setupGitIgnore([...gitIgnoreFiles.db, config_1.config.downloadedRootDir]); installPlaywright(); let mod = await Promise.resolve().then(() => __importStar(require('./collect'))); await mod.main(args.keywords); return; } let mode = args.mode; console.error('Error: unknown mode: ' + JSON.stringify(mode)); console.error('Run "npx image-dataset --help" to see help message'); process.exit(1); } let gitIgnoreFiles = { db: [db_1.dbFile, db_1.dbFile + '-shm', db_1.dbFile + '-wal'], }; function setupGitIgnore(files) { let content = ''; try { content = (0, fs_1.readFileSync)('.gitignore', 'utf-8'); } catch (error) { // e.g. file not found } let newContent = '\n' + content.trim().replaceAll('\r\n', '\n') + '\n'; for (let file of files) { if (file.startsWith('./')) { file = file.slice(2); } if (!newContent.includes('\n' + file + '\n')) { newContent += file + '\n'; } } newContent = newContent.trim() + '\n'; if (newContent == content) { return; } (0, fs_1.writeFileSync)('.gitignore', newContent); } function installPlaywright() { (0, child_process_1.execSync)('npx playwright install chromium'); } function installTensorflow() { let filename = 'tensorflow.dll'; let src = 'node_modules/@tensorflow/tfjs-node/deps/lib/' + filename; // test direct dependency on @tensorflow/tfjs-node { let dest_dir = 'node_modules/@tensorflow/tfjs-node/lib/napi-v8'; let dest_file = (0, path_1.join)(dest_dir, filename); if ((0, fs_1.existsSync)(src) && (0, fs_1.existsSync)(dest_dir) && !(0, fs_1.existsSync)(dest_file)) { (0, fs_1.copyFileSync)(src, dest_file); return; } } // test indirect dependency on @tensorflow/tfjs-node { let dest_dir = 'node_modules/image-dataset/node_modules/@tensorflow/tfjs-node/lib/napi-v8'; let dest_file = (0, path_1.join)(dest_dir, filename); if ((0, fs_1.existsSync)(src) && (0, fs_1.existsSync)(dest_dir) && !(0, fs_1.existsSync)(dest_file)) { (0, fs_1.copyFileSync)(src, dest_file); return; } } }