Dev.to AI 🤖 Ai 👁 0 📖 2 min read

PDF to Markdown in Python: build a RAG-ready pipeline

Large language models read Markdown far better than raw PDF text. In this guide you convert a PDF to clean Markdown with the AnyToMarkdown API, get RAG-ready chunks with page numbers, and embed them for semantic search.

Large language models read Markdown far better than raw PDF text. In this guide you convert a PDF to clean Markdown with the AnyToMarkdown API, get RAG-ready chunks with page numbers, and embed them for semantic search.

What you need

  • Python 3.9+ and pip install requests openai numpy
  • A RapidAPI key: subscribe to the free plan on AnyToMarkdown
  • An OPENAI_API_KEY for the embedding step

1. Convert the PDF and get chunks

import requests

HOST = "anytomarkdown-pdf-to-markdown-and-document-parser-api.p.rapidapi.com"
headers = {"X-RapidAPI-Key": "YOUR_RAPIDAPI_KEY", "X-RapidAPI-Host": HOST}

with open("handbook.pdf", "rb") as f:
    r = requests.post(
        f"https://{HOST}/v1/convert",
        headers=headers,
        files={"file": f},
        params={"includeChunks": "true", "includeContent": "false", "chunkSize": 400, "chunkOverlap": 40},
        timeout=180,
    )
r.raise_for_status()
chunks = r.json()["chunks"]
print(len(chunks), "chunks")

includeContent=false skips the full Markdown because you only need the chunks. Each chunk looks like this:

{ "index": 1, "content": "...", "tokens": 392, "headings": ["Employee Handbook", "2. Benefits"], "pageStart": 2, "pageEnd": 2 }

Chunks follow the document's sections: they never start in the middle of a table, and each one carries its heading path, so a chunk about vacation days still says it belongs to Benefits.

2. Embed the chunks

from openai import OpenAI
import numpy as np

client = OpenAI()
texts = [c["content"] for c in chunks]
response = client.embeddings.create(model="text-embedding-3-small", input=texts)
vectors = np.array([item.embedding for item in response.data])

Keep headings and pageStart next to each vector. They let your answers cite a section and page.

3. Search

def search(question, top=3):
    q = np.array(client.embeddings.create(model="text-embedding-3-small", input=question).data[0].embedding)
    scores = vectors @ q / (np.linalg.norm(vectors, axis=1) * np.linalg.norm(q))
    for i in scores.argsort()[::-1][:top]:
        c = chunks[i]
        print(f"{scores[i]:.2f}  {' > '.join(c['headings'])}  (page {c['pageStart']})")
        print(c["content"][:200], "\n")

search("How many vacation days do employees get?")

Tips

  • Scanned PDF? Leave ocr on auto, or force it with ocr=force.
  • Only need some pages? Add pages=1-10.
  • The free plan accepts 10 MB and 50 pages per request; higher plans raise the limits.
  • Want to see the Markdown first? Try the free PDF to Markdown converter.
📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.