feat(pipeline): Translator als Pipeline-Step + Watchdog-Limits erhoehen
Folgefix zu 952df87. Der Translator-Block laeuft post-summary bei jp_demo
40+ Min und war bisher fuer das Frontend unsichtbar und fuer den Watchdog
ein blinder Fleck (kein Pipeline-Step-Eintrag).
Aenderungen:
- pipeline_tracker.py: neuer Step 'translate' zwischen 'summary' und 'qc'
(DE+EN Label/Tooltip). Bewusst conditional sichtbar: erscheint nur, wenn
fremdsprachige Artikel ohne DE-Uebersetzung vorliegen UND
translator_enabled fuer die Org an ist.
- orchestrator.py: Translator-Block umrandet mit _pipe_start('translate')
und _pipe_done('translate', count_value=uebersetzt, count_secondary=
pending). Translator-Fehler schliesst Step trotzdem sauber ab.
Bedingung 'pending_translations and translator_enabled' ersetzt das
alte 'pending_translations' - skipped den Block sauber wenn Org-Override
deaktiviert (war vorher redundant in translate_articles selbst).
- main.py: ORPHAN_IDLE_LIMIT 30->60 Min, ORPHAN_HARD_LIMIT 90->120 Min.
Deckt jp_demo Translator-Phase (beobachtet bis 41 Min) mit Puffer ab,
ohne echte Haenger durchzulassen.
Resultierend: Frontend zeigt den Uebersetzungs-Schritt mit Fortschritt
(uebersetzt/gesamt). Watchdog killt nicht mehr vorzeitig.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -1753,6 +1753,7 @@ class AgentOrchestrator:
|
|||||||
# Idempotent: nur Artikel ohne headline_de/content_de werden geholt.
|
# Idempotent: nur Artikel ohne headline_de/content_de werden geholt.
|
||||||
# Lauft nach der Analyse (Lagebild ist schon committed) und vor QC
|
# Lauft nach der Analyse (Lagebild ist schon committed) und vor QC
|
||||||
# (damit normalize_umlaut_articles auch die frischen DE-Texte fasst).
|
# (damit normalize_umlaut_articles auch die frischen DE-Texte fasst).
|
||||||
|
_translate_step_started = False
|
||||||
try:
|
try:
|
||||||
tr_cursor = await db.execute(
|
tr_cursor = await db.execute(
|
||||||
"""SELECT id, headline, content_original, language
|
"""SELECT id, headline, content_original, language
|
||||||
@@ -1764,7 +1765,10 @@ class AgentOrchestrator:
|
|||||||
(incident_id,),
|
(incident_id,),
|
||||||
)
|
)
|
||||||
pending_translations = [dict(r) for r in await tr_cursor.fetchall()]
|
pending_translations = [dict(r) for r in await tr_cursor.fetchall()]
|
||||||
if pending_translations:
|
if pending_translations and translator_enabled:
|
||||||
|
# Pipeline-Schritt 9: Artikel uebersetzen (nur sichtbar wenn was zu uebersetzen)
|
||||||
|
await _pipe_start("translate")
|
||||||
|
_translate_step_started = True
|
||||||
logger.info(
|
logger.info(
|
||||||
"Translator fuer Incident %d: %d Artikel ohne DE-Uebersetzung",
|
"Translator fuer Incident %d: %d Artikel ohne DE-Uebersetzung",
|
||||||
incident_id, len(pending_translations),
|
incident_id, len(pending_translations),
|
||||||
@@ -1795,8 +1799,11 @@ class AgentOrchestrator:
|
|||||||
"Translator fuer Incident %d: %d/%d Artikel uebersetzt",
|
"Translator fuer Incident %d: %d/%d Artikel uebersetzt",
|
||||||
incident_id, len(translations), len(pending_translations),
|
incident_id, len(translations), len(pending_translations),
|
||||||
)
|
)
|
||||||
|
await _pipe_done("translate", count_value=len(translations), count_secondary=len(pending_translations))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("Translator-Fehler fuer Incident %d: %s", incident_id, e, exc_info=True)
|
logger.error("Translator-Fehler fuer Incident %d: %s", incident_id, e, exc_info=True)
|
||||||
|
if _translate_step_started:
|
||||||
|
await _pipe_done("translate", count_value=0, count_secondary=0)
|
||||||
# Refresh trotz Translator-Fehler weiterlaufen lassen
|
# Refresh trotz Translator-Fehler weiterlaufen lassen
|
||||||
|
|
||||||
# --- Neueste Entwicklungen (nur Live-Monitoring / adhoc) ---
|
# --- Neueste Entwicklungen (nur Live-Monitoring / adhoc) ---
|
||||||
|
|||||||
@@ -252,8 +252,8 @@ async def cleanup_expired():
|
|||||||
# vorzeitig gekillt werden. Ein Refresh gilt als verwaist, wenn entweder
|
# vorzeitig gekillt werden. Ein Refresh gilt als verwaist, wenn entweder
|
||||||
# (a) seit ORPHAN_IDLE_LIMIT Min kein Pipeline-Step Fortschritt zeigte,
|
# (a) seit ORPHAN_IDLE_LIMIT Min kein Pipeline-Step Fortschritt zeigte,
|
||||||
# oder (b) das harte Limit ORPHAN_HARD_LIMIT Min ueberschritten wurde.
|
# oder (b) das harte Limit ORPHAN_HARD_LIMIT Min ueberschritten wurde.
|
||||||
ORPHAN_IDLE_LIMIT = 30
|
ORPHAN_IDLE_LIMIT = 60
|
||||||
ORPHAN_HARD_LIMIT = 90
|
ORPHAN_HARD_LIMIT = 120
|
||||||
cursor = await db.execute(
|
cursor = await db.execute(
|
||||||
"SELECT id, incident_id, started_at FROM refresh_log WHERE status = 'running'"
|
"SELECT id, incident_id, started_at FROM refresh_log WHERE status = 'running'"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ _PIPELINE_STEPS_DE = [
|
|||||||
"tooltip": "Aus Foren-Quellen (z.B. 5ch, Hatena, Note) wird ein Stimmungsbild der öffentlichen Diskussion extrahiert. Keine Faktenlage, sondern dominante Themen und Bruchlinien."},
|
"tooltip": "Aus Foren-Quellen (z.B. 5ch, Hatena, Note) wird ein Stimmungsbild der öffentlichen Diskussion extrahiert. Keine Faktenlage, sondern dominante Themen und Bruchlinien."},
|
||||||
{"key": "summary", "label": "Lagebild verfassen", "icon": "file-text",
|
{"key": "summary", "label": "Lagebild verfassen", "icon": "file-text",
|
||||||
"tooltip": "Aus allen geprüften Meldungen wird ein zusammenhängendes Lagebild geschrieben, mit Quellenangaben am Text."},
|
"tooltip": "Aus allen geprüften Meldungen wird ein zusammenhängendes Lagebild geschrieben, mit Quellenangaben am Text."},
|
||||||
|
{"key": "translate", "label": "Artikel uebersetzen", "icon": "languages",
|
||||||
|
"tooltip": "Fremdsprachige Meldungen (z.B. japanisch) werden ins Lagebild-Output uebersetzt. Laeuft nur fuer Quellen-Pools mit nicht-deutschen Sprachen und kann bei vielen neuen Artikeln einige Minuten dauern."},
|
||||||
{"key": "qc", "label": "Qualitätscheck", "icon": "check-circle",
|
{"key": "qc", "label": "Qualitätscheck", "icon": "check-circle",
|
||||||
"tooltip": "Eine letzte Kontrollprüfung am Ergebnis: Doppelte Fakten zusammenführen, Karten-Verortung prüfen, bevor du benachrichtigt wirst."},
|
"tooltip": "Eine letzte Kontrollprüfung am Ergebnis: Doppelte Fakten zusammenführen, Karten-Verortung prüfen, bevor du benachrichtigt wirst."},
|
||||||
{"key": "notify", "label": "Benachrichtigen", "icon": "bell",
|
{"key": "notify", "label": "Benachrichtigen", "icon": "bell",
|
||||||
@@ -59,6 +61,8 @@ _PIPELINE_STEPS_EN = [
|
|||||||
"tooltip": "Forum sources (5ch, Hatena, Note, etc.) are summarised into a public-mood overview. Not factual, but dominant themes and fault lines."},
|
"tooltip": "Forum sources (5ch, Hatena, Note, etc.) are summarised into a public-mood overview. Not factual, but dominant themes and fault lines."},
|
||||||
{"key": "summary", "label": "Writing the briefing", "icon": "file-text",
|
{"key": "summary", "label": "Writing the briefing", "icon": "file-text",
|
||||||
"tooltip": "All verified articles are combined into a coherent briefing with inline citations."},
|
"tooltip": "All verified articles are combined into a coherent briefing with inline citations."},
|
||||||
|
{"key": "translate", "label": "Translating articles", "icon": "languages",
|
||||||
|
"tooltip": "Foreign-language articles (e.g. Japanese) are translated into the briefing output language. Runs only when the source pool contains non-target-language items and can take several minutes for large incoming batches."},
|
||||||
{"key": "qc", "label": "Quality check", "icon": "check-circle",
|
{"key": "qc", "label": "Quality check", "icon": "check-circle",
|
||||||
"tooltip": "A final review: consolidate duplicate facts, verify map locations, before you get notified."},
|
"tooltip": "A final review: consolidate duplicate facts, verify map locations, before you get notified."},
|
||||||
{"key": "notify", "label": "Notifying", "icon": "bell",
|
{"key": "notify", "label": "Notifying", "icon": "bell",
|
||||||
|
|||||||
In neuem Issue referenzieren
Einen Benutzer sperren