'use strict'; const assert = require('assert/strict'); const fs = require('fs'); const vm = require('vm'); const path = require('path'); const SkinScore = require('../js/skin-score'); const ReportUI = require('../js/report-ui'); const result = JSON.parse(fs.readFileSync(path.join(__dirname, '../../reference/facepp-skinanalyze/examples/ref_3view_raw.json'))).result; const details = ReportUI.wrinkleDetails(result); assert.equal(details.length, 12); assert.equal(new Set(details.map(row => row.key)).size, 12); assert.equal(details[0].name, '抬头纹(额头纹)'); assert.deepEqual(details[0].metrics, { wrinkle_score: 13, wrinkle_severity_level: 1, wrinkle_deep_num: 22, wrinkle_shallow_num: 18, wrinkle_norm_length: result.forehead_wrinkle_info.wrinkle_norm_length, wrinkle_norm_depth: result.forehead_wrinkle_info.wrinkle_norm_depth, wrinkle_pixel_density: result.forehead_wrinkle_info.wrinkle_pixel_density, wrinkle_area_ratio: result.forehead_wrinkle_info.wrinkle_area_ratio, wrinkle_deep_ratio: result.forehead_wrinkle_info.wrinkle_deep_ratio }); assert.equal(details.find(row => row.key === 'left_eye').metrics.wrinkle_deep_num, 58); assert.equal(details.find(row => row.key === 'right_eye').metrics.wrinkle_shallow_num, 46); assert.equal(details.find(row => row.key === 'left_cheek').metrics.wrinkle_score, 0); const alternate = ReportUI.wrinkleDetails({ right_nasolabial_fold_info: { wrinkle_score: { value: 31 }, wrinkle_severity_level: { value: 2 } }, wrinkle_count: { right_nasolabial_count: 5 }, fine_line: { right_nasolabial_count: 0 } }); assert.equal(alternate.find(row => row.key === 'right_nasolabial').metrics.wrinkle_score, 31); assert.equal(alternate.find(row => row.key === 'right_nasolabial').metrics.wrinkle_deep_num, 5); assert.equal(alternate.find(row => row.key === 'right_nasolabial').metrics.wrinkle_shallow_num, 0); assert(Object.values(alternate[0].metrics).every(value => value === null)); const model = SkinScore.buildViewModel(result, SkinScore.MOCK_SIDE, { realAge: 30 }); const modelBefore = JSON.stringify(model), rawBefore = JSON.stringify(result); const presentation = ReportUI.build(model, result); const text = presentation.views.find(view => view.key === 'wrinkles').text; assert.deepEqual(presentation.views.find(view => view.key === 'wrinkles').details, details); assert(!text.includes('分区明细') && !text.includes('标准化长度')); const approved = { '预警': '全脸共检测到皱纹 12 条、细纹 34 条,面中、口周、眼周等区域已出现静态纹倾向,纹路已呈现固化趋势,并非临时性干纹。', '改善': '全脸共检测到皱纹 12 条、细纹 34 条,面部整体平整,仅眼周或口周有细微的干纹,无明显静态深纹,纹路面积占比相对较低。', '良好': '面中、口周、眼周等各区域均无明显皱纹沟壑,无静态深纹与粗纹,各类纹路面积均处于极低水平,面部整体平整细腻。' }; for (const level of Object.keys(approved)) { const fixture = JSON.parse(modelBefore); fixture.cats.wrinkles.level = level; fixture.cats.wrinkles.vars.wr_cnt = 12; fixture.cats.wrinkles.vars.fl_cnt = 34; assert.equal(ReportUI.build(fixture, result).views.find(view => view.key === 'wrinkles').text, approved[level]); } assert.equal(JSON.stringify(model), modelBefore); assert.equal(JSON.stringify(result), rawBefore); const excellent = JSON.parse(JSON.stringify(model)); excellent.cats.smooth.level = '良好'; // Legacy level name maps to new "优秀". excellent.cats.smooth.vars.pore_cnt = 7; excellent.cats.smooth.vars.blackhead_cnt = 2; let smooth = ReportUI.build(excellent, result).views.find(view => view.key === 'smooth'); assert(smooth.text.includes('粗大毛孔 7 颗、黑头 2 颗')); assert(!smooth.text.includes('无明显粗大毛孔')); assert.equal(smooth.level, '优秀'); excellent.cats.smooth.vars.pore_cnt = null; smooth = ReportUI.build(excellent, result).views.find(view => view.key === 'smooth'); assert(smooth.text.includes('未完整获取')); const source = fs.readFileSync(path.join(__dirname, '../js/app.js'), 'utf8'); const pure = source.match(/\/\* viz-pure-begin[\s\S]*?\*\/([\s\S]*?)\/\* viz-pure-end \*\//)[1]; const sandbox = {}; vm.runInNewContext(pure, sandbox); const crop = sandbox.vizFaceCrop(4000, 3000, { left: 1479, top: 1133, width: 1116, height: 1116 }); assert(crop.focused); assert(crop.width < 1600 && crop.height < 1800); assert(crop.left <= 1479 && crop.top <= 1133); assert(crop.left + crop.width >= 2595 && crop.top + crop.height >= 2249); assert(Math.abs(crop.width / crop.height - 215 / 278) < 1e-8); for (const rect of [null, { left: NaN }, { left: 0, top: 0, width: -1, height: 20 }, { left: 3900, top: 0, width: 1000, height: 1000 }, { left: 0, top: 0, width: '100', height: 100 }]) { const full = sandbox.vizFaceCrop(4000, 3000, rect); assert.equal(full.focused, false); assert.equal(full.width, 4000); } for (const rect of [{ left: 0, top: 0, width: 300, height: 300 }, { left: 700, top: 700, width: 300, height: 300 }]) { const edge = sandbox.vizFaceCrop(1000, 1000, rect); assert(edge.focused); assert(edge.left >= 0 && edge.top >= 0); assert(edge.left + edge.width <= 1000 && edge.top + edge.height <= 1000); assert(edge.left <= rect.left && edge.top <= rect.top); assert(edge.left + edge.width >= rect.left + rect.width && edge.top + edge.height >= rect.top + rect.height); } console.log('PASS: 12 unique wrinkle regions, all nine real metrics, aliases/count fallbacks, missing≠zero; positive pore counts vs excellent score; no raw/model/algorithm mutations; face crop/aspect/edge containment/invalid-box fallback');