feat(sources): externer Reputations-Layer (IFCN + EUvsDisinfo)
Externe Datenquellen (kostenlos, Open Data) ergaenzen die LLM-geschaetzte Reliability-Achse mit objektiven Signalen: - IFCN-Signatories (raw.githubusercontent.com/IFCN/verified-signatories): Plain-Text-Liste anerkannter Faktencheck-Organisationen. - EUvsDisinfo (Zenodo CSV): Pro-Kreml-Desinformations-Datenbank. Schema-Erweiterung: - ifcn_signatory, eu_disinfo_listed, eu_disinfo_case_count, eu_disinfo_last_seen, external_data_synced_at. Service src/services/external_reputation.py: - sync_ifcn_signatories(), sync_eu_disinfo(), apply_reputation_overrides(), sync_all() mit Domain-Normalisierung (lowercase, ohne www., ohne Schema). Reliability-Override-Regeln (laufen nach Approve und manuellem Sync): - ifcn_signatory=1 -> reliability=sehr_hoch - eu_disinfo_case_count >= 5 -> reliability=sehr_niedrig - eu_disinfo_case_count >= 1 -> Reliability eine Stufe runter (max niedrig) API: POST /api/sources/external-reputation/sync (Admin, BackgroundTask). Filter: ?ifcn_signatory=true, ?eu_disinfo_listed=true. UI: - Filter-Dropdown "Externe Reputation" im Quellen-Modal. - Badges: gruenes "IFCN" und rotes "EU-Desinfo (n)". - Tooltip macht Reliability-Quelle transparent: "(IFCN-Faktenchecker)", "(EU-Desinfo, n Faelle)" oder "(LLM-Schaetzung)". - "Externe Daten syncen"-Button im Review-Toolbar (Admin-only). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -2834,6 +2834,16 @@ async handleRefresh() {
|
||||
}
|
||||
},
|
||||
|
||||
async triggerExternalReputationSync() {
|
||||
if (!confirm('IFCN- und EUvsDisinfo-Datenbanken jetzt syncen? Lauft im Hintergrund (~30 Sek).')) return;
|
||||
try {
|
||||
await API.triggerExternalReputationSync();
|
||||
UI.showToast('Externer Sync gestartet. Quellenliste in 30 Sek neu laden.', 'info');
|
||||
} catch (err) {
|
||||
UI.showToast('Sync fehlgeschlagen: ' + err.message, 'error');
|
||||
}
|
||||
},
|
||||
|
||||
renderSourceStats(stats) {
|
||||
const bar = document.getElementById('sources-stats-bar');
|
||||
if (!bar) return;
|
||||
@@ -2866,6 +2876,7 @@ async handleRefresh() {
|
||||
const mediaTypeFilter = document.getElementById('sources-filter-mediatype')?.value || '';
|
||||
const reliabilityFilter = document.getElementById('sources-filter-reliability')?.value || '';
|
||||
const alignmentFilter = document.getElementById('sources-filter-alignment')?.value || '';
|
||||
const externFilter = document.getElementById('sources-filter-extern')?.value || '';
|
||||
const search = (document.getElementById('sources-search')?.value || '').toLowerCase();
|
||||
|
||||
// Alle Quellen nach Domain gruppieren
|
||||
@@ -2929,6 +2940,11 @@ async handleRefresh() {
|
||||
if (alignmentFilter) {
|
||||
if (!feeds.some(f => Array.isArray(f.alignments) && f.alignments.includes(alignmentFilter))) continue;
|
||||
}
|
||||
if (externFilter === 'ifcn') {
|
||||
if (!feeds.some(f => f.ifcn_signatory)) continue;
|
||||
} else if (externFilter === 'eu_disinfo') {
|
||||
if (!feeds.some(f => f.eu_disinfo_listed)) continue;
|
||||
}
|
||||
|
||||
// Suche
|
||||
if (search) {
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren