From b74ab4ec46924be05c6928438816de5163079dc9 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 22 Sep 2026 07:36:20 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(wechat):=20news002=20=E8=8D=89?= =?UTF-8?q?=E7=A8=BF=E5=B7=A6=E4=B8=8A=E8=A7=92=E5=B0=8F=E5=9B=BE=EF=BC=8C?= =?UTF-8?q?=E9=85=8D=E5=9B=BE=E6=9C=AC=E5=9C=B0=E5=8C=96=E4=B8=94=E7=BC=BA?= =?UTF-8?q?=E5=9B=BE=E4=BF=9D=E7=95=99=E6=96=87=E5=AD=97=E5=8D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 微信 inline 与静态页 lead-card 统一为左侧缩略图;远程配图下载到当日 public/ 后再上传微信素材。SearXNG 预取与配图 enrichment 链路同步收紧,禁止默认占位小图删卡。 Co-authored-by: Cursor --- .env.example | 6 + docs/news-morning-templates.md | 17 +- mindsearch-providers.mjs | 2 + mindsearch.test.mjs | 13 ++ news-morning-templates.mjs | 25 +-- scripts/trigger-news002-generate-draft.mjs | 3 - wechat-daily-news-inline.mjs | 89 ++++++++- wechat-daily-news-inline.test.mjs | 13 +- wechat-news-morning-draft-worker.mjs | 16 +- wechat-news-morning-draft-worker.test.mjs | 63 +++++++ wechat-news-morning-draft.mjs | 6 +- wechat-news-morning-images.mjs | 208 ++++++++++++++++++++- wechat-news-morning-images.test.mjs | 157 +++++++++++++++- wechat-news-morning-search.mjs | 62 ++++-- wechat-news-morning-search.test.mjs | 51 ++++- 15 files changed, 664 insertions(+), 67 deletions(-) diff --git a/.env.example b/.env.example index 99403ab..9ac35e4 100644 --- a/.env.example +++ b/.env.example @@ -230,6 +230,7 @@ H5_PUBLIC_BASE_URL=http://127.0.0.1:5173 # H5_SCHEDULED_TASK_MAX_ATTEMPTS=3 # H5_SCHEDULED_TASK_EXECUTION_TIMEOUT_MS=900000 # 新闻早报 · 微信草稿箱自动 worker(默认跟随 H5_REMINDER_WORKER_ENABLED) +# 每天自动生成并推草稿:ENABLED + AUTO + AUTO_GENERATE 都要开;时刻以 DB 配置为准。 # H5_WECHAT_NEWS_MORNING_DRAFT_ENABLED=1 # H5_WECHAT_NEWS_MORNING_DRAFT_AUTO=1 # H5_WECHAT_NEWS_MORNING_DRAFT_WORKER_ENABLED=1 @@ -530,6 +531,11 @@ VITE_TKMIND_WORKING_DIR=/Users/john/PycharmProjects/tkmind # Template source: /Users/john/Project/searxng-prod/settings.yml.template # Goosed MCP endpoints are automatically rewritten to host.docker.internal. # TKMIND_SEARCH_SEARXNG_URL=http://127.0.0.1:20080/search +# 早报预取:默认走通用搜索(Yandex/Bing/360),最多 3 路并行,避免打满连接池和触发验证码。 +# MEMIND_NEWS_MORNING_SEARXNG_PREFETCH=1 +# MEMIND_NEWS_MORNING_SEARXNG_NEWS_CATEGORY=0 +# MEMIND_NEWS_MORNING_SEARXNG_CONCURRENCY=3 +# MEMIND_NEWS_MORNING_SEARXNG_ENGINES=yandex,bing,360search # Portal 在 web / search-enhanced 技能执行前预取 SearXNG;设为 0 可关闭。 # MEMIND_LIVE_SEARCH_PREFETCH=1 # TKMIND_SEARCH_MCP_HOST_GATEWAY=host.docker.internal diff --git a/docs/news-morning-templates.md b/docs/news-morning-templates.md index 5ee7647..b665bb1 100644 --- a/docs/news-morning-templates.md +++ b/docs/news-morning-templates.md @@ -60,9 +60,9 @@ prompt 层的「禁止重复」无法验证,所以在落盘后再做一次程 链路:SearXNG `img_src`/`thumbnail` → `normalizeSearchResult()` 透传 `image`/`publishedAt` → 预取 brief 里以 `图:{URL}` 单独成行 → Agent 写进 `.card .media > img`。 -- 有图:`loading="lazy"` + `referrerpolicy="no-referrer"` + `onerror` 降级为占位 -- 无图:`
{栏目 emoji}
`,版式不塌 -- 禁止张冠李戴、禁止编造图片地址、禁止整页长图 +- 有真实图:必须显示,`loading="lazy"` + `referrerpolicy="no-referrer"` +- 无图:先抓来源页 `og:image` / `twitter:image`;仍没有就不放配图,保留文字卡 +- 禁止默认小图凑数、禁止张冠李戴、禁止编造图片地址、禁止整页长图 ### 4. 视觉与排版 @@ -99,11 +99,14 @@ CSS 固化在 `NEWS002_STYLE_BLOCK`,直接内嵌进 taskSpec,Agent 照抄即 | 导语 | `.subtitle` | `.lede` | news002 的卡片图会先上传到微信正文素材接口,再由 inline 渲染器输出微信 CDN 地址。 -任一新闻卡缺少真实同源图片、图片上传失败、头条不是 3~4 条、事件卡超过 28 条, -或页面仍混有 news001 DOM,都会由生成/推送闸门阻断,不允许进入草稿箱。 +静态页与微信草稿均使用 **左上角 72~92px 小图**(`.card` / `.lead-card` 左侧缩略图),不再用全宽大图。 +能拿到真实配图的卡片必须显示并上传;没有真实图就只保留文字卡,不放默认小图。 +远程配图会先下载到当日 MindSpace `public/`,改写成本站相对 URL,避免海外图源在国内打不开。 +已有配图上传失败、头条不是 3~4 条、事件卡超过 28 条,或页面仍混有 news001 DOM, +才会由生成/推送闸门阻断,不允许进入草稿箱。 -真实图片来源按优先级取文章来源的 `og:image:secure_url`、`og:image`、 -`twitter:image`;不使用与事件无法核验关系的泛图片搜索结果。 +真实图片来源按优先级取 SearXNG 结果里的 `img_src`/`thumbnail`,以及文章来源的 +`og:image:secure_url`、`og:image`、`twitter:image`;不使用与事件无法核验关系的泛图片搜索结果。 ## 预览与验证 diff --git a/mindsearch-providers.mjs b/mindsearch-providers.mjs index a79aa7a..44c29c2 100644 --- a/mindsearch-providers.mjs +++ b/mindsearch-providers.mjs @@ -9,6 +9,7 @@ export async function searchSearxng(query, { signal, categories = '', language = '', + engines = '', } = {}) { if (!endpoint) throw new Error('SearXNG endpoint is not configured'); try { if (!['http:', 'https:'].includes(new URL(endpoint).protocol)) throw new Error('unsupported protocol'); } catch { throw new Error('SearXNG endpoint is not configured safely'); } @@ -17,6 +18,7 @@ export async function searchSearxng(query, { url.searchParams.set('format', 'json'); if (categories) url.searchParams.set('categories', String(categories)); if (language) url.searchParams.set('language', String(language)); + if (engines) url.searchParams.set('engines', String(engines)); const timeout = AbortSignal.timeout(timeoutMs); const response = await fetchImpl(url, { signal: signal ? AbortSignal.any([signal, timeout]) : timeout, diff --git a/mindsearch.test.mjs b/mindsearch.test.mjs index 7fb5d4f..d6a8d4e 100644 --- a/mindsearch.test.mjs +++ b/mindsearch.test.mjs @@ -215,6 +215,19 @@ test('SearXNG adapter can request news category and language', async () => { assert.match(requested, /language=zh-CN/); }); +test('SearXNG adapter can pin engines', async () => { + let requested; + await searchSearxng('今日热点', { + endpoint: 'http://search.local/search', + engines: 'yandex,bing', + fetchImpl: async (url) => { + requested = String(url); + return { ok: true, json: async () => ({ results: [] }) }; + }, + }); + assert.match(requested, /engines=yandex%2Cbing|engines=yandex,bing/); +}); + test('GitHub code adapter sends bounded queries and normalizes results', async () => { let requested; const result = await searchGithubCode('repo:openai goose', { limit: 50, fetchImpl: async (url, options) => { requested = { url: String(url), options }; return { ok: true, json: async () => ({ items: [{ repository: { full_name: 'openai/goose', description: 'agent' }, path: 'src/goose.rs', html_url: 'https://github.com/openai/goose/blob/main/src/goose.rs' }] }) }; } }); diff --git a/news-morning-templates.mjs b/news-morning-templates.mjs index 717f16d..6702b90 100644 --- a/news-morning-templates.mjs +++ b/news-morning-templates.mjs @@ -186,15 +186,16 @@ export const NEWS002_STYLE_BLOCK = `