#!/usr/bin/env python3 """META2.0 Monitor — überwacht alle 15 Agenten, zeigt Fortschritt, erkennt Stalls.""" import os import re import subprocess import sys import time from pathlib import Path from datetime import datetime BASE = Path(__file__).parent TOTAL_SOURCES = 97 # Transkripte STALL_MINUTES = 5 # Agent gilt als gestalled wenn kein neuer Eintrag seit X min FRAGEN = { "frage_01_kontrolle": "Ownership wenn Agenten autonomer", "frage_02_struktur": "Chaos → handhabbare Schritte", "frage_03_identitaet": "Wer ist Samuel in agentischer Welt", "frage_04_thalamus": "Digitaler Thalamus / Pyramide", "frage_05_qualitaet": "Metriken: gut mit Agenten?", "frage_06_energie": "Wann wirklich lebendig?", "frage_07_ueberforderung": "Nicht Fähigkeit — zu viel gleichzeitig", "frage_08_ownership": "Stark fühlen: wirklich meins", "frage_09_flucht": "Wiederholte Reset-Bewegungen", "frage_10_menschen": "Menschen: größer vs. kleiner", "frage_11_zustand": "Entscheidungen in schlechten Zuständen", "frage_12_talent": "Natürliches Talent (unsichtbar)", "frage_13_schmerz": "Schmerz → Produktideen", "frage_14_wiederholung": "Wiederkehrende Lebensszene", "frage_15_zukunft": "Welche Version will entstehen?", } def count_processed(log_path: Path) -> int: """Zählt verarbeitete Quellen aus session_log.md.""" if not log_path.exists(): return 0 count = 0 with open(log_path, encoding="utf-8", errors="ignore") as f: for line in f: if line.startswith("**") and ("`[transkript]`" in line or "`[session]`" in line): count += 1 return count def last_modified(path: Path) -> float: """Sekunden seit letzter Änderung.""" if not path.exists(): return 9999 return time.time() - path.stat().st_mtime def is_done(dir_path: Path) -> bool: return (dir_path / "ANTWORT.md").exists() def has_errors(run_log: Path) -> int: if not run_log.exists(): return 0 try: content = run_log.read_text(encoding="utf-8", errors="ignore") return content.count("[FEHLER:") except Exception: return 0 def get_last_entry(log_path: Path) -> str: """Letzter verarbeiteter Dateiname.""" if not log_path.exists(): return "—" last = "" with open(log_path, encoding="utf-8", errors="ignore") as f: for line in f: if line.startswith("**") and ("transkript" in line or "session" in line): last = line[2:50].split("**")[0].strip() return last or "—" def missed_sessions(log_path: Path, all_sources: list) -> list: """Welche Sources wurden noch nicht verarbeitet?""" if not log_path.exists(): return all_sources content = log_path.read_text(encoding="utf-8", errors="ignore") missed = [] for src in all_sources: if src[:40] not in content: missed.append(src) return missed def get_all_source_names() -> list: transcript_dir = Path("/home/smlflg/Projekte/IPAI/KnowdledgeGraph/data/raw") sources = [] if transcript_dir.exists(): sources = [f.name[:40] for f in sorted(transcript_dir.glob("*.txt"))] return sources def print_dashboard(all_sources: list): os.system("clear") now = datetime.now().strftime("%H:%M:%S") print(f"╔══════════════════════════════════════════════════════════════════╗") print(f"║ META2.0 Monitor [{now}] ║") print(f"╚══════════════════════════════════════════════════════════════════╝") print() total_done = 0 total_processed = 0 stalled = [] finished = [] errored = [] for key, label in FRAGEN.items(): dir_path = BASE / key log_path = dir_path / "session_log.md" run_log = dir_path / "run.log" done = is_done(dir_path) processed = count_processed(log_path) pct = int(processed / TOTAL_SOURCES * 100) if TOTAL_SOURCES else 0 age_min = last_modified(log_path) / 60 errors = has_errors(run_log) last = get_last_entry(log_path) # Status if done: status = "✓ DONE" finished.append(key) elif processed == 0: status = "⏳ warten" elif age_min > STALL_MINUTES and not done: status = f"⚠ STALL ({age_min:.0f}min)" stalled.append(key) else: bar = "█" * (pct // 5) + "░" * (20 - pct // 5) status = f"[{bar}] {pct:3d}%" err_str = f" ERR:{errors}" if errors else "" print(f" {key:<28} {status:<30} {processed:3d}/{TOTAL_SOURCES}{err_str}") print(f" {'':28} └─ {last[:50]}") print() total_processed += processed if done: total_done += 1 total_pct = int(total_processed / (TOTAL_SOURCES * len(FRAGEN)) * 100) print(f"─────────────────────────────────────────────────────────────────") print(f" Gesamt: {total_processed}/{TOTAL_SOURCES * len(FRAGEN)} Analyse-Calls ({total_pct}%)") print(f" Fertig: {total_done}/{len(FRAGEN)} Fragen | Stalled: {len(stalled)} | Laufend: {len(FRAGEN)-total_done-len(stalled)}") if stalled: print() print(f" ⚠ GESTALLED: {', '.join(stalled)}") print(f" → Neustart: python swarm_agent.py --frage-id ...") if finished: print() print(f" ✓ Fertige Antworten: {len(finished)}") for f in finished: print(f" cat {BASE}/{f}/ANTWORT.md") # Vollständigkeits-Check missed_total = 0 if "--check" in sys.argv: print() print(" VOLLSTÄNDIGKEITS-CHECK:") for key in FRAGEN: log_path = BASE / key / "session_log.md" missed = missed_sessions(log_path, all_sources) if missed: missed_total += len(missed) print(f" {key}: {len(missed)} nicht gelesen") for m in missed[:3]: print(f" - {m}") if missed_total == 0: print(" ✓ Alle Sources in allen Logs vorhanden.") print() print(" [Ctrl+C zum Beenden] [--check für Vollständigkeits-Audit]") def main(): all_sources = get_all_source_names() interval = 15 # Sekunden zwischen Updates if "--once" in sys.argv or "--check" in sys.argv: print_dashboard(all_sources) return try: while True: print_dashboard(all_sources) time.sleep(interval) except KeyboardInterrupt: print("\nMonitor beendet.") if __name__ == "__main__": main()