Initiales Ingest-Repo (aus gdelt-bot/ingest überführt)
Poller, Schema, Quadlet-Units und Quellenregister aus dem Monorepo gdelt-bot in ein eigenes Repo ausgelagert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VzNVf1KaHPZ1fzJT2jd18j
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
# Ingest
|
||||
|
||||
Stufe 0 und 1 der Pipeline: Quellenregister und Roh-Erfassung. Keine
|
||||
Kodierung — was hier landet, soll sich beliebig oft neu kodieren lassen.
|
||||
|
||||
## Dateien
|
||||
|
||||
| Datei | Zweck |
|
||||
|---|---|
|
||||
| `sources.toml` | Quellenregister, einzige Wahrheit ueber die Quellen |
|
||||
| `schema.sql` | Postgres-Schema (`quellen`, `raw_items`, `codings`, `poll_laeufe`) |
|
||||
| `poller.py` | Poller, zwei Senken: Postgres und gzip-JSONL |
|
||||
| `Containerfile` | Image fuer Bebop |
|
||||
| `lagebild-ingest.container`, `lagebild.network` | Quadlet-Units, rootless |
|
||||
| `ingest.env.example` | Vorlage fuer die Zugangsdaten |
|
||||
|
||||
## Bebop
|
||||
|
||||
```sh
|
||||
# 1. Schema einspielen
|
||||
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f schema.sql
|
||||
|
||||
# 2. Image bauen
|
||||
podman build -t localhost/lagebild-ingest:latest .
|
||||
|
||||
# 3. Konfiguration ablegen
|
||||
mkdir -p ~/.config/lagebild
|
||||
cp ingest.env.example ~/.config/lagebild/ingest.env
|
||||
cp sources.toml ~/.config/lagebild/sources.toml
|
||||
chmod 600 ~/.config/lagebild/ingest.env
|
||||
$EDITOR ~/.config/lagebild/ingest.env
|
||||
|
||||
# 4. Quadlet installieren
|
||||
mkdir -p ~/.config/containers/systemd
|
||||
cp lagebild-ingest.container lagebild.network ~/.config/containers/systemd/
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user start lagebild-ingest
|
||||
journalctl --user -u lagebild-ingest -f
|
||||
|
||||
# Damit der Dienst ohne offene Sitzung weiterlaeuft:
|
||||
loginctl enable-linger "$USER"
|
||||
```
|
||||
|
||||
`sources.toml` ist eingehaengt, nicht ins Image gebacken: eine neue Quelle ist
|
||||
ein `systemctl --user restart lagebild-ingest`, kein Neubau.
|
||||
|
||||
## Pi 5 — Schatten-Ingest
|
||||
|
||||
Ohne Postgres, ohne Container:
|
||||
|
||||
```sh
|
||||
python3 poller.py --sink jsonl:/var/lib/lagebild/schatten
|
||||
```
|
||||
|
||||
Legt `<dir>/YYYYMMDD/YYYYMMDDHHMMSS.jsonl.gz` an, dedupliziert ueber eine
|
||||
SQLite daneben. Als `systemd --user`-Unit mit `Restart=always` einrichten.
|
||||
|
||||
Der Sinn ist nicht Redundanz um ihrer selbst willen: RSS-Feeds haben kein
|
||||
Archiv. Steht Bebops Poller einen Tag still, ist dieser Tag unwiederbringlich
|
||||
weg. Kodierungen lassen sich wiederholen, Rohdaten nie.
|
||||
|
||||
## Betrieb
|
||||
|
||||
```sh
|
||||
# Lizenzstatus im Register gegen die aktuelle robots.txt pruefen
|
||||
python3 poller.py --check-robots # Exit != 0 bei Abweichung
|
||||
|
||||
# ein einzelner Durchlauf
|
||||
python3 poller.py --sink "$DATABASE_URL" --once
|
||||
```
|
||||
|
||||
`--check-robots` gehoert in einen woechentlichen Cron. Ein Verlag, der seine
|
||||
robots.txt aendert, aendert damit seinen Nutzungsvorbehalt — und das ist der
|
||||
Punkt, an dem eine Quelle stillgelegt werden muss.
|
||||
|
||||
Aendert sich etwas, wird **`sources.toml` angepasst, nie der Code.** Eine
|
||||
gesperrte Quelle bleibt im Register stehen (`aktiv = false`), damit
|
||||
nachvollziehbar bleibt, warum sie fehlt. Der Poller verweigert den Start,
|
||||
wenn eine als `gesperrt` gefuehrte Quelle aktiv geschaltet ist.
|
||||
|
||||
### Waechter
|
||||
|
||||
```sql
|
||||
-- aktive Quellen, die seit ueber sechs Stunden nichts Neues liefern
|
||||
select * from quellen_stillstand;
|
||||
|
||||
-- Fehler der letzten Stunde
|
||||
select quelle, http_status, fehler, begonnen_am from poll_laeufe
|
||||
where fehler is not null and begonnen_am > now() - interval '1 hour';
|
||||
```
|
||||
|
||||
### Arbeitsvorrat fuer Yantra
|
||||
|
||||
```sql
|
||||
select * from unkodiert('qwen3-14b-q4/prompt-1') limit 500;
|
||||
```
|
||||
|
||||
Liefert alle Items, die diese Kodierer-Version noch nicht gesehen hat. Eine
|
||||
neue Prompt-Version ist damit automatisch ein vollstaendiger Recode-Auftrag
|
||||
ueber die gesamte Historie, ohne dass ein Feed erneut abgerufen wird.
|
||||
|
||||
## Verhalten
|
||||
|
||||
- **15-Minuten-Takt**, an den Slotgrenzen ausgerichtet (+30 s Versatz),
|
||||
identisch zu GDELTs Paketgrenzen — damit bleiben die Slots vergleichbar.
|
||||
- **Bedingter GET** ueber ETag/Last-Modified, im Register gespeichert. Im
|
||||
Test antworteten 4 von 12 Quellen im zweiten Durchlauf mit 304.
|
||||
- **Dedup** ueber `unique (quelle, item_key)`; `item_key` ist guid, ersatzweise
|
||||
Link, ersatzweise ein Titel-Hash.
|
||||
- **Fehlertoleranz**: eine kaputte Quelle beendet den Durchlauf nicht, der
|
||||
Fehler landet in `poll_laeufe`.
|
||||
- **Kein Volltext-Abruf.** Nur der Feed selbst wird geholt. Titel und Teaser
|
||||
reichen als Kodierungsinput, und damit stellt sich die TDM-Frage nach
|
||||
§ 44b UrhG gar nicht erst.
|
||||
|
||||
## Gemessen (2026-09-04)
|
||||
|
||||
Erster Lauf ueber 12 aktive Quellen: 820 Items gesehen, 810 neu, gesamter
|
||||
Durchlauf unter 3 s. Zweiter Lauf unmittelbar danach: 1 neues Item.
|
||||
|
||||
Das Trigramm-Clustering findet quellenuebergreifende Dubletten sofort:
|
||||
|
||||
```
|
||||
zeit | handelsblatt | 1.00 | Bekennerschreiben: Erneut Sabotage am Stromnetz
|
||||
spiegel | derstandard | 0.92 | Niederlage fuer Donald Trump - Gericht in Missouri
|
||||
```
|
||||
|
||||
## Offen
|
||||
|
||||
- Telegram-Fetcher (Telethon/MTProto). Register ist vorbereitet, Eintraege
|
||||
stehen auf `aktiv = false`. Die Bot-API kann fremde Kanaele nicht lesen.
|
||||
- Ersatz-URL fuer den BR24-Feed (aktuell 404).
|
||||
- Quellenpool von 12 auf ~40 erweitern; Regionalzeitungen ueber SearXNG auf
|
||||
Debby suchen.
|
||||
Reference in New Issue
Block a user