Парсинг PDF для RAG: GPT-4o + embeddings
Превращаем сложные PDF (слайды, отчёты) в retrieval-ready контент: двойной парсинг текстом (pdfminer) и изображениями (GPT-4o vision), чанкинг по страницам, эмбеддинги text-embedding-3-small, cosine similarity для поиска.
Проблема сложных PDF
Обычные PDF-парсеры теряют таблицы, диаграммы и форматирование слайдов. OpenAI Cookbook решает это двумя параллельными методами:
- pdfminer — извлекает чистый текст (быстро, без GPU)
- GPT-4o vision — анализирует страницы как изображения, описывает диаграммы и схемы
Конвертация PDF в изображения
from pdf2image import convert_from_path
from pdfminer.high_level import extract_text
import base64, io
from openai import OpenAI
client = OpenAI()
def convert_doc_to_images(path):
return convert_from_path(path)
def get_img_uri(img):
buf = io.BytesIO()
img.save(buf, format="PNG")
b64 = base64.b64encode(buf.getvalue()).decode("utf-8")
return f"data:image/png;base64,{b64}"
Анализ страницы через GPT-4o
def analyze_image(img_uri: str) -> str:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "Describe this slide in detail."},
{"type": "image_url", "image_url": {"url": img_uri}},
],
}],
max_tokens=500,
)
return response.choices[0].message.content
Эмбеддинги и поиск
import pandas as pd
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
def get_embeddings(text: str) -> list[float]:
return client.embeddings.create(
model="text-embedding-3-small",
input=text,
encoding_format="float",
).data[0].embedding
df = pd.DataFrame(clean_content, columns=["content"])
df["embeddings"] = df["content"].apply(get_embeddings)
def search(query: str, df: pd.DataFrame, top_n: int = 3):
q_emb = np.array(get_embeddings(query)).reshape(1, -1)
doc_embs = np.vstack(df["embeddings"].values)
scores = cosine_similarity(q_emb, doc_embs)[0]
idx = scores.argsort()[::-1][:top_n]
return df.iloc[idx]["content"].tolist()
Параллельная обработка страниц через concurrent.futures.ThreadPoolExecutor(max_workers=8) сокращает время в 8 раз.
Возьмите любой PDF (технический отчёт, слайдек). Реализуйте двойной парсинг: pdfminer для текста + GPT-4o для первых 3 страниц. Создайте DataFrame с эмбеддингами и сделайте 3 поисковых запроса. Сравните качество результатов при поиске только по тексту vs только по GPT-4o-описаниям.
Скопируйте и адаптируйте под свой контекст. Текст в треугольных скобках — то, что нужно заменить.
from pdf2image import convert_from_path
from pdfminer.high_level import extract_text
import base64, io, os
from openai import OpenAI
import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
client = OpenAI()
def get_img_uri(img):
buf = io.BytesIO()
img.save(buf, format="PNG")
return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode()
def analyze_page(img):
uri = get_img_uri(img)
r = client.chat.completions.create(
model="gpt-4o",
messages=[{"role":"user","content":[
{"type":"text","text":"Describe this page in detail for a knowledge base."},
{"type":"image_url","image_url":{"url":uri}}
]}],
max_tokens=400,
)
return r.choices[0].message.contentПропускать первый слайд/страницу — он обычно содержит только заголовок и не несёт информации. Не объединять текстовый и vision-контент перед созданием эмбеддингов — теряется полнота. Использовать одну большую страницу как чанк без очистки переносов строк.
Добавляйте заголовок слайда и название документа в начало каждого чанка — это улучшает cosine similarity при поиске. Сохраняйте эмбеддинги в CSV/векторную БД, не пересчитывайте каждый раз.
Корпоративные базы знаний на основе PDF-документов, слайдов, отчётов с таблицами и диаграммами, которые плохо парсятся текстовыми инструментами.
Простые текстовые PDF без визуальных элементов — pdfminer справится без GPT-4o и будет значительно дешевле. Живые веб-страницы — используйте scraping.