remove old build server

pull/193/head
Vladimir Mandic 2021-09-10 21:21:54 -04:00
parent c3b59baff1
commit c9dacbd152
11 changed files with 0 additions and 821 deletions

View File

@ -1,8 +0,0 @@
# Human Library: Dev Server & Build Scripts
For details see Wiki:
- [**Build Process**](https://github.com/vladmandic/human/wiki/Build-Process)
- [**Development Server**](https://github.com/vladmandic/human/wiki/Development-Server)
Not required for normal funcioning of library

View File

@ -1,270 +0,0 @@
/**
* Implements Human build process
* Used to generate prod builds for releases or by dev server to generate on-the-fly debug builds
*/
const fs = require('fs');
const path = require('path');
const log = require('@vladmandic/pilogger');
const esbuild = require('esbuild');
const rimraf = require('rimraf');
const tfjs = require('@tensorflow/tfjs/package.json');
const changelog = require('./changelog.js');
const lint = require('./lint.js');
const typedoc = require('./typedoc.js');
const typings = require('./typings.js');
let busy = false;
const config = {
build: {
banner: { js: `
/*
Human library
homepage: <https://github.com/vladmandic/human>
author: <https://github.com/vladmandic>'
*/` },
tsconfig: './tsconfig.json',
logLevel: 'error',
bundle: true,
metafile: true,
target: 'es2018',
},
debug: {
minifyWhitespace: false,
minifyIdentifiers: false,
minifySyntax: false,
},
production: {
minifyWhitespace: true,
minifyIdentifiers: true,
minifySyntax: true,
},
buildLog: 'build.log',
changelog: '../CHANGELOG.md',
lintLocations: ['server/', 'src/', 'tfjs/', 'test/', 'demo/'],
cleanLocations: ['dist/*', 'types/*', 'typedoc/*'],
};
const targets = {
node: {
tfjs: {
platform: 'node',
format: 'cjs',
entryPoints: ['tfjs/tf-node.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['@tensorflow'],
sourcemap: false,
minifyWhitespace: false,
minifyIdentifiers: false,
minifySyntax: false,
},
node: {
platform: 'node',
format: 'cjs',
entryPoints: ['src/human.ts'],
outfile: 'dist/human.node.js',
external: ['@tensorflow'],
sourcemap: false,
minifyWhitespace: false,
minifyIdentifiers: false,
minifySyntax: false,
},
},
nodeGPU: {
tfjs: {
platform: 'node',
format: 'cjs',
entryPoints: ['tfjs/tf-node-gpu.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['@tensorflow'],
sourcemap: false,
minifyWhitespace: false,
minifyIdentifiers: false,
minifySyntax: false,
},
node: {
platform: 'node',
format: 'cjs',
entryPoints: ['src/human.ts'],
outfile: 'dist/human.node-gpu.js',
external: ['@tensorflow'],
sourcemap: false,
minifyWhitespace: false,
minifyIdentifiers: false,
minifySyntax: false,
},
},
nodeWASM: {
tfjs: {
platform: 'node',
format: 'cjs',
entryPoints: ['tfjs/tf-node-wasm.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['@tensorflow'],
sourcemap: false,
minifyWhitespace: false,
minifyIdentifiers: false,
minifySyntax: false,
},
node: {
platform: 'node',
format: 'cjs',
entryPoints: ['src/human.ts'],
outfile: 'dist/human.node-wasm.js',
external: ['@tensorflow'],
sourcemap: false,
minifyWhitespace: false,
minifyIdentifiers: false,
minifySyntax: false,
},
},
browserNoBundle: {
tfjs: {
platform: 'browser',
format: 'esm',
entryPoints: ['tfjs/tf-browser.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['fs', 'buffer', 'util', 'os', '@tensorflow'],
sourcemap: true,
},
esm: {
platform: 'browser',
format: 'esm',
entryPoints: ['src/human.ts'],
outfile: 'dist/human.esm-nobundle.js',
external: ['fs', 'buffer', 'util', 'os', '@tensorflow'],
sourcemap: true,
},
},
browserBundle: {
tfjs: {
banner: { js: '/* TFJS custom ESM bundle in ES2018 */' },
platform: 'browser',
format: 'esm',
entryPoints: ['tfjs/tf-browser.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['fs', 'buffer', 'util', 'os'],
// treeShaking: 'ignore-annotations',
sourcemap: true,
minifyWhitespace: false,
minifyIdentifiers: false,
minifySyntax: false,
},
iife: {
platform: 'browser',
format: 'iife',
globalName: 'Human',
entryPoints: ['src/human.ts'],
outfile: 'dist/human.js',
external: ['fs', 'buffer', 'util', 'os'],
sourcemap: false,
},
esm: {
platform: 'browser',
format: 'esm',
entryPoints: ['src/human.ts'],
outfile: 'dist/human.esm.js',
external: ['fs', 'buffer', 'util', 'os'],
sourcemap: true,
},
/*
demo: {
platform: 'browser',
format: 'esm',
entryPoints: ['demo/browser.js'],
outfile: 'dist/demo-browser-index.js',
external: ['fs', 'buffer', 'util', 'os'],
},
*/
},
};
async function getStats(json) {
const stats = {};
if (json && json.metafile?.inputs && json.metafile?.outputs) {
for (const [key, val] of Object.entries(json.metafile.inputs)) {
if (key.startsWith('node_modules')) {
stats.modules = (stats.modules || 0) + 1;
stats.moduleBytes = (stats.moduleBytes || 0) + val.bytes;
} else {
stats.imports = (stats.imports || 0) + 1;
stats.importBytes = (stats.importBytes || 0) + val.bytes;
}
}
const files = [];
for (const [key, val] of Object.entries(json.metafile.outputs)) {
if (!key.endsWith('.map')) {
files.push(key);
stats.outputBytes = (stats.outputBytes || 0) + val.bytes;
}
}
stats.outputFiles = files.join(', ');
}
return stats;
}
// rebuild typings
// rebuild on file change
async function build(f, msg, dev = false) {
if (busy) {
log.state('Build: busy...');
setTimeout(() => build(f, msg, dev), 500);
return;
}
busy = true;
log.info('Build: file', msg, f, 'type:', dev ? 'debug' : 'production', 'config:', dev ? config.debug : config.production);
// common build options
try {
// rebuild all target groups and types
for (const [targetGroupName, targetGroup] of Object.entries(targets)) {
for (const [targetName, targetOptions] of Object.entries(targetGroup)) {
// if triggered from watch mode, rebuild only browser bundle
// if ((require.main !== module) && ((targetGroupName === 'browserNoBundle') || (targetGroupName === 'nodeGPU'))) continue;
const opt = dev ? config.debug : config.production;
// @ts-ignore // eslint-typescript complains about string enums used in js code
const meta = await esbuild.build({ ...config.build, ...opt, ...targetOptions });
const stats = await getStats(meta);
log.state(` target: ${targetGroupName} type: ${targetName}:`, stats);
}
}
} catch (err) {
// catch errors and print where it occured
log.error('Build error', JSON.stringify(err.errors || err, null, 2));
if (require.main === module) process.exit(1);
}
if (!dev) { // only for prod builds, skipped for dev build
await lint.run(config.lintLocations); // run linter
await changelog.update(config.changelog); // generate changelog
await typings.run(targets.browserBundle.esm.entryPoints); // generate typings
await typedoc.run(targets.browserBundle.esm.entryPoints); // generate typedoc
}
if (require.main === module) process.exit(0);
busy = false;
}
function clean() {
log.info('Clean:', config.cleanLocations);
for (const loc of config.cleanLocations) rimraf.sync(loc);
}
if (require.main === module) {
config.buildLog = path.join(__dirname, config.buildLog);
if (fs.existsSync(config.buildLog)) fs.unlinkSync(config.buildLog);
log.logFile(config.buildLog);
log.header();
const toolchain = {
tfjs: tfjs.version,
esbuild: esbuild.version,
typescript: typings.version,
typedoc: typedoc.version,
eslint: lint.version,
};
log.info('Toolchain: ', toolchain);
clean();
build('all', 'startup');
} else {
exports.build = build;
}

View File

@ -1,13 +0,0 @@
2021-09-10 19:34:11 INFO:  @vladmandic/human version 2.1.5
2021-09-10 19:34:11 INFO:  User: vlado Platform: linux Arch: x64 Node: v16.5.0
2021-09-10 19:34:11 INFO:  Toolchain: {"tfjs":"3.9.0","esbuild":"0.12.26","typescript":"4.4.3","typedoc":"0.22.1","eslint":"7.32.0"}
2021-09-10 19:34:11 INFO:  Clean: ["dist/*","types/*","typedoc/*"]
2021-09-10 19:34:11 INFO:  Build: file startup all type: production config: {"minifyWhitespace":true,"minifyIdentifiers":true,"minifySyntax":true}
2021-09-10 19:34:11 STATE: target: node type: tfjs: {"imports":1,"importBytes":102,"outputBytes":1444,"outputFiles":"dist/tfjs.esm.js"}
2021-09-10 19:34:11 STATE: target: node type: node: {"imports":47,"importBytes":456903,"outputBytes":396607,"outputFiles":"dist/human.node.js"}
2021-09-10 19:34:11 STATE: target: nodeGPU type: tfjs: {"imports":1,"importBytes":110,"outputBytes":1452,"outputFiles":"dist/tfjs.esm.js"}
2021-09-10 19:34:11 STATE: target: nodeGPU type: node: {"imports":47,"importBytes":456911,"outputBytes":396611,"outputFiles":"dist/human.node-gpu.js"}
2021-09-10 19:34:11 STATE: target: nodeWASM type: tfjs: {"imports":1,"importBytes":149,"outputBytes":1519,"outputFiles":"dist/tfjs.esm.js"}
2021-09-10 19:34:11 STATE: target: nodeWASM type: node: {"imports":47,"importBytes":456978,"outputBytes":396683,"outputFiles":"dist/human.node-wasm.js"}
2021-09-10 19:34:11 STATE: target: browserNoBundle type: tfjs: {"imports":1,"importBytes":2168,"outputBytes":1242,"outputFiles":"dist/tfjs.esm.js"}
2021-09-10 19:34:11 STATE: target: browserNoBundle type: esm: {"imports":47,"importBytes":456701,"outputBytes":255452,"outputFiles":"dist/human.esm-nobundle.js"}

View File

@ -1,59 +0,0 @@
/**
* Creates changelog in markdown format from git log as part of the build process
*/
const fs = require('fs');
const path = require('path');
const dayjs = require('dayjs');
const simpleGit = require('simple-git/promise');
const logger = require('@vladmandic/pilogger');
const app = require('../package.json');
const git = simpleGit();
let text = `# ${app.name}
Version: **${app.version}**
Description: **${app.description}**
Author: **${app.author}**
License: **${app.license}** </LICENSE>
Repository: **<${app.repository.url}>**
## Changelog
`;
async function update(f) {
const gitLog = await git.log();
const entries = [...gitLog.all];
const log = entries.sort((a, b) => (new Date(b.date).getTime() - new Date(a.date).getTime()));
let previous = '';
const headings = [];
for (const l of log) {
const msg = l.message.toLowerCase();
if ((l.refs !== '') || msg.match(/^[0-99].[0-99].[0-99]/)) {
const dt = dayjs(l.date).format('YYYY/MM/DD');
let ver = msg.match(/[0-99].[0-99].[0-99]/) ? msg : l.refs;
ver = ver.replace('tag: v', '').replace('tag: ', 'release: ').split(',')[0];
const heading = `\n### **${ver}** ${dt} ${l.author_email}\n\n`;
if (!headings.includes(heading) && !ver.startsWith('tag')) {
headings.push(heading);
text += heading;
}
} else if ((msg.length > 2) && !msg.startsWith('update') && (previous !== msg)) {
previous = msg;
text += `- ${msg}\n`;
}
}
const name = path.join(__dirname, f);
fs.writeFileSync(name, text);
logger.info('Generate ChangeLog:', [name]);
}
if (require.main === module) {
update('../CHANGELOG.md');
} else {
exports.update = update;
}

View File

@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIUKQKodDBJnuweJs5IcTyL4NIp3vgwDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0Zsb3JpZGExDjAMBgNVBAcMBU1p
YW1pMRQwEgYDVQQKDAtAdmxhZG1hbmRpYzAeFw0yMDExMDcxNTE3NDNaFw0yMTEx
MDcxNTE3NDNaMEUxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdGbG9yaWRhMQ4wDAYD
VQQHDAVNaWFtaTEUMBIGA1UECgwLQHZsYWRtYW5kaWMwggIiMA0GCSqGSIb3DQEB
AQUAA4ICDwAwggIKAoICAQDSC88PF8NyLkagK5mAZ/d739SOU16l2Cx3zE35zZQh
O29+1L4L+oMksLYipo+FMgtGO+MSzFsvGgKCs2sDSdfyoNSTZ3QaN4BAZ0sbq+wL
cke7yRBTM/XIGOQfhqq8yC2q8/zXwUbZg0UsCAxDGNwUr0Qlm829laIU/UN1KcYS
57Nebl1z05wMEvYmyl4JBAl9ozne7KS9DyW7jbrAXE8TaEy3+pY66kx5GG6v2+up
ScITGm4YPmPPlpOF1UjQloosgxdVa+fVp8aNCa/rf0JNO0Uhb3OKOZ+4kYmpfPn/
trwoKWAa6CV1uAJ+3zDkLMq1JNlrV4OMp1QvX0wzA47a/n466JMN9SFb0Ng5wf19
VOtT5Zu7chDStBudVjxlMDfUixvhvn4sjbaLNYR1fyWPoNXwr0KX2lpTP1QOzp9/
Sd0iiJ8RPfXn8Xo26MStu4I52CZjS7yEMgJGCLH/mgPuSbrHHYYrrrCPJgmQOZG2
TNMI+EqOwQvHh2ghdv7t7EEk4IslBk0QzufMXQ2WFXQ20nvj74mrmmiMuBcmonpR
0egA5/M18ZPLQxYu0Q86NUr4XHtAG1fq+n8pseQ7Avy6Gk6HRiezCbB7TJ9rnNeu
jie1TDajC6W7rx0VF7hcxkIrDgNgnYcjXUV2hMx1lo4fIoWkL3nJJVEthMVIcJOX
EwIDAQABo1MwUTAdBgNVHQ4EFgQUHawIRAo1bW8Xy7l4oKfM+ESjhs0wHwYDVR0j
BBgwFoAUHawIRAo1bW8Xy7l4oKfM+ESjhs0wDwYDVR0TAQH/BAUwAwEB/zANBgkq
hkiG9w0BAQsFAAOCAgEAozQJk5Ahx7rDn/aMXLdZFxR81VfkmHDm7NhlJsdVKUx5
o/iegXnvwc1PoeKsz2S504QiuL8l7jqZoU2WPIm7Vlr+oxBgiKqjo1EqBsUgNCZ7
qxMD84TVp/KBGjKUh1TXhjJwGGfNNr+R/fJGw+36UeuY3fSckjaYTuNuVElp+DoZ
/pGyu1qpcybLfiR8mpQkCeU/iBq5gIjWddbVjlYoTKfqULZrpsAF2AeqELEgyshl
p3PNhW/54TJSn4mWK+39BibYHPkvx8orEuWKyjjRk82hEXi7J3hsGKX29qC3oO40
67DKDWmZdMCz+E1ERf10V0bSp6iJnnlwknHJloZUETV1NY/DdoSC6e8CN0+0cQqL
aJefJ483O3sXyN3v3+DaEFBLPFgRFGZB7eaBwR2xAv/KfjT5dSyi+wA4LZAxsQMC
Q7UYGNAfHLNHJo/bsj12+JDhJaFZ/KoBKzyMUuEXmvjxXNDMCfm+gVQFoLyXkGq3
491W/O7LjR6pkD+ce0qeTFMu3nfUubyfbONVDEfuH4GC1e+FAggCRaBnFsVzCzXj
jxOOLoQ9nwLk8v17mx0BSwX4iuqvXFntfJbzfcnzQfx/qqPFheIbGnmKw1lrRML8
87ZbN6t01+v2YyYe6Mc7p80s1R3jc8aVX8ca2KcYwsJAkg/xz0q5RJwsE1is5UY=
-----END CERTIFICATE-----

View File

@ -1,52 +0,0 @@
-----BEGIN PRIVATE KEY-----
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
qIRta3H9KNw2Mhpkm77TtUSV/W5aOmY=
-----END PRIVATE KEY-----

View File

@ -1,23 +0,0 @@
const log = require('@vladmandic/pilogger');
let eslint = null;
const { ESLint } = require('eslint');
const version = ESLint.version;
async function lint(lintLocations) {
log.info('Running Linter:', lintLocations);
if (!eslint) eslint = new ESLint();
const results = await eslint.lintFiles(lintLocations);
const errors = results.reduce((prev, curr) => prev += curr.errorCount, 0);
const warnings = results.reduce((prev, curr) => prev += curr.warningCount, 0);
log.info('Linter complete: files:', results.length, 'errors:', errors, 'warnings:', warnings);
if (errors > 0 || warnings > 0) {
const formatter = await eslint.loadFormatter('stylish');
const text = formatter.format(results);
log.warn(text);
}
}
exports.run = lint;
exports.version = version;

View File

@ -1,194 +0,0 @@
/**
Micro http/http2 server with file monitoring and automatic app rebuild
- can process concurrent http requests
- monitors specified filed and folders for changes
- triggers library and application rebuild
- any build errors are immediately displayed and can be corrected without need for restart
- passthrough data compression
*/
const fs = require('fs');
const zlib = require('zlib');
const http = require('http');
const http2 = require('http2');
const path = require('path');
const chokidar = require('chokidar');
const log = require('@vladmandic/pilogger');
const build = require('./build.js');
// app configuration
// you can provide your server key and certificate or use provided self-signed ones
// self-signed certificate generated using:
// openssl req -x509 -newkey rsa:4096 -nodes -keyout https.key -out https.crt -days 365 -subj "/C=US/ST=Florida/L=Miami/O=@vladmandic"
// client app does not work without secure server since browsers enforce https for webcam access
const options = {
key: fs.readFileSync('server/https.key'),
cert: fs.readFileSync('server/https.crt'),
defaultFolder: 'demo',
defaultFile: 'index.html',
httpPort: 10030,
httpsPort: 10031,
insecureHTTPParser: false,
minElapsed: 2,
monitor: ['package.json', 'config.ts', 'demo/*.js', 'demo/*.html', 'src'],
};
// just some predefined mime types
const mime = {
'.html': 'text/html; charset=utf-8',
'.js': 'text/javascript; charset=utf-8',
'.css': 'text/css; charset=utf-8',
'.json': 'application/json; charset=utf-8',
'.png': 'image/png',
'.jpg': 'image/jpg',
'.gif': 'image/gif',
'.ico': 'image/x-icon',
'.svg': 'image/svg+xml',
'.wav': 'audio/wav',
'.mp4': 'video/mp4',
'.woff': 'font/woff',
'.woff2': 'font/woff2',
'.ttf': 'font/ttf',
'.wasm': 'application/wasm',
};
let last = Date.now();
async function buildAll(evt, msg) {
const now = Date.now();
if ((now - last) > options.minElapsed) build.build(evt, msg, true);
else log.state('Build: merge event file', msg, evt);
last = now;
}
// watch filesystem for any changes and notify build when needed
async function watch() {
const watcher = chokidar.watch(options.monitor, {
persistent: true,
ignorePermissionErrors: false,
alwaysStat: false,
ignoreInitial: true,
followSymlinks: true,
usePolling: false,
useFsEvents: false,
atomic: true,
});
// single event handler for file add/change/delete
watcher
.on('add', (evt) => buildAll(evt, 'add'))
.on('change', (evt) => buildAll(evt, 'modify'))
.on('unlink', (evt) => buildAll(evt, 'remove'))
.on('error', (err) => log.error(`Client watcher error: ${err}`))
.on('ready', () => log.state('Monitoring:', options.monitor));
}
function handle(url) {
url = url.split(/[?#]/)[0];
const result = { ok: false, stat: {}, file: '' };
const checkFile = (f) => {
result.file = f;
if (fs.existsSync(f)) {
result.stat = fs.statSync(f);
if (result.stat.isFile()) {
result.ok = true;
return true;
}
}
return false;
};
const checkFolder = (f) => {
result.file = f;
if (fs.existsSync(f)) {
result.stat = fs.statSync(f);
if (result.stat.isDirectory()) {
result.ok = true;
return true;
}
}
return false;
};
return new Promise((resolve) => {
if (checkFile(path.join(process.cwd(), url))) resolve(result);
else if (checkFile(path.join(process.cwd(), url, options.defaultFile))) resolve(result);
else if (checkFile(path.join(process.cwd(), options.defaultFolder, url))) resolve(result);
else if (checkFile(path.join(process.cwd(), options.defaultFolder, url, options.defaultFile))) resolve(result);
else if (checkFolder(path.join(process.cwd(), url))) resolve(result);
else if (checkFolder(path.join(process.cwd(), options.defaultFolder, url))) resolve(result);
else resolve(result);
});
}
// process http requests
async function httpRequest(req, res) {
handle(decodeURI(req.url)).then((result) => {
// get original ip of requestor, regardless if it's behind proxy or not
const forwarded = (req.headers['forwarded'] || '').match(/for="\[(.*)\]:/);
const ip = (Array.isArray(forwarded) ? forwarded[1] : null) || req.headers['x-forwarded-for'] || req.ip || req.socket.remoteAddress;
if (!result || !result.ok || !result.stat) {
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
res.end('Error 404: Not Found\n', 'utf-8');
log.warn(`${req.method}/${req.httpVersion}`, res.statusCode, decodeURI(req.url), ip);
} else {
const input = encodeURIComponent(result.file).replace(/\*/g, '').replace(/\?/g, '').replace(/%2F/g, '/').replace(/%40/g, '@').replace(/%20/g, ' ');
if (result?.stat?.isFile()) {
const ext = String(path.extname(input)).toLowerCase();
const contentType = mime[ext] || 'application/octet-stream';
const accept = req.headers['accept-encoding'] ? req.headers['accept-encoding'].includes('br') : false; // does target accept brotli compressed data
res.writeHead(200, {
// 'Content-Length': result.stat.size, // not using as it's misleading for compressed streams
'Content-Language': 'en',
'Content-Type': contentType,
'Content-Encoding': accept ? 'br' : '',
'Last-Modified': result.stat.mtime,
'Cache-Control': 'no-cache',
'X-Content-Type-Options': 'nosniff',
'Cross-Origin-Embedder-Policy': 'require-corp',
'Cross-Origin-Opener-Policy': 'same-origin',
'Content-Security-Policy': "media-src 'self' http: https: data:",
});
const compress = zlib.createBrotliCompress({ params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 5 } }); // instance of brotli compression with level 5
const stream = fs.createReadStream(input);
if (!accept) stream.pipe(res); // don't compress data
else stream.pipe(compress).pipe(res); // compress data
/// alternative #2 read stream and send by chunk
// const stream = fs.createReadStream(result.file);
// stream.on('data', (chunk) => res.write(chunk));
// stream.on('end', () => res.end());
// alternative #3 read entire file and send it as blob
// const data = fs.readFileSync(result.file);
// res.write(data);
log.data(`${req.method}/${req.httpVersion}`, res.statusCode, contentType, result.stat.size, req.url, ip);
}
if (result?.stat?.isDirectory()) {
res.writeHead(200, { 'Content-Language': 'en', 'Content-Type': 'application/json; charset=utf-8', 'Last-Modified': result.stat.mtime, 'Cache-Control': 'no-cache', 'X-Content-Type-Options': 'nosniff' });
let dir = fs.readdirSync(input);
dir = dir.map((f) => path.join(decodeURI(req.url), f));
res.end(JSON.stringify(dir), 'utf-8');
log.data(`${req.method}/${req.httpVersion}`, res.statusCode, 'directory/json', result.stat.size, req.url, ip);
}
}
});
}
// app main entry point
async function main() {
log.header();
await watch();
process.chdir(path.join(__dirname, '..'));
if (options.httpPort && options.httpPort > 0) {
const server1 = http.createServer(options, httpRequest);
server1.on('listening', () => log.state('HTTP server listening:', options.httpPort));
server1.on('error', (err) => log.error('HTTP server:', err.message || err));
server1.listen(options.httpPort);
}
if (options.httpsPort && options.httpsPort > 0) {
const server2 = http2.createSecureServer(options, httpRequest);
server2.on('listening', () => log.state('HTTP2 server listening:', options.httpsPort));
server2.on('error', (err) => log.error('HTTP2 server:', err.message || err));
server2.listen(options.httpsPort);
}
await build.build('all', 'startup', true);
}
main();

View File

@ -1,99 +0,0 @@
#!/usr/bin/env -S node --no-deprecation --trace-warnings
/**
* Helper app that analyzes any TensorFlow SavedModel or GraphModel for inputs and outputs
*/
const fs = require('fs');
const path = require('path');
const log = require('@vladmandic/pilogger');
const tf = require('@tensorflow/tfjs-node');
async function analyzeGraph(modelPath) {
const model = await tf.loadGraphModel(`file://${modelPath}`);
log.info('graph model:', path.resolve(modelPath));
log.info('size:', tf.engine().memory());
const inputs = [];
if (model.modelSignature && model.modelSignature['inputs']) {
log.info('model inputs based on signature');
for (const [key, val] of Object.entries(model.modelSignature['inputs'])) {
const shape = val.tensorShape.dim.map((a) => parseInt(a.size));
inputs.push({ name: key, dtype: val.dtype, shape });
}
// @ts-ignore accessing private property
} else if (model.executor.graph['inputs']) {
log.info('model inputs based on executor');
// @ts-ignore accessing private property
for (const t of model.executor.graph['inputs']) {
inputs.push({ name: t.name, dtype: t.attrParams.dtype.value, shape: t.attrParams.shape.value });
}
} else {
log.warn('model inputs: cannot determine');
}
const outputs = [];
let i = 0;
if (model.modelSignature && model.modelSignature['outputs'] && Object.values(model.modelSignature['outputs'])[0].dtype) {
log.info('model outputs based on signature');
for (const [key, val] of Object.entries(model.modelSignature['outputs'])) {
const shape = val.tensorShape?.dim.map((a) => parseInt(a.size));
outputs.push({ id: i++, name: key, dytpe: val.dtype, shape });
}
// @ts-ignore accessing private property
} else if (model.executor.graph['outputs']) {
log.info('model outputs based on executor');
// @ts-ignore accessing private property
for (const t of model.executor.graph['outputs']) {
outputs.push({ id: i++, name: t.name, dtype: t.attrParams.dtype?.value || t.rawAttrs.T.type, shape: t.attrParams.shape?.value });
}
} else {
log.warn('model outputs: cannot determine');
}
log.data('inputs:', inputs);
log.data('outputs:', outputs);
}
async function analyzeSaved(modelPath) {
const meta = await tf.node.getMetaGraphsFromSavedModel(modelPath);
log.info('saved model:', path.resolve(modelPath));
const sign = Object.values(meta[0].signatureDefs)[0];
log.data('tags:', meta[0].tags);
log.data('signature:', Object.keys(meta[0].signatureDefs));
const inputs = Object.values(sign.inputs)[0];
// @ts-ignore a is array
const inputShape = inputs.shape?.map((a) => a.array[0]);
log.data('inputs:', { name: inputs.name, dtype: inputs.dtype, shape: inputShape });
const outputs = [];
let i = 0;
for (const [key, val] of Object.entries(sign.outputs)) {
// @ts-ignore a is array
const shape = val.shape?.map((a) => a.array[0]);
outputs.push({ id: i++, name: key, dytpe: val.dtype, shape });
}
log.data('outputs:', outputs);
}
async function main() {
log.header();
const param = process.argv[2];
if (process.argv.length !== 3) {
log.error('path required');
process.exit(0);
} else if (!fs.existsSync(param)) {
log.error(`path does not exist: ${param}`);
process.exit(0);
}
const stat = fs.statSync(param);
log.data('created on:', stat.birthtime);
if (stat.isFile()) {
if (param.endsWith('.json')) analyzeGraph(param);
}
if (stat.isDirectory()) {
if (fs.existsSync(path.join(param, '/saved_model.pb'))) analyzeSaved(param);
if (fs.existsSync(path.join(param, '/model.json'))) analyzeGraph(path.join(param, '/model.json'));
}
}
main();

View File

@ -1,35 +0,0 @@
const log = require('@vladmandic/pilogger');
const TypeDoc = require('typedoc');
const tsconfig = require('../tsconfig.json');
let td = null;
const version = TypeDoc.Application.VERSION;
async function typedoc(entryPoints) {
if (!td) {
td = new TypeDoc.Application();
td.options.addReader(new TypeDoc.TSConfigReader());
td.bootstrap({ entryPoints });
td.logger.warn = log.warn;
td.logger.error = log.error;
td.logger.verbose = () => { /***/ };
// td.logger.verbose = log.data; // remove extra logging
td.logger.log = log.info;
// td.converter = converter;
}
log.info('Generate TypeDocs:', entryPoints, 'outDir:', [tsconfig.typedocOptions.out]);
const project = td.convert();
if (!project) log.warn('TypeDoc: convert returned empty project');
if (td.logger.hasErrors() || td.logger.hasWarnings()) log.warn('TypeDoc:', 'errors:', td.logger.errorCount, 'warnings:', td.logger.warningCount);
const result = project ? await td.generateDocs(project, 'typedoc') : null;
if (result) log.warn('TypeDoc:', result);
}
if (require.main === module) {
log.header();
typedoc(['src/human.ts']); // generate typedoc
} else {
exports.run = typedoc;
exports.version = version;
}

View File

@ -1,37 +0,0 @@
const ts = require('typescript');
const log = require('@vladmandic/pilogger');
const version = ts.version;
async function typings(entryPoint) {
const configFileName = ts.findConfigFile('./', ts.sys.fileExists, 'tsconfig.json') || '';
const configFile = ts.readConfigFile(configFileName, ts.sys.readFile);
const compilerOptions = ts.parseJsonConfigFileContent(configFile.config, ts.sys, './');
// add explicitly to avoid generating compiled js files
compilerOptions.options.emitDeclarationOnly = true;
log.info('Generate Typings:', entryPoint, 'outDir:', [compilerOptions.options.outDir]);
const compilerHost = ts.createCompilerHost(compilerOptions.options);
const program = ts.createProgram(entryPoint, compilerOptions.options, compilerHost);
const emit = program.emit();
const diag = ts
.getPreEmitDiagnostics(program)
.concat(emit.diagnostics);
for (const info of diag) {
const msg = info.messageText['messageText'] || info.messageText;
if (msg.includes('package.json')) continue;
if (info.file) {
const pos = info.file.getLineAndCharacterOfPosition(info.start || 0);
log.error(`TSC: ${info.file.fileName} [${pos.line + 1},${pos.character + 1}]:`, msg);
} else {
log.error('TSC:', msg);
}
}
}
if (require.main === module) {
log.header();
typings(['src/human.ts']); // generate typedoc
} else {
exports.run = typings;
exports.version = version;
}