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
Dieser Commit ist enthalten in:
claude-dev
2026-03-04 20:22:47 +01:00
Ursprung 54d02d2c5b
Commit 3d9a827bc8
7 geänderte Dateien mit 541 neuen und 317 gelöschten Zeilen

Datei anzeigen

@@ -121,8 +121,11 @@ class RSSParser:
summary = entry.get("summary", "")
text = f"{title} {summary}".lower()
# Prüfe ob mindestens ein Suchwort vorkommt
if all(word in text for word in search_words):
# Flexibles Keyword-Matching: mindestens die Hälfte der Suchworte muss vorkommen
min_matches = max(1, len(search_words) // 2)
match_count = sum(1 for word in search_words if word in text)
if match_count >= min_matches:
published = None
if hasattr(entry, "published_parsed") and entry.published_parsed:
try:
@@ -130,6 +133,9 @@ class RSSParser:
except (TypeError, ValueError):
pass
# Relevanz-Score: Anteil der gematchten Suchworte (0.0-1.0)
relevance_score = match_count / len(search_words) if search_words else 0.0
articles.append({
"headline": title,
"headline_de": title if self._is_german(title) else None,
@@ -139,6 +145,7 @@ class RSSParser:
"content_de": summary[:1000] if summary and self._is_german(summary) else None,
"language": "de" if self._is_german(title) else "en",
"published_at": published,
"relevance_score": relevance_score,
})
except Exception as e: