Live-Monitoring: Quellen-IDs deterministisch aufloesen, Bias-Markierung raus

Aenderung am Grund-Mechanismus: LLM liefert pro Bullet die Meldungs-IDs
im Format {M<ID>, M<ID>}, das Backend loest die IDs gegen new_articles
zu Quellen-Namen auf und schreibt {Reuters, Rybar} in die DB. Uebernommene
Bullets aus previous_developments behalten ihre bestehende {Name}-Klammer.

Bullets ohne Quellen-Klammer oder mit unaufloesbarer Klammer werden vom
Parser verworfen — dadurch existiert "Keine Quelle" nicht mehr.

Frontend: Bias-Farbcodierung (pro-RU, staatsnah) + zugehoerige Heuristik
_classifyBias/_biasLabel entfernt. Kein Sonderfall-Rendering fuer leere
Pills mehr.
Dieser Commit ist enthalten in:
claude-dev
2026-04-18 20:50:46 +00:00
Ursprung 5c95d85871
Commit 89ab158202
3 geänderte Dateien mit 64 neuen und 60 gelöschten Zeilen

Datei anzeigen

@@ -788,12 +788,10 @@ const UI = {
const buildPill = (src, fallbackName) => {
const displayName = src ? (src.name || fallbackName) : fallbackName;
const esc = this.escape(displayName);
const biasClass = this._classifyBias(displayName);
const biasHtml = biasClass ? `<span class="dev-bias dev-bias-${biasClass}">${this._biasLabel(biasClass)}</span>` : '';
if (src && src.url) {
return `<a href="${this.escape(src.url)}" target="_blank" rel="noopener" class="dev-source-pill" title="${esc}">${esc}${biasHtml}</a>`;
return `<a href="${this.escape(src.url)}" target="_blank" rel="noopener" class="dev-source-pill" title="${esc}">${esc}</a>`;
}
return `<span class="dev-source-pill" title="${esc}">${esc}${biasHtml}</span>`;
return `<span class="dev-source-pill" title="${esc}">${esc}</span>`;
};
const cards = bulletLines.map(line => {
@@ -842,9 +840,7 @@ const UI = {
}
const cleanBody = this.escape(rawBody.trim());
const sourcesHtml = pillsHtml
? `<span class="dev-sources">${pillsHtml}</span>`
: `<span class="dev-sources dev-sources-empty">Keine Quelle</span>`;
const sourcesHtml = pillsHtml ? `<span class="dev-sources">${pillsHtml}</span>` : '<span class="dev-sources"></span>';
const timeHtml = `<span class="dev-time" title="${this.escape(date + ' ' + time)}">${this.escape(time)} \u00b7 ${this.escape(date)}</span>`;
return `<div class="dev-bullet"><div class="dev-bullet-head">${sourcesHtml}${timeHtml}</div><div class="dev-body">${cleanBody}</div></div>`;
@@ -853,21 +849,6 @@ const UI = {
return `<div class="dev-list">${cards.join('')}</div>`;
},
_classifyBias(name) {
if (!name) return null;
const n = name.toLowerCase();
const proRu = ['rybar', 'sputnik', 'tass', 'ria novosti', 'ria.ru', 'tsargrad', 'readovka', 'pravda', 'russia today', 'rt.com', 'rt deutsch'];
const staatsnah = ['cctv', 'global times', 'xinhua', "people's daily", 'press tv', 'irna', 'kcna'];
if (proRu.some(k => n.includes(k))) return 'pro-ru';
if (staatsnah.some(k => n.includes(k))) return 'staatsnah';
return null;
},
_biasLabel(cls) {
if (cls === 'pro-ru') return 'pro-RU';
if (cls === 'staatsnah') return 'staatsnah';
return cls;
},
renderSummary(summary, sourcesJson, incidentType) {
if (!summary) return '<span style="color:var(--text-tertiary);">Noch keine Zusammenfassung.</span>';