feat: KI-gestützte Inhaltsanalyse via OpenRouter (hash-gegated)
Optionale semantische Prüfung von Text und Bildern (inkl. OCR) auf problematische Inhalte ohne Link-Signal: Pornografie, Propaganda, diffamierende/strafbare Texte, versteckter Spam, themenfremde Werbung, widersprüchliche Aussagen. Bewertet die thematische Passung zum deklarierten site_context — eingestreute Heimat-Begriffe täuschen die Erkennung nicht. Kern: - scanner/ai_analyzer.py: run_ai_analysis + score_ai_findings. Hash-Gate über data/ai_ledger.json → unveränderte Inhalte = Cache- Treffer = kein API-Call. Nur neue/geänderte Inhalte kosten etwas. - Modell-Kette mit zweifacher Eskalation (Stufe 1+2 free, Stufe 3 günstig bezahlt); eskaliert bei Fehler ODER Timeout (attempt_timeout). Erfolgreiches Modell wird im Ledger vermerkt. - KI-Funde sind auf GELB gedeckelt — ROT bleibt harten Integritäts- Signalen vorbehalten. Graceful degradation: ohne Key/bei Fehler wird übersprungen, Scan läuft unverändert weiter. Integration: - baseline.py: load/save_ai_ledger, dismiss_ai_entries. - config.py: ai_analysis-Block + ai_* Scoring-Schlüssel. - __main__.py: Einhängung in cmd_scan/cmd_check, ai-dismiss-Subcommand, approve quittiert zugehörige Funde, status-Anzeige, diff-only + report. - alerter.py + __main__.py: beanstandete Dateien erscheinen mit URL, Begründung und Quittier-Fingerprint in E-Mail UND Markdown-Report. - plain.py: laienverständliche KI-Sätze. API-Key nur aus Umgebungsvariable (OPENROUTER_API_KEY). Audio/Video als abschaltbare Hooks vorbereitet (default aus). Modelle live gegen OpenRouter verifiziert; Demo auf bredelar.info zeigte korrekte Erkennung (echter Inhalt clean, eingeschleuster Casino-Spam mit Heimat-Begriffen als hidden_spam erkannt). Tests: 227 grün (+26 für ai_analyzer, +1 für E-Mail-KI-Abschnitt). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0aaf53135a
commit
cae3dbb985
11 changed files with 1301 additions and 7 deletions
|
|
@ -71,6 +71,7 @@ Alles Weitere in dieser Anleitung richtet sich an **Fortgeschrittene** und an
|
|||
17. [Cloaking-Erkennung](#17-cloaking-erkennung)
|
||||
18. [Externe Links auf Erreichbarkeit prüfen](#18-externe-links-auf-erreichbarkeit-prüfen)
|
||||
19. [Binärdateien und Assets prüfen](#19-binärdateien-und-assets-prüfen)
|
||||
20. [KI-gestützte Inhaltsanalyse](#20-ki-gestützte-inhaltsanalyse)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -220,6 +221,7 @@ Globale Optionen: `--config path/to/config.yaml`, `--verbose` (`-v`).
|
|||
| `check-assets` | Binärdateien (JS/CSS/Bilder) auf Inhaltsänderung prüfen |
|
||||
| `approve-assets` | Aktuelle Asset-Hashes als neue Baseline setzen |
|
||||
| `test-alert` | Test-E-Mail senden ohne echten Scan — prüft SMTP-Konfiguration |
|
||||
| `ai-dismiss --all` | KI-Funde als geprüft/akzeptiert quittieren (Fehlalarm) |
|
||||
|
||||
### Beispiele
|
||||
|
||||
|
|
@ -630,6 +632,8 @@ angewendet — falsch-positive Alarme durch dynamische CMS-Inhalte werden so unt
|
|||
| Kaputte **externe** Links (4xx/5xx) | Ja, mit `check-ext-links` | Kein Score, nur Report |
|
||||
| UA-basiertes Cloaking (Googlebot sieht anderen Inhalt) | Ja, mit `cloak-check` | Score 40–60 |
|
||||
| Veränderungen in JS/CSS/Bildern (Inhalt) | Ja, mit `check-assets` | Score 20–40 |
|
||||
| Problematischer Text (Pornografie, Propaganda, Spam, Off-Topic) | Ja, mit KI-Analyse | Score 20–50, auf Gelb gedeckelt |
|
||||
| Problematische Bildinhalte + Text im Bild (OCR) | Ja, mit KI-Analyse | Score ≥ 40, auf Gelb gedeckelt |
|
||||
| IP-basiertes Cloaking | Nein | Nur Google Search Console kann das erkennen |
|
||||
| Serverseitige Code-Änderungen | Nein | Nur sichtbare HTML-Ausgabe |
|
||||
|
||||
|
|
@ -822,3 +826,128 @@ Der Report liegt unter `reports/<ts>_assets/report.md` und zeigt pro geänderter
|
|||
`periodic_checks` in der `config.yaml`). Die Datei-Vergleichsgrundlage wird zudem beim
|
||||
ersten `approve --all` automatisch angelegt — `approve-assets` ist nur für den manuellen
|
||||
Sonderfall gedacht.
|
||||
|
||||
---
|
||||
|
||||
## 20. KI-gestützte Inhaltsanalyse
|
||||
|
||||
Eine **optionale** Ergänzung zum Integritäts-Kern. Sie prüft Text und Bilder **semantisch**
|
||||
auf problematische Inhalte, die kein strukturelles Signal hinterlassen:
|
||||
|
||||
- sexuell anstößige Inhalte / Pornografie
|
||||
- politische Propaganda
|
||||
- diffamierende oder strafbare Aussagen
|
||||
- versteckter Werbe-/Spam-Text
|
||||
- Werbung, die thematisch nicht zur Website passt
|
||||
- in sich widersprüchliche Aussagen
|
||||
- problematische Bildinhalte **und** Text in Bildern (OCR)
|
||||
|
||||
Die KI ist **Ergänzung, nicht Kern**: Ist sie deaktiviert (Standard), verhält sich der
|
||||
Scanner exakt wie bisher.
|
||||
|
||||
### Das Kostengate (warum das günstig ist)
|
||||
|
||||
Jeder Text und jedes Bild bekommt einen Fingerabdruck (Hash). Das Ergebnis der KI-Prüfung
|
||||
wird zu diesem Fingerabdruck in `data/ai_ledger.json` gespeichert. Bei jedem weiteren Scan
|
||||
gilt:
|
||||
|
||||
- **Inhalt unverändert** → gleicher Hash → Ergebnis kommt aus dem Cache → **keine** Abfrage,
|
||||
keine Kosten.
|
||||
- **Inhalt neu oder geändert** → eine günstige OpenRouter-Abfrage, Ergebnis wird gespeichert.
|
||||
|
||||
Dadurch kann die Analyse bei **jedem** Scan mitlaufen und kostet an den meisten Tagen 0 €.
|
||||
|
||||
### Wirkung auf die Ampel
|
||||
|
||||
KI-Funde sind **auf Gelb gedeckelt** — sie lösen niemals allein ROT aus. ROT bleibt den
|
||||
harten Integritäts-Signalen (Webshell, versteckte Inhalte) vorbehalten. Nur Funde mit
|
||||
ausreichender Sicherheit (Konfidenz ≥ `ai_confidence_min`, Standard 0,7) und mindestens
|
||||
mittlerer Schwere werden gewertet — das hält Fehlalarme niedrig.
|
||||
|
||||
Fehlt der API-Key oder schlägt eine Abfrage fehl, wird die Analyse **übersprungen** und der
|
||||
Scan läuft unverändert weiter. Die KI kann den normalen Betrieb nie blockieren.
|
||||
|
||||
### Aktivieren
|
||||
|
||||
```yaml
|
||||
ai_analysis:
|
||||
enabled: true
|
||||
api_key_env: "OPENROUTER_API_KEY"
|
||||
site_context: "Heimat- und Vereinswebsite über die Bergbaugeschichte in Bredelar."
|
||||
ai_confidence_min: 0.7
|
||||
attempt_timeout: 30 # Zeitlimit je Modell-Versuch → eskaliert bei Langsamkeit
|
||||
text:
|
||||
enabled: true
|
||||
models: # Kette: Stufe 1+2 free, Stufe 3 günstig bezahlt
|
||||
- "qwen/qwen3-next-80b-a3b-instruct:free"
|
||||
- "meta-llama/llama-3.3-70b-instruct:free"
|
||||
- "google/gemini-2.5-flash-lite"
|
||||
min_chars: 200 # nur Seitentexte ab dieser Größe
|
||||
max_pages_per_scan: 20 # Kostendeckel pro Lauf
|
||||
image:
|
||||
enabled: true
|
||||
models: # multimodal: Inhalt + OCR
|
||||
- "google/gemma-4-31b-it:free"
|
||||
- "nvidia/nemotron-nano-12b-v2-vl:free"
|
||||
- "google/gemini-2.5-flash-lite"
|
||||
max_images_per_scan: 15
|
||||
```
|
||||
|
||||
**Wichtig — `site_context`:** Die KI bewertet die **thematische Passung** zur hier
|
||||
beschriebenen Website, nicht einzelne Schlüsselwörter. Ein Angreifer kann Heimat- oder
|
||||
Ortsbegriffe einstreuen, um simple Wortlisten zu täuschen — gegen die semantische
|
||||
Themenprüfung hilft das nicht. Je präziser der `site_context`, desto besser die Trefferquote.
|
||||
|
||||
### API-Key setzen
|
||||
|
||||
Das Passwort/Token **niemals** in `config.yaml` eintragen, nur als Umgebungsvariable:
|
||||
|
||||
```bash
|
||||
# Dauerhaft in ~/.bashrc
|
||||
echo 'export OPENROUTER_API_KEY="sk-or-..."' >> ~/.bashrc
|
||||
```
|
||||
|
||||
Für den Cron-Betrieb die Variable wie bei `SCANNER_SMTP_PASSWORD` in der Crontab oder in
|
||||
`/etc/environment` hinterlegen.
|
||||
|
||||
### Fehlalarm quittieren
|
||||
|
||||
Wurde legitimer Inhalt fälschlich als auffällig markiert:
|
||||
|
||||
```bash
|
||||
python -m scanner https://ihre-website.de ai-dismiss --all # alle offenen Funde
|
||||
python -m scanner https://ihre-website.de ai-dismiss --hash <fp> # gezielt einen Fund
|
||||
```
|
||||
|
||||
Der Fingerabdruck `<fp>` steht im Report bei jedem KI-Fund. Ein `approve --all` oder
|
||||
`approve --url` quittiert die zugehörigen KI-Funde automatisch mit (freigegebener Inhalt
|
||||
gilt als geprüft).
|
||||
|
||||
### Modelle (OpenRouter) und Eskalation
|
||||
|
||||
Pro Modalität wird eine **Modell-Kette mit zweifacher Eskalation** abgearbeitet. Schlägt ein
|
||||
Modell fehl (Fehler, Rate-Limit) oder antwortet es langsamer als `attempt_timeout` Sekunden,
|
||||
wird automatisch zur nächsten Stufe gewechselt. Stufe 1 und 2 sind kostenlose Modelle, Stufe 3
|
||||
ist ein günstiges Bezahlmodell — so bleibt die Prüfung in der Regel kostenlos und ist trotzdem
|
||||
zuverlässig. Welche Stufe das Verdikt geliefert hat, wird im Ledger und Report festgehalten.
|
||||
|
||||
| Zweck | Stufe 1 (free) | Stufe 2 (free) | Stufe 3 (bezahlt) |
|
||||
|---|---|---|---|
|
||||
| Text/Semantik | `qwen3-next-80b-a3b-instruct:free` | `llama-3.3-70b-instruct:free` | `gemini-2.5-flash-lite` |
|
||||
| Bild + OCR | `gemma-4-31b-it:free` | `nemotron-nano-12b-v2-vl:free` | `gemini-2.5-flash-lite` |
|
||||
|
||||
Hinweis: Kostenlose Modelle liefern nicht immer ein gültiges Ergebnis (sie unterstützen das
|
||||
strikte JSON-Format nicht durchgehend). In dem Fall greift automatisch die nächste Stufe — das
|
||||
zuverlässige Bezahlmodell auf Stufe 3 fängt solche Fälle ab.
|
||||
|
||||
Audio- und Video-Prüfung sind als abschaltbare Erweiterungspunkte vorbereitet
|
||||
(`ai_analysis.audio` / `ai_analysis.video`, default deaktiviert) und können aktiviert werden,
|
||||
sobald eine Website solche Mediendateien direkt einbindet.
|
||||
|
||||
### Status prüfen
|
||||
|
||||
```bash
|
||||
python -m scanner https://ihre-website.de status
|
||||
```
|
||||
|
||||
zeigt bei aktivierter KI, wie viele Inhalte im Cache liegen und wie viele offene Funde es gibt.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue