Обученный сегментатор страниц (главный путь), правила — запасной; фикстура rt-topic-6870900
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
1 parent
96e5fa0d75
commit
d155b8584b
7 files changed
+1257
-4
No files matched your search
@@ -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()
|
||||
@@ -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)
|
||||
Reference in new issue
Block a user