diff --git a/_aj_base.log b/_aj_base.log deleted file mode 100644 index fbc898a..0000000 --- a/_aj_base.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2 -page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2 -page 3: 14 crops, 7 datelines | bullet titles flagged:1 -page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2 -DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final diff --git a/_aj_val.log b/_aj_val.log deleted file mode 100644 index fbc898a..0000000 --- a/_aj_val.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2 -page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2 -page 3: 14 crops, 7 datelines | bullet titles flagged:1 -page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2 -DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final diff --git a/_aj_val2.log b/_aj_val2.log deleted file mode 100644 index fbc898a..0000000 --- a/_aj_val2.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2 -page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2 -page 3: 14 crops, 7 datelines | bullet titles flagged:1 -page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2 -DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final diff --git a/_aj_val3.log b/_aj_val3.log deleted file mode 100644 index fbc898a..0000000 --- a/_aj_val3.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2 -page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2 -page 3: 14 crops, 7 datelines | bullet titles flagged:1 -page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2 -DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final diff --git a/_aj_val4.log b/_aj_val4.log deleted file mode 100644 index fbc898a..0000000 --- a/_aj_val4.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2 -page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2 -page 3: 14 crops, 7 datelines | bullet titles flagged:1 -page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2 -DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final diff --git a/_aj_val5.log b/_aj_val5.log deleted file mode 100644 index fbc898a..0000000 --- a/_aj_val5.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 12 crops, 9 datelines | Headline-strip:2, Floor-trim:2, orphan overlap:2 -page 2: 18 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2 -page 3: 14 crops, 7 datelines | bullet titles flagged:1 -page 4: 21 crops, 18 datelines | bullet titles flagged:1, Headline-strip:2, Block dateline split:2, Multi-column body:2 -DONE -> output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_final diff --git a/_cls.txt b/_cls.txt deleted file mode 100644 index 527b674..0000000 --- a/_cls.txt +++ /dev/null @@ -1,4 +0,0 @@ -R16 text bbox=[119, 616, 612, 1899] phones=3 kw=[] :: జనగామ, మే 19 (నమస్తే తెలంగాణ) : ఆల్‌ ఇండియా కెమిస్ -R89 paragraph_title bbox=[121, 2887, 595, 2978] phones=0 kw=['in the court'] :: IN THE COURT OF THE HONBLE JUNIOR CIVIL JUDGE AT G -R93 text bbox=[174, 4010, 545, 4080] phones=1 kw=['advocate'] :: ADVOCATE - JANGAON Cell: 9848259371 -R87 text bbox=[150, 5143, 604, 6267] phones=8 kw=['classified', 'contact'] :: For Classified Ads Please Contact... 9182777552 HA diff --git a/_cmp_mc.py b/_cmp_mc.py deleted file mode 100644 index c14c410..0000000 --- a/_cmp_mc.py +++ /dev/null @@ -1,34 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") - - -def blocks_for(pg, strip_mc): - png = D / f"page_{pg:03d}.png" - regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"] - regs = se.drop_masthead_regions(regs, "andhra_jyothi", pg, png) - ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi") - bars = separator_barriers(str(png), regs) - if strip_mc: - bars = [{k: v for k, v in b.items() if k not in ("mc", "anchor")} for b in bars] - bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars) - return {b["anchor_id"]: tuple(sorted(b["members"])) for b in bl} - - -for pg in (1, 2, 3, 4): - with contextlib.redirect_stdout(io.StringIO()): - cur = blocks_for(pg, False) - base = blocks_for(pg, True) - print(f"==== PAGE {pg} ====") - changed = False - for k in sorted(set(cur) | set(base)): - if cur.get(k) != base.get(k): - changed = True - print(f" anchor {k}: base={base.get(k)}") - print(f" curr={cur.get(k)}") - if not changed: - print(" (no change from mc clamp)") diff --git a/_dump_all.py b/_dump_all.py deleted file mode 100644 index 463403b..0000000 --- a/_dump_all.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys, json -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -png = D / "page_001.png" -regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"] -regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png) -ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi") -bars = separator_barriers(str(png), regs) -bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars) -allmem = set() -for b in sorted(bl, key=lambda b: (b["bbox"][1], b["bbox"][0])): - allmem |= set(b["members"]) - print(f" {b['kind']:>1} anchor={b['anchor_id']:>3} bbox={b['bbox']} members={sorted(b['members'])}") -present = {r["id"] for r in regs if r.get("type") not in ("header","number")} -print("MISSING (not in any block):", sorted(present - allmem)) diff --git a/_gap_probe.py b/_gap_probe.py deleted file mode 100644 index e75f420..0000000 --- a/_gap_probe.py +++ /dev/null @@ -1,40 +0,0 @@ -import sys, json -sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor") -from pathlib import Path -import smart_extractor as se - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") - -def headline_above(regions, start_bboxes, body, max_gap): - cx = (body[0] + body[2]) / 2 - cands = [r for r in regions - if (r.get("type") == "doc_title" or r.get("_promoted_from")) - and r["bbox"][0] <= cx <= r["bbox"][2] - and r["bbox"][3] <= body[1] + 40 - and (body[1] - r["bbox"][3]) <= max_gap] - if not cands: - return None, None - h = max(cands, key=lambda r: r["bbox"][3]) - gap = body[1] - h["bbox"][3] - for ob in start_bboxes: - if ob is body: - continue - ocx = (ob[0] + ob[2]) / 2 - if h["bbox"][3] < ob[1] < body[1] and cx - 120 <= ocx <= cx + 120: - return None, gap - return h["id"], gap - -for pg in (1, 2, 3, 4): - png = D / f"page_{pg:03d}.png" - regions = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"] - regions = se.drop_masthead_regions(regions, "andhra_jyothi", pg, png) - ds = se.find_article_starts_by_dateline(regions, str(png), "andhra_jyothi") - sb = [s["bbox"] for s in ds] - print(f"\n==== PAGE {pg} ====") - for s in ds: - rid = s["region_id"] - row = [] - for g in (900, 1000, 1100, 1300): - hid, gap = headline_above(regions, sb, s["bbox"], g) - row.append(f"g{g}:R{hid}" ) - print(f" DL R{rid:>3} gap_to_nearest_doc_title above -> " + " ".join(row)) diff --git a/_jg_base.log b/_jg_base.log deleted file mode 100644 index 0865293..0000000 --- a/_jg_base.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1483,838,4073,3081] 2590x2243 mem=13 {'text': 8, 'image': 3, 'figure_title': 2} - R 4 DL bbox=[105,846,1467,4295] 1362x3449 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,3089,3031,4921] 1533x1832 mem=13 {'text': 8, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1} - R 2 DL bbox=[3039,3957,4081,6269] 1042x2312 mem=4 {'text': 2, 'image': 1, 'figure_title': 1} - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,3211,6283] 1711x1271 mem=5 {'doc_title': 1, 'text': 2, 'figure_title': 1, 'image': 1} - [Containment-merge] x4 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val.log b/_jg_val.log deleted file mode 100644 index 7b02133..0000000 --- a/_jg_val.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3} - R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val2.log b/_jg_val2.log deleted file mode 100644 index 7b02133..0000000 --- a/_jg_val2.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3} - R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val3.log b/_jg_val3.log deleted file mode 100644 index eb07770..0000000 --- a/_jg_val3.log +++ /dev/null @@ -1,38 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3} - R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 78 F bbox=[123,4139,626,4285] 503x146 mem=1 {'image': 1} IMG-ONLY(no text) SINGLE-region - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 82 F bbox=[137,4423,618,4782] 481x359 mem=2 {'text': 1, 'paragraph_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R 44 F bbox=[133,4811,616,5113] 483x302 mem=1 {'text': 1} SINGLE-region - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val4.log b/_jg_val4.log deleted file mode 100644 index 7b02133..0000000 --- a/_jg_val4.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3} - R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val5.log b/_jg_val5.log deleted file mode 100644 index 7b02133..0000000 --- a/_jg_val5.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3} - R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val6.log b/_jg_val6.log deleted file mode 100644 index 7b02133..0000000 --- a/_jg_val6.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3} - R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val7.log b/_jg_val7.log deleted file mode 100644 index 4f92a23..0000000 --- a/_jg_val7.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=8 {'text': 7, 'image': 1} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,838,3031,4921] 1533x4083 mem=18 {'doc_title': 1, 'text': 9, 'image': 3, 'paragraph_title': 2, 'figure_title': 3} - R 2 DL bbox=[3039,3957,4081,5748] 1042x1791 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4087,1833] 1394x1428 mem=12 {'doc_title': 1, 'text': 7, 'image': 2, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=2 {'doc_title': 1, 'text': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,2023,2859] 1910x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[113,5731,3267,6318] 3154x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val8.log b/_jg_val8.log deleted file mode 100644 index 6baa4dc..0000000 --- a/_jg_val8.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=13 {'text': 8, 'image': 3, 'figure_title': 2} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,3089,3031,4921] 1533x1832 mem=13 {'doc_title': 1, 'text': 8, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 2 DL bbox=[3092,3957,4079,4960] 987x1003 mem=1 {'text': 1} SINGLE-region - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=8 {'text': 3, 'image': 2, 'doc_title': 1, 'figure_title': 2} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4078,1567] 1385x1162 mem=11 {'doc_title': 1, 'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=3 {'text': 1, 'image': 1, 'doc_title': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260609_130635/all_article_crops_review diff --git a/_jg_val8b.log b/_jg_val8b.log deleted file mode 100644 index d04f320..0000000 --- a/_jg_val8b.log +++ /dev/null @@ -1,36 +0,0 @@ - -=== page 1: 6 crops, 6 datelines === - R 3 DL bbox=[1497,137,4081,3023] 2584x2886 mem=13 {'text': 8, 'image': 3, 'figure_title': 2} - R 4 DL bbox=[105,145,1467,4295] 1362x4150 mem=15 {'text': 11, 'image': 2, 'paragraph_title': 2} - R 28 H bbox=[1498,3089,3031,4921] 1533x1832 mem=13 {'doc_title': 1, 'text': 8, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 2 DL bbox=[3092,3957,4079,4960] 987x1003 mem=1 {'text': 1} SINGLE-region - R 49 H RAW bbox=[106,4377,1429,6301] 1323x1924 mem=10 {'doc_title': 1, 'text': 5, 'image': 2, 'figure_title': 2} - R 29 H RAW bbox=[1500,5012,4081,6283] 2581x1271 mem=8 {'text': 3, 'image': 2, 'doc_title': 1, 'figure_title': 2} - [Containment-merge] x2 - [Headline-merge] x2 - [Banner rectangle] x4 - -=== page 2: 18 crops, 17 datelines === - R109 H bbox=[119,393,612,1899] 493x1506 mem=2 {'doc_title': 1, 'text': 1} - R 79 H bbox=[2693,405,4078,1567] 1385x1162 mem=11 {'doc_title': 1, 'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 55 H RAW bbox=[679,415,2630,1919] 1951x1504 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 2, 'figure_title': 1} - R 77 H bbox=[2692,1594,4087,1903] 1395x309 mem=3 {'text': 1, 'image': 1, 'doc_title': 1} - R 14 DL bbox=[2045,1950,3265,3097] 1220x1147 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 65 H bbox=[113,1958,1975,2859] 1862x901 mem=8 {'text': 5, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 96 H bbox=[3326,1964,4087,3638] 761x1674 mem=4 {'doc_title': 1, 'text': 2, 'image': 1} - R 89 L bbox=[118,2887,595,4080] 477x1193 mem=5 {'text': 4, 'paragraph_title': 1} - R 86 H bbox=[682,2894,1977,4292] 1295x1398 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 2, 'doc_title': 1} - R 64 H bbox=[2046,3116,3263,3907] 1217x791 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 97 H bbox=[3324,3756,4087,4627] 763x871 mem=2 {'doc_title': 1, 'text': 1} - R 84 H bbox=[2046,3920,3264,4820] 1218x900 mem=6 {'text': 3, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 44 F bbox=[123,4139,626,5113] 503x974 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R112 H bbox=[682,4325,1975,5056] 1293x731 mem=5 {'text': 2, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 58 H bbox=[3322,4658,4087,5831] 765x1173 mem=2 {'doc_title': 1, 'text': 1} - R110 H bbox=[2044,4858,3265,5685] 1221x827 mem=7 {'doc_title': 1, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 75 H RAW bbox=[680,5078,1975,5692] 1295x614 mem=5 {'doc_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R 59 H RAW bbox=[680,5731,3267,6318] 2587x587 mem=7 {'doc_title': 2, 'text': 5} - R 7 DL bbox=[3308,5839,4087,6305] 779x466 mem=1 {'text': 1} SINGLE-region - [Containment-merge] x10 - [Banner rectangle] x8 - -DONE -> output/NamastheTelangana_Jangaon_20260520_20260608_124720/all_article_crops_review diff --git a/_lc3.txt b/_lc3.txt deleted file mode 100644 index 9544705..0000000 --- a/_lc3.txt +++ /dev/null @@ -1,10 +0,0 @@ -AJ pg1: 12 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -AJ pg2: 18 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -AJ pg3: 14 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -AJ pg4: 20 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -NT pg1: 11 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -NT pg2: 22 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -NT pg3: 19 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -NT pg4: 24 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -JG pg1: 7 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) -JG pg2: 12 blocks (baseline AJ 12/18/14/20 NT 11/22/19/25 JG 7/12) diff --git a/_lencheck.txt b/_lencheck.txt deleted file mode 100644 index fe769c9..0000000 --- a/_lencheck.txt +++ /dev/null @@ -1,10 +0,0 @@ -AJ pg1 pitch755 hbars10 base12 | thr0.6: 12 (drop6) | thr0.8: 12 (drop7) | thr1.0: 12 (drop7) -AJ pg2 pitch719 hbars19 base18 | thr0.6: 18 (drop5) | thr0.8: 18 (drop8) | thr1.0: 18 (drop9) -AJ pg3 pitch728 hbars15 base14 | thr0.6: 14 (drop7) | thr0.8: 13 (drop9) | thr1.0: 13 (drop9) -AJ pg4 pitch728 hbars25 base20 | thr0.6: 20 (drop11) | thr0.8: 20 (drop13) | thr1.0: 20 (drop13) -NT pg1 pitch536 hbars24 base11 | thr0.6: 11 (drop5) | thr0.8: 11 (drop8) | thr1.0: 11 (drop9) -NT pg2 pitch527 hbars47 base22 | thr0.6: 22 (drop7) | thr0.8: 22 (drop10) | thr1.0: 22 (drop15) -NT pg3 pitch525 hbars25 base19 | thr0.6: 19 (drop3) | thr0.8: 19 (drop4) | thr1.0: 19 (drop7) -NT pg4 pitch523 hbars43 base25 | thr0.6: 25 (drop5) | thr0.8: 25 (drop8) | thr1.0: 21 (drop25) -JG pg1 pitch601 hbars15 base7 | thr0.6: 7 (drop5) | thr0.8: 7 (drop6) | thr1.0: 7 (drop9) -JG pg2 pitch594 hbars17 base12 | thr0.6: 12 (drop0) | thr0.8: 12 (drop0) | thr1.0: 12 (drop9) diff --git a/_lencheck2.txt b/_lencheck2.txt deleted file mode 100644 index e69de29..0000000 diff --git a/_lines.py b/_lines.py deleted file mode 100644 index 024b1dc..0000000 --- a/_lines.py +++ /dev/null @@ -1,416 +0,0 @@ -"""Separator-rule detection for newspaper pages (classical CV, no ML / no API). - -Detects the thin printed grey/black straight lines the paper uses to divide -stories, with a TEXT-ISOLATION filter to reject false positives from dense -Telugu text (a real rule sits in a whitespace gutter; a text stroke has ink -immediately above/below it). - -Public: - detect_separator_lines(png_path) -> {"h": [...], "v": [...], "size": (W,H)} - each line is a dict: {x1,y1,x2,y2,len,gray} (gray = mean intensity). -""" -import cv2 -import numpy as np - - -def _candidates(bw, horizontal, min_len, max_thick=55): - if horizontal: - k = cv2.getStructuringElement(cv2.MORPH_RECT, (min_len // 2, 1)) - else: - k = cv2.getStructuringElement(cv2.MORPH_RECT, (1, min_len // 2)) - opened = cv2.morphologyEx(bw, cv2.MORPH_OPEN, k, iterations=1) - # bridge small collinear gaps along the line direction - if horizontal: - opened = cv2.dilate(opened, cv2.getStructuringElement(cv2.MORPH_RECT, (25, 3))) - else: - opened = cv2.dilate(opened, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 25))) - cnts, _ = cv2.findContours(opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - out = [] - for c in cnts: - x, y, w, h = cv2.boundingRect(c) - if horizontal and w >= min_len and h <= max_thick: - out.append((x, y + h // 2, x + w, y + h // 2, w)) - if (not horizontal) and h >= min_len and w <= max_thick: - out.append((x + w // 2, y, x + w // 2, y + h, h)) - return out - - -def _isolated(gray, line, horizontal, ink_thresh=110, gap=(5, 16), - max_adjacent_ink=0.12): - """A true separator sits in a whitespace gutter: the tight band on BOTH sides - (parallel to the line) is mostly paper. Returns (is_isolated, mean_gray).""" - H, W = gray.shape - x1, y1, x2, y2, ln = line - if horizontal: - seg = gray[y1, x1:x2] - lo, hi = gap - above = gray[max(0, y1 - hi):max(0, y1 - lo), x1:x2] - below = gray[min(H, y1 + lo):min(H, y1 + hi), x1:x2] - else: - seg = gray[y1:y2, x1] - lo, hi = gap - above = gray[y1:y2, max(0, x1 - hi):max(0, x1 - lo)] - below = gray[y1:y2, min(W, x1 + lo):min(W, x1 + hi)] - if seg.size == 0 or above.size == 0 or below.size == 0: - return False, 255 - ink_a = float((above < ink_thresh).mean()) - ink_b = float((below < ink_thresh).mean()) - isolated = (ink_a <= max_adjacent_ink) and (ink_b <= max_adjacent_ink) - return isolated, float(seg.mean()) - - -def detect_separator_lines(png_path, h_frac=0.045, v_frac=0.06): - img = cv2.imread(str(png_path)) - gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - H, W = gray.shape - blur = cv2.GaussianBlur(gray, (3, 3), 0) - bw = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] - - h_min = int(h_frac * W) - v_min = int(v_frac * H) - h_out, v_out = [], [] - for ln in _candidates(bw, True, h_min): - iso, g = _isolated(gray, ln, True) - if iso: - h_out.append({"x1": ln[0], "y1": ln[1], "x2": ln[2], "y2": ln[3], - "len": ln[4], "gray": round(g, 1)}) - for ln in _candidates(bw, False, v_min): - iso, g = _isolated(gray, ln, False) - if iso: - v_out.append({"x1": ln[0], "y1": ln[1], "x2": ln[2], "y2": ln[3], - "len": ln[4], "gray": round(g, 1)}) - return {"h": h_out, "v": v_out, "size": (W, H)} - - -def detect_content_bottom(png_path, search_frac=0.12, color_thr=0.06, - blank_color=0.02, blank_ink=0.035, peak_thr=0.15, - max_band=160, min_gap=25, min_margin=18): - """Find the y below which a page holds only the printer's COLOUR-CALIBRATION - strip (the row of CMYK registration dots + grey bars) and the bottom paper - margin — i.e. the bottom of real article content. - - The calibration strip is a thin band of strongly-saturated colour dots near - the page bottom, isolated by a white paper margin BELOW it (down to the page - edge) and a white gap ABOVE it (separating it from article content). Crops - should be clamped to the returned y so the dots never bleed into an article. - - Returns the y at the TOP of the calibration band, or the full page height H - when no such strip is found (nothing to clamp).""" - img = cv2.imread(str(png_path)) - if img is None: - return None - H, W = img.shape[:2] - b, g, r = img[..., 0].astype(np.int16), img[..., 1].astype(np.int16), img[..., 2].astype(np.int16) - mx = np.maximum(np.maximum(r, g), b) - mn = np.minimum(np.minimum(r, g), b) - sat = mx - mn - colored = (sat > 55) & (mx > 80) # saturated colour (registration dots) - dark = mx < 110 # ink / dark - col_frac = colored.mean(axis=1) # per-row colour fraction - ink_frac = dark.mean(axis=1) # per-row ink fraction - blank = (col_frac < blank_color) & (ink_frac < blank_ink) - - y0 = int(H * (1 - search_frac)) - # The calibration strip is a band of strongly-coloured rows; identify it as the - # bottom-most run of rows whose colour fraction clears `color_thr`. - strip_rows = [y for y in range(y0, H) if col_frac[y] >= color_thr] - if not strip_rows: - return H # no coloured strip near the bottom - band_bottom = strip_rows[-1] - # A real calibration strip is followed by white paper margin to the page edge. - below = blank[band_bottom + 1:H] - if below.size < min_margin or float(below.mean()) < 0.9: - return H - # Walk up from band_bottom while still in the coloured band (tolerate the small - # white gaps between dot rows). - band_top = band_bottom - gap = 0 - y = band_bottom - 1 - while y > y0: - if col_frac[y] >= color_thr: - band_top = y - gap = 0 - else: - gap += 1 - if gap > 12: - break - y -= 1 - if (band_bottom - band_top + 1) > max_band: - return H # too tall -> fused with a photo, bail - # A genuine printer calibration strip is a dense row of saturated CMYK - # registration dots: its peak per-row colour fraction is high (~0.22-0.45 across - # Andhra Jyothi / Sakshi). A single-hue coloured ad/notice box embedded in - # article text peaks far lower (~0.11) -> reject it as a false positive. - peak = float(col_frac[band_top:band_bottom + 1].max()) - if peak < peak_thr: - return H - return band_top - - -def _hspan_overlap(ax1, ax2, bx1, bx2): - ix = max(0, min(ax2, bx2) - max(ax1, bx1)) - return ix / max(1, min(ax2 - ax1, bx2 - bx1)) - - -def _faint_rule_above(gray, hbbox, max_gap=170, min_gap=6, gray_lo=140, gray_hi=215, - cover=0.6, max_dark=0.06): - """Find a faint GREY horizontal rule sitting in the whitespace directly above a - (multi-column) header. Such a light rule reads as background to the ink-based - Otsu detector in `detect_separator_lines`, so we look for a thin row that is - mostly uniform mid-grey across the header's width and is isolated by white paper - above and below. Returns the rule's y, or None. (Used only above multi-column - headers, where it marks the article's TOP boundary.)""" - H, W = gray.shape - hx1, hy, hx2 = hbbox[0], hbbox[1], hbbox[2] - y_hi = max(0, hy - min_gap) - y_lo = max(0, hy - max_gap) - for y in range(y_hi, y_lo, -1): - row = gray[y, hx1:hx2].astype(np.int16) - if row.size == 0: - continue - mid = float(((row >= gray_lo) & (row <= gray_hi)).mean()) - dark = float((row < gray_lo).mean()) - if mid >= cover and dark <= max_dark: - above = gray[max(0, y - 6):max(0, y - 2), hx1:hx2] - below = gray[min(H, y + 2):min(H, y + 6), hx1:hx2] - if (above.size and below.size - and float((above > gray_hi).mean()) > 0.85 - and float((below > gray_hi).mean()) > 0.85): - return y - return None - - -def _faint_grey_band_above(gray, hbbox, max_gap=185, min_gap=6, max_thick=12, - gray_lo=135, gray_hi=232, cover=0.8, max_dark=0.08, - white_thr=235, white_cover=0.9): - """Find a faint GREY horizontal rule (1-`max_thick` px thick) sitting in the - whitespace directly above a SINGLE-column header. Per the layout convention a - grey rule whose length matches the article/header width marks the boundary - between two stacked stories, so the next story's headline must not fold into - the article above the rule. Such light rules read as background to the ink-based - Otsu detector in `detect_separator_lines`, and `_faint_rule_above` only accepts - a 1-px isolated rule, so a thicker grey band is missed; here we group the band - and require it to span the header's width and be isolated by white paper above - and below. Returns the band's centre y, or None.""" - H, W = gray.shape - hx1, hy, hx2 = int(hbbox[0]), int(hbbox[1]), int(hbbox[2]) - y_hi = max(0, hy - min_gap) - y_lo = max(0, hy - max_gap) - cols = slice(hx1, hx2) - grey_rows = [] - for y in range(y_lo, y_hi): - row = gray[y, cols].astype(np.int16) - if row.size == 0: - continue - mid = float(((row >= gray_lo) & (row <= gray_hi)).mean()) - dark = float((row < gray_lo).mean()) - if mid >= cover and dark <= max_dark: - grey_rows.append(y) - if not grey_rows: - return None - bands = [] - s = p = grey_rows[0] - for y in grey_rows[1:]: - if y == p + 1: - p = y - else: - bands.append((s, p)); s = p = y - bands.append((s, p)) - for top, bot in sorted(bands, key=lambda b: -b[1]): # nearest the header first - if bot - top + 1 > max_thick: - continue - above = gray[max(0, top - 4):top, cols] - below = gray[bot + 1:min(H, bot + 5), cols] - if (above.size and below.size - and float((above > white_thr).mean()) >= white_cover - and float((below > white_thr).mean()) >= white_cover): - return (top + bot) // 2 - return None - - -def _faint_grey_band_below(gray, bbox, max_gap=150, min_gap=4, max_thick=12, - gray_lo=135, gray_hi=232, cover=0.8, max_dark=0.08, - white_thr=235, white_cover=0.9): - """Mirror of `_faint_grey_band_above`, searching DOWNWARD: find the faint grey - rule that sits in the whitespace just below an article (within `max_gap` px of - its bottom edge) and spans its column width. That rule is the article's BOTTOM - boundary, so the crop can be cut precisely at it. Returns the band's top y (the - cut line), or None when no clean full-width grey rule is found below.""" - H, W = gray.shape - bx1, by, bx2 = int(bbox[0]), int(bbox[3]), int(bbox[2]) - y_lo = min(H, by + min_gap) - y_hi = min(H, by + max_gap) - cols = slice(bx1, bx2) - grey_rows = [] - for y in range(y_lo, y_hi): - row = gray[y, cols].astype(np.int16) - if row.size == 0: - continue - mid = float(((row >= gray_lo) & (row <= gray_hi)).mean()) - dark = float((row < gray_lo).mean()) - if mid >= cover and dark <= max_dark: - grey_rows.append(y) - if not grey_rows: - return None - bands = [] - s = p = grey_rows[0] - for y in grey_rows[1:]: - if y == p + 1: - p = y - else: - bands.append((s, p)); s = p = y - bands.append((s, p)) - for top, bot in sorted(bands, key=lambda b: b[0]): # nearest below first - if bot - top + 1 > max_thick: - continue - # Skip the 1-px anti-aliased fade row hugging the rule before checking for - # the white paper gutter above and below it. - above = gray[max(0, top - 7):max(0, top - 2), cols] - below = gray[bot + 2:min(H, bot + 7), cols] - if (above.size and below.size - and float((above > white_thr).mean()) >= white_cover - and float((below > white_thr).mean()) >= white_cover): - return top - return None - - -def separator_barriers(png_path, regions, near=80, min_overlap=0.3, - title_types=("doc_title", "paragraph_title", "figure_title"), - multicol_frac=0.22): - """Article-boundary rules: the horizontal printed lines that mark the END of a - story. Per the layout convention, a rule with NORMAL text (or whitespace) above - it separates two stacked articles, while a rule sitting right under a BOLD - headline/title is a decorative flourish and must NOT split anything. - - We approximate 'bold above' by a title-type region (doc_title / paragraph_title - / figure_title) whose bottom edge is within `near` px above the rule and that - horizontally overlaps it. Such rules are dropped; the rest are returned as - barriers {y, x1, x2} for the clusterer to forbid cross-line folding. - - Additionally, for every MULTI-COLUMN header (a doc_title at least `multicol_frac` - of the page width), we look for a faint grey rule directly above it and add it as - a barrier spanning the header's width: that rule is the article's TOP boundary, so - nothing above it folds into the multi-column article below.""" - res = detect_separator_lines(png_path) - - # A real article separator sits in a WHITESPACE GUTTER between two stacked - # boxes; it never lands deep inside a body-text region. PaddleOCR's morphology - # occasionally mistakes a dense Telugu text stroke for a thin rule, producing a - # phantom line straight through a paragraph. Reject any detected rule whose - # midpoint falls well inside (margin-shrunk) a 'text' box it column-overlaps. - _text_boxes = [r["bbox"] for r in regions if r.get("type") == "text"] - - def _in_text(y, lx1, lx2, margin=28): - mx = (lx1 + lx2) / 2 - for tx1, ty1, tx2, ty2 in _text_boxes: - if (tx1 <= mx <= tx2 - and ty1 + margin <= y <= ty2 - margin - and _hspan_overlap(lx1, lx2, tx1, tx2) >= min_overlap): - return True - return False - - # Column width (median text-region width). A horizontal line counts as an article - # separator only when it spans most of a column. NOTE: a strict ≥1.0× column floor is - # too aggressive — a SINGLE-column article's own boundary rule is itself <1 column wide, - # so ≥1.0× drops real separators and merges articles (measured: NT pg4 R121 -> 2 datelines). - # 0.6× column is the safe floor: it removes only the short caption / decorative underlines - # and merges NO articles on AJ / NT / JG. - _twid = sorted((r["bbox"][2] - r["bbox"][0]) for r in regions if r.get("type") == "text") - _pitch = _twid[len(_twid) // 2] if _twid else 0 - _len_floor = 0.6 * _pitch - - bars = [] - for L in res["h"]: - y, lx1, lx2 = L["y1"], L["x1"], L["x2"] - if _in_text(y, lx1, lx2): - continue - if _pitch and (lx2 - lx1) < _len_floor: - continue # too short to be an article separator (caption/underline) - bold_above = False - title_w_above = 0 - for r in regions: - b = r["bbox"] - if (b[3] <= y and (y - b[3]) <= near - and r.get("type") in title_types - and _hspan_overlap(lx1, lx2, b[0], b[2]) >= min_overlap): - bold_above = True - title_w_above = max(title_w_above, b[2] - b[0]) - # A rule under a bold title is a decorative flourish ONLY when it merely - # underlines that title (rule width ≈ title width). A rule spanning much - # WIDER than the title above it runs across several columns — e.g. a photo - # caption (figure_title) sits above ONE column while the rule runs the FULL - # article width — so it is a genuine article boundary and must be kept. - if (not bold_above) or ((lx2 - lx1) > 1.5 * title_w_above): - bars.append({"y": y, "x1": lx1, "x2": lx2}) - - gray = cv2.cvtColor(cv2.imread(str(png_path)), cv2.COLOR_BGR2GRAY) - W = gray.shape[1] - _img_boxes = [r["bbox"] for r in regions if r.get("type") == "image"] - - def _lead_photo_above(yb, hx1, hx2, gap=80): - """A faint rule directly under the article's OWN lead photo is that photo's - caption underline, not the article's top boundary. If an image sits flush - (within `gap`px) above the rule and overlaps the header's width, the rule must - NOT bound the article — otherwise the lead photo gets cut off.""" - for ix1, iy1, ix2, iy2 in _img_boxes: - if (0 <= yb - iy2 <= gap - and _hspan_overlap(hx1, hx2, ix1, ix2) >= min_overlap): - return True - return False - - for r in regions: - if r.get("type") != "doc_title": - continue - b = r["bbox"] - if (b[2] - b[0]) < multicol_frac * W: - continue # single-column header -> skip - yb = _faint_rule_above(gray, b) - if yb is not None and not _lead_photo_above(yb, b[0], b[2]): - bars.append({"y": yb, "x1": b[0], "x2": b[2], - "mc": True, "anchor": r["id"]}) - - # Same rule for SINGLE-column headers: a faint grey rule spanning the header's - # width directly above it bounds the article ABOVE it, so the header (and its - # story) cannot fold upward across the rule. Plain barrier (no mc clamp). - for r in regions: - if r.get("type") not in ("doc_title", "paragraph_title"): - continue - b = r["bbox"] - if (b[2] - b[0]) >= multicol_frac * W: - continue # multi-column -> handled above - yb = _faint_grey_band_above(gray, b) - if yb is not None and not _lead_photo_above(yb, b[0], b[2]): - bars.append({"y": yb, "x1": b[0], "x2": b[2]}) - - # Vertical column-divider rules. detect_separator_lines already requires each - # line to sit in a whitespace gutter (isolated on both sides), so photo/text - # internal strokes are filtered out. These fence rightward column-growth: an - # article must not grow across a printed vertical rule into the next column. - for L in res["v"]: - bars.append({"vert": True, "x": (L["x1"] + L["x2"]) // 2, - "y1": min(L["y1"], L["y2"]), "y2": max(L["y1"], L["y2"])}) - return bars - - -def overlay(png_path, lines, out_path): - img = cv2.imread(str(png_path)) - for L in lines["h"]: - cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (0, 0, 255), 6) - for L in lines["v"]: - cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (255, 0, 0), 6) - cv2.imwrite(str(out_path), img) - - -if __name__ == "__main__": - import sys - from pathlib import Path - p = Path(sys.argv[1]) - res = detect_separator_lines(p) - print(f"{p.name} {res['size']} H={len(res['h'])} V={len(res['v'])}") - for L in sorted(res["h"], key=lambda d: d["y1"]): - print(f" H y={L['y1']:>5} x[{L['x1']:>4}..{L['x2']:>4}] len={L['len']:>4} gray={L['gray']}") - for L in sorted(res["v"], key=lambda d: d["x1"]): - print(f" V x={L['x1']:>5} y[{L['y1']:>4}..{L['y2']:>4}] len={L['len']:>4} gray={L['gray']}") - out = Path(sys.argv[2]) if len(sys.argv) > 2 else Path(f"/tmp/lines_{p.stem}.png") - overlay(p, res, out) - print("overlay:", out) diff --git a/_nt4.txt b/_nt4.txt deleted file mode 100644 index e336e83..0000000 --- a/_nt4.txt +++ /dev/null @@ -1,4 +0,0 @@ -WITH ≥1col floor: 24 blocks - R67 H 4DL members=[5, 7, 28, 34, 42, 48, 50, 67, 68, 73, 74, 80, 100, 102, 107, 127, 135] - R121 H 2DL members=[12, 14, 21, 39, 59, 111, 116, 121] -anchors: R23,R67,R81,R85,R87,R89,R90,R91,R93,R94,R95,R96,R97,R98,R101,R103,R108,R118,R119,R121,R122,R128,R131,R132 diff --git a/_nt_base.log b/_nt_base.log deleted file mode 100644 index b5cf83d..0000000 --- a/_nt_base.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nt_val.log b/_nt_val.log deleted file mode 100644 index b5cf83d..0000000 --- a/_nt_val.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nt_val2.log b/_nt_val2.log deleted file mode 100644 index b5cf83d..0000000 --- a/_nt_val2.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nt_val3.log b/_nt_val3.log deleted file mode 100644 index e20286d..0000000 --- a/_nt_val3.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110, 105] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nt_val4.log b/_nt_val4.log deleted file mode 100644 index b5cf83d..0000000 --- a/_nt_val4.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nt_val5.log b/_nt_val5.log deleted file mode 100644 index b5cf83d..0000000 --- a/_nt_val5.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nt_val6.log b/_nt_val6.log deleted file mode 100644 index b5cf83d..0000000 --- a/_nt_val6.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nt_val7.log b/_nt_val7.log deleted file mode 100644 index bfffd7c..0000000 --- a/_nt_val7.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 28 crops, 25 datelines, 2+dl-blocks=[80] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nt_val8.log b/_nt_val8.log deleted file mode 100644 index b5cf83d..0000000 --- a/_nt_val8.log +++ /dev/null @@ -1,5 +0,0 @@ -page 1: 11 crops, 11 datelines, 2+dl-blocks=none | Caption bound:4, Headline-strip:8, Multi-column body:4 -page 2: 23 crops, 22 datelines, 2+dl-blocks=[110] | -page 3: 20 crops, 21 datelines, 2+dl-blocks=[54, 62] | -page 4: 25 crops, 25 datelines, 2+dl-blocks=[67, 121] | -DONE -> output/NamastheTelangana_Siddipet_20260602_20260604_214937/all_article_crops_final diff --git a/_nta.log b/_nta.log deleted file mode 100644 index 6e6f3f5..0000000 --- a/_nta.log +++ /dev/null @@ -1,179 +0,0 @@ -=== page 1: 5 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL5 [668,901,4084,6302] 3416x5401 mem=22 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 5 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL5 [668,901,4084,6302] 3416x5401 mem=22 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 5 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL5 [668,901,4084,6302] 3416x5401 mem=22 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 5 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL5 [668,901,4084,6302] 3416x5401 mem=22 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 5 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL5 [668,901,4084,6302] 3416x5401 mem=22 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 5 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL5 [668,901,4084,6302] 3416x5401 mem=22 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 5 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL5 [668,901,4084,6302] 3416x5401 mem=22 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 \ No newline at end of file diff --git a/_nta2.log b/_nta2.log deleted file mode 100644 index 6c11505..0000000 --- a/_nta2.log +++ /dev/null @@ -1,295 +0,0 @@ -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL56 [1265,901,4079,4724] 2814x3823 mem=11 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL56 [1265,901,4079,4724] 2814x3823 mem=11 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL56 [1265,901,4079,4724] 2814x3823 mem=11 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL56 [1265,901,4079,4724] 2814x3823 mem=11 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL56 [1265,901,4079,4724] 2814x3823 mem=11 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL56 [1265,901,4079,4724] 2814x3823 mem=11 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=21 - DL56 [1265,901,4079,4724] 2814x3823 mem=11 - DL9 [105,2334,1197,6302] 1092x3968 mem=5 - H59 [112,2762,3229,4860] 3117x2098 mem=13 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -DONE -> output/NamastheTelangana_Adilabad_20260528_20260610_160056/all_article_crops_review diff --git a/_nta3.log b/_nta3.log deleted file mode 100644 index c69bbe9..0000000 --- a/_nta3.log +++ /dev/null @@ -1,281 +0,0 @@ -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 2: 30 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,4979] 468x1493 mem=3 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [610,4170,1497,4966] 887x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - DL26 [154,4987,1498,5443] 1344x456 mem=3 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [114,5467,1498,6269] 1384x802 mem=3 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [590,5993,1498,6302] 908x309 mem=2 -=== page 2: 30 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,4979] 468x1493 mem=3 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [610,4170,1497,4966] 887x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - DL26 [154,4987,1498,5443] 1344x456 mem=3 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [114,5467,1498,6269] 1384x802 mem=3 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [590,5993,1498,6302] 908x309 mem=2 -=== page 2: 30 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,4979] 468x1493 mem=3 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [610,4170,1497,4966] 887x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - DL26 [154,4987,1498,5443] 1344x456 mem=3 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [114,5467,1498,6269] 1384x802 mem=3 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [590,5993,1498,6302] 908x309 mem=2 -=== page 2: 30 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,4979] 468x1493 mem=3 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [610,4170,1497,4966] 887x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - DL26 [154,4987,1498,5443] 1344x456 mem=3 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [114,5467,1498,6269] 1384x802 mem=3 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [590,5993,1498,6302] 908x309 mem=2 -=== page 2: 30 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,4979] 468x1493 mem=3 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [610,4170,1497,4966] 887x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - DL26 [154,4987,1498,5443] 1344x456 mem=3 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [114,5467,1498,6269] 1384x802 mem=3 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [590,5993,1498,6302] 908x309 mem=2 -=== page 2: 30 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,4979] 468x1493 mem=3 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [610,4170,1497,4966] 887x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - DL26 [154,4987,1498,5443] 1344x456 mem=3 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [114,5467,1498,6269] 1384x802 mem=3 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [590,5993,1498,6302] 908x309 mem=2 -=== page 2: 30 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,4979] 468x1493 mem=3 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [610,4170,1497,4966] 887x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - DL26 [154,4987,1498,5443] 1344x456 mem=3 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [114,5467,1498,6269] 1384x802 mem=3 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [590,5993,1498,6302] 908x309 mem=2 -DONE -> output/NamastheTelangana_Adilabad_20260528_20260610_160056/all_article_crops_review diff --git a/_nta4.log b/_nta4.log deleted file mode 100644 index 2fb4f59..0000000 --- a/_nta4.log +++ /dev/null @@ -1,295 +0,0 @@ -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 1: 6 crops, 6 datelines === - H44 [106,111,4084,3144] 3978x3033 mem=23 - DL9 [105,2334,1200,6302] 1095x3968 mem=6 - DL13 [1320,2761,4079,4724] 2759x1963 mem=14 - H59 [115,3752,3228,4860] 3113x1108 mem=7 - H41 [2577,4793,4084,6309] 1507x1516 mem=4 - H30 [668,4829,3208,6302] 2540x1473 mem=11 - ─ NT late rule-split: R5 → 2 bands at structural rules [4764] - 🖼 Orphan photo: R38 → article R5 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -=== page 2: 31 crops, 30 datelines === - H80 [1833,465,3228,1814] 1395x1349 mem=6 - H65 [3293,465,4079,987] 786x522 mem=2 - H84 [106,501,1776,1820] 1670x1319 mem=6 - H43 [3292,1014,4079,1562] 787x548 mem=2 - DL9 [3292,1590,4079,2136] 787x546 mem=2 - H78 [1838,1678,2517,1805] 679x127 mem=2 - DL7 [104,1851,923,2566] 819x715 mem=3 - H74 [981,1883,2350,3060] 1369x1177 mem=4 - H72 [2408,1884,3227,2713] 819x829 mem=2 - DL5 [3292,2167,4079,2759] 787x592 mem=2 - DL23 [104,2596,922,2998] 818x402 mem=2 - H58 [2408,2772,3226,3479] 818x707 mem=2 - DL13 [3292,2787,4079,3333] 787x546 mem=2 - DL20 [106,3050,923,3478] 817x428 mem=2 - H60 [981,3117,2351,3479] 1370x362 mem=3 - DL1 [3293,3382,4079,4190] 786x808 mem=2 - P67 [131,3486,599,5211] 468x1725 mem=4 - DL10 [1559,3528,3226,4291] 1667x763 mem=4 - P63 [677,3558,1499,4144] 822x586 mem=2 - H50 [678,4170,1497,4966] 819x796 mem=2 - DL12 [3292,4217,4079,4815] 787x598 mem=2 - H71 [1560,4365,3226,4958] 1666x593 mem=3 - H51 [3292,4842,4079,5479] 787x637 mem=2 - DL41 [1561,4960,3225,5110] 1664x150 mem=2 - H54 [678,4987,1498,5443] 820x456 mem=2 - H76 [1559,5171,3228,5881] 1669x710 mem=5 - H53 [677,5467,1498,5964] 821x497 mem=2 - H83 [3291,5509,4079,6303] 788x794 mem=3 - H56 [1559,5944,3228,6302] 1669x358 mem=3 - H46 [680,5993,1498,6302] 818x309 mem=2 - O79 [152,6141,590,6257] 438x116 mem=1 - 🖼 Orphan photo: R90 → article R67 (an image must belong to an article) -DONE -> output/NamastheTelangana_Adilabad_20260528_20260610_160056/all_article_crops_review diff --git a/_orphan_check.py b/_orphan_check.py deleted file mode 100644 index e1a3647..0000000 --- a/_orphan_check.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -for pg in (2, 3, 4): - png = D / f"page_{pg:03d}.png" - regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"] - with contextlib.redirect_stdout(io.StringIO()): - regs = se.drop_masthead_regions(regs, "andhra_jyothi", pg, png) - ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi") - bars = separator_barriers(str(png), regs) - bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars) - dl_ids = {s["region_id"] for s in ds} - n_dl = sum(1 for b in bl if any(m in dl_ids for m in b["members"])) - orph = [b for b in bl if b["kind"] == "O"] - print(f"==== PAGE {pg}: {len(bl)} blocks, {n_dl} dateline, {len(orph)} orphan ====") - for b in orph: - print(f" O anchor={b['anchor_id']} bbox={b['bbox']} members={sorted(b['members'])}") diff --git a/_partition_debug.py b/_partition_debug.py deleted file mode 100644 index 35c35fb..0000000 --- a/_partition_debug.py +++ /dev/null @@ -1,86 +0,0 @@ -"""TEST (read-only): finalize article boundaries using the RIGHTMOST dead-end (nearest big -vertical wall to the right, else page edge) and the TOPMOST dead-end (masthead bottom, for -top-row articles). Draw both the original block boundary (thin gray) and the dead-end-snapped -boundary (thick colour) on a blank canvas, plus the big vertical walls (red) and the masthead -band. No smart_extractor change, no API. Test on 1-2 pages.""" -import os, tempfile, json, io, contextlib, statistics -tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) -from pathlib import Path -from PIL import Image, ImageDraw, ImageFont -import smart_extractor as se -from _lines import separator_barriers, detect_separator_lines - -BIG_FRAC = 0.45 - -def big_walls(png): - res = detect_separator_lines(png); W, H = res["size"] - out = [] - for L in res["v"]: - y1, y2 = min(L["y1"], L["y2"]), max(L["y1"], L["y2"]) - if (y2 - y1) >= BIG_FRAC * H: - out.append({"x": (L["x1"]+L["x2"])//2, "y1": y1, "y2": y2}) - return out, (W, H) - -def masthead_bottom(png, raw, paper, pg, W, H): - # compute from RAW regions (before masthead removal) so the dropped band's bottom is visible - with contextlib.redirect_stdout(io.StringIO()): - dd = se.dedup_overlapping_regions([dict(r) for r in raw]) - kept = se.drop_masthead_regions([dict(r) for r in dd], paper, pg, png) - drop_bottom = max((r["bbox"][3] for r in dd - if r["id"] not in {k["id"] for k in kept}), default=0) - res = detect_separator_lines(png) - wide = sorted([L for L in res["h"] if (L["x2"]-L["x1"]) >= 0.30*W - and L["y1"] < 0.20*H], key=lambda L: L["y1"]) - top_rule = wide[0]["y1"] if wide else 0 - return max(drop_bottom, top_rule) - -def run(pdir, pg, paper, tag): - png = f"{pdir}/page_{pg:03d}.png" - raw = json.loads(Path(f"{pdir}/page_{pg:03d}.regions.json").read_text())["regions"] - with contextlib.redirect_stdout(io.StringIO()): - regs = se.dedup_overlapping_regions(raw); regs = se.merge_stacked_title_lines(regs, png) - regs = se.drop_masthead_regions(regs, paper, pg, png); regs = se.promote_paragraph_titles(regs, png, paper); regs = se.mark_bullet_titles(regs, png) - ds = se.find_article_starts_by_dateline(regs, png, paper) - _p = se.cluster_all_article_blocks(regs, ds, sep_lines=separator_barriers(png, regs)) - if se.recover_orphan_text_headlines(_p, regs, png): ds = se.find_article_starts_by_dateline(regs, png, paper) - bars = separator_barriers(png, regs) - blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) - walls, (W, H) = big_walls(png) - cright = max((r["bbox"][2] for r in regs), default=W) - mh = masthead_bottom(png, raw, paper, pg, W, H) - top_row_cut = mh + 320 # an article whose top is within this band is "top row" - - def deadends(b): - x1, y1, x2, y2 = b["bbox"]; cx = (x1 + x2) / 2; bh = y2 - y1 - # rightmost dead-end: nearest big wall right of the block centre that spans it; else page edge - rcand = [w["x"] for w in walls if w["x"] > cx - and max(0, min(y2, w["y2"]) - max(y1, w["y1"])) >= 0.4 * bh] - right = min(rcand) if rcand else cright - right = max(right, x2) # never shrink - # topmost dead-end: top-row article -> up to masthead bottom - top = mh if (y1 <= top_row_cut and mh > 0) else y1 - top = min(top, y1) # never shrink downward - return [x1, top, right, y2] - - img = Image.new("RGB", (W, H), "white"); d = ImageDraw.Draw(img) - try: font = ImageFont.truetype("DejaVuSans-Bold.ttf", 30) - except Exception: font = ImageFont.load_default() - if mh > 4: - d.rectangle([0, 0, W, mh], fill=(232,232,232)); d.line([0,mh,W,mh], fill=(140,140,140), width=5) - d.text((14, max(2, mh//2-16)), "MASTHEAD (top dead-end)", fill=(110,110,110), font=font) - for w in walls: - d.line([w["x"], w["y1"], w["x"], w["y2"]], fill=(235,70,70), width=8) - pal = se._ARTICLE_COLORS - for i, b in enumerate(blocks): - ox1, oy1, ox2, oy2 = b["bbox"]; nx1, ny1, nx2, ny2 = deadends(b); c = pal[i % len(pal)] - d.rectangle([ox1, oy1, ox2, oy2], outline=(180,180,180), width=3) # original (gray) - d.rectangle([nx1, ny1, nx2, ny2], outline=c, width=8) # dead-end (color) - lab = f"#{b['anchor_id']} [{b['kind']}]" - d.rectangle([nx1+5, ny1+6, nx1+16+len(lab)*15, ny1+42], fill=c) - d.text((nx1+11, ny1+9), lab, fill="white", font=font) - out = f"{pdir}/page_{pg:03d}_partition_debug.png"; img.save(out) - print(f"{tag} pg{pg}: {len(blocks)} blocks, {len(walls)} walls, masthead_bottom={int(mh)} -> {out}") - -run("output/NamastheTelangana_Siddipet_20260602_20260604_214937/pages", 2, "namaste_telangana", "NT") -run("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages", 1, "andhra_jyothi", "AJ") diff --git a/_probe71_tmp.py b/_probe71_tmp.py deleted file mode 100644 index fc9652f..0000000 --- a/_probe71_tmp.py +++ /dev/null @@ -1,26 +0,0 @@ -import sys, types; sys.modules.setdefault("fitz", types.ModuleType("fitz")) -import os, tempfile, json -tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -RUN = Path("output/Sakshi_Jangaon_District_20260520_20260609_210104") -png = str(RUN/"pages/page_001.png") -regions = json.loads((RUN/"pages/page_001.regions.json").read_text())["regions"] -regions = se.dedup_overlapping_regions(regions) -regions = se.merge_stacked_title_lines(regions, png) -regions = se.drop_masthead_regions(regions, "sakshi", 1, png) -regions = se.promote_paragraph_titles(regions, png, "sakshi") -dls = se.find_article_starts_by_dateline(regions, png, "sakshi") -seps = separator_barriers(png, regions) -blocks = se.cluster_all_article_blocks(regions, dls, sep_lines=seps) -rmap = {r['id']:r for r in regions} -for b in blocks: - if b['anchor_id']==71: - print("BLOCK:", {k:v for k,v in b.items() if k!='members'}) - print("members:") - for m in sorted(b['members']+[b['anchor_id']], key=lambda m: rmap[m]['bbox'][1] if m in rmap else 0): - r = rmap.get(m) - print(" ", m, r['type'] if r else '?', r['bbox'] if r else '?') -json.dump({'blocks':[{'anchor':b['anchor_id'],'kind':b['kind'],'bbox':b['bbox'],'members':b['members']} for b in blocks]}, open('/tmp/blocks71.json','w')) diff --git a/_probe_above.py b/_probe_above.py deleted file mode 100644 index 3e19e45..0000000 --- a/_probe_above.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys, json -sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -for pg in (1, 2, 3, 4): - png = D / f"page_{pg:03d}.png" - regions = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"] - regions = se.drop_masthead_regions(regions, "andhra_jyothi", pg, png) - ds = se.find_article_starts_by_dateline(regions, str(png), "andhra_jyothi") - bars = separator_barriers(str(png), regions) - blocks = se.cluster_all_article_blocks(regions, dateline_starts=ds, sep_lines=bars) - rmap = {r["id"]: r for r in regions} - print(f"\n==== PAGE {pg} ====") - for b in blocks: - anchor = rmap.get(b["anchor_id"]) - if not anchor: - continue - atop = anchor["bbox"][1] - # members whose ENTIRE box is above the anchor headline top - above_mems = [m for m in b["members"] - if m != b["anchor_id"] and rmap[m]["bbox"][3] <= atop + 20] - if above_mems and b["kind"] == "H": - print(f" block H anchor={b['anchor_id']} (top y={atop}) has {len(above_mems)} member(s) ABOVE it:") - for m in above_mems: - rb = rmap[m]["bbox"] - print(f" R{m} {rmap[m]['type']:<14} y[{rb[1]}..{rb[3]}] x[{rb[0]}..{rb[2]}]") diff --git a/_probe_bars.py b/_probe_bars.py deleted file mode 100644 index 6b19295..0000000 --- a/_probe_bars.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers, detect_separator_lines - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -png = D / "page_001.png" -regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png) - -res = detect_separator_lines(png) -print(f"=== {len(res['h'])} raw horizontal lines ===") -for L in sorted(res["h"], key=lambda d: d["y1"]): - print(f" H y={L['y1']:>5} x[{L['x1']:>4}..{L['x2']:>4}] len={L['len']:>4} gray={L['gray']}") - -print("\n=== separator_barriers (after filters) ===") -bars = separator_barriers(str(png), regs) -for L in sorted(bars, key=lambda d: d["y"]): - print(f" bar y={L['y']:>5} x[{L['x1']:>4}..{L['x2']:>4}] mc={L.get('mc')}") diff --git a/_probe_dl.py b/_probe_dl.py deleted file mode 100644 index a91f98b..0000000 --- a/_probe_dl.py +++ /dev/null @@ -1,22 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers, detect_separator_lines - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -png = D / "page_001.png" -regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png) - ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi") - -print(f"=== {len(ds)} dateline starts ===") -for s in sorted(ds, key=lambda s: s["bbox"][1]): - print(f" DL region={s['region_id']:>3} bbox={s['bbox']} headline={s.get('headline_region')}") - -byid = {r["id"]: r for r in regs} -print("\n=== all regions sorted by y ===") -for r in sorted(regs, key=lambda r: (r["bbox"][1], r["bbox"][0])): - b = r["bbox"] - print(f" R{r['id']:>3} {r['type']:<16} bbox={b}") diff --git a/_probe_fake.py b/_probe_fake.py deleted file mode 100644 index 8ceee91..0000000 --- a/_probe_fake.py +++ /dev/null @@ -1,38 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers, detect_separator_lines - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -png = D / "page_001.png" -regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png) - -byid = {r["id"]: r for r in regs} -# focus region 35 and 55 -for rid in (35, 55): - if rid in byid: - r = byid[rid] - print(f"R{rid} type={r['type']} bbox={r['bbox']}") - else: - print(f"R{rid} NOT in regs (dropped?)") - -print("\n-- all regions near x 150..750, y 1100..1600 --") -for r in sorted(regs, key=lambda r: r["bbox"][1]): - b = r["bbox"] - if b[1] < 1700 and b[3] > 1050 and b[0] < 760: - print(f" R{r['id']:>3} {r['type']:<16} bbox={b}") - -print("\n-- raw horizontal lines near y=1375 --") -res = detect_separator_lines(png) -for L in sorted(res["h"], key=lambda d: d["y1"]): - if 1300 < L["y1"] < 1450: - print(f" H y={L['y1']} x[{L['x1']}..{L['x2']}] len={L['len']} gray={L['gray']}") - -print("\n-- separator_barriers near y=1375 --") -bars = separator_barriers(str(png), regs) -for L in sorted(bars, key=lambda d: d["y"]): - if 1300 < L["y"] < 1450: - print(f" bar y={L['y']} x[{L['x1']}..{L['x2']}] mc={L.get('mc')}") diff --git a/_probe_fake2.py b/_probe_fake2.py deleted file mode 100644 index 0f1686a..0000000 --- a/_probe_fake2.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -png = D / "page_001.png" -regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png) - ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi") - bars = separator_barriers(str(png), regs) - bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars) - -print("bars near y=1375:", [b for b in bars if 1300 < b["y"] < 1450]) -print() -dl_ids = {s["region_id"] for s in ds} -for b in sorted(bl, key=lambda b: (b["bbox"][1], b["bbox"][0])): - kind = b["kind"] - print(f" {kind} anchor={b['anchor_id']:>3} bbox={b['bbox']} members={sorted(b['members'])}") diff --git a/_probe_fix.py b/_probe_fix.py deleted file mode 100644 index 197045a..0000000 --- a/_probe_fix.py +++ /dev/null @@ -1,41 +0,0 @@ -import os, tempfile, contextlib, io, json -tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -se._ACTIVE_PAPER = "sakshi" -RUN = Path("output/Sakshi_Jangaon_District_20260520_20260609_210104"); D = RUN / "pages" -png = str(D / "page_001.png") -regs = json.loads((D / "page_001.regions.json").read_text())["regions"] -buf = io.StringIO() -with contextlib.redirect_stdout(buf): - regs = se.dedup_overlapping_regions(regs); regs = se.merge_stacked_title_lines(regs, png) - regs = se.drop_masthead_regions(regs, "sakshi", 1, png) - regs = se.drop_classifieds_regions(regs, png); regs = se.tag_legal_notices(regs, png) - regs = se.promote_paragraph_titles(regs, png, "sakshi") - regs = se.detect_sakshi_headline_bands(regs, png) - regs = se.mark_bullet_titles(regs, png) - ds = se.find_article_starts_by_dateline(regs, png, "sakshi") - bars = separator_barriers(png, regs) - _p = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) - if se.recover_orphan_text_headlines(_p, regs, png): - ds = se.find_article_starts_by_dateline(regs, png, "sakshi") - blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) -WATCH = [44, 16, 36, 69, 61, 46, 23, 4, 74, 49, 17, 88, 33, 28, 3, 53, 56] -own = {} -for b in blocks: - for m in set(b["members"]) | {b["anchor_id"]}: - own.setdefault(m, []).append(f"{b['kind']}{b['anchor_id']}") -print("region owners:") -for w in WATCH: - print(f" R{w:>3} -> {own.get(w, ['(NONE)'])}") -print("\nhorizontal bars near lift-1 (y3300-4100) and R50 zone (y4350-4900):") -for L in bars: - if not L.get("vert") and "y" in L and (3300 <= L["y"] <= 4100 or 4350 <= L["y"] <= 4900): - print(f" y={L['y']} x={L['x1']}-{L['x2']} w={L['x2']-L['x1']}") -print("\ndateline regions:", sorted(s["region_id"] for s in ds)) -print("\npipeline lines mentioning watched regions / passes:") -for l in buf.getvalue().splitlines(): - if any(k in l for k in ("R44", "R69", "R61", "R46", "R23", "rebind", "Sakshi", "Orphan photo", "Masthead", "📐")): - print(" ", l.strip()) diff --git a/_probe_fix2.py b/_probe_fix2.py deleted file mode 100644 index 47d41f4..0000000 --- a/_probe_fix2.py +++ /dev/null @@ -1,46 +0,0 @@ -import os, tempfile, contextlib, io, json -tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -se._ACTIVE_PAPER = "sakshi" -RUN = Path("output/Sakshi_Jangaon_District_20260520_20260609_210104"); D = RUN / "pages" -png = str(D / "page_002.png") -regs = json.loads((D / "page_002.regions.json").read_text())["regions"] -buf = io.StringIO() -with contextlib.redirect_stdout(buf): - regs = se.dedup_overlapping_regions(regs); regs = se.merge_stacked_title_lines(regs, png) - regs = se.drop_masthead_regions(regs, "sakshi", 2, png) - regs = se.drop_classifieds_regions(regs, png); regs = se.tag_legal_notices(regs, png) - regs = se.promote_paragraph_titles(regs, png, "sakshi") - regs = se.detect_sakshi_headline_bands(regs, png) - regs = se.mark_bullet_titles(regs, png) - ds = se.find_article_starts_by_dateline(regs, png, "sakshi") - bars = separator_barriers(png, regs) - _p = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) - if se.recover_orphan_text_headlines(_p, regs, png): - ds = se.find_article_starts_by_dateline(regs, png, "sakshi") - blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) -rm = {r["id"]: r for r in regs} -print("BLOCKS:") -for b in sorted(blocks, key=lambda b: (b["bbox"][1], b["bbox"][0])): - x1, y1, x2, y2 = b["bbox"] - f = " FURN" if b.get("_furniture") else "" - print(f" {b['kind']}{b['anchor_id']:<4} [{x1},{y1},{x2},{y2}] mem={sorted(set(b['members']))}{f}") -WATCH = [20, 29, 34, 51, 3, 14, 31, 65, 87, 105, 121, 76, 8, 10, 36, 46, 81] -own = {} -for b in blocks: - tag = ("F" if b.get("_furniture") else b["kind"]) + str(b["anchor_id"]) - for m in set(b["members"]) | {b["anchor_id"]}: - own.setdefault(m, []).append(tag) -print("\nWATCH owners:", {f"R{w}": own.get(w, "NONE") for w in WATCH}) -print("\nbars y2380-2820 / y3400-3700 / y4640-4760:") -for L in bars: - if not L.get("vert") and "y" in L and (2380 <= L["y"] <= 2820 or 3400 <= L["y"] <= 3700 or 4640 <= L["y"] <= 4760): - print(f" y={L['y']} x={L['x1']}-{L['x2']} w={L['x2']-L['x1']}") -print("\ndatelines:", sorted(s["region_id"] for s in ds)) -print("\npipeline lines:") -for l in buf.getvalue().splitlines(): - if any(k in l for k in ("Type-2", "rule-split", "📐", "Masthead", "⇤", "re-home", "📸", "Orphan photo", "carve", "furniture")): - print(" ", l.strip()) diff --git a/_r121.txt b/_r121.txt deleted file mode 100644 index 406bd44..0000000 --- a/_r121.txt +++ /dev/null @@ -1,9 +0,0 @@ -R121 bbox=[2113, 2214, 3502, 3634] kind=H raw=True - R12 text y[1996,2719] x[2979,3480] DATELINE - R39 image y[2214,2622] x[2113,2939] - R111 figure_title y[2628,2725] x[2196,2856] - R121 doc_title y[2799,2898] x[2422,3493] - R59 image y[2902,3115] x[2981,3502] - R21 text y[2907,3621] x[2419,2945] DATELINE - R116 figure_title y[3123,3163] x[3113,3376] - R14 text y[3195,3622] x[2977,3502] diff --git a/_r65.txt b/_r65.txt deleted file mode 100644 index 65212aa..0000000 --- a/_r65.txt +++ /dev/null @@ -1,20 +0,0 @@ -page WxH=4200x6422; 12 blocks - -R65 bbox=[113, 1958, 1977, 6279] kind=H raw=True locked=False #members=36 -R65 datelines: [43, 47, 26, 21] -vertical walls: [(616, 4683, 6292), (141, 4683, 6292), (123, 4123, 6309), (637, 4122, 6309), (2015, 1949, 5689), (3300, 1929, 6308), (2669, 404, 1905)] -wide H-seps (>0.5W): [(1936, 114, 4091), (5709, 686, 3276)] - -all block anchors+bbox: - R109 H bbox=[119, 393, 612, 1899] ndl=1 - R79 H bbox=[2693, 405, 4087, 1833] ndl=1 - R55 H bbox=[679, 415, 2630, 1919] ndl=1 - R77 H bbox=[2692, 1594, 4087, 1903] ndl=1 - R14 DL bbox=[2045, 1950, 3265, 3097] ndl=1 - R65 H bbox=[113, 1958, 1977, 6279] ndl=4 - R96 H bbox=[3326, 1964, 4087, 3638] ndl=1 - R64 H bbox=[2046, 3116, 3264, 4832] ndl=2 - R97 H bbox=[3322, 3756, 4087, 5831] ndl=1 - R110 H bbox=[2044, 4858, 3265, 5685] ndl=1 - R59 H bbox=[680, 5731, 3267, 6318] ndl=1 - R7 DL bbox=[3308, 5839, 4087, 6305] ndl=1 diff --git a/_rSAK.txt b/_rSAK.txt deleted file mode 100644 index e69de29..0000000 diff --git a/_replay_adilabad.py b/_replay_adilabad.py deleted file mode 100644 index 52b443a..0000000 --- a/_replay_adilabad.py +++ /dev/null @@ -1,39 +0,0 @@ -import os, tempfile, contextlib, io, json, shutil -tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -se._ACTIVE_PAPER = "namaste_telangana" -RUN = Path(os.environ.get("NTA_RUN", "output/NamastheTelangana_Adilabad_20260528_20260610_160056")) -D = RUN / "pages"; P = "namaste_telangana" -OUT = RUN / "all_article_crops_review" -if OUT.exists(): shutil.rmtree(OUT) -pages = sorted(int(p.stem.split("_")[1]) for p in D.glob("page_*.png")) -for pg in pages: - png = str(D / f"page_{pg:03d}.png") - regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"] - buf = io.StringIO() - with contextlib.redirect_stdout(buf): - regs = se.dedup_overlapping_regions(regs); regs = se.merge_stacked_title_lines(regs, png) - regs = se.drop_masthead_regions(regs, P, pg, png); regs = se.drop_classifieds_regions(regs, png) - regs = se.tag_legal_notices(regs, png); regs = se.promote_paragraph_titles(regs, png, P) - if pg == 1: regs = se.detect_sakshi_headline_bands(regs, png) # NT: front-page only - regs = se.mark_bullet_titles(regs, png) - ds = se.find_article_starts_by_dateline(regs, png, P) - bars = separator_barriers(png, regs) - _p = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) - if se.recover_orphan_text_headlines(_p, regs, png): - ds = se.find_article_starts_by_dateline(regs, png, P) - blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) - n = se.crop_all_article_blocks(png, regs, str(OUT), pg, dateline_starts=ds, - sep_lines=bars, overlay=True) - print(f"=== page {pg}: {n} crops, {len(ds)} datelines ===") - for b in sorted(blocks, key=lambda b: (b["bbox"][1], b["bbox"][0])): - x1, y1, x2, y2 = b["bbox"] - f = " FURN" if b.get("_furniture") else "" - print(f" {b['kind']}{b['anchor_id']:<4} [{x1},{y1},{x2},{y2}] {x2-x1}x{y2-y1} mem={len(b['members'])}{f}") - for l in sorted({l.strip() for l in buf.getvalue().splitlines() - if "rule-split" in l or "Masthead" in l or "Orphan photo" in l}): - print(" ", l) -print("DONE ->", OUT) diff --git a/_replay_all.py b/_replay_all.py deleted file mode 100644 index ab14e2f..0000000 --- a/_replay_all.py +++ /dev/null @@ -1,35 +0,0 @@ -import os,tempfile,contextlib,io,json,shutil -tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir -os.makedirs("_tess_tmp",exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -RUN=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"); D=RUN/"pages" -OUT=RUN/"all_article_crops_final"; PAPER="andhra_jyothi" -if OUT.exists(): shutil.rmtree(OUT) -for pg in (1,2,3,4): - png=str(D/f"page_{pg:03d}.png") - regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] # 0.5 saved - buf=io.StringIO() - with contextlib.redirect_stdout(buf): - regs=se.dedup_overlapping_regions(regs) - regs=se.merge_stacked_title_lines(regs,png) - regs=se.drop_masthead_regions(regs,PAPER,pg,png) - regs=se.drop_classifieds_regions(regs,png) - regs=se.tag_legal_notices(regs,png) - regs=se.promote_paragraph_titles(regs,png,PAPER) - regs=se.mark_bullet_titles(regs,png) - bars=separator_barriers(png,regs) - ds=se.find_article_starts_by_dateline(regs,png,PAPER) - _probe=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - if se.recover_orphan_text_headlines(_probe,regs,png): ds=se.find_article_starts_by_dateline(regs,png,PAPER) - blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - se.draw_boundary_map_debug(png,regs,D,pg,dateline_starts=ds,sep_lines=bars) - n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars) - log=buf.getvalue() - tags={k:sum(1 for l in log.splitlines() if k in l) for k in - ["bullet titles flagged","Headline-strip","Floor-trim","Block dateline split", - "Multi-column body","orphan overlap"]} - tags={k:v//2 if k in ("Headline-strip","Floor-trim","Multi-column body","Block dateline split","orphan overlap") else v for k,v in tags.items()} - print(f"page {pg}: {n} crops, {len(ds)} datelines | "+", ".join(f"{k}:{v}" for k,v in tags.items() if v)) -print("DONE ->",OUT) diff --git a/_replay_crop_all.py b/_replay_crop_all.py deleted file mode 100644 index 297c331..0000000 --- a/_replay_crop_all.py +++ /dev/null @@ -1,36 +0,0 @@ -"""Re-crop EVERY article on all 4 pages using the EXISTING smart_extractor code -(no Claude / no paid API). Runs the FULL pre-processing chain the real pipeline uses -(dedup -> merge stacked titles -> drop masthead -> promote paragraph-titles -> dateline -scan -> separators -> cluster/crop), so the replay crops match real output. Tesseract -temp files are redirected off /tmp so OCR can read them. Output goes to a fresh dir.""" -import os, tempfile, json -tempfile.tempdir = os.path.abspath("_tess_tmp") # keep Tesseract off /tmp -os.environ["TMPDIR"] = tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) - -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -RUN = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919") -PAGES = RUN / "pages" -OUT = RUN / "all_article_crops_new" # fresh output dir -PAPER = "andhra_jyothi" - -for pg in (1, 2, 3, 4): - png = str(PAGES / f"page_{pg:03d}.png") - regions = json.loads((PAGES / f"page_{pg:03d}.regions.json").read_text())["regions"] - - # Full pre-processing chain (matches the real pipeline order): - regions = se.dedup_overlapping_regions(regions) - regions = se.merge_stacked_title_lines(regions, png) - regions = se.drop_masthead_regions(regions, PAPER, pg, png) - regions = se.promote_paragraph_titles(regions, png, PAPER) # paragraph_title -> doc_title - dateline_starts = se.find_article_starts_by_dateline(regions, png, PAPER) - sep_lines = separator_barriers(png, regions) - - n = se.crop_all_article_blocks(png, regions, str(OUT), pg, - dateline_starts=dateline_starts, sep_lines=sep_lines) - print(f"page {pg}: {len(dateline_starts)} datelines -> {n} article crop(s) written") - -print(f"\nCrops written under: {OUT}") diff --git a/_replay_dl9.py b/_replay_dl9.py deleted file mode 100644 index 004ad4b..0000000 --- a/_replay_dl9.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys, json, shutil, os -sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -png = D / "page_001.png" -regions = json.loads((D / "page_001.regions.json").read_text())["regions"] -regions2 = se.drop_masthead_regions(regions, "andhra_jyothi", 1, png) -ds = se.find_article_starts_by_dateline(regions2, str(png), "andhra_jyothi") -bars = separator_barriers(str(png), regions2) -blocks = se.cluster_all_article_blocks(regions2, dateline_starts=ds, sep_lines=bars) - -dl_ids = {s["region_id"] for s in ds} -dl_anchors = {b["anchor_id"] for b in blocks if any(m in dl_ids for m in b["members"])} -print(f"{len(ds)} datelines -> {len(dl_anchors)} dateline blocks: {sorted(dl_anchors)}") -for b in sorted(blocks, key=lambda d: (d["bbox"][1], d["bbox"][0])): - if b["anchor_id"] in dl_anchors: - print(f" {b['kind']} anchor={b['anchor_id']:>3} bbox={b['bbox']} members={sorted(b['members'])}") - -out = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/dateline_crops") -if out.exists(): - shutil.rmtree(out) -out.mkdir(parents=True) -n = se.crop_all_article_blocks(str(png), regions2, str(out), 1, - dateline_starts=ds, sep_lines=bars, - only_anchor_ids=dl_anchors) -print(f"\ndateline crops written: {n}") -for f in sorted(os.listdir(out / "page_001")): - print(" ", f) diff --git a/_replay_hstrip.py b/_replay_hstrip.py deleted file mode 100644 index b4113e5..0000000 --- a/_replay_hstrip.py +++ /dev/null @@ -1,24 +0,0 @@ -import os,tempfile,contextlib,io,json,shutil -tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir -os.makedirs("_tess_tmp",exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -RUN=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"); D=RUN/"pages" -OUT=RUN/"all_article_crops_hstrip"; PAPER="andhra_jyothi" -if OUT.exists(): shutil.rmtree(OUT) -for pg in (1,2,3,4): - png=str(D/f"page_{pg:03d}.png") - regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] - buf=io.StringIO() - with contextlib.redirect_stdout(buf): - regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png) - regs=se.drop_masthead_regions(regs,PAPER,pg,png); regs=se.promote_paragraph_titles(regs,png,PAPER) - bars=separator_barriers(png,regs) - ds=se.find_article_starts_by_dateline(regs,png,PAPER) - blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars) - ext=[l for l in buf.getvalue().splitlines() if "Headline-strip" in l] - print(f"page {pg}: {n} crops | {len(ext)} headline-strip extension(s)") - for l in ext: print(" ",l.strip()) -print("DONE") diff --git a/_replay_jangaon.py b/_replay_jangaon.py deleted file mode 100644 index c26b469..0000000 --- a/_replay_jangaon.py +++ /dev/null @@ -1,48 +0,0 @@ -import os,tempfile,contextlib,io,json,shutil -tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir -os.makedirs("_tess_tmp",exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -se._ACTIVE_PAPER = "namaste_telangana" # gates paper-specific clustering passes (pipeline sets this too) -RUN=Path(os.environ.get("JG_RUN","output/NamastheTelangana_Jangaon_20260520_20260609_130635")); D=RUN/"pages" -OUT=RUN/"all_article_crops_review"; P="namaste_telangana" -if OUT.exists(): shutil.rmtree(OUT) -for pg in (1,2): - png=str(D/f"page_{pg:03d}.png") - regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] - buf=io.StringIO() - with contextlib.redirect_stdout(buf): - regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png) - regs=se.drop_masthead_regions(regs,P,pg,png); regs=se.drop_classifieds_regions(regs,png); regs=se.tag_legal_notices(regs,png); regs=se.promote_paragraph_titles(regs,png,P) - if pg==1: regs=se.detect_sakshi_headline_bands(regs,png) # NT: front-page display headlines only - regs=se.mark_bullet_titles(regs,png) - ds=se.find_article_starts_by_dateline(regs,png,P) - bars=separator_barriers(png,regs) - _probe=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - if se.recover_orphan_text_headlines(_probe,regs,png): ds=se.find_article_starts_by_dateline(regs,png,P) - blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - se.draw_boundary_map_debug(png,regs,D,pg,dateline_starts=ds,sep_lines=bars) - n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars) - log=buf.getvalue() - rm={r['id']:r for r in regs}; dlids={s['region_id'] for s in ds} - print(f"\n=== page {pg}: {n} crops, {len(ds)} datelines ===") - for b in sorted(blocks,key=lambda b:(b['bbox'][1],b['bbox'][0])): - x1,y1,x2,y2=b['bbox']; w,h=x2-x1,y2-y1 - ndl=sum(1 for m in b['members'] if m in dlids) - types={} - for m in b['members']: - t=rm.get(m,{}).get('type','?'); types[t]=types.get(t,0)+1 - ntext=types.get('text',0); nimg=types.get('image',0) - flags=[] - if ndl>=2: flags.append(f"{ndl}DL(roundup?)") - if ntext==0 and nimg>0: flags.append("IMG-ONLY(no text)") - if len(b['members'])==1: flags.append("SINGLE-region") - if b['kind']=='O': flags.append("ORPHAN") - print(f" R{b['anchor_id']:>3} {b['kind']} {'RAW' if b.get('_raw_rect') else ' '} " - f"bbox=[{x1},{y1},{x2},{y2}] {w}x{h} mem={len(b['members'])} {types} " - f"{' '.join(flags)}") - for key in ("Section banner","Containment-merge","Headline-merge","Banner rectangle"): - c=[l.strip() for l in log.splitlines() if key in l] - if c: print(f" [{key}] x{len(c)//2 if key in ('Headline-merge','Containment-merge','Section banner','Banner rectangle') else len(c)}") -print("\nDONE ->",OUT) diff --git a/_replay_namaste.py b/_replay_namaste.py deleted file mode 100644 index 4e8bfca..0000000 --- a/_replay_namaste.py +++ /dev/null @@ -1,34 +0,0 @@ -import os,tempfile,contextlib,io,json,shutil -tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir -os.makedirs("_tess_tmp",exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -se._ACTIVE_PAPER = "namaste_telangana" # gates paper-specific clustering passes (pipeline sets this too) -RUN=Path("output/NamastheTelangana_Siddipet_20260602_20260604_214937"); D=RUN/"pages" -OUT=RUN/"all_article_crops_final"; P="namaste_telangana" -if OUT.exists(): shutil.rmtree(OUT) -for pg in (1,2,3,4): - png=str(D/f"page_{pg:03d}.png") - regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] - buf=io.StringIO() - with contextlib.redirect_stdout(buf): - regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png) - regs=se.drop_masthead_regions(regs,P,pg,png); regs=se.drop_classifieds_regions(regs,png); regs=se.tag_legal_notices(regs,png); regs=se.promote_paragraph_titles(regs,png,P) - if pg==1: regs=se.detect_sakshi_headline_bands(regs,png) # NT: front-page display headlines only - regs=se.mark_bullet_titles(regs,png) - ds=se.find_article_starts_by_dateline(regs,png,P) - bars=separator_barriers(png,regs) - _probe=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - if se.recover_orphan_text_headlines(_probe,regs,png): ds=se.find_article_starts_by_dateline(regs,png,P) - blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - se.draw_boundary_map_debug(png,regs,D,pg,dateline_starts=ds,sep_lines=bars) - n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars) - log=buf.getvalue() - tags={k:sum(1 for l in log.splitlines() if k in l) for k in - ["Caption bound","Caption orphan dropped","bullet titles flagged","Headline-strip", - "Floor-trim","Block dateline split","Multi-column body","orphan overlap"]} - tags={k:(v//2 if k in ("Headline-strip","Floor-trim","Multi-column body","Block dateline split","orphan overlap") else v) for k,v in tags.items()} - over=[b['anchor_id'] for b in blocks if len([m for m in b['members'] if m in {s['region_id'] for s in ds}])>=2] - print(f"page {pg}: {n} crops, {len(ds)} datelines, 2+dl-blocks={over or 'none'} | "+", ".join(f"{k}:{v}" for k,v in tags.items() if v)) -print("DONE ->",OUT) diff --git a/_replay_pg1.py b/_replay_pg1.py deleted file mode 100644 index 7159692..0000000 --- a/_replay_pg1.py +++ /dev/null @@ -1,47 +0,0 @@ -import sys, json -sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -png = D / "page_001.png" -regions = json.loads((D / "page_001.regions.json").read_text())["regions"] -print(f"raw regions: {len(regions)}") - -# 1) masthead drop -regions2 = se.drop_masthead_regions(regions, "andhra_jyothi", 1, png) -dropped = {r['id'] for r in regions} - {r['id'] for r in regions2} -print(f"masthead dropped ids: {sorted(dropped)} -> {len(regions2)} regions") - -# 2) dateline starts -ds = se.find_article_starts_by_dateline(regions2, str(png), "andhra_jyothi") -print(f"dateline starts: {len(ds)}") -for s in ds: - print(f" DL region_id={s['region_id']} headline_id={s.get('headline_id')} bbox={s['bbox']}") - -# 3) separator barriers -bars = separator_barriers(str(png), regions2) -print(f"separator barriers: {len(bars)}") - -# 4) cluster -blocks = se.cluster_all_article_blocks(regions2, dateline_starts=ds, sep_lines=bars) -print(f"\nblocks: {len(blocks)}") -dl_ids = {s['region_id'] for s in ds} -for b in sorted(blocks, key=lambda d: (d['bbox'][1], d['bbox'][0])): - mem = b['members'] - has_dl = any(m in dl_ids for m in mem) - print(f" block anchor={b['anchor_id']} kind={b['kind']} dl={has_dl} bbox={b['bbox']} members={sorted(mem)}") - -# 5) render crops to /tmp for visual check -import shutil -out = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/all_article_crops_test") -if out.exists(): - shutil.rmtree(out) -out.mkdir(parents=True) -n = se.crop_all_article_blocks(str(png), regions2, str(out), 1, - dateline_starts=ds, sep_lines=bars) -print(f"\ncrops written: {n} -> {out}/page_001") -import os -for f in sorted(os.listdir(out / "page_001")): - print(" ", f) diff --git a/_replay_pg23.py b/_replay_pg23.py deleted file mode 100644 index 5f1720c..0000000 --- a/_replay_pg23.py +++ /dev/null @@ -1,33 +0,0 @@ -import sys, json -sys.path.insert(0, "/Users/kranthikumar/Documents/telugu_extractor") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -for pg in (2, 3): - png = D / f"page_{pg:03d}.png" - regions = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"] - regions = se.drop_masthead_regions(regions, "andhra_jyothi", pg, png) - ds = se.find_article_starts_by_dateline(regions, str(png), "andhra_jyothi") - bars = separator_barriers(str(png), regions) - blocks = se.cluster_all_article_blocks(regions, dateline_starts=ds, sep_lines=bars) - dl_ids = {s['region_id'] for s in ds} - print(f"\n==== PAGE {pg} datelines={len(ds)} bars={len(bars)} blocks={len(blocks)} ====") - # each dateline must sit in a block that ALSO has a headline/title anchor - for s in ds: - rid = s['region_id'] - owner = None - for b in blocks: - if rid in b['members'] or rid == b['anchor_id']: - owner = b; break - kind = owner['kind'] if owner else '??' - ndl = sum(1 for m in owner['members'] if m in dl_ids) if owner else 0 - flag = '' - if owner is None: - flag = 'LOST' - elif kind == 'DL': - flag = 'headless(DL)' - elif ndl > 1: - flag = f'MERGED({ndl} datelines)' - print(f" DL R{rid} -> block anchor={owner['anchor_id'] if owner else None} kind={kind} {flag}") diff --git a/_replay_political.py b/_replay_political.py deleted file mode 100644 index b5fc71a..0000000 --- a/_replay_political.py +++ /dev/null @@ -1,53 +0,0 @@ -import os, tempfile, contextlib, io, json, sys, shutil -tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -# Replays the POLITICAL crop step (no API): saved political_result.json member ids -# + freshly recomputed region prep chain -> crop_political_articles (block-snap). -RUNS = [ - ("sakshi", Path("output/Sakshi_Jangaon_District_20260520_20260609_210104"), [1]), - ("andhra_jyothi", Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"), [2, 3, 4]), - ("namaste_telangana", Path("output/NamastheTelangana_Jangaon_20260520_20260608_124720"), [1]), -] -for paper, RUN, pages in RUNS: - se._ACTIVE_PAPER = paper - D = RUN / "pages" - OUT = RUN / "articles_review" - if OUT.exists(): - shutil.rmtree(OUT) - for pg in pages: - png = str(D / f"page_{pg:03d}.png") - prf = D / f"page_{pg:03d}.political_result.json" - if not prf.exists() or not os.path.exists(png): - continue - political = json.load(open(prf)).get("political_articles", []) - if not political: - continue - regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"] - buf = io.StringIO() - with contextlib.redirect_stdout(buf): - regs = se.dedup_overlapping_regions(regs) - regs = se.merge_stacked_title_lines(regs, png) - regs = se.drop_masthead_regions(regs, paper, pg, png) - regs = se.drop_classifieds_regions(regs, png) - regs = se.tag_legal_notices(regs, png) - regs = se.promote_paragraph_titles(regs, png, paper) - if paper == "sakshi": - regs = se.detect_sakshi_headline_bands(regs, png) - regs = se.mark_bullet_titles(regs, png) - ds = se.find_article_starts_by_dateline(regs, png, paper) - bars = separator_barriers(png, regs) - _p = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) - if se.recover_orphan_text_headlines(_p, regs, png): - ds = se.find_article_starts_by_dateline(regs, png, paper) - recs = se.crop_political_articles(png, political, regs, OUT, pg, - dateline_starts=ds, sep_lines=bars) - print(f"=== {RUN.name} page {pg}: {len(political)} political -> {len(recs)} crops") - for l in buf.getvalue().splitlines(): - if any(k in l for k in ("Block-snap", "Cropped:", "Clipped", "Floored", "Grew", - "Banner", "block-snap unavailable")): - print(" ", l.strip()) -print("DONE") diff --git a/_replay_rescue.py b/_replay_rescue.py deleted file mode 100644 index b536288..0000000 --- a/_replay_rescue.py +++ /dev/null @@ -1,25 +0,0 @@ -import os,tempfile,contextlib,io,json,shutil -tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir -os.makedirs("_tess_tmp",exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -RUN=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"); D=RUN/"pages" -OUT=RUN/"all_article_crops_rescue"; PAPER="andhra_jyothi" -if OUT.exists(): shutil.rmtree(OUT) -for pg in (1,2,3,4): - png=str(D/f"page_{pg:03d}.png") - regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] # 0.5 saved - buf=io.StringIO() - with contextlib.redirect_stdout(buf): - regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png) - regs=se.drop_masthead_regions(regs,PAPER,pg,png); regs=se.promote_paragraph_titles(regs,png,PAPER) - bars=separator_barriers(png,regs) - regs=se.rescue_headlines_above_photos(regs,png,PAPER,bars) # NEW - ds=se.find_article_starts_by_dateline(regs,png,PAPER) - blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars) - resc=[l for l in buf.getvalue().splitlines() if "HEADLINE RESCUE" in l] - print(f"page {pg}: {n} crops | {len(resc)} headline(s) rescued") - for l in resc: print(" ",l.strip()) -print("DONE") diff --git a/_replay_sakshi.py b/_replay_sakshi.py deleted file mode 100644 index d47d665..0000000 --- a/_replay_sakshi.py +++ /dev/null @@ -1,47 +0,0 @@ -import os,tempfile,contextlib,io,json,shutil -tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir -os.makedirs("_tess_tmp",exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -se._ACTIVE_PAPER = "sakshi" # gate Sakshi-specific clustering passes -RUN=Path(os.environ.get("SAK_RUN","output/Sakshi_Jangaon_District_20260520_20260609_210104")); D=RUN/"pages" -OUT=RUN/"all_article_crops_review"; P="sakshi" -if OUT.exists(): shutil.rmtree(OUT) -for pg in (1,2): - png=str(D/f"page_{pg:03d}.png") - regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] - buf=io.StringIO() - with contextlib.redirect_stdout(buf): - regs=se.dedup_overlapping_regions(regs); regs=se.merge_stacked_title_lines(regs,png) - regs=se.drop_masthead_regions(regs,P,pg,png); regs=se.drop_classifieds_regions(regs,png); regs=se.tag_legal_notices(regs,png); regs=se.promote_paragraph_titles(regs,png,P) - regs=se.detect_sakshi_headline_bands(regs,png) - regs=se.mark_bullet_titles(regs,png) - ds=se.find_article_starts_by_dateline(regs,png,P) - bars=separator_barriers(png,regs) - _probe=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - if se.recover_orphan_text_headlines(_probe,regs,png): ds=se.find_article_starts_by_dateline(regs,png,P) - blocks=se.cluster_all_article_blocks(regs,ds,sep_lines=bars) - se.draw_boundary_map_debug(png,regs,D,pg,dateline_starts=ds,sep_lines=bars) - n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars,overlay=True) - log=buf.getvalue() - rm={r['id']:r for r in regs}; dlids={s['region_id'] for s in ds} - print(f"\n=== page {pg}: {n} crops, {len(ds)} datelines ===") - img_orphans=[] - for b in sorted(blocks,key=lambda b:(b['bbox'][1],b['bbox'][0])): - x1,y1,x2,y2=b['bbox']; w,h=x2-x1,y2-y1 - types={} - for m in b['members']: - t=rm.get(m,{}).get('type','?'); types[t]=types.get(t,0)+1 - ntext=types.get('text',0); nimg=types.get('image',0) - is_art=any(rm.get(m,{}).get('type') in ('doc_title','paragraph_title') for m in b['members']) or any(m in dlids for m in b['members']) - flags=[] - if nimg>0 and not is_art: flags.append("IMG-ORPHAN?") - if b['kind']=='O': flags.append("ORPHAN") - if nimg>0 and not is_art and ntext==0: img_orphans.append(b['anchor_id']) - print(f" R{b['anchor_id']:>3} {b['kind']} bbox=[{x1},{y1},{x2},{y2}] {w}x{h} mem={len(b['members'])} {types} {' '.join(flags)}") - binds=sorted({l.strip() for l in log.splitlines() - if "Orphan photo" in l or "Masthead" in l or "📐" in l or "rule-split" in l}) - print(f" >>> image-only orphans REMAINING: {img_orphans}") - for l in binds: print(f" {l}") -print("\nDONE ->",OUT) diff --git a/_replay_thresh045.py b/_replay_thresh045.py deleted file mode 100644 index 01652a4..0000000 --- a/_replay_thresh045.py +++ /dev/null @@ -1,24 +0,0 @@ -import os,tempfile,contextlib,io -tempfile.tempdir=os.path.abspath("_tess_tmp"); os.environ["TMPDIR"]=tempfile.tempdir -os.makedirs("_tess_tmp",exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -RUN=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919"); D=RUN/"pages" -OUT=RUN/"all_article_crops_t045"; PAPER="andhra_jyothi" -import shutil -if OUT.exists(): shutil.rmtree(OUT) -for pg in (1,2,3,4): - png=str(D/f"page_{pg:03d}.png") - with contextlib.redirect_stdout(io.StringIO()): - regs=se.detect_regions(png, threshold=0.45) # NEW cutoff - regs=se.dedup_overlapping_regions(regs) - regs=se.merge_stacked_title_lines(regs,png) - regs=se.drop_masthead_regions(regs,PAPER,pg,png) - regs=se.promote_paragraph_titles(regs,png,PAPER) - ds=se.find_article_starts_by_dateline(regs,png,PAPER) - bars=separator_barriers(png,regs) - n=se.crop_all_article_blocks(png,regs,str(OUT),pg,dateline_starts=ds,sep_lines=bars) - nreg=len(regs) - print(f"page {pg}: {nreg} regions, {len(ds)} datelines, {n} crops") -print("DONE ->",OUT) diff --git a/_sak_base.log b/_sak_base.log deleted file mode 100644 index 5048a17..0000000 --- a/_sak_base.log +++ /dev/null @@ -1,78 +0,0 @@ - -=== page 1: 22 crops, 17 datelines === - R 55 H bbox=[2796,291,4114,2002] 1318x1711 mem=8 {'image': 2, 'text': 5, 'doc_title': 1} - R 94 P bbox=[2113,299,2785,3703] 672x3404 mem=5 {'paragraph_title': 1, 'text': 4} - R 52 H bbox=[1080,371,2766,2350] 1686x1979 mem=6 {'doc_title': 1, 'image': 3, 'paragraph_title': 1, 'text': 1} - R 71 DL bbox=[769,913,1375,1781] 606x868 mem=3 {'text': 2, 'paragraph_title': 1} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 11 DL bbox=[694,1789,1440,2678] 746x889 mem=1 {'text': 1} - R 77 H bbox=[2793,1973,4114,3303] 1321x1330 mem=10 {'text': 6, 'image': 1, 'figure_title': 1, 'doc_title': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 66 P bbox=[694,2686,1391,3745] 697x1059 mem=4 {'paragraph_title': 1, 'text': 3} - R 51 P bbox=[1399,2686,2105,3458] 706x772 mem=3 {'paragraph_title': 1, 'text': 2} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 78 H bbox=[749,3466,2070,6049] 1321x2583 mem=11 {'text': 8, 'image': 1, 'figure_title': 1, 'doc_title': 1} - R 54 H bbox=[2793,3509,4114,6094] 1321x2585 mem=13 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 1} - R 4 DL bbox=[2113,3707,2752,4876] 639x1169 mem=2 {'text': 1, 'image': 1} - R 3 DL bbox=[750,3753,1388,4588] 638x835 mem=1 {'text': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=4 {'doc_title': 1, 'text': 3} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,1391,6637] 619x555 mem=2 {'paragraph_title': 1, 'text': 1} - R 18 O bbox=[1430,6086,2049,6635] 619x549 mem=1 {'text': 1} ORPHAN - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 🖼 Orphan photo: R28 → article R78 (an image must belong to an article) - 🖼 Orphan photo: R28 → article R78 (an image must belong to an article) - 🖼 Orphan photo: R28 → article R78 (an image must belong to an article) - 🖼 Orphan photo: R28 → article R78 (an image must belong to an article) - -=== page 2: 20 crops, 11 datelines === - R 61 O bbox=[777,474,1506,2308] 729x1834 mem=8 {'image': 3, 'text': 3, 'figure_title': 2} IMG-ORPHAN? ORPHAN - R 82 H bbox=[695,478,2747,2308] 2052x1830 mem=10 {'text': 3, 'image': 4, 'figure_title': 2, 'doc_title': 1} - R 55 O bbox=[2549,479,2801,1028] 252x549 mem=2 {'image': 1, 'text': 1} IMG-ORPHAN? ORPHAN - R129 P bbox=[80,482,769,1053] 689x571 mem=2 {'paragraph_title': 1, 'text': 1} - R 72 H bbox=[2755,482,3519,2232] 764x1750 mem=8 {'image': 3, 'text': 3, 'doc_title': 1, 'figure_title': 1} - R127 H bbox=[3353,482,4115,2215] 762x1733 mem=9 {'text': 4, 'image': 3, 'figure_title': 1, 'doc_title': 1} - R 24 O bbox=[80,1061,687,2305] 607x1244 mem=4 {'image': 1, 'figure_title': 1, 'text': 2} IMG-ORPHAN? ORPHAN - R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'doc_title': 1, 'text': 1, 'image': 2} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R113 H bbox=[72,2417,709,4641] 637x2224 mem=7 {'doc_title': 1, 'text': 3, 'image': 2, 'figure_title': 1} - R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 4 F bbox=[2002,3658,2752,5938] 750x2280 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 3} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,6617] 478x1638 mem=6 {'text': 5, 'paragraph_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 77 H bbox=[1217,5969,2752,6682] 1535x713 mem=4 {'text': 3, 'doc_title': 1} - >>> image-only orphans REMAINING: [] - 🖼 Orphan photo: R42 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R52 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R63 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R60 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R38 → article R72 (an image must belong to an article) - 🖼 Orphan photo: R48 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R42 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R52 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R63 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R60 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R38 → article R72 (an image must belong to an article) - 🖼 Orphan photo: R48 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R42 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R52 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R63 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R60 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R38 → article R72 (an image must belong to an article) - 🖼 Orphan photo: R48 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R42 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R52 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R63 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R60 → article R82 (an image must belong to an article) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_fix2.log b/_sak_fix2.log deleted file mode 100644 index 4a9833e..0000000 --- a/_sak_fix2.log +++ /dev/null @@ -1,63 +0,0 @@ - -=== page 1: 19 crops, 16 datelines === - R 55 H bbox=[2796,1049,4114,2002] 1318x953 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 52 H bbox=[664,1067,2749,2657] 2085x1590 mem=8 {'doc_title': 1, 'text': 3, 'image': 2, 'paragraph_title': 2} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 94 P bbox=[2113,1941,2755,3257] 642x1316 mem=4 {'paragraph_title': 1, 'text': 3} - R 77 H bbox=[2793,1973,4114,3315] 1321x1342 mem=8 {'text': 6, 'doc_title': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 66 P bbox=[693,2665,1391,3349] 698x684 mem=2 {'paragraph_title': 1, 'text': 1} - R 51 P bbox=[1399,2665,2105,3349] 706x684 mem=3 {'paragraph_title': 1, 'text': 2} - R100 H bbox=[2113,2860,4114,4876] 2001x2016 mem=10 {'doc_title': 1, 'text': 5, 'image': 3, 'figure_title': 1} - R 99 H bbox=[750,3357,2068,4588] 1318x1231 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 78 H bbox=[749,3891,2070,6049] 1321x2158 mem=10 {'doc_title': 1, 'text': 8, 'figure_title': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=4 {'doc_title': 1, 'text': 3} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [664, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 21 crops, 11 datelines === - R 61 O bbox=[777,474,1506,2308] 729x1834 mem=8 {'image': 3, 'text': 3, 'figure_title': 2} IMG-ORPHAN? ORPHAN - R 82 H bbox=[695,478,2747,2308] 2052x1830 mem=10 {'text': 3, 'image': 4, 'figure_title': 2, 'doc_title': 1} - R 55 O bbox=[2549,479,2801,1028] 252x549 mem=2 {'image': 1, 'text': 1} IMG-ORPHAN? ORPHAN - R129 P bbox=[80,482,769,1053] 689x571 mem=2 {'paragraph_title': 1, 'text': 1} - R 72 H bbox=[2755,482,3519,2232] 764x1750 mem=8 {'image': 3, 'text': 3, 'doc_title': 1, 'figure_title': 1} - R127 H bbox=[3353,482,4115,2215] 762x1733 mem=9 {'text': 4, 'image': 3, 'figure_title': 1, 'doc_title': 1} - R 24 O bbox=[80,1061,687,2305] 607x1244 mem=4 {'image': 1, 'figure_title': 1, 'text': 2} IMG-ORPHAN? ORPHAN - R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'doc_title': 1, 'text': 1, 'image': 2} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R113 H bbox=[72,2417,709,4641] 637x2224 mem=7 {'doc_title': 1, 'text': 3, 'image': 2, 'figure_title': 1} - R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 99 H bbox=[650,3656,2071,6145] 1421x2489 mem=10 {'image': 1, 'text': 7, 'doc_title': 1, 'paragraph_title': 1} - R 10 F bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 4 F bbox=[2002,4723,2752,5938] 750x1215 mem=4 {'text': 2, 'paragraph_title': 2} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 77 H bbox=[1104,5969,2752,6682] 1648x713 mem=4 {'text': 3, 'doc_title': 1} - R139 H bbox=[614,6155,1168,6617] 554x462 mem=2 {'doc_title': 1, 'text': 1} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R139 doc_title [614, 6155, 1168, 6236] (un-boxed display headline band, ink=0.51) - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1104, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R72 (an image must belong to an article) - 🖼 Orphan photo: R42 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R48 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R52 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R60 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R63 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_fix3.log b/_sak_fix3.log deleted file mode 100644 index 6681937..0000000 --- a/_sak_fix3.log +++ /dev/null @@ -1,54 +0,0 @@ - -=== page 1: 16 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1} - R 52 H bbox=[664,1067,2755,3314] 2091x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [664, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2736] 646x2237 mem=8 {'paragraph_title': 1, 'image': 2, 'text': 3, 'figure_title': 2} - R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'text': 1, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[650,3656,2071,6145] 1421x2489 mem=10 {'image': 1, 'text': 7, 'doc_title': 1, 'paragraph_title': 1} - R 10 F bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 4 F bbox=[2002,4723,2752,5938] 750x1215 mem=4 {'text': 2, 'paragraph_title': 2} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 77 H bbox=[1104,5969,2752,6682] 1648x713 mem=4 {'text': 3, 'doc_title': 1} - R139 H bbox=[614,6155,1168,6617] 554x462 mem=2 {'doc_title': 1, 'text': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline SYNTH: R139 doc_title [614, 6155, 1168, 6236] (un-boxed display headline band, ink=0.51) - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1104, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_fix4.log b/_sak_fix4.log deleted file mode 100644 index 9032b7b..0000000 --- a/_sak_fix4.log +++ /dev/null @@ -1,54 +0,0 @@ - -=== page 1: 16 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1} - R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2736] 646x2237 mem=8 {'paragraph_title': 1, 'image': 2, 'text': 3, 'figure_title': 2} - R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'text': 1, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 4 F bbox=[2002,3658,2752,5938] 750x2280 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 3} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=4 {'text': 3, 'doc_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,6145] 478x1166 mem=5 {'text': 4, 'paragraph_title': 1} - R 77 H bbox=[1147,5193,2752,6694] 1605x1501 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R139 H bbox=[614,6155,1168,6617] 554x462 mem=2 {'doc_title': 1, 'text': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline SYNTH: R139 doc_title [614, 6155, 1168, 6236] (un-boxed display headline band, ink=0.51) - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_fix5.log b/_sak_fix5.log deleted file mode 100644 index b1068d9..0000000 --- a/_sak_fix5.log +++ /dev/null @@ -1,52 +0,0 @@ - -=== page 1: 16 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1} - R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2736] 646x2237 mem=8 {'paragraph_title': 1, 'image': 2, 'text': 3, 'figure_title': 2} - R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 88 P bbox=[2002,3658,2752,5938] 750x2280 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 3} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,6617] 478x1638 mem=6 {'text': 5, 'paragraph_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_fix6.log b/_sak_fix6.log deleted file mode 100644 index 178f746..0000000 --- a/_sak_fix6.log +++ /dev/null @@ -1,52 +0,0 @@ - -=== page 1: 16 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1} - R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1} - R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 88 P bbox=[2002,3658,2752,5938] 750x2280 mem=8 {'text': 4, 'image': 1, 'paragraph_title': 3} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,6617] 478x1638 mem=6 {'text': 5, 'paragraph_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_fix7.log b/_sak_fix7.log deleted file mode 100644 index 9317ffa..0000000 --- a/_sak_fix7.log +++ /dev/null @@ -1,55 +0,0 @@ - -=== page 1: 16 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'doc_title': 1, 'text': 9, 'image': 1, 'paragraph_title': 1} - R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'doc_title': 1, 'text': 9, 'image': 2, 'paragraph_title': 5} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1} - R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1} - R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1} - R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1} - R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_fixABC.log b/_sak_fixABC.log deleted file mode 100644 index 2be5047..0000000 --- a/_sak_fixABC.log +++ /dev/null @@ -1,55 +0,0 @@ - -=== page 1: 12 crops, 16 datelines === - R 55 H bbox=[2796,1049,4114,2002] 1318x953 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 52 H bbox=[664,1067,2749,2657] 2085x1590 mem=8 {'doc_title': 1, 'text': 3, 'image': 2, 'paragraph_title': 2} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 94 P bbox=[2113,1941,2755,3257] 642x1316 mem=4 {'paragraph_title': 1, 'text': 3} - R 77 H bbox=[2793,1973,4114,3315] 1321x1342 mem=8 {'text': 6, 'doc_title': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 66 P bbox=[693,2665,1391,6678] 698x4013 mem=2 {'paragraph_title': 1, 'text': 1} - R 51 P bbox=[1399,2665,2105,6678] 706x4013 mem=3 {'paragraph_title': 1, 'text': 2} - R 99 H bbox=[749,2860,4114,6698] 3365x3838 mem=45 {'text': 30, 'image': 5, 'figure_title': 2, 'paragraph_title': 3, 'doc_title': 5} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3353, 4097, 3452] (un-boxed display headline band, ink=0.32) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [664, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 21 crops, 11 datelines === - R 61 O bbox=[777,474,1506,2308] 729x1834 mem=8 {'image': 3, 'text': 3, 'figure_title': 2} IMG-ORPHAN? ORPHAN - R 82 H bbox=[695,478,2747,2308] 2052x1830 mem=10 {'text': 3, 'image': 4, 'figure_title': 2, 'doc_title': 1} - R 55 O bbox=[2549,479,2801,1028] 252x549 mem=2 {'image': 1, 'text': 1} IMG-ORPHAN? ORPHAN - R129 P bbox=[80,482,769,1053] 689x571 mem=2 {'paragraph_title': 1, 'text': 1} - R 72 H bbox=[2755,482,3519,2232] 764x1750 mem=8 {'image': 3, 'text': 3, 'doc_title': 1, 'figure_title': 1} - R127 H bbox=[3353,482,4115,2215] 762x1733 mem=9 {'text': 4, 'image': 3, 'figure_title': 1, 'doc_title': 1} - R 24 O bbox=[80,1061,687,2305] 607x1244 mem=4 {'image': 1, 'figure_title': 1, 'text': 2} IMG-ORPHAN? ORPHAN - R118 H bbox=[2795,2298,4115,2954] 1320x656 mem=4 {'doc_title': 1, 'text': 1, 'image': 2} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=3 {'doc_title': 1, 'text': 2} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R113 H bbox=[72,2417,709,4641] 637x2224 mem=7 {'doc_title': 1, 'text': 3, 'image': 2, 'figure_title': 1} - R 14 DL bbox=[3475,2685,4115,3999] 640x1314 mem=5 {'text': 3, 'image': 1, 'paragraph_title': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 99 H bbox=[650,3656,2071,6145] 1421x2489 mem=10 {'image': 1, 'text': 7, 'doc_title': 1, 'paragraph_title': 1} - R 10 F bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,1963,5939] 747x1229 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 4 F bbox=[2002,4723,2752,5938] 750x1215 mem=4 {'text': 2, 'paragraph_title': 2} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 77 H bbox=[1104,5969,2752,6682] 1648x713 mem=4 {'text': 3, 'doc_title': 1} - R139 H bbox=[614,6155,1168,6617] 554x462 mem=2 {'doc_title': 1, 'text': 1} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R139 doc_title [614, 6155, 1168, 6236] (un-boxed display headline band, ink=0.51) - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1104, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R72 (an image must belong to an article) - 🖼 Orphan photo: R42 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R48 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R52 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R60 → article R82 (an image must belong to an article) - 🖼 Orphan photo: R63 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_newrun.log b/_sak_newrun.log deleted file mode 100644 index 2fc667b..0000000 --- a/_sak_newrun.log +++ /dev/null @@ -1,41 +0,0 @@ - -=== page 1: 13 crops, 14 datelines === - R 53 H bbox=[2792,1069,4115,3285] 1323x2216 mem=14 {'doc_title': 1, 'text': 9, 'image': 1, 'figure_title': 1, 'paragraph_title': 2} - R 46 H bbox=[684,1077,2784,3285] 2100x2208 mem=21 {'doc_title': 2, 'text': 11, 'image': 2, 'paragraph_title': 6} - R 66 H bbox=[99,1078,681,2654] 582x1576 mem=3 {'doc_title': 1, 'text': 1, 'paragraph_title': 1} - R 65 H bbox=[99,2678,680,4455] 581x1777 mem=6 {'text': 3, 'image': 1, 'doc_title': 1, 'paragraph_title': 1} - R 82 H bbox=[2114,3293,4115,5007] 2001x1714 mem=11 {'doc_title': 1, 'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 75 H bbox=[749,3323,2069,4792] 1320x1469 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 3 DL bbox=[98,4463,741,5703] 643x1240 mem=2 {'text': 1, 'image': 1} - R 47 H bbox=[749,4850,2368,5588] 1619x738 mem=6 {'doc_title': 1, 'text': 2, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 93 H bbox=[2791,5058,4115,6247] 1324x1189 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - R 55 H bbox=[2137,5113,2736,6130] 599x1017 mem=2 {'doc_title': 1, 'text': 1} - R 44 H bbox=[98,5711,681,6639] 583x928 mem=2 {'doc_title': 1, 'text': 1} - R100 H bbox=[750,5782,2072,6697] 1322x915 mem=5 {'doc_title': 1, 'text': 2, 'image': 2} - R 56 H bbox=[2564,6284,4115,6691] 1551x407 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline WIDEN: R100 [765, 6130, 1350, 6228] → [765, 6130, 1949, 6228] (un-boxed kicker ink alongside) - -=== page 2: 16 crops, 15 datelines === - R 61 H bbox=[931,490,4115,2536] 3184x2046 mem=32 {'text': 15, 'image': 8, 'doc_title': 2, 'paragraph_title': 5, 'figure_title': 2} - R106 H bbox=[2081,490,2753,5535] 672x5045 mem=6 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 2, 'paragraph_title': 1} - R105 P bbox=[78,498,898,1656] 820x1158 mem=5 {'paragraph_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R128 P bbox=[106,1664,860,2507] 754x843 mem=4 {'paragraph_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R 57 H bbox=[751,2579,2754,4161] 2003x1582 mem=10 {'doc_title': 1, 'text': 7, 'image': 1, 'paragraph_title': 1} - R 69 H bbox=[2794,2589,4115,3863] 1321x1274 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R121 DL bbox=[70,2805,709,3948] 639x1143 mem=6 {'text': 3, 'image': 1, 'paragraph_title': 1, 'figure_title': 1} - R100 H bbox=[752,3306,2070,5044] 1318x1738 mem=5 {'text': 4, 'doc_title': 1} - R 95 H bbox=[2795,3914,4115,4990] 1320x1076 mem=6 {'doc_title': 2, 'image': 1, 'text': 2, 'figure_title': 1} - R 87 DL bbox=[73,3974,709,5049] 636x1075 mem=5 {'text': 2, 'image': 2, 'figure_title': 1} - R 80 H bbox=[2814,5054,4115,6172] 1301x1118 mem=7 {'text': 4, 'image': 2, 'doc_title': 1} - R115 DL bbox=[94,5097,1161,6624] 1067x1527 mem=5 {'text': 4, 'image': 1} - R107 H bbox=[1199,5102,2071,6685] 872x1583 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 74 F bbox=[658,5350,1139,6624] 481x1274 mem=4 {'text': 4} - R 7 DL bbox=[2114,5559,2754,6684] 640x1125 mem=3 {'text': 1, 'image': 1, 'paragraph_title': 1} - R 90 H bbox=[2814,5760,3431,6635] 617x875 mem=4 {'doc_title': 1, 'text': 3} - R 76 H bbox=[3474,5970,4115,6634] 641x664 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R12 → 2 bands at rules [4170] - 🖼 Orphan photo: R36 → article R87 (an image must belong to an article) - -DONE -> output/Sakshi_Jangaon District_20260513_20260610_140735/all_article_crops_review diff --git a/_sak_newrun2.log b/_sak_newrun2.log deleted file mode 100644 index 1ffcc65..0000000 --- a/_sak_newrun2.log +++ /dev/null @@ -1,50 +0,0 @@ - -=== page 1: 19 crops, 14 datelines === - R 53 H bbox=[2792,1069,4115,3285] 1323x2216 mem=14 {'text': 9, 'image': 1, 'doc_title': 1, 'figure_title': 1, 'paragraph_title': 2} - R 46 H bbox=[684,1077,2784,2187] 2100x1110 mem=8 {'doc_title': 2, 'text': 4, 'image': 1, 'paragraph_title': 1} - R 84 P bbox=[1433,1077,2107,2755] 674x1678 mem=2 {'paragraph_title': 1, 'text': 1} - R 66 H bbox=[99,1078,681,2654] 582x1576 mem=3 {'doc_title': 1, 'text': 1, 'paragraph_title': 1} - R 45 P bbox=[689,2195,1425,3315] 736x1120 mem=2 {'paragraph_title': 1, 'text': 1} - R 72 P bbox=[2115,2195,2784,2915] 669x720 mem=5 {'paragraph_title': 1, 'text': 3, 'image': 1} - R 65 H bbox=[99,2678,680,4291] 581x1613 mem=4 {'text': 2, 'image': 1, 'doc_title': 1} - R 48 P bbox=[1433,2763,2107,3315] 674x552 mem=2 {'paragraph_title': 1, 'text': 1} - R 60 P bbox=[2115,2923,2784,3285] 669x362 mem=2 {'paragraph_title': 1, 'text': 1} - R 82 H bbox=[2114,3293,4115,5007] 2001x1714 mem=11 {'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1, 'doc_title': 1} - R 75 H bbox=[749,3323,2069,4792] 1320x1469 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 86 P bbox=[102,4299,741,4455] 639x156 mem=2 {'paragraph_title': 1, 'text': 1} - R 3 DL bbox=[98,4463,741,5703] 643x1240 mem=2 {'text': 1, 'image': 1} - R 47 H bbox=[749,4850,2368,5588] 1619x738 mem=6 {'doc_title': 1, 'text': 2, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 93 H bbox=[2791,5058,4115,6247] 1324x1189 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - R 55 H bbox=[2137,5113,2736,6130] 599x1017 mem=2 {'doc_title': 1, 'text': 1} - R 44 H bbox=[98,5711,681,6639] 583x928 mem=2 {'doc_title': 1, 'text': 1} - R100 H bbox=[750,5782,2072,6697] 1322x915 mem=5 {'doc_title': 1, 'text': 2, 'image': 2} - R 56 H bbox=[2564,6284,4115,6691] 1551x407 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline WIDEN: R100 [765, 6130, 1350, 6228] → [765, 6130, 1949, 6228] (un-boxed kicker ink alongside) - -=== page 2: 19 crops, 15 datelines === - R 61 H bbox=[931,490,4115,2536] 3184x2046 mem=32 {'text': 15, 'image': 8, 'doc_title': 2, 'paragraph_title': 5, 'figure_title': 2} - R127 P bbox=[2081,490,2754,4147] 673x3657 mem=3 {'paragraph_title': 1, 'text': 1, 'figure_title': 1} - R105 P bbox=[78,498,898,1518] 820x1020 mem=5 {'paragraph_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R121 DL bbox=[70,1526,743,3817] 673x2291 mem=4 {'text': 2, 'image': 1, 'figure_title': 1} - R128 P bbox=[106,1664,860,2507] 754x843 mem=4 {'paragraph_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R 57 H bbox=[754,2579,2751,3639] 1997x1060 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 69 H bbox=[2794,2589,4115,3863] 1321x1274 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 4 DL bbox=[751,3306,2071,4149] 1320x843 mem=3 {'text': 3} - R 81 P bbox=[75,3825,743,3966] 668x141 mem=2 {'paragraph_title': 1, 'text': 1} - R 95 H bbox=[2795,3914,4115,4990] 1320x1076 mem=6 {'doc_title': 2, 'image': 1, 'text': 2, 'figure_title': 1} - R 87 DL bbox=[73,3974,709,5049] 636x1075 mem=5 {'text': 2, 'image': 2, 'figure_title': 1} - R100 H bbox=[752,4203,2070,5044] 1318x841 mem=4 {'text': 3, 'doc_title': 1} - R106 H bbox=[2114,4209,2753,5535] 639x1326 mem=5 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 80 H bbox=[2814,5054,4115,6172] 1301x1118 mem=7 {'text': 4, 'image': 2, 'doc_title': 1} - R115 DL bbox=[94,5097,1161,6624] 1067x1527 mem=5 {'text': 4, 'image': 1} - R107 H bbox=[1199,5102,2071,6685] 872x1583 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 74 F bbox=[658,5350,1139,6624] 481x1274 mem=4 {'text': 4} - R 7 DL bbox=[2114,5559,2754,6684] 640x1125 mem=3 {'text': 1, 'image': 1, 'paragraph_title': 1} - R 90 H bbox=[2814,5760,3431,6635] 617x875 mem=4 {'doc_title': 1, 'text': 3} - R 76 H bbox=[3474,5970,4115,6634] 641x664 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R12 → 2 bands at rules [4170] - 🖼 Orphan photo: R36 → article R87 (an image must belong to an article) - -DONE -> output/Sakshi_Jangaon District_20260513_20260610_140735/all_article_crops_review diff --git a/_sak_newrun3.log b/_sak_newrun3.log deleted file mode 100644 index 3949b33..0000000 --- a/_sak_newrun3.log +++ /dev/null @@ -1,42 +0,0 @@ - -=== page 1: 14 crops, 14 datelines === - R 53 H bbox=[2792,1069,4115,3285] 1323x2216 mem=14 {'text': 9, 'image': 1, 'doc_title': 1, 'figure_title': 1, 'paragraph_title': 2} - R 46 H bbox=[684,1077,2784,3285] 2100x2208 mem=21 {'text': 11, 'image': 2, 'paragraph_title': 6, 'doc_title': 2} - R 66 H bbox=[99,1078,681,2654] 582x1576 mem=3 {'doc_title': 1, 'text': 1, 'paragraph_title': 1} - R 65 H bbox=[99,2678,680,4291] 581x1613 mem=4 {'text': 2, 'image': 1, 'doc_title': 1} - R 82 H bbox=[2114,3293,4115,5007] 2001x1714 mem=11 {'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1, 'doc_title': 1} - R 75 H bbox=[749,3323,2069,4792] 1320x1469 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 86 P bbox=[102,4299,741,4455] 639x156 mem=2 {'paragraph_title': 1, 'text': 1} - R 3 DL bbox=[98,4463,741,5703] 643x1240 mem=2 {'text': 1, 'image': 1} - R 47 H bbox=[749,4850,2368,5588] 1619x738 mem=6 {'doc_title': 1, 'text': 2, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 93 H bbox=[2791,5058,4115,6247] 1324x1189 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - R 55 H bbox=[2137,5113,2736,6130] 599x1017 mem=2 {'doc_title': 1, 'text': 1} - R 44 H bbox=[98,5711,681,6639] 583x928 mem=2 {'doc_title': 1, 'text': 1} - R100 H bbox=[750,5782,2072,6697] 1322x915 mem=5 {'doc_title': 1, 'text': 2, 'image': 2} - R 56 H bbox=[2564,6284,4115,6691] 1551x407 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline WIDEN: R100 [765, 6130, 1350, 6228] → [765, 6130, 1949, 6228] (un-boxed kicker ink alongside) - -=== page 2: 16 crops, 15 datelines === - R 61 H bbox=[931,490,4115,2536] 3184x2046 mem=32 {'text': 15, 'image': 8, 'doc_title': 2, 'paragraph_title': 5, 'figure_title': 2} - R106 H bbox=[2081,490,2753,5535] 672x5045 mem=6 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 2, 'paragraph_title': 1} - R105 P bbox=[78,498,898,1656] 820x1158 mem=5 {'paragraph_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R128 P bbox=[106,1664,860,2507] 754x843 mem=4 {'paragraph_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R 57 H bbox=[751,2579,2754,4161] 2003x1582 mem=11 {'text': 8, 'image': 1, 'doc_title': 1, 'paragraph_title': 1} - R 69 H bbox=[2794,2589,4115,3863] 1321x1274 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R121 DL bbox=[70,2805,709,3948] 639x1143 mem=6 {'text': 3, 'image': 1, 'paragraph_title': 1, 'figure_title': 1} - R 95 H bbox=[2795,3914,4115,4990] 1320x1076 mem=6 {'doc_title': 2, 'image': 1, 'text': 2, 'figure_title': 1} - R 87 DL bbox=[73,3974,709,5049] 636x1075 mem=5 {'text': 2, 'image': 2, 'figure_title': 1} - R100 H bbox=[752,4203,2070,5044] 1318x841 mem=4 {'text': 3, 'doc_title': 1} - R 80 H bbox=[2814,5054,4115,6172] 1301x1118 mem=7 {'text': 4, 'image': 2, 'doc_title': 1} - R115 DL bbox=[94,5097,1161,6624] 1067x1527 mem=5 {'text': 4, 'image': 1} - R107 H bbox=[1199,5102,2071,6685] 872x1583 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 74 F bbox=[658,5350,1139,6624] 481x1274 mem=4 {'text': 4} - R 7 DL bbox=[2114,5559,2754,6684] 640x1125 mem=3 {'text': 1, 'image': 1, 'paragraph_title': 1} - R 90 H bbox=[2814,5760,3431,6635] 617x875 mem=4 {'doc_title': 1, 'text': 3} - R 76 H bbox=[3474,5970,4115,6634] 641x664 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R12 → 2 bands at rules [4170] - 🖼 Orphan photo: R36 → article R87 (an image must belong to an article) - -DONE -> output/Sakshi_Jangaon District_20260513_20260610_140735/all_article_crops_review diff --git a/_sak_newrun4.log b/_sak_newrun4.log deleted file mode 100644 index b046ab8..0000000 --- a/_sak_newrun4.log +++ /dev/null @@ -1,42 +0,0 @@ - -=== page 1: 14 crops, 14 datelines === - R 53 H bbox=[2792,1069,4115,3285] 1323x2216 mem=14 {'text': 9, 'image': 1, 'doc_title': 1, 'figure_title': 1, 'paragraph_title': 2} - R 46 H bbox=[684,1077,2784,3285] 2100x2208 mem=21 {'text': 11, 'image': 2, 'paragraph_title': 6, 'doc_title': 2} - R 66 H bbox=[99,1078,681,2654] 582x1576 mem=3 {'doc_title': 1, 'text': 1, 'paragraph_title': 1} - R 65 H bbox=[99,2678,680,4291] 581x1613 mem=4 {'text': 2, 'image': 1, 'doc_title': 1} - R 82 H bbox=[2114,3293,4115,5007] 2001x1714 mem=11 {'text': 7, 'image': 1, 'figure_title': 1, 'paragraph_title': 1, 'doc_title': 1} - R 75 H bbox=[749,3323,2069,4792] 1320x1469 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 86 P bbox=[102,4299,741,4455] 639x156 mem=2 {'paragraph_title': 1, 'text': 1} - R 3 DL bbox=[98,4463,741,5703] 643x1240 mem=2 {'text': 1, 'image': 1} - R 47 H bbox=[749,4850,2368,5588] 1619x738 mem=6 {'doc_title': 1, 'text': 2, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 93 H bbox=[2791,5058,4115,6247] 1324x1189 mem=6 {'doc_title': 1, 'text': 3, 'image': 1, 'figure_title': 1} - R 55 H bbox=[2137,5113,2736,6130] 599x1017 mem=2 {'doc_title': 1, 'text': 1} - R 44 H bbox=[98,5711,681,6639] 583x928 mem=2 {'doc_title': 1, 'text': 1} - R100 H bbox=[750,5782,2072,6697] 1322x915 mem=5 {'doc_title': 1, 'text': 2, 'image': 2} - R 56 H bbox=[2564,6284,4115,6691] 1551x407 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline WIDEN: R100 [765, 6130, 1350, 6228] → [765, 6130, 1949, 6228] (un-boxed kicker ink alongside) - -=== page 2: 16 crops, 15 datelines === - R 61 H bbox=[931,490,4115,2536] 3184x2046 mem=33 {'text': 15, 'image': 8, 'doc_title': 2, 'paragraph_title': 5, 'figure_title': 3} - R105 P bbox=[78,498,898,1656] 820x1158 mem=5 {'paragraph_title': 1, 'image': 1, 'text': 2, 'figure_title': 1} - R128 P bbox=[106,1664,860,2507] 754x843 mem=4 {'paragraph_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R 57 H bbox=[751,2579,2754,4161] 2003x1582 mem=11 {'text': 8, 'image': 1, 'doc_title': 1, 'paragraph_title': 1} - R 69 H bbox=[2794,2589,4115,3863] 1321x1274 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R121 DL bbox=[70,2805,709,3948] 639x1143 mem=6 {'text': 3, 'image': 1, 'paragraph_title': 1, 'figure_title': 1} - R 95 H bbox=[2795,3914,4115,4990] 1320x1076 mem=6 {'doc_title': 2, 'image': 1, 'text': 2, 'figure_title': 1} - R 87 DL bbox=[73,3974,709,5049] 636x1075 mem=5 {'text': 2, 'image': 2, 'figure_title': 1} - R100 H bbox=[752,4203,2070,5044] 1318x841 mem=4 {'text': 3, 'doc_title': 1} - R106 H bbox=[2114,4209,2753,5535] 639x1326 mem=5 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1, 'paragraph_title': 1} - R 80 H bbox=[2814,5054,4115,6172] 1301x1118 mem=7 {'text': 4, 'image': 2, 'doc_title': 1} - R115 DL bbox=[94,5097,1161,6624] 1067x1527 mem=5 {'text': 4, 'image': 1} - R107 H bbox=[1199,5102,2071,6685] 872x1583 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 74 F bbox=[658,5350,1139,6624] 481x1274 mem=4 {'text': 4} - R 7 DL bbox=[2114,5559,2754,6684] 640x1125 mem=3 {'text': 1, 'image': 1, 'paragraph_title': 1} - R 90 H bbox=[2814,5760,3431,6635] 617x875 mem=4 {'doc_title': 1, 'text': 3} - R 76 H bbox=[3474,5970,4115,6634] 641x664 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R12 → 2 bands at rules [4170] - 🖼 Orphan photo: R36 → article R87 (an image must belong to an article) - -DONE -> output/Sakshi_Jangaon District_20260513_20260610_140735/all_article_crops_review diff --git a/_sak_oldrun2.log b/_sak_oldrun2.log deleted file mode 100644 index d901e23..0000000 --- a/_sak_oldrun2.log +++ /dev/null @@ -1,58 +0,0 @@ - -=== page 1: 19 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'text': 9, 'image': 1, 'doc_title': 1, 'paragraph_title': 1} - R 52 H bbox=[688,1067,2749,2854] 2061x1787 mem=9 {'doc_title': 1, 'text': 4, 'image': 2, 'paragraph_title': 2} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 94 P bbox=[2113,1941,2755,3257] 642x1316 mem=4 {'paragraph_title': 1, 'text': 3} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 66 P bbox=[749,2686,1391,3302] 642x616 mem=2 {'paragraph_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R 51 P bbox=[1399,2862,2105,3349] 706x487 mem=2 {'paragraph_title': 1, 'text': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1} - R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1} - R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1} - R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1} - R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_oldrun3.log b/_sak_oldrun3.log deleted file mode 100644 index a225e8d..0000000 --- a/_sak_oldrun3.log +++ /dev/null @@ -1,55 +0,0 @@ - -=== page 1: 16 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'text': 9, 'image': 1, 'doc_title': 1, 'paragraph_title': 1} - R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'text': 9, 'image': 2, 'paragraph_title': 5, 'doc_title': 1} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1} - R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1} - R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1} - R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1} - R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_oldrun4.log b/_sak_oldrun4.log deleted file mode 100644 index a225e8d..0000000 --- a/_sak_oldrun4.log +++ /dev/null @@ -1,55 +0,0 @@ - -=== page 1: 16 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'text': 9, 'image': 1, 'doc_title': 1, 'paragraph_title': 1} - R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'text': 9, 'image': 2, 'paragraph_title': 5, 'doc_title': 1} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1} - R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1} - R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1} - R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1} - R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sak_val7.log b/_sak_val7.log deleted file mode 100644 index a225e8d..0000000 --- a/_sak_val7.log +++ /dev/null @@ -1,55 +0,0 @@ - -=== page 1: 16 crops, 16 datelines === - R 55 H bbox=[2763,1049,4114,2732] 1351x1683 mem=12 {'text': 9, 'image': 1, 'doc_title': 1, 'paragraph_title': 1} - R 52 H bbox=[688,1067,2755,3314] 2067x2247 mem=17 {'text': 9, 'image': 2, 'paragraph_title': 5, 'doc_title': 1} - R 83 H bbox=[92,1079,686,2507] 594x1428 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'paragraph_title': 1} - R 72 H bbox=[92,2536,685,3404] 593x868 mem=2 {'doc_title': 1, 'text': 1} - R 77 H bbox=[2793,2740,4114,3303] 1321x563 mem=4 {'doc_title': 1, 'text': 1, 'image': 1, 'figure_title': 1} - R100 H bbox=[2113,3353,4113,4297] 2000x944 mem=7 {'doc_title': 1, 'text': 5, 'image': 1} - R 99 H bbox=[750,3357,2069,4605] 1319x1248 mem=8 {'doc_title': 1, 'text': 5, 'image': 1, 'figure_title': 1} - R 67 H bbox=[92,3432,686,4743] 594x1311 mem=3 {'doc_title': 1, 'text': 1, 'image': 1} - R 50 H bbox=[2112,4357,2752,5581] 640x1224 mem=5 {'text': 3, 'image': 1, 'doc_title': 1} - R 54 H bbox=[2793,4368,4114,6094] 1321x1726 mem=9 {'doc_title': 1, 'text': 6, 'image': 1, 'paragraph_title': 1} - R 78 H bbox=[749,4622,2070,6049] 1321x1427 mem=7 {'doc_title': 1, 'text': 6} - R 9 DL bbox=[92,4771,685,5982] 593x1211 mem=2 {'text': 1, 'paragraph_title': 1} - R 5 DL bbox=[2112,5609,2753,6686] 641x1077 mem=2 {'text': 1, 'paragraph_title': 1} - R 75 H bbox=[91,6012,688,6640] 597x628 mem=2 {'doc_title': 1, 'text': 1} - R 79 P bbox=[772,6082,2049,6637] 1277x555 mem=3 {'text': 2, 'paragraph_title': 1} - R 98 H bbox=[2793,6114,4114,6696] 1321x582 mem=3 {'doc_title': 1, 'text': 2} - >>> image-only orphans REMAINING: [] - 📐 Sakshi headline SYNTH: R100 doc_title [2126, 3353, 4097, 3452] (un-boxed display headline band, ink=0.35) - 📐 Sakshi headline SYNTH: R99 doc_title [763, 3357, 2068, 3452] (un-boxed display headline band, ink=0.30) - 📐 Sakshi headline WIDEN: R52 [1182, 1067, 2738, 1327] → [688, 1067, 2738, 1327] (un-boxed kicker ink alongside) - 🗞️ Masthead: dropped 5 Sakshi top-band region(s) [59, 62, 63, 64, 71] (above first headline y=1049) - -=== page 2: 17 crops, 11 datelines === - R 82 H bbox=[777,474,2801,2212] 2024x1738 mem=20 {'text': 7, 'image': 8, 'figure_title': 4, 'doc_title': 1} - R127 H bbox=[2755,485,4086,2232] 1331x1747 mem=17 {'text': 8, 'image': 6, 'figure_title': 2, 'doc_title': 1} - R129 P bbox=[95,499,741,2209] 646x1710 mem=6 {'paragraph_title': 1, 'image': 1, 'text': 3, 'figure_title': 1} - R118 H bbox=[2795,2298,4115,2957] 1320x659 mem=5 {'text': 2, 'image': 2, 'doc_title': 1} - R 91 H bbox=[72,2313,707,3101] 635x788 mem=5 {'text': 2, 'image': 1, 'doc_title': 1, 'figure_title': 1} - R 41 H bbox=[753,2316,2753,3600] 2000x1284 mem=11 {'text': 9, 'doc_title': 1, 'image': 1} - R 3 DL bbox=[2761,2958,3467,4049] 706x1091 mem=3 {'text': 1, 'image': 1, 'figure_title': 1} - R 14 DL bbox=[3475,3022,4115,3999] 640x977 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R113 H bbox=[72,3129,709,4641] 637x1512 mem=5 {'doc_title': 1, 'text': 3, 'image': 1} - R 99 H bbox=[752,3656,2071,4649] 1319x993 mem=5 {'image': 1, 'text': 3, 'doc_title': 1} - R 88 P bbox=[2113,3658,2752,4643] 639x985 mem=4 {'text': 2, 'image': 1, 'paragraph_title': 1} - R 70 H bbox=[2760,4057,4115,5702] 1355x1645 mem=11 {'doc_title': 1, 'text': 9, 'image': 1} - R 93 H bbox=[1216,4710,2752,5939] 1536x1229 mem=10 {'text': 5, 'image': 1, 'doc_title': 1, 'paragraph_title': 2, 'figure_title': 1} - R136 P bbox=[95,4735,1161,5529] 1066x794 mem=3 {'paragraph_title': 1, 'text': 1, 'image': 1} - R 44 F bbox=[650,4979,1128,5185] 478x206 mem=1 {'text': 1} - R 92 F bbox=[653,5252,1127,5744] 474x492 mem=3 {'text': 2, 'paragraph_title': 1} - R111 P bbox=[120,5618,603,6628] 483x1010 mem=3 {'paragraph_title': 1, 'text': 2} - R 98 H bbox=[2798,5710,4115,6696] 1317x986 mem=6 {'doc_title': 1, 'text': 4, 'image': 1} - R 90 F bbox=[685,5924,1099,6145] 414x221 mem=1 {'text': 1} - R 77 H bbox=[1147,5969,2752,6682] 1605x713 mem=4 {'text': 3, 'doc_title': 1} - R110 F bbox=[668,6258,1106,6617] 438x359 mem=1 {'text': 1} - >>> image-only orphans REMAINING: [] - ─ Sakshi rule-split: R41 → 3 bands at rules [1066, 2252] - ─ Sakshi rule-split: R74 → 2 bands at rules [1066] - 📐 Sakshi headline WIDEN: R77 [1217, 5969, 2690, 6109] → [1147, 5969, 2690, 6109] (un-boxed kicker ink alongside) - 🖼 Orphan photo: R38 → article R127 (an image must belong to an article) - 🖼 Orphan photo: R61 → article R82 (an image must belong to an article) - 🗞️ Masthead: dropped 4 Sakshi top-band region(s) [68, 71, 84, 104] (above first headline y=499) - -DONE -> output/Sakshi_Jangaon_District_20260520_20260609_210104/all_article_crops_review diff --git a/_sim71.py b/_sim71.py deleted file mode 100644 index daa0b34..0000000 --- a/_sim71.py +++ /dev/null @@ -1,50 +0,0 @@ -"""Sandbox simulation of the Sakshi Jangaon page-1/2 crop run. -Telugu tesseract is unavailable here, so dateline starts are INJECTED with the -exact anchor set the real 20260609_210104 run found (DL anchors from the saved -crop filenames). Usage: python3 _sim71.py -Writes block table to stdout and crops to output/.../_sim_crops_/.""" -import sys, types -sys.modules.setdefault("fitz", types.ModuleType("fitz")) -import os, tempfile, contextlib, io, json, shutil -tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -TAG = sys.argv[1] if len(sys.argv) > 1 else "base" -RUN = Path("output/Sakshi_Jangaon_District_20260520_20260609_210104"); D = RUN / "pages" -OUT = RUN / f"_sim_crops_{TAG}"; P = "sakshi" -DL_IDS = {1: [71, 11, 4, 3, 9, 5], 2: []} # real run's headline-less datelines -if OUT.exists(): shutil.rmtree(OUT) - -for pg in (1, 2): - png = str(D / f"page_{pg:03d}.png") - regs = json.loads((D / f"page_{pg:03d}.regions.json").read_text())["regions"] - buf = io.StringIO() - with contextlib.redirect_stdout(buf): - regs = se.dedup_overlapping_regions(regs) - regs = se.merge_stacked_title_lines(regs, png) - regs = se.drop_masthead_regions(regs, P, pg, png) - regs = se.drop_classifieds_regions(regs, png) - regs = se.tag_legal_notices(regs, png) - regs = se.promote_paragraph_titles(regs, png, P) - regs = se.mark_bullet_titles(regs, png) - rm = {r["id"]: r for r in regs} - ds = [{"region_id": i, "dateline": "sim:", "bbox": rm[i]["bbox"], - "headline_region": None} for i in DL_IDS[pg] if i in rm] - bars = separator_barriers(png, regs) - blocks = se.cluster_all_article_blocks(regs, ds, sep_lines=bars) - n = se.crop_all_article_blocks(png, regs, str(OUT), pg, - dateline_starts=ds, sep_lines=bars) - print(f"=== page {pg}: {n} crops, {len(ds)} injected datelines ===") - for b in sorted(blocks, key=lambda b: (b["bbox"][1], b["bbox"][0])): - x1, y1, x2, y2 = b["bbox"] - types = {} - for m in b["members"]: - t = rm.get(m, {}).get("type", "?"); types[t] = types.get(t, 0) + 1 - print(f" R{b['anchor_id']:>3} {b['kind']} bbox=[{x1},{y1},{x2},{y2}] " - f"{x2-x1}x{y2-y1} mem={len(b['members'])} {types}") - for l in buf.getvalue().splitlines(): - if "Masthead" in l: print(" ", l.strip()) -print("DONE ->", OUT) diff --git a/_sim_base.log b/_sim_base.log deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_14ktolcb b/_tess_tmp/tess_14ktolcb deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_14ktolcb.txt b/_tess_tmp/tess_14ktolcb.txt deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_14ktolcb_input.PNG b/_tess_tmp/tess_14ktolcb_input.PNG deleted file mode 100644 index 65f39c9..0000000 Binary files a/_tess_tmp/tess_14ktolcb_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_1511jiz9 b/_tess_tmp/tess_1511jiz9 deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_1511jiz9.txt b/_tess_tmp/tess_1511jiz9.txt deleted file mode 100644 index 71dca2d..0000000 --- a/_tess_tmp/tess_1511jiz9.txt +++ /dev/null @@ -1,18 +0,0 @@ -ADEA ASEXE shotloo Sr crsrAs -Boas dof datwera, Ads Soseor -weak? Hiirtht dod Siro. Kew0e vOt -BORD arLBSCOS TS SUNG HOTS -SS SHS EH ert. SYS OED HU, -Brag SomoSodS Dweakl SASHyw -TY. 80 OY GSo DHWBwHS S%So Bra -oer BS BP wid Sard dren Sewn -Sndke dSKo Hnowt, & Ysos! -BraS Zodoh soerr Gardsivg -DUS HEH OZ dbx Som Soebrey -Perle SH Spor Sad Seared. ac -GAS SOShowsh dso SO advert -Sto, SEBS SrerS ZokoH Sodh ws -B%o BLISS SS SyPHHS Ser -UPSPAE SOY. wisp Ero HS Koha -SE SK0. Stot dSthen Kar aeh'B - \ No newline at end of file diff --git a/_tess_tmp/tess_1511jiz9_input.PNG b/_tess_tmp/tess_1511jiz9_input.PNG deleted file mode 100644 index 75e4cf9..0000000 Binary files a/_tess_tmp/tess_1511jiz9_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_1onw_da9 b/_tess_tmp/tess_1onw_da9 deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_1onw_da9.txt b/_tess_tmp/tess_1onw_da9.txt deleted file mode 100644 index 58d10c5..0000000 --- a/_tess_tmp/tess_1onw_da9.txt +++ /dev/null @@ -1,12 +0,0 @@ -BS: GSS Sel Ste (ohowS) -Srghoh SES wQos*s eer wpideSo -& NODA. 2025 ws8 LeeS* Snifo Tox -©%8 S0508 ZHf6* ToXoT09 s0A8 -SeghoF SQ erp, 90.59 wo Karciws -8008. 20m 72,194 0 LY soshoh -wokofire 408. warshdS(SgE ssp -espe) Soms 2,33,75 Tre, 31.93 wdor -608. vert & 3018 5 d45* HOR ay -Segboh SOB 3.214 Sow wonsen -weberthen BDar%. - \ No newline at end of file diff --git a/_tess_tmp/tess_1onw_da9_input.PNG b/_tess_tmp/tess_1onw_da9_input.PNG deleted file mode 100644 index aa6f326..0000000 Binary files a/_tess_tmp/tess_1onw_da9_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_1sf6wilh b/_tess_tmp/tess_1sf6wilh deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_1sf6wilh.txt b/_tess_tmp/tess_1sf6wilh.txt deleted file mode 100644 index 7a60fb8..0000000 --- a/_tess_tmp/tess_1sf6wilh.txt +++ /dev/null @@ -1,18 +0,0 @@ -BPSASOU: DeogS adFgroo wdhen L608 -woxso maaan. oY SAijo mddos -Dio AGSL0B. wd Gesey wwe od: -BOE nO AE SHE wSsr¥o ¥Oy0N0 -&. SiSHoE NDS Gadag we nod -CRE AHIYHasryon. wond Neds’ -PH SrSo nddo woo SASS ors -Gets. OY aro{go SpSaras Higher, OF -ROARS, DAS PASS, Rrcsorer Bo S*ar -doS HS Sy b3de Se, Smaysd -aPOE URES DS WES BdaryWS SEyhe -S850 wdgsore Boorres Ga GE & Hearrs -RS Yond OWGE doryim Sod. oHo8 -wont DeiegS Soxseo ae ads’, bf es -8, éé a ALa6, dé 25K4495 aod -Bo Exp 0% J actyso Sodd davrd) s08. -BaSSoo8 nado BE 4408. 3&% &%7.0 - \ No newline at end of file diff --git a/_tess_tmp/tess_1sf6wilh_input.PNG b/_tess_tmp/tess_1sf6wilh_input.PNG deleted file mode 100644 index 68b1fe4..0000000 Binary files a/_tess_tmp/tess_1sf6wilh_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_3ayv267z b/_tess_tmp/tess_3ayv267z deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_3ayv267z.txt b/_tess_tmp/tess_3ayv267z.txt deleted file mode 100644 index 71dca2d..0000000 --- a/_tess_tmp/tess_3ayv267z.txt +++ /dev/null @@ -1,18 +0,0 @@ -ADEA ASEXE shotloo Sr crsrAs -Boas dof datwera, Ads Soseor -weak? Hiirtht dod Siro. Kew0e vOt -BORD arLBSCOS TS SUNG HOTS -SS SHS EH ert. SYS OED HU, -Brag SomoSodS Dweakl SASHyw -TY. 80 OY GSo DHWBwHS S%So Bra -oer BS BP wid Sard dren Sewn -Sndke dSKo Hnowt, & Ysos! -BraS Zodoh soerr Gardsivg -DUS HEH OZ dbx Som Soebrey -Perle SH Spor Sad Seared. ac -GAS SOShowsh dso SO advert -Sto, SEBS SrerS ZokoH Sodh ws -B%o BLISS SS SyPHHS Ser -UPSPAE SOY. wisp Ero HS Koha -SE SK0. Stot dSthen Kar aeh'B - \ No newline at end of file diff --git a/_tess_tmp/tess_3ayv267z_input.PNG b/_tess_tmp/tess_3ayv267z_input.PNG deleted file mode 100644 index 75e4cf9..0000000 Binary files a/_tess_tmp/tess_3ayv267z_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_4yfor0nu b/_tess_tmp/tess_4yfor0nu deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_4yfor0nu.txt b/_tess_tmp/tess_4yfor0nu.txt deleted file mode 100644 index dc1bf58..0000000 --- a/_tess_tmp/tess_4yfor0nu.txt +++ /dev/null @@ -1,19 +0,0 @@ -Sorisarote: SONS Srsowird dir -wdho OY Siro Sho vbsrthen Go -wy GS ONSey BOB. donBI*G -oped wostren adie Stgods -DRaho BORod. ak DoxRebo sod by -G0dS GSS FONE DoF, HAtyeo Dory», -ProreosD Aor BOAS Swydrcen, -RES BL FORH, Divwr pasos aided -SEfoh wOwrcre Berk Ago dasep -Seirardo. 180 Sars! sorgsties wxosoe -©, BRAS Sbxfeo Ntglrodocss Bots -BrHoxood SSarigen Syoxsew BOLO -8. wr Goss armen Sorl¥arwo & -Ahoo AKowo Sk O50 waisr¥o 6%) -ey BSrardo. Bots 2S sossoWo 5 -Kotor PSE darosoiiyee Seord¥od. Sao -oO S8orsed woerss 180 See’ wh -DO dxoen Grd JasD) dotwod. - \ No newline at end of file diff --git a/_tess_tmp/tess_4yfor0nu_input.PNG b/_tess_tmp/tess_4yfor0nu_input.PNG deleted file mode 100644 index e787aed..0000000 Binary files a/_tess_tmp/tess_4yfor0nu_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_5o3xjw_o b/_tess_tmp/tess_5o3xjw_o deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_5o3xjw_o.txt b/_tess_tmp/tess_5o3xjw_o.txt deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_5o3xjw_o_input.PNG b/_tess_tmp/tess_5o3xjw_o_input.PNG deleted file mode 100644 index d3ee835..0000000 Binary files a/_tess_tmp/tess_5o3xjw_o_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_6mykaz2z b/_tess_tmp/tess_6mykaz2z deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_6mykaz2z.txt b/_tess_tmp/tess_6mykaz2z.txt deleted file mode 100644 index c14da0d..0000000 --- a/_tess_tmp/tess_6mykaz2z.txt +++ /dev/null @@ -1,19 +0,0 @@ -Beso a6 JUS 44 D0dH Sowb 88, -Brto & So 316% addo Gkcd HO -Bao. DyS SoYor LOHR asyg -adder 268A visio Sty sodasod. -nddo woo BASS PSGe. axspes -088 Ch Be Exons 408. Be &%5y0 -& Ad'yo Sodd der doemodd ws -SF DeogS wOsrcoen, SS'yoeo seRe, Ja -Exo FF TOs SENG Oy Ge -Bosses’ SEHSp wie Depo -worth, GE%roe bg IHS SHS dows -Daw. CAS ariglo, Sqvoosso Sve -Gigas Avfor 26A08. word 068 dake -Seren Tverd) soci. ctormsivrarshy -Sen Soda srensioreron. 08% dor -Son sds wad dciiowop syrorer -Shobayws. Gawss* arvigo adordsoors -Gos Ad Ser%o mObo2% SSO. - \ No newline at end of file diff --git a/_tess_tmp/tess_6mykaz2z_input.PNG b/_tess_tmp/tess_6mykaz2z_input.PNG deleted file mode 100644 index da8f545..0000000 Binary files a/_tess_tmp/tess_6mykaz2z_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_71zcinaf b/_tess_tmp/tess_71zcinaf deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_71zcinaf.txt b/_tess_tmp/tess_71zcinaf.txt deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_71zcinaf_input.PNG b/_tess_tmp/tess_71zcinaf_input.PNG deleted file mode 100644 index acb5162..0000000 Binary files a/_tess_tmp/tess_71zcinaf_input.PNG and /dev/null differ diff --git a/_tess_tmp/tess_80f9u6zp b/_tess_tmp/tess_80f9u6zp deleted file mode 100644 index e69de29..0000000 diff --git a/_tess_tmp/tess_80f9u6zp.txt b/_tess_tmp/tess_80f9u6zp.txt deleted file mode 100644 index 4f6f9ed..0000000 --- a/_tess_tmp/tess_80f9u6zp.txt +++ /dev/null @@ -1,18 +0,0 @@ -Domes: aS 81 Sov a8 sohergiar -09-1 Sxen > eS SHH wohorres -AaYDs LEcho BSO Somods wosrds -0% Slows. LosoosN dorfoss -(rm IPHS‘O HOB wrasro AQ So 25 -BOSD OH-1 SoSH Poy Sarows -Hor¥ardo wowten, woeryé, Gere’ -BOS? KO SOMO. wPSosirWorr -aWiOeyy Sop sUliro SYodme. se -QAS Show SoHE dor Sosio eS SHH wohorres -AaYDs LEcho BSO Somods wosrds -0% Slows. LosoosN dorfoss -(rm IPHS‘O HOB wrasro AQ So 25 -BOSD OH-1 SoSH Poy Sarows -Hor¥ardo wowten, woeryé, Gere’ -BOS? KO SOMO. wPSosirWorr -aWiOeyy Sop sUliro SYodme. se -QAS Show SoHE dor Sosio=2] - cls=[l.strip() for l in buf.getvalue().splitlines() if 'Classifieds:' in l] - o.write(f" pg{pg}: {len(blocks)} blocks | 2+dl={over} | {cls[0] if cls else 'no classifieds'}\n") - except Exception as e: - o.write(f" pg{pg}: ERROR {e}\n") -o.close();print("WROTE") diff --git a/_testcls.txt b/_testcls.txt deleted file mode 100644 index e69de29..0000000 diff --git a/_trace76.py b/_trace76.py deleted file mode 100644 index 3153da2..0000000 --- a/_trace76.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers - -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -png = D / "page_001.png" -regs0 = json.loads((D / "page_001.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs = se.drop_masthead_regions(regs0, "andhra_jyothi", 1, png) - ds = se.find_article_starts_by_dateline(regs, str(png), "andhra_jyothi") - bars = separator_barriers(str(png), regs) - bl = se.cluster_all_article_blocks(regs, dateline_starts=ds, sep_lines=bars) - -owner = {} -for b in bl: - for m in b["members"]: - owner[m] = b["anchor_id"] -for rid in (76, 68, 46): - print(f"R{rid} -> block anchor {owner.get(rid)}") - -# manual barrier check R32 vs R76/R68 -byid = {r["id"]: r for r in regs} -print("bars (full-width-ish) near y4227/4915:", [b for b in bars if b["y"] in (4227,4915) or 4200", owner.get(76), " R68 ->", owner.get(68)) diff --git a/_vwalls_test.py b/_vwalls_test.py deleted file mode 100644 index 949fa56..0000000 --- a/_vwalls_test.py +++ /dev/null @@ -1,62 +0,0 @@ -"""TEST (read-only): identify & map the BIG vertical lines on a page — the long column -dividers that separate articles — ignoring short verticals (in-article box edges, stray -strokes). Draws a blank-canvas 'vertical wall map' per page. No smart_extractor changes, -no API. Test on 1-2 pages only.""" -import os, tempfile, json -tempfile.tempdir = os.path.abspath("_tess_tmp"); os.environ["TMPDIR"] = tempfile.tempdir -os.makedirs("_tess_tmp", exist_ok=True) -from pathlib import Path -from PIL import Image, ImageDraw, ImageFont -from _lines import detect_separator_lines - -# A vertical line counts as a BIG article-separating wall when it runs at least this -# fraction of the page height. Column dividers span most of a column; box edges are short. -BIG_FRAC = 0.45 - -def big_vertical_walls(png_path, min_frac=BIG_FRAC): - res = detect_separator_lines(png_path) - W, H = res["size"] - walls = [] - for L in res["v"]: - y1, y2 = min(L["y1"], L["y2"]), max(L["y1"], L["y2"]) - length = y2 - y1 - if length >= min_frac * H: - walls.append({"x": (L["x1"] + L["x2"]) // 2, "y1": y1, "y2": y2, - "len": length, "frac": round(length / H, 2)}) - walls.sort(key=lambda w: w["x"]) - return walls, (W, H) - -def draw_walls(png_path, out_path): - walls, (W, H) = big_vertical_walls(png_path) - res = detect_separator_lines(png_path) # for the 'ignored' short ones - small = [L for L in res["v"] - if (max(L["y1"], L["y2"]) - min(L["y1"], L["y2"])) < BIG_FRAC * H] - img = Image.new("RGB", (W, H), "white") - d = ImageDraw.Draw(img) - try: - font = ImageFont.truetype("DejaVuSans-Bold.ttf", 30) - except Exception: - font = ImageFont.load_default() - # ignored short verticals = thin gray - for L in small: - d.line([ (L["x1"]+L["x2"])//2, min(L["y1"],L["y2"]), - (L["x1"]+L["x2"])//2, max(L["y1"],L["y2"]) ], fill=(200,200,200), width=3) - # big walls = thick red, labelled with height fraction - for w in walls: - d.line([w["x"], w["y1"], w["x"], w["y2"]], fill=(220, 30, 30), width=10) - d.text((w["x"] + 14, w["y1"] + 10), f'WALL x={w["x"]} {int(w["frac"]*100)}%H', - fill=(220, 30, 30), font=font) - img.save(out_path) - return walls - -TESTS = [ - ("output/NamastheTelangana_Siddipet_20260602_20260604_214937/pages", 2, "NT"), - ("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages", 1, "AJ"), -] -for pdir, pg, tag in TESTS: - png = f"{pdir}/page_{pg:03d}.png" - out = f"{pdir}/page_{pg:03d}_vwalls_debug.png" - walls = draw_walls(png, out) - print(f"{tag} pg{pg}: {len(walls)} BIG vertical wall(s) -> {out}") - for w in walls: - print(f" x={w['x']:>4} y[{w['y1']},{w['y2']}] height={int(w['frac']*100)}% of page") diff --git a/app_py_utf8.txt b/app_py_utf8.txt deleted file mode 100644 index 40a629e..0000000 --- a/app_py_utf8.txt +++ /dev/null @@ -1 +0,0 @@ -None diff --git a/fix_pdf.py b/fix_pdf.py deleted file mode 100644 index 835cae5..0000000 --- a/fix_pdf.py +++ /dev/null @@ -1,11 +0,0 @@ -import json -from pathlib import Path -from generate_pdf import generate_political_pdf - -job_dir = Path(r'c:\Users\sunde\proxmox\news-scan\output\20260612_131909') -articles = json.loads((job_dir / 'political_articles.json').read_text(encoding='utf-8')) -for a in articles: - a['image_file'] = f"{a['id']}.png" - -generate_political_pdf(articles, job_dir) -print("Regenerated PDF with images!") diff --git a/original_app_py.txt b/original_app_py.txt deleted file mode 100644 index af0e4f4..0000000 Binary files a/original_app_py.txt and /dev/null differ diff --git a/scratch_py/_blocks_snapshot.py b/scratch_py/_blocks_snapshot.py deleted file mode 100644 index 4edc24f..0000000 --- a/scratch_py/_blocks_snapshot.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0, ".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -out={} -for pg in (1,2,3,4): - png=D/f"page_{pg:03d}.png" - regs=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] - with contextlib.redirect_stdout(io.StringIO()): - regs=se.drop_masthead_regions(regs,"andhra_jyothi",pg,png) - ds=se.find_article_starts_by_dateline(regs,str(png),"andhra_jyothi") - bars=separator_barriers(str(png),regs) - bl=se.cluster_all_article_blocks(regs,dateline_starts=ds,sep_lines=bars) - out[pg]={b["anchor_id"]:[b["kind"],tuple(sorted(b["members"]))] for b in bl} -tag=sys.argv[1] if len(sys.argv)>1 else "base" -Path(f"scratch_py/_snap_{tag}.json").write_text(json.dumps(out,indent=0)) -print(f"saved _snap_{tag}.json") -for pg in (1,2,3,4): - print(f"PAGE{pg}: {len(out[pg])} blocks anchors={sorted(out[pg])}") diff --git a/scratch_py/_boundaries.py b/scratch_py/_boundaries.py deleted file mode 100644 index 796d1ea..0000000 --- a/scratch_py/_boundaries.py +++ /dev/null @@ -1,204 +0,0 @@ -"""Construct one boundary box per article by fusing three signals: - - 1. DATELINE pattern -> the MINIMUM set of articles (one per ', date:'). - 2. HEADLINE above -> the article's top anchor / column span (doc_title). - 3. STRAIGHT RULES -> hard walls: snap top/bottom to horizontal rules and - left/right to vertical rules between stories. - -Pure geometry on saved fixtures + the page PNG. No Claude, no API. - -construct_boundaries(regions, datelines, lines, size) -> list of: - {region_id, dateline, headline_region, bbox:[l,t,r,b], walls:{...}} -""" - - -def _cx(b): - return (b[0] + b[2]) / 2 - - -def construct_boundaries(regions, datelines, lines, size): - W, H = size - rmap = {r["id"]: r for r in regions} - h_rules = sorted(lines["h"], key=lambda L: L["y1"]) - v_rules = sorted(lines["v"], key=lambda L: L["x1"]) - dls = sorted(datelines, key=lambda s: s["bbox"][1]) - - # ---- duplicate-dateline dedup: PaddleOCR sometimes boxes the SAME physical text - # twice (and a false dateline match — an ad/phone line — then appears as two - # near-identical bodies). Two datelines are one article when EITHER their bodies - # overlap heavily (IoU>0.6) OR one body is mostly nested inside the other AND the - # dateline text is identical (the same town double-boxed as a thin line + a tall - # paragraph — IoU stays low but containment is near 1). Keep the larger body and - # inherit a headline from the dropped twin if the keeper had none. - def _area(b): - return (b[2]-b[0]) * (b[3]-b[1]) - - def _same_dateline(sa, sb): - a, b = sa["bbox"], sb["bbox"] - ix = max(0, min(a[2], b[2]) - max(a[0], b[0])) - iy = max(0, min(a[3], b[3]) - max(a[1], b[1])) - inter = ix * iy - if not inter: - return False - aa, ba = _area(a), _area(b) - iou = inter / (aa + ba - inter) if (aa + ba - inter) else 0.0 - if iou > 0.6: - return True - contain = inter / min(aa, ba) if min(aa, ba) else 0.0 - ta = (sa.get("dateline") or "").strip() - tb = (sb.get("dateline") or "").strip() - return contain > 0.8 and ta != "" and ta == tb - - deduped = [] - for s in dls: - dup = next((k for k in deduped if _same_dateline(s, k)), None) - if dup is None: - deduped.append(s) - else: # keep larger body; inherit a missing headline - keep, drop = (s, dup) if _area(s["bbox"]) > _area(dup["bbox"]) else (dup, s) - if keep.get("headline_region") not in rmap and drop.get("headline_region") in rmap: - keep = {**keep, "headline_region": drop["headline_region"]} - deduped[deduped.index(dup)] = keep - dls = deduped - - # ---- shared-headline dedup: a doc_title can only head ONE article. When two - # datelines both matched the same headline (stacked in a column, or a 2-col - # headline with a missed neighbour), keep it for the dateline with the SMALLEST - # positive gap below the headline; the others lose it (anchor on their own body). - by_hl = {} - for s in dls: - h = s.get("headline_region") - if h in rmap: - by_hl.setdefault(h, []).append(s) - hid_of = {id(s): s.get("headline_region") for s in dls} - for h, group in by_hl.items(): - if len(group) <= 1: - continue - hb = rmap[h]["bbox"] - below = [s for s in group if s["bbox"][1] >= hb[3] - 30] - keeper = min(below, key=lambda s: s["bbox"][1] - hb[3]) if below \ - else min(group, key=lambda s: abs(s["bbox"][1] - hb[3])) - for s in group: - if s is not keeper: - hid_of[id(s)] = None - - def _anchor_rect(ns): - """A neighbour's article ANCHOR = its headline (if it owns one) UNION its - dateline body. Floors are computed against this rect — not the bare body — - so a story ends at the TOP of the next story's HEADLINE, and a wide 2-column - headline that reaches sideways into this column still acts as a wall.""" - b = ns["bbox"] - h = hid_of.get(id(ns)) - if h in rmap: - hb = rmap[h]["bbox"] - return (min(b[0], hb[0]), min(b[1], hb[1]), - max(b[2], hb[2]), max(b[3], hb[3])) - return (b[0], b[1], b[2], b[3]) - - def _covers(L, y0, y1): - # the rule must span the MAJORITY of [y0,y1], not merely touch an edge - ov = min(L["y2"], y1) - max(L["y1"], y0) - return ov >= 0.5 * max(1, y1 - y0) - - def vwall_left(cx, y0, y1): - cands = [L for L in v_rules if L["x1"] < cx - 20 and _covers(L, y0, y1)] - return max((L["x1"] for L in cands), default=0) - - def vwall_right(cx, y0, y1): - cands = [L for L in v_rules if L["x1"] > cx + 20 and _covers(L, y0, y1)] - return min((L["x1"] for L in cands), default=W) - - def hrule_between(x0, x1, y_lo, y_hi, want_above): - """Return the horizontal rule whose span covers [x0,x1] within (y_lo,y_hi). - want_above=True -> the LOWEST such rule (closest above the body's top is the - bottom-most of those above); we pick nearest to the reference edge.""" - hits = [L for L in h_rules - if L["y1"] > y_lo and L["y1"] < y_hi - and L["x1"] <= x1 - 30 and L["x2"] >= x0 + 30] - if not hits: - return None - # nearest to the reference edge: above -> max y (closest below ceiling ref), - # below -> min y (closest above floor ref) - return max(hits, key=lambda L: L["y1"]) if want_above \ - else min(hits, key=lambda L: L["y1"]) - - out = [] - for i, s in enumerate(dls): - db = s["bbox"] - cx = _cx(db) - hid = hid_of[id(s)] - hb = rmap[hid]["bbox"] if (hid in rmap) else None - - # ---- horizontal span: UNION of headline + dateline body so the body is - # always contained; top anchor is the headline top if present. - if hb: - left0, right0 = min(hb[0], db[0]), max(hb[2], db[2]) - top_anchor = hb[1] - else: - left0, right0 = db[0], db[2] - top_anchor = db[1] - - # ---- CEILING: snap up to a horizontal rule just above the anchor (but no - # higher than the previous article's dateline in this column). - prev_y = 0 - for ps in dls: - if ps is s: - continue - pb = ps["bbox"] - if pb[0] - 40 <= cx <= pb[2] + 40 and pb[3] <= top_anchor: - prev_y = max(prev_y, pb[3]) - ceil_rule = hrule_between(left0, right0, prev_y, top_anchor + 20, want_above=True) - # a ceiling rule only counts if it sits a sane distance ABOVE the anchor - # (a far-away rule is a different story's divider, not this article's top). - top = top_anchor - if ceil_rule and 0 <= (top_anchor - ceil_rule["y1"]) <= 500: - top = ceil_rule["y1"] - else: - ceil_rule = None - top = min(top, top_anchor) # never cut INTO the article from above - - # ---- FLOOR: nearest boundary directly below in THIS dateline's OWN column - # (own column, not the wide headline span — a neighbour under a 2-col - # headline must clip the SIDE, not act as the floor). - own_l, own_r = db[0], db[2] - next_y = H - for ns in dls: - if ns is s: - continue - na = _anchor_rect(ns) # headline ∪ body of neighbour - if na[1] > db[1] + 30 and not (na[2] < own_l + 20 or na[0] > own_r - 20): - next_y = min(next_y, na[1]) - floor_rule = hrule_between(own_l, own_r, db[3], next_y + 5, want_above=False) - bottom = floor_rule["y1"] if floor_rule else next_y - bottom = max(bottom, db[3]) # never cut INTO the article from below - - # ---- SIDE-CLIP: a neighbour dateline that sits beside this body within the - # (wide) headline span clips the corresponding edge, so a left-column - # story never swallows the right column's separate story. - for ns in dls: - if ns is s: - continue - nb = ns["bbox"] - if nb[3] > top_anchor + 20 and nb[1] < bottom - 20: # vertical overlap - if own_r - 10 <= nb[0] < right0: # neighbour to the right - right0 = min(right0, nb[0]) - if left0 < nb[2] <= own_l + 10: # neighbour to the left - left0 = max(left0, nb[2]) - - # ---- side walls: snap to vertical rules spanning the article's y-band - lwall = vwall_left(cx, top, bottom) - rwall = vwall_right(cx, top, bottom) - left = max(left0 - 20, lwall) - right = min(right0 + 20, rwall) - left = min(left, db[0]) # guarantee the dateline body fits - right = max(right, db[2]) - - out.append({ - "region_id": s["region_id"], - "dateline": s.get("dateline", ""), - "headline_region": hid, - "bbox": [int(left), int(top), int(right), int(bottom)], - "walls": {"ceil_rule": bool(ceil_rule), "floor_rule": bool(floor_rule), - "lwall": int(lwall), "rwall": int(rwall)}, - }) - return out diff --git a/scratch_py/_continuation.py b/scratch_py/_continuation.py deleted file mode 100644 index 0a945ab..0000000 --- a/scratch_py/_continuation.py +++ /dev/null @@ -1,462 +0,0 @@ -"""Cross-page article-continuation linker (classical, no Claude / no API). - -Telugu papers "jump" long stories across pages: - - • bottom of the source article : 'మిగతా వ పేజీలో...' (rest is on page N) - • top of the continuation page : the SAME headline repeated, plus the marker - '(మొదటి పేజీ తరువాయి)' (continued from page 1) - -We REQUIRE BOTH signals: the jump-from marker on the source page (which also tells -us the target page N) AND a repeated headline on page N that matches the source -article's headline. We then build a boundary box for the continuation by injecting -a SYNTHETIC dateline anchored on that repeated headline and running the existing -boundary engine (so the continuation floors correctly against page-N's own -articles), and finally STITCH the source crop + continuation crop into ONE tall -image per article. - -Pure geometry + Tesseract on saved fixtures (page PNGs + regions.json + the -per-article info.json the pipeline already wrote). No Claude. - - link_continuations(run_dir) -> list of link records (also written to - /continuations/links.json, stitched PNGs alongside). -""" -import difflib -import json -import re -import unicodedata -from pathlib import Path - -from PIL import Image - -from _lines import detect_separator_lines - -try: - from smart_extractor import _dateline_in_text -except Exception: # keep the module importable in isolation - def _dateline_in_text(_t, _paper=None): - return None - -_ZW = "‌‍" # zero-width non-joiner / joiner -_TERMINATORS = ".।?!" # sentence-enders: full stop, danda, ?, ! -_TELUGU_DIGITS = {ord("౦") + i: str(i) for i in range(10)} - -# jump-FROM: 'మిగతా వ పేజీ...' — tolerate OCR noise between the tokens. -_JUMP_FROM = re.compile(r"మిగ[తథధ]ా.{0,10}?([0-9౦-౯]{1,2})\s*వ?\s*పే[జీిౌ]", re.UNICODE) -# jump-TO: 'మొదటి పేజీ తరువాయి' — the continuation marker on the target page. -_JUMP_TO = re.compile(r"మొదట[ిి]?\s*పే[జీి].{0,6}?తరు[వ]?ా[యి]", re.UNICODE) - - -def _paper_of_height(h): - if 7040 <= h <= 7060: - return "sakshi" - if h in (6833, 6549): - return "andhra_jyothi" - if h == 6422: - return "namaste_telangana" - return f"h{h}" - - -def _ocr(page, box): - import pytesseract - try: - return pytesseract.image_to_string(page.crop((int(box[0]), int(box[1]), - int(box[2]), int(box[3]))), - lang="tel") - except Exception: - return "" - - -def _page_num_from(text): - m = _JUMP_FROM.search(text or "") - if not m: - return None - digits = m.group(1).translate(_TELUGU_DIGITS) - dm = re.search(r"\d+", digits) - if not dm: - return None - d = dm.group() - # OCR frequently DOUBLE-RECOGNISES a single glyph as the Latin digit followed - # by its Telugu twin (e.g. '3౩' → '33'). District editions only ever run a - # handful of pages, so a run of identical digits is that artefact, not page 33. - if len(d) == 2 and d[0] == d[1]: - d = d[0] - return int(d) - - -def _norm(s): - s = unicodedata.normalize("NFC", s or "") - s = "".join(c for c in s if c not in _ZW) - return re.sub(r"[\s.,!?:;\-()।\"'‘’]", "", s) - - -def _similar(a, b): - a, b = _norm(a), _norm(b) - if not a or not b: - return 0.0 - return difflib.SequenceMatcher(None, a, b).ratio() - - -def _find_jump_from(page, art_bbox): - """Scan the BOTTOM band of the source article for the 'మిగతా Nవ పేజీలో' marker; - fall back to the whole article box. Returns the target page number or None.""" - l, t, r, b = art_bbox - band_top = max(t, b - 340) - n = _page_num_from(_ocr(page, (l, band_top, r, b))) - if n is None: # marker may sit a little higher - n = _page_num_from(_ocr(page, (l, t, r, b))) - return n - - -def _best_headline(regs, page, headline_tel, thresh=0.60): - """Among the doc_titles on the target page, return (region, score, has_marker) - for the one whose OCR text best matches the source headline (>= thresh).""" - best, best_score = None, 0.0 - for r in regs: - if r.get("type") != "doc_title": - continue - score = _similar(_ocr(page, r["bbox"]), headline_tel) - if score > best_score: - best, best_score = r, score - if not best or best_score < thresh: - return None, best_score, False - hb = best["bbox"] - below = _ocr(page, (hb[0], hb[3], hb[2], min(hb[3] + 240, page.height))) - has_marker = bool(_JUMP_TO.search(below) or _JUMP_TO.search(_ocr(page, hb))) - return best, best_score, has_marker - - -def _ends_terminated(text): - """True if the column's last word ends a sentence (., danda, ?, !), ignoring - trailing quotes/brackets. This is the (noisy, OCR-based) 'article concluded' - signal — used only AFTER the structural stop-tests have had their say.""" - t = (text or "").rstrip() - t = t.rstrip("\"'’”)]]》」』 ") - return bool(t) and t[-1] in _TERMINATORS - - -def _col_width(regs): - """Robust single-column width = median width of the page's text boxes.""" - ws = sorted(r["bbox"][2] - r["bbox"][0] for r in regs if r.get("type") == "text") - return ws[len(ws) // 2] if ws else 700 - - -def _has_body_below(regs, b): - """True if a text box sits below box `b` within its horizontal span — i.e. `b` - is a headline opening its OWN article (a new story), not a trailing label or an - inline emphasis run. Used to let a paragraph_title act as an article floor.""" - for r in regs: - if r.get("type") == "text": - rb = r["bbox"] - if rb[1] > b[1] + 5 and rb[0] < b[2] and rb[2] > b[0]: - return True - return False - - -def _is_floor_head(regs, r, hid): - """A region that floors a continuation: any doc_title, OR a paragraph_title that - has its own body beneath it (the start of a DIFFERENT article — e.g. a - 'continued from page N' sub-head sitting below our continuation block).""" - if r.get("id") == hid: - return False - t = r.get("type") - if t == "doc_title": - return True - return t == "paragraph_title" and _has_body_below(regs, r["bbox"]) - - -def _floor_under(regs, lines, hb, hid, x0, x1, H): - """Lowest boundary below the header within the corridor [x0,x1]: the top of the - next headline (doc_title, or an article-starting paragraph_title), or a - horizontal rule, whichever comes first (else page bottom).""" - f = H - for r in regs: - b = r["bbox"] - if (_is_floor_head(regs, r, hid) - and b[1] > hb[3] + 20 and b[0] < x1 and b[2] > x0): - f = min(f, b[1]) - for ln in (lines.get("h") or []): - y = ln["y1"] - if hb[3] + 20 < y < f and ln["x1"] < x1 and ln["x2"] > x0: - f = min(f, y) - return f - - -def _floor_below_body(regs, lines, hb, hid, x0, x1, body, H): - """Lowest article boundary in corridor [x0,x1]. A next-headline or horizontal - rule only counts as the floor when NO included body text continues *below* it in - an overlapping column — that distinguishes the next article's wide headline (no - body beneath, within this block) from an interior sub-head / column-top rule - (article body keeps going underneath it).""" - def _no_body_below(bx0, bx2, yt): - for bb in body: - if bb[3] > yt + 10 and bb[0] < bx2 and bb[2] > bx0: - return False - return True - - f = H - for r in regs: - b = r["bbox"] - if (_is_floor_head(regs, r, hid) - and b[1] > hb[3] + 20 and b[0] < x1 and b[2] > x0 - and _no_body_below(b[0], b[2], b[1])): - f = min(f, b[1]) - for ln in (lines.get("h") or []): - y = ln["y1"] - if hb[3] + 20 < y < f and ln["x1"] < x1 and ln["x2"] > x0 \ - and _no_body_below(ln["x1"], ln["x2"], y): - f = min(f, y) - return f - - -def _vrule_in_gutter(lines, x0, x1, y0, y1): - """A printed vertical rule sitting in the gutter [x0,x1] across most of [y0,y1].""" - for ln in (lines.get("v") or []): - if x0 - 8 <= ln["x1"] <= x1 + 8: - ov = min(ln["y2"], y1) - max(ln["y1"], y0) - if ov > 0.4 * (y1 - y0): - return True - return False - - -def _track_starts_with_title(regs, items, hb): - """STOP-test 5: does a headline / sub-head box open the next column?""" - xs = min(it["bbox"][0] for it in items) - xe = max(it["bbox"][2] for it in items) - ytop = min(it["bbox"][1] for it in items) - for r in regs: - if r.get("type") in ("doc_title", "paragraph_title"): - b = r["bbox"] - if b[0] < xe and b[2] > xs and b[1] > hb[3] + 20 and abs(b[1] - ytop) < 130: - return True - return False - - -def _continuation_crop(regs, png_path, paper, headline_region): - """Crop the FULL continuation article by GROWING RIGHT from the headline. - - A continuation's body is usually wider than its header and spans several columns. - We start at the header's column and walk right column-by-column, absorbing the - next column unless a STOP-test fires: - - 1 no next column 5 next column opens with a headline/sub-head - 2 vertical-rule wall 6 current column's last word ends with a period - 3 horizontal-rule break 7 grammatical bridge fails (approx: 4+6 absent) - 4 next column opens a dateline - - Structural tests (1-5) outrank the OCR period (6). The crop is the single - rectangle enclosing every absorbed column (+ any photo inside the block), - floored at the next headline / horizontal rule. - - Returns (PIL.Image, debug_bbox) or (None, None).""" - page = Image.open(png_path).convert("RGB") - H = page.height - hb = headline_region["bbox"] - hid = headline_region.get("id") - cx = (hb[0] + hb[2]) / 2 - lines = detect_separator_lines(png_path) - colW = _col_width(regs) - - # provisional floor under the header's own span gives us the band to cluster in - F0 = _floor_under(regs, lines, hb, hid, hb[0], hb[2], H) - - # body text boxes in the band, clustered into left-to-right COLUMN TRACKS - band = [r for r in regs if r.get("type") == "text" - and (r["bbox"][1] + r["bbox"][3]) / 2 < F0 - and r["bbox"][3] > hb[1] - and r["bbox"][0] >= hb[0] - colW * 0.5] # drop columns left of the header - if not band: - return None, None - tracks = [] - for r in sorted(band, key=lambda r: r["bbox"][0]): - for tr in tracks: - if abs(r["bbox"][0] - tr["x0"]) < colW * 0.5: - tr["items"].append(r) - break - else: - tracks.append({"x0": r["bbox"][0], "items": [r]}) - tracks.sort(key=lambda t: t["x0"]) - - # START column = the track straddling the headline centre (else nearest) - start = None - for i, t in enumerate(tracks): - if min(it["bbox"][0] for it in t["items"]) <= cx <= max(it["bbox"][2] for it in t["items"]): - start = i - break - if start is None: - start = min(range(len(tracks)), key=lambda i: abs(tracks[i]["x0"] - cx)) - - import os - DBG = os.environ.get("CONT_DEBUG") - if DBG: - print(f"[dbg] hb={hb} cx={cx} colW={colW} F0={F0}") - for ti, t in enumerate(tracks): - print(f"[dbg] track {ti} x0={t['x0']} items=" - + ",".join(f"{it.get('id')}{it['bbox']}" for it in t['items'])) - print(f"[dbg] start track = {start}") - - # GROW RIGHT, applying the stop-tests at each gutter - included = [start] - i = start - while True: - cur = tracks[i]["items"] - cur_r = max(it["bbox"][2] for it in cur) - nxt = next((j for j in range(i + 1, len(tracks)) - if tracks[j]["x0"] > cur_r - colW * 0.3), None) - if nxt is None: # 1 no next column - if DBG: print(f"[dbg] from {i}: STOP test1 no next column") - break - nt = tracks[nxt]["items"] - nt_l = min(it["bbox"][0] for it in nt) - y0, y1 = hb[1], F0 - if _vrule_in_gutter(lines, cur_r, nt_l, y0, y1): # 2 vertical wall - if DBG: print(f"[dbg] from {i} to {nxt}: STOP test2 vrule wall {cur_r}-{nt_l}") - break - top_reg = min(nt, key=lambda it: it["bbox"][1]) - tb = top_reg["bbox"] - head_txt = _ocr(page, (tb[0], tb[1], tb[2], min(tb[1] + 150, tb[3]))) - if _dateline_in_text(head_txt, paper): # 4 dateline opens next col - if DBG: print(f"[dbg] from {i} to {nxt}: STOP test4 dateline '{head_txt[:40]}'") - break - if _track_starts_with_title(regs, nt, hb): # 5 headline opens next col - if DBG: print(f"[dbg] from {i} to {nxt}: STOP test5 title opens next") - break - bot_reg = max(cur, key=lambda it: it["bbox"][3]) - bot_txt = _ocr(page, bot_reg["bbox"]) - if _ends_terminated(bot_txt): # 6 period concludes - if DBG: print(f"[dbg] from {i} to {nxt}: STOP test6 period; tail='{bot_txt[-30:]}'") - break - if DBG: print(f"[dbg] grow {i} -> {nxt}") - included.append(nxt) # 7 bridge holds -> grow - i = nxt - if DBG: print(f"[dbg] included tracks = {included}") - - # FINAL rectangle over the absorbed columns, floored against the real corridor - left = hb[0] - right = max(max(it["bbox"][2] for it in tracks[k]["items"]) for k in included) - body = [it["bbox"] for k in included for it in tracks[k]["items"]] - F = _floor_below_body(regs, lines, hb, hid, left, right, body, H) - if DBG: print(f"[dbg] left={left} right={right} F={F}") - - members = list(body) - for r in regs: # sweep in photos / captions inside the block - if r.get("type") in ("image", "figure_title", "paragraph_title", "doc_title"): - b = r["bbox"] - bcx = (b[0] + b[2]) / 2 - if left - 10 <= bcx <= right + 10 and b[3] <= F and b[3] > hb[1] - 320: - members.append(b) - - left = min(left, min(m[0] for m in members)) - top = min(hb[1], min(m[1] for m in members)) - bot = min(int(F) - 8, max(m[3] for m in members) + 22) - box = (int(left), int(max(0, top - 6)), int(right), int(bot)) - return page.crop(box), list(box) - - -def _stitch(top_png, cont_img, out_path): - """Stack the source page-1 crop above the composed continuation image.""" - top = Image.open(top_png).convert("RGB") - W = max(top.width, cont_img.width) - sep = 18 - combo = Image.new("RGB", (W, top.height + sep + cont_img.height), "white") - combo.paste(top, (0, 0)) - combo.paste(cont_img, (0, top.height + sep)) - combo.save(out_path) - return combo.size - - -def link_continuations(run_dir, out_dir=None, match_thresh=0.60, verbose=True): - run = Path(run_dir) - pages_dir = run / "pages" - arts_dir = run / "articles" - out_dir = Path(out_dir) if out_dir else (run / "continuations") - out_dir.mkdir(parents=True, exist_ok=True) - - p1 = pages_dir / "page_001.png" - paper = _paper_of_height(Image.open(p1).height) if p1.exists() else "unknown" - - results = [] - for info_path in sorted(arts_dir.glob("*/info.json")): - info = json.loads(info_path.read_text()) - P, bbox = info.get("page"), info.get("bbox") - headline = info.get("headline_telugu") or "" - if not P or not bbox: - continue - # Continuations only ever START on page 1 — the front page jumps long lead - # stories onto inside pages. Articles on pages 2+ are self-contained, so we - # never scan them for a jump-from marker. - if P != 1: - continue - src_png = pages_dir / f"page_{P:03d}.png" - if not src_png.exists(): - continue - - N = _find_jump_from(Image.open(src_png), bbox) # SIGNAL 1: jump-from - if not N or N == P: - continue - - # The jump-from page DIGIT is OCR-noisy (Telugu ౪/౬ confusion) and can point - # at a page outside this extraction (here the front page said '6వ పేజీ' but - # the run only has 4 pages). So treat the marker as "this front-page lead - # continues on a later page" and resolve the ACTUAL target by the repeated- - # headline signal: score every OTHER page's doc_titles against the source - # headline and take the best match, breaking ties toward the OCR'd page N. - existing = sorted( - int(m.group(1)) - for q in pages_dir.glob("page_*.png") - if (m := re.match(r"page_(\d+)\.png$", q.name))) - best = None # (score, page, tregs, tgt_png_str, hl, marker) - for q in existing: - if q == P: - continue - qr = pages_dir / f"page_{q:03d}.regions.json" - qp = pages_dir / f"page_{q:03d}.png" - if not qr.exists() or not qp.exists(): - continue - qregs = json.loads(qr.read_text())["regions"] - hl_q, score_q, marker_q = _best_headline(qregs, Image.open(qp), headline, match_thresh) - if hl_q is None: - continue - if best is None or score_q > best[0] or (score_q == best[0] and q == N): - best = (score_q, q, qregs, str(qp), hl_q, marker_q) - - if best is None: - rec = {"article": info_path.parent.name, "src_page": P, "headline": headline, - "target_page": N, "match_score": 0.0, "taruvaayi_marker": False, - "linked": False, - "reason": "no matching repeated headline on any inside page"} - results.append(rec) - if verbose: - print(f" ✗ {rec['article']} → p{N}: jump-from found but no repeated " - f"headline match on any inside page (NOT linked)") - continue - - score, N, tregs, tgt_png, hl, marker = best - rec = {"article": info_path.parent.name, "src_page": P, "headline": headline, - "target_page": N, "match_score": round(score, 2), - "taruvaayi_marker": marker, "linked": False} - - cont_img, cbox = _continuation_crop(tregs, tgt_png, paper, hl) - if cont_img is None: - rec["reason"] = "no body under repeated headline" - results.append(rec) - continue - out_png = out_dir / f"{info_path.parent.name}__cont_p{N:03d}.png" - size = _stitch(arts_dir / info_path.parent.name / "article.png", - cont_img, out_png) - rec.update({"linked": True, "cont_bbox": cbox, - "stitched": str(out_png), "stitched_size": size}) - results.append(rec) - if verbose: - print(f" ✓ {rec['article']} '{headline[:26]}' → p{N} " - f"(headline {score:.2f}, తరువాయి={marker}) → {out_png.name}") - - (out_dir / "links.json").write_text(json.dumps(results, indent=2, ensure_ascii=False)) - linked = sum(1 for r in results if r["linked"]) - if verbose: - print(f"\n {linked} continuation(s) linked & stitched; report: {out_dir/'links.json'}") - return results - - -if __name__ == "__main__": - import sys - link_continuations(sys.argv[1] if len(sys.argv) > 1 else "output/20260601_234709") diff --git a/scratch_py/_detect_rules.py b/scratch_py/_detect_rules.py deleted file mode 100644 index bf1fccb..0000000 --- a/scratch_py/_detect_rules.py +++ /dev/null @@ -1,74 +0,0 @@ -"""PROOF-OF-CONCEPT: detect the printed grey separator rules on a newspaper page -using classical CV (no ML, no API). Horizontal + vertical thin straight lines are -extracted by morphological opening with long thin kernels, then overlaid on the -page so we can see whether they recover article boundaries. - -Usage: venv/bin/python3 _detect_rules.py [out_png] -""" -import sys -from pathlib import Path - -import cv2 -import numpy as np - - -def detect_rules(gray, min_frac=0.10, thickness=9): - """Return (h_lines, v_lines) as lists of (x1,y1,x2,y2). - min_frac: a rule must be at least this fraction of page width/height long. - """ - H, W = gray.shape - # The rules are mid-grey on white. Invert + threshold so lines become white. - # Use a gentle adaptive-ish binarisation: anything clearly darker than paper. - blur = cv2.GaussianBlur(gray, (3, 3), 0) - bw = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] - - def extract(kernel_len, horizontal): - if horizontal: - k = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_len, 1)) - else: - k = cv2.getStructuringElement(cv2.MORPH_RECT, (1, kernel_len)) - opened = cv2.morphologyEx(bw, cv2.MORPH_OPEN, k, iterations=1) - # thicken slightly so near-collinear fragments merge - opened = cv2.dilate(opened, cv2.getStructuringElement( - cv2.MORPH_RECT, (thickness, thickness))) - cnts, _ = cv2.findContours(opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - lines = [] - for c in cnts: - x, y, w, h = cv2.boundingRect(c) - if horizontal and w >= min_frac * W and h <= 60: - lines.append((x, y + h // 2, x + w, y + h // 2, w)) - if (not horizontal) and h >= min_frac * H and w <= 60: - lines.append((x + w // 2, y, x + w // 2, y + h, h)) - return lines - - h_lines = extract(int(min_frac * W), horizontal=True) - v_lines = extract(int(min_frac * H), horizontal=False) - return h_lines, v_lines - - -def main(png_path, out_path=None): - png_path = Path(png_path) - out_path = Path(out_path) if out_path else Path(f"/tmp/rules_{png_path.stem}.png") - img = cv2.imread(str(png_path)) - gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - H, W = gray.shape - h_lines, v_lines = detect_rules(gray) - - print(f"page {png_path.name} {W}x{H}") - print(f" horizontal rules: {len(h_lines)}") - for x1, y1, x2, y2, ln in sorted(h_lines, key=lambda L: L[1]): - print(f" y={y1:>5} x[{x1:>4}..{x2:>4}] len={ln}") - print(f" vertical rules: {len(v_lines)}") - for x1, y1, x2, y2, ln in sorted(v_lines, key=lambda L: L[0]): - print(f" x={x1:>5} y[{y1:>4}..{y2:>4}] len={ln}") - - for x1, y1, x2, y2, ln in h_lines: - cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 6) # red = horizontal - for x1, y1, x2, y2, ln in v_lines: - cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 6) # blue = vertical - cv2.imwrite(str(out_path), img) - print(f"\noverlay written: {out_path}") - - -if __name__ == "__main__": - main(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None) diff --git a/scratch_py/_diff_snap.py b/scratch_py/_diff_snap.py deleted file mode 100644 index 8c10f04..0000000 --- a/scratch_py/_diff_snap.py +++ /dev/null @@ -1,16 +0,0 @@ -import json -from pathlib import Path -b=json.loads(Path("scratch_py/_snap_base.json").read_text()) -n=json.loads(Path("scratch_py/_snap_new.json").read_text()) -any_change=False -for pg in ("1","2","3","4"): - bp,np_=b[pg],n[pg] - keys=set(bp)|set(np_) - for k in sorted(keys,key=int): - if bp.get(k)!=np_.get(k): - any_change=True - print(f"PAGE{pg} anchor {k}:") - print(f" base={bp.get(k)}") - print(f" new ={np_.get(k)}") -if not any_change: - print("NO CHANGE across all 4 pages — column-walk is a no-op on this fixture.") diff --git a/scratch_py/_find_banner.py b/scratch_py/_find_banner.py deleted file mode 100644 index fc2f39b..0000000 --- a/scratch_py/_find_banner.py +++ /dev/null @@ -1,14 +0,0 @@ -import json -from pathlib import Path -import numpy as np -D = Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -for pg in (1,2,3,4): - regs = json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] - texts=[r for r in regs if r.get("type")=="text"] - ws=[r["bbox"][2]-r["bbox"][0] for r in texts] - pitch=int(np.median(ws)) if ws else 0 - docs=[r for r in regs if r.get("type")=="doc_title"] - print(f"== PAGE {pg}: textmedian(pitch)={pitch}, {len(docs)} doc_titles ==") - for r in sorted(docs,key=lambda r:r["bbox"][1]): - b=r["bbox"]; w=b[2]-b[0] - print(f" doc#{r['id']:>3} bbox={b} w={w} (~{w/max(1,pitch):.1f} col)") diff --git a/scratch_py/_ocr_page4.py b/scratch_py/_ocr_page4.py deleted file mode 100644 index dde81d8..0000000 --- a/scratch_py/_ocr_page4.py +++ /dev/null @@ -1,21 +0,0 @@ -import paddleocr -from PIL import Image -from pathlib import Path - -# Find the latest page 4 image -img_path = next(Path("output").glob("20260612_003429/pages/page_004.png")) -print(f"Running PaddleOCR on {img_path}") - -ocr = paddleocr.PaddleOCR(lang='te') -result = ocr.predict(str(img_path)) - -print("OCR lines on Page 4 containing 'చెరువు' or 'మంత్రి' or numbers:") -if isinstance(result, list) and len(result) > 0: - det_result = result[0] - # Check if it has boxes and texts - texts = det_result.get('rec_texts', []) - boxes = det_result.get('dt_polys', []) - for i, txt in enumerate(texts): - if any(w in txt for w in ["చెరువు", "మంత్రి", "36", "ఏళ్ల", "ఉత్తమ్", "పల్లా", "సిద్ధపేట", "గూడెం"]): - box = boxes[i].tolist() if hasattr(boxes[i], 'tolist') else boxes[i] - print(f"Text: '{txt}' at box: {box}") diff --git a/scratch_py/_peek.py b/scratch_py/_peek.py deleted file mode 100644 index 583e167..0000000 --- a/scratch_py/_peek.py +++ /dev/null @@ -1,11 +0,0 @@ -import sys -sys.path.insert(0,".") -from PIL import Image -from pathlib import Path -base=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -img=Image.open(base/"page_001.png").convert("RGB") -print("page size",img.size) -# bottom region holding H38 + neighbours -crop=img.crop((1550,5300,4135,6800)) -crop.save("scratch_py/_peek_bottom.png") -print("saved scratch_py/_peek_bottom.png", crop.size) diff --git a/scratch_py/_peek2.py b/scratch_py/_peek2.py deleted file mode 100644 index b000dfa..0000000 --- a/scratch_py/_peek2.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys, json -sys.path.insert(0,".") -from PIL import Image -from pathlib import Path -base=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -img=Image.open(base/"page_001.png").convert("RGB") -img.crop((2750,4750,4150,6800)).save("scratch_py/_peek_rightcol.png") -# list regions in right column area -regs=json.loads((base/"page_001.regions.json").read_text())["regions"] -print("regions with cx in [3100,4150] and y in [4750,6800]:") -for r in sorted(regs,key=lambda r:r["bbox"][1]): - b=r["bbox"]; cx=(b[0]+b[2])/2 - if 3100<=cx<=4150 and b[1]<6800 and b[3]>4750: - print(f" R{r['id']:>3} {r.get('type'):<14} bbox={b}") diff --git a/scratch_py/_probe_walk.py b/scratch_py/_probe_walk.py deleted file mode 100644 index fd151bc..0000000 --- a/scratch_py/_probe_walk.py +++ /dev/null @@ -1,29 +0,0 @@ -import sys, json, contextlib, io -sys.path.insert(0,".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -D=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919/pages") -def cx(b): return (b[0]+b[2])/2 -for pg in (1,2,3,4): - png=D/f"page_{pg:03d}.png" - regs0=json.loads((D/f"page_{pg:03d}.regions.json").read_text())["regions"] - with contextlib.redirect_stdout(io.StringIO()): - regs=se.drop_masthead_regions(regs0,"andhra_jyothi",pg,png) - ds=se.find_article_starts_by_dateline(regs,str(png),"andhra_jyothi") - bars=separator_barriers(str(png),regs) - bl=se.cluster_all_article_blocks(regs,dateline_starts=ds,sep_lines=bars) - tws=sorted(r["bbox"][2]-r["bbox"][0] for r in regs if r.get("type")=="text") - pitch=tws[len(tws)//2] if tws else 0 - dl=set(s["region_id"] for s in ds) - docids=set(r["id"] for r in regs if r.get("type")=="doc_title") - hard=dl|docids - vsep=[L for L in bars if L.get("vert")] - print(f"== PAGE{pg} pitch={pitch} vrules={len(vsep)} ==") - for blk in bl: - b=blk["bbox"]; w=b[2]-b[0] - if blk["kind"]=="H" and w>=1.6*pitch: - lo,hi=b[2],b[2]+int(1.4*pitch) - col=[r for r in regs if r.get("type") not in ("header","number") and lo+5<=cx(r["bbox"])<=hi] - hardhit=[r["id"] for r in col if r["id"] in hard] - print(f" banner R{blk['anchor_id']} bbox={b} w={w} (~{w/pitch:.1f}col) rightcol_regs={[r['id'] for r in col]} hard={hardhit}") diff --git a/scratch_py/_regress_final.py b/scratch_py/_regress_final.py deleted file mode 100644 index 13f7c12..0000000 --- a/scratch_py/_regress_final.py +++ /dev/null @@ -1,147 +0,0 @@ -"""Production-path regression harness for grow_articles_final. - -Unlike _regress_grow.py (which calls _grow_article_downward directly with -dateline_starts=None and so over-estimates wrapping), this mirrors the REAL -pipeline tail: it computes dateline_starts via find_article_starts_by_dateline -and runs grow_articles_final exactly as production does. A diff of two snapshots -therefore isolates what the code change does ON THE SHIPPING PATH. - -Usage: - venv/bin/python3 _regress_final.py snapshot.json # snapshot current code - venv/bin/python3 _regress_final.py --diff a.json b.json # compare two snapshots -""" -import json -import sys -from collections import Counter -from pathlib import Path - -OUT = Path("output") - - -def paper_of_height(h): - if 7040 <= h <= 7060: - return "sakshi" - if h in (6833, 6549): - return "andhra_jyothi" - if h == 6422: - return "namaste_telangana" - return "unknown" - - -def union_bbox(member_ids, region_map): - bs = [region_map[r]["bbox"] for r in member_ids if r in region_map] - if not bs: - return None - return [min(b[0] for b in bs), min(b[1] for b in bs), - max(b[2] for b in bs), max(b[3] for b in bs)] - - -def run(): - import copy - from PIL import Image - from smart_extractor import find_article_starts_by_dateline, grow_articles_final - - runs = sorted([d for d in OUT.iterdir() if d.is_dir()], - key=lambda d: d.stat().st_mtime, reverse=True) - snapshot = {} - papers = Counter() - for run_dir in runs: - pages_dir = run_dir / "pages" - if not pages_dir.exists(): - continue - for reg_path in sorted(pages_dir.glob("page_*.regions.json")): - pol_path = reg_path.with_name(reg_path.name.replace( - ".regions.json", ".political_result.json")) - png = reg_path.with_name(reg_path.name.replace(".regions.json", ".png")) - if not pol_path.exists() or not png.exists(): - continue - regions = json.loads(reg_path.read_text())["regions"] - region_map = {r["id"]: r for r in regions} - political = json.loads(pol_path.read_text()).get("political_articles", []) - if not political: - continue - try: - paper = paper_of_height(Image.open(png).height) - dateline_starts = find_article_starts_by_dateline( - regions, str(png), paper) - grown = grow_articles_final( - copy.deepcopy(political), regions, dateline_starts) - except Exception as e: - print(f" SKIP {run_dir.name}/{reg_path.stem}: {e}") - continue - - for i, art in enumerate(grown): - key = f"{run_dir.name}/{reg_path.stem}/art{i}" - members = sorted(art.get("member_region_ids", []) or []) - snapshot[key] = { - "paper": paper, - "headline": art.get("headline_english", "")[:50], - "members": members, - "bbox": union_bbox(members, region_map), - } - papers[paper] += 1 - print(f" papers: {dict(papers)}") - return snapshot - - -def diff(path_a, path_b): - a = json.loads(Path(path_a).read_text()) - b = json.loads(Path(path_b).read_text()) - keys = sorted(set(a) | set(b)) - - per_total = Counter() - per_changed = Counter() - grew = Counter() - shrank = Counter() - samples = [] - - for k in keys: - ra, rb = a.get(k), b.get(k) - paper = (rb or ra).get("paper", "unknown") - per_total[paper] += 1 - if ra is None or rb is None: - per_changed[paper] += 1 - samples.append((k, paper, "ONLY IN ONE SNAPSHOT", None, None)) - continue - sa, sb = set(ra["members"]), set(rb["members"]) - if sa != sb: - per_changed[paper] += 1 - added = sorted(sb - sa) - removed = sorted(sa - sb) - if added: - grew[paper] += 1 - if removed: - shrank[paper] += 1 - samples.append((k, paper, rb["headline"], added, removed)) - - print("\n=== PRODUCTION-PATH DIFF (A=baseline/OLD -> B=new) ===") - print(f"{'paper':<18}{'articles':>10}{'changed':>9}{'grew':>7}{'shrank':>8}") - for paper in sorted(per_total): - print(f"{paper:<18}{per_total[paper]:>10}{per_changed[paper]:>9}" - f"{grew[paper]:>7}{shrank[paper]:>8}") - tot = sum(per_total.values()) - chg = sum(per_changed.values()) - print(f"{'TOTAL':<18}{tot:>10}{chg:>9}{sum(grew.values()):>7}{sum(shrank.values()):>8}") - - if samples: - print(f"\n--- {len(samples)} changed article(s) ---") - for k, paper, hl, added, removed in samples: - print(f"\n[{paper}] {k}") - print(f" headline: {hl}") - if added: - print(f" + added : {added}") - if removed: - print(f" - removed: {removed}") - else: - print("\nNo differences — member sets identical across all fixtures.") - return chg - - -if __name__ == "__main__": - if len(sys.argv) >= 4 and sys.argv[1] == "--diff": - diff(sys.argv[2], sys.argv[3]) - else: - out_path = sys.argv[1] if len(sys.argv) > 1 else "/tmp/final_snapshot.json" - snap = run() - Path(out_path).write_text(json.dumps(snap, indent=2, ensure_ascii=False)) - print(f"wrote {len(snap)} article snapshots to {out_path}") diff --git a/scratch_py/_regress_grow.py b/scratch_py/_regress_grow.py deleted file mode 100644 index 94437d7..0000000 --- a/scratch_py/_regress_grow.py +++ /dev/null @@ -1,173 +0,0 @@ -"""Regression harness for _grow_article_downward. - -Runs the grow function over the saved fixtures of EVERY cached run, with IDENTICAL -auxiliary inputs (claimed = union of OTHER articles' members on the page, -dateline_starts = None). Because old and new code receive the same inputs, a diff -of the two output snapshots isolates exactly what the code change does. - -Records per article: the grown member-id set and its union bbox, tagged with the -source newspaper (from meta.json) so results can be broken down per paper. - -Usage: - python3 _regress_grow.py snapshot.json # snapshot current code - python3 _regress_grow.py --diff a.json b.json # compare two snapshots -""" -import json -import re -import sys -from collections import Counter -from pathlib import Path - -OUT = Path("output") - - -def union_bbox(member_ids, region_map): - bs = [region_map[r]["bbox"] for r in member_ids if r in region_map] - if not bs: - return None - return [min(b[0] for b in bs), min(b[1] for b in bs), - max(b[2] for b in bs), max(b[3] for b in bs)] - - -def paper_of(run_dir): - meta = run_dir / "meta.json" - if meta.exists(): - try: - fn = json.loads(meta.read_text()).get("filename", "") - name = re.split(r"[_0-9]", fn)[0].strip() - if name: - return name - except Exception: - pass - # Cached fixtures carry no meta.json; identify the paper by page-1 image height, - # which is distinct per edition (verified against the printed masthead nameplate). - png = run_dir / "pages" / "page_001.png" - if png.exists(): - try: - from PIL import Image - h = Image.open(png).height - if 7040 <= h <= 7060: - return "Sakshi" - if h in (6833, 6549): - return "Andhra Jyothi" - if h == 6422: - return "Namaste Telangana" - except Exception: - pass - return "unknown" - - -def run(): - from smart_extractor import _grow_article_downward - - runs = sorted([d for d in OUT.iterdir() if d.is_dir()], - key=lambda d: d.stat().st_mtime, reverse=True) - snapshot = {} - papers = Counter() - for run_dir in runs: - pages_dir = run_dir / "pages" - if not pages_dir.exists(): - continue - paper = paper_of(run_dir) - for reg_path in sorted(pages_dir.glob("page_*.regions.json")): - pol_path = reg_path.with_name(reg_path.name.replace(".regions.json", - ".political_result.json")) - if not pol_path.exists(): - continue - regions = json.loads(reg_path.read_text())["regions"] - region_map = {r["id"]: r for r in regions} - political = json.loads(pol_path.read_text()).get("political_articles", []) - - # claimed = every member of every article (mirrors the real caller's - # global claimed set built before growth). - all_members = set() - for a in political: - all_members.update(a.get("member_region_ids", [])) - - for i, art in enumerate(political): - members = art.get("member_region_ids", []) or [] - if not members: - continue - # claimed for THIS article = everything claimed by OTHER articles. - claimed = set(all_members) - set(members) - grown, added = _grow_article_downward( - members, region_map, regions, claimed, dateline_starts=None - ) - key = f"{run_dir.name}/{reg_path.stem}/art{i}" - snapshot[key] = { - "paper": paper, - "headline": art.get("headline_english", "")[:50], - "in_members": sorted(members), - "grown_members": sorted(grown), - "added": sorted(added), - "in_bbox": union_bbox(members, region_map), - "grown_bbox": union_bbox(grown, region_map), - } - papers[paper] += 1 - print(f" papers: {dict(papers)}") - return snapshot - - -def diff(path_a, path_b): - """Compare snapshot A (baseline/OLD) against B (NEW). Reports per-paper how many - articles changed their grown member set, plus a sample of the changes.""" - a = json.loads(Path(path_a).read_text()) - b = json.loads(Path(path_b).read_text()) - keys = sorted(set(a) | set(b)) - - per_paper_total = Counter() - per_paper_changed = Counter() - grew = Counter() # NEW added regions OLD didn't - shrank = Counter() # NEW dropped regions OLD had - samples = [] - - for k in keys: - ra, rb = a.get(k), b.get(k) - paper = (rb or ra).get("paper", "unknown") - per_paper_total[paper] += 1 - if ra is None or rb is None: - per_paper_changed[paper] += 1 - samples.append((k, paper, "ONLY IN ONE SNAPSHOT", None, None)) - continue - sa, sb = set(ra["grown_members"]), set(rb["grown_members"]) - if sa != sb: - per_paper_changed[paper] += 1 - added = sorted(sb - sa) - removed = sorted(sa - sb) - if added: - grew[paper] += 1 - if removed: - shrank[paper] += 1 - samples.append((k, paper, rb["headline"], added, removed)) - - print("\n=== REGRESSION DIFF (A=baseline/OLD → B=new) ===") - print(f"{'paper':<18}{'articles':>10}{'changed':>9}{'grew':>7}{'shrank':>8}") - for paper in sorted(per_paper_total): - print(f"{paper:<18}{per_paper_total[paper]:>10}{per_paper_changed[paper]:>9}" - f"{grew[paper]:>7}{shrank[paper]:>8}") - tot = sum(per_paper_total.values()) - chg = sum(per_paper_changed.values()) - print(f"{'TOTAL':<18}{tot:>10}{chg:>9}{sum(grew.values()):>7}{sum(shrank.values()):>8}") - - if samples: - print(f"\n--- {len(samples)} changed article(s) (showing up to 40) ---") - for k, paper, hl, added, removed in samples[:40]: - print(f"\n[{paper}] {k}") - print(f" headline: {hl}") - if added: - print(f" + added : {added}") - if removed: - print(f" - removed: {removed}") - else: - print("\nNo differences — grown member sets are identical across all fixtures.") - return chg - - -if __name__ == "__main__": - if len(sys.argv) >= 4 and sys.argv[1] == "--diff": - diff(sys.argv[2], sys.argv[3]) - else: - out_path = sys.argv[1] if len(sys.argv) > 1 else "/tmp/grow_snapshot.json" - snap = run() - Path(out_path).write_text(json.dumps(snap, indent=2, ensure_ascii=False)) - print(f"wrote {len(snap)} article snapshots to {out_path}") diff --git a/scratch_py/_regress_masthead.py b/scratch_py/_regress_masthead.py deleted file mode 100644 index 3313aa9..0000000 --- a/scratch_py/_regress_masthead.py +++ /dev/null @@ -1,139 +0,0 @@ -"""Regression harness for drop_masthead_regions. - -drop_masthead_regions runs inside main() BEFORE political_result.json is saved, so -the saved fixtures never capture its effect. This harness replays it directly over -every cached page's regions.json, mirroring the real call -(drop_masthead_regions(regions, paper, page_num, page_img_path)). - -The cached fixtures carry no meta.json, so the paper is recovered from the page-1 -image height (verified against the printed masthead nameplate): - 7053/7055 -> sakshi 6833/6549 -> andhra_jyothi 6422 -> namaste_telangana - -Two views: - • SHIPPED (gated): what the function actually drops in production. Expect the - Namaste Telangana page-1 masthead to be dropped (incl. a doc_title nameplate, - the mis-group seed) and NOTHING dropped on inner pages or other papers. - • UNGATED PROBE: the same geometric rule with the paper/page gate removed, run on - every page-1. Confirms the gate is the only thing keeping the rule off other - papers AND that the rule would never strip a genuine page-1 headline. -""" -import glob -import json -import sys -from collections import Counter -from pathlib import Path - -from PIL import Image - -import smart_extractor -from smart_extractor import drop_masthead_regions - -OUT = Path("output") - - -def paper_of(run_dir): - png = run_dir / "pages" / "page_001.png" - if png.exists(): - try: - h = Image.open(png).height - if 7040 <= h <= 7060: - return "sakshi" - if h in (6833, 6549): - return "andhra_jyothi" - if h == 6422: - return "namaste_telangana" - except Exception: - pass - return "unknown" - - -def page_num_of(reg_path): - # page_001.regions.json -> 1 - stem = reg_path.name.split(".")[0] # page_001 - return int(stem.split("_")[1]) - - -def types_of(regions, ids): - m = {r["id"]: r.get("type") for r in regions} - return Counter(m.get(i) for i in ids) - - -def run(): - dirs = sorted([d for d in OUT.iterdir() if d.is_dir()]) - shipped = [] # rows: (paper, page, run, dropped_ids, dropped_types) - probe = [] # ungated, page-1 only - fired = Counter() # paper -> #page-1 runs where shipped drop fired - p1_total = Counter() # paper -> #page-1 runs - false_pos = [] # shipped drops on non-NT or page>1 (should be empty) - - for d in dirs: - pages_dir = d / "pages" - if not pages_dir.exists(): - continue - paper = paper_of(d) - for reg_path in sorted(pages_dir.glob("page_*.regions.json")): - page_num = page_num_of(reg_path) - png = pages_dir / reg_path.name.replace(".regions.json", ".png") - regions = json.loads(reg_path.read_text())["regions"] - - # ---- SHIPPED (gated) ---- - kept = drop_masthead_regions(list(regions), paper, page_num, str(png)) - kept_ids = {r["id"] for r in kept} - dropped = sorted(r["id"] for r in regions if r["id"] not in kept_ids) - if dropped: - shipped.append((paper, page_num, d.name, dropped, types_of(regions, dropped))) - if not (paper == "namaste_telangana" and page_num == 1): - false_pos.append((paper, page_num, d.name, dropped)) - - if page_num == 1: - p1_total[paper] += 1 - if paper == "namaste_telangana" and dropped: - fired[paper] += 1 - - # ---- UNGATED PROBE (force the rule to run) ---- - probe_kept = drop_masthead_regions(list(regions), "namaste_telangana", 1, str(png)) - probe_kept_ids = {r["id"] for r in probe_kept} - pdropped = sorted(r["id"] for r in regions if r["id"] not in probe_kept_ids) - if pdropped: - probe.append((paper, d.name, pdropped, types_of(regions, pdropped))) - - return shipped, probe, fired, p1_total, false_pos - - -def report(shipped, probe, fired, p1_total, false_pos): - print("\n=== SHIPPED (gated) — Namaste Telangana page-1 masthead drop ===") - nt = [s for s in shipped if s[0] == "namaste_telangana" and s[1] == 1] - print(f"NT page-1 runs: {p1_total['namaste_telangana']} | masthead fired in: {fired['namaste_telangana']}") - seedless = [] - for paper, page, run, dropped, types in sorted(nt, key=lambda x: x[2]): - has_title = types.get("doc_title", 0) > 0 - flag = "" if has_title else " ⚠️ no doc_title dropped (seed not removed?)" - if not has_title: - seedless.append(run) - print(f" {run}: dropped {dropped} types={dict(types)}{flag}") - - misses = p1_total['namaste_telangana'] - fired['namaste_telangana'] - print(f"\n NT page-1 misses (nothing dropped): {misses}") - print(f" NT page-1 drops WITHOUT a doc_title nameplate seed: {len(seedless)} {seedless}") - - print("\n=== FALSE POSITIVES (shipped drops on non-NT, or page>1) ===") - if false_pos: - for paper, page, run, dropped in false_pos: - print(f" ⚠️ {paper} p{page} {run}: dropped {dropped}") - else: - print(" none — gate held: 0 drops on inner pages and on Sakshi/Andhra Jyothi.") - - print("\n=== UNGATED PROBE — would the bare geometric rule strip a real headline? ===") - by_paper = Counter(p[0] for p in probe) - print(f"page-1 runs where the ungated rule drops something, by paper: {dict(by_paper)}") - for paper in ("sakshi", "andhra_jyothi"): - hits = [p for p in probe if p[0] == paper] - print(f"\n --- {paper}: {len(hits)} page-1 run(s) would drop something ungated ---") - for _, run, dropped, types in hits[:12]: - print(f" {run}: {dropped} types={dict(types)}") - if not hits: - print(" none — rule is inert on this paper's page-1 even ungated (safe).") - - -if __name__ == "__main__": - report(*run()) diff --git a/scratch_py/_replay_crop.py b/scratch_py/_replay_crop.py deleted file mode 100644 index 47bc4dc..0000000 --- a/scratch_py/_replay_crop.py +++ /dev/null @@ -1,70 +0,0 @@ -"""Replay the post-Claude pipeline tail on a saved run's fixtures, WITHOUT any -billable Claude calls. Loads regions.json + political_result.json (already -post-safeguard), then applies ONLY the new steps that change the crop: - - grow_articles_final (Fix #1 floor threshold + Fix #3 final grow pass) - - crop_political_articles (Fix #2 column-aware foreign-headline clip) -and writes regenerated crops to a /tmp dir for visual inspection. - -Usage: python3 _replay_crop.py -""" -import json -import sys -from pathlib import Path - -import smart_extractor -from smart_extractor import ( - find_article_starts_by_dateline, - grow_articles_final, - crop_political_articles, -) - - -def paper_of_height(h): - if 7040 <= h <= 7060: - return "sakshi" - if h in (6833, 6549): - return "andhra_jyothi" - if h == 6422: - return "namaste_telangana" - return "unknown" - - -def main(run_dir, page_num): - run = Path(run_dir) - pages = run / "pages" - png = pages / f"page_{page_num:03d}.png" - reg_path = pages / f"page_{page_num:03d}.regions.json" - pol_path = pages / f"page_{page_num:03d}.political_result.json" - - regions = json.loads(reg_path.read_text())["regions"] - political = json.loads(pol_path.read_text())["political_articles"] - - from PIL import Image - paper = paper_of_height(Image.open(png).height) - print(f"paper={paper} regions={len(regions)} articles={len(political)}") - - dateline_starts = find_article_starts_by_dateline(regions, str(png), paper) - - print("\n--- BEFORE grow_articles_final (saved member sets) ---") - for i, a in enumerate(political, 1): - m = sorted(a.get("member_region_ids", []) or []) - print(f" a{i:03d}: {a.get('headline_english','?')[:38]!r:42} members={m}") - - political = grow_articles_final(political, regions, dateline_starts) - - print("\n--- AFTER grow_articles_final ---") - for i, a in enumerate(political, 1): - m = sorted(a.get("member_region_ids", []) or []) - print(f" a{i:03d}: {a.get('headline_english','?')[:38]!r:42} members={m}") - - out = Path(f"/tmp/replay_{run.name}_p{page_num:03d}") - out.mkdir(parents=True, exist_ok=True) - print(f"\n--- CROP (writing to {out}) ---") - crop_political_articles(str(png), political, regions, out, page_num) - print(f"\nCrops written to: {out}") - for f in sorted(out.glob("*.png")): - print(f" {f.name}") - - -if __name__ == "__main__": - main(sys.argv[1], int(sys.argv[2])) diff --git a/scratch_py/_replay_pg1_all.py b/scratch_py/_replay_pg1_all.py deleted file mode 100644 index 9f83196..0000000 --- a/scratch_py/_replay_pg1_all.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys, json, shutil, contextlib, io -sys.path.insert(0,".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -base=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919") -D=base/"pages"; out=base/"pg1_all_current" -if out.exists(): shutil.rmtree(out) -png=D/"page_001.png" -regs=json.loads((D/"page_001.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs=se.drop_masthead_regions(regs,"andhra_jyothi",1,png) - ds=se.find_article_starts_by_dateline(regs,str(png),"andhra_jyothi") - bars=separator_barriers(str(png),regs) - bl=se.cluster_all_article_blocks(regs,dateline_starts=ds,sep_lines=bars) - n=se.crop_all_article_blocks(str(png),regs,str(out),1,dateline_starts=ds,sep_lines=bars) -for b in sorted(bl,key=lambda d:(d["bbox"][1],d["bbox"][0])): - print(f"{b['kind']:>2} anchor={b['anchor_id']:>3} bbox={b['bbox']} w={b['bbox'][2]-b['bbox'][0]}") -print(f"\n{n} crops -> {out}/page_001/") diff --git a/scratch_py/_replay_pg2_all.py b/scratch_py/_replay_pg2_all.py deleted file mode 100644 index efd6304..0000000 --- a/scratch_py/_replay_pg2_all.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys, json, shutil, contextlib, io -sys.path.insert(0,".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -base=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919") -D=base/"pages"; out=base/"pg2_all_current" -if out.exists(): shutil.rmtree(out) -png=D/"page_002.png" -regs=json.loads((D/"page_002.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs=se.drop_masthead_regions(regs,"andhra_jyothi",2,png) - ds=se.find_article_starts_by_dateline(regs,str(png),"andhra_jyothi") - bars=separator_barriers(str(png),regs) - bl=se.cluster_all_article_blocks(regs,dateline_starts=ds,sep_lines=bars) - n=se.crop_all_article_blocks(str(png),regs,str(out),2,dateline_starts=ds,sep_lines=bars) -for b in sorted(bl,key=lambda d:(d["bbox"][1],d["bbox"][0])): - print(f"{b['kind']:>2} anchor={b['anchor_id']:>3} bbox={b['bbox']} w={b['bbox'][2]-b['bbox'][0]}") -print(f"\n{n} crops -> {out}/page_002/") diff --git a/scratch_py/_replay_pg3_all.py b/scratch_py/_replay_pg3_all.py deleted file mode 100644 index 127826b..0000000 --- a/scratch_py/_replay_pg3_all.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys, json, shutil, contextlib, io -sys.path.insert(0,".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -base=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919") -D=base/"pages"; out=base/"pg3_all_current" -if out.exists(): shutil.rmtree(out) -png=D/"page_003.png" -regs=json.loads((D/"page_003.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs=se.drop_masthead_regions(regs,"andhra_jyothi",3,png) - ds=se.find_article_starts_by_dateline(regs,str(png),"andhra_jyothi") - bars=separator_barriers(str(png),regs) - bl=se.cluster_all_article_blocks(regs,dateline_starts=ds,sep_lines=bars) - n=se.crop_all_article_blocks(str(png),regs,str(out),3,dateline_starts=ds,sep_lines=bars) -for b in sorted(bl,key=lambda d:(d["bbox"][1],d["bbox"][0])): - print(f"{b['kind']:>2} anchor={b['anchor_id']:>3} bbox={b['bbox']} w={b['bbox'][2]-b['bbox'][0]}") -print(f"\n{n} crops -> {out}/page_003/") diff --git a/scratch_py/_replay_pg4_all.py b/scratch_py/_replay_pg4_all.py deleted file mode 100644 index cd5eaff..0000000 --- a/scratch_py/_replay_pg4_all.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys, json, shutil, contextlib, io -sys.path.insert(0,".") -from pathlib import Path -import smart_extractor as se -from _lines import separator_barriers -base=Path("output/AndhraJyothi_Siddipet District_20260602_20260603_144919") -D=base/"pages"; out=base/"pg4_all_current" -if out.exists(): shutil.rmtree(out) -png=D/"page_004.png" -regs=json.loads((D/"page_004.regions.json").read_text())["regions"] -with contextlib.redirect_stdout(io.StringIO()): - regs=se.drop_masthead_regions(regs,"andhra_jyothi",4,png) - ds=se.find_article_starts_by_dateline(regs,str(png),"andhra_jyothi") - bars=separator_barriers(str(png),regs) - bl=se.cluster_all_article_blocks(regs,dateline_starts=ds,sep_lines=bars) - n=se.crop_all_article_blocks(str(png),regs,str(out),4,dateline_starts=ds,sep_lines=bars) -for b in sorted(bl,key=lambda d:(d["bbox"][1],d["bbox"][0])): - print(f"{b['kind']:>2} anchor={b['anchor_id']:>3} bbox={b['bbox']} w={b['bbox'][2]-b['bbox'][0]}") -print(f"\n{n} crops -> {out}/page_004/") diff --git a/scratch_py/_replay_regions.py b/scratch_py/_replay_regions.py deleted file mode 100644 index 287aaf2..0000000 --- a/scratch_py/_replay_regions.py +++ /dev/null @@ -1,61 +0,0 @@ -"""Re-run ONLY PaddleOCR layout detection (no Claude calls) on a saved run's -page PNG, at the default 0.5 cutoff and at a lowered threshold, and write the -all-regions debug image for each so the effect of the threshold is visible. - -Usage: venv/bin/python3 _replay_regions.py [threshold] - (threshold defaults to 0.3) -""" -import sys -from collections import Counter -from pathlib import Path - -from smart_extractor import detect_regions, draw_all_regions_debug - - -def summarize(regions): - c = Counter(r.get("type", "unknown") for r in regions) - return ", ".join(f"{k}={v}" for k, v in sorted(c.items(), key=lambda kv: -kv[1])) - - -def main(run_dir, page_num, threshold=0.3): - run = Path(run_dir) - png = run / "pages" / f"page_{page_num:03d}.png" - out = Path(f"/tmp/replay_regions_{run.name}_p{page_num:03d}") - out.mkdir(parents=True, exist_ok=True) - - print(f"=== page {png} -> {out} ===\n") - - # BASELINE: stock 0.5 cutoff - print("--- detection @ default (0.5) ---") - base = detect_regions(str(png), threshold=0.5) - print(f" {len(base)} regions: {summarize(base)}") - draw_all_regions_debug(str(png), base, out, page_num) - Path(out / f"page_{page_num:03d}_allregions_debug.png").rename( - out / f"page_{page_num:03d}_thr050.png") - - # LOWERED: threshold under test - print(f"\n--- detection @ {threshold} ---") - low = detect_regions(str(png), threshold=threshold) - print(f" {len(low)} regions: {summarize(low)}") - draw_all_regions_debug(str(png), low, out, page_num) - Path(out / f"page_{page_num:03d}_allregions_debug.png").rename( - out / f"page_{page_num:03d}_thr{int(threshold*100):03d}.png") - - # DELTA: new regions gained by lowering the cutoff - print(f"\n--- delta: {len(low) - len(base)} more region(s) at {threshold} ---") - base_boxes = {tuple(r["bbox"]) for r in base} - gained = [r for r in low if tuple(r["bbox"]) not in base_boxes] - gained.sort(key=lambda r: (r["bbox"][1], r["bbox"][0])) - for r in gained: - b = r["bbox"] - print(f" + R{r['id']:>3} {r.get('type','?'):>16} conf={r.get('confidence',0):.2f} " - f"bbox={b} ({b[2]-b[0]}x{b[3]-b[1]})") - - print(f"\nImages written to: {out}") - for f in sorted(out.glob("*.png")): - print(f" {f.name}") - - -if __name__ == "__main__": - thr = float(sys.argv[3]) if len(sys.argv) > 3 else 0.3 - main(sys.argv[1], int(sys.argv[2]), thr) diff --git a/scratch_py/_search_pdf.py b/scratch_py/_search_pdf.py deleted file mode 100644 index 145a5c1..0000000 --- a/scratch_py/_search_pdf.py +++ /dev/null @@ -1,13 +0,0 @@ -import fitz -import sys -from pathlib import Path - -# Find the PDF in the processed directory -pdf_path = next(Path("processed").glob("Jyothi_SiddipetDistrict_17-05-2026*.pdf")) -doc = fitz.open(str(pdf_path)) -if len(doc) >= 4: - page = doc[3] # 0-indexed page 4 is index 3 - print("PAGE 4 TEXT:") - print(page.get_text()) -else: - print(f"PDF only has {len(doc)} pages") diff --git a/scratch_py/_snap_base.json b/scratch_py/_snap_base.json deleted file mode 100644 index cd9070f..0000000 --- a/scratch_py/_snap_base.json +++ /dev/null @@ -1,683 +0,0 @@ -{ -"1": { -"32": [ -"H", -[ -1, -4, -6, -9, -20, -23, -31, -32, -36, -42, -45, -46, -56, -64 -] -], -"61": [ -"H", -[ -13, -25, -26, -28, -39, -47, -61 -] -], -"55": [ -"P", -[ -22, -35, -55, -65 -] -], -"5": [ -"DL", -[ -5, -18, -53 -] -], -"59": [ -"H", -[ -2, -59 -] -], -"60": [ -"H", -[ -15, -60, -66 -] -], -"3": [ -"DL", -[ -3, -21, -75 -] -], -"16": [ -"O", -[ -16 -] -], -"12": [ -"O", -[ -12, -33, -34, -58 -] -], -"76": [ -"O", -[ -76 -] -], -"68": [ -"O", -[ -68 -] -], -"48": [ -"H", -[ -14, -17, -19, -29, -44, -48, -54, -62, -67, -71 -] -], -"50": [ -"H", -[ -8, -11, -27, -30, -43, -49, -50, -57, -63, -73 -] -], -"38": [ -"H", -[ -7, -10, -37, -38, -41, -51, -52, -69, -70, -74 -] -] -}, -"2": { -"68": [ -"H", -[ -7, -27, -34, -36, -47, -65, -68, -69, -75, -76 -] -], -"4": [ -"DL", -[ -4, -63 -] -], -"61": [ -"P", -[ -32, -61 -] -], -"64": [ -"P", -[ -6, -41, -62, -64 -] -], -"10": [ -"DL", -[ -10, -43 -] -], -"56": [ -"H", -[ -1, -3, -5, -14, -56, -58, -79, -83, -89 -] -], -"87": [ -"H", -[ -2, -22, -40, -42, -87, -93, -94 -] -], -"28": [ -"DL", -[ -12, -28, -38, -85, -92, -96 -] -], -"71": [ -"O", -[ -71, -77, -80, -88 -] -], -"39": [ -"O", -[ -39, -72 -] -], -"50": [ -"H", -[ -8, -9, -16, -50, -73 -] -], -"18": [ -"DL", -[ -11, -18, -24, -26, -46, -51, -66, -70 -] -], -"19": [ -"DL", -[ -19 -] -], -"78": [ -"H", -[ -17, -35, -78 -] -], -"13": [ -"DL", -[ -13, -55 -] -], -"86": [ -"H", -[ -23, -25, -29, -57, -86 -] -], -"20": [ -"DL", -[ -20, -59 -] -], -"49": [ -"H", -[ -30, -37, -44, -49, -60, -74, -91 -] -], -"53": [ -"H", -[ -15, -31, -33, -53, -81, -84, -90 -] -], -"54": [ -"H", -[ -21, -54, -82 -] -] -}, -"3": { -"48": [ -"H", -[ -18, -22, -27, -36, -48, -49, -60, -72 -] -], -"63": [ -"H", -[ -6, -31, -63, -71, -73 -] -], -"32": [ -"O", -[ -32 -] -], -"56": [ -"P", -[ -20, -28, -41, -56, -66 -] -], -"75": [ -"H", -[ -2, -14, -47, -69, -75 -] -], -"15": [ -"DL", -[ -15, -23, -51 -] -], -"53": [ -"P", -[ -9, -11, -24, -53 -] -], -"19": [ -"O", -[ -19, -29, -61 -] -], -"26": [ -"O", -[ -26, -64 -] -], -"33": [ -"H", -[ -1, -3, -12, -21, -33, -34, -43, -46, -62 -] -], -"59": [ -"H", -[ -4, -17, -45, -59 -] -], -"42": [ -"H", -[ -13, -25, -30, -42, -54, -55, -57 -] -], -"35": [ -"H", -[ -7, -10, -16, -35, -40, -44, -58, -67, -70, -76, -78, -79 -] -], -"38": [ -"H", -[ -5, -38 -] -], -"50": [ -"H", -[ -8, -50, -68, -77 -] -] -}, -"4": { -"48": [ -"H", -[ -2, -3, -9, -10, -24, -25, -27, -32, -33, -34, -45, -48, -49, -59, -71, -87 -] -], -"92": [ -"P", -[ -12, -39, -64, -83, -92 -] -], -"97": [ -"H", -[ -11, -13, -14, -16, -46, -51, -52, -68, -69, -76, -77, -97, -107 -] -], -"26": [ -"O", -[ -26, -66 -] -], -"96": [ -"H", -[ -5, -38, -41, -42, -65, -86, -96 -] -], -"91": [ -"H", -[ -1, -6, -29, -31, -36, -37, -60, -73, -78, -91 -] -], -"89": [ -"H", -[ -17, -35, -40, -47, -56, -80, -89, -102 -] -], -"62": [ -"H", -[ -7, -8, -54, -57, -62, -75, -82, -94 -] -], -"85": [ -"H", -[ -4, -23, -67, -74, -85 -] -], -"93": [ -"H", -[ -18, -93 -] -], -"22": [ -"O", -[ -22 -] -], -"21": [ -"DL", -[ -21, -63 -] -], -"19": [ -"DL", -[ -19, -30, -50, -58, -88 -] -], -"103": [ -"H", -[ -28, -43, -101, -103 -] -], -"44": [ -"O", -[ -44 -] -], -"81": [ -"H", -[ -15, -81 -] -], -"72": [ -"H", -[ -20, -72 -] -], -"98": [ -"O", -[ -98 -] -], -"90": [ -"O", -[ -90 -] -] -} -} \ No newline at end of file diff --git a/scratch_py/_snap_new.json b/scratch_py/_snap_new.json deleted file mode 100644 index c8f4c15..0000000 --- a/scratch_py/_snap_new.json +++ /dev/null @@ -1,683 +0,0 @@ -{ -"1": { -"61": [ -"H", -[ -13, -23, -25, -26, -28, -39, -47, -61, -64 -] -], -"55": [ -"P", -[ -22, -35, -55, -65 -] -], -"5": [ -"DL", -[ -5, -18, -53 -] -], -"32": [ -"H", -[ -1, -4, -6, -9, -20, -31, -32, -36, -42, -45, -46, -56 -] -], -"59": [ -"H", -[ -2, -59 -] -], -"60": [ -"H", -[ -15, -60, -66 -] -], -"3": [ -"DL", -[ -3, -21, -75 -] -], -"16": [ -"O", -[ -16 -] -], -"12": [ -"O", -[ -12, -33, -34, -58 -] -], -"76": [ -"O", -[ -76 -] -], -"68": [ -"O", -[ -68 -] -], -"48": [ -"H", -[ -17, -48 -] -], -"38": [ -"H", -[ -7, -10, -14, -19, -29, -37, -38, -41, -44, -51, -52, -54, -62, -67, -69, -70, -71, -74 -] -], -"50": [ -"H", -[ -8, -11, -27, -30, -43, -49, -50, -57, -63, -73 -] -] -}, -"2": { -"68": [ -"H", -[ -7, -27, -34, -36, -47, -65, -68, -69, -75, -76 -] -], -"4": [ -"DL", -[ -4, -63 -] -], -"61": [ -"P", -[ -32, -61 -] -], -"64": [ -"P", -[ -6, -41, -62, -64 -] -], -"10": [ -"DL", -[ -10, -43 -] -], -"56": [ -"H", -[ -1, -3, -5, -14, -56, -58, -79, -83, -89 -] -], -"87": [ -"H", -[ -2, -22, -40, -42, -87, -93, -94 -] -], -"28": [ -"DL", -[ -12, -28, -38, -85, -92, -96 -] -], -"71": [ -"O", -[ -71, -77, -80, -88 -] -], -"39": [ -"O", -[ -39, -72 -] -], -"50": [ -"H", -[ -8, -9, -16, -50, -73 -] -], -"18": [ -"DL", -[ -11, -18, -24, -26, -46, -51, -66, -70 -] -], -"19": [ -"DL", -[ -19 -] -], -"78": [ -"H", -[ -17, -35, -78 -] -], -"13": [ -"DL", -[ -13, -55 -] -], -"86": [ -"H", -[ -23, -25, -29, -57, -86 -] -], -"20": [ -"DL", -[ -20, -59 -] -], -"49": [ -"H", -[ -30, -37, -44, -49, -60, -74, -91 -] -], -"53": [ -"H", -[ -15, -31, -33, -53, -81, -84, -90 -] -], -"54": [ -"H", -[ -21, -54, -82 -] -] -}, -"3": { -"48": [ -"H", -[ -18, -22, -27, -36, -48, -49, -60, -72 -] -], -"63": [ -"H", -[ -6, -31, -63, -71, -73 -] -], -"32": [ -"O", -[ -32 -] -], -"56": [ -"P", -[ -20, -28, -41, -56, -66 -] -], -"75": [ -"H", -[ -2, -14, -47, -69, -75 -] -], -"15": [ -"DL", -[ -15, -23, -51 -] -], -"53": [ -"P", -[ -9, -11, -24, -53 -] -], -"19": [ -"O", -[ -19, -29, -61 -] -], -"26": [ -"O", -[ -26, -64 -] -], -"33": [ -"H", -[ -1, -3, -12, -21, -33, -34, -43, -46, -62 -] -], -"59": [ -"H", -[ -4, -17, -45, -59 -] -], -"42": [ -"H", -[ -13, -25, -30, -42, -54, -55, -57 -] -], -"35": [ -"H", -[ -7, -10, -16, -35, -40, -44, -58, -67, -70, -76, -78, -79 -] -], -"38": [ -"H", -[ -5, -38 -] -], -"50": [ -"H", -[ -8, -50, -68, -77 -] -] -}, -"4": { -"48": [ -"H", -[ -2, -3, -9, -10, -24, -25, -27, -32, -33, -34, -45, -48, -49, -59, -71, -87 -] -], -"92": [ -"P", -[ -12, -39, -64, -83, -92 -] -], -"97": [ -"H", -[ -11, -13, -14, -16, -46, -51, -52, -68, -69, -76, -77, -97, -107 -] -], -"26": [ -"O", -[ -26, -66 -] -], -"96": [ -"H", -[ -5, -38, -41, -42, -65, -86, -96 -] -], -"91": [ -"H", -[ -1, -6, -29, -31, -36, -37, -60, -73, -78, -91 -] -], -"89": [ -"H", -[ -17, -35, -40, -47, -56, -80, -89, -102 -] -], -"62": [ -"H", -[ -7, -8, -54, -57, -62, -75, -82, -94 -] -], -"85": [ -"H", -[ -4, -23, -67, -74, -85 -] -], -"93": [ -"H", -[ -18, -93 -] -], -"22": [ -"O", -[ -22 -] -], -"21": [ -"DL", -[ -21, -63 -] -], -"19": [ -"DL", -[ -19, -30, -50, -58, -88 -] -], -"103": [ -"H", -[ -28, -43, -101, -103 -] -], -"44": [ -"O", -[ -44 -] -], -"81": [ -"H", -[ -15, -81 -] -], -"72": [ -"H", -[ -20, -72 -] -], -"98": [ -"O", -[ -98 -] -], -"90": [ -"O", -[ -90 -] -] -} -} \ No newline at end of file diff --git a/scratch_py/_synth_walk.py b/scratch_py/_synth_walk.py deleted file mode 100644 index d351ccd..0000000 --- a/scratch_py/_synth_walk.py +++ /dev/null @@ -1,18 +0,0 @@ -import sys -sys.path.insert(0,".") -import smart_extractor as se -# pitch ~ 700. Banner spans cols 1-2 (x 0..1500). Article band y 0..2000. -R=[ - {"id":1,"type":"doc_title","bbox":[0,0,1500,150],"confidence":0.9}, # banner (cols1-2) - {"id":2,"type":"text","bbox":[0,200,700,2000],"confidence":0.9}, # col1 body (has dateline) - {"id":3,"type":"text","bbox":[760,200,1460,2000],"confidence":0.9}, # col2 body - {"id":4,"type":"text","bbox":[1520,200,2220,2000],"confidence":0.9}, # col3 CONTINUATION (no dateline) - {"id":5,"type":"paragraph_title","bbox":[1520,200,2120,260],"confidence":0.9}, # col3 subhead -] -# dateline only in col1 body (region 2) -ds=[{"region_id":2,"bbox":[0,200,700,260],"headline_region":1}] -bl=se.cluster_all_article_blocks(R,dateline_starts=ds,sep_lines=[]) -for b in bl: - print(b["kind"],"anchor",b["anchor_id"],"members",sorted(b["members"]),"bbox",b["bbox"]) -assert any(b["anchor_id"]==1 and 4 in b["members"] and 5 in b["members"] for b in bl), "col3 NOT absorbed" -print("\nPASS: col3 (regions 4,5) absorbed into banner block anchor=1") diff --git a/scratch_py/_test_boundaries.py b/scratch_py/_test_boundaries.py deleted file mode 100644 index b0f66db..0000000 --- a/scratch_py/_test_boundaries.py +++ /dev/null @@ -1,87 +0,0 @@ -"""Single-page boundary test: datelines + rules -> article boxes, overlaid. -Usage: venv/bin/python3 _test_boundaries.py -""" -import json -import sys -from pathlib import Path - -import cv2 -from PIL import Image - -from _lines import detect_separator_lines -from _boundaries import construct_boundaries -from smart_extractor import find_article_starts_by_dateline - - -def paper_of_height(h): - if 7040 <= h <= 7060: - return "sakshi" - if h in (6833, 6549): - return "andhra_jyothi" - if h == 6422: - return "namaste_telangana" - return "unknown" - - -def iou(a, b): - ix = max(0, min(a[2], b[2]) - max(a[0], b[0])) - iy = max(0, min(a[3], b[3]) - max(a[1], b[1])) - inter = ix * iy - if inter == 0: - return 0.0 - ua = (a[2] - a[0]) * (a[3] - a[1]) + (b[2] - b[0]) * (b[3] - b[1]) - inter - return inter / ua if ua else 0.0 - - -def main(run_dir, page_num): - run = Path(run_dir) - png = run / "pages" / f"page_{page_num:03d}.png" - regs = json.loads((run / "pages" / f"page_{page_num:03d}.regions.json").read_text())["regions"] - rmap = {r["id"]: r for r in regs} - paper = paper_of_height(Image.open(png).height) - - lines = detect_separator_lines(png) - dls = find_article_starts_by_dateline(regs, str(png), paper) - boxes = construct_boundaries(regs, dls, lines, lines["size"]) - - print(f"\npaper={paper} datelines={len(dls)} boxes={len(boxes)} " - f"rules H={len(lines['h'])} V={len(lines['v'])}") - - # validation - fails = [] - for bx in boxes: - db = rmap[bx["region_id"]]["bbox"] - bb = bx["bbox"] - contains = bb[0] <= db[0] and bb[1] <= db[1] and bb[2] >= db[2] and bb[3] >= db[3] - if not contains: - fails.append(f"R{bx['region_id']} box does NOT contain its dateline body") - if bb[2] - bb[0] < 50 or bb[3] - bb[1] < 50: - fails.append(f"R{bx['region_id']} degenerate box {bb}") - for i in range(len(boxes)): - for j in range(i + 1, len(boxes)): - ov = iou(boxes[i]["bbox"], boxes[j]["bbox"]) - if ov > 0.25: - fails.append(f"R{boxes[i]['region_id']} & R{boxes[j]['region_id']} overlap iou={ov:.2f}") - - for bx in sorted(boxes, key=lambda z: z["bbox"][1]): - print(f" R{bx['region_id']:>3} hl=R{bx['headline_region']} {bx['dateline'][:22]!r:24} " - f"bbox={bx['bbox']} walls={bx['walls']['ceil_rule']}/{bx['walls']['floor_rule']}") - print(f"\nVALIDATION: {'PASS' if not fails else f'{len(fails)} ISSUE(S)'}") - for f in fails: - print(" ⚠", f) - - img = cv2.imread(str(png)) - for L in lines["h"]: - cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (0, 0, 255), 4) - for L in lines["v"]: - cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (255, 0, 0), 4) - for bx in boxes: - b = bx["bbox"] - cv2.rectangle(img, (b[0], b[1]), (b[2], b[3]), (0, 180, 0), 8) - out = Path(f"/tmp/boundaries_{run.name}_p{page_num:03d}.png") - cv2.imwrite(str(out), img) - print("overlay:", out) - - -if __name__ == "__main__": - main(sys.argv[1], int(sys.argv[2])) diff --git a/scratch_py/_test_boundaries50.py b/scratch_py/_test_boundaries50.py deleted file mode 100644 index 8306c61..0000000 --- a/scratch_py/_test_boundaries50.py +++ /dev/null @@ -1,170 +0,0 @@ -"""50-run validation harness (no Claude). For every page with a regions.json in -the last N runs: detect rules -> dateline scan -> construct article boundaries -> -validate. Writes overlays for FAILING pages and a per-paper pass/fail report. - -Usage: venv/bin/python3 _test_boundaries50.py [N=50] [out_dir=/tmp/bnd50] -""" -import json -import sys -import traceback -from collections import Counter -from pathlib import Path - -import cv2 -from PIL import Image - -from _lines import detect_separator_lines -from _boundaries import construct_boundaries -from smart_extractor import find_article_starts_by_dateline - -OUT = Path("output") -DL_CACHE = Path("/tmp/dl_cache") -DL_CACHE.mkdir(parents=True, exist_ok=True) - - -def cached_datelines(regs, png, paper, key): - """Datelines depend only on the (fixed) regions + page image, so cache the - Tesseract scan to disk — re-validation after a _boundaries.py edit is then - instant (no OCR).""" - cf = DL_CACHE / f"{key}.json" - if cf.exists(): - return json.loads(cf.read_text()) - dls = find_article_starts_by_dateline(regs, png, paper) - cf.write_text(json.dumps(dls)) - return dls - - -def paper_of_height(h): - if 7040 <= h <= 7060: - return "sakshi" - if h in (6833, 6549): - return "andhra_jyothi" - if h == 6422: - return "namaste_telangana" - return f"h{h}" - - -def iou(a, b): - ix = max(0, min(a[2], b[2]) - max(a[0], b[0])) - iy = max(0, min(a[3], b[3]) - max(a[1], b[1])) - inter = ix * iy - if not inter: - return 0.0 - ua = (a[2]-a[0])*(a[3]-a[1]) + (b[2]-b[0])*(b[3]-b[1]) - inter - return inter / ua if ua else 0.0 - - -def validate(boxes, rmap): - issues = [] - for bx in boxes: - db = rmap[bx["region_id"]]["bbox"] - bb = bx["bbox"] - if not (bb[0] <= db[0]+2 and bb[1] <= db[1]+2 and bb[2] >= db[2]-2 and bb[3] >= db[3]-2): - issues.append(("no-contain", bx["region_id"])) - if bb[2]-bb[0] < 60 or bb[3]-bb[1] < 60: - issues.append(("degenerate", bx["region_id"])) - for i in range(len(boxes)): - for j in range(i+1, len(boxes)): - if iou(boxes[i]["bbox"], boxes[j]["bbox"]) > 0.25: - issues.append(("overlap", (boxes[i]["region_id"], boxes[j]["region_id"]))) - return issues - - -def draw(png, lines, boxes, out_path): - img = cv2.imread(str(png)) - for L in lines["h"]: - cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (0, 0, 255), 4) - for L in lines["v"]: - cv2.line(img, (L["x1"], L["y1"]), (L["x2"], L["y2"]), (255, 0, 0), 4) - for bx in boxes: - b = bx["bbox"] - cv2.rectangle(img, (b[0], b[1]), (b[2], b[3]), (0, 180, 0), 8) - cv2.imwrite(str(out_path), img) - - -def main(n=50, out_dir="/tmp/bnd50"): - out_dir = Path(out_dir) - out_dir.mkdir(parents=True, exist_ok=True) - runs = sorted([d for d in OUT.iterdir() if d.is_dir()], - key=lambda d: d.stat().st_mtime, reverse=True)[:n] - - per_paper_pages = Counter() - per_paper_fail = Counter() - issue_kinds = Counter() - fail_list = [] - total_pages = 0 - total_boxes = 0 - total_dls = 0 - - for run in runs: - pages = run / "pages" - if not pages.exists(): - continue - for reg_path in sorted(pages.glob("page_*.regions.json")): - png = reg_path.with_name(reg_path.name.replace(".regions.json", ".png")) - if not png.exists(): - continue - try: - regs = json.loads(reg_path.read_text())["regions"] - rmap = {r["id"]: r for r in regs} - paper = paper_of_height(Image.open(png).height) - lines = detect_separator_lines(png) - dls = cached_datelines(regs, str(png), paper, - f"{run.name}_{reg_path.stem}") - if not dls: - continue # no datelines -> nothing to bound - boxes = construct_boundaries(regs, dls, lines, lines["size"]) - issues = validate(boxes, rmap) - except Exception: - issues = [("exception", reg_path.name)] - boxes, dls, lines = [], [], {"h": [], "v": []} - traceback.print_exc() - - total_pages += 1 - total_boxes += len(boxes) - total_dls += len(dls) - per_paper_pages[paper] += 1 - if issues: - per_paper_fail[paper] += 1 - for k, _ in issues: - issue_kinds[k] += 1 - tag = f"{run.name}_{reg_path.stem}" - fail_list.append((tag, paper, len(dls), len(boxes), issues)) - try: - draw(png, lines, boxes, out_dir / f"FAIL_{tag}.png") - except Exception: - pass - - print("\n==================== BOUNDARY VALIDATION (last %d runs) ====================" % n) - print(f"{'paper':<20}{'pages':>8}{'fail':>7}{'pass%':>8}") - for paper in sorted(per_paper_pages): - pg = per_paper_pages[paper] - fl = per_paper_fail[paper] - print(f"{paper:<20}{pg:>8}{fl:>7}{100*(pg-fl)/pg:>7.0f}%") - tot = total_pages - fl = sum(per_paper_fail.values()) - print(f"{'TOTAL':<20}{tot:>8}{fl:>7}{100*(tot-fl)/max(1,tot):>7.0f}%") - print(f"\ndatelines total={total_dls} boxes total={total_boxes} " - f"(boxes should equal datelines: {'OK' if total_dls==total_boxes else 'MISMATCH'})") - print(f"issue kinds: {dict(issue_kinds)}") - - if fail_list: - print(f"\n--- {len(fail_list)} failing page(s) (overlays in {out_dir}/FAIL_*.png) ---") - for tag, paper, nd, nb, issues in fail_list[:60]: - ic = Counter(k for k, _ in issues) - print(f" [{paper}] {tag} dls={nd} boxes={nb} {dict(ic)}") - # machine-readable - (out_dir / "report.json").write_text(json.dumps({ - "pages": total_pages, "fail": fl, - "per_paper": {p: [per_paper_pages[p], per_paper_fail[p]] for p in per_paper_pages}, - "issue_kinds": dict(issue_kinds), - "fails": [[t, p, nd, nb, [list(x) if isinstance(x, tuple) else x for _, x in iss]] - for t, p, nd, nb, iss in fail_list], - }, indent=2)) - print(f"\nreport: {out_dir/'report.json'}") - - -if __name__ == "__main__": - n = int(sys.argv[1]) if len(sys.argv) > 1 else 50 - od = sys.argv[2] if len(sys.argv) > 2 else "/tmp/bnd50" - main(n, od) diff --git a/scratch_py/vl_compare.py b/scratch_py/vl_compare.py deleted file mode 100644 index 06bf0e7..0000000 --- a/scratch_py/vl_compare.py +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env python3 -""" -vl_compare.py — Run PaddleOCR-VL on one newspaper page and compare its -layout / reading-order output against the existing PaddleOCR LayoutDetection -regions (page_XXX.regions.json) produced by extractor.py. - -Goal: see whether VL's reading-order blocks line up with article boundaries -better than the current "box soup" before deciding to swap engines. - -USAGE - # auto-pick the most recent output//pages/page_001.png and its regions.json - python vl_compare.py - - # or point at a specific page + regions file - python vl_compare.py output/20260529_004651/pages/page_001.png \ - output/20260529_004651/pages/page_001.regions.json - -OUTPUT (written next to the page image) - page_XXX.vl_layout.json normalized VL blocks (id, type, bbox, reading order, text) - page_XXX.vl_debug.png page with VL boxes + reading-order numbers drawn - page_XXX.vl_vs_paddle.json side-by-side summary (counts by type, totals) - page_XXX.vl_raw.json raw VL result (best-effort, for debugging) - -NOTES - * PaddleOCR-VL is a ~0.9B vision-language model — expect a GPU and a model - download on first run. It is SEPARATE from the lightweight LayoutDetection - used in extractor.py. - * The VL entry point has moved across releases. This script tries several - known import paths and prints a clear hint if none are found so you can - adapt the one line to your installed version. - * Run inside your project venv: ./venv/bin/python vl_compare.py -""" - -import os -import sys -import glob -import json -import traceback - - -# -------------------------------------------------------------------------- -# 1. Resolve input page image + matching regions.json -# -------------------------------------------------------------------------- -def resolve_inputs(argv): - if len(argv) >= 2: - page_png = argv[1] - regions_json = argv[2] if len(argv) >= 3 else os.path.splitext(page_png)[0] + ".regions.json" - return page_png, regions_json - - # auto-discover: most recently modified page_001.png under output/ - candidates = sorted( - glob.glob("output/*/pages/page_001.png"), - key=os.path.getmtime, - reverse=True, - ) - if not candidates: - sys.exit("No page_001.png found under output/*/pages/. " - "Pass a page image path explicitly: python vl_compare.py [regions.json]") - page_png = candidates[0] - regions_json = os.path.splitext(page_png)[0] + ".regions.json" - return page_png, regions_json - - -# -------------------------------------------------------------------------- -# 2. Load the VL model (defensive across releases) -# -------------------------------------------------------------------------- -def load_vl_model(): - import paddleocr - print(f"paddleocr version: {getattr(paddleocr, '__version__', 'unknown')}") - - # Try the documented entry points, newest-first. Adjust if your release differs. - attempts = [ - ("paddleocr.PaddleOCRVL", lambda: paddleocr.PaddleOCRVL()), - ("paddleocr.PPDocVL", lambda: paddleocr.PPDocVL()), - ("paddleocr.DocVLM", lambda: paddleocr.DocVLM()), - ] - for name, ctor in attempts: - try: - model = ctor() - print(f"Loaded VL model via: {name}") - return model - except Exception as e: # noqa: BLE001 - print(f" - {name} unavailable: {e}") - - # Last resort: PaddleX pipeline name - try: - from paddlex import create_pipeline - model = create_pipeline(pipeline="PaddleOCR-VL") - print("Loaded VL model via: paddlex.create_pipeline('PaddleOCR-VL')") - return model - except Exception as e: # noqa: BLE001 - print(f" - paddlex pipeline unavailable: {e}") - - sys.exit( - "\nCould not load PaddleOCR-VL with any known entry point.\n" - "Check the exact class name for your installed version, e.g.:\n" - " python -c \"import paddleocr; print([n for n in dir(paddleocr) if 'VL' in n or 'Doc' in n])\"\n" - "then edit the `attempts` list near the top of load_vl_model()." - ) - - -# -------------------------------------------------------------------------- -# 3. Run VL + normalize its output to the same shape as regions.json -# -------------------------------------------------------------------------- -def to_bbox(coord): - """Accept [x1,y1,x2,y2] or polygon [x1,y1,...] -> [x1,y1,x2,y2] ints.""" - if coord is None: - return [0, 0, 0, 0] - if hasattr(coord, "tolist"): - coord = coord.tolist() - coord = [float(v) for v in coord] - if len(coord) == 4: - return [int(v) for v in coord] - xs = coord[0::2] - ys = coord[1::2] - return [int(min(xs)), int(min(ys)), int(max(xs)), int(max(ys))] - - -def run_vl(model, page_png): - if hasattr(model, "predict"): - raw = model.predict(page_png) - elif callable(model): - raw = model(page_png) - else: - raw = model.predict(input=page_png) - - # raw is typically a list of result objects (dict-like). Iterate generically. - results = list(raw) if not isinstance(raw, list) else raw - - blocks = [] - raw_dump = [] - - for res in results: - # try to get a plain dict for dumping/parsing - d = None - for attr in ("json", "res", "_to_dict"): - try: - v = getattr(res, attr, None) - d = v() if callable(v) else v - if d: - break - except Exception: # noqa: BLE001 - pass - if d is None and isinstance(res, dict): - d = res - raw_dump.append(_jsonable(d if d is not None else str(res))) - - # VL layout blocks commonly live under one of these keys - layout = None - if isinstance(d, dict): - for key in ("layout_det_res", "parsing_res_list", "layout", "blocks", "boxes"): - if key in d and d[key]: - layout = d[key] - break - if layout is None: - continue - - # layout may itself be a dict containing 'boxes' - if isinstance(layout, dict): - layout = layout.get("boxes", layout.get("parsing_res_list", [])) - - for i, b in enumerate(layout): - if not isinstance(b, dict): - continue - coord = b.get("coordinate", b.get("bbox", b.get("block_bbox", b.get("layout_bbox")))) - label = str(b.get("label", b.get("type", b.get("block_label", "unknown")))).lower() - score = float(b.get("score", b.get("confidence", 0)) or 0) - order = b.get("reading_order", b.get("order", b.get("index", i))) - text = b.get("text", b.get("block_content", b.get("rec_text", ""))) - if isinstance(text, list): - text = " ".join(map(str, text)) - blocks.append({ - "id": len(blocks) + 1, - "type": label, - "bbox": to_bbox(coord), - "confidence": round(score, 4), - "reading_order": order, - "text_preview": (str(text)[:120] if text else ""), - }) - - # sort by reading order if available - try: - blocks.sort(key=lambda x: (x["reading_order"] if isinstance(x["reading_order"], (int, float)) else 0)) - for i, b in enumerate(blocks, 1): - b["id"] = i - except Exception: # noqa: BLE001 - pass - - return blocks, raw_dump - - -def _jsonable(obj): - try: - json.dumps(obj) - return obj - except Exception: # noqa: BLE001 - return str(obj) - - -# -------------------------------------------------------------------------- -# 4. Compare against existing PaddleOCR regions -# -------------------------------------------------------------------------- -def type_counts(regions): - c = {} - for r in regions: - t = r.get("type", "unknown") - c[t] = c.get(t, 0) + 1 - return dict(sorted(c.items(), key=lambda x: -x[1])) - - -def draw_debug(page_png, blocks, out_png): - try: - from PIL import Image, ImageDraw, ImageFont - except Exception: # noqa: BLE001 - print("Pillow not available — skipping debug image.") - return - img = Image.open(page_png).convert("RGB") - draw = ImageDraw.Draw(img) - try: - font = ImageFont.truetype("DejaVuSans-Bold.ttf", 60) - except Exception: # noqa: BLE001 - font = ImageFont.load_default() - for b in blocks: - x1, y1, x2, y2 = b["bbox"] - draw.rectangle([x1, y1, x2, y2], outline=(220, 30, 30), width=6) - tag = f"{b['id']}:{b['type']}" - draw.text((x1 + 8, y1 + 8), tag, fill=(220, 30, 30), font=font) - img.save(out_png) - print(f" wrote {out_png}") - - -def main(): - page_png, regions_json = resolve_inputs(sys.argv) - if not os.path.exists(page_png): - sys.exit(f"Page image not found: {page_png}") - print(f"Page image : {page_png}") - print(f"Regions JSON: {regions_json} (exists={os.path.exists(regions_json)})") - - stem = os.path.splitext(page_png)[0] - - # existing paddle regions - paddle_regions = [] - if os.path.exists(regions_json): - with open(regions_json) as f: - paddle_regions = json.load(f).get("regions", []) - - # run VL - print("\nLoading PaddleOCR-VL (first run downloads the model)...") - model = load_vl_model() - print("Running VL on the page...") - blocks, raw_dump = run_vl(model, page_png) - - # write outputs - with open(stem + ".vl_layout.json", "w") as f: - json.dump({"page_image": os.path.basename(page_png), "blocks": blocks}, f, indent=2, ensure_ascii=False) - with open(stem + ".vl_raw.json", "w") as f: - json.dump(raw_dump, f, indent=2, ensure_ascii=False) - - summary = { - "page_image": os.path.basename(page_png), - "paddle_layoutdetection": { - "total_regions": len(paddle_regions), - "by_type": type_counts(paddle_regions), - }, - "paddleocr_vl": { - "total_blocks": len(blocks), - "by_type": type_counts(blocks), - "has_reading_order": any(isinstance(b.get("reading_order"), (int, float)) for b in blocks), - }, - } - with open(stem + ".vl_vs_paddle.json", "w") as f: - json.dump(summary, f, indent=2, ensure_ascii=False) - - draw_debug(page_png, blocks, stem + ".vl_debug.png") - - print("\n" + "=" * 60) - print("COMPARISON SUMMARY") - print("=" * 60) - print(json.dumps(summary, indent=2, ensure_ascii=False)) - print("\nWrote:") - for ext in (".vl_layout.json", ".vl_raw.json", ".vl_vs_paddle.json", ".vl_debug.png"): - print(" " + stem + ext) - print("\nNext: open page_XXX_regions_debug.png (existing) next to page_XXX.vl_debug.png") - print("and eyeball whether VL's blocks track article boundaries better.") - - -if __name__ == "__main__": - try: - main() - except SystemExit: - raise - except Exception: # noqa: BLE001 - traceback.print_exc() - sys.exit("\nFailed. If the error is about the VL class name, see load_vl_model().") diff --git a/test_fpdf_real.py b/test_fpdf_real.py deleted file mode 100644 index 0a97c66..0000000 --- a/test_fpdf_real.py +++ /dev/null @@ -1,24 +0,0 @@ -import json -import glob -from fpdf import FPDF - -pdf = FPDF() -pdf.set_auto_page_break(auto=True, margin=15) - -for f in glob.glob('output/20260612_110447/articles/*/info.json'): - info = json.loads(open(f, encoding='utf-8').read()) - if not info.get('priority'): - continue - - pdf.add_page() - pdf.set_font("helvetica", "B", 16) - pdf.cell(0, 10, "Header", ln=True) - - pdf.set_font("helvetica", "B", 12) - pdf.multi_cell(0, 8, f"Headline: {info.get('headline_english', '')}") - print(f"Testing Category: {info.get('category', '')}") - pdf.multi_cell(0, 8, f"Category: {str(info.get('category', '')).upper()}") - pdf.multi_cell(0, 8, f"Why: {info.get('reasoning', '')}") - -pdf.output('test_real.pdf') -print("SUCCESS!") diff --git a/test_padding.py b/test_padding.py deleted file mode 100644 index e69de29..0000000 diff --git a/test_pdf.py b/test_pdf.py deleted file mode 100644 index 668883e..0000000 --- a/test_pdf.py +++ /dev/null @@ -1 +0,0 @@ -"from pathlib import Path\nfrom generate_pdf import generate_political_pdf\n\njob_dir = Path(r\"c:\\Users\\sunde\\proxmox\\news-scan\\output\\20260611_161537\")\n\nmock_selected = [\n {\n \"id\": \"p001_a002\",\n \"headline_english\": \"Mock Headline: Government Fails to Deliver Promises on Agriculture\",\n \"priority\": \"high\",\n \"category\": \"farmer_issues\",\n \"political_significance\": \"Shows direct failure of government to support farmers leading to massive distress.\",\n \"attack_angle\": \"The ruling party claimed they are pro-farmer, but this report proves they are letting farmers suffer without MSP.\"\n },\n {\n \"id\": \"p001_a003\",\n \"headline_english\": \"Corruption Allegations in Irrigation Project\",\n \"priority\": \"medium\",\n \"category\": \"corruption\",\n \"political_significance\": \"Highlights massive irregularities in the tender process.\",\n \"attack_angle\": \"Demand an immediate CBI probe into the 500-crore scam.\"\n }\n]\n\nprint(\"Generating mock PDF...\")\ngenerate_political_pdf(mock_selected, job_dir)\nprint(\"Done!\")\n" \ No newline at end of file