A deterministic survey of a directory or a set of paths: what is there, which files a registered extractor can read, which PDFs are scans that need OCR, how big the whole thing is, and roughly what one pass would cost. It makes no model calls and needs no API key.
Usage
gr_inventory(
sources,
recursive = TRUE,
model = NULL,
ocr_min_chars = 40L,
max_pdf_pages = 3L
)Arguments
- sources
A directory, or a character vector of paths. A directory is walked; anything else is taken as given.
- recursive
Descend into subdirectories.
TRUEhere, unlikegr_read_many(), because the point of the function is to show you everything.- model
Model id used for the cost floor. Defaults to
gr_options("model").- ocr_min_chars
A PDF page with fewer than this many characters of extractable text is counted as needing OCR. Read exactly as
gr_ingest_spec()reads it, default included, so what this predicts is what ingestion will do.- max_pdf_pages
Pages sampled per PDF for the text-layer probe. The whole point is to be fast on a big folder; a scan is obvious from a few pages.
Infreads every page.
Value
An object of class gr_inventory:
filesOne row per file found, readable or not:
file(the path relative tosources, so the folder it came from survives),folder,ext,bytes,extractor(NAwhen none claims it),status,pages,ocr_pages,tokensandnote.by_statusCounts and sizes per status.
totalsFiles, readable files, bytes, known
tokens,tokens_unknown(readable files whose size cannot be counted yet), andcost_floor_usd.rootThe directory surveyed, or
NA.
status is one of "ready" (an extractor claims it and there is text),
"needs_ocr" (a PDF whose pages have no text layer), "needs_package" (an
extractor claims it, but that extractor's package is not installed, so
reading it would abort), "no_extractor",
"empty" (zero bytes, or nothing that reads as text; note says which),
or "unreadable" (it exists but could not be opened, or probing it raised
an error; note carries the reason).
No file can stop the survey. A folder is surveyed because nobody knows what
is in it yet, so a corrupt PDF, a binary file wearing a .txt extension, a
broken symlink or anything else unforeseen becomes a row saying so, not an
error. That is the same contract gr_read_many() gives a corpus run.
Details
Run it before gr_read_many() or gr_extract() on anything you have not
read before. The three things it exists to catch are the three that turn a
corpus run into a confident wrong answer: files no extractor claims (which
would otherwise be dropped without appearing anywhere), PDFs with no text
layer (which extract to nothing and then answer NOT_IN_DOCUMENT,
indistinguishable from a document that genuinely does not say), and a folder
whose contents are one level further down than you scanned.
What it does not do
It does not decide anything for you. There is no automatic routing of files
to recipes here, and that is deliberate: a router that quietly reads one
document with retrieve and another with stuff gives you a plausible
answer built on part of a file with nothing saying so, and it makes
gr_compare() meaningless because the corpus no longer had a
configuration. Group the rows yourself (split(inv$files, inv$files$folder)
is usually all it takes) and pass each group to the recipe you chose.
Tokens, and what is left unknown
tokens is counted exactly where counting is cheap: plain text, markdown,
HTML, CSV, and PDFs from the pages actually probed, scaled by page count. For
formats needing an optional package that is not installed, and for scans
whose text does not exist until OCR runs, it is NA, not a guess. Those
files are counted in totals$tokens_unknown rather than folded into the sum
as zeroes, so the total is always a floor and always says how far from
complete it is.
cost_floor_usd is a floor: what a single call per document over that much
input would cost. Every per-chunk reader costs more, most of them by a factor
of the chunk count. It is there to catch the order of magnitude (to tell
four dollars from four hundred), not to be a quote.
See also
gr_read_many(), gr_extract(), gr_extractors(),
gr_ingest_spec() for the OCR settings this predicts
Other corpus functions:
gr_calibrate(),
gr_records(),
gr_reference(),
gr_search()
Examples
d <- tempfile(); dir.create(file.path(d, "2019"), recursive = TRUE)
writeLines("The 2019 cohort had 482 participants.", file.path(d, "2019", "report.txt"))
writeLines("notes", file.path(d, "notes.doc")) # no extractor claims .doc
inv <- gr_inventory(d)
inv
#> <gr_inventory> /tmp/RtmpRyE9R0/file1dcd74c67009
#> 2 file(s), 44.0 B; 1 readable
#> 1 ready, 1 no_extractor
#> tokens: 16 cost floor: $0.01 (gpt-5.6-terra, one call per document)
#> ! 1 file(s) would be skipped: .doc (1). gr_register_extractor() adds a format.
inv$files[, c("file", "folder", "ext", "status", "tokens")]
#> file folder ext status tokens
#> 1 2019/report.txt 2019 txt ready 16
#> 2 notes.doc . doc no_extractor NA