feat(public-mood): Stimmungs-Kachel aus Foren-Quellen

Eigene Pipeline-Stufe nach factcheck, vor summary, die Foren-Artikel
(media_type='forum') zu einer Themen-Zusammenfassung verarbeitet. Wird als
separate Dashboard-Kachel "Öffentliche Stimmung" angezeigt — getrennt von
Lagebild und Faktencheck, damit anonyme Forenposts nicht mit belegter
Faktenlage verwechselt werden.

- DB-Migration: incidents.public_mood (TEXT) + public_mood_updated_at (TS).
- pipeline_tracker: neuer Pipeline-Step "public_mood" (DE/EN-Labels).
- analyzer.generate_public_mood: Haiku-Call der Foren-Beitraege pro Quelle
  gruppiert und 3-6 thematische Bullets erzeugt, mit expliziter Quellen-
  Herkunft pro Bullet. Bei zu duennem Material gibt's keinen Output.
- orchestrator: neuer Schritt zwischen Factcheck und Summary. Laedt alle
  Foren-Artikel der Lage (via JOIN auf sources), uebergibt sie an den
  Stimmungs-Agent, speichert den Markdown-Text in incidents.public_mood.
- Topic-Filter (analyzer.filter_relevant_articles) markiert Foren-Quellen
  mit [FORUM]-Tag und bekommt im Prompt die Regel, Foren-Artikel weicher
  zu bewerten (Lage-Keyword im Titel reicht). Sie sollen in der Stimmungs-
  Kachel landen, nicht voreilig verworfen werden.
- IncidentResponse-Modell: public_mood/public_mood_updated_at ergaenzt.
- Frontend: neuer Tab "Öffentliche Stimmung" (nur sichtbar wenn Inhalt da),
  eigene Kachel mit Warn-Hinweis "keine Faktenlage". UI.renderPublicMood
  als einfacher Bullet-Renderer.
- dashboard.html Cache-Buster fuer components.js + app.js gebumpt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
2026-05-22 00:20:17 +02:00
Ursprung 379d14518c
Commit d65f0180d9
8 geänderte Dateien mit 243 neuen und 3 gelöschten Zeilen

Datei anzeigen

@@ -813,6 +813,26 @@ const UI = {
return html;
},
/**
* Rendert die "Öffentliche Stimmung"-Kachel.
* Eingabe ist Markdown mit "- "-Bullets (vom AnalyzerAgent.generate_public_mood).
* Quellen-Pills brauchen wir hier nicht — die Bullet-Texte nennen die Foren-Herkunft
* explizit ("auf 5ch /seiji/ ...", "Hatena-Kommentare betonen ...").
*/
renderPublicMood(text) {
if (!text) return '<span style="color:var(--text-disabled);">Noch kein Stimmungsbild erfasst.</span>';
const bulletLines = text.split("\n").map(l => l.trim()).filter(l => l.startsWith("- "));
if (bulletLines.length === 0) {
// Fliesstext-Fallback: HTML-escapen + Zeilenumbrueche
return this.escape(text).replace(/\n/g, '<br>');
}
const items = bulletLines.map(l => {
const body = l.replace(/^-\s+/, '');
return `<li>${this.escape(body)}</li>`;
}).join('');
return `<ul style="margin:4px 0 4px 18px;line-height:1.7;">${items}</ul>`;
},
/**
* Rendert "Neueste Entwicklungen" für Live-Monitoring (adhoc).
* Erwartet Bullets im Format "- [DD.MM. HH:MM] Text {Quelle1, Quelle2}".