File size: 7,164 Bytes
b1c46d8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
#!/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 <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()