Skip to content

ephuri/paper-assistant

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Paper Reading Assistant

每日自动抓 arXiv + HuggingFace 新论文,按个人研究方向筛选后推送到飞书群,支持按需生成深度阅读报告(飞书文档)、按主题调研、对话式编辑报告、@bot 发链接即读。

研究画像、关键词、筛选阈值全部在 config.py 配置;LLM 走 claude CLI(Max 订阅),全程只走你允许的出口 IP。


快速开始

首次使用前先读 FEISHU_SETUP.md(飞书应用怎么建、要哪些权限、订阅哪些事件) 不用 Claude Max 订阅 / 想换成 OpenAI Codex 等其它 LLM 后端:见 LLM_BACKEND.md

cd paper_assistant

# 1. 每日管道(默认昨天 UTC)— 自己机器上挂 cron 每天跑
python main.py
python main.py --date 2026-04-20         # 指定日期补跑
python main.py --dry-run                 # 只筛选,不推飞书
python main.py --no-listen               # 跑完退出,不起 WebSocket

# 2. 单篇精读
python run_one_paper.py 2602.15763       # 给 arxiv id,全流程走一遍

# 3. 主题调研(覆盖最近 5 年相关论文)
python survey.py "world knowledge"       # 互动选画像,推 top-K 到群

# 4. 对话式编辑已有飞书报告
python chat.py 2602.15763                # 进 claude REPL,自然语言改报告

# cron 后台托管(已挂 11:00 每天)
bash run_daily.sh                        # 手动触发一次(同 cron 行为)

六种使用模式

1. 每日自动推送(daily cron)

流程:抓 arXiv+HF → 关键词粗筛(阈值 5)→ Claude Sonnet 精筛(阈值 7)→ 推飞书群卡片 + Bitable → 起 WebSocket 监听回调。

cron:已注册每天 11:00 (SGT+8)run_daily.sh。查看:

crontab -l                # 查看已注册
tail -20 logs/cron.log    # 查看启动日志
tail -50 logs/daily.log   # 查看流水线输出

run_daily.sh 启动前会杀掉上一个同目录的 python main.py,然后 nohup 启新进程,保证常驻监听回调。

2. 单篇手动精读(run_one_paper.py

python run_one_paper.py <arxiv_id>

跳过筛选,直接:入库 → 推 Bitable → 标收藏 → 生成深度报告(约 2 分钟)→ 建飞书文档 → 群通知。适合你已知 arxiv id 想立即读的场景。

3. Bitable 收藏触发报告

日常管道推到 Bitable 的论文,勾上"收藏"字段,系统自动生成报告。两条触发路径并行:

  • WebSocket 实时回调callback_server.pymain.py 内启动)——点击/勾选立即触发
  • 轮询兜底watcher.py,每 5 分钟扫一次)——进程意外重启后也不漏

独立起轮询(一般不需要,main.py 已够):

python watcher.py          # 5 分钟循环轮询
python watcher.py --once   # 扫一次就退

4. @bot 发 arxiv 链接即读(群内最方便)

群里直接 @ 机器人 + 发一个 arxiv 链接/ID,机器人自动触发精读:

@<your-bot> 2510.01174
@<your-bot> https://arxiv.org/abs/2511.12345 这篇方法怎么样
@<your-bot> arxiv.org/pdf/2602.15763v2.pdf

机器人会:

  • 识别到 → 立即回复「📖 收到 xxx,正在分析(约 2 分钟)...」
  • 已读过 → 回复「📄 这篇之前已经读过了:」去重
  • 正在读 → 回复「⏳ xxx 正在分析中,稍等几分钟」
  • 识别不到 ID → 回复「🤔 没识别到 arXiv ID」

前提:飞书应用要订阅 im.message.receive_v1 事件(已配)。私聊也支持,无需 @。

5. 主题调研(survey.py

不止看"最新",覆盖某个领域的过往 5 年精选:

python survey.py "world knowledge"              # 5 年,30 篇候选,top 10 入库
python survey.py "robot manipulation" --years 8
python survey.py "video diffusion" --top-k 15 --max-papers 50
python survey.py "llm reasoning" --auto         # 跳过画像选择,用候选 A

流程

  1. Claude 生成 3 个侧重不同的候选画像+关键词(例如"世界知识"可以生出"LLM 知识存储与编辑"/"知识增强生成"/"多模态世界知识理解")
  2. 终端提示你选 A/B/C 或自己输入
  3. Semantic Scholar 检索(有引用数,能涵盖"经典")→ arxiv 兜底
  4. Sonnet 打分 → top-K 入库 + 推飞书群一张汇总卡片
  5. 不自动生成报告——挑感兴趣的再触发(@bot 或 Bitable 勾选)

可选:申请 Semantic Scholar API key(30 秒)放进 .envexport SEMANTIC_SCHOLAR_API_KEY="xxx",可免限流。

6. 对话式编辑已有报告(chat.py

启动一个 claude 交互终端,飞书文档当前内容已预先注入 system prompt,你用自然语言提修改需求,claude 原地 lark-cli docs +update 改飞书文档:

python chat.py 2602.15763                       # arxiv id → 自动查 user_marks 里的 doc URL
python chat.py https://www.feishu.cn/docx/xxx   # 直接给飞书 URL
python chat.py 2602.15763 --with-paper          # 加 arxiv 全文进 prompt(~15k tokens)

对话示例:

> 当前「三句话说清这篇」太简略了,扩展成 6 条关键贡献点
> 在「方法」章节后面插入一个比较 DSA vs MLA 的表格
> 「不足」段改成更中立的措辞

Claude 每次要 lark-cli 改文档会弹出 Bash 确认(Claude Code 默认),避免乱动;同意一次可选 always allow。


配置:切换研究方向

三要素都在 config.py

作用 改动成本
RESEARCH_PROFILE 自然语言描述研究兴趣,喂给 Claude 精筛 最轻,直接改文字
KEYWORDS 加权关键词列表(粗筛用) 改列表
ARXIV_CATEGORIES arXiv 类目白名单(决定抓取池) 改数组

临时扫某个不同领域(不想动日常配置):

cp config.py config.py.bak
# 编辑 config.py → 换成目标领域关键词和 profile
python main.py --date 2026-04-21 --dry-run   # 预览筛选结果
python main.py --date 2026-04-21             # 确认无误后正式推
mv config.py.bak config.py                   # 恢复

环境依赖

必须存在且可用:

  • Python 3.12+requirements.txt 里的包(arxivlark-oapiPyMuPDFbeautifulsoup4requests
  • claude CLI(Max 订阅,无需 API key)
  • lark-cli@larksuite/clinpm install -g,负责 markdown 导入飞书文档 + 图片插入)
  • 网络代理(可选):如果你机器访问 claude/lark-cli/HuggingFace 需要走代理,在 run_daily.sh 里设 http_proxy / https_proxy 环境变量
  • cron 守护进程/usr/sbin/cron,已手动启动;机器重启后需要重新 cron 启动)

.env 关键变量(本地 gitignored):

FEISHU_APP_ID                # 飞书应用 ID
FEISHU_APP_SECRET            # 飞书应用 Secret
FEISHU_BITABLE_APP_TOKEN     # 多维表格 app_token
FEISHU_BITABLE_TABLE_ID      # 多维表格 table_id
FEISHU_REPORT_FOLDER_TOKEN   # 报告落地文件夹(留空则进 bot 默认空间)
FEISHU_BOT_RECEIVE_ID_TYPE   # "chat_id" 或 "open_id"
FEISHU_BOT_CHAT_ID           # 接收消息的群/人 ID
ALLOWED_OUTBOUND_IP          # 调 claude 前强校验的出口 IP;留空则禁用此门
SEMANTIC_SCHOLAR_API_KEY     # 可选;survey.py 不填则免费共享池易限流

飞书应用需要订阅的事件(开放平台 → 事件与回调):

  • 事件配置 tab:im.message.receive_v1(接收 @bot 消息)
  • 回调配置 tab:card.action.trigger(接收卡片按钮回传,200340 错误就是没开这个)
  • 订阅方式都选长连接(推荐,不用暴露公网 URL)

IP 门(出口控制)

claude CLI 前,utils/ip_gate.py::assert_outbound_ipcurl ifconfig.me 对比 ALLOWED_OUTBOUND_IP,不符就抛 IPGateBlocked 拒绝调用——避免代理节点切换到不可信出口时把 Max 订阅暴露出去。

  • 校验点:filters/llm_filter.py::_score_one_clireports/deep_report.py::_generate_via_cli
  • 60 秒缓存:连续跑 30 篇论文只查一次 ifconfig.me
  • 代理节点换了 → 更新 .env 里的 ALLOWED_OUTBOUND_IP 为新 IP;临时禁用 → 设空字符串

Bitable 字段约定

飞书多维表格 11 列,列名和类型必须和代码匹配push/feishu_bitable.py):

列名 类型 代码传什么
日期 日期 毫秒时间戳
标题 文本 论文标题
作者 文本 前 10 位作者逗号分隔
分数 数字 LLM 精筛打分 1-10
推荐理由 文本 LLM 一句话
arXiv链接 超链接 {text, link}
摘要 文本 前 500 字
收藏 复选框 用户勾选 → 触发报告
arxiv_id 文本 2602.15763 这种(不能是数字列,会丢精度)
报告状态 文本 "生成中" / "已完成"
报告链接 超链接 生成完的飞书文档 URL

目录结构

paper_assistant/
├── main.py                         # 入口:管道 + WebSocket 监听
├── run_one_paper.py                # 入口:单篇强制精读
├── survey.py                       # 入口:主题调研(Claude 生成画像 + SS 搜索)
├── chat.py                         # 入口:对话式编辑已有飞书报告
├── watcher.py                      # 入口:轮询 Bitable 补漏
├── run_daily.sh                    # cron 包装:杀旧 → nohup 启新
├── callback_server.py              # 飞书事件:卡片按钮 + @bot 消息
├── config.py                       # 研究画像 / 关键词 / 阈值 / env
├── sources/
│   ├── arxiv_source.py             # arXiv 每日抓取
│   ├── hf_source.py                # HuggingFace Papers 抓取
│   ├── semantic_scholar.py         # survey.py 用的 SS 搜索
│   └── institutions.py             # 从 arxiv 页面抠机构
├── filters/
│   ├── keyword_filter.py           # 关键词加权粗筛
│   └── llm_filter.py               # Claude Sonnet 精筛
├── reports/
│   └── deep_report.py              # 深度报告生成(Sonnet)
├── push/
│   ├── feishu_bitable.py           # Bitable 读写
│   ├── feishu_msg.py               # 飞书群卡片
│   └── feishu_doc.py               # lark-cli 两阶段文档 + 图片插入
├── storage/db.py                   # SQLite(papers / daily_picks / user_marks)
├── utils/ip_gate.py                # 出口 IP 校验
├── schema.sql                      # DB schema
├── papers.db                       # SQLite (gitignored)
└── logs/                           # 运行日志 (gitignored)

常见问题

Q: cron 挂了但任务没跑? pgrep cron 看守护进程在不在;不在就 /usr/sbin/cron 启一下。机器重启后需重新启动 cron 进程(无 systemd)。

Q: 出现 IPGateBlocked 代理节点切换了。查当前 IP:curl ifconfig.me,更新 .envALLOWED_OUTBOUND_IP,重跑。

Q: feishu-cli 报 permission / 协作者错? 通常是应用未发布到租户,无法直接加为协作者。可以先让文档进 bot 默认空间(FEISHU_REPORT_FOLDER_TOKEN 留空),通过 Bitable "报告链接" 字段访问。想集中到文件夹:先发布应用 → 飞书 UI 把 bot 加为文件夹协作者 → 填 FEISHU_REPORT_FOLDER_TOKEN

Q: 重启 / 补跑某天? python main.py --date 2026-04-20。数据库幂等,重跑已处理过的论文会跳过。

Q: 换研究方向?config.pyRESEARCH_PROFILE + KEYWORDS + ARXIV_CATEGORIES。临时扫描记得备份再改,或者直接用 survey.py(不动全局配置)。

Q: @bot 发链接没反应? 先查飞书开放平台"事件与回调"是否订阅了 im.message.receive_v1card.action.trigger;订阅方式是否选"长连接"。若报 200340,说明"回调配置" tab(不是"事件配置")没开长连接。权限/订阅改过后记得发版本才生效(顶部橙条会提示)。

Q: survey.py 总是 SS 限流 429? 申请 Semantic Scholar 免费 API key(https://www.semanticscholar.org/product/api#api-key-form,秒发),放到 .envexport SEMANTIC_SCHOLAR_API_KEY="xxx"。没 key 会 fallback 到 arxiv 全文搜索,覆盖较稀疏。

Q: chat.py 里 claude 每次改文档都要我按 Y? Claude Code 默认对 Bash 调用做用户批准。同类命令选 "always allow" 后续自动过。想整个会话免批但只这一次,别选 always。真不想要确认就在启动时加 --dangerously-skip-permissions(仅限你信任的操作)。

Q: 调研画像能单独保留成"日常画像"吗? 目前 survey.py 是一次性的,不会覆盖 config.py 的常驻配置。如果某次调研的画像你想转成日常,手动把它的 profile/keywords 拷到 config.py 对应字段即可。

About

No description, website, or topics provided.

Resources

Stars

9 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors