From c06d15a2d44d7c2c4278542bfde5ceee52468eab Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 28 Sep 2026 22:45:57 +0800 Subject: [PATCH] =?UTF-8?q?chore+perf:=20=E5=AF=86=E9=92=A5=E5=87=BA?= =?UTF-8?q?=E5=BA=93=20+=20=E5=90=8E=E5=8F=B0=E8=AF=A6=E6=83=85=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E8=A3=81=E5=89=AA=20face=5Fmaps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 安全: - reference/facepp-skinanalyze/credentials.env 内含 Face++ 正式 key/secret 且被 git 跟踪,移出 index(文件保留本地,.gitignore 已覆盖 *.env)。 ⚠️ 密钥已存在于 git 历史,若 origin 曾被 push 即视为泄漏, 请在旷视控制台重置 API secret,改用环境变量/apikey.bash 注入。 性能(后台详情页卡顿): - 详情接口将 raw_json.result.face_maps 的 base64 图层(单条约 3MB) 替换为占位说明,响应 3.2MB→163KB;新增 GET /api/admin/records/:id/raw 供下载完整原始 JSON(走 Basic Auth) - admin 列表/详情图片加 loading=lazy + decoding=async --- h5/js/admin.js | 11 ++++--- h5/server.js | 30 +++++++++++++++++++- reference/facepp-skinanalyze/credentials.env | 16 ----------- 3 files changed, 36 insertions(+), 21 deletions(-) delete mode 100644 reference/facepp-skinanalyze/credentials.env diff --git a/h5/js/admin.js b/h5/js/admin.js index b86e579..7c49b36 100644 --- a/h5/js/admin.js +++ b/h5/js/admin.js @@ -115,7 +115,7 @@ function loadRecords() { var tr = el('tr'); var photos = it.photos || {}; var thumb = photos.front - ? '正脸' + ? '正脸' : '无'; tr.innerHTML = '' + thumb + '' + @@ -321,7 +321,7 @@ function renderDetail(data) { var u = data.photos[w]; if (!u) continue; anyPhoto = true; - photosHtml += '
' + whichNames[w] + '' + + photosHtml += ''; } photosHtml += anyPhoto ? '' : '无照片'; @@ -429,9 +429,12 @@ function renderDetail(data) { } } - /* 接口原始 JSON:details 折叠,pre 展示 */ + /* 接口原始 JSON:details 折叠,pre 展示(face_maps 已在服务端裁剪,完整版走下载链接) */ if (data.raw_json) { - h += dSec('接口原始 JSON', '
展开/收起(raw_json,' + (data.raw_file || '') + ')
' +
+    var rawDl = data.raw_file
+      ? ' 下载完整原始 JSON'
+      : '';
+    h += dSec('接口原始 JSON', '
展开/收起(' + (data.raw_file || '') + ')' + rawDl + '
' +
       esc(JSON.stringify(data.raw_json, null, 1)) + '
'); } else { h += dSec('接口原始 JSON', '
无(失败记录或未落盘)
'); diff --git a/h5/server.js b/h5/server.js index f8d62e6..87ad22a 100644 --- a/h5/server.js +++ b/h5/server.js @@ -524,13 +524,23 @@ function handleRecordsQuery(req, res, url) { function handleRecordDetail(req, res, id) { const rec = findRecord(id); if (!rec) return sendJson(res, 404, { ok: false, message: '记录不存在' }); - // 原始 JSON 全文:读文件失败给 null + // 原始 JSON 全文:读文件失败给 null。 + // face_maps 是整幅 base64 叠加图(单文件可达数 MB),详情页直接渲染会卡死浏览器: + // 展示层把各图层值替换为占位说明,完整原文件走 /api/admin/records/:id/raw 下载 let rawJson = null; if (rec.raw_file) { const fname = String(rec.raw_file).replace(/[^\w.,-]/g, ''); try { rawJson = JSON.parse(fs.readFileSync(path.join(DATA_DIR, fname), 'utf8')); } catch (e) { rawJson = null; } } + if (rawJson && rawJson.result && rawJson.result.face_maps) { + for (const k of Object.keys(rawJson.result.face_maps)) { + const v = rawJson.result.face_maps[k]; + if (typeof v === 'string' && v.length) { + rawJson.result.face_maps[k] = ``; + } + } + } // 版本链:它 retry_of 指向的(父)+ retry_of 指向它的(子) const all = readAllRecords(); const parent = rec.retry_of ? (all.find(r => r.record_id === rec.retry_of) || null) : null; @@ -548,6 +558,22 @@ function handleRecordDetail(req, res, id) { }); } +/* 完整原始 JSON 下载(face_maps base64 未裁剪,动辄数 MB,仅供复核下载,不做页面内展示) */ +function handleRawDownload(req, res, id) { + const rec = findRecord(id); + if (!rec || !rec.raw_file) return sendJson(res, 404, { ok: false, message: '记录或原始 JSON 不存在' }); + const fname = String(rec.raw_file).replace(/[^\w.,-]/g, ''); + const file = path.join(DATA_DIR, fname); + fs.readFile(file, (err, data) => { + if (err) return sendJson(res, 404, { ok: false, message: '原始 JSON 文件不存在' }); + res.writeHead(200, { + 'Content-Type': 'application/json; charset=utf-8', + 'Content-Disposition': `attachment; filename="${rec.record_id}-raw.json"` + }); + res.end(data); + }); +} + function handlePhoto(req, res, id, which) { const safe = String(id || '').replace(/[^\w-]/g, ''); const file = path.join(PHOTOS_DIR, safe, which + '.jpg'); @@ -710,6 +736,8 @@ async function handleAdmin(req, res, pathname, url) { try { const retryM = pathname.match(/^\/api\/admin\/records\/([\w-]+)\/retry$/); if (req.method === 'POST' && retryM) return await handleRetry(req, res, retryM[1]); + const rawM = pathname.match(/^\/api\/admin\/records\/([\w-]+)\/raw$/); + if (req.method === 'GET' && rawM) return handleRawDownload(req, res, rawM[1]); const detailM = pathname.match(/^\/api\/admin\/records\/([\w-]+)$/); if (req.method === 'GET' && detailM) return handleRecordDetail(req, res, detailM[1]); const photoM = pathname.match(/^\/api\/admin\/photos\/([\w-]+)\/(front|left|right)$/); diff --git a/reference/facepp-skinanalyze/credentials.env b/reference/facepp-skinanalyze/credentials.env deleted file mode 100644 index 95b2382..0000000 --- a/reference/facepp-skinanalyze/credentials.env +++ /dev/null @@ -1,16 +0,0 @@ -# ~/.openclaw/credentials.env — 统一凭据存放(勿提交 git、勿发到聊天) -# 用法: set -a; source ~/.openclaw/credentials.env; set +a - -# ---- 旷视 Face++(巨子测肤 skinanalyze_pro 测试接口)---- -# 试用key(cAa5...)已弃用: 旷视规则试用key不能调专业版。当前为正式key(EcZ...) -FACEPP_API_KEY=EcZiqYhA8eQSiRgXVem8mijgzPfSC2qp -FACEPP_API_SECRET=p62QRWv9tQitZ1tvXmEBV8AgmaS00lO8 - -# ---- FaceStyle 专业版调用参数 ---- -FACEPP_SKINANALYZE_URL=https://api-cn.faceplusplus.com/facepp/v1/skinanalyze_pro - -# ---- 飞书 / OCR(合同盖章核验项目)---- -# 实际值在 ~/Desktop/合同盖章核验项目/service/.env(未入库) - -# ---- 智谱 / 火山引擎 ---- -# 已存于 ~/.zshrc 及 openclaw.json providers 配置