# Flow 2C: LLM Extraction & Vectorization

Diagram ini merupakan fase di mana sistem melakukan ekstraksi cerdas dan mengubah teks menjadi vektor spasial. Sorotan utama pada diagram ini adalah **The Anchor-Density Strategy (Metode C)**, sebuah teknik kueri lokal yang membombardir *dense retriever* dengan kumpulan kata benda teknis (*Lexical Anchors*) tanpa format kalimat utuh, untuk menghasilkan pencarian semantik lokal yang sangat presisi sebelum data dikirim ke LLM.

```mermaid
flowchart TD
    classDef init fill:#e3f2fd,stroke:#1565c0,stroke-width:2px;
    classDef logic fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px;
    classDef anchor fill:#ffeb3b,stroke:#e65100,stroke-width:3px,color:#212121;
    classDef ai fill:#00A4A6,stroke:#232F3E,stroke-width:2px,color:#FFFFFF;
    classDef error fill:#ffebee,stroke:#c62828,stroke-width:2px;

    Start(["Purified Parent &amp; Child Chunks"]):::init --> LocalRetrieval
    
    %% The Anchor-Density Strategy (Metode C) - Highlighted
    subgraph MethodC ["🌟 The Anchor-Density Strategy (Local Semantic Search)"]
        direction TB
        Queries["5 Kueri Pilar (Lexical Anchors)<br/>e.g. 'latar belakang masalah, urgensi...'"]:::anchor
        InjectPrefix["Injeksi Prefix 'query: '"]:::anchor
        E5Small["Local Model: E5-Small (384D)"]:::logic
        FindTopK["Cosine Similarity: Top 3 Child Chunks"]:::logic
        
        Queries --> InjectPrefix --> E5Small --> FindTopK
    end
    
    LocalRetrieval[("Kirim Child Chunks<br/>(Prefix 'passage: ')")]:::logic --> FindTopK
    
    FindTopK --> Deduplicate["Deduplikasi: Ambil Unique<br/>Parent IDs"]:::logic
    Deduplicate --> StuffedContext["Gabungkan Teks Parent Chunks<br/>(Stuffed Context)"]:::logic
    
    %% Injeksi Metadata
    StuffedContext --> InjectMeta["Injeksi 1500 Char Pertama<br/>(Menjaga Konteks Judul &amp; Penulis)"]:::logic
    InjectMeta --> SendLLM
    
    %% LLM Extraction & Pydantic Validation
    subgraph LLMExtract ["🧠 DashScope (Qwen) Extraction"]
        direction TB
        SendLLM["Prompt: Ekstrak 5 Pilar Akademik"]:::ai
        Sweeper["The Sweeper (Lapis 1)<br/>Hapus Markdown Fences / Basa-basi"]:::logic
        Pydantic["The Pydantic Armor (Lapis 3)<br/>Sanitasi Halusinasi ('tidak ada', 'none')"]:::logic
        
        SendLLM --> Sweeper --> Pydantic
    end
    
    Pydantic --> CheckLLM{"Pilar Valid &amp;<br/>Tidak Kosong?"}:::logic
    CheckLLM -- "Tidak" --> Abort(["Abort (Failed)"]):::error
    CheckLLM -- "Ya" --> EmbedVectors
    
    %% Vectorization (OpenAI)
    subgraph Vectorization ["📐 OpenAI Embedding"]
        direction TB
        EmbedVectors["OpenAI text-embedding-3-small<br/>(1536D)"]:::ai
        ValidateVector{"Vector Valid?<br/>(Finite &amp; Norm > 0)"}:::logic
        
        EmbedVectors --> ValidateVector
    end
    
    ValidateVector -- "Tidak" --> SkipVector["Skip Vector"]:::error
    ValidateVector -- "Ya" --> End(["Lanjut ke Flow 2D: Neo4j Storage"]):::init
    SkipVector --> End
```

### Penjelasan Detail (Fokus pada Anchor-Density):
1. **The Anchor-Density Strategy (Metode C):** Ini adalah kunci akurasi *retrieval* lokal. Alih-alih bertanya ke model E5-Small dengan kalimat utuh (seperti "Apa tujuan penelitian ini?"), sistem menggunakan *Lexical Anchors* padat (contoh: "tujuan utama penelitian, sasaran spesifik, kontribusi inti makalah..."). Kueri ini juga diinjeksi dengan awalan `query: ` (sementara *child chunks* diberi awalan `passage: `) agar pencarian di ruang vektor 384D jauh lebih terpusat dan kebal terhadap gaya bahasa jurnal yang tidak beraturan.
2. **Deduplication & Stuffed Context:** Hasil pencarian vektor lokal (Top-3 *Child Chunks* per pilar) tidak langsung dikirim ke LLM. Sistem mengambil `parent_id` unik dari *child chunks* tersebut, lalu memanggil teks utuh dari *Parent Chunks* (1500 karakter). Teks ini digabungkan, disuntik dengan 1500 karakter pertama dari dokumen mentah (untuk menjaga konteks judul/abstrak), membentuk satu *Stuffed Context* kaya raya.
3. **Pydantic Validation & Fallback:** Respons JSON dari LLM (Alibaba DashScope) dibersihkan dari *markdown fences* (```json ... ```) oleh *The Sweeper*. Setelah itu, *The Pydantic Armor* mengintervensi dengan membuang frasa halusinasi kosong seperti "informasi tidak tersedia" atau "none", mengubahnya menjadi *string* kosong yang aman untuk database.
4. **Vectorization:** Kelima pilar yang berhasil diekstrak dan disanitasi dikirim ke OpenAI (`text-embedding-3-small`) untuk diubah menjadi array vektor berdimensi 1536 yang siap masuk ke Neo4j. Jika ada vektor yang korup (norm 0 atau *infinite*), sistem akan mengabaikan vektor tersebut tanpa membatalkan pembuatan *node*.
