feat: mehrere Glossare kombinieren, gemeinsames Krone-Schmalz-Glossar

- rede_korrigieren.py: -g mehrfach, Ersetzungen in Reihenfolge der Angabe
- Ersetzungen ohne Treffer werden gesammelt in einer Zeile gemeldet
- krone-schmalz.glossar.txt: wiederkehrende Namen und Hörfehler; die
  Rede-Glossare enthalten nur noch Spezielles
- Magdeburg ergibt exakt denselben Text wie vorher, Ramstein profitiert von
  den gemeinsamen Einträgen (Russland-Versteher, Status quo, vornherein …)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-10-10 19:56:18 +02:00
commit 6610679d80

View file

@ -121,13 +121,18 @@ def read_glossary(path):
def apply_replacements(text, replacements):
"""Replace whole words in file order; report rules without any match."""
unmatched = []
for wrong, right in replacements:
pattern = re.compile(rf"(?<!\w){re.escape(wrong)}(?!\w)")
text, count = pattern.subn(right, text)
if count:
print(f" Ersetzt {count}× „{wrong}“ → „{right}“")
else:
print(f" WARNUNG: Ersetzung ohne Treffer: „{wrong}“")
unmatched.append(wrong)
# Normal for a shared glossary, a hint at a typo in one for a single speech
if unmatched:
names = ", ".join(f"„{wrong}“" for wrong in unmatched)
print(f" {len(unmatched)} Ersetzung(en) ohne Treffer: {names}")
return text
@ -366,8 +371,9 @@ def parse_args():
help="Ausgabedatei (Standard: <Eingabe ohne Endung>.korrigiert.txt)",
)
parser.add_argument(
"-g", "--glossar", type=Path,
help="Glossar: ein Begriff pro Zeile oder feste Ersetzung „falsch => richtig“",
"-g", "--glossar", type=Path, action="append", default=[],
help="Glossar: ein Begriff pro Zeile oder feste Ersetzung „falsch => richtig“; "
"mehrfach angeben, um Glossare zu kombinieren (Reihenfolge zählt)",
)
parser.add_argument(
"-m", "--model", default=MODEL, help=f"Ollama-Modell (Standard: {MODEL})"
@ -376,8 +382,9 @@ def parse_args():
if not args.input.is_file():
parser.error(f"Eingabedatei nicht gefunden: {args.input}")
if args.glossar is not None and not args.glossar.is_file():
parser.error(f"Glossar nicht gefunden: {args.glossar}")
for glossary in args.glossar:
if not glossary.is_file():
parser.error(f"Glossar nicht gefunden: {glossary}")
if args.output is None:
args.output = args.input.with_name(f"{args.input.stem}.korrigiert.txt")
if args.output.resolve() == args.input.resolve():
@ -396,7 +403,15 @@ def main():
target = args.output
parts_dir = target.with_suffix(".parts")
terms, replacements = read_glossary(args.glossar) if args.glossar else ([], [])
terms, replacements = [], []
for glossary in args.glossar:
more_terms, more_replacements = read_glossary(glossary)
print(
f"Glossar {glossary}: {len(more_terms)} Begriffe, "
f"{len(more_replacements)} feste Ersetzungen"
)
terms += more_terms
replacements += more_replacements
system = build_system(terms)
raw = source.read_text(encoding="utf-8-sig")
@ -405,11 +420,7 @@ def main():
# Subtitle line breaks carry no meaning; send plain running text
text = " ".join(raw.split())
if args.glossar:
print(
f"Glossar {args.glossar}: {len(terms)} Begriffe, "
f"{len(replacements)} feste Ersetzungen"
)
if replacements:
text = apply_replacements(text, replacements)
chunks = split_chunks(text)