diff --git a/README.md b/README.md index 84c9d78..16f39cd 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,7 @@ werden trotzdem umgewandelt; der Exit-Code ist dann 1. | `-i`, `--input` | Eingabedatei: Rohabschrift (`.txt`) oder Untertitel (`.vtt`, wird wie mit `vtt2txt.py` umgewandelt), Pflicht | | `-o`, `--output` | Ausgabedatei; Standard: `.korrigiert.txt` neben der Eingabe | | `-g`, `--glossar` | Glossar mit festen Ersetzungen und Schreibweisen | +| `-m`, `--model` | Ollama-Modell; Standard: `qwen3:32b` (Konstante `MODEL`) | ## Ablauf @@ -205,7 +206,7 @@ dazu Muster, Ausgabeverzeichnis und Fehlerfälle. Jeder fertige Abschnitt und jede Absatzgliederung wird in `.parts/` gespeichert. Ein erneuter Lauf überspringt alles, was schon berechnet ist. -Ändern sich Modell, Prompt, Glossar oder Text eines Abschnitts, wird genau dieser +Ändern sich Modell (auch per `-m`), Prompt, Glossar oder Text eines Abschnitts, wird genau dieser Teil neu berechnet. Den Ordner kann man jederzeit löschen. ## Einstellungen @@ -214,7 +215,7 @@ Oben in `rede_korrigieren.py`: | Konstante | Standard | Bedeutung | |---|---|---| -| `MODEL` | `qwen3:32b` | Ollama-Modell | +| `MODEL` | `qwen3:32b` | Ollama-Modell (Standard für `-m`) | | `CHUNK_SIZE` | 1200 | Wörter pro Korrekturabschnitt | | `MAX_WORD_DEVIATION` | 0.05 | Warnschwelle Wortzahl | | `MAX_PARAGRAPH_SENTENCES` | 10 | längster erlaubter Absatz | diff --git a/rede_korrigieren.py b/rede_korrigieren.py index 47f06b4..4074c3e 100755 --- a/rede_korrigieren.py +++ b/rede_korrigieren.py @@ -355,7 +355,7 @@ def build_paragraphs(text, parts_dir): def parse_args(): parser = argparse.ArgumentParser( description="Korrigiert eine automatische Abschrift einer deutschen Rede " - f"mit {MODEL} über Ollama." + "mit einem lokalen Sprachmodell über Ollama." ) parser.add_argument( "-i", "--input", required=True, type=Path, @@ -369,6 +369,9 @@ def parse_args(): "-g", "--glossar", type=Path, help="Glossar: ein Begriff pro Zeile oder feste Ersetzung „falsch => richtig“", ) + parser.add_argument( + "-m", "--model", default=MODEL, help=f"Ollama-Modell (Standard: {MODEL})" + ) args = parser.parse_args() if not args.input.is_file(): @@ -383,7 +386,12 @@ def parse_args(): def main(): + global MODEL args = parse_args() + # All model calls and cache keys read MODEL, so a different model never + # reuses cached parts of another + MODEL = args.model + print(f"Modell: {MODEL}") source = args.input target = args.output parts_dir = target.with_suffix(".parts") diff --git a/tests/test_rede_korrigieren.py b/tests/test_rede_korrigieren.py index 8215453..dfda84c 100644 --- a/tests/test_rede_korrigieren.py +++ b/tests/test_rede_korrigieren.py @@ -46,6 +46,8 @@ def no_model_calls(*args, **kwargs): def run_main(monkeypatch, *args): monkeypatch.setattr(sys, "argv", ["rede_korrigieren.py", *map(str, args)]) + # main() sets the module-wide model; restore it after the test + monkeypatch.setattr(rk, "MODEL", rk.MODEL) rk.main() @@ -301,6 +303,40 @@ def test_main_vtt_input_matches_txt_input(sample_copy, monkeypatch): ) == expected.read_text(encoding="utf-8") +def test_main_model_option(sample_copy, monkeypatch): + default = rk.MODEL + used = [] + + def correct(chunk, index, system): + used.append(rk.MODEL) + return chunk.strip() + + monkeypatch.setattr(rk, "correct_chunk", correct) + monkeypatch.setattr(rk, "find_paragraph_starts", every_nth_start(5)) + parts = sample_copy.parent / "ramstein.de.korrigiert.parts" + + run_main(monkeypatch, "-i", sample_copy) + default_parts = {p.name for p in parts.glob("part*")} + run_main(monkeypatch, "-i", sample_copy, "-m", "anderes:7b") + + assert set(used) == {default, "anderes:7b"} + # Another model must not reuse the cached parts of the default model + assert {p.name for p in parts.glob("part*")} - default_parts + + +def test_correct_chunk_sends_model(monkeypatch): + sent = {} + + def urlopen(request, timeout=None): + sent.update(json.loads(request.data)) + return FakeResponse(stream_body(["Text."])) + + monkeypatch.setattr(rk, "MODEL", "anderes:7b") + monkeypatch.setattr(rk.urllib.request, "urlopen", urlopen) + rk.correct_chunk("Text.", 1, "system") + assert sent["model"] == "anderes:7b" + + def test_main_warns_on_word_count_deviation(sample_copy, monkeypatch, capsys): def shortening(chunk, index, system): words = chunk.split()