update
This commit is contained in:
@@ -71,10 +71,7 @@ TIMEOUTS = {
|
|||||||
|
|
||||||
# Auswahl-Auftrag je Format: (Mindest-Anteil, Maximal-Anteil, Mindestanzahl, Zweck).
|
# Auswahl-Auftrag je Format: (Mindest-Anteil, Maximal-Anteil, Mindestanzahl, Zweck).
|
||||||
FORMAT_ANTEIL = {
|
FORMAT_ANTEIL = {
|
||||||
"MiniGuide": (0.05, 0.10, 8, "einen kompakten Anfänger-Guide — der schnelle Einstieg ins Thema"),
|
"Guide": (0.0, 1.0, 0, "einen fokussierten Guide — alles Relevante ohne Randthemen"),
|
||||||
"Guide": (0.25, 0.35, 20, "einen ausführlichen Anfänger-Guide — ein solides Fundament im Thema"),
|
|
||||||
"ProGuide": (0.0, 1.0, 0, "einen fokussierten Guide — alles Relevante ohne Randthemen"),
|
|
||||||
"FullGuide": (0.90, 1.00, 0, "einen Komplett-Guide — das ganze Thema"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Provider-Stacks: komplett unabhängig, einer kann jederzeit entfernt werden.
|
# Provider-Stacks: komplett unabhängig, einer kann jederzeit entfernt werden.
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ def _topic_context(topic: str, limit: int = 12000) -> str:
|
|||||||
bp = bausteine_path(topic)
|
bp = bausteine_path(topic)
|
||||||
if bp.exists():
|
if bp.exists():
|
||||||
parts.append(bp.read_text(encoding="utf-8"))
|
parts.append(bp.read_text(encoding="utf-8"))
|
||||||
for fmt in ("FullGuide", "ProGuide", "Guide", "MiniGuide", "OnePager"):
|
for fmt in ("Guide", "OnePager"):
|
||||||
content = _json_datei(guide_content_path(topic, fmt))
|
content = _json_datei(guide_content_path(topic, fmt))
|
||||||
if content:
|
if content:
|
||||||
for ch in content.get("chapters", []):
|
for ch in content.get("chapters", []):
|
||||||
|
|||||||
@@ -408,17 +408,17 @@ async def _generate_sections(
|
|||||||
"Wähle, was diesem Zweck dient — lass weg, was dafür nicht nötig ist."
|
"Wähle, was diesem Zweck dient — lass weg, was dafür nicht nötig ist."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subbausteine je Baustein (Sidecar) — früh geladen: ProGuide wählt darüber aus,
|
# Subbausteine je Baustein (Sidecar) — früh geladen: „Guide" wählt darüber aus
|
||||||
# Nicht-FullGuide filtert später Rand-Subbausteine. Fehlt sie → {} (Fallback).
|
# (Bausteine mit ≥1 relevantem Sub) und filtert später Rand-Subs. Fehlt sie → {} (Fallback).
|
||||||
subs_raw = _load_subbausteine(topic)
|
subs_raw = _load_subbausteine(topic)
|
||||||
|
|
||||||
# Schritt 0: Auswahl. ProGuide ist deterministisch — alle Bausteine mit ≥1
|
# Schritt 0: Auswahl. „Guide" ist deterministisch — alle Bausteine mit ≥1
|
||||||
# relevantem Subbaustein. Fallback (keine Relevanz-Daten): alle Bausteine.
|
# relevantem Subbaustein. Fallback (keine Relevanz-Daten): alle Bausteine.
|
||||||
if format_name == "ProGuide":
|
if format_name == "Guide":
|
||||||
auswahl = [num for num in entries
|
auswahl = [num for num in entries
|
||||||
if any(s.get("relevanz") == "relevant" for s in subs_raw.get(_titel(entries[num]), []))]
|
if any(s.get("relevanz") == "relevant" for s in subs_raw.get(_titel(entries[num]), []))]
|
||||||
if not auswahl:
|
if not auswahl:
|
||||||
_log(topic, "ProGuide: keine Relevanz-Daten — alle Bausteine genommen")
|
_log(topic, "Guide: keine Relevanz-Daten — alle Bausteine genommen")
|
||||||
auswahl = list(entries)
|
auswahl = list(entries)
|
||||||
else:
|
else:
|
||||||
# Auswahl-Konsens (5 Agenten → Voting → Mapping → Klärungs-Loop)
|
# Auswahl-Konsens (5 Agenten → Voting → Mapping → Klärungs-Loop)
|
||||||
@@ -501,16 +501,14 @@ async def _generate_sections(
|
|||||||
# dieselbe Aufteilung: 1 Agent je ~30 Bausteine (gedeckelt).
|
# dieselbe Aufteilung: 1 Agent je ~30 Bausteine (gedeckelt).
|
||||||
total_sections = sum(len(c["nums"]) for c in plan)
|
total_sections = sum(len(c["nums"]) for c in plan)
|
||||||
chunks = _split_chunks(plan, min(WRITER_MAX, max(1, math.ceil(total_sections / WRITER_SECTIONS))))
|
chunks = _split_chunks(plan, min(WRITER_MAX, max(1, math.ceil(total_sections / WRITER_SECTIONS))))
|
||||||
# Subbausteine je Baustein. Rand-Subbausteine fliegen aus allen Guides AUSSER
|
# Subbausteine je Baustein. Rand-Subbausteine fliegen aus dem Guide (Fokus auf
|
||||||
# FullGuide (Fokus). Subs ohne Relevanz-Feld (Alt-Themen) bleiben erhalten.
|
# Relevantes). Subs ohne Relevanz-Feld (Alt-Themen) bleiben erhalten.
|
||||||
# Fehlt die Sidecar → leer → Inhalte/Writer laufen auf Baustein-Granularität.
|
# Fehlt die Sidecar → leer → Inhalte/Writer laufen auf Baustein-Granularität.
|
||||||
subs_by_titel = subs_raw
|
subs_by_titel = {
|
||||||
if format_name != "FullGuide":
|
t: [s for s in subs if s.get("relevanz") != "rand"]
|
||||||
subs_by_titel = {
|
for t, subs in subs_raw.items()
|
||||||
t: [s for s in subs if s.get("relevanz") != "rand"]
|
}
|
||||||
for t, subs in subs_raw.items()
|
subs_by_titel = {t: subs for t, subs in subs_by_titel.items() if subs}
|
||||||
}
|
|
||||||
subs_by_titel = {t: subs for t, subs in subs_by_titel.items() if subs}
|
|
||||||
zuteilungen = [_zuteilung_subs(chunk, entries, subs_by_titel) for chunk in chunks]
|
zuteilungen = [_zuteilung_subs(chunk, entries, subs_by_titel) for chunk in chunks]
|
||||||
chunk_sizes = [sum(len(c["nums"]) for c in chunk) for chunk in chunks]
|
chunk_sizes = [sum(len(c["nums"]) for c in chunk) for chunk in chunks]
|
||||||
writer_count = len(chunks)
|
writer_count = len(chunks)
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ from typing import Literal
|
|||||||
|
|
||||||
FormatType = Literal[
|
FormatType = Literal[
|
||||||
"OnePager",
|
"OnePager",
|
||||||
"MiniGuide",
|
|
||||||
"Guide",
|
"Guide",
|
||||||
"ProGuide",
|
|
||||||
"FullGuide",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
ProviderType = Literal["claude", "minimax", "lokal"]
|
ProviderType = Literal["claude", "minimax", "lokal"]
|
||||||
|
|||||||
@@ -18,12 +18,11 @@ from paths import bausteine_path, guide_content_path
|
|||||||
from textkit import _norm_titel
|
from textkit import _norm_titel
|
||||||
|
|
||||||
MAX_OFFENE_GUIDES = 3
|
MAX_OFFENE_GUIDES = 3
|
||||||
# Lineare Progression: jedes Format schaltet das nächste frei, sobald ALLE Bausteine
|
# Nur noch EIN Format „Guide" (alle relevanten Bausteine, Prüfung 0–30). Keine Progression,
|
||||||
# der Vorstufe das geforderte Niveau (Score-Meilenstein 10/20/30) erreicht haben.
|
# keine Vorstufe → der Guide ist immer freischaltbar. „Rest"/OnePager separat.
|
||||||
VORSTUFE = {"Guide": "MiniGuide", "ProGuide": "Guide", "FullGuide": "ProGuide"}
|
VORSTUFE: dict[str, str] = {}
|
||||||
# absolviert=6 · verstanden=12 · gemeistert=18 (siehe lernen.NOETIG/MASTERY/MEISTERN).
|
FREISCHALT_LEVEL: dict[str, str] = {}
|
||||||
FREISCHALT_LEVEL = {"Guide": "absolviert", "ProGuide": "verstanden", "FullGuide": "gemeistert"}
|
FORMATE = ("Guide",)
|
||||||
FORMATE = ("MiniGuide", "Guide", "ProGuide", "FullGuide")
|
|
||||||
|
|
||||||
# Geforderter Score je Freischalt-Niveau — nur für die Sperr-Meldung.
|
# Geforderter Score je Freischalt-Niveau — nur für die Sperr-Meldung.
|
||||||
_LEVEL_WORT = {
|
_LEVEL_WORT = {
|
||||||
@@ -106,8 +105,8 @@ def ist_absolviert(topic: str, fmt: str, guides: list[dict], progress: dict[str,
|
|||||||
|
|
||||||
|
|
||||||
def thema_abgeschlossen(topic: str, guides: list[dict], progress: dict[str, set[str]], levels: dict[str, dict[str, set[str]]]) -> bool:
|
def thema_abgeschlossen(topic: str, guides: list[dict], progress: dict[str, set[str]], levels: dict[str, dict[str, set[str]]]) -> bool:
|
||||||
"""Thema fertig: neuester fertiger FullGuide, alle Bausteine gemeistert (25)?"""
|
"""Thema fertig: neuester fertiger Guide, alle Bausteine gemeistert (18)?"""
|
||||||
return ist_level(topic, "FullGuide", guides, progress, levels["gemeistert"])
|
return ist_level(topic, "Guide", guides, progress, levels["gemeistert"])
|
||||||
|
|
||||||
|
|
||||||
def formate_stats(guides: list[dict], progress: dict[str, set[str]], levels: dict[str, dict[str, set[str]]]) -> dict:
|
def formate_stats(guides: list[dict], progress: dict[str, set[str]], levels: dict[str, dict[str, set[str]]]) -> dict:
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ async function loadBausteine() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FORMAT_ORDER = ['OnePager', 'MiniGuide', 'Guide', 'ProGuide', 'FullGuide']
|
const FORMAT_ORDER = ['Guide', 'OnePager']
|
||||||
|
|
||||||
function autoPreview() {
|
function autoPreview() {
|
||||||
const map = doneByFormat.value
|
const map = doneByFormat.value
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ const bandZiel = computed(() => {
|
|||||||
return ABSOLVIERT
|
return ABSOLVIERT
|
||||||
})
|
})
|
||||||
const FORM_NAME = { quiz: 'Quiz', lueckentext: 'Lückentext', erklaeren: 'Erklären' }
|
const FORM_NAME = { quiz: 'Quiz', lueckentext: 'Lückentext', erklaeren: 'Erklären' }
|
||||||
const NAECHSTES_FORMAT = { 6: 'Guide', 12: 'ProGuide', 18: 'FullGuide' }
|
|
||||||
|
|
||||||
// --- Toggle-Bereich ---
|
// --- Toggle-Bereich ---
|
||||||
const activeTab = ref(props.mode === 'full' ? props.initialTab : null) // null | 'chat' | 'pruefung'
|
const activeTab = ref(props.mode === 'full' ? props.initialTab : null) // null | 'chat' | 'pruefung'
|
||||||
@@ -702,7 +701,7 @@ function onPruefKey(e) {
|
|||||||
<!-- Prüfung: gesteuerter Dialog -->
|
<!-- Prüfung: gesteuerter Dialog -->
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<p class="bp-hint">
|
<p class="bp-hint">
|
||||||
<template v-if="amDeckel">{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ cap }} — <strong>Max</strong>.<template v-if="cap < VOLL"> Erstelle den {{ NAECHSTES_FORMAT[cap] }} für mehr.</template></template>
|
<template v-if="amDeckel">{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ cap }} — <strong>Max</strong>.</template>
|
||||||
<template v-else>{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ bandZiel }} · {{ modusRegel }}<span v-if="imZufall" class="bp-hint-key"> · zufällig</span></template>
|
<template v-else>{{ FORM_NAME[zeigeForm] }} · {{ score }}/{{ bandZiel }} · {{ modusRegel }}<span v-if="imZufall" class="bp-hint-key"> · zufällig</span></template>
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ async function load() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Baustein relevant = hat ≥1 relevanten Subbaustein (gleiche Regel wie ProGuide).
|
// Baustein relevant = hat ≥1 relevanten Subbaustein (gleiche Regel wie der Guide).
|
||||||
// Ohne Relevanz-Daten (Alt-Themen) nicht dimmen.
|
// Ohne Relevanz-Daten (Alt-Themen) nicht dimmen.
|
||||||
function relevant(b) {
|
function relevant(b) {
|
||||||
const mitRelevanz = (b.subbausteine || []).filter((s) => s.relevanz)
|
const mitRelevanz = (b.subbausteine || []).filter((s) => s.relevanz)
|
||||||
@@ -70,7 +70,7 @@ const subTotal = computed(() => items.value.reduce((n, b) => n + (b.subbausteine
|
|||||||
:key="b.num"
|
:key="b.num"
|
||||||
class="bk-card"
|
class="bk-card"
|
||||||
:class="{ 'bk-irrelevant': !relevant(b) }"
|
:class="{ 'bk-irrelevant': !relevant(b) }"
|
||||||
:title="relevant(b) ? null : 'Nicht relevant — nur im FullGuide'"
|
:title="relevant(b) ? null : 'Nicht relevant — kommt später in den „Rest“'"
|
||||||
>
|
>
|
||||||
<h3 class="bk-title"><span class="bk-num">{{ b.num }}</span>{{ b.titel }}</h3>
|
<h3 class="bk-title"><span class="bk-num">{{ b.num }}</span>{{ b.titel }}</h3>
|
||||||
<p v-if="b.beschreibung" class="bk-desc">{{ b.beschreibung }}</p>
|
<p v-if="b.beschreibung" class="bk-desc">{{ b.beschreibung }}</p>
|
||||||
@@ -79,7 +79,7 @@ const subTotal = computed(() => items.value.reduce((n, b) => n + (b.subbausteine
|
|||||||
<span class="bk-stufe-label">{{ g.label }}</span>
|
<span class="bk-stufe-label">{{ g.label }}</span>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="s in g.subs" :key="s.titel" :class="{ rand: s.relevanz === 'rand' }">
|
<li v-for="s in g.subs" :key="s.titel" :class="{ rand: s.relevanz === 'rand' }">
|
||||||
{{ s.titel }}<span v-if="s.relevanz === 'rand'" class="rand-tag" title="Randthema — nur im FullGuide">Rand</span>
|
{{ s.titel }}<span v-if="s.relevanz === 'rand'" class="rand-tag" title="Randthema — kommt später in den „Rest“">Rand</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -122,12 +122,16 @@ watch(() => props.graph, build, { immediate: true })
|
|||||||
background: var(--panel, #fff);
|
background: var(--panel, #fff);
|
||||||
color: var(--text, #111);
|
color: var(--text, #111);
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
line-height: 1.3;
|
line-height: 1.35;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
max-width: 240px;
|
max-width: 300px;
|
||||||
|
/* Langer Text/Formel umbricht, statt im Knoten abgeschnitten zu werden. */
|
||||||
|
white-space: normal;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
}
|
}
|
||||||
/* KaTeX im Knoten nicht umbrechen lassen */
|
/* KaTeX im Knoten umbrechen lassen + geerbtes Klippen (markdown .katex-display) neutralisieren. */
|
||||||
.gv-node :deep(.katex) { white-space: nowrap; }
|
.gv-node :deep(.katex) { white-space: normal; }
|
||||||
|
.gv-node :deep(.katex-display) { overflow: visible; margin: 0; }
|
||||||
.graph-view :deep(.vue-flow__edge-text) { font-size: 0.72rem; fill: var(--text-muted, #666); }
|
.graph-view :deep(.vue-flow__edge-text) { font-size: 0.72rem; fill: var(--text-muted, #666); }
|
||||||
.graph-view :deep(.vue-flow__edge-textbg) { fill: var(--panel, #fff); }
|
.graph-view :deep(.vue-flow__edge-textbg) { fill: var(--panel, #fff); }
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -93,14 +93,8 @@ const fortschritt = computed(() => {
|
|||||||
return { total: bausteine.value.length, absolviert: a, verstanden: v, gemeistert: g }
|
return { total: bausteine.value.length, absolviert: a, verstanden: v, gemeistert: g }
|
||||||
})
|
})
|
||||||
|
|
||||||
// Score-Deckel folgt dem höchsten erstellten Format: Mini→6, Guide→12, ProGuide→18, FullGuide→30.
|
// Ein Format „Guide" → Prüfung läuft voll 0–30. Ohne fertigen Guide kein Deckel relevant (6).
|
||||||
const cap = computed(() => {
|
const cap = computed(() => (props.doneByFormat?.Guide ? 30 : 6))
|
||||||
const d = props.doneByFormat || {}
|
|
||||||
if (d.FullGuide) return 30
|
|
||||||
if (d.ProGuide) return 18
|
|
||||||
if (d.Guide) return 12
|
|
||||||
return 6
|
|
||||||
})
|
|
||||||
|
|
||||||
// --- Chat (Mechanik in useChat; Kontext-Extraktion bleibt hier) ---
|
// --- Chat (Mechanik in useChat; Kontext-Extraktion bleibt hier) ---
|
||||||
const chat = useChat((msgs) => {
|
const chat = useChat((msgs) => {
|
||||||
@@ -188,7 +182,7 @@ function extractContext() {
|
|||||||
<header class="guide-head">
|
<header class="guide-head">
|
||||||
<h1>{{ previewGuide.topic }}</h1>
|
<h1>{{ previewGuide.topic }}</h1>
|
||||||
<span class="guide-format">{{ previewGuide.format }}</span>
|
<span class="guide-format">{{ previewGuide.format }}</span>
|
||||||
<span v-if="themaAbgeschlossen" class="thema-done" title="Alle FullGuide-Bausteine gemeistert (25/25)">✓ Thema abgeschlossen</span>
|
<span v-if="themaAbgeschlossen" class="thema-done" title="Alle Bausteine gemeistert (18/18)">✓ Thema abgeschlossen</span>
|
||||||
</header>
|
</header>
|
||||||
<section
|
<section
|
||||||
v-for="(ch, ci) in content.chapters"
|
v-for="(ch, ci) in content.chapters"
|
||||||
|
|||||||
@@ -47,19 +47,13 @@ const trackerItems = computed(() => {
|
|||||||
const fmt = (k) => `${f[k]?.absolviert ?? 0}/${f[k]?.erstellt ?? 0}`
|
const fmt = (k) => `${f[k]?.absolviert ?? 0}/${f[k]?.erstellt ?? 0}`
|
||||||
return [
|
return [
|
||||||
{ label: 'Themen', value: String(props.stats.themen ?? 0), title: 'Themen inkl. Projekte' },
|
{ label: 'Themen', value: String(props.stats.themen ?? 0), title: 'Themen inkl. Projekte' },
|
||||||
{ label: 'MiniGuides', value: fmt('MiniGuide'), title: 'absolviert/erstellt' },
|
|
||||||
{ label: 'Guides', value: fmt('Guide'), title: 'absolviert/erstellt' },
|
{ label: 'Guides', value: fmt('Guide'), title: 'absolviert/erstellt' },
|
||||||
{ label: 'ProGuides', value: fmt('ProGuide'), title: 'absolviert/erstellt' },
|
|
||||||
{ label: 'FullGuides', value: fmt('FullGuide'), title: 'absolviert/erstellt' },
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
const formats = [
|
const formats = [
|
||||||
{ key: 'OnePager', label: 'OnePager' },
|
{ key: 'OnePager', label: 'OnePager' },
|
||||||
{ key: 'MiniGuide', label: 'MiniGuide' },
|
|
||||||
{ key: 'Guide', label: 'Guide' },
|
{ key: 'Guide', label: 'Guide' },
|
||||||
{ key: 'ProGuide', label: 'ProGuide' },
|
|
||||||
{ key: 'FullGuide', label: 'FullGuide' },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const bausteineState = computed(() => {
|
const bausteineState = computed(() => {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ PRÜFE auf:
|
|||||||
- **Inhalt:** die relevanten Subbausteine kommen vor; Richtung/Kanten geben die Beziehungen korrekt wieder; nichts Erfundenes.
|
- **Inhalt:** die relevanten Subbausteine kommen vor; Richtung/Kanten geben die Beziehungen korrekt wieder; nichts Erfundenes.
|
||||||
- **Mathe:** Symbole stehen als echte KaTeX-Notation in Dollarzeichen (`$\Sigma$`, `$w \in L$`), nicht als Wort ausgeschrieben. Korrigiere Verstöße.
|
- **Mathe:** Symbole stehen als echte KaTeX-Notation in Dollarzeichen (`$\Sigma$`, `$w \in L$`), nicht als Wort ausgeschrieben. Korrigiere Verstöße.
|
||||||
- **Kanten-Label:** nur ein kurzes Wort (ja/nein/kodiert), **keine Formeln/Dollarzeichen** in Kanten — Formeln gehören in die Knoten.
|
- **Kanten-Label:** nur ein kurzes Wort (ja/nein/kodiert), **keine Formeln/Dollarzeichen** in Kanten — Formeln gehören in die Knoten.
|
||||||
- **Knappheit:** Knotentexte kurz.
|
- **Knappheit:** Knotentexte SEHR kurz (≤ 6 Wörter / eine kompakte Inline-Formel). **Verboten:** `\\`, `\text{…}`, `$$…$$`, mehrteilige Formeln. Kürze lange Knoten (z.B. volle Formaldefinitionen) auf den Kern ein.
|
||||||
|
|
||||||
Korrigiere alle Mängel. Ist die Grafik bereits gut, gib sie unverändert zurück.
|
Korrigiere alle Mängel. Ist die Grafik bereits gut, gib sie unverändert zurück.
|
||||||
{extra}
|
{extra}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ AUFGABE:
|
|||||||
- Baue EINEN gerichteten Graphen: **Knoten** = die Subbausteine (plus ggf. Verbindungs-Knoten wie Start/Ende/Verzweigung), **Kanten** = ihre Beziehungen (Reihenfolge, Abhängigkeit, Ober-/Unterbegriff, Ja/Nein).
|
- Baue EINEN gerichteten Graphen: **Knoten** = die Subbausteine (plus ggf. Verbindungs-Knoten wie Start/Ende/Verzweigung), **Kanten** = ihre Beziehungen (Reihenfolge, Abhängigkeit, Ober-/Unterbegriff, Ja/Nein).
|
||||||
- Decke die relevanten Subbausteine ab. Erfinde keine Inhalte außerhalb des Bausteins.
|
- Decke die relevanten Subbausteine ab. Erfinde keine Inhalte außerhalb des Bausteins.
|
||||||
- Wähle die Richtung passend: `TB` (oben→unten, für Abläufe/Hierarchien) oder `LR` (links→rechts, für Ketten).
|
- Wähle die Richtung passend: `TB` (oben→unten, für Abläufe/Hierarchien) oder `LR` (links→rechts, für Ketten).
|
||||||
- **Knotentext kurz** (Stichwort/kurzer Satz). Mathematik schreibst du als **echte Notation** mit KaTeX in Dollarzeichen: `$\Sigma$`, `$(L, \Sigma)$`, `$w \in L$`, `$2^n$`. Niemals Symbole als Wort ausschreiben (nicht „Sigma", nicht „Vereinigung").
|
- **Knotentext SEHR kurz** (ein Stichwort oder eine **kompakte** Inline-Formel, Richtwert ≤ 6 Wörter). Lange Formaldefinitionen gehören NICHT in den Graph — die stehen im Guide-Text.
|
||||||
|
- Mathematik als **echte Notation** mit KaTeX in Dollarzeichen: `$\Sigma$`, `$(L, \Sigma)$`, `$w \in L$`, `$2^n$`. Niemals Symbole als Wort ausschreiben (nicht „Sigma", nicht „Vereinigung").
|
||||||
|
- **Verboten im Knotentext:** `\\` (Zeilenumbruch), `\text{…}`, `$$…$$` (Display-Mathe), mehrteilige/verkettete Formeln. Eine Formel pro Knoten, knapp.
|
||||||
- Kanten-Label (`text`) ist optional und **nur ein kurzes Wort** (z.B. „kodiert", „ja", „nein") — **keine Formeln/Dollarzeichen** in Kanten. Formeln gehören in die Knoten.
|
- Kanten-Label (`text`) ist optional und **nur ein kurzes Wort** (z.B. „kodiert", „ja", „nein") — **keine Formeln/Dollarzeichen** in Kanten. Formeln gehören in die Knoten.
|
||||||
- Jede `id` ist ein kurzes Kürzel (a–z, 0–9), eindeutig. Jede Kante verweist mit `von`/`nach` auf existierende Knoten-`id`s.
|
- Jede `id` ist ein kurzes Kürzel (a–z, 0–9), eindeutig. Jede Kante verweist mit `von`/`nach` auf existierende Knoten-`id`s.
|
||||||
{extra}
|
{extra}
|
||||||
|
|||||||
Reference in New Issue
Block a user