news 2026/10/2 13:27:20

zotero-arxiv-daily 使用指南:基于 Zotero 文献库的 arXiv 每日论文自动推荐与邮件推送

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
zotero-arxiv-daily 使用指南:基于 Zotero 文献库的 arXiv 每日论文自动推荐与邮件推送
  • 人工智能
  • AI 应用
  • RAG
  • 科研

【免费下载链接】zotero-arxiv-daily

Recommend new arxiv papers of your interest daily according to your Zotero libarary.

项目地址:https://gitcode.com/GitHub_Trending/zo/zotero-arxiv-daily
点击查看免费下载

本文是一份面向研究者的实战部署指南,围绕开源项目Zotero-arXiv-Daily展开:它通过读取你 Zotero 文献库的上下文,每天自动检索 arXiv(以及 bioRxiv / medRxiv / chemRxiv)新发布论文,用嵌入相似度排序后由大模型生成 TL;DR,最终以邮件形式推送到你的邮箱。读完本文,你将掌握在 GitHub Actions 上零成本部署、用CUSTOM_CONFIG完整自定义配置、理解多源检索与重排序的底层实现,并能把整个流水线迁移到本地运行。

项目是什么

Zotero-arXiv-Daily的核心思路是"以你的 Zotero 文献库为兴趣画像":先读取你已收藏论文的标题与摘要,再从 arXiv 等预印本平台拉取前一天新发布的论文,计算两者之间的语义相似度并排序,把最贴近你近期研究方向的文章推送给你。项目描述原文为:

Track new scientific researches of your interest by just forking (and staring) this repo!😊

它的典型部署形态是GitHub Actions Workflow——只需 fork 仓库并配置少量环境变量,即可实现零成本、无需安装、每日自动投递。对于公开仓库,所有计算都可以在 GitHub Actions runner 的免费配额内完成。

核心特性

  • 完全免费:所有计算都在 GitHub Action runner 本地完成(公开仓库配额内),无需购买服务器。
  • AI 生成的 TL;DR:为每篇论文生成一句话摘要,方便快速筛选目标论文。
  • 作者机构解析:论文中作者的所属机构会被解析并展示在邮件中。
  • PDF 与代码链接:邮件中包含论文 PDF 下载链接,以及(如果存在的话)代码实现链接。
  • 相关性排序:论文列表按照与你近期研究兴趣的相关度排序。
  • 快速部署:fork 仓库后在 GitHub Actions 页面设置环境变量即可。
  • LLM API 支持:可接入任意 OpenAI 兼容 API 生成 TL;DR。
  • 忽略不想要的文献:支持用 glob 模式列表过滤掉 Zotero 库中不想参与兴趣建模的条目。
  • 多论文源支持:内置 arxiv、biorxiv、medrxiv、chemrxiv 四种检索源。

工作原理:从 Zotero 到邮箱的完整流水线

README 的 "How it works" 一节描述了整体机制:项目首先通过 API 读取 Zotero 文献库中的全部论文,以及前一日发布的所有新论文;随后用嵌入模型计算每篇论文摘要的向量表示;每篇候选论文的得分是其与所有 Zotero 文献的加权平均相似度(越新加入文献库的论文权重越高);每篇论文的 TL;DR 由 LLM 基于pymupdf4llm提取的正文文本生成。

结合源码,这条流水线在 executor.py 的Executor.run()中被编排为六个环节:

  1. 拉取 Zotero 语料库:fetch_zotero_corpus()(executor.py)通过 pyzotero 读取conferencePaper / journalArticle / preprint三类条目,且要求abstractNote非空,并为每篇文献递归计算其在 Zotero 集合中的路径。
  2. 过滤语料库:filter_corpus()(executor.py)先按include_path白名单筛选,再按ignore_path黑名单剔除(忽略规则优先)。
  3. 检索新论文:按配置的executor.source依次调用各 Retriever(arxiv / biorxiv / medrxiv / chemrxiv)拉取新论文。
  4. 重排序:调用 Reranker 对候选论文打分并按分数降序排列,再截取前max_paper_num篇。
  5. 生成 TL;DR 与机构:逐篇调用 LLM 生成一句话总结与作者机构列表。
  6. 渲染并发送邮件:render_email()生成 HTML,再经 SMTP 发送(utils.py)。

整个流水线的拓扑结构也在 CLAUDE.md 中得到了印证,其插件式设计值得关注:Retriever 通过@register_retriever注册、Reranker 通过@register_reranker注册,均通过统一的工厂函数get_retriever_cls()/get_reranker_cls()按名称动态加载(见 retriever/base.py 与 reranker/base.py)。

快速开始:GitHub Actions 部署

第 1 步:Fork 仓库

打开仓库主页点击右上角 Fork 按钮(顺手 Star 一下也是作者欢迎的😊):

[!IMPORTANT] 请密切关注上游仓库的动态,上游发布更新时及时将你 fork 的分支与上游合并(merge),以便享受新功能并修复已发现的 bug。

第 2 步:设置 GitHub Actions 环境变量(Secrets)

在仓库的Settings → Secrets and variables → Actions页面中,把下表列出的密钥逐个添加为Repository secrets。一旦设置,这些值对包括你本人在内的所有人都不可见,安全性有保障:

Key说明示例
ZOTERO_ID你的 Zotero 账户User ID。注意它不是用户名,而是一串数字。在 Zotero 设置页的 Security 面板中获取,位置见 assets/userid.png。12345678
ZOTERO_KEY一个具备只读权限的 Zotero API key,同样在 Zotero 设置页 Security 面板创建。AB5tZ877P2j7Sm2Mragq041H
SENDER负责发信的 SMTP 服务器邮箱账号。abc@qq.com
SENDER_PASSWORD发件账号的密码。注意它不一定是邮箱客户端登录密码,而是SMTP 服务的授权码,请向你的邮箱服务商索取。abcdefghijklmn
RECEIVER接收论文列表的邮箱地址。abc@outlook.com
OPENAI_API_KEY通过 API 访问 LLM 的密钥(可选用硅基流动等平台提供的开源大模型免费 API)。sk-xxx
OPENAI_API_BASE访问 LLM 的 API 地址。https://api.siliconflow.cn/v1

第 3 步:设置公共变量CUSTOM_CONFIG

除了 Secrets,还需要在Settings → Secrets and variables → Actions → Variables中新增一个公共变量CUSTOM_CONFIG(见 assets/repo_var.png 与 assets/config_var.png),并把下面的 YAML 内容粘贴为它的值:

zotero: user_id: ${oc.env:ZOTERO_ID} api_key: ${oc.env:ZOTERO_KEY} include_path: null # Or e.g. ["2026/survey/**", "2026/reading-group/**"] email: sender: ${oc.env:SENDER} receiver: ${oc.env:RECEIVER} smtp_server: smtp.qq.com smtp_port: 465 sender_password: ${oc.env:SENDER_PASSWORD} llm: api: key: ${oc.env:OPENAI_API_KEY} base_url: ${oc.env:OPENAI_API_BASE} api_mode: chat_completion # Or response to use the Responses API. generation_kwargs: model: gpt-4o-mini source: arxiv: category: ["cs.AI","cs.CV","cs.LG","cs.CL"] include_cross_list: false # Set to true to include arXiv cross-list papers in these categories. executor: debug: ${oc.env:DEBUG,null} source: ['arxiv']

这里的${oc.env:XXX,yyy}是 Hydra/OmegaConf 的环境变量插值语法:表示取环境变量XXX的值,若该变量未设置,则使用默认值yyy。所以 Secrets 中的ZOTERO_ID、ZOTERO_KEY、SENDER、RECEIVER、SENDER_PASSWORD、OPENAI_API_KEY、OPENAI_API_BASE会分别被注入到对应配置项;executor.debug则读取DEBUG环境变量,未设置时默认为null。

若希望把 arXiv 跨列表(cross-list)论文也纳入候选,可将source.arxiv.include_cross_list设为true。

第 4 步:手动触发测试

配置完成后即可在Actions页面手动触发工作流进行验证:

[!NOTE]Test-Workflow是主工作流(Send-emails-daily)的调试版本,它总是检索 5 篇 arxiv 论文,与日期无关;而主工作流每天自动触发,检索昨天发布的新论文。周末和节假日 arXiv 没有新论文,此时主工作流日志中可能出现 "No new papers found"。

触发后检查 Actions 日志以及收件邮箱即可确认结果。默认情况下主工作流每天22:00 UTC运行,可通过修改工作流配置.github/workflows/main.yml调整触发时间。

完整配置参考

README 同时给出了覆盖全部模块的完整配置骨架,其中???表示该值必须填写:

zotero: user_id: ??? # User ID of your Zotero account. api_key: ??? # An Zotero API key with read access. include_path: null # A list of glob patterns marking the Zotero collections that should be included. Example: ["2026/survey/**", "2026/reading-group/**"] source: arxiv: category: null # The categories of target arxiv papers. Find the abbr of your research area from arxiv category taxonomy. Example: ["cs.AI","cs.CV","cs.LG","cs.CL"] include_cross_list: false # Whether to include arXiv cross-list papers in subscribed categories. Example: true biorxiv: category: null # The categories of target biorxiv papers. Find categories from biorxiv site. Example: ["biochemistry","animal behavior and cognition"] medrxiv: category: null # The categories of target medrxiv papers. Find categories from medrxiv site. Example: ["psychiatry and clinical psychology", "neurology"] chemrxiv: include_new_versions: false # Whether to include revised versions (v2, v3, ...) of previously posted chemrxiv preprints in addition to new first postings. chemrxiv has no category filter: all new preprints (a few dozen per day) are retrieved via Crossref and left to the reranker. Example: true email: sender: ??? # The email account of the SMTP server that sends you email. Example: abc@qq.com receiver: ??? # The email account that receives the paper list. Example: abc@outlook.com smtp_server: ??? # The SMTP server that sends the email. Ask your email provider (Gmail, QQ, Outlook, ...) for its SMTP server. Example: smtp.qq.com smtp_port: ??? # The port of SMTP server. Example: 465 sender_password: ??? # The password of the sender account. Note that it's not necessarily the password for logging in the e-mail client, but the authentication code for SMTP service. Ask your email provider for this. Example: abcdefghijklmn llm: api: key: ??? # API Key of your LLM API. Example: sk-xxx base_url: ??? # API URL of your LLM API. Example: https://api.openai.com/v1 api_mode: chat_completion # The LLM API to use. Options: chat_completion or response. generation_kwargs: # Arguments for the selected LLM API. max_tokens: 16384 model: ??? language: English # Preferred language for the TL;DR. Example: English reranker: local: model: jinaai/jina-embeddings-v5-text-nano # The Hugging Face model name of the local embedding model. Example: jinaai/jina-embeddings-v5-text-nano encode_kwargs: # The kwargs for the encode method of the local embedding model. Details see sentence-transformers encode API. task: retrieval prompt_name: document api: key: null # API Key of your embedding model API. Example: sk-xxx base_url: null # API URL of your embedding model API. Example: https://api.openai.com/v1 model: null # The model name of the embedding model. Example: text-embedding-3-large batch_size: null # The batch size for embedding API requests. Adjust to match your provider's limit. Example: 64 executor: debug: false # Whether to use debug mode. Example: true send_empty: false # Whether to send an empty email even if no new papers today. Example: true max_paper_num: 100 # The maximum number of the papers presented in the email. Example: 100 source: ??? # The sources of papers to retrieve. Example: ['arxiv','biorxiv','medrxiv','chemrxiv'] reranker: local # The reranker to use. Example: 'local' or 'api'

配置分层机制

配置系统基于Hydra + OmegaConf组合式配置,入口在 main.py 的@hydra.main(config_path="../../config", config_name="default")。default.yaml通过defaults依次组合base与custom两份配置:

  • config/base.yaml:完整参数骨架,含所有默认值与注释(例如email.smtp_server: ???、executor.max_paper_num: 100、executor.reranker: local);
  • config/custom.yaml:面向 GitHub Actions 的覆盖层,把密钥类参数与ZOTERO_ID、SENDER等环境变量绑定,并预置smtp.qq.com: 465、model: gpt-4o-mini、arxiv 默认分类["cs.AI","cs.CV","cs.LG","cs.CL"]等开箱即用的取值;
  • 你在 Actions 页面设置的CUSTOM_CONFIG变量会被覆盖到该分层配置之上,作为最终生效配置。

值得注意的是,README 示例中本地 reranker 模型名写作jinaai/jina-embeddings-v5-text-nano,而仓库内 config/base.yaml 的默认值实际为jinaai/jina-embeddings-v5-text-nano-retrieval,两者都指向 jina 的轻量级文本嵌入模型,以base.yaml为准即可。

配置与实现深入解析

Zotero 语料过滤:include_path 与 ignore_path

include_path用于把 Zotero 中某些集合纳入兴趣建模(例如只跟踪2026/survey/**、2026/reading-group/**目录下的文献),ignore_path则用于排除不需要的条目(例如archive/**、已读文献)。

其底层实现由normalize_path_patterns()(executor.py)与glob_match()(utils.py)完成:glob_match基于 Pythonglob.translate(..., recursive=True)把 glob 模式编译为正则,支持**递归匹配;而normalize_path_patterns明确规定只接受字符串列表或 null,传单个字符串会直接抛出TypeError(这一行为在 tests/test_executor.py 中有对应测试)。过滤顺序为先 include 后 ignore,ignore 优先级更高(见 executor.py)。

多源论文检索器

arXiv:RSS 订阅 + 全文本三级提取

arxiv_retriever.py 通过https://rss.arxiv.org/atom/{category1+category2+...}拉取 RSS 订阅,并利用条目中的arxiv_announce_type字段区分new(新发布)与cross(跨列表)论文:include_cross_list=false时只保留new类型;debug 模式下仅处理前 10 条。RSS 抓取内置了 5 次重试(每次间隔 5 秒),并会校验 HTTP 状态与 feed 解析状态,避免把错误的 feed 当作有效数据。

真正有技术含量的是全文本提取:convert_to_paper()(arxiv_retriever.py)按 "源码 tar → HTML → PDF" 的顺序尝试获取论文全文:

  1. 源码 tar:从https://arxiv.org/src/{paper_id}下载 LaTeX 源码包,由extract_tex_code_from_tar()(utils.py)识别主.tex文件——优先依据.bbl文件匹配,找不到时寻找包含\begin{document}的候选文件,多候选时用BM25 算法按论文标题挑出最相关的文件,并把\input/\include的子文件内联合并;
  2. HTML:通过 trafilatura 从https://arxiv.org/html/{id}抽取正文;
  3. PDF:下载 PDF 后用pymupdf4llm.to_markdown()转成 Markdown(utils.py)。

下载与提取都设置了硬性超时:连接超时(10, 60)秒、PDF 提取与 tar 提取均为 180 秒,超时进程会被强制终止(_run_with_hard_timeout,arxiv_retriever.py),保证单个坏论文不会拖垮整个工作流。

bioRxiv / medRxiv:REST API + 最新日期过滤

biorxiv_retriever.py 调用https://api.biorxiv.org/details/{server}/2d拉取近两天数据,先取日期最大(即最新发布日)的那一批论文,再按category列表过滤;请求失败时最多重试 10 次、每次间隔 10 秒。受限于站点的爬虫限制,bioRxiv 论文不提取全文(full_text=None)。而 medrxiv_retriever.py 仅一行:直接继承 bioRxiv Retriever 并把server改为medrxiv,充分体现了插件体系的复用性。

chemRxiv:经由 Crossref 获取

chemrxiv_retriever.py 是一个较新的实现:由于 chemRxiv 已迁移到 Wiley Research Exchange 平台并启用 Cloudflare 防护,旧公开 API 不可用,因此改为通过Crossref REST API(前缀10.26434)获取所有 chemRxiv 预印本。它没有分类过滤(chemRxiv 每天仅几十篇新预印本),按 Crossref 的created时间戳筛出过去lookback_hours(24 小时)内的记录,并通过include_new_versions控制是否包含修订版本(v2、v3…)。docstring 中的这段注释同样说明了选择 Crossref 的缘由:每篇 chemRxiv 预印本发布后几分钟内就会以10.26434前缀注册到 Crossref。

重排序算法:时间衰减加权相似度

README 提到"越新加入文献库的论文权重越高",其精确公式在 reranker/base.py:

  1. 语料库按added_date倒序排列;
  2. 时间衰减权重w_i = 1 / (1 + log10(i + 1))(i从 0 开始),并归一化使权重之和为 1;
  3. 计算候选论文与语料库的相似度矩阵sim(形状为[候选数, 语料数]);
  4. 加权求和后整体乘以 10:score = (sim * w).sum(axis=1) * 10,得到每篇候选论文的最终得分,再按得分降序排列。

这样的设计让最近加入的文献对兴趣画像的贡献最大,而数年前的旧文献影响力对数衰减。得分会被展示在邮件中作为相关性评分。

Reranker 有两种实现,通过executor.reranker: local / api切换:

  • local(默认):使用sentence-transformers本地加载嵌入模型(local.py),默认模型为jinaai/jina-embeddings-v5-text-nano系列,encode_kwargs中的task: retrieval、prompt_name: document是发给模型 encode 方法的参数;非 debug 模式下会静默各框架的日志与警告。
  • api:通过 OpenAI 兼容的 embeddings 接口批量调用(api.py),按batch_size(默认 64)分批编码,再对向量做 L2 归一化后计算余弦相似度矩阵。这一模式把嵌入计算从本地 GPU/CPU 挪到云端,适合不想下载模型的用户。

两种实现都继承自BaseReranker,rerank()中"排序语料 → 计算时间衰减权重 → 加权打分"的骨架完全共享,只有get_similarity_score()这一抽象方法不同。

LLM 生成 TL;DR 与机构解析

LLM 相关逻辑集中在 protocol.py 的Paper数据类中:

  • TL;DR 生成(protocol.py):把标题、摘要、正文预览拼进 prompt,要求模型用language指定的语言生成一句话总结;为避免超长 prompt,先用 gpt-4o 分词器把 prompt 截断到4000 tokens;调用失败时回退为直接使用摘要。
  • 机构解析(protocol.py):基于全文开头 2000 tokens,让模型输出按作者顺序排列的 Python 机构列表,并要求只保留顶级机构(例如 "Department of Computer Science, TsingHua University" 只取 "TsingHua University")、去重;失败时置为None。
  • API 模式(_request_llm,protocol.py):api_mode: chat_completion走chat.completions.create;api_mode: response走新版responses.create,且会自动把max_tokens映射为max_output_tokens。两种模式都接受generation_kwargs中的任意参数(如model、max_tokens)。

由于 TL;DR 需要逐篇调用 LLM,Executor.run()中使用了tqdm进度条并逐篇处理;邮件渲染(construct_email.py)会把相关性得分保留一位小数展示,作者超过 5 人时缩写为"前 3 + … + 后 2"的形式,机构最多展示前 5 个。

邮件发送:TLS → SSL → 明文自动降级

send_email()(utils.py)使用 Python 标准库smtplib:先尝试SMTP + starttls(),失败则尝试SMTP_SSL,再失败则退化为明文连接;邮件主题为Daily arXiv {yyyy/mm/dd},发件人显示为 "Github Action"。当send_empty=true且当天没有新论文时,邮件正文会是 "No Papers Today. Take a Rest!";而send_empty=false时则不发送任何邮件(Executor.run()中的短路逻辑,executor.py)。

本地运行

README 与仓库说明(CLAUDE.md)都支持在本地用 uv 直接运行。前提是安装 uv,并设置与 GitHub Actions 部署相同的环境变量:

# 先导出所有环境变量(示例) # export ZOTERO_ID=xxxx # export ZOTERO_KEY=xxxx # export SENDER=xxxx # export SENDER_PASSWORD=xxxx # export RECEIVER=xxxx # export OPENAI_API_KEY=xxxx # export OPENAI_API_BASE=https://api.openai.com/v1 cd zotero-arxiv-daily uv run main.py

本仓库的实际入口位于 src/zotero_arxiv_daily/main.py,因此更稳妥的等价命令是uv run src/zotero_arxiv_daily/main.py。入口会先通过dotenv加载根目录.env文件(main.py),再依据executor.debug调整日志级别,最后构造Executor并执行整条流水线。项目要求 Python ≥ 3.13(见 pyproject.toml),核心依赖包括pyzotero、arxiv、sentence-transformers、pymupdf4llm、hydra-core、openai等,uv run会自动根据uv.lock同步环境。若偏好容器化部署,仓库还提供了 Docker 部署说明(见 assets/use_docker.md),支持定时执行、日志持久化与模型缓存。

与上游保持同步

项目处于活跃开发中,建议在 GitHub 上订阅该仓库的Watch → Releases通知,以便在发布新版本时及时获得提醒:

同步时在你 fork 的仓库中把上游 main 分支合并进来即可,具体操作可参考 GitHub 的 "Sync fork" 功能。

已知限制

  • 推荐算法比较简单:README 明确说明,当前算法可能无法精确反映你的真实兴趣,欢迎提出更好的算法改进思路。这里的"简单"是指它只用摘要嵌入的加权相似度,没有引入更复杂的协同过滤或学习型排序。
  • max_paper_num不宜过大:过高的MAX_PAPER_NUM会让执行时间超出 GitHub Actions runner 的限额(公开仓库单次执行 6 小时,私有仓库每月 2000 分钟)。对个人使用而言,公开仓库配额通常足够;如有特殊需求,可以在自己的服务器部署、使用自托管 GitHub Actions runner,或为超出的执行时间付费。

结语

Zotero-arXiv-Daily用一套相当克制的技术栈完成了"个性化论文订阅"这件事:Zotero 做兴趣画像、多源 Retriever 做候选采集、嵌入重排序做相关度打分、LLM 做摘要与机构解析、SMTP 做最终投递,整套流水线在 executor.py 中环环相扣,并借助 Hydra 配置与插件注册机制保持高度可扩展。无论是想要一个零成本的每日 arXiv 推荐服务,还是想研究"文献库驱动的论文推荐"这一模式的工程实现,它都是一份可以直接 fork 运行、也可以细细研读的参考实现。项目以 AGPLv3 协议分发(见 LICENSE)。

  • 人工智能
  • AI 应用
  • RAG
  • 科研

【免费下载链接】zotero-arxiv-daily

Recommend new arxiv papers of your interest daily according to your Zotero libarary.

项目地址:https://gitcode.com/GitHub_Trending/zo/zotero-arxiv-daily
点击查看免费下载
上一篇:如何永久保存微信聊天记录?WeChatMsg让你的珍贵对话永不丢失
下一篇:终极指南:如何永久保存微信聊天记录并生成年度报告

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 13:27:11

Android直读U盘底层实现:绕过libaums解析USB与文件系统

1. 不靠 libaums,Android 直读 U 盘到底难在哪先别急着搜库、抄代码。这事儿得从根上讲清楚:Android 上读 U 盘,系统明明自带“OTG 文件管理”功能,插上去偶尔也能弹出提示,可一旦你想在自己的 App 里直接读取 U 盘里的…

作者头像 李华
网站建设 2026/10/2 13:24:32

PLM才是数字化工厂的根:从产品数据源头打通研发与制造

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 13:24:32

全检不等于零漏检:缺陷流到下一道工序的根因与对策

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/2 13:24:17

CRLB克拉美-罗界详解:参数估计精度下限与Fisher信息量应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华