% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/vlm-extract.R
\name{extract_horizons_from_pdf}
\alias{extract_horizons_from_pdf}
\title{Extract horizons from a soil description PDF}
\usage{
extract_horizons_from_pdf(
  pedon,
  pdf_path = NULL,
  provider,
  max_retries = 3L,
  overwrite = FALSE,
  prompt_name = "extract_horizons",
  schema_name = "horizon",
  pdf_text = NULL
)
}
\arguments{
\item{pedon}{A \code{\link{PedonRecord}} to merge into. Mutated in
place AND returned invisibly.}

\item{pdf_path}{Path to the PDF file. Either \code{pdf_path} or
\code{pdf_text} must be supplied.}

\item{provider}{A chat provider from \code{\link{vlm_provider}} (or
a \code{\link{MockVLMProvider}} for testing).}

\item{max_retries}{Integer; how many times to re-prompt on
validation failure. Default 3.}

\item{overwrite}{If \code{TRUE}, lower-authority values are allowed
to clobber higher-authority ones. Default \code{FALSE}.}

\item{prompt_name}{Override the default prompt template
(\code{"extract_horizons"}).}

\item{schema_name}{Override the default schema (\code{"horizon"}).}

\item{pdf_text}{Optional alternative to \code{pdf_path}: the
already-extracted description text. Useful for smoke
tests, unit tests without \code{pdftools}, and for
already-OCR'd field-sheet text.}
}
\value{
Invisibly, the (mutated) \code{pedon}. Carries a
        \code{"vlm_extraction"} attribute with the parsed response,
        number of attempts, and number of provenance entries added.
}
\description{
Reads a PDF (typically a soil survey chapter, field-sheet scan, or
thesis appendix), prompts the configured VLM to extract horizon
attributes against \code{inst/schemas/horizon.json}, and merges
the result into \code{pedon}. Every extracted attribute is recorded
with \code{source = "extracted_vlm"} and the model's reported
confidence and verbatim source quote.
}
\details{
The PedonRecord's authority order guarantees that values already
tagged \code{"measured"} are never silently overwritten by VLM
extraction unless \code{overwrite = TRUE}.

If the PDF is long (more than ~30,000 characters), it is chunked
page-by-page and each page is sent independently. This is a
conservative-but-simple strategy; for very long surveys callers
should pre-chunk and call this function once per profile.
}
\section{Failure modes}{

\itemize{
  \item If \code{pdftools} is not installed -> error.
  \item If the PDF cannot be read -> error.
  \item If the VLM response fails JSON parse / schema validation
        after \code{max_retries + 1} attempts -> error from
        \code{validate_or_retry}.
}
}

