Commit graph

30 Commits

Autor SHA1 Nachricht Datum
Claude Dev
b38ae9e1b1 fix: Quellenlinks bei String-Nr repariert (574, 610, 611, 617 etc.)
Ursache: Claude liefert teilweise Quellennummern als String statt Integer.
Der Frontend-Vergleich (===) schlug dann fehl: "574" !== 574.

Fixes:
- 95 String-Nummern in Irankonflikt sources_json zu Integer konvertiert
- 5 Duplikate entfernt
- Frontend: Number() statt parseInt/=== fuer robusten Vergleich
- Orchestrator: Automatische Konvertierung von String-Nr zu Integer vor DB-Speicherung
- Cache-Buster aktualisiert

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 11:00:00 +01:00
Claude Dev
aad473a568 feat: Quelleneinordnung (Bias) in Lageberichten fuer kritische Quellen
Parteiische Quellen (pro-russisch, pro-iranisch, rechtsextrem etc.)
werden jetzt im Lagebericht-Fliesstext als solche gekennzeichnet,
damit der Leser die Informationen einordnen kann.

Aenderungen:
- Orchestrator reichert Artikel mit source_bias aus der sources-Tabelle an
- Analyzer zeigt Einordnung im Artikel-Kontext fuer den Claude-Prompt
- Alle 4 Prompt-Templates enthalten neue Regel zur Quellenkennzeichnung

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:53:36 +01:00
Claude Dev
bf21bc4e2c fix: Fehlende Quellenverweise in Lageberichten repariert und Validierung ergaenzt
17 fehlende Quellen (815-831) im Irankonflikt und 11 fehlende (77-87)
im Ukraine-Konflikt in sources_json nachgetragen. Ursache: Claude
referenziert Quellen im Summary-Text, liefert sie aber nicht immer
im sources-Array mit. Neue Validierung im Orchestrator erkennt
fehlende Quellennummern nach dem Merge und fuegt Platzhalter ein.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 10:46:25 +01:00
Claude Dev
6a2bd9e9c9 feat: Adhoc-Recherche bekommt bestehende Artikel als Kontext
- RESEARCH_PROMPT_TEMPLATE: {existing_context} Platzhalter eingefügt
- search(): Baut bei Adhoc-Folge-Refreshes Kontextblock mit bis zu 30 bekannten Headlines auf
- orchestrator: Übergibt bestehende Artikel jetzt für ALLE Incident-Typen, nicht nur Research

Effekt: Bei Adhoc-Auto-Refreshes findet Claude WebSearch gezielt neue Quellen statt immer dieselben Mainstream-Treffer

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 20:07:13 +01:00
Claude Dev
e0f8124e10 feat: Mehrstufige Deep-Research-Pipeline mit Quellenkontext
- DEEP_RESEARCH_PROMPT: 4-Phasen-Strategie (Breite Erfassung → Lückenanalyse → Gezielte Tiefenrecherche → Verifikation)
- Ziel 15-25 Quellen aus 5+ Quellentypen statt 8-15 aus Mainstream
- researcher.search(): Neuer Parameter existing_articles — bereits bekannte Quellen werden als Kontext übergeben, damit Claude gezielt neue Perspektiven findet
- orchestrator: DB-Abfrage vor Pipeline verschoben, bestehende Artikel als Kontext an Researcher übergeben (nur Research-Typ)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 18:33:56 +01:00
Claude Dev
19da099583 feat: Kontextabhängige Karten-Kategorien
4 feste Farbstufen (primary/secondary/tertiary/mentioned) mit
variablen Labels pro Lage, die von Haiku generiert werden.

- DB: category_labels Spalte in incidents, alte Kategorien migriert
  (target->primary, response/retaliation->secondary, actor->tertiary)
- Geoparsing: generate_category_labels() + neuer Prompt mit neuen Keys
- QC: Kategorieprüfung auf neue Keys umgestellt
- Orchestrator: Tuple-Rückgabe + Labels in DB speichern
- API: category_labels im Locations- und Lagebild-Response
- Frontend: Dynamische Legende aus API-Labels mit Fallback-Defaults
- Migrationsskript für bestehende Lagen

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 15:04:02 +01:00
Claude Dev
bbb543fac6 Fix: evidence-Spalte im FC-SELECT laden, damit alte URLs bei Re-Checks erhalten bleiben
Beim Re-Check eines Faktenchecks wurde die bestehende evidence nicht
aus der DB geladen (fehlte im SELECT). Dadurch konnte der Fallback-Code,
der alte URLs bewahren soll, nie greifen. Neue Evidence ohne URLs
überschrieb die alte mit URLs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-13 23:26:23 +01:00
Claude Dev
2792e916c2 Telegram-Kategorie-Checkboxen: Nutzer koennen bei Lage-Erstellung einzelne Telegram-Quellkategorien auswaehlen 2026-03-13 19:08:36 +01:00
Claude Dev
01cad9dac5 Telegram-Kanaele als Quelle: Parser, Pipeline, UI-Checkbox, Validate-Endpoint
- Neuer source_type telegram_channel in models.py (Source + Incident)
- DB-Migration: include_telegram Spalte fuer incidents
- feeds/telegram_parser.py: Telethon-basierter Parser (analog RSS)
- Orchestrator: Telegram-Pipeline parallel zu RSS + WebSearch
- sources.py: POST /api/sources/telegram/validate Endpoint
- incidents.py: include_telegram in Create/Update/Response
- dashboard.html: Telegram-Checkbox + Filter-Option
- app.js: FormData, EditModal, SourceStats, TypeLabels
- config.py: TELEGRAM_API_ID, API_HASH, SESSION_PATH
- requirements.txt: telethon hinzugefuegt
2026-03-13 13:10:24 +01:00
claude-dev
81a393fd4a feat: Post-Refresh Quality Check fuer Faktenchecks und Karten-Locations
Automatischer QC-Schritt nach jedem Refresh:
- Erkennt inhaltliche Faktencheck-Duplikate via Fuzzy-Matching (Threshold 0.80)
- Korrigiert falsch kategorisierte Karten-Locations (z.B. entfernte Laender als 'target')
- Laeuft nach dem Faktencheck-Commit, vor den Notifications
- Fehler im QC blockieren nicht den Refresh-Ablauf

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 21:41:45 +01:00
claude-dev
32dbfe99ac fix: sources_json Fallback auf vorherige Quellen wenn Analyse leer
Gleicher Bug wie bei der Summary: Wenn die Claude-API-Analyse keine Quellen
zurueckgibt, wurde sources_json mit NULL ueberschrieben. Dadurch konnten die
Quellenverweise [1], [2] etc. im Dashboard nicht mehr als Links gerendert werden.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 07:42:37 +01:00
claude-dev
ad41b8f4ea fix: Leere Summary nicht mehr in DB schreiben - Fallback auf vorherige Summary
Wenn die Claude-API-Analyse keinen oder einen leeren Summary zurueckgibt,
wird jetzt die vorherige Summary beibehalten statt mit einem leeren String
ueberschrieben zu werden.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 07:33:33 +01:00
claude-dev
1f3b3cb858 Zwei-Phasen-Faktencheck + parallele Analyse/Faktencheck-Ausführung
- Neuer Zwei-Phasen-Faktencheck: Haiku-Triage identifiziert betroffene Fakten,
  dann parallele Opus-Verifikation pro thematischer Gruppe (max 8 Fakten/Gruppe)
- Analyse und Faktencheck laufen jetzt parallel via asyncio.gather
- Snapshot-Erstellung vor parallele Verarbeitung verschoben
- Fallback auf Standard-Faktencheck bei Triage-Fehler
- Erwartete Verbesserung: ~19 Min -> ~8 Min pro Refresh bei gleichbleibender Qualität

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 20:16:45 +01:00
claude-dev
e2ea4eaaa0 Faktencheck-Deduplizierung und Auto-Resolve implementiert
3-Ebenen-System gegen Duplikate:
1. Pre-Dedup: LLM-Antwort wird vor DB-Insert dedupliziert (deduplicate_new_facts)
2. Auto-Resolve: Bestaetigte Fakten loesen automatisch stale developing/unconfirmed Fakten auf
3. Periodische Konsolidierung: Haiku clustert alle 6h semantische Duplikate und entfernt sie

Verbessertes Claim-Matching: SequenceMatcher (70%) + Jaccard-Keyword-Overlap (30%)
statt reinem SequenceMatcher. Threshold von 0.7 auf 0.75 erhoeht.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 21:59:50 +01:00
claude-dev
5e19736a25 Per-User Domain-Ausschlüsse + Grundquellen-Schutz
- Neue Tabelle user_excluded_domains für benutzerspezifische Ausschlüsse
- Domain-Ausschlüsse wirken nur für den jeweiligen User, nicht org-weit
- user_id wird durch die gesamte Pipeline geschleust (Orchestrator → Researcher → RSS-Parser)
- Grundquellen (is_global) können nicht mehr bearbeitet/gelöscht werden im Frontend
- Grundquelle-Badge bei globalen Quellen statt Edit/Delete-Buttons
- Filter Von mir ausgeschlossen im Quellen-Modal

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 14:30:21 +01:00
claude-dev
7734eefd35 Dynamische Keyword-Extraktion fuer RSS-Filterung + min_matches-Fix
- researcher.py: Neuer dedizierter Haiku-Call extract_dynamic_keywords()
  analysiert die letzten 30 Headlines und generiert 5 DE+EN Begriffspaare
- orchestrator.py: Dynamische Keywords vor Feed-Selektion aus DB-Headlines
- rss_parser.py: min_matches auf max 2 gedeckelt (vorher n/2, bei 10 Keywords = 5)
- analyzer.py: Fettdruck-Anweisungen entfernt

Vorher: 0 RSS-Treffer (min_matches=5 unerreichbar)
Nachher: 22 RSS-Treffer (Tagesschau 11, Al Jazeera 5, BBC 4, NYT 2)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 23:12:17 +01:00
claude-dev
5ae61a1379 Geoparsing von spaCy auf Haiku umgestellt
- geoparsing.py: Komplett-Rewrite (spaCy NER + Nominatim -> Haiku + geonamescache)
- orchestrator.py: incident_context an geoparse_articles, category in INSERT
- incidents.py: incident_context aus DB laden und an Geoparsing uebergeben
- public_api.py: Locations aggregiert im Lagebild-Endpoint
- components.js: response-Kategorie neben retaliation (beide akzeptiert)
- requirements.txt: spaCy und geopy entfernt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 22:00:40 +01:00
claude-dev
1c7adafa70 Fix: Progress-Timer zeigte negative Zahlen (-58:-10)
Ursache: Server sendete started_at als Lokalzeit (Europe/Berlin),
aber der Client interpretierte es als UTC via parseUTC().
Bei UTC+1 lag die Startzeit dadurch 1 Stunde in der Zukunft.

- orchestrator.py: started_at in WebSocket-Nachrichten als echtes UTC
  (ISO 8601 mit Z-Suffix) senden, DB-Timestamps bleiben Lokalzeit
- components.js: elapsed auf min. 0 clampen als Sicherheitsnetz

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 10:51:33 +01:00
claude-dev
f7809ccc77 Fix: TimeoutError wird nicht mehr verschluckt - Retry greift jetzt
- researcher.py/factchecker.py: TimeoutError wird nach oben durchgereicht
  statt vom breiten except Exception geschluckt zu werden
- orchestrator.py: Built-in TimeoutError zu TRANSIENT_ERRORS hinzugefuegt
  (war nur asyncio.TimeoutError, aber claude_client wirft TimeoutError)
- config.py: CLAUDE_TIMEOUT von 300s auf 420s erhoeht

Vorher: Timeout fuehrte zu "0 Artikel" ohne Retry (8 Timeouts seit 28.02.)
Nachher: Timeout loest bis zu 3 Retries aus (sofort, +2min, +5min)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 10:48:48 +01:00
claude-dev
a69352575d Fix: Komplett auf Europe/Berlin + DB-Migration + Timer-Fix
- ALLE Timestamps einheitlich Europe/Berlin (kein UTC mehr)
- DB-Migration: 1704 bestehende Timestamps von UTC nach Berlin konvertiert
- Auto-Refresh Timer Fix: ORDER BY id DESC statt completed_at DESC
  (verhindert falsche Sortierung bei gemischten Timestamp-Formaten)
- started_at statt completed_at fuer Timer-Vergleich (konsistenter)
- Manuelle Refreshes werden bei Intervall-Pruefung beruecksichtigt
- Debug-Logging fuer Auto-Refresh Entscheidungen
- astimezone() fuer Timestamps mit Offset-Info

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 02:56:51 +01:00
claude-dev
a8e9f34ff8 Fix: UTC fuer interne Timer, Berlin nur fuer Anzeige
Korrektur: Alle DB-Timestamps (refresh_log, created_at, updated_at,
auth, notifications) bleiben UTC fuer korrekte Timer-Vergleiche.
Europe/Berlin nur fuer angezeigte Werte (Exporte, Prompts, API).
Verhindert zu fruehes Ausloesen des Auto-Refresh-Timers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 02:40:02 +01:00
claude-dev
706d0b49d6 Fix: Alle Timestamps einheitlich auf Europe/Berlin Zeitzone
Inkonsistenz behoben: Manche Timestamps wurden in UTC, andere in
Berlin-Zeit gespeichert. Das fuehrte zu Fehlern beim Auto-Refresh
und Faktencheck, da Zeitvergleiche falsche Ergebnisse lieferten.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 02:37:30 +01:00
claude-dev
32f0281a96 Refactor: Email statt Username als Anzeige-Identifier
- Header zeigt volle Email statt Username
- Lagen-Karten/Sidebar zeigen Email-Prefix (vor dem @) als Ersteller
- Feedback-Emails nutzen Email-Prefix statt Username
- Login/Notification-Emails nutzen Email-Prefix als Anrede
- DB-Queries holen email statt username für Ersteller-Anzeige

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:55:24 +01:00
claude-dev
536e7f585b Feat: Claude-Keywords für RSS-Suche, Jahreszahlen-Filter, strikteres Matching
- rss_researcher liefert jetzt Keywords zurück, die direkt für RSS-Suche genutzt werden
- Neue _clean_search_words() filtert rein-numerische Begriffe (Jahreszahlen etc.)
- Matching-Schwelle aufgerundet: bei 3 Keywords müssen mindestens 2 matchen

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 18:36:08 +01:00
claude-dev
7672bbcad6 Domain-Balance vor Haiku entfernt — Feeds sollen alle verfügbar bleiben
Die Feed-Vorfilterung (max 3 pro Domain) vor der Haiku-Selektion war
falsch: Alle thematischen Feeds (z.B. Guardian World, Politics, Middle East)
sollen Haiku zur Auswahl stehen. Die Quellenvielfalt wird stattdessen
durch den Prompt (QUELLENVIELFALT-Regel) und den Artikel-Cap nach
dem RSS-Fetch (max 10 Artikel/Domain) sichergestellt.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:28:37 +01:00
claude-dev
ff4c54d9a8 Quellenvielfalt sicherstellen: Domain-Cap + Balance + Discovery-Verbesserungen
- config.py: MAX_FEEDS_PER_DOMAIN=3, MAX_ARTICLES_PER_DOMAIN_RSS=10
- rss_parser.py: _apply_domain_cap() begrenzt Artikel pro Domain nach RSS-Fetch
- orchestrator.py: Domain-Balance vor Feed-Selektion (max 3 Feeds/Domain),
  Domain-Cap in Background-Discovery
- source_rules.py: article_count in get_feeds_with_metadata(), Content-Hash
  in _validate_feed() für Duplikat-Erkennung bei Discovery
- researcher.py: QUELLENVIELFALT-Regel im Haiku Feed-Selektions-Prompt
- DB: 52 WordPress-Redirect-Duplikate deaktiviert (netzpolitik.org, bashinho.de)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 23:25:04 +01:00
claude-dev
4bfc626067 Kartenfeature: Geoparsing + Leaflet-Karte im Dashboard
- Neues Geoparsing-Modul (spaCy NER + geonamescache/Nominatim)
- article_locations-Tabelle mit Migration
- Pipeline-Integration nach Artikel-Speicherung
- API-Endpunkt GET /incidents/{id}/locations
- Leaflet.js + MarkerCluster im Dashboard-Grid
- Theme-aware Kartenkacheln (CartoDB dark / OSM light)
- Gold-Akzent MarkerCluster, Popup mit Artikelliste

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:04:07 +01:00
claude-dev
3d9a827bc8 Inkrementelle Analyse + Token-Optimierung + Relevanz-Scoring
TOKEN-OPTIMIERUNG:
- Inkrementelle Analyse: Folge-Refreshes senden nur noch das bisherige
  Lagebild + neue Artikel an Claude (statt alle Artikel erneut).
  Spart ~60-70% Tokens bei Lagen mit vielen Artikeln.
- Inkrementeller Faktencheck: Bestehende Fakten als Zusammenfassung,
  nur neue Artikel werden vollstaendig geprueft.
- Modell-Steuerung: Feed-Selektion nutzt jetzt Haiku (CLAUDE_MODEL_FAST)
  statt Opus. Spart ~50-70% bei Feed-Auswahl.
- Set-basierte DB-Deduplizierung: Bestehende URLs/Headlines einmal
  in Sets geladen statt N*M einzelne DB-Queries pro Artikel.

INHALTLICHE VERBESSERUNGEN:
- Relevanz-Scoring: Artikel nach Keyword-Dichte (40%),
  Quellen-Reputation (30%), Inhaltstiefe (20%), RSS-Score (10%).
- Flexibles RSS-Matching: min. Haelfte der Keywords statt alle.
  RSS-Artikel bekommen einen relevance_score.
- Fuzzy Claim-Matching: SequenceMatcher (0.7) statt exakter
  String-Vergleich. Verhindert Duplikat-Akkumulation.
- Translation-Fix: Nur gueltige DB-IDs (isinstance int).
- Researcher: WebFetch fuer Top-Artikel, erweiterte Zusammenfassungen.

DATEIEN:
- config.py: CLAUDE_MODEL_FAST
- claude_client.py: model-Parameter
- researcher.py: Haiku Feed-Selektion, erweiterte Prompts
- analyzer.py: Inkrementelle Analyse + analyze_incremental()
- factchecker.py: Inkrementeller Check + Fuzzy-Matching
- orchestrator.py: Set-Dedup, Relevanz-Scoring, inkrementeller Flow
- rss_parser.py: Flexibles Keyword-Matching + relevance_score
2026-03-04 20:22:47 +01:00
claude-dev
71296edb97 Großes Cleanup: Bugs fixen, Features fertigstellen, toten Code entfernen
Bugs behoben:
- handleEdit() async keyword hinzugefügt (E-Mail-Checkboxen funktionieren jetzt)
- parseUTC() Funktion definiert (Fortschritts-Timer nutzt Server-Startzeit)
- Status cancelling wird im Frontend korrekt angezeigt

Features fertiggestellt:
- Sidebar: Lagen nach Typ getrennt (adhoc/research) mit Zählern
- Quellen-Bearbeiten: Edit-Button pro Quelle, Formular vorausfüllen
- Lizenz-Info: Org-Name und Lizenzstatus im Header angezeigt

Toter Code entfernt:
- 5 verwaiste Dateien gelöscht (alte rss_parser, style.css, components.js, layout.js, setup_users)
- 6 ungenutzte Pydantic Models entfernt
- Ungenutzte Funktionen/Imports in auth.py, routers, agents, config
- Tote API-Methoden, Legacy-UI-Methoden, verwaiste WS-Handler
- Abgeschlossene DB-Migrationen aufgeräumt

Sonstiges:
- requirements.txt: passlib[bcrypt] durch bcrypt ersetzt
- Umlaute korrigiert (index.html)
- CSS: incident-type-label → incident-type-badge, .login-success hinzugefügt
- Schließen statt Schliessen im Feedback-Modal
2026-03-04 18:45:38 +01:00
claude-dev
8312d24912 Initial commit: AegisSight-Monitor (OSINT-Monitoringsystem) 2026-03-04 17:53:18 +01:00