diff --git a/classify-images.ts b/classify-images.ts index 49ae04b..803bcc0 100644 --- a/classify-images.ts +++ b/classify-images.ts @@ -19,6 +19,7 @@ import fs from 'fs'; import {Command} from 'commander'; import {dedent} from './utils'; +import path from 'path'; const temp = require('temp').track(); @@ -27,21 +28,27 @@ function list(val: string) { } interface CLIArgs { + port?: number; output: string; labels: string[]; max_width?: number; + randomOrder?: boolean; } const program = new Command(); program .version('2.1.1') .usage('[options] /path/to/images/*.jpg | images.txt') + .option('-p, --port ', 'Run on this port (default 4321)', parseInt) .option('-o, --output ', 'Path to output CSV file (default output.csv)', 'output.csv') .option('-l, --labels ', 'Comma-separated list of choices of labels', list, ['Yes', 'No']) .option('-w, --max_width ', 'Make the images this width when displaying in-browser', parseInt) + .option('-r, --random-order', + 'Serve images in random order, rather than sequentially. This is useful for ' + + 'generating valid subsamples or for minimizing collisions during group localturking.') .parse() if (program.args.length == 0) { @@ -62,11 +69,19 @@ if (fs.existsSync(options.output)) { const csvInfo = temp.openSync({suffix: '.csv'}); const templateInfo = temp.openSync({suffix: '.html'}); -const images = program.args; +let staticDir: string | null = null; +let images = program.args; if (images.length === 1 && images[0].endsWith('.txt')) { fs.writeSync(csvInfo.fd, 'path\n'); fs.writeSync(csvInfo.fd, fs.readFileSync(images[0], 'utf8')); } else { + const anyOutsideCwd = images.some(p => path.isAbsolute(p) || p.startsWith('..')); + if (anyOutsideCwd) { + staticDir = path.dirname(images[0]); + images = images.map(p => path.relative(staticDir!, p)); + } else { + staticDir = '.'; + } fs.writeSync(csvInfo.fd, 'path\n' + images.join('\n') + '\n'); } fs.closeSync(csvInfo.fd); @@ -94,6 +109,16 @@ html += dedent` fs.writeSync(templateInfo.fd, html); fs.closeSync(templateInfo.fd); -const args = ['localturk', '--static-dir', '.', templateInfo.path, csvInfo.path, options.output]; +const opts = []; +if (staticDir) { + opts.push('--static-dir', staticDir); +} +if (options.port) { + opts.push('--port', options.port.toString()); +} +if (options.randomOrder) { + opts.push('--random-order'); +} +const args = ['localturk', ...opts, templateInfo.path, csvInfo.path, options.output]; console.log('Running ', args.join(' ')); child_process.spawn(args[0], args.slice(1), {stdio: 'inherit'}); diff --git a/localturk.ts b/localturk.ts index 17d72f0..6b6c7ed 100644 --- a/localturk.ts +++ b/localturk.ts @@ -43,6 +43,7 @@ interface CLIArgs { const program = new Command(); +// If you add an option here, consider adding it in classify-images.ts as well. program .version('2.1.1') .usage('[options] template.html tasks.csv outputs.csv')