引用文献速览(citation-digest)
입력된 논문을 바탕으로, "누가 인용했는지 + 각 논문이 어떤 문제를 해결하려는지 + 주제별 그룹화" 결과를 markdown 또는 Notion 페이지로 출력합니다.
파이프라인은 네 단계로 구성되며, 스크립트가 이미 캡슐화되어 있으므로 새로 만들지 마십시오:
s2_citations.py → citations.json 누가 인용했는지 (인용 수/날짜/DOI/arXiv 포함)
kimi_q1.py → kimi.json 각 논문의 Kimi Q1 원문 (구조화된 블록)
(직접 판단) → classify.json 분류 결과
build_content.py → content.json + digest.md
notion_publish.py→ Notion 페이지
0. 사전 준비
- S2 키: 우선순위는
$SEMANTIC_SCHOLAR_API_KEY, 그 다음--key, 마지막으로~/.env/semantic-scholar. 키가 없어도 실행은 가능하지만 429 오류가 많이 발생하며, 스크립트가 자동으로 재시도합니다 (8회 × 12초). - Notion 토큰:
~/.notion-token또는$NOTION_TOKEN; 대상 페이지는 반드시 이 integration과 먼저 공유되어야 검색이 가능합니다.
1. 인용 정보 가져오기
python3 scripts/s2_citations.py --title "MP-GUI: Modality Perception with MLLMs for GUI Understanding" --out citations.json
# 또는 --arxiv 2503.14021 / --paper-id 0e931ba8...
스크립트에는 여러분이 반드시 겪게 될 세 가지 규칙이 내장되어 있습니다:
- 중복 제거: S2는 동일한 arXiv 논문을 두 개의 레코드로 반환하는 경우가 잦습니다 (예: "A Survey on ..."과 "A Summary on ...", 하나는 ArXiv ID, 다른 하나는 DOI
10.48550/arXiv.xxxx만 있음). arXiv id → DOI → 제목 순으로 중복을 제거하고, 인용 수가 높은 레코드를 유지합니다. - 20편 초과 시 상위 10개만 유지:
--max-total 20 --top 10을 통해, 인용 수 상위 10개 ∪ 날짜 상위 10개를 유지합니다. 기본적으로 활성화되어 있으므로 별도로 필터링하지 마십시오. - 제목 매칭: 검색 인터페이스는 토큰 중복도가 가장 높은 결과를 선택합니다; 점수가 <0.55인 경우 stderr에 후보 목록을 출력하여 사용자에게 동일 논문인지 확인을 요청합니다.
먼저 citations.json의 source.citationCount를 확인하세요. 이 값이 보고할 "인용 수"입니다.
2. Kimi 요약 가져오기
python3 scripts/kimi_q1.py --in citations.json --out kimi.json --sleep 10 --resume
POST https://papers.cool/arxiv/kimi?paper=<arxiv_id>엔드포인트를 사용합니다 (로컬 papers-cool MCP의 하부 구현과 동일). 반드시User-Agent/Origin/Referer헤더를 포함해야 하며, 그렇지 않으면 차단됩니다.- HTML FAQ 형식의 응답이 반환되며, 오직 Q1, "이 논문은 어떤 문제를 해결하려는가?" 부분만 추출하여 구조화된 블록으로 변환합니다:
###→ heading_3,-→ bulleted_list_item,**bold**→ 굵게. 원문을 그대로 가져오며, 압축하거나 수정하지 않습니다. - papers.cool은 arXiv 외에도 venue 섹션을 지원합니다:
/venue/<CODE>.<YEAR>. CODE는 다음과 같습니다: AAAI/ACL/COLM/COLT/CoRL/CVPR/ECCV/EMNLP/ICCV/ICLR/ICML/IJCAI/INTERSPEECH/IWSLT/MICCAI/MLSYS/NAACL/NDSS/NeurIPS/OSDI/UAI. 스크립트는 arXiv ID가 없는 논문에 대해 자동으로 이 우회 경로를 사용합니다:/venue/<CODE>.<YEAR>?show=5000리스트 페이지에서id="title-<pid>"로 제목을 매칭하여 paper id를 얻은 후 (형식:49@2026@IJCAI; IJCAI의 시퀀스 번호는 DOI의 끝자리와 같습니다),POST /venue/kimi?paper=<pid>를 호출하여 동일한 FAQ HTML을 반환받습니다. venue 리스트 페이지는 기본적으로 25개만 제공하므로?show=파라미터를 반드시 포함해야 합니다. - 두 경로 모두 실패하는 경우 (IEEE MIPR, AIoTC 등 papers.cool이 수집하지 않는 학술지),
missing목록에 추가되고 요약문이나 제목으로 대체됩니다. 반드시 페이지에 "Kimi 요약 아님"을 표시해야 합니다 —build_content.py/notion_publish.py는source != "kimi"인 경우 자동으로 ⚠️ 표시를 추가하며,classify.json의notes에 사유를 명시해야 합니다. --sleep 10은 2보다 안정적입니다; 캐시되지 않은 논문의 경우 Kimi가 실시간으로 계산해야 하므로 단일 논문에 60-90초가 소요될 수 있습니다. 각 논문을 가져올 때마다--out파일에 기록하며, 중단된 경우--resume플래그를 사용하여 재개할 수 있습니다.- ⚠️
pkill -f kimi_q1.py를 사용하지 마십시오: 여러 Claude 세션이 동시에 이 스킬을 실행할 때 서로를 잘못 종료할 수 있습니다 (실제로 26편의 가져온 결과가 디스크에 기록되기 전에 손실된 사례가 있습니다). 백그라운드에서 실행해야 한다면 먼저cp scripts/kimi_q1.py <scratchpad>/pcfetch_<세션ID>.py로 복사하여 독립적인 프로세스 이름을 사용하십시오.
3. 분류 (직접 수행, 스크립트가 하지 않음)
classify.json 파일을 작성하십시오:
{
"categories": [
{"name": "🧩 시나리오 혁신 / 문제 혁신", "desc": "새로운 작업, 새로운 벤치마크, 새로운 평가 차원, 또는 문제를 재정의한 경우",
"papers": ["2503.14021", "10.1109/CVPR52734.2025.02766", "Exact Title"]},
{"name": "🔧 기술 개선", "desc": "문제는 알려져 있고, 기여는 방법/훈련 절차/시스템/아키텍처에 있음",
"papers": ["..."]},
{"name": "📚 리뷰에 한정", "desc": "새로운 방법이나 작업을 제안하지 않으며, 가치는 맥락과 미해결 문제 정리에 있음",
"papers": ["..."]}
],
"notes": {"2504.20464": "이 논문은 S2에 중복 레코드가 두 개 있으며, 병합 완료"}
}
papers에는 arXiv id, DOI, 제목 중 하나를 사용할 수 있습니다 (정확히 일치 또는 포함 매칭). 분류되지 않은 논문은 자동으로 "❓ 미분류"에 포함되며, 조용히 사라지지 않습니다.
판단 기준 (사용자가 별도로 지정하지 않은 경우 다음 세 가지를 사용):
- 시나리오 혁신 / 문제 혁신: 새로운 작업, 새로운 벤치마크, 새로운 평가 차원을 제안 (예: "최종 상태만 보는 것이 아니라 과정을 봐야 함"), 또는 어떤 현상을 문제로 재정의 (예: "도구가 고장났는데 사용하지 않음").
- 기술 개선: 문제가 이미 인정되었으며, 기여는 방법, 훈련 절차, 시스템 구현, 아키텍처에 있음.
- 리뷰에 한정: Survey / Review / Position 논문이며, 실험 가능한 새로운 방법을 제안하지 않음.
- 경계 사례 (벤치마크를 문제 혁신으로 볼지 별도 분류로 볼지, 분석형 논문의 분류) — 위 기준에 따라 우선 판단한 후, 응답에 판단 근거를 한 문장으로 설명하고 단순히 조용히 분류하지 마십시오.
본문 레이블: 일반 논문은 "해결하려는 문제", 리뷰 논문은 "핵심 통찰"을 사용 — 그러나 Q1 원문을 그대로 가져오므로 일반적으로 레이블을 추가하지 않고, 원문이 스스로 말하도록 합니다.
4. 조립 + 출력
python3 scripts/build_content.py --citations citations.json --kimi kimi.json \
--classify classify.json --out content.json --md digest.md
5. Notion에 게시
python3 scripts/notion_publish.py --content content.json --page-title "topic论文阅读"
# 또는 --page-id xxx; 기존 내용을 덮어쓰려면 --replace 추가
구조는 다음과 같이 고정됩니다: 논문 제목으로 명명된 최상위 toggle → 설명 단락 + 세 개의 분류 toggle → 각 논문당 하나의 toggle (첫 번째 줄은 회색 메타 정보: 발행처 · 날짜 · 인용 N회 · arXiv:xxx, 클릭 가능; 아래는 Q1 원문 블록).
문제점 (모두 실제로 겪은 사례)
| 증상 | 원인 / 해결 방법 |
|---|---|
POST /v1/blocks/{id}/children → 400 invalid_request_url | 이 Integration은 PATCH 추가만 허용; notion_publish.py는 이미 PATCH를 사용합니다. |
| 기존 블록을 "이동"하고 싶을 때 | Notion에는 move API가 없습니다. 재구성해야 함: 이전 블록 읽기 → 새 부모에 재구성 → 이전 블록 삭제. |
블록 삭제 시 Can't edit block that is archived 오류 | DELETE /v1/blocks/{id} 사용 (일단 PATCH {archived:true}를 하면 더 이상 수정할 수 없습니다). |
| 단일 rich_text가 너무 김 | 각 단락은 ≤2000자; seg()가 자동으로 1900자 단위로 분할합니다 (긴 영문 초록에서 자주 발생, 실제로 2063자 사례 있었음). |
PATCH /blocks/{id}/children → 400 ... start_cursor provided is invalid | Notion 최종 일관성 문제: 방금 생성한 블록에 바로 내용을 추가하면 발생 가능. 쓰기는 대개 성공. 바로 GET children을 해도 0개의 자식 블록이 반환될 수 있음. req()에 이 400에 대한 백오프 재시도가 구현되어 있음. 문제 해결 시 서둘러 전체 페이지를 재전송하지 말고, 우선 최상위 toggle을 순회하며 실제 구조를 확인하십시오. |
| 전체 페이지 재전송 전 | 스크립트는 멱등적이지 않으므로, 그냥 다시 실행하면 최상위 toggle이 하나 더 추가됩니다. 먼저 DELETE /v1/blocks/<이전 최상위 toggle id> (로그의 root toggle: 행 참조)를 실행한 후 재실행하십시오. |
| 한 번에 너무 많이 추가 | 각 요청은 ≤100 블록 (스크립트는 80개 단위로 분할). |
| 중첩이 생성되지 않음 | 단일 요청은 최대 두 단계까지: toggle의 children 안에 toggle을 넣는 것은 가능하지만, 세 단계 이상은 여러 번 append해야 합니다. |
| S2가 계속 429 반환 | 정상입니다. 백오프 재시도; 병렬 요청은 더 쉽게 걸리므로, 직렬 + sleep 사용. |
마무리 전 자가 점검
-
citations.json.source.citationCount와 실제 나열된 논문 수가 일치 (<=20이면 전체 나열; >20이면 두 목록의 합집합). - 각 논문에 메타 정보 행이 있음 (인용 수 필수), arXiv가 있는 경우 클릭 가능한 링크.
- Kimi 원문이 없는 논문은 모두 사유가 표시됨 (⚠️ 표시 +
notes). - Notion 최상위에는 하나의 toggle만 존재 (재전송으로 인한 중복 없음).
- 분류된 항목 수 + 미분류 수 = 총 논문 수.
- Notion에서 임의의 toggle 하나를 확인: 제목 → 메타 정보 → Q1 원문 (소제목/목록/굵은 글씨 모두 정상).