From 2049bc8c6e79d4fc9b27b5440a73965149da28db Mon Sep 17 00:00:00 2001 From: john Date: Mon, 21 Sep 2026 09:31:54 +0800 Subject: [PATCH] fix(news): count lead cards in degradation check, add draft dry-run script Trying to push a WeChat draft locally surfaced two problems. isNewsMorningContentDegraded matched cards with `class="card(?:\s|")`, which never matches news002's `class="lead-card"`. Headline cards were therefore invisible to the check, so a healthy news002 page could be flagged as degraded and regenerated. Count cards through the shared extractor instead, which handles card, lead-card and highlight-box alike. Add scripts/dryrun-news-morning-draft.mjs to run a page through the dedup gate, degradation check, inline conversion and footer layout without calling the WeChat API, since local IPs are not in the official account whitelist (errcode 40164) and a real push would write into the production draft box. Co-authored-by: Cursor --- scripts/dryrun-news-morning-draft.mjs | 85 +++++++++++++++++++++++++++ wechat-news-morning-dedup.mjs | 7 ++- wechat-news-morning-dedup.test.mjs | 13 ++++ wechat-news-morning-draft.mjs | 7 ++- wechat-news-morning-draft.test.mjs | 13 ++++ 5 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 scripts/dryrun-news-morning-draft.mjs diff --git a/scripts/dryrun-news-morning-draft.mjs b/scripts/dryrun-news-morning-draft.mjs new file mode 100644 index 0000000..0506c0c --- /dev/null +++ b/scripts/dryrun-news-morning-draft.mjs @@ -0,0 +1,85 @@ +#!/usr/bin/env node +/** + * 本地 dry-run:把一张早报 HTML 走完「去重闸门 → 微信 inline 转换 → 统一页脚」全链路, + * 输出最终草稿正文,但不调用任何微信接口、不落 DB。 + * + * 用于在本机 IP 不在公众号白名单时验证 news001 / news002 的草稿产出。 + * + * 用法: + * node scripts/dryrun-news-morning-draft.mjs <页面.html> [输出目录] + */ +import fs from 'node:fs'; +import path from 'node:path'; +import { + dedupeNewsMorningHtml, + formatNewsMorningDedupeSummary, +} from '../wechat-news-morning-dedup.mjs'; +import { + convertNewsPageHtmlToWechatArticle, + isDailyNewsFormat, + isNewsMorningContentDegraded, +} from '../wechat-news-morning-draft.mjs'; + +const MAX_WECHAT_CONTENT_CHARS = 20000; + +const input = process.argv[2]; +const outDir = process.argv[3] || path.dirname(input ?? '.'); +if (!input || !fs.existsSync(input)) { + console.error('用法:node scripts/dryrun-news-morning-draft.mjs <页面.html> [输出目录]'); + process.exit(1); +} + +const publicUrl = 'https://m.tkmind.cn/MindSpace/dry-run/public/daily-news-dryrun.html'; +const raw = fs.readFileSync(input, 'utf8'); + +console.log(`输入:${input}(${raw.length} 字符)`); + +// 1. 去重闸门 +const deduped = dedupeNewsMorningHtml(raw); +console.log(`\n[1] 去重闸门:${formatNewsMorningDedupeSummary(deduped)}`); +if (deduped.removedSectionIds.length) { + console.log(` 移除空栏目:${deduped.removedSectionIds.join(', ')}`); +} + +// 2. 降级检测 +const degraded = isNewsMorningContentDegraded(deduped.html); +console.log(`\n[2] 降级检测:${degraded ? '❌ 判定为降级页(卡片不足/检索失败)' : '✅ 正常'}`); + +// 3. 识别版式 + 转换为微信草稿 +console.log(`\n[3] 版式识别:${isDailyNewsFormat(deduped.html) ? '✅ daily-news' : '❌ 非早报版式'}`); + +const article = convertNewsPageHtmlToWechatArticle( + deduped.html, + { publicUrl, qrcodeImageUrl: 'https://mmbiz.qpic.cn/dryrun-qrcode.png' }, +); + +console.log('\n[4] 草稿产出:'); +console.log(` 标题:${article.title}`); +console.log(` 摘要:${String(article.digest ?? '').slice(0, 60)}`); +console.log(` 正文长度:${article.content.length} / ${MAX_WECHAT_CONTENT_CHARS}` + + (article.content.length > MAX_WECHAT_CONTENT_CHARS ? ' ❌ 超限' : ' ✅ 未超限')); + +const checks = [ + // 微信不支持