Glazkov commited on
Commit
fc70dae
·
verified ·
1 Parent(s): 1f01927

Add examples/batch.py

Browse files
Files changed (1) hide show
  1. examples/batch.py +81 -0
examples/batch.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Batch extraction over a directory of table-cropped images.
2
+
3
+ Looks for ``<stem>.md`` alongside each image; if found, passes its contents
4
+ as the ``markdown`` disambiguator. Without markdown the model picks an
5
+ arbitrary plausible table and quality drops significantly.
6
+
7
+ Usage:
8
+ python examples/batch.py <image_dir> [--preset quality|fast] [--out results.jsonl]
9
+ """
10
+
11
+ import argparse
12
+ import json
13
+ import sys
14
+ import time
15
+ from pathlib import Path
16
+
17
+ sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
18
+
19
+ from inference import PRESETS, StructuredExtractor
20
+
21
+ CHECKPOINT = "Glazkov/structured-extractor-qwen3vl-4b-exp93"
22
+ IMAGE_EXTS = {".png", ".jpg", ".jpeg", ".webp", ".bmp", ".tif", ".tiff"}
23
+
24
+
25
+ def parse_args() -> argparse.Namespace:
26
+ p = argparse.ArgumentParser(description=__doc__)
27
+ p.add_argument("image_dir", type=Path, help="Directory with table-crop images")
28
+ p.add_argument(
29
+ "--preset",
30
+ choices=list(PRESETS),
31
+ default="quality",
32
+ help="quality (beam=4 + rp=1.1), balanced (beam=4), fast (greedy). Default: quality.",
33
+ )
34
+ p.add_argument(
35
+ "--out",
36
+ type=Path,
37
+ default=Path("results.jsonl"),
38
+ help="Path to JSONL output file (one record per image).",
39
+ )
40
+ return p.parse_args()
41
+
42
+
43
+ def main() -> None:
44
+ args = parse_args()
45
+ paths = sorted(p for p in args.image_dir.iterdir() if p.suffix.lower() in IMAGE_EXTS)
46
+ if not paths:
47
+ sys.exit(f"No images found in {args.image_dir}")
48
+
49
+ markdowns: list[str | None] = []
50
+ for p in paths:
51
+ md_path = p.with_suffix(".md")
52
+ markdowns.append(md_path.read_text(encoding="utf-8") if md_path.exists() else None)
53
+ print(f"Loaded {sum(1 for m in markdowns if m)}/{len(paths)} markdown sidecars.")
54
+
55
+ print(f"Loading checkpoint {CHECKPOINT} ...")
56
+ extractor = StructuredExtractor.from_pretrained(CHECKPOINT)
57
+
58
+ print(f"Running '{args.preset}' over {len(paths)} images ...")
59
+ t0 = time.time()
60
+ results = extractor.extract_batch(
61
+ paths,
62
+ preset=args.preset,
63
+ markdown_batch=markdowns,
64
+ batch_size=1,
65
+ return_raw=False,
66
+ )
67
+ elapsed = time.time() - t0
68
+
69
+ with args.out.open("w", encoding="utf-8") as f:
70
+ for path, result in zip(paths, results):
71
+ record = {"image": str(path), "parameters": result["parameters"]}
72
+ f.write(json.dumps(record, ensure_ascii=False) + "\n")
73
+
74
+ print(
75
+ f"\nDone in {elapsed:.1f}s ({elapsed / len(paths):.2f}s/image). "
76
+ f"Wrote {len(paths)} records to {args.out}"
77
+ )
78
+
79
+
80
+ if __name__ == "__main__":
81
+ main()