update
This commit is contained in:
@@ -63,13 +63,6 @@ def _load_subbausteine(topic: str) -> dict[str, list[dict]]:
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def _section_markup(sec: dict) -> str:
|
|
||||||
"""Section-Text mit Sub-Markern (für Lese-Check/Fix), damit die Struktur erhalten bleibt."""
|
|
||||||
if not sec.get("subs"):
|
|
||||||
return sec["md"]
|
|
||||||
return "\n\n".join(f"<!-- sub: {s['stufe']} | {s['titel']} -->\n{s['md']}" for s in sec["subs"])
|
|
||||||
|
|
||||||
|
|
||||||
def _zuteilung_subs(chunk: list[dict], entries: dict[int, str], subs_by_titel: dict[str, list[dict]]) -> str:
|
def _zuteilung_subs(chunk: list[dict], entries: dict[int, str], subs_by_titel: dict[str, list[dict]]) -> str:
|
||||||
"""Wie _zuteilung_text, aber listet pro Baustein seine Subbausteine mit Stufe."""
|
"""Wie _zuteilung_text, aber listet pro Baustein seine Subbausteine mit Stufe."""
|
||||||
lines: list[str] = []
|
lines: list[str] = []
|
||||||
@@ -654,11 +647,11 @@ async def _generate_sections(
|
|||||||
chunk_nums = [[num for ch in chunk for num in ch["nums"] if num in by_num] for chunk in chunks]
|
chunk_nums = [[num for ch in chunk for num in ch["nums"] if num in by_num] for chunk in chunks]
|
||||||
|
|
||||||
def sections_text(nums: list[int]) -> str:
|
def sections_text(nums: list[int]) -> str:
|
||||||
return "\n\n".join(f"SECTION: {_titel(entries[num])}\n{_section_markup(by_num[num])}" for num in nums)
|
return "\n\n".join(f"SECTION: {_titel(entries[num])}\n{by_num[num]['md']}" for num in nums)
|
||||||
|
|
||||||
def auftraege_text(nums: list[int], probleme: dict[int, str]) -> str:
|
def auftraege_text(nums: list[int], probleme: dict[int, str]) -> str:
|
||||||
return "\n\n".join(
|
return "\n\n".join(
|
||||||
f"SECTION: {_titel(entries[num])}\nPROBLEM: {probleme[num]}\nAKTUELLER INHALT:\n{_section_markup(by_num[num])}"
|
f"SECTION: {_titel(entries[num])}\nPROBLEM: {probleme[num]}\nAKTUELLER INHALT:\n{by_num[num]['md']}"
|
||||||
for num in nums
|
for num in nums
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -740,16 +733,12 @@ async def _generate_sections(
|
|||||||
scope = [[num for num in nums if num in ersetzt] for nums in chunk_nums]
|
scope = [[num for num in nums if num in ersetzt] for nums in chunk_nums]
|
||||||
|
|
||||||
await _set_progress(guide_id, "Setze zusammen…")
|
await _set_progress(guide_id, "Setze zusammen…")
|
||||||
def _section(num: int) -> dict:
|
|
||||||
sec = by_num[num]
|
|
||||||
d = {"num": num, "title": _titel(entries[num]), "md": sec["md"]}
|
|
||||||
if sec.get("subs"):
|
|
||||||
d["subbausteine"] = [{"stufe": s["stufe"], "titel": s["titel"], "md": s["md"]} for s in sec["subs"]]
|
|
||||||
return d
|
|
||||||
|
|
||||||
chapters: list[dict] = []
|
chapters: list[dict] = []
|
||||||
for ch in plan:
|
for ch in plan:
|
||||||
sections = [_section(num) for num in ch["nums"] if num in by_num]
|
sections = [
|
||||||
|
{"num": num, "title": _titel(entries[num]), "md": by_num[num]["md"]}
|
||||||
|
for num in ch["nums"] if num in by_num
|
||||||
|
]
|
||||||
if sections:
|
if sections:
|
||||||
chapters.append({"title": ch["title"], "sections": sections})
|
chapters.append({"title": ch["title"], "sections": sections})
|
||||||
geplant = {num for ch in plan for num in ch["nums"]}
|
geplant = {num for ch in plan for num in ch["nums"]}
|
||||||
|
|||||||
@@ -440,10 +440,6 @@ onMounted(async () => {
|
|||||||
--warning-soft: #fef3c7;
|
--warning-soft: #fef3c7;
|
||||||
--warning-border: #fbbf24;
|
--warning-border: #fbbf24;
|
||||||
--danger: #991b1b;
|
--danger: #991b1b;
|
||||||
/* Subbaustein-Stufen als Ampel (Schwierigkeit), bewusst NICHT die Stand-Farben. */
|
|
||||||
--stufe-einfach: #22c55e;
|
|
||||||
--stufe-mittel: #f59e0b;
|
|
||||||
--stufe-schwer: #ef4444;
|
|
||||||
--code-bg: #1e2a3a;
|
--code-bg: #1e2a3a;
|
||||||
--code-fg: #e6e6e6;
|
--code-fg: #e6e6e6;
|
||||||
--shadow: rgba(0, 0, 0, 0.12);
|
--shadow: rgba(0, 0, 0, 0.12);
|
||||||
@@ -472,9 +468,6 @@ html.dark {
|
|||||||
--warning-soft: #3a2c0a;
|
--warning-soft: #3a2c0a;
|
||||||
--warning-border: #a06a12;
|
--warning-border: #a06a12;
|
||||||
--danger: #f87171;
|
--danger: #f87171;
|
||||||
--stufe-einfach: #22c55e;
|
|
||||||
--stufe-mittel: #f59e0b;
|
|
||||||
--stufe-schwer: #ef4444;
|
|
||||||
--shadow: rgba(0, 0, 0, 0.5);
|
--shadow: rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import BausteinPanel from './BausteinPanel.vue'
|
import BausteinPanel from './BausteinPanel.vue'
|
||||||
import SubbausteinView from './SubbausteinView.vue'
|
|
||||||
import { renderMarkdown } from '../markdown.js'
|
import { renderMarkdown } from '../markdown.js'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -53,8 +52,7 @@ const standFarbe = computed(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div class="fokus-body">
|
<div class="fokus-body">
|
||||||
<div class="fokus-col left">
|
<div class="fokus-col left">
|
||||||
<div v-if="!baustein.subbausteine?.length" class="markdown" v-html="renderMarkdown(baustein.md)"></div>
|
<div class="markdown" v-html="renderMarkdown(baustein.md)"></div>
|
||||||
<SubbausteinView v-else :subbausteine="baustein.subbausteine" :md="baustein.md" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="fokus-col right">
|
<div class="fokus-col right">
|
||||||
<BausteinPanel
|
<BausteinPanel
|
||||||
|
|||||||
@@ -1,105 +0,0 @@
|
|||||||
<script setup>
|
|
||||||
import { ref, computed } from 'vue'
|
|
||||||
import { renderMarkdown } from '../markdown.js'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
subbausteine: { type: Array, default: null },
|
|
||||||
md: { type: String, default: '' },
|
|
||||||
})
|
|
||||||
|
|
||||||
const STUFEN = ['einfach', 'mittel', 'schwer']
|
|
||||||
const rang = (s) => {
|
|
||||||
const i = STUFEN.indexOf(s)
|
|
||||||
return i < 0 ? 0 : i
|
|
||||||
}
|
|
||||||
// 0 = nur einfach (Default), 1 = + mittel, 2 = alle
|
|
||||||
const stufe = ref(0)
|
|
||||||
const labels = ['Einfach', '+ Mittel', 'Alle']
|
|
||||||
|
|
||||||
const hatSubs = computed(() => Array.isArray(props.subbausteine) && props.subbausteine.length > 0)
|
|
||||||
const sichtbar = computed(() => {
|
|
||||||
if (!hatSubs.value) return []
|
|
||||||
const gefiltert = props.subbausteine.filter((s) => rang(s.stufe) <= stufe.value)
|
|
||||||
return gefiltert.length ? gefiltert : props.subbausteine // nie ganz leer anzeigen
|
|
||||||
})
|
|
||||||
const verborgen = computed(() => (hatSubs.value ? props.subbausteine.length - sichtbar.value.length : 0))
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div v-if="hatSubs">
|
|
||||||
<div class="subs-filter">
|
|
||||||
<button v-for="(lab, i) in labels" :key="i" :class="{ active: stufe === i }" @click="stufe = i">{{ lab }}</button>
|
|
||||||
<span v-if="verborgen > 0" class="subs-hidden">{{ verborgen }} ausgeblendet</span>
|
|
||||||
</div>
|
|
||||||
<div v-for="(s, i) in sichtbar" :key="i" :class="['sub', 'stufe-' + s.stufe]">
|
|
||||||
<div class="sub-head">
|
|
||||||
<span class="sub-pill">{{ s.stufe }}</span>
|
|
||||||
<span class="sub-titel">{{ s.titel }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="markdown" v-html="renderMarkdown(s.md)"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else class="markdown" v-html="renderMarkdown(md)"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.subs-filter {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.4rem;
|
|
||||||
align-items: center;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin-bottom: 0.9rem;
|
|
||||||
}
|
|
||||||
.subs-filter button {
|
|
||||||
padding: 0.2rem 0.7rem;
|
|
||||||
font-size: 0.8rem;
|
|
||||||
cursor: pointer;
|
|
||||||
border: 1px solid var(--border-strong);
|
|
||||||
border-radius: 999px;
|
|
||||||
background: var(--panel);
|
|
||||||
color: var(--text-muted);
|
|
||||||
}
|
|
||||||
.subs-filter button.active {
|
|
||||||
background: var(--accent);
|
|
||||||
border-color: var(--accent);
|
|
||||||
color: var(--on-accent);
|
|
||||||
}
|
|
||||||
.subs-hidden {
|
|
||||||
font-size: 0.75rem;
|
|
||||||
color: var(--text-faint);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ampel je Stufe: farbiger linker Rand + zarter Hintergrund. */
|
|
||||||
.sub {
|
|
||||||
border-left: 3px solid var(--sub-c);
|
|
||||||
background: color-mix(in srgb, var(--sub-c) 7%, var(--panel));
|
|
||||||
border-radius: 0 8px 8px 0;
|
|
||||||
padding: 0.6rem 0.9rem;
|
|
||||||
margin-bottom: 0.7rem;
|
|
||||||
}
|
|
||||||
.sub.stufe-einfach { --sub-c: var(--stufe-einfach); }
|
|
||||||
.sub.stufe-mittel { --sub-c: var(--stufe-mittel); }
|
|
||||||
.sub.stufe-schwer { --sub-c: var(--stufe-schwer); }
|
|
||||||
.sub-head {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 0.5rem;
|
|
||||||
margin-bottom: 0.35rem;
|
|
||||||
}
|
|
||||||
.sub-pill {
|
|
||||||
font-size: 0.65rem;
|
|
||||||
font-weight: 700;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.04em;
|
|
||||||
padding: 0.08rem 0.45rem;
|
|
||||||
border-radius: 999px;
|
|
||||||
color: #fff;
|
|
||||||
background: var(--sub-c);
|
|
||||||
}
|
|
||||||
.sub-titel {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
color: var(--text);
|
|
||||||
}
|
|
||||||
.sub .markdown :deep(p:last-child) { margin-bottom: 0; }
|
|
||||||
</style>
|
|
||||||
@@ -5,7 +5,6 @@ import { renderMarkdown } from '../markdown.js'
|
|||||||
import { useChat } from '../composables/useChat.js'
|
import { useChat } from '../composables/useChat.js'
|
||||||
import BausteinPanel from './BausteinPanel.vue'
|
import BausteinPanel from './BausteinPanel.vue'
|
||||||
import BausteinFokus from './BausteinFokus.vue'
|
import BausteinFokus from './BausteinFokus.vue'
|
||||||
import SubbausteinView from './SubbausteinView.vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
previewGuide: { type: Object, default: null },
|
previewGuide: { type: Object, default: null },
|
||||||
@@ -200,8 +199,7 @@ function extractContext() {
|
|||||||
<span v-else-if="lernstand[s.title]?.verstanden" class="baustein-done verstanden" title="Vollständig verstanden (10/10)">✓✓ Verstanden</span>
|
<span v-else-if="lernstand[s.title]?.verstanden" class="baustein-done verstanden" title="Vollständig verstanden (10/10)">✓✓ Verstanden</span>
|
||||||
<span v-else-if="lernstand[s.title]?.absolviert" class="baustein-done" title="Prüfung bestanden">✓ Absolviert</span>
|
<span v-else-if="lernstand[s.title]?.absolviert" class="baustein-done" title="Prüfung bestanden">✓ Absolviert</span>
|
||||||
</h3>
|
</h3>
|
||||||
<div v-if="isOnePager || !s.subbausteine?.length" class="section-body markdown" v-html="renderMarkdown(s.md)"></div>
|
<div class="section-body markdown" v-html="renderMarkdown(s.md)"></div>
|
||||||
<SubbausteinView v-else class="section-body" :subbausteine="s.subbausteine" :md="s.md" />
|
|
||||||
<BausteinPanel
|
<BausteinPanel
|
||||||
v-if="!isOnePager"
|
v-if="!isOnePager"
|
||||||
mode="trigger"
|
mode="trigger"
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ ZU ÜBERARBEITEN — je Section der aktuelle Inhalt und das notierte Problem:
|
|||||||
|
|
||||||
Behebe pro Section NUR das notierte Problem; was in Ordnung ist, bleibt inhaltlich erhalten.
|
Behebe pro Section NUR das notierte Problem; was in Ordnung ist, bleibt inhaltlich erhalten.
|
||||||
|
|
||||||
Enthält eine Section `<!-- sub: stufe | Titel -->`-Marker (Subbausteine), BEHALTE diese Struktur bei: gib pro Subbaustein wieder den Marker und darunter den überarbeiteten Text. Stufe und Subbaustein-Titel exakt übernehmen, keine Subbausteine entfernen oder hinzufügen.
|
Schreibe NUR die Datei {out_path} in GENAU diesem Format — für JEDE beanstandete Section ein section-Marker (Titel EXAKT wie oben), darunter der vollständige neue Markdown-Body:
|
||||||
|
|
||||||
Schreibe NUR die Datei {out_path} in GENAU diesem Format — für JEDE beanstandete Section ein section-Marker (Titel EXAKT wie oben), darunter der vollständige neue Markdown-Body (mit den `<!-- sub: … -->`-Markern, falls die Section welche hatte):
|
|
||||||
|
|
||||||
<!-- section: Exakter Section-Titel -->
|
<!-- section: Exakter Section-Titel -->
|
||||||
<!-- sub: einfach | Subbaustein-Titel -->
|
Erklärung (Einordnung → Wie/Warum) laut SECTION-SPEZIFIKATION…
|
||||||
Überarbeiteter Text zu diesem Teilpunkt…
|
|
||||||
|
### Beispiel
|
||||||
|
(Beispiel im themengerechten Format laut SECTION-SPEZIFIKATION: Codeblock NUR bei Code-Themen, sonst Beispielsätze oder Mini-Szenario)
|
||||||
|
|
||||||
Die Marker-Zeilen exakt so schreiben. Kein Text außerhalb der Sections.
|
Die Marker-Zeilen exakt so schreiben. Kein Text außerhalb der Sections.
|
||||||
{extra}
|
{extra}
|
||||||
|
|||||||
@@ -1,40 +1,36 @@
|
|||||||
Schreibe Sections für einen Lern-Guide zum Thema "{topic}" (Format: {format_name}).
|
Schreibe Sections für einen Lern-Guide zum Thema "{topic}" (Format: {format_name}).
|
||||||
|
|
||||||
Dir zugeteilt sind folgende Kapitel und Bausteine — verbindlich: jede zugeteilte Section muss vorkommen, keine zusätzlichen erfinden. Unter jedem Baustein stehen seine SUBBAUSTEINE mit Stufe (`[einfach]`, `[mittel]`, `[schwer]`):
|
Dir zugeteilt sind folgende Kapitel und Bausteine — verbindlich: jede zugeteilte Section muss vorkommen, keine zusätzlichen erfinden. Unter jedem Baustein stehen seine SUBBAUSTEINE mit Stufe (`[einfach]`/`[mittel]`/`[schwer]`):
|
||||||
{zuteilung}
|
{zuteilung}
|
||||||
|
|
||||||
{facts}
|
{facts}
|
||||||
|
|
||||||
Das Format ({format_name}) beeinflusst NICHT, wie ein Baustein geschrieben wird — nur, wie viele Bausteine das Thema abdecken. Derselbe Baustein bekommt in MiniGuide, Guide und FullGuide denselben Text.
|
Das Format ({format_name}) beeinflusst NICHT, wie ein Baustein geschrieben wird — nur, wie viele Bausteine das Thema abdecken. Derselbe Baustein bekommt in MiniGuide, Guide und FullGuide denselben Text.
|
||||||
|
|
||||||
SUBBAUSTEINE — so schreibst du:
|
SO SCHREIBST DU einen Baustein — EIN zusammenhängender Text, kein Stichwort-Stakkato:
|
||||||
- Pro zugeteiltem Subbaustein schreibst du EINEN kurzen, eigenständigen Abschnitt. Ein Subbaustein = ein Teilpunkt.
|
- Schreibe pro Baustein EINEN fließenden Lern-Text laut SECTION-SPEZIFIKATION (Einordnung → Erklärung → Beispiel). Ein roter Faden, mit Übergängen.
|
||||||
- Jeder Subbaustein-Abschnitt steht für sich: allein verständlich, ohne die anderen gelesen zu haben. Ein Anfänger darf später nur die `[einfach]`-Abschnitte sehen — die müssen für sich Sinn ergeben.
|
- Die Subbausteine sind deine INHALTS-CHECKLISTE, keine Überschriften: webe sie in den Fließtext ein. Behandle jeden, aber als Teil eines Ganzen — nicht als isolierten Mini-Absatz.
|
||||||
- Die Stufe steuert die Tiefe: `[einfach]` = Grundlage, knapp und sofort verständlich. `[mittel]` = ein Detail/eine Variante. `[schwer]` = Sonderfall/Tücke.
|
- Reihenfolge: erst die `[einfach]`-Punkte (das Fundament), dann `[mittel]` (Details/Varianten), zuletzt `[schwer]` (Sonderfälle/Tücken — knapp, als fortgeschrittener Hinweis).
|
||||||
- So lang wie nötig, so kurz wie möglich: 1–4 Sätze je Subbaustein. Ein Beispiel NUR, wo es wirklich hilft (Format laut Spezifikation).
|
- Tiefe folgt der Zahl der Subbausteine: ein Baustein mit vielen Subbausteinen wird ein langer, gehaltvoller Text; einer mit wenigen bleibt kurz. Das ist gewollt.
|
||||||
- Ein Baustein mit vielen Subbausteinen wird dadurch lang, einer mit wenigen kurz — das ist gewollt.
|
- KEIN festes Längen-Limit. So lang wie nötig, damit ein Anfänger es ohne Vorwissen versteht. Lieber ein Satz mehr und klar.
|
||||||
|
- Beispiel großzügig einsetzen, wo es hilft — bei Code-/Tool-Themen fast immer ein kurzes Code-Snippet (Format laut Spezifikation).
|
||||||
|
|
||||||
GEPRÜFTE INHALTE je Baustein — das ist verbindlich, was gelehrt werden muss:
|
GEPRÜFTE INHALTE je Baustein — das ist verbindlich, was gelehrt werden muss:
|
||||||
{inhalte}
|
{inhalte}
|
||||||
|
|
||||||
Nutze diese Inhalte. Erfinde nichts dazu, lass nichts Wesentliches weg. Verteile sie auf die Subbausteine. Lehre simpel: kurze Sätze, Listen für Aufzählungen, ein Anfänger versteht es sofort.
|
Nutze diese Inhalte. Erfinde nichts dazu, lass nichts Wesentliches weg. Lehre simpel: kurze Sätze, Listen für Aufzählungen, ein Anfänger versteht es sofort.
|
||||||
|
|
||||||
SECTION-SPEZIFIKATION (gilt je Subbaustein-Abschnitt):
|
SECTION-SPEZIFIKATION (gilt je Baustein):
|
||||||
{spec}
|
{spec}
|
||||||
|
|
||||||
Schreibe NUR die Datei {out_path} in GENAU diesem Format — pro Kapitel ein kapitel-Marker, pro Baustein ein section-Marker (Titel EXAKT aus der Zuteilung), darunter PRO Subbaustein ein sub-Marker `<!-- sub: stufe | Subbaustein-Titel -->` und dann der Markdown-Body dieses Subbausteins:
|
Schreibe NUR die Datei {out_path} in GENAU diesem Format — pro Kapitel ein kapitel-Marker, pro Baustein ein section-Marker (Titel EXAKT aus der Zuteilung), darunter der zusammenhängende Markdown-Body:
|
||||||
|
|
||||||
<!-- kapitel: Kapiteltitel -->
|
<!-- kapitel: Kapiteltitel -->
|
||||||
<!-- section: Exakter Baustein-Titel -->
|
<!-- section: Exakter Baustein-Titel -->
|
||||||
<!-- sub: einfach | Erster Subbaustein-Titel -->
|
Erklärung (Einordnung → Wie/Warum) laut SECTION-SPEZIFIKATION…
|
||||||
Kurzer, eigenständiger Text zu diesem Teilpunkt…
|
|
||||||
|
|
||||||
<!-- sub: mittel | Zweiter Subbaustein-Titel -->
|
### Beispiel
|
||||||
Kurzer Text…
|
(Beispiel im themengerechten Format laut SECTION-SPEZIFIKATION: Codeblock NUR bei Code-Themen, sonst Beispielsätze oder Mini-Szenario)
|
||||||
|
|
||||||
Regeln für die Marker:
|
Die Marker-Zeilen exakt so schreiben. Kein Text außerhalb der Sections, kein Dokument-Titel, kein Inhaltsverzeichnis.
|
||||||
- `stufe` ist genau eines von: einfach, mittel, schwer (aus der Zuteilung übernehmen).
|
|
||||||
- Der Subbaustein-Titel nach `|` EXAKT aus der Zuteilung.
|
|
||||||
- Hat ein Baustein in der Zuteilung KEINE Subbausteine, schreibe direkt unter den section-Marker einen normalen Section-Body (ohne sub-Marker).
|
|
||||||
- Kein Text außerhalb der Marker, kein Dokument-Titel, kein Inhaltsverzeichnis.
|
|
||||||
{extra}
|
{extra}
|
||||||
|
|||||||
Reference in New Issue
Block a user