44 lines
2.3 KiB
JavaScript
44 lines
2.3 KiB
JavaScript
'use strict';
|
|
const CaptureQuality = require('../js/capture-quality.js');
|
|
const HeadPose = require('../js/head-pose.js');
|
|
const views = ['front', 'left', 'right'];
|
|
function scalar(value) { return typeof value === 'number' && Number.isFinite(value) ? value : null; }
|
|
// Client observations are untrusted calibration hints, never authorization or
|
|
// a provider-quality verdict. Strip arbitrary strings/extra fields on ingestion.
|
|
function normalize(input) {
|
|
if (!input || typeof input !== 'object') return null;
|
|
const version = typeof input.version === 'string' && /^[\w.-]{1,64}$/.test(input.version) ? input.version : 'unknown';
|
|
const result = { version, source: 'client-untrusted', views: {} };
|
|
for (const key of views) {
|
|
const row = input.views && input.views[key];
|
|
if (!row || typeof row !== 'object') continue;
|
|
const out = { mode: ['live', 'file', 'unchecked', 'mock'].includes(row.mode) ? row.mode : 'unknown' };
|
|
if (['preview', 'none'].includes(row.check_stage)) out.check_stage = row.check_stage;
|
|
if (row.reason === 'model-unavailable') out.reason = row.reason;
|
|
if (typeof row.direction_checked === 'boolean') out.direction_checked = row.direction_checked;
|
|
for (const metric of ['yaw', 'pitch', 'roll', 'score', 'luma', 'ratio', 'center_x', 'center_y']) {
|
|
const value = scalar(row[metric]);
|
|
if (value != null && Math.abs(value) <= 1000) out[metric] = value;
|
|
}
|
|
result.views[key] = out;
|
|
}
|
|
if (version === CaptureQuality.config.version) result.policy = { capture: CaptureQuality.config, pose: HeadPose.config };
|
|
return result;
|
|
}
|
|
function assess(raw) {
|
|
const nested = raw.side_result || {};
|
|
const result = { status: 'valid', views: {} };
|
|
for (const key of ['left', 'right']) {
|
|
const side = raw[key + '_side_result'] || nested[key + '_side_result'];
|
|
const node = side && side[key + '_jawline_info'];
|
|
const quality = scalar(node && node[key + '_jawline_quality']);
|
|
const angle = scalar(node && node[key + '_jawline_angle']);
|
|
const status = quality == null ? 'unavailable' : quality === 1 && angle != null ? 'valid' : 'invalid';
|
|
result.views[key] = { quality, angle, status };
|
|
if (status === 'invalid') result.status = 'invalid';
|
|
else if (status === 'unavailable' && result.status === 'valid') result.status = 'unavailable';
|
|
}
|
|
return result;
|
|
}
|
|
module.exports = { normalize, assess };
|