This commit is contained in:
2026-05-06 19:55:37 +02:00
parent 7a7994e8b6
commit b41993c455
43 changed files with 1563 additions and 14 deletions

View File

@@ -250,6 +250,7 @@ def list_lessons() -> list[dict]:
"cycle": cycle,
"asset_count": len(assets),
"assets": assets,
"adaptive_kit": collect_adaptive_kit(lesson_dir),
}
)
@@ -297,6 +298,7 @@ def save_review_state(state: dict) -> None:
def collect_lesson_status(lesson: dict) -> dict:
lesson_dir = CONTENT_ROOT / lesson["id"]
kit_dir = lesson_dir / "kit_adaptatif"
return {
"micro_fiches": len([path for path in lesson_dir.glob("*.md") if path.name.startswith(tuple("0123456789"))]),
"lesson_svg": len(lesson.get("assets") or []),
@@ -304,6 +306,9 @@ def collect_lesson_status(lesson: dict) -> dict:
"contexts": len(list((lesson_dir / "card_contexts").rglob("Fiche*Card*.md"))),
"text_exercises": len(list((lesson_dir / "exercices").rglob("exercices.md"))),
"exercise_svg": len(list((lesson_dir / "exercices_svg").glob("*.svg"))),
"adaptive_tests": len([path for path in (kit_dir / "test_diagnostic").glob("*.md") if path.name != "README.md"]) if kit_dir.exists() else 0,
"adaptive_profiles": len([path for path in (kit_dir / "parcours_profils").glob("*.md") if path.name != "README.md"]) if kit_dir.exists() else 0,
"adaptive_svg": len(list((kit_dir / "svg").glob("*.svg"))) if kit_dir.exists() else 0,
"validations": sorted(path.stem for path in lesson_dir.glob("VALIDATION_PHASE_*.md")),
}
@@ -318,6 +323,69 @@ def append_tree_child(parent: dict, key: str, label: str, node_type: str, path:
return child
def read_review_text(path: Path, max_chars: int = 6000) -> str:
text = path.read_text(encoding="utf-8", errors="ignore").strip()
return text[:max_chars]
def collect_adaptive_kit(lesson_dir: Path) -> dict | None:
kit_dir = lesson_dir / "kit_adaptatif"
if not kit_dir.exists():
return None
def markdown_items(folder: str) -> list[dict]:
base = kit_dir / folder
if not base.exists():
return []
return [
{
"id": path.relative_to(CONTENT_ROOT).as_posix(),
"title": title_from_slug(path.stem),
"content": read_review_text(path),
}
for path in sorted(base.glob("*.md"))
if path.name != "README.md"
]
supports = []
svg_dir = kit_dir / "svg"
if svg_dir.exists():
for path in sorted(svg_dir.glob("*.svg")):
relative = path.relative_to(CONTENT_ROOT).as_posix()
supports.append(
{
"id": relative,
"title": title_from_slug(path.stem),
"url": build_asset_url(relative),
}
)
return {
"id": kit_dir.relative_to(CONTENT_ROOT).as_posix(),
"title": "Kit adaptatif",
"diagnostics": markdown_items("test_diagnostic"),
"profiles": markdown_items("parcours_profils"),
"supports": supports,
}
def format_adaptive_kit_context(lesson: dict | None) -> str:
kit = (lesson or {}).get("adaptive_kit")
if not kit:
return ""
diagnostics = ", ".join(item["title"] for item in kit.get("diagnostics") or [])
profiles = ", ".join(item["title"] for item in kit.get("profiles") or [])
return (
"Kit adaptatif disponible pour cette leçon.\n"
f"Tests diagnostics: {diagnostics or 'aucun'}.\n"
f"Parcours de reprise: {profiles or 'aucun'}.\n"
"Règle adaptative: si l'élève se trompe nettement, semble bloqué, inverse les notions ou demande de l'aide, "
"ne change pas de card tout de suite. Propose une micro-question de diagnostic liée à la difficulté observée, "
"puis oriente vers le parcours le plus probable en une phrase courte.\n"
)
def build_program_tree() -> dict:
reviews = load_review_state()
root = {
@@ -365,6 +433,37 @@ def build_program_tree() -> dict:
)
section_node["url"] = section.get("url")
section_node["review"] = reviews.get(section_key, {})
lesson_dir = CONTENT_ROOT / lesson["id"]
kit_dir = lesson_dir / "kit_adaptatif"
if kit_dir.exists():
kit_key = f"{lesson['id']}/kit_adaptatif"
kit_node = append_tree_child(lesson_node, kit_key, "Kit adaptatif", "kit", kit_key)
kit_node["review"] = reviews.get(kit_key, {})
tests_node = append_tree_child(kit_node, f"{kit_key}/test_diagnostic", "Tests diagnostics", "group", f"{kit_key}/test_diagnostic")
for test_path in sorted((kit_dir / "test_diagnostic").glob("*.md")):
if test_path.name == "README.md":
continue
relative = test_path.relative_to(CONTENT_ROOT).as_posix()
test_node = append_tree_child(tests_node, relative, title_from_slug(test_path.stem), "diagnostic", relative)
test_node["content"] = read_review_text(test_path)
test_node["review"] = reviews.get(relative, {})
profiles_node = append_tree_child(kit_node, f"{kit_key}/parcours_profils", "Parcours profils", "group", f"{kit_key}/parcours_profils")
for profile_path in sorted((kit_dir / "parcours_profils").glob("*.md")):
if profile_path.name == "README.md":
continue
relative = profile_path.relative_to(CONTENT_ROOT).as_posix()
profile_node = append_tree_child(profiles_node, relative, title_from_slug(profile_path.stem), "parcours", relative)
profile_node["content"] = read_review_text(profile_path)
profile_node["review"] = reviews.get(relative, {})
svg_node = append_tree_child(kit_node, f"{kit_key}/svg", "Supports visuels", "group", f"{kit_key}/svg")
for svg_path in sorted((kit_dir / "svg").glob("*.svg")):
relative = svg_path.relative_to(CONTENT_ROOT).as_posix()
support_node = append_tree_child(svg_node, relative, title_from_slug(svg_path.stem), "support", relative)
support_node["url"] = build_asset_url(relative)
support_node["review"] = reviews.get(relative, {})
return root