2021-11-17 21:45:49 +01:00
const fs = require ( 'fs' ) ;
2022-08-12 15:13:48 +02:00
const path = require ( 'path' ) ;
2022-08-21 19:34:51 +02:00
const log = require ( '@vladmandic/pilogger' ) ; // eslint-disable-line node/no-unpublished-require
const Build = require ( '@vladmandic/build' ) . Build ; // eslint-disable-line node/no-unpublished-require
const APIExtractor = require ( '@microsoft/api-extractor' ) ; // eslint-disable-line node/no-unpublished-require
const tf = require ( '@tensorflow/tfjs-node' ) ; // eslint-disable-line node/no-unpublished-require
const packageJSON = require ( './package.json' ) ;
2021-11-17 21:45:49 +01:00
2022-08-12 15:51:45 +02:00
const logFile = 'test/build.log' ;
2022-07-18 03:31:08 +02:00
const modelsOut = 'models/models.json' ;
2022-08-12 15:13:48 +02:00
const modelsFolders = [
'./models' ,
'../human-models/models' ,
'../blazepose/model/' ,
'../anti-spoofing/model' ,
'../efficientpose/models' ,
'../insightface/models' ,
'../movenet/models' ,
'../nanodet/models' ,
] ;
2021-11-17 21:45:49 +01:00
2022-08-21 19:34:51 +02:00
const apiExtractorIgnoreList = [ // eslint-disable-line no-unused-vars
2022-04-01 15:12:04 +02:00
'ae-missing-release-tag' ,
'tsdoc-param-tag-missing-hyphen' ,
'tsdoc-escape-right-brace' ,
'tsdoc-undefined-tag' ,
'tsdoc-escape-greater-than' ,
'ae-unresolved-link' ,
'ae-forgotten-export' ,
'tsdoc-malformed-inline-tag' ,
2022-04-21 15:38:36 +02:00
'tsdoc-unnecessary-backslash' ,
2022-04-01 15:12:04 +02:00
] ;
2021-11-17 21:45:49 +01:00
2022-07-18 03:31:08 +02:00
function copy ( src , dst ) {
2022-11-11 17:11:27 +01:00
if ( ! fs . existsSync ( src ) ) {
log . warn ( 'Copy:' , { input : src , output : dst } ) ;
return ;
}
log . state ( 'Copy:' , { input : src , output : dst } ) ;
2022-07-18 03:31:08 +02:00
const buffer = fs . readFileSync ( src ) ;
fs . writeFileSync ( dst , buffer ) ;
}
2022-09-30 16:20:08 +02:00
function write ( str , dst ) {
2022-11-11 17:11:27 +01:00
log . state ( 'Write:' , { output : dst } ) ;
2022-09-30 16:20:08 +02:00
fs . writeFileSync ( dst , str ) ;
}
function filter ( str , src ) {
2022-11-11 17:11:27 +01:00
if ( ! fs . existsSync ( src ) ) {
log . warn ( 'Filter:' , { src } ) ;
return ;
}
log . state ( 'Filter:' , { input : src } ) ;
2022-09-30 16:20:08 +02:00
const buffer = fs . readFileSync ( src , 'UTF-8' ) ;
const lines = buffer . split ( /\r?\n/ ) ;
const out = [ ] ;
for ( const line of lines ) {
if ( ! line . includes ( str ) ) out . push ( line ) ;
}
fs . writeFileSync ( src , out . join ( '\n' ) ) ;
}
2022-07-18 03:31:08 +02:00
async function analyzeModels ( ) {
2022-08-12 15:13:48 +02:00
log . info ( 'Analyze models:' , { folders : modelsFolders . length , result : modelsOut } ) ;
2022-07-18 03:31:08 +02:00
let totalSize = 0 ;
const models = { } ;
2022-08-12 15:13:48 +02:00
const allModels = [ ] ;
for ( const folder of modelsFolders ) {
try {
if ( ! fs . existsSync ( folder ) ) continue ;
const stat = fs . statSync ( folder ) ;
if ( ! stat . isDirectory ) continue ;
const dir = fs . readdirSync ( folder ) ;
const found = dir . map ( ( f ) => ` file:// ${ folder } / ${ f } ` ) . filter ( ( f ) => f . endsWith ( 'json' ) ) ;
log . state ( 'Models' , { folder , models : found . length } ) ;
allModels . push ( ... found ) ;
} catch {
// log.warn('Cannot enumerate:', modelFolder);
}
2022-07-18 03:31:08 +02:00
}
2022-08-12 15:13:48 +02:00
for ( const url of allModels ) {
// if (!f.endsWith('.json')) continue;
// const url = `file://${modelsDir}/${f}`;
2022-07-18 03:31:08 +02:00
const model = new tf . GraphModel ( url ) ; // create model prototype and decide if load from cache or from original modelurl
model . findIOHandler ( ) ;
const artifacts = await model . handler . load ( ) ;
const size = artifacts ? . weightData ? . byteLength || 0 ;
totalSize += size ;
2022-08-12 15:13:48 +02:00
const name = path . basename ( url ) . replace ( '.json' , '' ) ;
if ( ! models [ name ] ) models [ name ] = size ;
2022-07-18 03:31:08 +02:00
}
const json = JSON . stringify ( models , null , 2 ) ;
fs . writeFileSync ( modelsOut , json ) ;
log . state ( 'Models:' , { count : Object . keys ( models ) . length , totalSize } ) ;
}
2021-11-17 21:45:49 +01:00
async function main ( ) {
2022-08-12 15:51:45 +02:00
log . logFile ( logFile ) ;
2022-08-21 19:34:51 +02:00
log . data ( 'Build' , { name : packageJSON . name , version : packageJSON . version } ) ;
2022-11-11 17:11:27 +01:00
2021-11-17 21:45:49 +01:00
// run production build
const build = new Build ( ) ;
await build . run ( 'production' ) ;
2022-11-11 17:11:27 +01:00
2021-11-17 21:45:49 +01:00
// patch tfjs typedefs
2022-10-17 02:28:57 +02:00
copy ( 'src/tfjs/tfjs.esm.d.ts' , 'dist/tfjs.esm.d.ts' ) ;
2022-11-11 17:11:27 +01:00
copy ( 'node_modules/@vladmandic/tfjs/types/tfjs-core.d.ts' , 'types/tfjs-core.d.ts' ) ;
copy ( 'node_modules/@vladmandic/tfjs/types/tfjs.d.ts' , 'types/tfjs.esm.d.ts' ) ;
copy ( 'tfjs/types-tsconfig.json' , 'types/tsconfig.json' ) ;
copy ( 'tfjs/types-eslint.json' , 'types/.eslintrc.json' ) ;
filter ( 'reference types' , 'types/tfjs-core.d.ts' ) ;
2021-11-17 21:45:49 +01:00
// run api-extractor to create typedef rollup
2022-09-03 13:13:08 +02:00
const extractorConfig = APIExtractor . ExtractorConfig . loadFileAndPrepare ( '.api-extractor.json' ) ;
2021-11-17 21:45:49 +01:00
const extractorResult = APIExtractor . Extractor . invoke ( extractorConfig , {
localBuild : true ,
showVerboseMessages : false ,
messageCallback : ( msg ) => {
msg . handled = true ;
if ( msg . logLevel === 'none' || msg . logLevel === 'verbose' || msg . logLevel === 'info' ) return ;
if ( msg . sourceFilePath ? . includes ( '/node_modules/' ) ) return ;
2022-04-01 15:12:04 +02:00
// if (apiExtractorIgnoreList.reduce((prev, curr) => prev || msg.messageId.includes(curr), false)) return; // those are external issues outside of human control
2021-11-17 21:45:49 +01:00
log . data ( 'API' , { level : msg . logLevel , category : msg . category , id : msg . messageId , file : msg . sourceFilePath , line : msg . sourceFileLine , text : msg . text } ) ;
} ,
} ) ;
log . state ( 'API-Extractor:' , { succeeeded : extractorResult . succeeded , errors : extractorResult . errorCount , warnings : extractorResult . warningCount } ) ;
2022-09-30 16:20:08 +02:00
filter ( 'reference types' , 'types/human.d.ts' ) ;
write ( 'export * from \'../types/human\';' , 'dist/human.esm-nobundle.d.ts' ) ;
write ( 'export * from \'../types/human\';' , 'dist/human.esm.d.ts' ) ;
write ( 'export * from \'../types/human\';' , 'dist/human.d.ts' ) ;
write ( 'export * from \'../types/human\';' , 'dist/human.node-gpu.d.ts' ) ;
write ( 'export * from \'../types/human\';' , 'dist/human.node.d.ts' ) ;
write ( 'export * from \'../types/human\';' , 'dist/human.node-wasm.d.ts' ) ;
2022-08-12 15:51:45 +02:00
// generate model signature
await analyzeModels ( ) ;
log . info ( 'Human Build complete...' , { logFile } ) ;
2021-11-17 21:45:49 +01:00
}
main ( ) ;