This commit is contained in:
team3
2026-07-07 00:25:23 +02:00
parent f2feb1dbd0
commit f0c1bdacfa
15 changed files with 1363 additions and 367 deletions

View File

@@ -101,11 +101,14 @@ class Welt:
j = json.dumps
# Board 1 / Inventar
if "-research-" in key:
# Bottom-up: Research liefert die ATOME flach; Board 1 gruppiert sie zu den
# Cluster-Bausteinen. Jedes Atom gehört zu genau einem Cluster.
zeilen = []
n = 1
for t, b in self.bloecke.items():
zeilen.append(f"{n}. {t}{b['beschreibung']}")
n += 1
for cl, b in self.bloecke.items():
for atom in b["subs"]:
zeilen.append(f"{n}. {atom} — Atom aus {cl}")
n += 1
return "\n".join(zeilen)
if "-pair-" in key:
n = prompt.count("\nA: ") or 1
@@ -130,7 +133,19 @@ class Welt:
if "-gruppierung-completion-" in key:
return j({"additions": []})
if "-gruppierung-" in key:
return j({"umbrellas": []})
# jedes Atom seinem Cluster zuordnen (nur die FULL ITEM LIST, 1..n eindeutig)
seg = prompt.split("FULL ITEM LIST", 1)[-1]
atom_cluster = {_norm(a): cl for cl, b in self.bloecke.items() for a in b["subs"]}
umb: dict[str, list[int]] = {}
for m in _NUM_RE.finditer(seg):
nr, zeile = int(m.group(1)), _norm(m.group(2))
for an, cl in atom_cluster.items():
if zeile.startswith(an):
umb.setdefault(cl, []).append(nr)
break
umbrellas = [{"title": cl, "description": self.bloecke[cl]["beschreibung"],
"members": ms} for cl, ms in umb.items() if ms]
return j({"umbrellas": umbrellas})
if "-supplement-beleg" in key or "-anker-beleg-" in key:
nums = {m.group(1) for m in _NUM_RE.finditer(prompt)}
return j({"relevant": {k: "ja" for k in sorted(nums, key=int)} or {"1": "ja"}})
@@ -141,6 +156,16 @@ class Welt:
return j({"relevant": {k: "ja" for k in sorted(nums, key=int)} or {"1": "ja"}})
# Board 2 / Artefakte (verschmolzene Calls, block_calls.py)
if "-sb-enrich-" in key: # Bottom-up: feste Subs (aus dem Prompt) mit Facts anreichern
seg = prompt.split("FIXED SUBBLOCKS", 1)[-1].split("\n\n", 1)[0]
subs = []
for m in re.finditer(r"^\s*\d+\.\s+(.+)$", seg, re.M):
s = m.group(1).strip()
f = self._fakt("", s)
subs.append({"title": s, "level": "beginner", "relevance": "relevant",
**{k: f[k] for k in ("key_points", "prerequisites", "hurdles",
"cited_facts", "example_idea")}})
return j({"subs": subs})
if "-sb-gen-" in key:
subs = []
for t in self._bloecke_im_prompt(prompt):
@@ -251,13 +276,15 @@ class Welt:
def standard_bloecke() -> dict:
"""3 Blöcke; „Gemeinsamer Grundbegriff" liegt in Alpha UND Beta (Cross-Block-Fall)."""
"""3 Themen-Cluster; die subs sind die ATOME, die Board 1 bottom-up zu genau diesem
Cluster gruppiert. Jedes Atom liegt in genau einem Cluster (kein geteiltes Atom mehr —
das globale Clustern in Board 1 macht Cross-Block-Dubletten unmöglich)."""
return {
"Alpha-Konzept": {"beschreibung": "Das erste Grundkonzept",
"subs": ["Definition Alpha", "Alpha Eigenschaften",
"Gemeinsamer Grundbegriff"]},
"Beta-Verfahren": {"beschreibung": "Das zentrale Verfahren",
"subs": ["Beta Ablauf", "Beta Grenzen", "Gemeinsamer Grundbegriff"]},
"subs": ["Beta Ablauf", "Beta Grenzen"]},
"Gamma-Anwendung": {"beschreibung": "Praktische Anwendung",
"subs": ["Gamma Praxisfall", "Gamma Werkzeuge"]},
}
@@ -308,11 +335,18 @@ def aktivieren(welt: Welt, setattr_fn=setattr) -> None:
@staticmethod
def embed(texts):
import hashlib
import numpy as np
uniq = {t: k for k, t in enumerate(dict.fromkeys(texts))}
arr = np.zeros((len(texts), max(len(uniq), 1)))
# FESTE Dimension (hash → One-hot): identischer Text = gleiche Spalte = cos 1.0,
# verschiedener Text = andere Spalte = cos 0.0. Anders als eine pro-Aufruf
# variable Breite lassen sich so Vektoren aus verschiedenen embed()-Aufrufen
# concatenieren (Board-1-Cluster-Cache) ohne Dimensions-Mismatch.
D = 4096
arr = np.zeros((len(texts), D))
for r, t in enumerate(texts):
arr[r, uniq[t]] = 1.0
h = int(hashlib.blake2b(t.encode("utf-8"), digest_size=8).hexdigest(), 16) % D
arr[r, h] = 1.0
return arr
@staticmethod
@@ -320,9 +354,14 @@ def aktivieren(welt: Welt, setattr_fn=setattr) -> None:
arr = _FakeEmb.embed(texts)
return arr @ arr.T
for mod in (blocks, ba, qa):
setattr_fn(mod, "embedding", _FakeEmb)
# reine Matrix-/Union-Find-Helfer (modell-unabhängig) ans echte Modul delegieren
import embedding as _real_emb
capped_blocks = staticmethod(_real_emb.capped_blocks)
_find = staticmethod(_real_emb._find)
_union = staticmethod(_real_emb._union)
async def emb_ok(flow): # Board-1-Vektorpfade aus — Judge-Wellen reichen
return False
setattr_fn(bi, "_emb_ok", emb_ok)
for mod in (blocks, ba, qa, bi):
setattr_fn(mod, "embedding", _FakeEmb)
# _emb_ok bleibt echt (True über _FakeEmb): Bottom-up braucht den Grouping-Stage.
# _FakeEmb bildet nur bei identischem Text Nachbarn — verschiedene Atome erzeugen keine
# falschen Vorab-Cluster; das eigentliche Clustern macht der TOP-Judge (Card-sort).