# Rencana Integrasi Hybrid Chunking & Supabase

## 1. Judul
Rencana Arsitektur dan Integrasi Hybrid Chunking (Pendekatan V1 yang Ditingkatkan) & Penyimpanan Supabase.

## 2. Tanggal
02 Mei 2026

## 3. Deskripsi
Dokumen ini merupakan panduan implementasi komprehensif untuk mengintegrasikan logika pemotongan teks (chunking) ke dalam `orchestrator_ingest.py`. Bertujuan untuk mengefisiensikan biaya token ekstraksi LLM melalui filter heuristik dan menyediakan data teks terpotong rapi yang akan dikirim secara asynchronous ke Supabase sebagai bahan baku sistem _retrieval_ chatbot.

## 4. Metodologi
*   **Asynchronous Queuing**: Pemisahan tugas jaringan (Supabase) dari utas utama (*Main Thread*) untuk mempertahankan standar performa *sub-5-second*.
*   **Dual-Idempotency Check**: Validasi status berkas secara terpisah terhadap Neo4j dan Supabase untuk menghindari korupsi atau ketimpangan data.
*   **Heuristic Filtering**: Pendekatan penyaringan teks berbiaya rendah (tanpa LLM) berdasarkan deteksi metadata *heading* (bilingual).
*   **Drop-in Replacement**: Mengganti _custom loop_ V1 lama dengan pustaka standar `langchain-text-splitters`.

## 5. Keputusan
*   **Chunking Engine**: Menggunakan kombinasi `MarkdownHeaderTextSplitter` dan `RecursiveCharacterTextSplitter` dari LangChain. (Ukuran chunk: 1500, Overlap: 150).
*   **Efisiensi Token**: Mengadopsi Opsi 1 (Heuristic Filtering) sebelum mengirim teks ke LLM Gemini.
*   **Safety Net**: Membatasi teks yang sudah di-filter maksimal 25.000 karakter untuk mencegah *context length error*.
*   **Penyimpanan**: Chunk mentah disimpan ke Supabase **tanpa** embedding vektor baru (menggunakan 1 _Dedicated Background Worker_).

## 6. Alur Diagram

```mermaid
flowchart TD
    A[Mulai: PDF Ditemukan] --> B{Dual Idempotency Check}
    B -- "Ada di Neo4j & Supabase" --> C[Skip PDF]
    B -- "Belum/Pincang" --> D[HybridParser]
    
    D --> E[Parse to Markdown]
    E --> F[MarkdownHeaderTextSplitter\nMetadata Tagger]
    F --> G[RecursiveCharacterTextSplitter\n1500 chars / 150 overlap]
    
    G --> H{Heuristic Filter\nIrrelevant Headers?}
    
    %% Alur LLM & Neo4j
    H -- "Relevan (Metode, Hasil, dll)" --> I[Gabungkan Teks & Safety Net max 25k]
    I --> J[Gemini LLM: Ekstrak 5 Pilar]
    J --> K[Gemini LLM: Embed 5 Pilar]
    K --> L[(Neo4j: Node & Vector)]
    
    %% Alur Supabase
    H -- "Semua Chunk (Termasuk References)" --> M[Supabase Queue]
    M --> N[Worker Thread: supabase_uploader]
    N --> O[(Supabase: Raw Text Chunks)]
    
    L -.-> P[Queue: Edge Generator]
    P -.-> Q[Worker Thread: Neo4j Edge]
```

## 7. Struktur Folder (Tree)
```text
poc-task2-neo4j-vector-(Chunking)/
├── orchestrator_ingest.py        (Main Script - Diperbarui)
├── core/
│   ├── parser/
│   │   ├── hybrid_parser.py      (Eksisting - Tidak Diubah)
│   │   └── smart_chunker.py      (BARU: Wrapper untuk Splitters LangChain)
│   └── storage/
│       └── supabase_client.py    (BARU: Klien Supabase & Worker Queue)
└── .env                          (Diperbarui dengan SUPABASE_URL & SUPABASE_KEY)
```

## 8. Asumsi
1. Akun Supabase sudah dibuat dan memiliki tabel `document_chunks` dengan skema minimal: `id`, `file_hash`, `title`, `chunk_index`, `metadata_header`, `content`.
2. Kredensial `SUPABASE_URL` dan `SUPABASE_KEY` akan ditambahkan di `.env` pengguna.
3. Paket `langchain-text-splitters` dan `supabase` akan diinstal di _environment_ Python.

## 9. Konsep Tabel Metriks
Untuk mengevaluasi keberhasilan integrasi ini, metrik berikut akan dipantau:

| Metrik | Target Pasca-Integrasi | Metode Pengukuran |
| :--- | :--- | :--- |
| **Kecepatan Main Thread** | < 5 Detik per Dokumen | Waktu eksekusi sebelum dokumen masuk ke Queue |
| **Efisiensi Token LLM** | Pengurangan token _input_ > 30% | Menghitung total karakter yang dikirim per PDF |
| **Idempotensi Sinkronisasi**| 100% (Tidak ada ketimpangan) | Membandingkan jumlah dokumen di Neo4j vs file_hash di Supabase |

## 10. Konsep Logika Prompting (Filtering)
Kamus *Blacklist* yang akan dipakai oleh fungsi penyaring:
```python
IRRELEVANT_HEADERS = [
    "reference", "references", "bibliography", "daftar pustaka", "referensi",
    "acknowledgement", "acknowledgements", "ucapan terima kasih", 
    "appendix", "appendices", "lampiran", "table of contents", "daftar isi"
]
```
Logika: *Jika metadata header terdeteksi mengandung salah satu _string_ di atas (case-insensitive), maka chunk tersebut tidak akan ikut dirangkai dan tidak dikirim ke LLM.*

## 11. Langkah Implementasi
1. **Persiapan Dependencies**: Menginstal `langchain-text-splitters` dan modul `supabase`.
2. **Pembuatan Modul Chunker**: Membuat `core/parser/smart_chunker.py` yang membungkus dua mekanisme splitter.
3. **Pembuatan Modul Supabase**: Membuat `core/storage/supabase_client.py` yang berisi koneksi SDK dan fungsi Worker Thread (seperti `worker_edge_generator`).
4. **Modifikasi Orchestrator**: 
   - Memperbarui `check_node_exists` menjadi Dual-Check.
   - Menyisipkan langkah pemotongan dan _Heuristic Filtering_ ke dalam `process_sync_pdf`.
   - Mengalihkan teks bersih ke pemanggilan LLM.
   - Menambahkan mekanisme _push_ ke antrean Supabase.

## 12. Tabel Eksekusi Task

| Check | Fase | Task | Detail Task | Deskripsi | Acceptance Criteria |
| :---: | :--- | :--- | :--- | :--- | :--- |
| [x] | **Setup** | Install Libs | Install `langchain-text-splitters`, `supabase` | Menambahkan library baru ke environment untuk mendukung skrip | Library terinstal tanpa _conflict_ dependencies |
| [x] | **Storage** | Buat `supabase_client.py` | Implementasi `init_supabase()`, `check_supabase_hash()`, `worker_supabase_uploader()` | Modul khusus untuk mengurus konektivitas dan _background pushing_ ke Supabase | Skrip bisa push data secara *async* menggunakan antrean *Queue* khusus Supabase |
| [x] | **Parser** | Buat `smart_chunker.py` | Implementasi `generate_chunks()` dengan Markdown & Recursive Splitters | Memindahkan filosofi V1 ke dalam library standar LangChain | Fungsi mereturn list of objects berisi teks dan metadata *heading* jurnal |
| [x] | **Core** | Modifikasi Idempotensi | Ubah `check_node_exists` | Menambahkan pengecekan *Dual Idempotency* (Neo4j dan Supabase) | Skrip bisa meneruskan proses ke Supabase jika data di Neo4j ada tapi di Supabase hilang |
| [x] | **Core** | Implementasi Filtering | Tambahkan logika *Heuristic Filtering* di `process_sync_pdf` | Memfilter chunk berdasarkan `IRRELEVANT_HEADERS` sebelum masuk ke LLM | Teks yang dikirim ke LLM terbebas dari *Daftar Pustaka*, max 25.000 karakter |
| [x] | **Core** | Integrasi Alur Utama | Panggil fungsi Chunker & Supabase Worker di Main Execution | Menyambungkan semua komponen baru ke dalam `orchestrator_ingest.py` | Seluruh *pipeline* berjalan tanpa _error_, performa *Main Thread* tetap *sub-5-second* |
| [x] | **Test** | End-to-End Test | Uji coba satu file PDF | Menjalankan *script* untuk melihat efisiensi token dan masuknya data | Log terminal menunjukkan *chunk* diproses, LLM berhasil ekstrak, data masuk Neo4j & Supabase |
