weji-gannet
Extract, index, and search any collection of PDF documents.
weji-gannet turns a collection of PDFs into a properly structured, queryable database — the same way a gannet dives into the ocean and surfaces with exactly what it went in for.
Point it at any PDF collection — scanned documents, government disclosures, research papers, contracts, archives — and get clean text extraction with full-text search and optional columnar analytics via weji-goose.
Built by WEJI Northern Technologies Inc. — 100% Indigenous-owned, Qalipu Mi'kmaq First Nation, Bay St. George, NL.
How it works
Your PDFs → per-page extraction cascade → SQLite FTS5 (full-text search)
→ weji-goose (analytics, optional)
Each page is processed independently through three passes in order:
- pdftotext — fast, lossless for digitally-generated PDFs
- tesseract 250 DPI / PSM 6 — OCR for scanned pages
- tesseract 300 DPI / PSM 3 — higher-res OCR for complex layouts
A hybrid PDF (typed cover page + scanned attachments) gets complete, correctly ordered text from both sections with no duplication.
Install
pip install weji-gannet
# System dependencies:
sudo apt install poppler-utils tesseract-ocr tesseract-ocr-eng # Ubuntu/Debian
brew install poppler tesseract # macOS
With weji-goose columnar analytics (optional):
pip install "weji-gannet[goose]"
Quick start — Python
from weji_gannet import Pipeline
from weji_gannet.sources import LocalDirectorySource
p = Pipeline("./output")
p.ingest(LocalDirectorySource("./my_pdfs"))
# Full-text search
results = p.query("search terms here")
for r in results:
print(r["doc_id"], r["excerpt"])
# Keyword intelligence — define your own categories
report = p.intelligence(targets={
"contracts": ["procurement", "tender", "awarded", "vendor"],
"environmental": ["contamination", "remediation", "PFAS"],
"complaints": ["violation", "enforcement", "cease and desist"],
})
print(p.stats())
Quick start — CLI
# Index a directory of PDFs
gannet --data-dir ./output ingest ./my_pdfs
# Search
gannet --data-dir ./output query "search terms"
# Intelligence report (define your targets in a JSON file)
echo '{"contracts": ["procurement", "tender"]}' > targets.json
gannet --data-dir ./output intel --targets targets.json
# Stats
gannet --data-dir ./output stats
Extending to any PDF source
Implement DocumentSource to pull PDFs from anywhere — a web portal, an S3
bucket, a database of URLs, an API:
from weji_gannet.sources import Document, DocumentSource
from pathlib import Path
class MySource(DocumentSource):
def documents(self):
for row in my_db.query("SELECT id, title, dept FROM docs"):
yield Document(
id=str(row.id),
title=row.title,
source=row.dept,
)
def download(self, doc, dest_dir):
pdf_bytes = my_api.fetch(doc.id)
dest = dest_dir / f"{doc.id}.pdf"
dest.write_bytes(pdf_bytes)
return dest
p = Pipeline("./output")
p.ingest(MySource())
Output structure
output/
├── documents.db — SQLite FTS5 (full-text search index)
├── goose/
│ └── documents/ — weji-goose columnar store (analytics, if installed)
├── files/ — downloaded PDFs
├── report.txt — intelligence query results (human-readable)
└── report.json — intelligence query results (structured)
documents table schema
| Column | Description |
|---|---|
doc_id |
unique document identifier |
source |
originating collection or organisation |
title |
short label / document summary |
body |
extracted full text (all pages, joined by \f) |
year / month |
document date |
file_path |
local PDF path |
source_url |
original URL |
page_count |
total pages |
ocr_method |
how text was extracted (pdftotext, tesseract, hybrid:dN/oM/bK, exhausted) |
Part of the WEJI stack
| Package | Role |
|---|---|
| weji-goose | Columnar storage engine — analytics layer |
| weji-gannet | PDF extraction and indexing pipeline |
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file weji_gannet-0.1.0.tar.gz.
File metadata
- Download URL: weji_gannet-0.1.0.tar.gz
- Upload date:
- Size: 19.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2abf9f2bcb322252f127fecb8afcd8fcc083d205339bc6b8953a8871b6fccfe6
|
|
| MD5 |
c10964301c7097355132b12d08b1f7bc
|
|
| BLAKE2b-256 |
49e16cbfa14b43b7054b2bf2fd4df78fcaf796826c221f1c1392579a433ebddb
|
File details
Details for the file weji_gannet-0.1.0-py3-none-any.whl.
File metadata
- Download URL: weji_gannet-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
65edc0b0968c246c9551830ebd8eabc995004de448a5c5fd30bf5fb10a7a8ad1
|
|
| MD5 |
5115070fdf732c0bd3cebfc70324be1b
|
|
| BLAKE2b-256 |
f38a07b5ce16f02adde7119f63ff3ae7ef455f504e297e82ae5a53b98156db0d
|