From f5b5ad23148ccfad4c9e1dc65ed3ce1ab5630235 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Sun, 28 Aug 2022 22:02:24 +0200 Subject: [PATCH 01/19] fix: Make preload.ts work again --- .erb/configs/webpack.config.main.prod.ts | 1 + .erb/configs/webpack.config.renderer.dev.ts | 3 +++ .erb/configs/webpack.config.renderer.prod.ts | 3 +++ src/main/main.ts | 3 +++ 4 files changed, 10 insertions(+) diff --git a/.erb/configs/webpack.config.main.prod.ts b/.erb/configs/webpack.config.main.prod.ts index 03420550..eb107786 100644 --- a/.erb/configs/webpack.config.main.prod.ts +++ b/.erb/configs/webpack.config.main.prod.ts @@ -24,6 +24,7 @@ const configuration: webpack.Configuration = { entry: { main: path.join(webpackPaths.srcMainPath, 'main.ts'), + preload: path.join(webpackPaths.srcMainPath, 'preload.ts'), }, output: { diff --git a/.erb/configs/webpack.config.renderer.dev.ts b/.erb/configs/webpack.config.renderer.dev.ts index 442d176a..0ab92a4b 100644 --- a/.erb/configs/webpack.config.renderer.dev.ts +++ b/.erb/configs/webpack.config.renderer.dev.ts @@ -51,6 +51,9 @@ const configuration: webpack.Configuration = { path: webpackPaths.distRendererPath, publicPath: '/', filename: 'renderer.dev.js', + library: { + type: 'umd', + }, }, module: { diff --git a/.erb/configs/webpack.config.renderer.prod.ts b/.erb/configs/webpack.config.renderer.prod.ts index ce191bc1..ed5d56f9 100644 --- a/.erb/configs/webpack.config.renderer.prod.ts +++ b/.erb/configs/webpack.config.renderer.prod.ts @@ -31,6 +31,9 @@ const configuration: webpack.Configuration = { path: webpackPaths.distRendererPath, publicPath: './', filename: 'renderer.js', + library: { + type: 'umd', + }, }, module: { diff --git a/src/main/main.ts b/src/main/main.ts index 18844e91..e13a92d1 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -68,6 +68,9 @@ const createWindow = async () => { icon: path.join(RESOURCES_PATH, 'assets', 'icon.png'), // TODO: Use default (safer) web preferences. webPreferences: { + preload: app.isPackaged + ? path.join(__dirname, 'preload.js') + : path.join(__dirname, '../../.erb/dll/preload.js'), // Allows the renderer to use Node.js APIs, e.g. `fs` and `child_process`. contextIsolation: false, nodeIntegration: true, From 4d3fe25b1f7714afbfe353d9e679a998b399c7d6 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Sun, 28 Aug 2022 22:25:49 +0200 Subject: [PATCH 02/19] chore: Install dependencies --- package-lock.json | 395 +++++++++++----- package.json | 5 + release/app/package-lock.json | 848 +++++++++++++++++++++++++++++++++- release/app/package.json | 5 +- 4 files changed, 1136 insertions(+), 117 deletions(-) diff --git a/package-lock.json b/package-lock.json index 13542fb7..ef45a4c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,9 +17,12 @@ "electron-debug": "^3.2.0", "electron-log": "^4.4.8", "electron-updater": "^5.2.1", + "exifreader": "^4.5.1", + "globby": "^13.1.2", "i18next": "^21.8.16", "lodash": "^4.17.21", "mapbox-gl": "^1.13.2", + "ndarray": "^1.0.19", "node-machine-id": "^1.1.12", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -38,10 +41,12 @@ "@types/jest": "28.1.8", "@types/lodash": "4.14.184", "@types/mapbox-gl": "1.13.4", + "@types/ndarray": "^1.0.11", "@types/node": "18.6.3", "@types/react": "18.0.17", "@types/react-dom": "18.0.6", "@types/react-test-renderer": "18.0.0", + "@types/sharp": "^0.30.5", "@types/terser-webpack-plugin": "5.2.0", "@types/universal-analytics": "0.4.5", "@types/webpack-bundle-analyzer": "4.4.2", @@ -1813,7 +1818,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1826,7 +1830,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -1835,7 +1838,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2546,6 +2548,12 @@ "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", "dev": true }, + "node_modules/@types/ndarray": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/ndarray/-/ndarray-1.0.11.tgz", + "integrity": "sha512-hOZVTN24zDHwCHaW7mF9n1vHJt83fZhNZ0YYRBwQGhA96yBWWDPTDDlqJatagHIOJB0a4xoNkNc+t/Cxd+6qUA==", + "dev": true + }, "node_modules/@types/node": { "version": "18.6.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz", @@ -2677,6 +2685,15 @@ "@types/node": "*" } }, + "node_modules/@types/sharp": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.30.5.tgz", + "integrity": "sha512-EhO29617AIBqxoVtpd1qdBanWpspk/kD2B6qTFRJ31Q23Rdf+DNU1xlHSwtqvwq1vgOqBwq1i38SX+HGCymIQg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -2914,6 +2931,26 @@ "node": ">=10" } }, + "node_modules/@typescript-eslint/experimental-utils/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@typescript-eslint/parser": { "version": "5.35.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.35.1.tgz", @@ -3024,6 +3061,26 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@typescript-eslint/utils": { "version": "5.35.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.35.1.tgz", @@ -3266,6 +3323,15 @@ } } }, + "node_modules/@xmldom/xmldom": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", + "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==", + "optional": true, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -4197,7 +4263,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -5974,7 +6039,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, "dependencies": { "path-type": "^4.0.0" }, @@ -7588,6 +7652,26 @@ "node": ">=10" } }, + "node_modules/eslint-config-erb/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint-config-erb/node_modules/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -7659,37 +7743,6 @@ "eslint-plugin-import": "*" } }, - "node_modules/eslint-import-resolver-typescript/node_modules/globby": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", - "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", - "dev": true, - "dependencies": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-import-resolver-typescript/node_modules/slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-import-resolver-webpack": { "version": "0.13.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.2.tgz", @@ -8129,6 +8182,26 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/eslint/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/espree": { "version": "9.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", @@ -8260,6 +8333,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/exifreader": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.5.1.tgz", + "integrity": "sha512-TYWL3TLhvPipgFZgaInomFj9ZR80hpq3BypCtSAWNOYVZ59N8oZtHir0kVOUqdOTqmfUhmZDdHn7gfhG/5F3WQ==", + "hasInstallScript": true, + "optionalDependencies": { + "@xmldom/xmldom": "^0.7.5" + } + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -8422,7 +8504,6 @@ "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -8438,7 +8519,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -8471,7 +8551,6 @@ "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -8571,7 +8650,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -9030,20 +9108,29 @@ "dev": true }, "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", "dependencies": { - "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", + "fast-glob": "^3.2.11", "ignore": "^5.2.0", "merge2": "^1.4.1", - "slash": "^3.0.0" + "slash": "^4.0.0" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -9662,7 +9749,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true, "engines": { "node": ">= 4" } @@ -9812,6 +9898,11 @@ "node": ">= 0.10" } }, + "node_modules/iota-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz", + "integrity": "sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==" + }, "node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -9887,6 +9978,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "node_modules/is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", @@ -9955,7 +10051,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -9982,7 +10077,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -10049,7 +10143,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "engines": { "node": ">=0.12.0" } @@ -12306,7 +12399,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -12324,7 +12416,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -12639,6 +12730,15 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/ndarray": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.0.19.tgz", + "integrity": "sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==", + "dependencies": { + "iota-array": "^1.0.0", + "is-buffer": "^1.0.2" + } + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -13337,7 +13437,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -14215,7 +14314,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -14788,7 +14886,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -14836,7 +14933,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -16123,7 +16219,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "dependencies": { "is-number": "^7.0.0" }, @@ -18894,7 +18989,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "requires": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -18903,14 +18997,12 @@ "@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" }, "@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "requires": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -19520,6 +19612,12 @@ "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", "dev": true }, + "@types/ndarray": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/ndarray/-/ndarray-1.0.11.tgz", + "integrity": "sha512-hOZVTN24zDHwCHaW7mF9n1vHJt83fZhNZ0YYRBwQGhA96yBWWDPTDDlqJatagHIOJB0a4xoNkNc+t/Cxd+6qUA==", + "dev": true + }, "@types/node": { "version": "18.6.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz", @@ -19651,6 +19749,15 @@ "@types/node": "*" } }, + "@types/sharp": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.30.5.tgz", + "integrity": "sha512-EhO29617AIBqxoVtpd1qdBanWpspk/kD2B6qTFRJ31Q23Rdf+DNU1xlHSwtqvwq1vgOqBwq1i38SX+HGCymIQg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -19824,6 +19931,20 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } } } }, @@ -19879,6 +20000,22 @@ "is-glob": "^4.0.3", "semver": "^7.3.7", "tsutils": "^3.21.0" + }, + "dependencies": { + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + } } }, "@typescript-eslint/utils": { @@ -20087,6 +20224,12 @@ "dev": true, "requires": {} }, + "@xmldom/xmldom": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.5.tgz", + "integrity": "sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==", + "optional": true + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -20818,7 +20961,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -22157,7 +22299,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, "requires": { "path-type": "^4.0.0" } @@ -23164,6 +23305,20 @@ "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } } } }, @@ -23382,6 +23537,20 @@ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -23434,27 +23603,6 @@ "is-core-module": "^2.10.0", "is-glob": "^4.0.3", "synckit": "^0.8.3" - }, - "dependencies": { - "globby": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", - "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", - "dev": true, - "requires": { - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^4.0.0" - } - }, - "slash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", - "dev": true - } } }, "eslint-import-resolver-webpack": { @@ -23856,6 +24004,14 @@ } } }, + "exifreader": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/exifreader/-/exifreader-4.5.1.tgz", + "integrity": "sha512-TYWL3TLhvPipgFZgaInomFj9ZR80hpq3BypCtSAWNOYVZ59N8oZtHir0kVOUqdOTqmfUhmZDdHn7gfhG/5F3WQ==", + "requires": { + "@xmldom/xmldom": "^0.7.5" + } + }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -23983,7 +24139,6 @@ "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", - "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -23996,7 +24151,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "requires": { "is-glob": "^4.0.1" } @@ -24025,7 +24179,6 @@ "version": "1.13.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, "requires": { "reusify": "^1.0.4" } @@ -24108,7 +24261,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -24445,17 +24597,22 @@ "dev": true }, "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", "requires": { - "array-union": "^2.1.0", "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", + "fast-glob": "^3.2.11", "ignore": "^5.2.0", "merge2": "^1.4.1", - "slash": "^3.0.0" + "slash": "^4.0.0" + }, + "dependencies": { + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + } } }, "globrex": { @@ -24920,8 +25077,7 @@ "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", - "dev": true + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" }, "immediate": { "version": "3.0.6", @@ -25034,6 +25190,11 @@ "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true }, + "iota-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz", + "integrity": "sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==" + }, "ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -25088,6 +25249,11 @@ "has-tostringtag": "^1.0.0" } }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "is-callable": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", @@ -25128,8 +25294,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -25147,7 +25312,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -25189,8 +25353,7 @@ "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { "version": "1.0.7", @@ -26898,8 +27061,7 @@ "merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "methods": { "version": "1.1.2", @@ -26911,7 +27073,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "requires": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -27136,6 +27297,15 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "ndarray": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.0.19.tgz", + "integrity": "sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==", + "requires": { + "iota-array": "^1.0.0", + "is-buffer": "^1.0.2" + } + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -27661,8 +27831,7 @@ "picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" }, "pidtree": { "version": "0.6.0", @@ -28252,8 +28421,7 @@ "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" }, "quick-lru": { "version": "5.1.1", @@ -28675,8 +28843,7 @@ "reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" }, "rfdc": { "version": "1.3.0", @@ -28711,7 +28878,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "requires": { "queue-microtask": "^1.2.2" } @@ -29699,7 +29865,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "requires": { "is-number": "^7.0.0" } diff --git a/package.json b/package.json index c12961d9..1bdc0bd8 100644 --- a/package.json +++ b/package.json @@ -107,9 +107,12 @@ "electron-debug": "^3.2.0", "electron-log": "^4.4.8", "electron-updater": "^5.2.1", + "exifreader": "^4.5.1", + "globby": "^13.1.2", "i18next": "^21.8.16", "lodash": "^4.17.21", "mapbox-gl": "^1.13.2", + "ndarray": "^1.0.19", "node-machine-id": "^1.1.12", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -128,10 +131,12 @@ "@types/jest": "28.1.8", "@types/lodash": "4.14.184", "@types/mapbox-gl": "1.13.4", + "@types/ndarray": "^1.0.11", "@types/node": "18.6.3", "@types/react": "18.0.17", "@types/react-dom": "18.0.6", "@types/react-test-renderer": "18.0.0", + "@types/sharp": "^0.30.5", "@types/terser-webpack-plugin": "5.2.0", "@types/universal-analytics": "0.4.5", "@types/webpack-bundle-analyzer": "4.4.2", diff --git a/release/app/package-lock.json b/release/app/package-lock.json index 28c963ff..6853bb9e 100644 --- a/release/app/package-lock.json +++ b/release/app/package-lock.json @@ -8,7 +8,853 @@ "name": "mbaza", "version": "1.3.1", "hasInstallScript": true, - "license": "AGPL-3.0-or-later" + "license": "AGPL-3.0-or-later", + "dependencies": { + "onnxruntime-node": "^1.12.1", + "sharp": "^0.30.7" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node_modules/node-abi": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.24.0.tgz", + "integrity": "sha512-YPG3Co0luSu6GwOBsmIdGW6Wx0NyNDLg/hriIyDllVsNwnI6UeqaWShxC3lbH4LtEQUgoLP3XR1ndXiDAWvmRw==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onnxruntime-common": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.12.1.tgz", + "integrity": "sha512-tWr/9nkQtzc61SH6zSE+3j2/HWBLgVcrXqS5HqQFitJ6hYNmNDcXwV2LYtFDH6CB9Qg987BMMv0ldaDUdB78VA==" + }, + "node_modules/onnxruntime-node": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.12.1.tgz", + "integrity": "sha512-H06kB4tRcZf93YDipL2nG5Oqs8WGhZzpWMgWUhH8r6ciGTZ85JrZpHuqRIabTS6Rls/IjbnBcrPXYPZnSgXqkQ==", + "os": [ + "win32", + "darwin", + "linux" + ], + "dependencies": { + "onnxruntime-common": "~1.12.1" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.7.tgz", + "integrity": "sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==", + "hasInstallScript": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.1", + "node-addon-api": "^5.0.0", + "prebuild-install": "^7.1.1", + "semver": "^7.3.7", + "simple-get": "^4.0.1", + "tar-fs": "^2.1.1", + "tunnel-agent": "^0.6.0" + }, + "engines": { + "node": ">=12.13.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" + }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" + }, + "node-abi": { + "version": "3.24.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.24.0.tgz", + "integrity": "sha512-YPG3Co0luSu6GwOBsmIdGW6Wx0NyNDLg/hriIyDllVsNwnI6UeqaWShxC3lbH4LtEQUgoLP3XR1ndXiDAWvmRw==", + "requires": { + "semver": "^7.3.5" + } + }, + "node-addon-api": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.0.0.tgz", + "integrity": "sha512-CvkDw2OEnme7ybCykJpVcKH+uAOLV2qLqiyla128dN9TkEWfrYmxG6C2boDe5KcNQqZF3orkqzGgOMvZ/JNekA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onnxruntime-common": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.12.1.tgz", + "integrity": "sha512-tWr/9nkQtzc61SH6zSE+3j2/HWBLgVcrXqS5HqQFitJ6hYNmNDcXwV2LYtFDH6CB9Qg987BMMv0ldaDUdB78VA==" + }, + "onnxruntime-node": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.12.1.tgz", + "integrity": "sha512-H06kB4tRcZf93YDipL2nG5Oqs8WGhZzpWMgWUhH8r6ciGTZ85JrZpHuqRIabTS6Rls/IjbnBcrPXYPZnSgXqkQ==", + "requires": { + "onnxruntime-common": "~1.12.1" + } + }, + "prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "sharp": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.7.tgz", + "integrity": "sha512-G+MY2YW33jgflKPTXXptVO28HvNOo9G3j0MybYAHeEmby+QuD2U98dT6ueht9cv/XDqZspSpIhoSW+BAKJ7Hig==", + "requires": { + "color": "^4.2.3", + "detect-libc": "^2.0.1", + "node-addon-api": "^5.0.0", + "prebuild-install": "^7.1.1", + "semver": "^7.3.7", + "simple-get": "^4.0.1", + "tar-fs": "^2.1.1", + "tunnel-agent": "^0.6.0" + } + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/release/app/package.json b/release/app/package.json index 36b0e28b..9ec3135f 100644 --- a/release/app/package.json +++ b/release/app/package.json @@ -13,5 +13,8 @@ "postinstall": "npm run electron-rebuild && npm run link-modules", "link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts" }, - "dependencies": {} + "dependencies": { + "onnxruntime-node": "^1.12.1", + "sharp": "^0.30.7" + } } From 18ab51c4fea9d4f8435d1945e7e0143c864c2e20 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 30 Aug 2022 17:17:16 +0200 Subject: [PATCH 03/19] fix: Add sharp to asarUnpack so it works in production --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1bdc0bd8..7a2712b8 100644 --- a/package.json +++ b/package.json @@ -243,7 +243,10 @@ "target": [ "AppImage" ], - "category": "Development" + "asarUnpack": [ + "node_modules/sharp/**" + ], + "category": "Utilities" }, "directories": { "app": "release/app", From 76a0ebdd7993d90023c9a16580b784828eb91f70 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Mon, 5 Sep 2022 15:33:54 +0200 Subject: [PATCH 04/19] refactor: Move RESOURCES_PATH to utils.ts --- src/main/main.ts | 4 +--- src/main/util.ts | 6 +++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/main.ts b/src/main/main.ts index e13a92d1..155903f3 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -14,7 +14,7 @@ import { autoUpdater } from 'electron-updater'; import path from 'path'; import MenuBuilder from './menu'; -import { resolveHtmlPath } from './util'; +import { resolveHtmlPath, RESOURCES_PATH } from './util'; // TODO: Drop `@electron/remote`: // https://github.com/electron/remote/blob/main/README.md @@ -54,8 +54,6 @@ const installExtensions = async () => { .catch(console.log); }; -const RESOURCES_PATH = app.isPackaged ? process.resourcesPath : path.join(__dirname, '..', '..'); - const createWindow = async () => { if (isDebug) { await installExtensions(); diff --git a/src/main/util.ts b/src/main/util.ts index fd79553e..3633fa08 100644 --- a/src/main/util.ts +++ b/src/main/util.ts @@ -1,4 +1,4 @@ -/* eslint import/prefer-default-export: off */ +import { app } from 'electron'; import path from 'path'; import { URL } from 'url'; @@ -11,3 +11,7 @@ export function resolveHtmlPath(htmlFileName: string) { } return `file:///${path.resolve(__dirname, '../renderer/', htmlFileName)}`; } + +export const RESOURCES_PATH = app.isPackaged + ? process.resourcesPath + : path.join(__dirname, '..', '..'); From 34f948f92af5dde94273300d9ed6d23628b9f780 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Sun, 4 Sep 2022 19:39:16 +0200 Subject: [PATCH 05/19] feat: Add assets/models directory --- assets/models/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 assets/models/.gitignore diff --git a/assets/models/.gitignore b/assets/models/.gitignore new file mode 100644 index 00000000..e1a699ac --- /dev/null +++ b/assets/models/.gitignore @@ -0,0 +1 @@ +*.onnx From d4959356b09385b9649455aa3ab0539c6e025ca8 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 6 Sep 2022 20:55:32 +0200 Subject: [PATCH 06/19] feat: Define models in src/common directory --- src/common/models.ts | 98 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 src/common/models.ts diff --git a/src/common/models.ts b/src/common/models.ts new file mode 100644 index 00000000..0c759db0 --- /dev/null +++ b/src/common/models.ts @@ -0,0 +1,98 @@ +export const MODELS = { + CENTRAL_AFRICAN_FORESTS: { + file: 'central_african_forests.onnx', + name: 'Central African forests', + labels: [ + 'Bird', + 'Blank', + 'Buffalo_African', + 'Cat_Golden', + 'Chevrotain_Water', + 'Chimpanzee', + 'Civet_African_Palm', + 'Duiker_Blue', + 'Duiker_Red', + 'Duiker_Yellow_Backed', + 'Elephant_African', + 'Genet', + 'Gorilla', + 'Guineafowl_Black', + 'Guineafowl_Crested', + 'Hog_Red_River', + 'Human', + 'Leopard_African', + 'Mandrillus', + 'Mongoose', + 'Mongoose_Black_Footed', + 'Monkey', + 'Pangolin', + 'Porcupine_Brush_Tailed', + 'Rail_Nkulengu', + 'Rat_Giant', + 'Rodent', + 'Squirrel', + ], + }, + EAST_AFRICAN_SAVANNAS: { + file: 'east_african_savannas.onnx', + name: 'East African savannas', + labels: [ + 'aardvark', + 'aardwolf', + 'baboon', + 'bat', + 'batearedfox', + 'buffalo', + 'bushbuck', + 'caracal', + 'cattle', + 'cheetah', + 'civet', + 'dikdik', + 'duiker', + 'eland', + 'elephant', + 'empty', + 'gazellegrants', + 'gazellethomsons', + 'genet', + 'giraffe', + 'guineafowl', + 'hare', + 'hartebeest', + 'hippopotamus', + 'honeybadger', + 'hyenaspotted', + 'hyenastriped', + 'impala', + 'insectspider', + 'jackal', + 'koribustard', + 'leopard', + 'lionfemale', + 'lionmale', + 'mongoose', + 'monkeyvervet', + 'ostrich', + 'otherbird', + 'porcupine', + 'reedbuck', + 'reptiles', + 'rhinoceros', + 'rodents', + 'secretarybird', + 'serval', + 'steenbok', + 'topi', + 'vulture', + 'warthog', + 'waterbuck', + 'wildcat', + 'wildebeest', + 'zebra', + 'zorilla', + ], + }, +}; + +export type Model = keyof typeof MODELS; From 4b5066a209f394e1a75ae49ad7ca22086794db22 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Mon, 5 Sep 2022 14:19:47 +0200 Subject: [PATCH 07/19] feat: Generic IPC implementation --- src/main/inference/index.ts | 3 +++ src/main/ipc/main.ts | 26 ++++++++++++++++++++++++++ src/main/ipc/renderer.ts | 15 +++++++++++++++ src/main/main.ts | 3 +++ src/main/preload.ts | 4 +++- 5 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/main/inference/index.ts create mode 100644 src/main/ipc/main.ts create mode 100644 src/main/ipc/renderer.ts diff --git a/src/main/inference/index.ts b/src/main/inference/index.ts new file mode 100644 index 00000000..f3bb7b6a --- /dev/null +++ b/src/main/inference/index.ts @@ -0,0 +1,3 @@ +export default async function runInference() { + return 42; +} diff --git a/src/main/ipc/main.ts b/src/main/ipc/main.ts new file mode 100644 index 00000000..546aa236 --- /dev/null +++ b/src/main/ipc/main.ts @@ -0,0 +1,26 @@ +// The IPC implementation is split into two separate files: +// one consumed by the main process build, and another by the renderer. +// This way dependencies which only work in the main process won't be bundled into the renderer. +import { ipcMain } from 'electron'; + +import runInference from '../inference'; + +// To expose a function via the `window.ipc` object in the renderer process: +// 1. Ensure it returns a promise (otherwise typings will be incorrect). +// 2. Add it to the object below. +// 3. Add its name to the corresponding object in `ipc/renderer.ts`. +const ipc = { runInference }; + +declare global { + interface Window { + ipc: typeof ipc; + } +} + +// Must be called from the main process. +export default function setupIpcMain() { + for (const [name, func] of Object.entries(ipc)) { + // eslint-disable-next-line @typescript-eslint/ban-types + ipcMain.handle(name, (_event, ...args) => (func as Function)(...args)); + } +} diff --git a/src/main/ipc/renderer.ts b/src/main/ipc/renderer.ts new file mode 100644 index 00000000..96b9a4c9 --- /dev/null +++ b/src/main/ipc/renderer.ts @@ -0,0 +1,15 @@ +// Refer to `ipc/main.ts` for explanation of this file. +import { ipcRenderer } from 'electron'; + +const ipc = ['runInference']; + +function ipcStub(name: string) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return (...args: any[]) => ipcRenderer.invoke(name, ...args); +} + +// Must be called from the renderer process in the preload script. +export default function setupIpcRenderer() { + const stubs = ipc.map((name) => [name, ipcStub(name)]); + window.ipc = Object.fromEntries(stubs); +} diff --git a/src/main/main.ts b/src/main/main.ts index 155903f3..5bf9014f 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -13,6 +13,7 @@ import log from 'electron-log'; import { autoUpdater } from 'electron-updater'; import path from 'path'; +import setupIpcMain from './ipc/main'; import MenuBuilder from './menu'; import { resolveHtmlPath, RESOURCES_PATH } from './util'; @@ -20,6 +21,8 @@ import { resolveHtmlPath, RESOURCES_PATH } from './util'; // https://github.com/electron/remote/blob/main/README.md require('@electron/remote/main').initialize(); +setupIpcMain(); + class AppUpdater { constructor() { log.transports.file.level = 'info'; diff --git a/src/main/preload.ts b/src/main/preload.ts index 4b24e0bd..be0ac69b 100644 --- a/src/main/preload.ts +++ b/src/main/preload.ts @@ -1 +1,3 @@ -// TODO: Expose a limited API to the main process via IPC. +import setupIpcRenderer from './ipc/renderer'; + +setupIpcRenderer(); From 486919ca554cad2d0713610765fbea3e4fb166ac Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 6 Sep 2022 20:56:05 +0200 Subject: [PATCH 08/19] feat: Implement runInference() --- src/main/inference/index.ts | 57 +++++++++++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/src/main/inference/index.ts b/src/main/inference/index.ts index f3bb7b6a..cf7a818a 100644 --- a/src/main/inference/index.ts +++ b/src/main/inference/index.ts @@ -1,3 +1,56 @@ -export default async function runInference() { - return 42; +import ndarray from 'ndarray'; +import * as ort from 'onnxruntime-node'; +import { join } from 'path'; +import sharp from 'sharp'; + +import { Model, MODELS } from '../../common/models'; +import { RESOURCES_PATH } from '../util'; + +const WIDTH = 512; +const HEIGHT = 384; +const CHANNELS = 3; + +function modelPath(model: Model) { + return join(RESOURCES_PATH, 'assets', 'models', MODELS[model].file); +} + +async function readPhoto(path: string) { + const raw = await sharp(path).resize(WIDTH, HEIGHT, { fit: 'fill' }).raw().toBuffer(); + + // Reshape and normalize to match model input shape. + const srcShape = [HEIGHT, WIDTH, CHANNELS]; + const dstShape = [CHANNELS, HEIGHT, WIDTH]; + const src = ndarray(raw, srcShape); + const dst = ndarray(new Float32Array(raw.length), dstShape); + for (let i = 0; i < HEIGHT; i += 1) { + for (let j = 0; j < WIDTH; j += 1) { + for (let k = 0; k < CHANNELS; k += 1) { + dst.set(k, i, j, src.get(i, j, k) / 255); + } + } + } + return dst; +} + +function attachLabels(model: Model, output: ort.Tensor) { + const entries = MODELS[model].labels.map((label, idx) => [label, output.data[idx]]); + return Object.fromEntries(entries); +} + +export default async function runInference(model: Model, photoPaths: string[]) { + const session = await ort.InferenceSession.create(modelPath(model)); + const results = []; + // Intentionally await in loop: attempting to process + // all photos at once would consume too much resources. + /* eslint-disable no-await-in-loop */ + for (const path of photoPaths) { + const photo = await readPhoto(path); + // The first dimension of the tensor is the photo index (used for batch processing). + // TODO: Process photos in batches to improve performance. + const input = new ort.Tensor('float32', photo.data, [1, ...photo.shape]); + const { output } = await session.run({ input }); + results.push(attachLabels(model, output)); + } + /* eslint-enable no-await-in-loop */ + return results; } From a5acfbf8d7a904084c9e063e063cc57638259bcb Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Wed, 7 Sep 2022 03:32:23 +0200 Subject: [PATCH 09/19] feat: Implement getTopPredictions() --- src/renderer/inference/getTopPredictions.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/renderer/inference/getTopPredictions.ts diff --git a/src/renderer/inference/getTopPredictions.ts b/src/renderer/inference/getTopPredictions.ts new file mode 100644 index 00000000..434b01e9 --- /dev/null +++ b/src/renderer/inference/getTopPredictions.ts @@ -0,0 +1,19 @@ +import _ from 'lodash'; + +export type InferenceResult = Record; + +function f(result: InferenceResult) { + const top = _.sortBy(_.toPairs(result), 1).reverse(); + return { + pred_1: top[0][0], + pred_2: top[1][0], + pred_3: top[2][0], + score_1: top[0][1], + score_2: top[1][1], + score_3: top[2][1], + }; +} + +export default function getTopPredictions(results: InferenceResult[]) { + return results.map(f); +} From ebdc9d56e06e78ea73b1b0e0672f3e769773561f Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 6 Sep 2022 22:31:07 +0200 Subject: [PATCH 10/19] feat: Implement getPathMetadata() --- src/renderer/inference/getPathMetadata.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/renderer/inference/getPathMetadata.ts diff --git a/src/renderer/inference/getPathMetadata.ts b/src/renderer/inference/getPathMetadata.ts new file mode 100644 index 00000000..99bb6616 --- /dev/null +++ b/src/renderer/inference/getPathMetadata.ts @@ -0,0 +1,21 @@ +import path from 'path'; + +function f(relativePath: string) { + let station = ''; + let camera = ''; + let pathDate = ''; + for (const part of relativePath.split(path.sep)) { + if (part.startsWith('STATION')) { + station = part; + } else if (part.startsWith('CAM')) { + camera = part.substring(3); + } else if (/^\d{4}-\d{2}-\d{2}$/.test(part)) { + pathDate = part; + } + } + return { station, camera, path_date: pathDate }; +} + +export default function getPathMetadata(relativePaths: string[]) { + return relativePaths.map(f); +} From f52a2d54939ad28527c4c58628cd6aeac3f7bc30 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 6 Sep 2022 23:46:27 +0200 Subject: [PATCH 11/19] feat: Implement getExifMetadata() --- src/renderer/inference/getExifMetadata.ts | 35 +++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/renderer/inference/getExifMetadata.ts diff --git a/src/renderer/inference/getExifMetadata.ts b/src/renderer/inference/getExifMetadata.ts new file mode 100644 index 00000000..5125d4ac --- /dev/null +++ b/src/renderer/inference/getExifMetadata.ts @@ -0,0 +1,35 @@ +import ExifReader from 'exifreader'; +import { readFile } from 'fs/promises'; +import _ from 'lodash'; + +function getDateTime(tags: ExifReader.ExpandedTags) { + const dateTime = _.get(tags, 'exif.DateTimeOriginal.value[0]'); + if (typeof dateTime === 'string') { + const [date, time] = dateTime.split(' '); + return { exif_date: date.replaceAll(':', '-'), exif_time: time }; + } + return { exif_date: '', exif_time: '' }; +} + +function getCoords(tags: ExifReader.ExpandedTags) { + if (tags.gps) { + const { Longitude, Latitude } = tags.gps; + return { exif_gps_long: Longitude, exif_gps_lat: Latitude }; + } + return { exif_gps_long: undefined, exif_gps_lat: undefined }; +} + +function f(photo: Buffer) { + const tags = ExifReader.load(photo, { expanded: true }); + return { ...getDateTime(tags), ...getCoords(tags) }; +} + +export default async function getExifMetadata(photosAbsolute: string[]) { + const result = []; + // TODO: Read photos concurrently to increase performance. + for (const photoPath of photosAbsolute) { + const photo = await readFile(photoPath); // eslint-disable-line no-await-in-loop + result.push(f(photo)); + } + return result; +} From e80150de81e8f51e6b75884cdd857513b784eaa6 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Wed, 7 Sep 2022 00:40:04 +0200 Subject: [PATCH 12/19] feat: Implement getWcsMetadata() --- src/renderer/inference/getWcsMetadata.ts | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/renderer/inference/getWcsMetadata.ts diff --git a/src/renderer/inference/getWcsMetadata.ts b/src/renderer/inference/getWcsMetadata.ts new file mode 100644 index 00000000..d724e87f --- /dev/null +++ b/src/renderer/inference/getWcsMetadata.ts @@ -0,0 +1,42 @@ +import path from 'path'; + +import { taxonMap } from '../constants/taxons'; + +const remote = require('@electron/remote'); + +export default function getWcsMetadata({ + projectId, + deploymentId, + location, + date, + time, + prediction, + score, +}: { + projectId: string; + deploymentId: string; + location: string; + date: string; + time: string; + prediction: string; + score: number; +}) { + return { + project_id: projectId, + deployment_id: deploymentId, + image_id: path.parse(location).name, + location, + identified_by: `Mbaza-AI-${remote.app.getVersion()}`, + ...taxonMap[prediction], + uncertainty: score, + timestamp: `${date} ${time}`, + number_of_objects: 1, + highlighted: undefined, + age: undefined, + sex: 'Unknown', + animal_recognizable: undefined, + individual_id: undefined, + individual_animal_notes: undefined, + markings: undefined, + }; +} From 3a691f232a1ce5bf2ce9fa5840d5cc8935437218 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Wed, 7 Sep 2022 01:50:35 +0200 Subject: [PATCH 13/19] feat: Implement getStationMetadata() --- src/renderer/inference/getStationMetadata.ts | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/renderer/inference/getStationMetadata.ts diff --git a/src/renderer/inference/getStationMetadata.ts b/src/renderer/inference/getStationMetadata.ts new file mode 100644 index 00000000..5e58c782 --- /dev/null +++ b/src/renderer/inference/getStationMetadata.ts @@ -0,0 +1,35 @@ +import { csvParse } from 'd3-dsv'; +import { readFile } from 'fs/promises'; + +type Row = { + camStation: string; + Lat: string; + Lon: string; +}; + +type StationMetadata = { + grid_file_lat: string | undefined; + grid_file_long: string | undefined; +}; + +async function readStationsCsv(stationsCsvPath: string) { + if (!stationsCsvPath) return new Map(); + const stationsCsv = await readFile(stationsCsvPath); + const rows = csvParse(stationsCsv.toString()) as unknown as Row[]; + return new Map( + rows.map(({ camStation, Lat, Lon }) => [ + camStation, + { grid_file_lat: Lat, grid_file_long: Lon }, + ]) + ); +} + +export default async function getStationMetadata( + rows: { station: string }[], + stationsCsvPath: string +): Promise { + const stationsMap = await readStationsCsv(stationsCsvPath); + return rows.map( + (row) => stationsMap.get(row.station) || { grid_file_lat: undefined, grid_file_long: undefined } + ); +} From 72e0ce962a7bfe4c6cfd55c4bd8bc293bfc5382b Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 6 Sep 2022 11:04:40 +0200 Subject: [PATCH 14/19] feat: Stub implementation for prepareResults() --- src/renderer/inference/index.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/renderer/inference/index.ts diff --git a/src/renderer/inference/index.ts b/src/renderer/inference/index.ts new file mode 100644 index 00000000..6acdbef6 --- /dev/null +++ b/src/renderer/inference/index.ts @@ -0,0 +1,25 @@ +import { csvFormat } from 'd3-dsv'; +import { writeFile } from 'fs/promises'; +import { globby } from 'globby'; + +import { Model } from '../../common/models'; + +function listPhotos(dir: string) { + // Formats supported by `sharp`: https://sharp.pixelplumbing.com/#formats + // File extensions: https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types + const pattern = '**/*.(jpg|jpeg|jfif|pjpeg|pjp|png|webp|gif|avif|tif|tiff)'; + return globby(pattern, { cwd: dir, caseSensitiveMatch: false, onlyFiles: true }); +} + +export default async function prepareResults( + inputPath: string, + outputPath: string, + _stationsCsvPath: string, + _model: Model, + _projectId: string, + _deploymentId: string +) { + const photos = await listPhotos(inputPath); + const rows = photos.map((location) => ({ location })); + await writeFile(outputPath, csvFormat(rows)); +} From 6555614e843242164b5440cef330852d2ba0ca98 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Wed, 7 Sep 2022 03:10:38 +0200 Subject: [PATCH 15/19] feat: Implement prepareResults() --- src/renderer/inference/index.ts | 49 +++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/renderer/inference/index.ts b/src/renderer/inference/index.ts index 6acdbef6..02ba0453 100644 --- a/src/renderer/inference/index.ts +++ b/src/renderer/inference/index.ts @@ -1,8 +1,15 @@ import { csvFormat } from 'd3-dsv'; import { writeFile } from 'fs/promises'; import { globby } from 'globby'; +import _ from 'lodash'; +import path from 'path'; import { Model } from '../../common/models'; +import getExifMetadata from './getExifMetadata'; +import getPathMetadata from './getPathMetadata'; +import getStationMetadata from './getStationMetadata'; +import getTopPredictions, { InferenceResult } from './getTopPredictions'; +import getWcsMetadata from './getWcsMetadata'; function listPhotos(dir: string) { // Formats supported by `sharp`: https://sharp.pixelplumbing.com/#formats @@ -14,12 +21,42 @@ function listPhotos(dir: string) { export default async function prepareResults( inputPath: string, outputPath: string, - _stationsCsvPath: string, - _model: Model, - _projectId: string, - _deploymentId: string + stationsCsvPath: string, + model: Model, + projectId: string, + deploymentId: string ) { - const photos = await listPhotos(inputPath); - const rows = photos.map((location) => ({ location })); + const photosRelative = await listPhotos(inputPath); + const photosAbsolute = photosRelative.map((photo) => path.join(inputPath, photo)); + + const results: InferenceResult[] = await window.ipc.runInference(model, photosAbsolute); + const topPredictions = getTopPredictions(results); + const pathMetadata = getPathMetadata(photosRelative); + const exifMetadata = await getExifMetadata(photosAbsolute); + const stationMetadata = await getStationMetadata(pathMetadata, stationsCsvPath); + + const rows = _.range(photosRelative.length).map((i) => { + const date = exifMetadata[i].exif_date || pathMetadata[i].path_date; + return { + ...getWcsMetadata({ + projectId, + deploymentId, + location: photosRelative[i], + date, + time: exifMetadata[i].exif_time, + prediction: topPredictions[i].pred_1, + score: topPredictions[i].score_1, + }), + date, + coordinates_long: stationMetadata[i].grid_file_long || exifMetadata[i].exif_gps_long, + coordinates_lat: stationMetadata[i].grid_file_lat || exifMetadata[i].exif_gps_lat, + ...pathMetadata[i], + ...exifMetadata[i], + ...stationMetadata[i], + ...topPredictions[i], + ...results[i], + label: topPredictions[i].pred_1, + }; + }); await writeFile(outputPath, csvFormat(rows)); } From dc5f3c17a76aaeb51166791f18dc0af2e3051766 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 6 Sep 2022 17:38:20 +0200 Subject: [PATCH 16/19] feat: Simplified LogViewer component --- src/renderer/components/LogViewer.module.scss | 10 +++++ src/renderer/components/LogViewer.tsx | 38 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/renderer/components/LogViewer.module.scss create mode 100644 src/renderer/components/LogViewer.tsx diff --git a/src/renderer/components/LogViewer.module.scss b/src/renderer/components/LogViewer.module.scss new file mode 100644 index 00000000..42a25949 --- /dev/null +++ b/src/renderer/components/LogViewer.module.scss @@ -0,0 +1,10 @@ +.card { + .preloader { + margin-top: 20px; + text-align: center; + + .message { + margin-top: 20px; + } + } +} diff --git a/src/renderer/components/LogViewer.tsx b/src/renderer/components/LogViewer.tsx new file mode 100644 index 00000000..463e8748 --- /dev/null +++ b/src/renderer/components/LogViewer.tsx @@ -0,0 +1,38 @@ +import { Callout, Card, Elevation, H5, H6, Intent, Spinner } from '@blueprintjs/core'; + +import styles from './LogViewer.module.scss'; + +export enum TaskStatus { + NOT_STARTED, + IN_PROGRESS, + SUCCESS, + FAILURE, +} + +type Props = { + title: string; + status: TaskStatus; + message: string; +}; + +export default function LogViewer(props: Props) { + const { title, message, status } = props; + + if (status === TaskStatus.NOT_STARTED) return null; + return ( + +
{title}
+ {status === TaskStatus.IN_PROGRESS ? ( +
+ +
{message}
+
+ ) : ( + + )} +
+ ); +} From a13a7720be42ba9cec2022290d48c714bb25ca8e Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 6 Sep 2022 18:20:39 +0200 Subject: [PATCH 17/19] refactor: Replace computePredictions() with prepareResults() in Classifier --- src/renderer/components/Classifier.tsx | 189 +++++-------------------- 1 file changed, 36 insertions(+), 153 deletions(-) diff --git a/src/renderer/components/Classifier.tsx b/src/renderer/components/Classifier.tsx index 519b14c7..86661456 100644 --- a/src/renderer/components/Classifier.tsx +++ b/src/renderer/components/Classifier.tsx @@ -8,147 +8,53 @@ import { Intent, Radio, RadioGroup, - Toaster, } from '@blueprintjs/core'; -import { ChildProcessWithoutNullStreams, spawn } from 'child_process'; -import fs from 'fs'; -import { TFunction } from 'i18next'; -import path from 'path'; import React, { useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; -import { isDev, isLinux, isWin, rootModelsDirectory } from '../utils/environment'; +import { Model, MODELS } from '../../common/models'; +import prepareResults from '../inference'; import { openCsvDialog, openDirectoryDialog, saveCsvDialog } from '../utils/fileDialog'; import styles from './Classifier.module.scss'; -import MissingModelsMessage from './MissingModelsMessage'; +import LogViewer, { TaskStatus } from './LogViewer'; import PathInput from './PathInput'; -import PythonLogViewer from './PythonLogViewer'; -const toaster = Toaster.create({}); - -function displayErrorToast(message: string) { - toaster.show({ - message, - intent: Intent.DANGER, - icon: 'warning-sign', - }); -} - -function runModelProcess(baseArgs: string[], t: TFunction): ChildProcessWithoutNullStreams | null { - let workdir; - let program; - const args = []; - const command = 'infer_to_csv'; - - if (isDev) { - workdir = path.join(rootModelsDirectory, 'runner'); - program = path.join(workdir, 'venv', 'bin', 'python3'); - args.push('main.py'); - args.push(command); - } else if (isWin) { - workdir = path.join(rootModelsDirectory, 'runner_win', 'main'); - program = path.join(workdir, 'main.exe'); - args.push(command); - args.push('--pytorch_num_workers=0'); - } else if (isLinux) { - workdir = path.join(rootModelsDirectory, 'runner_linux', 'main'); - program = path.join(workdir, 'main'); - args.push(command); - } else { - throw new Error(`Unsupported operating system for running models: ${process.platform}`); - } - - if (!fs.existsSync(program)) { - displayErrorToast(t('classify.modelExecutableNotFound', { program })); - return null; +function useStatusMessage(status: TaskStatus) { + const { t } = useTranslation(); + switch (status) { + case TaskStatus.IN_PROGRESS: + return t('classify.inProgress'); + case TaskStatus.SUCCESS: + return t('classify.success'); + case TaskStatus.FAILURE: + return t('classify.failure'); + default: + return ''; } - - args.push(...baseArgs); - return spawn(program, args, { cwd: workdir }); } -const computePredictions = ( - inputPath: string, - outputPath: string, - gridFilePath: string, - modelName: string, - projectId: string, - deploymentId: string, - setLogMessage: (value: string) => void, - setIsRunning: (value: boolean) => void, - setExitCode: (value: number | null | undefined) => void, - t: TFunction -) => { - const modelWeightsPath = path.join(rootModelsDirectory, modelName, 'trained_model.pkl'); - - const args: string[] = [ - '--input_folder', - inputPath, - '--output', - outputPath, - '--model', - modelWeightsPath, - '--project_id', - projectId, - '--deployment_id', - deploymentId, - '--overwrite', - ]; - - if (gridFilePath) { - args.push('--grid_file', gridFilePath); - } - if (!fs.existsSync(modelWeightsPath)) { - displayErrorToast(t('classify.modelWeightsNotFound', { modelWeightsPath })); - return; - } - - // TODO: Fix and simplify logging: - // * Progress bar is not properly displayed in the output (#89). - // * Is `changeLogMessageType` necessary? - // * Are Redux actions appropriate for this use case? - const process = runModelProcess(args, t); - if (process !== null) { - setLogMessage(''); - setExitCode(undefined); - setIsRunning(true); - process.stdout.on('data', (data) => { - setLogMessage(`${data}`); - }); - process.stderr.on('data', (data) => { - // eslint-disable-next-line no-console - console.log(`classifier stderr: ${data}`); - setLogMessage(`${data}`); - }); - process.on('exit', (exitCode) => { - // eslint-disable-next-line no-console - console.log(`Classifier exited with code ${exitCode}`); - setIsRunning(false); - setExitCode(exitCode); - }); - } -}; - export default function Classifier() { const { t } = useTranslation(); - const [isRunning, setIsRunning] = useState(false); - const [exitCode, setExitCode] = useState(); - + const [status, setStatus] = useState(TaskStatus.NOT_STARTED); const [inputPath, setInputPath] = useState(''); const [outputPath, setOutputPath] = useState(''); const [stationsCsvPath, setStationsCsvPath] = useState(''); + const [model, setModel] = useState('CENTRAL_AFRICAN_FORESTS'); const [projectId, setProjectId] = useState(''); const [deploymentId, setDeploymentId] = useState(''); - const [logMessage, setLogMessage] = useState(''); - // TODO: Detect available models instead of hardcoding them. Display a warning - // if there are no models available. - const models = [ - { label: 'Central African forests', value: 'central_african_forests' }, - { label: 'East African savannas', value: 'east_african_savannas' }, - ]; - const [modelName, setModelName] = useState(models[0].value); - const rootModelsDirectoryExists = fs.existsSync(rootModelsDirectory); + const message = useStatusMessage(status); + + const runInference = async () => { + setStatus(TaskStatus.IN_PROGRESS); + try { + await prepareResults(inputPath, outputPath, stationsCsvPath, model, projectId, deploymentId); + setStatus(TaskStatus.SUCCESS); + } catch (e) { + console.error(e); // eslint-disable-line no-console + setStatus(TaskStatus.FAILURE); + } + }; const classifierFormView = (
@@ -178,12 +84,12 @@ export default function Classifier() { { - setModelName(event.currentTarget.value); + setModel(event.currentTarget.value as Model); }} - selectedValue={modelName} + selectedValue={model} > - {models.map((model) => ( - + {Object.entries(MODELS).map(([key, m]) => ( + ))} @@ -208,34 +114,11 @@ export default function Classifier() { className={styles.button} text={t('classify.find')} icon="predictive-analysis" - onClick={() => { - computePredictions( - inputPath, - outputPath, - stationsCsvPath, - modelName, - projectId, - deploymentId, - setLogMessage, - setIsRunning, - setExitCode, - t - ); - }} - disabled={isRunning || inputPath === '' || outputPath === ''} + onClick={runInference} + disabled={status === TaskStatus.IN_PROGRESS || !inputPath || !outputPath} /> - {exitCode !== undefined || isRunning ? ( - - ) : null} +
); @@ -244,7 +127,7 @@ export default function Classifier() {

{t('classify.title')}

- {rootModelsDirectoryExists ? classifierFormView : } + {classifierFormView}
From 6bd4fd2d8dc7d7cabe0ff356b2aca45f037063ab Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Tue, 6 Sep 2022 18:11:56 +0200 Subject: [PATCH 18/19] feat: Update translations --- assets/translations.json | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/assets/translations.json b/assets/translations.json index 784a552d..4b8c2a65 100644 --- a/assets/translations.json +++ b/assets/translations.json @@ -62,8 +62,6 @@ "find": "Find animals!", "logTitle": "Classifier output", "inProgress": "Please wait. Animal detection in progress. This may take a long time.", - "modelExecutableNotFound": "Could not find the model executable. Please make sure you unpacked the models in the correct directory. It should be in {{program}}.", - "modelWeightsNotFound": "Could not find the model weights file. Please make sure you unpacked the models in the correct directory. Model weights should be in {{modelWeightsPath}}.", "modelsDirectoryMissing": { "title": "Models directory not found", "description1": "You need to obtain a zip file containing the AI models and unzip it in the program's main directory. Please make sure that you have a ", @@ -71,7 +69,7 @@ }, "success": "Species classification completed.", "failure": "Species classification failed.", - "info": "

Here you can detect animals in images. If you would like to detect animals in videos, please go to Extract frames tab first.

Please select an input directory containing subfolders with images.

Please select an output CSV file where the results of the detection will be stored.

You can optionally provide project and deployment IDs which will be used to populate the output CSV.

You can also provide a CSV with the latitude and longitude coordinates of camera stations, which will automatically generate a map.

After the detection is complete, explore the results in the Explore results tab.

" + "info": "

Here you can detect animals in images.

Please select an input directory containing subfolders with images.

Please select an output CSV file where the results of the detection will be stored.

You can optionally provide project and deployment IDs which will be used to populate the output CSV.

You can also provide a CSV with the latitude and longitude coordinates of camera stations, which will automatically generate a map.

After the detection is complete, explore the results in the Explore results tab.

" }, "explore": { "specifyPaths": "Specify file and directory paths to explore", @@ -199,8 +197,6 @@ "find": "Trouver des animaux !", "logTitle": "Sortie du classifieur", "inProgress": "Veuillez patienter. Détection d'animaux en cours. Cela peut prendre beaucoup de temps.", - "modelExecutableNotFound": "Le modèle d'exécutable n'a pas été trouver. Veuillez vous assurer que vous avez décompressé les modèles dans le bon dossier. Il devrait être dans {{program}}.", - "modelWeightsNotFound": "Le fichier des poids modèles n'a pas été trouvé. Veuillez vous assurer que vous avez décompressé les modèles dans le bon dossier. Les poids des modèles doivent être dans le dossier {{modelWeightsPath}}.", "modelsDirectoryMissing": { "title": "Le répertoire des modèles n'a pas été trouvé", "description1": "Vous devez obtenir un fichier zip contenant les modèles d'IA et le décompresser dans le dossier principal du programme. Veuillez vous assurer que vous disposez d'un répertoire ", @@ -208,7 +204,7 @@ }, "success": "La détection des animaux est terminée.", "failure": "La détection des animaux a échoué.", - "info": "

Vous pouvez ici détecter des animaux dans des images. Si vous souhaitez détecter des animaux dans des vidéos, veuillez d'abord aller dans l'onglet Extraire des images.

Veuillez sélectionner un répertoire d'entrée contenant des sous-dossiers avec des images.

Veuillez sélectionner un fichier .csv de sortie où seront stockés les résultats de la détection.

Vous pouvez éventuellement fournir des identifiants de projet et de déploiement qui seront utilisés pour alimenter le CSV de sortie.

Vous pouvez également fournir un CSV avec les coordonnées de latitude et de longitude des stations de caméra, ce qui générera une carte.

After the detection is complete, explore the results in the Explore results tab.

" + "info": "

Vous pouvez ici détecter des animaux dans des images.

Veuillez sélectionner un répertoire d'entrée contenant des sous-dossiers avec des images.

Veuillez sélectionner un fichier .csv de sortie où seront stockés les résultats de la détection.

Vous pouvez éventuellement fournir des identifiants de projet et de déploiement qui seront utilisés pour alimenter le CSV de sortie.

Vous pouvez également fournir un CSV avec les coordonnées de latitude et de longitude des stations de caméra, ce qui générera une carte.

After the detection is complete, explore the results in the Explore results tab.

" }, "explore": { "specifyPaths": "Specify file and directory paths to explore (TODO)", From 609cc82616e07e1312d6ed075b027c651ec44da6 Mon Sep 17 00:00:00 2001 From: Kamil Zyla Date: Wed, 7 Sep 2022 05:36:49 +0200 Subject: [PATCH 19/19] fix: Handle corrupt images --- src/main/inference/index.ts | 24 +++++++++++++++-------- src/renderer/inference/getExifMetadata.ts | 13 ++++++++---- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/main/inference/index.ts b/src/main/inference/index.ts index cf7a818a..e28f59c9 100644 --- a/src/main/inference/index.ts +++ b/src/main/inference/index.ts @@ -32,8 +32,11 @@ async function readPhoto(path: string) { return dst; } -function attachLabels(model: Model, output: ort.Tensor) { - const entries = MODELS[model].labels.map((label, idx) => [label, output.data[idx]]); +function buildResult(model: Model, output?: ort.Tensor) { + const entries = MODELS[model].labels.map((label, idx) => [ + label, + output ? output.data[idx] : undefined, + ]); return Object.fromEntries(entries); } @@ -44,12 +47,17 @@ export default async function runInference(model: Model, photoPaths: string[]) { // all photos at once would consume too much resources. /* eslint-disable no-await-in-loop */ for (const path of photoPaths) { - const photo = await readPhoto(path); - // The first dimension of the tensor is the photo index (used for batch processing). - // TODO: Process photos in batches to improve performance. - const input = new ort.Tensor('float32', photo.data, [1, ...photo.shape]); - const { output } = await session.run({ input }); - results.push(attachLabels(model, output)); + try { + const photo = await readPhoto(path); + // The first dimension of the tensor is the photo index (used for batch processing). + // TODO: Process photos in batches to improve performance. + const input = new ort.Tensor('float32', photo.data, [1, ...photo.shape]); + const { output } = await session.run({ input }); + results.push(buildResult(model, output)); + } catch (e) { + console.error(e); // eslint-disable-line no-console + results.push(buildResult(model)); + } } /* eslint-enable no-await-in-loop */ return results; diff --git a/src/renderer/inference/getExifMetadata.ts b/src/renderer/inference/getExifMetadata.ts index 5125d4ac..ce9af885 100644 --- a/src/renderer/inference/getExifMetadata.ts +++ b/src/renderer/inference/getExifMetadata.ts @@ -2,7 +2,7 @@ import ExifReader from 'exifreader'; import { readFile } from 'fs/promises'; import _ from 'lodash'; -function getDateTime(tags: ExifReader.ExpandedTags) { +function getDateTime(tags?: ExifReader.ExpandedTags) { const dateTime = _.get(tags, 'exif.DateTimeOriginal.value[0]'); if (typeof dateTime === 'string') { const [date, time] = dateTime.split(' '); @@ -11,8 +11,8 @@ function getDateTime(tags: ExifReader.ExpandedTags) { return { exif_date: '', exif_time: '' }; } -function getCoords(tags: ExifReader.ExpandedTags) { - if (tags.gps) { +function getCoords(tags?: ExifReader.ExpandedTags) { + if (tags && tags.gps) { const { Longitude, Latitude } = tags.gps; return { exif_gps_long: Longitude, exif_gps_lat: Latitude }; } @@ -20,7 +20,12 @@ function getCoords(tags: ExifReader.ExpandedTags) { } function f(photo: Buffer) { - const tags = ExifReader.load(photo, { expanded: true }); + let tags; + try { + tags = ExifReader.load(photo, { expanded: true }); + } catch (e) { + console.error(e); // eslint-disable-line no-console + } return { ...getDateTime(tags), ...getCoords(tags) }; }