Skip to main content
Build a research assistant that can show the passage behind a finding. Context.dev turns pages and files into Markdown; your application tracks source identity, creates chunks, retrieves evidence, and verifies the answer. Sourcely uses Context.dev for journal and PDF crawling. This recipe covers user-selected papers, including documents that need OCR.

Choose the document input

Store a source ID, title, original URL or internal document link, retrieval time, and selected page range before chunking. A file upload does not inherently contain its source URL; your application must retain that association. Parse returns Markdown and the detected file type. It does not return a citation graph or guarantee that every recovered passage includes a page number.

Parse a bounded selection

Start with a server-side key from the Quickstart. The Parse guide includes requests in every SDK. This Python worker uses the standard library to make file-size checks, raw-byte upload, and failure states explicit.
research_source.py
start and end are inclusive and start at 1. Limiting pages does not reduce the uploaded file’s byte size: the entire request must still fit within 25 MiB. Split oversized files first and record how each part maps to the original document. For a public PDF, the Markdown API can accept a pdf option with shouldParse, start, end, and ocr; follow the Markdown content controls and API reference for the request format.

Handle OCR and partial evidence

When a PDF has no usable text layer, Parse can return PDF_IMAGES_ONLY. If OCR is appropriate for your task and budget, retry with ocr=True. OCR applies to PDF pages without usable text; it is not a general interpretation of all charts, equations, or images. Standalone image uploads return image metadata rather than OCR text. Keep empty, ocr_required, and failed sources visible in the research view. Even a ready result needs inspection when a finding depends on a table, formula, or scanned passage. A nonempty Markdown response is not proof that every selected page was recovered completely.

Attach source identity to chunks

The next function splits retrieved paragraphs into bounded text chunks and preserves the requested range. It does not infer a page number from a chunk’s position.
research_chunks.py
Add your embedding model’s token limit before indexing. This small splitter may divide a long table or formula; use structure-aware splitting and inspect those cases when they matter. See website RAG for indexing and retrieval.

Verify the answer’s citations

Give the model only the selected chunks and require a source chunk ID plus a supporting excerpt for each claim. Treat document text as evidence, never as instructions that change tool access or the task.
citation_check.py
This check rejects invented IDs and excerpts; it does not establish that the excerpt logically supports the claim. Add a support review before presenting the finding. Render the original source link and excerpt so the reader can inspect them. Label a range as Pages requested: 1–5, not as the exact page of a quote. Show an exact page citation only when a separately verified page mapping supports it. Resolve relative document links against the known original URL, and enforce document access when opening internal upload links.

Try a mixed research set

Run one selectable-text PDF, one scanned PDF, and one empty or unreadable selection. Verify that failed documents remain visible, every citation resolves to retained text, and the answer acknowledges missing evidence. A model should be able to say that the available excerpts do not answer the question.

Parse documents

Review supported formats, OCR, upload limits, and SDK examples.

Live agent web tools

Add bounded source discovery and page reads.