Download code/src/preprocessing/quality_gate.py from savastakan/hitit-cuneiform-ocr: direct link, hf CLI and curl.
- Browser
- Download file 3.45 kB
-
https://huggingface.co/savastakan/hitit-cuneiform-ocr/resolve/main/code/src/preprocessing/quality_gate.py
- Command line
-
hf download hf://savastakan/hitit-cuneiform-ocr/code/src/preprocessing/quality_gate.py
-
curl -L -o quality_gate.py https://huggingface.co/savastakan/hitit-cuneiform-ocr/resolve/main/code/src/preprocessing/quality_gate.py
3.45 kB
| #!/usr/bin/env python3 | |
| """Quality gate — preprocessing.yaml thresholds uygulama. | |
| Her kayda quality_gate_pass (bool) + quality_gate_reasons (list) ekler. | |
| """ | |
| import json, yaml | |
| from pathlib import Path | |
| from collections import Counter | |
| ROOT = Path("/arf/scratch/stakan/hitit-proje") | |
| SOURCES = ROOT / "datasets" / "sources" | |
| def main(): | |
| cfg = yaml.safe_load(open(ROOT / "hitit_ocr" / "configs" / "preprocessing.yaml")) | |
| gates = cfg['quality_gates'] | |
| blur_min = gates['blur_laplacian_min_variance'] | |
| exp_min = gates['exposure_mean_min'] | |
| exp_max = gates['exposure_mean_max'] | |
| cont_min = gates['contrast_std_min'] | |
| w_min = gates['resolution_min_w'] | |
| h_min = gates['resolution_min_h'] | |
| total = 0 | |
| passed = 0 | |
| reason_counts = Counter() | |
| for d in sorted(SOURCES.iterdir()): | |
| if not d.is_dir(): continue | |
| for mf in ['manifest.jsonl', 'manifest_classification.jsonl', 'manifest_detection.jsonl']: | |
| mp = d / mf | |
| if not mp.exists(): continue | |
| records = [] | |
| with open(mp) as f: | |
| for line in f: | |
| r = json.loads(line) | |
| reasons = [] | |
| # Sadece integrity_ok=True olanlara uygula; diğerleri None bırak | |
| if r.get('integrity_ok') is True: | |
| blur = r.get('blur_score') | |
| expo = r.get('exposure_mean') | |
| cont = r.get('contrast_std') | |
| w = r.get('width') | |
| h = r.get('height') | |
| if blur is not None and blur < blur_min: | |
| reasons.append('blur') | |
| if expo is not None and (expo < exp_min or expo > exp_max): | |
| reasons.append('exposure') | |
| if cont is not None and cont < cont_min: | |
| reasons.append('contrast') | |
| if w and w < w_min: | |
| reasons.append('width') | |
| if h and h < h_min: | |
| reasons.append('height') | |
| r['quality_gate_pass'] = len(reasons) == 0 | |
| r['quality_gate_reasons'] = reasons | |
| if mf == 'manifest.jsonl': | |
| total += 1 | |
| if r['quality_gate_pass']: passed += 1 | |
| for rr in reasons: reason_counts[rr] += 1 | |
| else: | |
| r['quality_gate_pass'] = None | |
| r['quality_gate_reasons'] = None | |
| records.append(r) | |
| with open(mp, 'w') as f: | |
| for r in records: | |
| f.write(json.dumps(r, ensure_ascii=False) + '\n') | |
| print(f"Total: {total:,}, passed: {passed:,} (%{100*passed/max(1,total):.1f})") | |
| print(f"Fail reasons:") | |
| for rr, n in reason_counts.most_common(): | |
| print(f" {rr}: {n:,}") | |
| with open(ROOT / "datasets" / "processed" / "quality_gate_report.json", 'w') as f: | |
| json.dump({ | |
| "config_version": cfg['version'], | |
| "thresholds": gates, | |
| "total_scored": total, | |
| "passed": passed, | |
| "pass_rate": round(100*passed/max(1,total), 2), | |
| "fail_reasons": dict(reason_counts), | |
| }, f, indent=2, ensure_ascii=False) | |
| if __name__ == '__main__': | |
| main() | |