ai-news-hub:用 Claude Code 无头模式生成德语 AI 新闻归档
frankknebeljanssen-create/ai-news-hub
开源项目 ai-news-hub 用 Python 流水线抓取国际与德国 RSS 源,通过 Claude Code 无头模式(claude -p,走 Claude 订阅、无 API 费用)为每条新闻生成 2-3 句摘要并标注主题、地区与相关性,结果存为 JSON。
Tägliches KI-Nachrichtenarchiv auf Deutsch. Eine Python-Pipeline sammelt Meldungen aus internationalen und deutschen Quellen, erstellt zu jeder Meldung eine eigene Kurzfassung mit Claude Code im Headless-Modus und speichert das Ergebnis als JSON. Eine statische Web-App ohne Build-Schritt macht die Daten durchsuchbar und wird über GitHub Pages ausgeliefert.
Live: https://frankknebeljanssen-create.github.io/ai-news-hub/
Inhalt
- Funktionen
- Inhaltliches Konzept
- Architektur
- Pipeline
- Datenmodell
- Quellen
- Web-App
- Automatisierung
- Installation und Betrieb
- Projektstruktur
- Datenschutz, Urheberrecht und KI-Hinweis
- Bekannte Grenzen
- Lizenz
Funktionen
Web-App
- Briefing (
#/briefing): kompakte Ansicht für 2 bis 3 Minuten mit den 5 wichtigsten Meldungen, drei Meldungen aus Deutschland, einem Praxistipp, einem kuriosen Fall und einem Glossarbegriff des Tages, mit Fortschrittsbalken und Tageswechsel - Die Woche in Kürze (
#/woche): Top-Meldungen der Kalenderwoche, Deutschland, Themenverteilung, Praxistipps, Kurioses und Zahlen, mit Wochenwechsel - Tagesansicht mit Top-Stories (je ein Satz), Meldungen nach Themen und Sprungleiste
- Zusatzboxen "Aus Deutschland" und "Kurios & krass"
- Archiv mit Gruppierung nach Tagen, Wochen, Monaten oder Kategorien, Sortierung nach Datum oder Relevanz sowie Filtern für Thema, Quelle, Bereich und Zeitraum
- Volltextsuche im Browser (Fuse.js), auch ohne Suchbegriff nach Quelle filterbar
- Glossar mit 309 Begriffen, Suche, Alphabet-Sprungleiste und Verweisen auf passende Meldungen
- Merkliste mit Export und Import als JSON-Datei
- Hell-, Dunkel- und Systemdarstellung, einstellbare Schriftgröße, Einstellungsseite
- Responsives Layout, mobil zuerst (Tab-Leiste am Handy, Navigation oben am Desktop)
- Neu seit deinem letzten Besuch: neue Meldungen sind markiert, mit Zähler am Reiter "Heute" und Filter "Nur Neues"
- Mehrfachmeldungen zusammengeführt: dasselbe Ereignis aus mehreren Quellen erscheint einmal, die übrigen Quellen stehen als "Auch bei" darunter
- Systemstatus (
#/status): Zustand des letzten Laufs und aller Quellen - Offline-Betrieb über einen Service Worker, installierbar auf dem Home-Bildschirm
- Stand-Anzeige ("aktualisiert heute 07:12")
Pipeline
- Abruf von RSS-Feeds und Übersichtsseiten, Entfernen von Dubletten, Auswahl nur neuer Artikel
- Kuratierung über
claude -pmit dem Claude-Abonnement, ohne API-Kosten - Tagesüberblick mit 5 bis 8 Top-Stories
- Speicherung als JSON, automatischer Git-Commit und Push
- Automatischer Start über macOS launchd, Nachholen verpasster Tage
Inhaltliches Konzept
Die Meldungen sind in zwei Bereiche und sieben Themen gegliedert.
| Bereich | Inhalt |
|---|---|
| A, International | aktuelle News, wichtige Updates, neueste Entwicklungen, Fälle und Stories, Politik und Regulierung |
| B, Deutschland | neue KI-Weiterbildungen und Kurse, Entwicklungen deutscher Unternehmen, relevante Politik |
Themen: KI & Lernen (alles zu Weiterbildung, Schulung, Fortbildung und KI-Kompetenz), Modelle und Produkte, Forschung, Business, Politik und Regulierung, Unternehmen DE, Sicherheit und Ethik. Werbung, etwa Webinar- und Seminarwerbung, wird bei der Kuratierung verworfen.
Zusätzlich markiert die Kuratierung einzelne Meldungen als Praxistipp/Tool (Anleitungen, Workflows, Tool-Empfehlungen) und als kurios (außergewöhnliche Fälle und Fakten). Beide Merkmale kommen zum Thema hinzu und sind im Archiv filterbar.
Architektur
sources.yaml ──► pipeline.py ──► data/*.json ──► git push ──► GitHub Pages ──► Browser
│ (statisch) (Vanilla JS,
├─ Feeds und Seiten abrufen Fuse.js,
├─ filtern, deduplizieren localStorage)
├─ claude -p (Abo, Headless)
└─ validieren und speichern
launchd (07:00, Anmeldung, stündlich) ──► run.sh ──► pipeline.py
Es gibt keinen Server und keine Datenbank. Die Pipeline läuft lokal auf einem Mac, das Ergebnis wird als statische Dateien im Repository veröffentlicht. Die Web-App lädt ausschließlich JSON aus data/ und content/.
Pipeline
pipeline.py führt pro Lauf diese Schritte aus:
- Abruf. Für jede aktive Quelle aus
sources.yaml: RSS überfeedparser, Web-Quellen über die Link-Liste einer Übersichtsseite und die Meta-Angaben der Artikelseiten (Titel und Beschreibung). Ein Fehler bei einer Quelle wird protokolliert und überspringt nur diese Quelle. - Auswahl.
- Zeitfenster: 3 bis 10 Tage, abhängig vom letzten erfolgreichen Lauf. Verpasste Tage werden so nachgeholt.
- Optionaler Keyword-Filter je Quelle für allgemeine Feeds. Kurze Kürzel wie "KI" werden exakt, andere Begriffe am Wortanfang geprüft.
- Dubletten: normalisierte URL (ohne Tracking-Parameter) und Titelähnlichkeit (
difflib, Schwelle 0,88) gegen Bestand und aktuellen Lauf. - Limit je Quelle (Standard 6), Prioritätsquellen zuerst, höchstens 100 Artikel pro Lauf.
- Kuratierung. Die Artikel werden in Batches zu je 10 an
claude -p --output-format json --no-session-persistence --tools ""übergeben. Pro Artikel liefert das Modell als JSON:headline,summary(2 bis 3 Sätze in eigenen Worten),thema,region,relevanz(1 bis 5),tagssowie optionalkurios,praxisundki_bezug. Die Antwort wird validiert. Artikel ohne KI-Bezug werden 30 Tage lang gemerkt und verworfen. Unvollständige oder ungültige Antworten werden beim nächsten Lauf erneut versucht. - Zusammenführen. Ein weiterer
claude -p-Aufruf erkennt Meldungen, die dasselbe Ereignis behandeln (Fenster: betroffene Tage und je der Vortag, höchstens 180 Meldungen). Die Hauptmeldung erhältalso(Quelle und Link der übrigen), die Nebenmeldungendup_of. Eine leere oder unbrauchbare Antwort ändert bestehende Gruppen nicht. - Tagesüberblick. Für jeden betroffenen Tag wählt ein weiterer Aufruf aus den Hauptmeldungen 5 bis 8 Top-Stories aus und formuliert je einen Satz. Wenn Meldungen aus Deutschland vorhanden sind, werden mindestens zwei berücksichtigt.
- Speichern. Tagesdateien, Index und Status werden atomar geschrieben (temporäre Datei, dann Ersetzen).
- Git. Commit "Daten JJJJ-MM-TT",
git pull --rebase --autostash,git push.
Abrechnung. Der Aufruf von claude erfolgt mit einer bereinigten Umgebung. Die Variablen ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_BASE_URL sowie alle CLAUDE_CODE_*-Variablen werden entfernt, sodass ausschließlich die Anmeldung des Abonnements verwendet wird.
Betriebssicherheit.
- Ein Lauf pro Tag:
state.jsonmerkt sich den letzten erfolgreichen Tag. Ein weiterer Start am selben Tag beendet sich sofort. - Lockfile (
fcntl) verhindert parallele Läufe. - Log in
~/Library/Logs/ai-news-hub.log(rotierend, 3 x 1 MB). - Bei fehlgeschlagener Kuratierung oder Push-Fehlern erscheint höchstens einmal pro Tag eine macOS-Mitteilung.
- Nur bei vollständigem Erfolg wird der Tag als erledigt markiert, sonst wiederholt der stündliche Start den Lauf.
Kommandozeile.
pipeline.py [--force] [--no-git] [--only ID] [--limit N] [--backfill {kurios,praxis}]
| Option | Wirkung |
|---|---|
--force |
läuft auch, wenn für heute schon ein Lauf existiert |
--no-git |
kein Commit und kein Push |
--only ID |
nur die Quelle mit dieser ID |
--limit N |
höchstens N Artikel in diesem Lauf |
--backfill kurios, praxis oder cluster |
bestehende Artikel nachträglich auf das Merkmal prüfen bzw. Mehrfachmeldungen neu zusammenführen |
Datenmodell
data/
index.json alle Meldungen (für Suche und Archiv)
state.json Laufstatus, Quellenstatus (mit Namen), verworfene URLs
JJJJ/MM/JJJJ-MM-TT.json Tagesdatei: Überblick und Meldungen des Tages
content/
glossar.json Glossar
Meldung (in index.json und in den Tagesdateien):
| Feld | Bedeutung |
|---|---|
id |
stabile Kennung (Hash der normalisierten URL) |
date, published |
Veröffentlichungstag und -zeitpunkt (Europe/Berlin) |
headline |
eigene Schlagzeile |
summary |
eigene Kurzfassung, 2 bis 3 Sätze |
thema |
eines der sieben Themen |
region |
de oder intl (Bereich B oder A) |
relevanz |
1 bis 5 |
tags |
bis zu fünf Schlagworte |
kurios |
optional, ein Satz zur Begründung |
praxis |
optional, true bei Praxistipps und Tools |
source, source_id |
Anzeigename und ID der Quelle |
added |
Zeitpunkt der Aufnahme durch die Pipeline (Grundlage für "Neu") |
also |
optional, bei Hauptmeldungen: Quelle und Link weiterer Quellen zum selben Ereignis |
dup_of |
optional, bei Nebenmeldungen: id der Hauptmeldung, wird nicht einzeln angezeigt |
quelle_titel, url |
Originaltitel und Link zur Quelle |
Tagesdatei: date, generated_at, overview (Liste aus id und text), items.
Quellen
Alle Quellen stehen in sources.yaml. Eine neue Quelle ist ein neuer Eintrag.
- id: heise-ki name: heise KI type: rss # rss oder web region: de # de oder intl url: "https://www.heise.de/thema/Kuenstliche-Intelligenz.xml" keywords: [KI, "Künstliche Intelligenz"] # optional, Filter für allgemeine Feeds max_items: 4 # optional, Limit pro Lauf priority: true # optional, wird zuerst kuratiert enabled: false # optional, Quelle behalten, aber nicht abrufen note: Freitext
Für type: web gibt link_pattern (regulärer Ausdruck) an, welche Links der Übersichtsseite Artikel sind. Mit google_news: true wird ein Sammel-Feed (Google-News-RSS-Suche) behandelt: Quelle und Titel stammen aus dem Eintrag, es gibt keinen Teaser.
Der Bestand umfasst 69 Einträge (64 aktiv), davon 19 international und 50 für Deutschland, darunter 6 thematische Suchfeeds.
Quellen ohne eigenen Feed
| Quelle | Lösung |
|---|---|
| Anthropic | kein offizieller Feed, Community-Feed (GitHub, Olshansk/rss-feeds) |
| Meta AI | Engineering-Blog (ML) als Ersatz |
| The Batch, Fraunhofer Academy | Web-Quelle über Link-Liste |
| Euractiv, BMWE, Kursnet, VentureBeat | deaktiviert (Bot-Schutz, keine Links im HTML, Suchanwendung, Rate-Limit) |
Bezahlte Newsletter sind bewusst nicht Teil des Repositories.
Web-App
Single-Page-App aus index.html, css/style.css und js/app.js, ohne Framework und ohne Build-Schritt.
- Routing über den URL-Hash:
#/(neuester Tag),#/tag/JJJJ-MM-TT,#/briefing,#/woche,#/status,#/archiv,#/suche,#/glossar,#/merkliste,#/einstellungen. Filter und Suchbegriffe stehen in der URL und sind teilbar. - Briefing: wird vollständig im Browser aus den vorhandenen Daten zusammengestellt (Tagesüberblick, Region, Praxis- und Kurios-Markierung, Glossar), ohne zusätzlichen Pipeline-Schritt. Der Begriff des Tages ist pro Datum stabil. Wahlweise als Startseite einstellbar.
- Neu-Markierung: Pro Gerät merkt sich die App im Browser, wann zuletzt Betrieb war (
visitBase,visitActive). Nach 30 Minuten Pause beginnt eine neue Sitzung, Meldungen mitadded(sonstpublished) nach deren Beginn gelten als neu. - Offline:
sw.jslädt beim Installieren die App-Dateien,data/index.json, das Glossar und den neuesten Tag vor. Seiten und JSON werden zuerst vom Netz geholt (nach 4 Sekunden Wartezeit zählt die gespeicherte Kopie), versionierte Dateien und Symbole kommen aus dem Speicher. Mitmanifest.webmanifestund den Symbolen untericons/lässt sich die App auf dem Home-Bildschirm ablegen. Ein Hinweis zeigt, wenn das Gerät offline ist. - Suche mit Fuse.js 7.0.0 (lokal eingebunden) über Schlagzeile, Tags, Kurzfassung, Quelle und Originaltitel.
- Lokaler Speicher (
localStorage):theme,fs(Schriftgröße),favs(Merkliste),settings. Es werden keine Daten an einen Server gesendet. - Gestaltung: AITI-Farben (DeepAi
#26595E, LimeByte#F5FC9C, MintTech#D1FAE3, SkyMind#C9DEE3, VerdaNova#F2F0E8) in hellem und dunklem Modus, dazu ein Blau (#2f6bff) als zweiter Akzent für "Die Woche in Kürze" und das Thema "Modelle und Produkte". Der Tag ist grün, die Woche blau. Die Farben stehen als Variablen am Anfang voncss/style.cssund im Block "AITI-Farben" am Ende. - Darstellung: Farbschema folgt dem System oder wird festgelegt, Schriftgröße in acht Stufen (Standard 15 px, mobil 14 px). Formularfelder haben 16 px, damit iOS-Safari nicht hineinzoomt.
- Barrierefreiheit: semantische Elemente, ARIA-Beschriftungen, sichtbarer Fokus, Rücksicht auf
prefers-reduced-motion. - Laden: Karten im Archiv werden erst beim Aufklappen einer Gruppe erzeugt, die Tagesansicht lädt nur die Datei des gewählten Tages.
- Cache: JS und CSS werden mit Versionsnummer eingebunden (
?v=N). Bei Änderungen an der App wird sie erhöht.
Automatisierung
Der launchd-Job com.frank.ai-news-hub startet run.sh:
- täglich um 07:00 (Systemzeitzone Europe/Berlin)
- beim Anmelden (
RunAtLoad) - stündlich (
StartInterval3600)
Das Skript prüft zuerst, ob für heute schon ein Lauf existiert, und beendet sich dann sofort. Ist der Mac zur Startzeit aus oder im Ruhezustand, holt der nächste Start (Anmeldung oder stündlicher Takt) alles nach. Die Datei run.sh setzt einen minimalen PATH, so wie launchd ihn auch vorgibt.
launchd/install.sh # installieren oder aktualisieren
launchd/install.sh --uninstall # entfernen
Die Vorlage launchd/com.frank.ai-news-hub.plist.template enthält Platzhalter für Repository- und Home-Pfad, install.sh setzt sie ein und lädt den Job mit launchctl bootstrap.
Installation und Betrieb
Voraussetzungen
- macOS (für launchd), Python 3.9 oder neuer, Git
- Claude Code mit Anmeldung über ein Abonnement:
claude auth login - Optional
ghfür das Anlegen des Repositories
Einrichtung
git clone https://github.com/frankknebeljanssen-create/ai-news-hub.git
cd ai-news-hub
python3 -m venv .venv
.venv/bin/pip install -r requirements.txtTestlauf ohne Veröffentlichung
.venv/bin/python pipeline.py --force --no-git --limit 10
Regulärer Lauf und Automatik
./run.sh # ein Lauf, committet und pusht launchd/install.sh # Automatik einrichten
GitHub Pages: Branch main, Ordner / (Wurzel). Die Datei .nojekyll verhindert die Jekyll-Verarbeitung.
Lokale Vorschau
python3 -m http.server 8000 # danach http://localhost:8000Impressum: Anbieterangaben stehen in impressum.json (name, anschrift, email, telefon) und werden in den Einstellungen angezeigt.
Projektstruktur
.
├── index.html Einstiegsseite der Web-App
├── css/style.css Gestaltung, Hell- und Dunkelmodus
├── sw.js Service Worker (Offline-Zwischenspeicher)
├── manifest.webmanifest Web-App-Manifest für den Home-Bildschirm
├── icons/ App-Symbole (PNG)
├── tools/make_icons.py erzeugt Icon (SVG, PNG) ohne Fremdbibliotheken: LimeByte-Grund, Briefing-Karte, blauer Funke, kleines AITI-Zeichen
├── js/
│ ├── app.js Router, Ansichten, Suche, Merkliste, Einstellungen
│ └── vendor/fuse.min.js Fuse.js 7.0.0 (Apache License 2.0)
├── content/glossar.json Glossar (309 Begriffe)
├── data/ Ausgabe der Pipeline (siehe Datenmodell)
├── pipeline.py Abruf, Auswahl, Kuratierung, Speicherung, Git
├── sources.yaml Quellenliste
├── run.sh Startskript für launchd
├── launchd/ Plist-Vorlage und Installationsskript
├── impressum.json Anbieterangaben
├── requirements.txt feedparser, pyyaml
└── .nojekyll
Datenschutz, Urheberrecht und KI-Hinweis
- Urheberrecht. Gespeichert und veröffentlicht werden nur eigene Kurzfassungen, der Originaltitel und der Link zur Quelle. Es gibt keine Volltexte und keine Zitate. Die Kuratierung erhält Titel und Teaser der Quelle als Eingabe.
- Datenschutz. Die Web-App setzt keine Cookies, nutzt kein Tracking und lädt keine Ressourcen von Dritten. Einstellungen und Merkliste bleiben im Browser. Beim Aufruf der Seite verarbeitet GitHub Pages technisch bedingt die IP-Adresse.
- KI-Hinweis. Schlagzeilen, Kurzfassungen, Themenzuordnung, Markierungen und Tagesüberblick werden automatisch mit KI (Claude von Anthropic) erstellt und können Fehler enthalten. Maßgeblich ist stets der verlinkte Originalartikel.
- Geheimnisse. Das Repository enthält keine Zugangsdaten. Die Anmeldung bei Claude liegt im Schlüsselbund des ausführenden Nutzers.
Bekannte Grenzen
- Die Pipeline setzt einen angemeldeten Mac voraus. Läuft er nicht, entstehen bis zum nächsten Start keine neuen Daten.
- Bei Ablauf der Claude-Anmeldung schlägt die Kuratierung fehl. Die Mitteilung weist darauf hin, die Lösung ist
claude auth login. - Die Zuordnung zu Thema, Region und Relevanz ist eine Einschätzung des Modells. Meldungen zum selben Ereignis aus mehreren Quellen werden in den Themenblöcken nicht zusammengeführt, in den Zusatzboxen nur grob entfernt.
- Bei Quellen ohne Teaser (Suchfeeds) beruht die Kurzfassung allein auf dem Titel.
- Der Offline-Betrieb setzt einen ersten Besuch mit Netz voraus. Ob Safari den Zwischenspeicher dauerhaft behält, entscheidet das System, bei längerer Nichtnutzung kann er geleert werden.
- Kursdatenbanken wie Kursnet haben keinen Feed und sind nicht angebunden.
Lizenz
Für den Quelltext ist noch keine Lizenz festgelegt. Die enthaltene Bibliothek Fuse.js steht unter der Apache License 2.0.
来源:GitHub · github.com