diff --git a/wechat-news-morning-draft-worker.mjs b/wechat-news-morning-draft-worker.mjs index 5a688e1..7931cbf 100644 --- a/wechat-news-morning-draft-worker.mjs +++ b/wechat-news-morning-draft-worker.mjs @@ -24,6 +24,7 @@ import { auditNews002ImageCoverage, enrichNews002HtmlWithSourceImages, pruneNews002ImagelessStoryCards, + stripNews002ImagelessStoryCards, } from './wechat-news-morning-images.mjs'; import { isWechatNewsMorningDraftWorkerEnabled, @@ -71,17 +72,16 @@ function applyNewsMorningDedupe(page, logger) { } } -function finalizeNews002Html(html, logger, page, label) { - const pruned = pruneNews002ImagelessStoryCards(html); - if (pruned.removedCards > 0 || pruned.removedSections > 0) { - logger.log?.('[NewsMorningDraft] news002 pruned imageless cards', { +function stripNews002ForGate(html, logger, page, label) { + const stripped = stripNews002ImagelessStoryCards(html); + if (stripped.removedCards > 0) { + logger.log?.('[NewsMorningDraft] news002 stripped imageless cards', { slug: page.slug, phase: label, - removedCards: pruned.removedCards, - removedSections: pruned.removedSections, + removedCards: stripped.removedCards, }); } - return pruned.html; + return stripped.html; } async function applyNews002ImageGate( @@ -95,7 +95,7 @@ async function applyNews002ImageGate( if (!page?.localPath || !fs.existsSync(page.localPath)) { throw new Error('news002 配图闸门无法读取生成页面'); } - let source = finalizeNews002Html(fs.readFileSync(page.localPath, 'utf8'), logger, page, 'pre-enrich'); + let source = stripNews002ForGate(fs.readFileSync(page.localPath, 'utf8'), logger, page, 'pre-enrich'); let enriched = await enrichNews002HtmlWithSourceImages(source, { timeoutMs: Number(env.MEMIND_NEWS_MORNING_IMAGE_META_TIMEOUT_MS ?? 6000) || 6000, concurrency: Number(env.MEMIND_NEWS_MORNING_IMAGE_META_CONCURRENCY ?? 8) || 8, @@ -155,6 +155,15 @@ async function applyNews002ImageGate( + `(卡片 ${audit.cardCount},真实配图 ${audit.imageCount},头条配图 ${audit.leadImageCount}/${audit.leadCount})`, ); } + const display = pruneNews002ImagelessStoryCards(enriched.html); + if (display.removedCards > 0 || display.removedSections > 0) { + logger.log?.('[NewsMorningDraft] news002 display prune after gate', { + slug: page.slug, + removedCards: display.removedCards, + removedSections: display.removedSections, + }); + fs.writeFileSync(page.localPath, display.html); + } return audit; } diff --git a/wechat-news-morning-draft.mjs b/wechat-news-morning-draft.mjs index 88b6710..6b83d2c 100644 --- a/wechat-news-morning-draft.mjs +++ b/wechat-news-morning-draft.mjs @@ -25,7 +25,7 @@ import { countNewsMorningStoryCards } from './wechat-news-morning-dedup.mjs'; import { auditNews002ImageCoverage, extractNews002CardImageUrls, - pruneNews002ImagelessStoryCards, + stripNews002ImagelessStoryCards, } from './wechat-news-morning-images.mjs'; import { NEWS001_FRESH_CONTENT_SPEC, @@ -837,8 +837,11 @@ export async function buildDailyNewsWechatDraftArticleForPush({ memindLibRoot, }); if (/class="[^"]*\bmasthead\b/i.test(String(html ?? ''))) { - html = pruneNews002ImagelessStoryCards(String(html ?? '')).html; - const audit = auditNews002ImageCoverage(html, { requireTemplateStructure: true }); + html = stripNews002ImagelessStoryCards(String(html ?? '')).html; + const audit = auditNews002ImageCoverage(html, { + requireTemplateStructure: true, + requireAllCoreSections: false, + }); if (!audit.ok) { throw new Error(`news002 页面未通过推送闸门:${audit.violations.join(', ')}`); } diff --git a/wechat-news-morning-images.mjs b/wechat-news-morning-images.mjs index b468790..1b0cde7 100644 --- a/wechat-news-morning-images.mjs +++ b/wechat-news-morning-images.mjs @@ -254,8 +254,8 @@ function pruneEmptyNews002Sections(html) { return { html: output, removedSections }; } -/** 移除无图故事卡并清理空栏目,保证页面只展示有配图的条目。 */ -export function pruneNews002ImagelessStoryCards(html) { +/** 仅移除无图故事卡,不删空栏目(闸门阶段用,避免 fallback 补栏后被误删)。 */ +export function stripNews002ImagelessStoryCards(html) { let output = String(html ?? ''); let removedCards = 0; const imageless = extractNews002StoryCards(output) @@ -264,10 +264,16 @@ export function pruneNews002ImagelessStoryCards(html) { output = output.slice(0, card.start) + output.slice(card.end); removedCards += 1; } - const prunedSections = pruneEmptyNews002Sections(output); + return { html: output, removedCards, removedSections: 0 }; +} + +/** 移除无图故事卡并清理空栏目(推送/展示前用,保证页面协调)。 */ +export function pruneNews002ImagelessStoryCards(html) { + const stripped = stripNews002ImagelessStoryCards(html); + const prunedSections = pruneEmptyNews002Sections(stripped.html); return { html: prunedSections.html, - removedCards, + removedCards: stripped.removedCards, removedSections: prunedSections.removedSections, }; } @@ -353,22 +359,26 @@ export async function enrichNews002HtmlWithSourceImages( output = output.slice(0, card.start) + replacement + output.slice(card.end); } - const pruned = pruneNews002ImagelessStoryCards(output); - const remainingCards = extractNews002StoryCards(pruned.html).filter((card) => card.title); + const stripped = stripNews002ImagelessStoryCards(output); + const remainingCards = extractNews002StoryCards(stripped.html).filter((card) => card.title); return { - html: pruned.html, + html: stripped.html, cardCount: remainingCards.length, attemptedCount: unresolved.length, resolvedCount, - removedCards: pruned.removedCards, - removedSections: pruned.removedSections, + removedCards: stripped.removedCards, + removedSections: 0, }; } export function auditNews002ImageCoverage( html, - { maxStoryCards = 28, requireTemplateStructure = false } = {}, + { + maxStoryCards = 28, + requireTemplateStructure = false, + requireAllCoreSections = true, + } = {}, ) { const source = String(html ?? ''); const cards = extractNews002StoryCards(source).filter((card) => card.title); @@ -422,8 +432,10 @@ export function auditNews002ImageCoverage( } return false; }; - const missingSections = requiredSectionIds.filter((id) => !hasNews002Section(id)); - if (missingSections.length > 0) violations.push(`missing-sections:${missingSections.join('|')}`); + if (requireAllCoreSections) { + const missingSections = requiredSectionIds.filter((id) => !hasNews002Section(id)); + if (missingSections.length > 0) violations.push(`missing-sections:${missingSections.join('|')}`); + } if (cards.some((card) => !card.eventKey)) violations.push('missing-event-key'); if (cards.some((card) => !card.url)) violations.push('missing-source-url'); if (cards.some((card) => !/class="[^"]*\bbody\b/i.test(card.raw))) {