#!/usr/bin/env python3 """Produce a heuristic human-review queue; flags are not translation judgments.""" from __future__ import annotations import argparse import csv import re from collections import Counter, defaultdict from pathlib import Path from verify_output import DEFAULT_BASELINE, DEFAULT_SOURCE, TRANSLATION, audit, read_baseline def review(rows, baseline): duplicates = defaultdict(list) for key, text in rows.items(): duplicates[(key[0], key[1], text.strip())].append(key[2]) for key, text in sorted(rows.items()): flags = [] original = baseline.get(key, '') if not re.search(r'[\u3040-\u30ff\u3400-\u9fff]', text): flags.append('no-japanese') if re.search(r'[\u0370-\u03ff\u0590-\u05ff\u1f00-\u1fff]', text): flags.append('source-script') if re.search(r'[A-Za-z]{2,}', text): flags.append('latin-text') if re.search(r'TODO|TBD|未翻訳|翻訳できません|翻訳は以下|翻訳結果|訳文:', text, re.I): flags.append('placeholder-or-commentary') if re.search(r'(.{8,}?)\1{2,}', text): flags.append('repeated-phrase') if len(duplicates[(key[0], key[1], text.strip())]) > 1: flags.append('identical-within-chapter') if len(text) < 5: flags.append('very-short') if original and len(original) >= 30 and len(text) < len(original) * 0.35: flags.append('short-vs-kougo') if original and len(text) > max(100, len(original) * 3): flags.append('long-vs-kougo') if flags: yield {'book': key[0], 'chapter': key[1], 'verse': key[2], 'flags': ';'.join(flags), 'text': text, 'kougo_text': original} def main(): parser = argparse.ArgumentParser(description=__doc__) parser.add_argument('--source', type=Path, default=DEFAULT_SOURCE) parser.add_argument('--baseline', type=Path, default=DEFAULT_BASELINE) parser.add_argument('--report', type=Path, required=True, help='Review CSV destination (outside source)') args = parser.parse_args() if args.report.resolve().is_relative_to(args.source.resolve()) or args.report.resolve() == args.baseline.resolve(): parser.error('report must not overwrite source data or baseline') try: baseline = read_baseline(args.baseline) structural, rows = audit(args.source, baseline) queue = list(review(rows, baseline)) args.report.parent.mkdir(parents=True, exist_ok=True) with args.report.open('w', encoding='utf-8', newline='') as stream: writer = csv.DictWriter(stream, fieldnames=['book', 'chapter', 'verse', 'flags', 'text', 'kougo_text']) writer.writeheader() writer.writerows(queue) except (OSError, ValueError, csv.Error) as error: parser.exit(2, f'Cannot review: {error}\n') print(f'{TRANSLATION}: {len(queue)} verses flagged for human review') for flag, count in sorted(Counter(flag for row in queue for flag in row['flags'].split(';')).items()): print(f' {flag}: {count}') print(f'Structural issues: {len(structural["issues"])} (run verify_output.py for details)') print(f'Report: {args.report}') return 0 if structural['passed'] else 1 if __name__ == '__main__': raise SystemExit(main())