Обученный сегментатор страниц (главный путь), правила — запасной; фикстура rt-topic-6870900

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
DenozordecandClaude Sonnet 5.5 committed 2026-10-27 18:06:47 +07:00
1 parent 96e5fa0d75
commit d155b8584b
7 files changed
+1257 -4

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
"""Сравнение сегментации: правила vs обученный сегментатор (predict_release).
Метрика — пары (тип, автор) на уровне релиза против меток датасета, только по
страницам, которых сегментатор не видел при обучении (is_test_release).
Запуск: .venv/Scripts/python tests/e2e_segmenter.py
"""
from __future__ import annotations
import json
import sys
from collections import defaultdict
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from src.html_extract import read_input # noqa: E402
from src.predict import DubPredictor # noqa: E402
from src.release import predict_release # noqa: E402
from src.segmenter import is_test_release # noqa: E402
ROOT = Path(__file__).resolve().parents[1]
def run(predictor, rows, mode: str, test_only: bool) -> dict:
by_rel = defaultdict(list)
for r in rows:
by_rel[r["release_id"]].append(r)
per_src = defaultdict(list)
for page in sorted((ROOT / "data" / "pages").glob("*.txt")):
rid = page.stem
if is_test_release(rid) != test_only or rid not in by_rel:
continue
gold = {(r["translation_type"], r["studio"] or None) for r in by_rel[rid]}
res = predict_release(predictor, text=read_input(page), segmenter=mode)
pred = {(t["translation_type"], t["studio"]) for t in res["tracks"]}
tp = len(gold & pred)
p = tp / len(pred) if pred else 0.0
r = tp / len(gold) if gold else 0.0
per_src[by_rel[rid][0]["source"]].append((p, r))
out = {}
for s, v in per_src.items():
out[s] = (len(v), sum(x[0] for x in v) / len(v), sum(x[1] for x in v) / len(v))
return out
def main() -> None:
rows = json.loads((ROOT / "data" / "processed" / "dataset.json").read_text(encoding="utf-8"))
predictor = DubPredictor()
if predictor.segmenter is None:
sys.exit("нет models/segmenter: python -m src.segmenter --train")
for test_only, name in ((True, "тестовые страницы (не виделись сегментатору)"),
(False, "train-страницы (для справки, оптимистично)")):
print(f"== {name} ==")
for mode in ("rules", "model"):
res = run(predictor, rows, mode, test_only)
print(f" {mode:5s}: " + "; ".join(
f"{s} n={n} P={p:.3f} R={r:.3f}" for s, (n, p, r) in res.items()))
if __name__ == "__main__":
main()
+14
View File
@@ -301,5 +301,19 @@ _agg2 = aggregate([_t("проф. дубляж", "Продубляж"), _t("пр
check("aggregate: дорожка без студии того же типа схлопывается",
[x["translation_type"] for x in _agg2["tracks"]] == ["проф. дубляж", "проф. двухголосый"])
print("== сегментатор (модель) ==")
try:
from src.segmenter import LineSegmenter, is_test_release # noqa: E402
_seg = LineSegmenter("models/segmenter", "cpu")
_fx = open("data/samples/rt-topic-6870900.html", encoding="utf-8").read()
_lines = _seg.select_lines(html_to_text(_fx))
check("сегментатор: найдены 4 строки «Перевод N» реальной страницы",
sum(l.startswith("Перевод") for l in _lines) == 4, str(_lines[:5]))
check("сегментатор: «Субтитры» и «Оригинальная аудиодорожка» не дорожки",
not any(l.startswith(("Субтитры", "Оригинальная")) for l in _lines))
check("разбиение страниц детерминировано", is_test_release("6870900") == is_test_release("6870900"))
except Exception as e: # noqa: BLE001
print(f" пропущено (нет models/segmenter): {e}")
print(f"\nитог: {PASS} ok, {FAIL} failed")
sys.exit(1 if FAIL else 0)