fix: Quellenlinks mit Buchstaben-Suffix ([389a] etc.) korrekt verlinken
Probleme: - Frontend-Regex matchte nur reine Zahlen, nicht [389a]-Style Refs - 17 alphanumerische Quellen im Irankonflikt blieben unverlinkt - Orchestrator-Validierung erkannte diese Refs nicht als fehlend Fixes: - Frontend: Regex erweitert auf [\d+a-z?], Vergleich mit String und Number - Orchestrator: Validierung erkennt jetzt auch alphanumerische Refs - Analyzer-Prompts: Explizite Anweisung, nur ganze Zahlen als Nr zu verwenden - 822a und 859a in Irankonflikt sources_json nachgetragen - Cache-Buster aktualisiert Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -38,7 +38,7 @@ REGELN:
|
|||||||
- Wenn eine Quelle eine erkennbare Ausrichtung hat (z.B. pro-russisch, pro-iranisch, staatsnah, rechtsextrem), muss dies im Fliesstext erwaehnt werden, damit der Leser die Information einordnen kann. Beispiel: "Laut dem pro-russischen Telegram-Kanal Rybar..." oder "Die iranische Nachrichtenagentur Fars meldete..." oder "Der rechtsextreme Kanal Compact behauptete..."
|
- Wenn eine Quelle eine erkennbare Ausrichtung hat (z.B. pro-russisch, pro-iranisch, staatsnah, rechtsextrem), muss dies im Fliesstext erwaehnt werden, damit der Leser die Information einordnen kann. Beispiel: "Laut dem pro-russischen Telegram-Kanal Rybar..." oder "Die iranische Nachrichtenagentur Fars meldete..." oder "Der rechtsextreme Kanal Compact behauptete..."
|
||||||
- Quellen immer mit [Nr] referenzieren
|
- Quellen immer mit [Nr] referenzieren
|
||||||
- Jede verwendete Quelle MUSS im sources-Array aufgelistet sein
|
- Jede verwendete Quelle MUSS im sources-Array aufgelistet sein
|
||||||
- Nummeriere die Quellen fortlaufend ab [1]
|
- Nummeriere die Quellen fortlaufend ab [1]. Verwende NUR ganze Zahlen als Quellennummern (z.B. [389], [390]), KEINE Buchstaben-Suffixe wie [389a]
|
||||||
- Ältere Quellen zeitlich einordnen (z.B. "laut einem Bericht vom Januar", "Anfang Februar berichtete...")
|
- Ältere Quellen zeitlich einordnen (z.B. "laut einem Bericht vom Januar", "Anfang Februar berichtete...")
|
||||||
|
|
||||||
Antworte AUSSCHLIESSLICH als JSON-Objekt mit diesen Feldern:
|
Antworte AUSSCHLIESSLICH als JSON-Objekt mit diesen Feldern:
|
||||||
@@ -91,7 +91,7 @@ REGELN:
|
|||||||
- Wenn eine Quelle eine erkennbare Ausrichtung hat (z.B. pro-russisch, pro-iranisch, staatsnah, rechtsextrem), muss dies im Fliesstext erwaehnt werden, damit der Leser die Information einordnen kann. Beispiel: "Laut dem pro-russischen Telegram-Kanal Rybar..." oder "Die iranische Nachrichtenagentur Fars meldete..." oder "Der rechtsextreme Kanal Compact behauptete..."
|
- Wenn eine Quelle eine erkennbare Ausrichtung hat (z.B. pro-russisch, pro-iranisch, staatsnah, rechtsextrem), muss dies im Fliesstext erwaehnt werden, damit der Leser die Information einordnen kann. Beispiel: "Laut dem pro-russischen Telegram-Kanal Rybar..." oder "Die iranische Nachrichtenagentur Fars meldete..." oder "Der rechtsextreme Kanal Compact behauptete..."
|
||||||
- Quellen immer mit [Nr] referenzieren
|
- Quellen immer mit [Nr] referenzieren
|
||||||
- Jede verwendete Quelle MUSS im sources-Array aufgelistet sein
|
- Jede verwendete Quelle MUSS im sources-Array aufgelistet sein
|
||||||
- Nummeriere die Quellen fortlaufend ab [1]
|
- Nummeriere die Quellen fortlaufend ab [1]. Verwende NUR ganze Zahlen als Quellennummern (z.B. [389], [390]), KEINE Buchstaben-Suffixe wie [389a]
|
||||||
- Ältere Quellen zeitlich einordnen (z.B. "laut einem Bericht vom Januar", "Anfang Februar berichtete...")
|
- Ältere Quellen zeitlich einordnen (z.B. "laut einem Bericht vom Januar", "Anfang Februar berichtete...")
|
||||||
- Markdown-Überschriften (##) für die Abschnitte verwenden
|
- Markdown-Überschriften (##) für die Abschnitte verwenden
|
||||||
- KEIN Fettdruck (**) verwenden
|
- KEIN Fettdruck (**) verwenden
|
||||||
@@ -142,7 +142,7 @@ REGELN:
|
|||||||
|
|
||||||
Antworte AUSSCHLIESSLICH als JSON-Objekt mit diesen Feldern:
|
Antworte AUSSCHLIESSLICH als JSON-Objekt mit diesen Feldern:
|
||||||
- "summary": Aktualisierte Zusammenfassung mit Quellenverweisen [1], [2] etc.
|
- "summary": Aktualisierte Zusammenfassung mit Quellenverweisen [1], [2] etc.
|
||||||
- "sources": Array mit NUR den NEUEN Quellen aus den neuen Meldungen, je: {{"nr": <fortlaufend>, "name": "Quellenname", "url": "https://..."}}. Alte Quellen werden automatisch gemerged.
|
- "sources": Array mit NUR den NEUEN Quellen aus den neuen Meldungen, je: {{"nr": <fortlaufende ganze Zahl, KEINE Buchstaben-Suffixe>, "name": "Quellenname", "url": "https://..."}}. Alte Quellen werden automatisch gemerged.
|
||||||
- "key_facts": Array aller aktuellen Kernfakten (in Ausgabesprache)
|
- "key_facts": Array aller aktuellen Kernfakten (in Ausgabesprache)
|
||||||
- "translations": Array von Objekten mit "article_id", "headline_de", "content_de" (nur für neue fremdsprachige Artikel)
|
- "translations": Array von Objekten mit "article_id", "headline_de", "content_de" (nur für neue fremdsprachige Artikel)
|
||||||
|
|
||||||
@@ -187,7 +187,7 @@ REGELN:
|
|||||||
|
|
||||||
Antworte AUSSCHLIESSLICH als JSON-Objekt mit diesen Feldern:
|
Antworte AUSSCHLIESSLICH als JSON-Objekt mit diesen Feldern:
|
||||||
- "summary": Das aktualisierte Briefing als Markdown-Text mit Quellenverweisen
|
- "summary": Das aktualisierte Briefing als Markdown-Text mit Quellenverweisen
|
||||||
- "sources": Array mit NUR den NEUEN Quellen aus den neuen Meldungen, je: {{"nr": <fortlaufend>, "name": "Quellenname", "url": "https://..."}}. Alte Quellen werden automatisch gemerged.
|
- "sources": Array mit NUR den NEUEN Quellen aus den neuen Meldungen, je: {{"nr": <fortlaufende ganze Zahl, KEINE Buchstaben-Suffixe>, "name": "Quellenname", "url": "https://..."}}. Alte Quellen werden automatisch gemerged.
|
||||||
- "key_facts": Array aller gesicherten Kernfakten (in Ausgabesprache)
|
- "key_facts": Array aller gesicherten Kernfakten (in Ausgabesprache)
|
||||||
- "translations": Array von Objekten mit "article_id", "headline_de", "content_de" (nur für neue fremdsprachige Artikel)
|
- "translations": Array von Objekten mit "article_id", "headline_de", "content_de" (nur für neue fremdsprachige Artikel)
|
||||||
|
|
||||||
|
|||||||
@@ -980,13 +980,24 @@ class AgentOrchestrator:
|
|||||||
# Validierung: Fehlende Quellennummern im Summary erkennen und reparieren
|
# Validierung: Fehlende Quellennummern im Summary erkennen und reparieren
|
||||||
if sources and new_summary:
|
if sources and new_summary:
|
||||||
import re as _re
|
import re as _re
|
||||||
referenced_nrs = set(int(m) for m in _re.findall(r'\[(\d+)\]', new_summary))
|
# Auch alphanumerische Refs wie [389a] erkennen
|
||||||
|
referenced_raw = set(_re.findall(r'\[(\d+[a-z]?)\]', new_summary))
|
||||||
|
referenced_nrs = set()
|
||||||
|
for r in referenced_raw:
|
||||||
|
try:
|
||||||
|
referenced_nrs.add(int(r))
|
||||||
|
except ValueError:
|
||||||
|
referenced_nrs.add(r) # Keep alphanumeric as string
|
||||||
defined_nrs = set()
|
defined_nrs = set()
|
||||||
for s in sources:
|
for s in sources:
|
||||||
try:
|
nr = s.get("nr", 0)
|
||||||
defined_nrs.add(int(s.get("nr", 0)))
|
if isinstance(nr, int):
|
||||||
except (ValueError, TypeError):
|
defined_nrs.add(nr)
|
||||||
pass
|
elif isinstance(nr, str):
|
||||||
|
try:
|
||||||
|
defined_nrs.add(int(nr))
|
||||||
|
except ValueError:
|
||||||
|
defined_nrs.add(nr) # Keep alphanumeric like '389a'
|
||||||
missing_nrs = sorted(referenced_nrs - defined_nrs)
|
missing_nrs = sorted(referenced_nrs - defined_nrs)
|
||||||
if missing_nrs:
|
if missing_nrs:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
|
|||||||
@@ -751,7 +751,7 @@
|
|||||||
<script src="/static/vendor/leaflet.markercluster.js"></script>
|
<script src="/static/vendor/leaflet.markercluster.js"></script>
|
||||||
<script src="/static/js/api.js?v=20260316b"></script>
|
<script src="/static/js/api.js?v=20260316b"></script>
|
||||||
<script src="/static/js/ws.js?v=20260316b"></script>
|
<script src="/static/js/ws.js?v=20260316b"></script>
|
||||||
<script src="/static/js/components.js?v=20260316c"></script>
|
<script src="/static/js/components.js?v=20260316d"></script>
|
||||||
<script src="/static/js/layout.js?v=20260316b"></script>
|
<script src="/static/js/layout.js?v=20260316b"></script>
|
||||||
<script src="/static/js/app.js?v=20260316b"></script>
|
<script src="/static/js/app.js?v=20260316b"></script>
|
||||||
<script src="/static/js/api_network.js?v=20260316a"></script>
|
<script src="/static/js/api_network.js?v=20260316a"></script>
|
||||||
|
|||||||
@@ -446,8 +446,8 @@ const UI = {
|
|||||||
|
|
||||||
// Inline-Zitate [1], [2] etc. als klickbare Links rendern
|
// Inline-Zitate [1], [2] etc. als klickbare Links rendern
|
||||||
if (sources.length > 0) {
|
if (sources.length > 0) {
|
||||||
html = html.replace(/\[(\d+)\]/g, (match, num) => {
|
html = html.replace(/\[(\d+[a-z]?)\]/g, (match, num) => {
|
||||||
const src = sources.find(s => Number(s.nr) === Number(num));
|
const src = sources.find(s => String(s.nr) === num || Number(s.nr) === Number(num));
|
||||||
if (src && src.url) {
|
if (src && src.url) {
|
||||||
return `<a href="${this.escape(src.url)}" target="_blank" rel="noopener" class="citation" title="${this.escape(src.name)}">[${num}]</a>`;
|
return `<a href="${this.escape(src.url)}" target="_blank" rel="noopener" class="citation" title="${this.escape(src.name)}">[${num}]</a>`;
|
||||||
}
|
}
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren