Asosiy qismga o'tish

OCR → RAG Integratsiyasi

8-bob 5 kod bloki 690 so'z

OCR ning pipeline dagi o'rni

RAG qo'llanmasi 5-bobidagi ingestion pipeline ni eslang: scraping → extraction → chunking → embedding → pgvector. OCR bu zanjirga extraction bosqichida ulanadi:

python11 qator
Hujjat manbalari
  |
  +-- web sahifa  -------> BeautifulSoup extractor --+
  |                                                  |
  +-- digital PDF -------> pdfplumber ---------------+--> TOZALASH --> chunking
  |                                                  |    (shu bob)     |
  +-- skanerlangan PDF --> OCR pipeline (7-bob) -----+                  v
  |                                                  |               embedding
  +-- rasm (jpg/png) ----> OCR to'g'ridan-to'g'ri ---+                  |
                                                                        v
                                                                    pgvector

Lekin OCR matni to'g'ridan-to'g'ri chunking ga yuborilmaydi — avval tozalash kerak. Nega?

OCR matni nega "iflos"

Tesseract har vizual qatorni \n bilan tugatadi. Qog'ozda 60-belgilik qatorlar — demak har gap 2-3 bo'lakka bo'linadi:

matn5 qator
OCR chiqishi:                      Bo'lishi kerak edi:

Shartnoma tomonlari o'z zimma-     Shartnoma tomonlari o'z 
siga olgan majburiyatlarni to'-    zimmasiga olgan majburiyatlarni
liq bajarishga kafolat beradi.     to'liq bajarishga kafolat beradi.

RAG qo'llanmasi 4-bobini eslang: paragraph-based chunking paragraf chegaralariga (\n\n) tayanadi. OCR matni esa har 60 belgida \n — chunker "har qator alohida paragraf" deb o'ylaydi va chunk lar mayda-mayda bo'lib ketadi. Embedding sifati ham tushadi: "zimma-" va "siga" alohida so'zlar emas.

Tozalash funksiyasi

To'rt eng muhim tuzatish:

python17 qator
import re

def clean_ocr_text(text):
    # 1. Bo'g'in ko'chirish: "zimma-\nsiga" -> "zimmasiga"
    text = re.sub(r"([\w'])-\n(\w)", r"\1\2", text)

    # 2. Sun'iy qator uzilishi: bitta \n -> bo'shliq
    #    (\n\n paragraf chegarasi sifatida SAQLANADI)
    text = re.sub(r"(?<!\n)\n(?!\n)", " ", text)

    # 3. Ortiqcha bo'shliqlar
    text = re.sub(r"[ \t]{2,}", " ", text)

    # 4. Yolg'iz sahifa raqamlari va kolontitullar
    text = re.sub(r"^\s*-?\s*\d+\s*-?\s*$", "", text, flags=re.MULTILINE)

    return text.strip()

2-qadam eng nozigi: (?<!\n)\n(?!\n) — "oldida ham, orqasida ham \n bo'lmagan \n". Ya'ni yolg'iz qator uzilishi bo'shliqqa aylanadi, \n\n (haqiqiy paragraf) esa tegilmaydi.

Yana bir tez-tez uchraydigan muammo — har sahifada takrorlanadigan kolontitul ("«Nihol» MChJ — Ichki hujjat — Maxfiy"). U har chunk ga kirib, qidiruv natijalarini ifloslaydi. Yechim: sahifalar orasida takrorlangan qatorlarni topib olib tashlash (10-bobdagi kodda bor).

Metadata enrichment

RAG qo'llanmasi 4-bobidagi metadata g'oyasini OCR ma'lumoti bilan boyitamiz:

python7 qator
chunk_metadata = {
    "source_file": "shartnoma_2024.pdf",
    "page": 3,
    "extraction_method": "ocr_tesseract",   # "text_layer" | "ocr_tesseract" | "ocr_vlm"
    "ocr_confidence": 84.2,                  # VLM uchun -1 (confidence bermaydi)
    "language": "rus",
}

Bu metadata uch joyda asqotadi:

  1. Error analysis (RAG guide, 15-bob): foydalanuvchi "javob noto'g'ri" desa — extraction_method va ocr_confidence ga qarang. Ko'pincha muammo retrieval da emas, manba matnning o'zida.
  2. Filtering: "faqat ishonchli manbalardan javob ber" — ocr_confidence > 70 sharti bilan SQL darajasida filtrlash.
  3. Citation: javob manbasini ko'rsatganda "skanerlangan hujjatdan olindi, xato bo'lishi mumkin" ogohlantirishi.

Quality gate — sifat darvozasi

Production tizimda past sifatli OCR ni jimgina bazaga qo'shib yubormaslik kerak. RAGAS (RAG guide, 10-bob) faqat retrieval/generation ni baholaydi — u manba matni buzuqligini ko'rmaydi. Darvoza shunday:

python12 qator
def quality_gate(page_result):
    if page_result.method == "text_layer":
        return "accept"                      # digital matn — ishonchli

    if page_result.method == "ocr_vlm":
        return "accept_with_flag"            # confidence yo'q — belgilab qo'yamiz (6-bob: xatosi ko'rinmaydi)

    if page_result.confidence >= 80:
        return "accept"
    if page_result.confidence >= 60:
        return "accept_with_flag"            # metadata da belgi, keyin tekshiriladi
    return "manual_review"                   # bazaga kirmasin, admin ko'rsin

Admin panelda "manual review" ro'yxati bo'ladi: past confidence li sahifalar odamga ko'rsatiladi. Odam yo qo'lda tuzatadi, yo qayta skanerlashni so'raydi, yo VLM natijasini tasdiqlaydi. Buzuq matn bazaga kirsa, uni topish juda qiyin — darvozada ushlash arzonroq. VLM o'qigan sahifalar ham har doim belgilanadi: ularda confidence yo'q, xatosi esa ko'rinmaydi (6-bob) — yuridik va moliyaviy hujjatlarda ularni odam ko'rib chiqadi.

Xulosa

Tushuncha Asosiy fikr
O'rin OCR = extraction bosqichi; undan keyin har doim tozalash
Tozalash Bo'g'in ko'chirish + yolg'iz \n — busiz chunking buziladi
Kolontitul Takrorlangan qatorlarni olib tashlang — chunk larni ifloslaydi
Metadata extraction_method + ocr_confidence — error analysis va filtering uchun
Quality gate conf < 60 bazaga kirmasin — darvozada ushlash keyin qidirishdan arzon

Bu bobni bepul o'qidingiz.

Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.

Telegramda yozish Narxlar