feat: 完善淘宝小程序拍照、报告与登录流程
接入本地实时识别和自动三连拍,调整报告裁切、商品跳转、分享标题及居中页眉;完善游客会话、后台渠道隔离、部署脚本与回归测试。
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
// Build-time only. The miniapp runtime never reads files or uses Buffer.
|
||||
const fs = require('node:fs'), path = require('node:path'), crypto = require('node:crypto');
|
||||
const source = path.resolve(__dirname, '../../h5/vendor/faceapi');
|
||||
const target = path.resolve(__dirname, '../vendor/native-face');
|
||||
const modelSources = path.resolve(__dirname, '../../reference/native-face-models');
|
||||
const models = [['tiny', 'tiny_face_detector_model', path.join(source, 'models')], ['landmark', 'face_landmark_68_model', path.join(source, 'models')],
|
||||
['landmarkTiny', 'face_landmark_68_tiny_model', modelSources]];
|
||||
const output = {};
|
||||
const sourceFiles = [];
|
||||
function record(file, data) { sourceFiles.push({ path: path.relative(path.resolve(__dirname, '../..'), file).replace(/\\/g, '/'), bytes: data.length,
|
||||
sha256: crypto.createHash('sha256').update(data).digest('hex') }); }
|
||||
let bytes = 0;
|
||||
for (const [key, name, directory] of models) {
|
||||
const manifestPath = path.join(directory, name + '-weights_manifest.json');
|
||||
const manifestBytes = fs.readFileSync(manifestPath); record(manifestPath, manifestBytes);
|
||||
const manifest = JSON.parse(manifestBytes.toString('utf8'));
|
||||
if (manifest.length !== 1) throw new Error('Expected one weight group: ' + name);
|
||||
const data = Buffer.concat(manifest[0].paths.map(file => {
|
||||
if (path.basename(file) !== file) throw new Error('Unexpected model path');
|
||||
const fullPath = path.join(directory, file), content = fs.readFileSync(fullPath); record(fullPath, content); return content;
|
||||
}));
|
||||
bytes += data.length;
|
||||
output[key] = { weights: manifest[0].weights, base64: data.toString('base64') };
|
||||
}
|
||||
const bundle = fs.readFileSync(path.join(source, 'face-api.js'));
|
||||
record(path.join(source, 'face-api.js'), bundle);
|
||||
// Old bundled TFJS needs a registry named global/window/self. Give this copy a
|
||||
// module-local registry and prevent Node environment branches in the miniapp.
|
||||
const adapter = '// Miniapp CPU adapter: private TFJS registry; no Node or DOM environment.\nvar global = {}; var process; var Buffer;\n' +
|
||||
'function nativeFaceNodeUnsupported(name) { throw new Error("Node-only module unavailable in local miniapp CPU engine: " + name); }\n';
|
||||
// The IDE statically resolves require(), even inside unreachable Node branches.
|
||||
// Stub these optional Node-only paths rather than bundling Node polyfills. The
|
||||
// tfjs-node occurrence is only a console-help string; remove it there too.
|
||||
const nodeOnlyModules = ['crypto', 'node-fetch', 'util', 'fs', '@tensorflow/tfjs-node'];
|
||||
const counts = {};
|
||||
const adaptedBundle = bundle.toString('utf8').replace(/\brequire\s*\(\s*(['"])(crypto|node-fetch|util|fs|@tensorflow\/tfjs-node)\1\s*\)/g, (expression, quote, name) => {
|
||||
counts[name] = (counts[name] || 0) + 1;
|
||||
return 'nativeFaceNodeUnsupported(' + quote + name + quote + ')';
|
||||
});
|
||||
for (const name of nodeOnlyModules) if (counts[name] !== 1) throw new Error('Upstream Node branch audit changed: ' + name);
|
||||
if (/\brequire\s*\(/.test(adaptedBundle)) throw new Error('Unreviewed runtime require in face-api bundle');
|
||||
const weightModule = '// Generated by scripts/build-native-face.cjs; quantized source weights, no runtime filesystem.\nmodule.exports = ' + JSON.stringify(output) + ';\n';
|
||||
const provenance = { source: 'Existing h5/vendor/faceapi (unchanged) plus official upstream tiny 68 model in reference/native-face-models', upstream: 'https://github.com/justadudewhohacks/face-api.js',
|
||||
build: 'node taobao/scripts/build-native-face.cjs', verify: 'node taobao/scripts/build-native-face.cjs --check',
|
||||
modifications: ['Module-local TFJS registry', 'Shadow process and Buffer to keep Node branches inactive', 'Node-only require calls replaced with explicit unsupported stubs'],
|
||||
nodeOnlyStubs: counts, quantizedBytes: bytes, sourceFiles, downloadedSources: JSON.parse(fs.readFileSync(path.join(modelSources, 'sources.json'), 'utf8')) };
|
||||
const files = { 'face-api.js': adapter + adaptedBundle, 'weights.js': weightModule, 'provenance.json': JSON.stringify(provenance, null, 2) + '\n' };
|
||||
const check = process.argv.includes('--check');
|
||||
if (!check) fs.mkdirSync(target, { recursive: true });
|
||||
for (const [name, content] of Object.entries(files)) {
|
||||
const destination = path.join(target, name), expected = Buffer.from(content);
|
||||
if (check) {
|
||||
if (!fs.existsSync(destination) || !fs.readFileSync(destination).equals(expected)) throw new Error('Generated model bundle differs: ' + name);
|
||||
} else fs.writeFileSync(destination, expected);
|
||||
}
|
||||
process.stdout.write(JSON.stringify({ checked: check, quantizedBytes: bytes, bundleBytes: bundle.length,
|
||||
sourceSHA256: crypto.createHash('sha256').update(bundle).digest('hex') }) + '\n');
|
||||
Reference in New Issue
Block a user