OPEN SOURCE
tools/collect-provenance.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"""Export hash-matched historical outputs and an allowlisted input inventory.23Never export user prompts: they embed separately licensed reference translations.4System prompts are project-authored instructions, deduplicated by SHA-256.5"""6import argparse7from collections import Counter8import hashlib9import json10from pathlib import Path111213def digest(raw):14return hashlib.sha256(raw).hexdigest()151617def collect(source, audit, destination, recovered=None):18destination.mkdir(parents=True, exist_ok=True)19records, systems, chapters = [], {}, []20source_names = Counter()21with_prompts = 022unavailable = []23for name, expected in sorted(audit['input_files'].items()):24path = source / name25origin = 'current source output'26if (not path.is_file() or digest(path.read_bytes()) != expected) and recovered is not None:27candidate = recovered / name28if candidate.is_file() and digest(candidate.read_bytes()) == expected:29path = candidate30origin = 'recovered historical source output; exact audit hash match'31if not path.is_file() or digest(path.read_bytes()) != expected:32unavailable.append({'file': name, 'expected_sha256': expected, 'status': 'changed' if path.is_file() else 'missing'})33continue34chapter = json.loads(path.read_bytes())35chapters.append({'file': name, 'sha256': expected, 'origin': origin})36for verse, saved in sorted(chapter['verses'].items(), key=lambda item: int(item[0])):37row = {'reference': f"{chapter['book']}:{chapter['chapter']}:{verse}",38'source_file': name, 'output_kind': 'saved parsed translation, not raw model response'}39for field in ('text', 'text_with_furigana', 'model', 'timestamp', 'prompt_version', 'sources_used'):40row[field] = saved.get(field)41provenance = saved.get('provenance')42if provenance:43system = provenance.get('system_prompt', '')44user = provenance.get('user_prompt', '')45systems[digest(system.encode())] = system46row['input'] = {'system_prompt_sha256': digest(system.encode()),47'user_prompt_sha256': digest(user.encode()),48'user_prompt_characters': len(user),49'user_prompt_status': 'retained privately; embeds separately licensed Bible text',50'source_text_sha256': {k: digest(v.encode()) for k, v in provenance.get('source_texts', {}).items()},51'reference_labels_in_prompt': [label for label in ('口語訳 (1955)', 'KJV', 'ASV', '明治訳', '大正訳') if label in user]}52for field in ('started_at', 'completed_at', 'attempt_number', 'style_config_hash', 'glossary_hash'):53row['input'][field] = provenance.get(field)54with_prompts += bool(system and user)55source_names.update(row['input']['reference_labels_in_prompt'])56else:57row['input'] = None58records.append(row)59for name, value in [('outputs.jsonl', ''.join(json.dumps(r, ensure_ascii=False) + '\n' for r in records)),60('system-prompts.json', json.dumps(systems, ensure_ascii=False, indent=2)+'\n')]:61(destination/name).write_text(value)62report = {'schema': 1, 'edition': 'nichijo-v1', 'chapters': len(chapters), 'source_records': len(records),63'records_with_retained_prompts': with_prompts, 'records_without_retained_prompts': len(records)-with_prompts,64'reference_labels_in_retained_prompts': dict(source_names), 'system_prompts': len(systems),65'limits': ['Only chapter files matching the immutable release audit are included.',66'Saved parsed output is not the complete raw model response.',67'Input records are absent for chunk translations; absence is not proof that reference text was excluded.',68'Historical prompts include reference translations; a no-reference-input claim is contradicted by these records.',69'Model and source labels are saved local metadata, not independently verified provider records.',70'Exact user prompts remain private because they embed separately licensed Bible text. Hashes permit later verification.'],71'source_files': chapters, 'unavailable_files': unavailable,72'files': {p.name: digest(p.read_bytes()) for p in (destination/'outputs.jsonl', destination/'system-prompts.json')}}73(destination/'index.json').write_text(json.dumps(report, ensure_ascii=False, indent=2)+'\n')74return report757677if __name__ == '__main__':78parser=argparse.ArgumentParser()79parser.add_argument('--source-output', type=Path, required=True)80parser.add_argument('--audit', type=Path, required=True)81parser.add_argument('--destination', type=Path, required=True)82parser.add_argument('--recovered-output', type=Path)83args=parser.parse_args()84report=collect(args.source_output,json.loads(args.audit.read_text()),args.destination,args.recovered_output)85print(json.dumps({k:v for k,v in report.items() if k not in ('source_files','files')},ensure_ascii=False,indent=2))86