feat: Warnung chapter-large mit --chapter-level-Empfehlung für sehr große Kapitel
Kapiteldateien über 30 000 Wörtern mit mindestens zwei ##-Unterabschnitten erzeugen eine Warnung mit der passenden --chapter-level-Empfehlung (QA-Befund R2, z. B. Roman mit Teilen als h1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3b07fcf01a
commit
8afa1cc6d4
3 changed files with 31 additions and 2 deletions
|
|
@ -150,6 +150,8 @@ Literaturlisten mit eigenen Labels (`[BryL06]`) werden nicht doppelt nummeriert.
|
|||
|
||||
**Tipp:** Hat ein Buch Teile als `h1` und Kapitel als `h2` (typisch bei Romanen), erzeugt
|
||||
`--chapter-level 2` eine Datei pro Kapitel. Mit dem Standard `1` entsteht eine Datei pro Teil.
|
||||
Ist eine Kapiteldatei größer als 30 000 Wörter und hat sie mindestens zwei `##`-Unterabschnitte, meldet
|
||||
epub2md eine Warnung `chapter-large` mit der passenden `--chapter-level`-Empfehlung.
|
||||
|
||||
## Math-Modi
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
|
||||
import os
|
||||
import posixpath
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
|
@ -28,6 +29,7 @@ from .utils import is_inside, iter_elements, sha256_file, slugify
|
|||
from . import writer
|
||||
|
||||
MARKER_FILES = ("conversion-report.json", "manifest.json")
|
||||
LARGE_CHAPTER_WORDS = 30000 # above this a deeper --chapter-level is suggested (RAG/readability)
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
@ -189,6 +191,7 @@ def _convert(reader: EpubReader, input_path: Path, output_dir: Path, opts: Optio
|
|||
diag.step(f"Rendere {ch.filename}")
|
||||
ch.markdown = renderer.render_chapter(ch)
|
||||
ch.stats.word_count = _word_count(ch.markdown)
|
||||
_check_chapter_size(ch, opts.chapter_level, diag)
|
||||
endnotes: Chapter | None = None
|
||||
endnotes_md = ""
|
||||
if opts.footnotes == "end-of-book" and renderer.book_notes:
|
||||
|
|
@ -288,9 +291,22 @@ def _assign_filenames(chapters: list[Chapter], slug_language: str) -> None:
|
|||
ch.filename = f"chapters/{candidate}.md"
|
||||
|
||||
|
||||
def _word_count(markdown: str) -> int:
|
||||
import re
|
||||
def _check_chapter_size(ch: Chapter, chapter_level: int, diag: Diagnostics) -> None:
|
||||
"""Suggest a deeper --chapter-level for very large chapters with enough sub-headings."""
|
||||
if ch.stats.word_count <= LARGE_CHAPTER_WORDS or chapter_level >= 6:
|
||||
return
|
||||
sections = len(re.findall(r"^## ", ch.markdown, re.M))
|
||||
if sections >= 2:
|
||||
diag.warn(
|
||||
"chapter-large",
|
||||
f"Kapitel „{ch.title}“ hat {ch.stats.word_count} Wörter und {sections} Unterabschnitte; "
|
||||
f"--chapter-level {chapter_level + 1} würde sie als eigene Dateien ausgeben.",
|
||||
ch.docs[0] if ch.docs else "",
|
||||
ch.filename,
|
||||
)
|
||||
|
||||
|
||||
def _word_count(markdown: str) -> int:
|
||||
text = re.sub(r"^(`{3,}).*?^\1\s*$", " ", markdown, flags=re.M | re.S)
|
||||
text = re.sub(r"<[^>]+>|\]\([^)]*\)", " ", text)
|
||||
return len(re.findall(r"\w+", text))
|
||||
|
|
|
|||
|
|
@ -122,3 +122,14 @@ def test_glossary_anchor_is_placed_before_bold_term(convert):
|
|||
'<dl><dt id="g">API</dt><dd>Schnittstelle.</dd></dl></section>')
|
||||
text = convert(Book(docs=[Doc("c.xhtml", body)])).chapter("002")
|
||||
assert '<a id="g"></a>**API:** Schnittstelle.' in text
|
||||
|
||||
|
||||
def test_large_chapter_with_subheadings_suggests_deeper_chapter_level(convert):
|
||||
words = " ".join(["Wort"] * 11000)
|
||||
body = "<h1>Teil 1</h1>" + "".join(f"<h2>Kapitel {i}</h2><p>{words}</p>" for i in range(3))
|
||||
run = convert(Book(docs=[Doc("t.xhtml", body)]))
|
||||
hints = [w for w in run.report["warnings"] if w["code"] == "chapter-large"]
|
||||
assert len(hints) == 1
|
||||
assert "--chapter-level 2" in hints[0]["message"] and "3 Unterabschnitte" in hints[0]["message"]
|
||||
small = convert(Book(docs=[Doc("t.xhtml", "<h1>Teil</h1><h2>A</h2><p>x</p><h2>B</h2><p>y</p>")]))
|
||||
assert not any(w["code"] == "chapter-large" for w in small.report["warnings"])
|
||||
|
|
|
|||
Loading…
Reference in a new issue