OPEN SOURCE
software/scripts/review_output.py
Read on this site and download the files you need.
Nichijoyaku was created using AI. A complete review by human biblical-language and biblical-studies specialists has not been established. Read alongside established translations and original-language resources.
← Back to the open-source guide
1#!/usr/bin/env python32"""Produce a heuristic human-review queue; flags are not translation judgments."""3from __future__ import annotations45import argparse6import csv7import re8from collections import Counter, defaultdict9from pathlib import Path1011from verify_output import DEFAULT_BASELINE, DEFAULT_SOURCE, TRANSLATION, audit, read_baseline121314def review(rows, baseline):15duplicates = defaultdict(list)16for key, text in rows.items():17duplicates[(key[0], key[1], text.strip())].append(key[2])18for key, text in sorted(rows.items()):19flags = []20original = baseline.get(key, '')21if not re.search(r'[\u3040-\u30ff\u3400-\u9fff]', text):22flags.append('no-japanese')23if re.search(r'[\u0370-\u03ff\u0590-\u05ff\u1f00-\u1fff]', text):24flags.append('source-script')25if re.search(r'[A-Za-z]{2,}', text):26flags.append('latin-text')27if re.search(r'TODO|TBD|未翻訳|翻訳できません|翻訳は以下|翻訳結果|訳文:', text, re.I):28flags.append('placeholder-or-commentary')29if re.search(r'(.{8,}?)\1{2,}', text):30flags.append('repeated-phrase')31if len(duplicates[(key[0], key[1], text.strip())]) > 1:32flags.append('identical-within-chapter')33if len(text) < 5:34flags.append('very-short')35if original and len(original) >= 30 and len(text) < len(original) * 0.35:36flags.append('short-vs-kougo')37if original and len(text) > max(100, len(original) * 3):38flags.append('long-vs-kougo')39if flags:40yield {'book': key[0], 'chapter': key[1], 'verse': key[2],41'flags': ';'.join(flags), 'text': text, 'kougo_text': original}424344def main():45parser = argparse.ArgumentParser(description=__doc__)46parser.add_argument('--source', type=Path, default=DEFAULT_SOURCE)47parser.add_argument('--baseline', type=Path, default=DEFAULT_BASELINE)48parser.add_argument('--report', type=Path, required=True, help='Review CSV destination (outside source)')49args = parser.parse_args()50if args.report.resolve().is_relative_to(args.source.resolve()) or args.report.resolve() == args.baseline.resolve():51parser.error('report must not overwrite source data or baseline')52try:53baseline = read_baseline(args.baseline)54structural, rows = audit(args.source, baseline)55queue = list(review(rows, baseline))56args.report.parent.mkdir(parents=True, exist_ok=True)57with args.report.open('w', encoding='utf-8', newline='') as stream:58writer = csv.DictWriter(stream, fieldnames=['book', 'chapter', 'verse', 'flags', 'text', 'kougo_text'])59writer.writeheader()60writer.writerows(queue)61except (OSError, ValueError, csv.Error) as error:62parser.exit(2, f'Cannot review: {error}\n')63print(f'{TRANSLATION}: {len(queue)} verses flagged for human review')64for flag, count in sorted(Counter(flag for row in queue for flag in row['flags'].split(';')).items()):65print(f' {flag}: {count}')66print(f'Structural issues: {len(structural["issues"])} (run verify_output.py for details)')67print(f'Report: {args.report}')68return 0 if structural['passed'] else 1697071if __name__ == '__main__':72raise SystemExit(main())73