# 📋 Quy Trình Chuyển JSON OCR → Markdown RAW

**Cập nhật:** 2026-06-13 | **Phiên bản:** 3.0 (V6 — Y-bucket sorting)
**Script:** `scripts/json_to_markdown_v6.py`
**Áp dụng:** Tất cả văn bản Myanmar/Pāli OCR từ Cloud Vision

---

## 🔧 Vấn Đề & Giải Pháp

### ❌ V1 (script cũ — `json_to_markdown_raw.py`)
Dùng `fullTextAnnotation.text` thô từ Cloud Vision → text trả về theo thứ tự cột (column-major), không theo thứ tự đọc. Layout TOC và hội thoại nhiều cột bị **xáo trộn hoàn toàn**.

### ✅ V6 — Y-bucket Sorting

Google Cloud Vision trả về block với `normalizedVertices` (tọa độ x, y). V6 sắp xếp lại theo thứ tự đọc bằng thuật toán:

```
1. Split multi-line blocks → từng dòng riêng (estimate Y cho mỗi dòng)
2. Nhóm dòng theo int(y / Y_THRESHOLD) → các dòng cùng độ cao vào cùng bucket
3. Sort X (trái→phải) trong mỗi bucket
4. Join với spacing phù hợp (COL_GAP=4 spaces, WORD_GAP=2 spaces)
```

**Tại sao Y-bucket thay vì Y-overlap?**
Y-overlap chain: 1 block cao (multi-line) kéo dài Y range → kéo fragments bên dưới vào cùng row → lộn xộn. Y-bucket (fixed bin) ngăn chain effect này.

**Tại sao không dùng column detection?**
Layout sách Pali/Myanmar không có cột độc lập thực sự. Text chảy tự nhiên trái→phải trong mỗi dòng. Column detection tách items khỏi text của chúng → hỏng output.

---

## 📦 Script: `scripts/json_to_markdown_v6.py`

### Cách chạy:

```bash
cd /home/tuan-nguyen/.openclaw/workspace

# Cơ bản
python3 scripts/json_to_markdown_v6.py \
  "010-pali-thaykha/ocr/raw/" \
  "010-pali-thaykha/extracted/"

# Dry-run (xem preview không lưu)
python3 scripts/json_to_markdown_v6.py \
  "010-pali-thaykha/ocr/raw/" \
  "010-pali-thaykha/extracted/" \
  --dry-run

# Debug (hiện fragment/bucket count)
python3 scripts/json_to_markdown_v6.py \
  "010-pali-thaykha/ocr/raw/" \
  "010-pali-thaykha/extracted/" \
  --debug
```

---

## ⚙️ Tham Số Có Thể Tinh Chỉnh

| Tham số | Default | Mô tả |
|---------|---------|-------|
| `BUCKET_SIZE` | `0.022` | Khoảng cách Y (normalized) để coi là cùng 1 dòng. ~1 dòng Myanmar text. Tăng → gộp nhiều dòng hơn. Giảm → tách dòng chi tiết hơn |
| `COLUMN_GAP_THRESHOLD` | `0.15` | Khoảng cách X để chèn 4 spaces (cột). Dưới ngưỡng này → 2 spaces |
| `WORD_GAP_THRESHOLD` | `0.03` | Khoảng cách X để chèn 2 spaces (từ). Dưới ngưỡng này → 1 space |

---

## 📂 Cấu Trúc Thư Mục

```
010-pali-thaykha/
  ├── pdf/
  │   └── pali-thaykha.pdf
  ├── ocr/
  │   └── raw/
  │       ├── output-1-to-3.json    ← Cloud Vision output
  │       ├── output-4-to-6.json
  │       └── ...
  └── extracted/
      ├── output-1-to-3.md          ← V6 output: ## PAGE 1 → ## PAGE 3
      ├── output-4-to-6.md
      └── ...
```

---

## ⚠️ Lưu Ý

- **Lọc scanner watermark** — `Scanned with CS CamScanner` tự động bị loại bỏ
- **KHÔNG sửa nội dung** — Text được trích nguyên trạng, chỉ sắp xếp lại thứ tự
- **Không bỏ header/footer** — Để bước cleanup xử lý sau
- **Multi-line block** — Các block có `\n` được split thành dòng riêng, Y ước tính phân bổ đều
- **Y-bucket có thể lệch 1 dòng** — Với TOC, thi thoảng số trang rơi vào bucket khác tên mục. Chấp nhận được, cleanup sau

---

## 📊 So Sánh Kết Quả (Pali-Thaykha, 44 trang)

| Loại trang | V1 (cũ) | V6 (Y-bucket) |
|-----------|---------|---------------|
| Văn xuôi 1 cột | ✅ Tốt | ✅ Tốt |
| TOC (Mục lục) | ❌ Hỗn loạn | 🟡 80% tốt, còn lỗi bucket |
| Hội thoại 2 cột | ❌ Items lộn xộn | ✅ Đúng thứ tự số |
| Bài tập đánh số | ❌ Lộn xộn | ✅ ၁→၂→၃... đúng thứ tự |

---

## 🔗 Liên Kết Nội Bộ

- [[Cloud-Vision-OCR]] — Bước trước: OCR PDF → JSON
- [[../quy-trinh/04-OCR-Pipeline]] — Pipeline tổng quan
- [[../quy-trinh/03A-Hieu-Dinh-Myanmar-OCR]] — Bước sau: Cleanup headers

---

**Tags:** #quy-trinh #json #markdown #y-bucket #sorting #myanmar #pali
