feat: rede_korrigieren.py -u URL – von YouTube direkt zum korrigierten Text
- extract_text.fetch_text() aus main() herausgelöst und wiederverwendet - -u/--url statt -i, -l/--lang für die Sprache (Standard: Original-Audio) - Ohne -o: <Video-ID>.korrigiert.txt; der Rohtext wird daneben gespeichert, eine vorhandene, abweichende Rohtext-Datei aber nie überschrieben Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
bc09ddf3bf
commit
5a072deca3
1 changed files with 133 additions and 18 deletions
|
|
@ -5,12 +5,15 @@ import argparse
|
|||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
import urllib.request
|
||||
|
||||
from aenderungen import REVIEW_MARK, print_summary, report_path, write_report
|
||||
from extract_text import fetch_text
|
||||
from vtt2txt import vtt_to_lines
|
||||
from yt_untertitel import YT_DLP
|
||||
|
||||
MODEL = "qwen3:32b"
|
||||
OLLAMA_URL = "http://127.0.0.1:11434/api/chat"
|
||||
|
|
@ -362,13 +365,23 @@ def parse_args():
|
|||
description="Korrigiert eine automatische Abschrift einer deutschen Rede "
|
||||
"mit einem lokalen Sprachmodell über Ollama."
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i", "--input", required=True, type=Path,
|
||||
source = parser.add_mutually_exclusive_group(required=True)
|
||||
source.add_argument(
|
||||
"-i", "--input", type=Path,
|
||||
help="Eingabedatei: Rohabschrift (.txt) oder Untertitel (.vtt)",
|
||||
)
|
||||
source.add_argument(
|
||||
"-u", "--url",
|
||||
help="YouTube-URL: Untertitel laden (Rohtext wird neben der Ausgabe gespeichert)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l", "--lang",
|
||||
help="nur mit -u: Sprache der Untertitel (Standard: Sprache des Original-Audios)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o", "--output", type=Path,
|
||||
help="Ausgabedatei (Standard: <Eingabe ohne Endung>.korrigiert.txt)",
|
||||
help="Ausgabedatei (Standard: <Eingabe ohne Endung>.korrigiert.txt, "
|
||||
"mit -u <Video-ID>.korrigiert.txt)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-g", "--glossar", type=Path, action="append", default=[],
|
||||
|
|
@ -384,11 +397,19 @@ def parse_args():
|
|||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
if not args.input.is_file():
|
||||
parser.error(f"Eingabedatei nicht gefunden: {args.input}")
|
||||
for glossary in args.glossar:
|
||||
if not glossary.is_file():
|
||||
parser.error(f"Glossar nicht gefunden: {glossary}")
|
||||
if args.url is not None:
|
||||
if shutil.which(YT_DLP) is None:
|
||||
parser.error(f"{YT_DLP} nicht gefunden (Installation: pip install yt-dlp).")
|
||||
# Without -o the name depends on the video ID, known after the download
|
||||
return args
|
||||
|
||||
if args.lang is not None:
|
||||
parser.error("-l/--lang gibt es nur zusammen mit -u/--url.")
|
||||
if not args.input.is_file():
|
||||
parser.error(f"Eingabedatei nicht gefunden: {args.input}")
|
||||
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,6 +417,38 @@ def parse_args():
|
|||
return args
|
||||
|
||||
|
||||
def raw_text_path(target):
|
||||
"""Where -u keeps the raw transcript: rede.korrigiert.txt -> rede.txt."""
|
||||
if target.name.endswith(".korrigiert.txt"):
|
||||
return target.with_name(target.name.removesuffix(".korrigiert.txt") + ".txt")
|
||||
return target.with_name(f"{target.stem}.roh.txt")
|
||||
|
||||
|
||||
def save_raw_text(path, raw):
|
||||
"""Keep the downloaded transcript for glossary work, never overwrite edits."""
|
||||
if path.exists() and path.read_text(encoding="utf-8") != raw:
|
||||
print(f"WARNUNG: {path} existiert mit anderem Inhalt und bleibt unverändert.")
|
||||
return
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(raw, encoding="utf-8")
|
||||
print(f"Rohtext: {path}")
|
||||
|
||||
|
||||
def read_source(args):
|
||||
"""Return the raw transcript and the output path."""
|
||||
if args.url is not None:
|
||||
info, lines = fetch_text(args.url, args.lang)
|
||||
target = args.output or Path(f"{info['id']}.korrigiert.txt")
|
||||
raw = "\n".join(lines) + "\n"
|
||||
save_raw_text(raw_text_path(target), raw)
|
||||
return raw, target
|
||||
|
||||
raw = args.input.read_text(encoding="utf-8-sig")
|
||||
if args.input.suffix.lower() == ".vtt":
|
||||
raw = "\n".join(vtt_to_lines(raw))
|
||||
return raw, args.output
|
||||
|
||||
|
||||
def main():
|
||||
global MODEL
|
||||
args = parse_args()
|
||||
|
|
@ -403,8 +456,7 @@ def main():
|
|||
# reuses cached parts of another
|
||||
MODEL = args.model
|
||||
print(f"Modell: {MODEL}")
|
||||
source = args.input
|
||||
target = args.output
|
||||
raw, target = read_source(args)
|
||||
parts_dir = target.with_suffix(".parts")
|
||||
|
||||
terms, replacements = [], []
|
||||
|
|
@ -418,9 +470,6 @@ def main():
|
|||
replacements += more_replacements
|
||||
system = build_system(terms)
|
||||
|
||||
raw = source.read_text(encoding="utf-8-sig")
|
||||
if source.suffix.lower() == ".vtt":
|
||||
raw = "\n".join(vtt_to_lines(raw))
|
||||
# Subtitle line breaks carry no meaning; send plain running text
|
||||
text = " ".join(raw.split())
|
||||
# The change report compares against this, so glossary effects show up too
|
||||
|
|
|
|||
Loading…
Reference in a new issue