Was macht Zitierungs-Digest (citation-digest)?
Gib eine Arbeit ein, erhalte eine Ausgabe mit „Wer zitiert sie + was will jede zitierende Arbeit lösen + gruppiert nach Kategorien“, als Markdown oder Notion-Seite.
Die Pipeline besteht aus vier Schritten, die Skripte sind bereits fertig – nicht neu erfinden:
s2_citations.py → citations.json Wer zitiert sie (mit Zitationszahl/Datum/DOI/arXiv)
kimi_q1.py → kimi.json Originaltext der Kimi Q1 jeder Arbeit (strukturierte Blöcke)
(Du bestimmst) → classify.json Klassifikationsergebnis
build_content.py → content.json + digest.md
notion_publish.py→ Notion-Seite
0. Voraussetzungen
- S2-Key: Bevorzugt
$SEMANTIC_SCHOLAR_API_KEY, dann--key, zuletzt~/.env/semantic-scholar. Ohne Key läuft es auch, aber 429-Fehler häufen sich; das Skript wiederholt automatisch (8× mit 12s Verzögerung). - Notion-Token:
~/.notion-tokenoder$NOTION_TOKEN; die Zielseite muss zuerst mit dieser Integration geteilt werden, sonst findet die Suche sie nicht.
1. Zitate abrufen
python3 scripts/s2_citations.py --title "MP-GUI: Modality Perception with MLLMs for GUI Understanding" --out citations.json
# Alternativ: --arxiv 2503.14021 / --paper-id 0e931ba8...
Das Skript enthält drei Regeln, die du mit Sicherheit selbst übersehen würdest:
- Deduplizierung: S2 gibt oft denselben arXiv-Artikel zweimal zurück (z.B. „A Survey on ...“ und „A Summary on ...“, einmal mit ArXiv, einmal nur mit DOI
10.48550/arXiv.xxxx). Es wird nach arXiv-ID → DOI → Titel dedupliziert, wobei der Eintrag mit der höheren Zitationszahl behalten wird. - Bei mehr als 20 Artikeln nur zwei Top-10 behalten:
--max-total 20 --top 10behält die Vereinigung aus „Top-10 nach Zitationszahl“ ∪ „Top-10 nach Datum“. Standardmäßig aktiviert – filtere nicht selbst. - Titelabgleich: Die Suchschnittstelle nimmt das Ergebnis mit der höchsten Token-Ähnlichkeit; bei einem Score <0,55 werden Kandidaten auf stderr aufgelistet, damit der Benutzer bestätigen kann, ob es sich um denselben Artikel handelt.
Sieh dir zuerst citations.json unter source.citationCount an – das ist die zu berichtende „Zitationszahl“.
2. Kimi-Zusammenfassung abrufen
python3 scripts/kimi_q1.py --in citations.json --out kimi.json --sleep 10 --resume
- Verwendet
POST https://papers.cool/arxiv/kimi?paper=<arxiv_id>(genau die zugrundeliegende Implementierung des lokalen papers-cool MCP), mussUser-Agent/Origin/Referer-Header setzen, sonst wird der Zugriff blockiert. - Gibt HTML-FAQ zurück, nimm nur Q1 „Welches Problem versucht diese Arbeit zu lösen?“ und wandle es strukturiert in Blöcke um:
###→ heading_3,-→ bulleted_list_item,**bold**→ fett. Originaltext 1:1, keine Komprimierung oder Umschreibung. - papers.cool nimmt nicht nur arXiv auf, sondern auch Venue-Bereiche:
/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. Das Skript geht für Arbeiten ohne arXiv-ID automatisch diesen Weg:/venue/<CODE>.<YEAR>?show=5000Listenseite → Matche Titel viaid="title-<pid>"um die Paper-ID zu erhalten (z.B.49@2026@IJCAI, die IJCAI-Nummer ist das DOI-Endstück) →POST /venue/kimi?paper=<pid>gibt dasselbe FAQ-HTML zurück. Die Venue-Listenseite zeigt standardmäßig nur 25 Einträge, daher muss?show=mitgegeben werden. - Arbeiten, bei denen beide Wege fehlschlagen (z.B. IEEE MIPR/AIoTC – nicht in papers.cool) landen in
missingund fallen auf Abstract oder Titel zurück. In der Seite muss markiert werden „Keine Kimi-Zusammenfassung“ –build_content.py/notion_publish.pyfügt beisource != "kimi"automatisch ein ⚠️ hinzu. Trage außerdem inclassify.jsonunternotesden Grund ein. --sleep 10ist stabiler als 2; bei nicht gecachten Arbeiten berechnet Kimi neu, einzelne können 60–90s dauern. Nach jedem Artikel wird--outgeschrieben; bei Unterbrechung mit--resumeweitermachen.- ⚠️ Nicht
pkill -f kimi_q1.pyverwenden: Mehrere Claude-Sitzungen, die dieses Skill gleichzeitig ausführen, können sich gegenseitig töten (es wurden bereits 26 fertig abgerufene, aber noch nicht geschriebene Ergebnisse verloren). Wenn du es im Hintergrund laufen lassen willst, kopiere zuerstscripts/kimi_q1.py <scratchpad>/pcfetch_<Sitzungs-ID>.pyund verwende einen separaten Prozessnamen.
3. Klassifikation (du machst es, nicht das Skript)
Schreibe classify.json:
{
"categories": [
{"name": "🧩 Szenario-Innovation / Problem-Innovation", "desc": "Neue Aufgabe, neuer Benchmark, neue Bewertungsdimension oder ein Phänomen wird als Problem neu definiert",
"papers": ["2503.14021", "10.1109/CVPR52734.2025.02766", "Exakter Titel"]},
{"name": "🔧 Technische Verbesserung", "desc": "Problem bekannt, Beitrag liegt in Methode/Trainingsablauf/System/Architektur",
"papers": ["..."]},
{"name": "📚 Reiner Survey", "desc": "Keine neue Methode oder Aufgabe, Wert liegt in Zusammenhängen und offenen Fragen",
"papers": ["..."]}
],
"notes": {"2504.20464": "Dieser Artikel hat bei S2 zwei doppelte Einträge, bereits zusammengeführt"}
}
papers kann arXiv-ID, DOI oder Titel enthalten (exakt oder teilweise übereinstimmend). Nicht abgedeckte Arbeiten landen automatisch in „❓ Nicht klassifiziert“ – werden nicht stillschweigend verloren.
Kriterien (wenn der Benutzer nichts anderes sagt, verwende diese drei):
- Szenario-Innovation / Problem-Innovation: Neue Aufgabe, neuer Benchmark, neue Bewertungsdimension (z.B. „Nur den Endzustand zu betrachten reicht nicht, man muss den Prozess sehen“) oder ein Phänomen wird als Problem neu definiert (z.B. „Ein Werkzeug fällt aus, wird aber nicht verwendet“).
- Technische Verbesserung: Problem allgemein anerkannt, Beitrag liegt in Methode, Trainingsablauf, Systemimplementierung, Architektur.
- Reiner Survey: Überblicksarbeit / Review / Positionspapier, stellt keine experimentell überprüfbare neue Methode vor.
- Grenzfälle (zählt Benchmark als Problem-Innovation oder eigene Kategorie, wohin mit analytischen Arbeiten) – entscheide nach obigen Kriterien und füge im Antworttext einen kurzen Begründungssatz hinzu, nicht stillschweigend einordnen.
Text-Label: Normale Arbeiten erhalten „Zu lösendes Problem“, Surveys erhalten „Kern-Einsicht“ – da aber der Q1-Originaltext 1:1 übernommen wird, füge normalerweise kein Label hinzu; der Originaltext spricht für sich.
4. Zusammenbau + Ausgabe
python3 scripts/build_content.py --citations citations.json --kimi kimi.json \
--classify classify.json --out content.json --md digest.md
5. Nach Notion veröffentlichen
python3 scripts/notion_publish.py --content content.json --page-title "topic paper reading"
# oder --page-id xxx; um vorhandene Inhalte zu überschreiben, --replace hinzufügen
Struktur fest vorgegeben: Ein Root-Toggle mit dem Namen der Arbeit → Einleitender Absatz + drei Kategorie-Toggles → Ein Toggle pro Arbeit (erste Zeile graue Metadaten: Veröffentlichungsort · Datum · Zitiert N · arXiv:xxx, klickbar; darunter der Q1-Originaltext als Blöcke).
Fallstricke (alle selbst erlebt)
| Symptom | Ursache / Lösung |
|---|---|
POST /v1/blocks/{id}/children → 400 invalid_request_url | Diese Integration akzeptiert nur PATCH zum Anhängen; notion_publish.py verwendet bereits PATCH |
| Vorhandene Blöcke „verschieben“ | Notion hat keine Move-API, nur Neuanlegen: Alten Block lesen → unter neuem Elternteil neu anlegen → alten Block löschen |
Block löschen gibt Can't edit block that is archived | DELETE /v1/blocks/{id} verwenden (nach PATCH {archived:true} kann man ihn nicht mehr ändern) |
| Einzelner rich_text zu lang | Jeder Absatz ≤2000 Zeichen; seg() teilt automatisch bei 1900 Zeichen (lange englische Abstracts ohne Kimi landen hier, getestet mit 2063 Zeichen) |
PATCH /blocks/{id}/children → 400 ... start_cursor provided is invalid | Notion-Ev.-Konsistenzproblem: Ein gerade erstellter Block kann beim sofortigen Anhängen diesen Fehler werfen – der Schreibvorgang ist oft trotzdem erfolgreich, und ein direktes GET children kann sogar 0 Unterblöcke anzeigen. req() wiederholt bei diesem 400 mit Backoff; bei der Fehlersuche nicht sofort die ganze Seite neu senden, sondern zuerst anhand der Root-Toggles die tatsächliche Struktur prüfen |
| Vor dem erneuten Senden der gesamten Seite | Das Skript ist nicht idempotent; ein erneuter Durchlauf erzeugt einen zusätzlichen Root-Toggle. Lösche zuerst DELETE /v1/blocks/<vorherige Root-Toggle-ID> (im Log unter root toggle:), dann erneut ausführen |
| Zu viele Blöcke auf einmal anhängen | Maximal 100 Blöcke pro Request (Skript teilt bei 80) |
| Verschachtelung wird nicht erstellt | Maximal zwei Ebenen pro Request: Toggle in Toggle geht, drei oder mehr Ebenen müssen in separaten Appends erstellt werden |
| S2 gibt ständig 429 | Normal, Backoff-Wiederholung; parallele Requests erhöhen die Wahrscheinlichkeit, seriell + sleep verwenden |
Checkliste vor Fertigstellung
-
citations.json.source.citationCountstimmt mit der tatsächlichen Anzahl der aufgelisteten Arbeiten überein (≤20 alle; >20 Vereinigung der beiden Top-Listen) - Jede Arbeit hat eine Metadatenzeile (Zitationszahl Pflicht), bei arXiv-Arbeiten klickbaren Link
- Arbeiten ohne Kimi-Originaltext sind mit Grund markiert (⚠️ +
notes) - Notion hat genau einen Root-Toggle auf oberster Ebene (keine Duplikate durch erneutes Senden)
- Anzahl Kategorien + „Nicht klassifiziert“ = Gesamtzahl der Arbeiten
- Stichprobe in Notion: Titel → Metadaten → Q1-Originaltext (Untertitel/Liste/Fett vorhanden)