【免费下载链接】wechat-radar
微信聊天情报看板:聚合群聊信号、话题、链接和趋势
wechat-radar 是一个微信聊天情报看板,它的「链接情报」模块专门解决一个痛点:同一个好链接被 20 个群、30 个人反复转发,到底值不值得点开?本文将完整拆解它的链接去重机制与标题生成流程——从 URL 规范化、按天聚合,到 AI 语义去重和可读中文标题,带你搞清楚每个环节是怎么做的。
群聊链接为什么需要"链接情报"?
先感受一下群聊里的真实场景:
- 一篇技术文章,早上在 5 个群各被转一次,URL 还带着不同的
utm_参数和锚点; - 同一个开源工具,有人发官网、有人发 GitHub 镜像、有人只甩一句"这工具不错"加短链;
- 很多链接干脆没有标题,点开才知道是什么。
wechat-radar 的思路是:先提取、再规范化去重、再按天聚合、最后生成可读标题,把"刷屏噪音"变成一份每天 24 条以内、可直接处理的情报列表。
链路全景:一条群消息的 4 个旅程阶段
| 阶段 | 做什么 | 关键代码位置 |
|---|---|---|
| ① 链接提取 | 从消息正文中解析出所有 URL,识别微信原文卡片 | lib/message-links.ts |
| ② 规范化入库 | 生成canonical_url,写入message_links表并带置信度 | lib/message-links.ts |
| ③ 按天聚合去重 | 按类型 + 规范URL分桶,统计次数与来源群 | lib/link-intelligence.ts |
| ④ 标题生成与 AI 去重 | 抓网页标题 + Codex 生成中文标题和group_key | lib/link-intelligence.ts |
页面入口是「链接情报」页(app/links/page.tsx),它请求/api/topics/links拿到当天的文章与工具两个列表。
第一层去重:canonical_url 把"同一个链接"变成同一个 key
这一层解决的是机器层面的重复。在 lib/message-links.ts 的normalizeUrl中做了三件事:
- 清洗 URL 尾巴:去掉聊天里常见的结尾标点(
),。;等)和截断省略号; - 删除跟踪参数:
utm_source、utm_medium、utm_campaign等 5 个参数一律剥离; - 去掉 hash 锚点,统一得到规范地址
canonical_url。
也就是说,https://mp.weixin.qq.com/s/abc?utm_source=group和https://mp.weixin.qq.com/s/abc在数据库里是同一条记录。入库时以(chatroom_id, local_id, canonical_url)为主键做 upsert(lib/db.ts),同一条消息里的重复链接只保留置信度最高的来源——微信原文卡片wechat_raw(置信度 1.0)优先于普通网页链接plain_url(0.9)。
第二层去重:按天聚合,数清楚"谁发了几次"
每天的链接情报由 getDailyLinkIntelligence 生成,逻辑非常直观:
- 分桶键=
文章/工具 : canonical_url,同一个链接在当天只算一个条目; - count= 当天总转发次数,group_count= 来自多少个不同群;
- 每个条目保留来源明细(哪个群、谁发的、几点、消息片段),并用
first_seen/last_seen记录首末出现时间; - 排序规则是
转发次数 > 覆盖群数 > 最近出现时间,每类最多取 24 条(常量定义)。
📌 一个链接如果"8 次转发、来自 5 个群",它几乎必然比"1 次转发、1 个群"的链接更值得点开——这就是聚合去重后的价值。
标题生成:三级兜底,从聊天上下文到网页真实标题
刚入库的链接标题往往不理想,wechat-radar 用三层策略逐步"升级"标题:
① 聊天上下文标题
入库时优先取微信卡片里的<title>字段;没有的话,从消息正文里挑一行 4–90 字的中文内容当临时标题(titleFromContext)。
② 网页真实标题
对标题太短或只剩域名的条目,并发抓取网页,优先读og:title,其次twitter:title,最后才是<title>,并自动去掉" - 微信公众平台"这类后缀(fetchTitle)。单次请求 1.4 秒超时、每类最多抓 8 条,抓到即写入 24 小时缓存,避免重复请求。
③ AI 生成可读中文标题
这是核心。系统会把候选链接(含 URL、域名、当前标题、前 3 条群聊片段)打包成 JSONL,交给 Codex CLI,提示词要求很具体(buildTitleGenerationPrompt):
- 标题要短、具体、可点击,保留产品名/文章主题/工具名;
- 去掉寒暄、@人名、表情、"老师"等噪声;
- 用
--output-schema约束输出为严格 JSON,防止模型自由发挥。
AI 语义去重:用 group_key 合并"URL 不同但内容相同"的链接
canonical_url 解决不了的情况:同一个工具,A 群发官网、B 群发 GitHub 页面——URL 不同,语义相同。
解法是让模型在生成标题的同时,为每个链接输出一个group_key(小写字母/数字/短横线):同一个工具、同一篇文章、同一组资料,哪怕 URL 不同也给相同 key。随后 mergeDuplicateItems 按类型 + group_key再次合并:次数累加、来源合并、首末时间取并集。
💡 如果 Codex 不可用或超时(默认 180 秒),系统会优雅降级:用"标题去符号取前 40 字符"作为兜底 key(fallbackDedupeKey),保证链接情报功能始终可用。
缓存与"重新整理":刷新一次,管一整天
每天的整理结果(含标题和去重 key)会同时写入:
- 内存缓存:TTL 24 小时;
- SQLite 表
link_intelligence_cache:以日期 + 版本(当前 v8)为主键持久化(lib/db.ts)。
下次打开页面直接读缓存,秒开。对结果不满意?点页面上的「重新整理」按钮(refreshLinks),带refresh=1参数强制重算并覆盖缓存——标题生成、AI 去重都会重新执行一遍。
链接情报页面怎么看:三个面板各有什么用
打开「链接情报」页,按日期查看:
| 面板 | 内容 | 看点 |
|---|---|---|
| 文章链接 | 去重后的文章列表 | 标题 + 域名 + "N 次 · 时间",点击可跳回来源群 |
| 工具与资源 | 去重后的工具/资源列表 | 按域名特征 + 聊天关键词判断类型(isToolLink) |
| 微信文章链接 | 当天原始微信文章链接 | 未聚合的原始明细,带解析来源标签,方便核对 |
每条情报都能点回「群名 · 发送人」,一键回到消息现场。
核心文件速查
- 链接提取与规范化:lib/message-links.ts
- 聚合去重与标题生成:lib/link-intelligence.ts
- 补扫历史消息中的链接:app/api/message-links/backfill/route.ts
- 手动/公开搜索补链:app/api/message-links/resolve/route.ts
- 页面:app/links/page.tsx
常见问题
问:昨天的链接没被识别出来?用「重扫」重新同步消息,或调用 backfill 接口按日期范围补扫历史消息(backfillMessageLinks 会全量重解析含http的消息)。
问:标题还是域名,不是文章名?hydrateTitles每天只对标题缺失的条目抓 8 条网页、单条 1.4 秒超时,冷门页面可能抓不到;点「重新整理」再试一次即可。
问:AI 去重需要装什么?需要本机可运行codexCLI;未安装时自动降级为规则兜底,不影响基础去重。
wechat-radar 的链接情报 =canonical_url 机器去重 × 按天聚合计数 × 三级标题生成 × AI 语义合并。四层机制叠加,让好链接从群聊噪音里浮出来。数据全程留在你自己的本机 SQLite(~/.wechat-radar/radar.db),不上传任何第三方服务。
【免费下载链接】wechat-radar
微信聊天情报看板:聚合群聊信号、话题、链接和趋势
相关推荐
告别URL混乱:Laravel Sluggable 让SEO友好链接自动生成
告别URL混乱:Laravel Sluggable 让SEO友好链接自动生成 你是否还在手动处理URL中的特殊字符?是否为重复标题导致的404错误头疼不已?是否
Zola 站内链接与锚点(Deep Linking)完全指南:标题 ID 生成、锚点插入与 `@/` 内部链接解析
Zola 站内链接与锚点(Deep Linking)完全指南:标题 ID 生成、锚点插入与 @/ 内部链接解析 Zola 是一个把站点生成、模板渲染、Sass
静态站点CLI开发工具marked 自动链接(Autolink)行为深度解析:链接后的裸 URL 如何被正确识别
marked 自动链接(Autolink)行为深度解析:链接后的裸 URL 如何被正确识别 导读 本文围绕 marked 仓库中的规范测试用例 autolink
前端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考