davanstrien/historical-illustration-search

Space

Historical Illustration Search

27

stars

22

commits

Sep 15, 2026

updated

gradio

README

Historical Illustration Search

Search 1,492,199 public-domain images from the British Library and Encyclopaedia Britannica. Search by description, refine with example images, and download original illustrations or clean cutouts.

Search and download

  1. Describe an illustration, or try an example below the search box.
  2. Choose both collections or narrow to British Library / Encyclopaedia Britannica. Open a result to inspect it and its source details.
  3. Choose Download illustration. British Library images come directly from the public bucket. Britannica downloads are full-resolution rectangular crops of the original JP2 scan, with a 2% margin. Choose Download clean cutout for a transparent Britannica PNG, using its existing predicted mask with 2% dilation to preserve engraving edges. Supported BL images also offer clean cutouts (white background).

Britannica previews use 2000px JPEG page mirrors for speed; downloads and the large viewer use the original JP2. The original page link opens the corresponding Internet Archive scan. “Scan leaf” is its archive image position, not a printed page number. Some records have no recorded edition or year. Source details can be copied with the image's stable identifier.

Images are served from public buckets. Large originals are decoded on demand; the first crop can take a few seconds. Britannica page and crop caches are bounded to 768 MiB combined; BL cutouts have a separate 256 MiB cache and at most two concurrent decodes. If a source changes from its verified identity, the app reports it unavailable instead of silently cropping a different scan.

Space setup

Before merging/deploying, open Settings → Variables and secrets:

KindNameValue
SecretHF_TOKENYour Hugging Face token with read access to the private artifact repository davanstrien/bl-images-lance-dev
VariableSEARCH_BACKENDlance

Keep the token in Secrets, never in source files or a public variable. It is used server-side to download pinned index and mask artifacts. Visitors do not need to sign in. The source image buckets and source datasets are public.

The code defaults to the tested LANCE_NPROBES=64 and LANCE_REFINE_FACTOR=20. To match the dev CPU configuration, also set RAYON_NUM_THREADS=2 and OPENBLAS_NUM_THREADS=2 as variables. No LANCE_REPO, LANCE_REVISION or LANCE_RUN variables are needed when the committed serving.json is present.

The app downloads its index, masks and display metadata to local disk at startup, then reuses them for requests. display_assets.json pins the atlas and original-page catalogue in the same private artifact repository; those binary files are not bundled in this public repository. Original page images are fetched on demand. The tested CPU Basic dev startup took about 50 seconds with roughly 6–7 GB peak RSS; cold downloads and shared-host conditions can vary.

After deployment, check both collections, full-resolution JPEG and clean PNG downloads in a signed-out browser, and the Explore map. To roll back this release, restore production revision 4536eb0a3b8f870138c196887612d5de666448b9 and remove SEARCH_BACKEND (or set it to numpy); retain a copy of the release revision for inspection.

Browse by publication date

Browse traverses the complete collection without a text query. Choose oldest or newest first, a collection/image type, or a year range, then choose Browse to apply. Undated images appear last when included; an explicit year range excludes them. Dates describe the source publication, not when the image was digitised.

More images load automatically near the bottom, with a Load more button also available. Opening an image preserves your browsing position. Off-screen pages release their image cards and metadata; scrolling back reloads the same page. Find similar starts a fresh image search across both collections. Search and Explore remain separate views, and the atlas is still the British Library sample.

GET /browse accepts dataset, image_type, order (oldest/newest), year_from, year_to, include_undated, limit (1–96; default 48) and an opaque cursor. It returns results, total, offset, next_cursor and revision. Cursors are tied to the filters, page size and pinned metadata revision; restart browsing if any change. This endpoint uses the existing metadata and precomputed date/row-ID ordering, with a bounded filtered-order cache. It does not query vectors or load original images.

Search index and reproducibility

The two collections use the same pinned google/siglip2-so400m-patch16-256 model (e8708ab72d125807e45b36fb7d4e0aacbb59f379). No new inference was needed for this integration.

serving.json is the authoritative, immutable Lance artifact pin, deployed atomically with the app. With no file present, the original LANCE_REPO, LANCE_REVISION, and LANCE_RUN environment variables are used for rollback. Keep SEARCH_BACKEND=lance; NumPy is the legacy BL-only path.

build_combined.py imports original BL vectors plus completed Britannica embedding shards, validates every source ID/geometry/metadata record and finite unit vector, and verifies every float and ID after Lance ingestion. It builds IVF-RQ with 256 partitions; serving uses 64 minimum probes and 20× refinement. The full metadata/index snapshot is downloaded locally at startup; original page images remain in the buckets.

prepare_cutouts.py joins existing masks to all 411,385 indexed Britannica illustrations by stable ID, validates source/model/geometry and builds a compressed SQLite lookup with 411,383 usable masks (578 MB); two empty predictions retain rectangular downloads only. cutouts.json pins that artifact independently of Lance; no embeddings or inference are repeated. Masks stay on disk. PNGs and rectangular JPEGs share the bounded image cache. These are model predictions, so retain the original crop option for imperfect masks.

prepare_originals.py verifies all 92,196 Britannica original-page paths and records their Xet object hashes in originals.parquet. Native downloads verify those identities; JPEG previews verify the SHA-256 saved by the embedding run. The independent full-vector check and six image-query recall checks are recorded in the artifact's manifest.json; these mechanical checks are not a general relevance evaluation.

The combined source contains 1,080,814 BL images and 411,385 Britannica figure crops. Britannica crop metadata is pinned to dataset revision d14ad4cf2717f97b63c668c3d6a83e6257791e33, score ≥0.30. No image files are duplicated into the index.

API and map

search_collections accepts query, image type, year bounds, result count, positive/negative row IDs, text weight and dataset (all, bl, britannica). Previous search, search_reference and search_feedback positional APIs remain available. Row IDs are temporary index references; use asset_id for durable records. Each result carries bucket_path (the source object in the public bucket); it is not named path because gradio_client treats any path key as a file to download and fails with 403. Near-identical results (the same engraving reprinted across editions, cosine ≥ 0.95) are collapsed, so a page can return fewer than k rows.

The existing Explore map remains an explicitly labelled 6,000-image British Library sample. Its original UMAP coordinates and BL row IDs are preserved. Find similar searches the full index using the selected collection filter. Lasso selections are temporary; ZIP export, saved collections and annotation submission are not implemented.

Development checks

For the full pinned CPU runtime, use Linux and Python 3.12.

uv venv --python 3.12
uv pip install -r requirements.txt pytest psutil
PYTHONPATH=. uv run --no-project pytest tests/test_combined.py tests/test_cutouts.py tests/test_search_backend.py tests/test_bl_cache.py tests/test_display_assets.py
node tests/atlas-geometry.cjs

Sources: British Library dataset, Britannica dataset, Britannica page store.

Contributors

davanstrien

21 commits

CF

davanstrien/historical-illustration-search

Space

Historical Illustration Search

27

stars

22

commits

Sep 15, 2026

updated

gradio

README

Historical Illustration Search

Search 1,492,199 public-domain images from the British Library and Encyclopaedia Britannica. Search by description, refine with example images, and download original illustrations or clean cutouts.

Search and download

  1. Describe an illustration, or try an example below the search box.
  2. Choose both collections or narrow to British Library / Encyclopaedia Britannica. Open a result to inspect it and its source details.
  3. Choose Download illustration. British Library images come directly from the public bucket. Britannica downloads are full-resolution rectangular crops of the original JP2 scan, with a 2% margin. Choose Download clean cutout for a transparent Britannica PNG, using its existing predicted mask with 2% dilation to preserve engraving edges. Supported BL images also offer clean cutouts (white background).

Britannica previews use 2000px JPEG page mirrors for speed; downloads and the large viewer use the original JP2. The original page link opens the corresponding Internet Archive scan. “Scan leaf” is its archive image position, not a printed page number. Some records have no recorded edition or year. Source details can be copied with the image's stable identifier.

Images are served from public buckets. Large originals are decoded on demand; the first crop can take a few seconds. Britannica page and crop caches are bounded to 768 MiB combined; BL cutouts have a separate 256 MiB cache and at most two concurrent decodes. If a source changes from its verified identity, the app reports it unavailable instead of silently cropping a different scan.

Space setup

Before merging/deploying, open Settings → Variables and secrets:

KindNameValue
SecretHF_TOKENYour Hugging Face token with read access to the private artifact repository davanstrien/bl-images-lance-dev
VariableSEARCH_BACKENDlance

Keep the token in Secrets, never in source files or a public variable. It is used server-side to download pinned index and mask artifacts. Visitors do not need to sign in. The source image buckets and source datasets are public.

The code defaults to the tested LANCE_NPROBES=64 and LANCE_REFINE_FACTOR=20. To match the dev CPU configuration, also set RAYON_NUM_THREADS=2 and OPENBLAS_NUM_THREADS=2 as variables. No LANCE_REPO, LANCE_REVISION or LANCE_RUN variables are needed when the committed serving.json is present.

The app downloads its index, masks and display metadata to local disk at startup, then reuses them for requests. display_assets.json pins the atlas and original-page catalogue in the same private artifact repository; those binary files are not bundled in this public repository. Original page images are fetched on demand. The tested CPU Basic dev startup took about 50 seconds with roughly 6–7 GB peak RSS; cold downloads and shared-host conditions can vary.

After deployment, check both collections, full-resolution JPEG and clean PNG downloads in a signed-out browser, and the Explore map. To roll back this release, restore production revision 4536eb0a3b8f870138c196887612d5de666448b9 and remove SEARCH_BACKEND (or set it to numpy); retain a copy of the release revision for inspection.

Browse by publication date

Browse traverses the complete collection without a text query. Choose oldest or newest first, a collection/image type, or a year range, then choose Browse to apply. Undated images appear last when included; an explicit year range excludes them. Dates describe the source publication, not when the image was digitised.

More images load automatically near the bottom, with a Load more button also available. Opening an image preserves your browsing position. Off-screen pages release their image cards and metadata; scrolling back reloads the same page. Find similar starts a fresh image search across both collections. Search and Explore remain separate views, and the atlas is still the British Library sample.

GET /browse accepts dataset, image_type, order (oldest/newest), year_from, year_to, include_undated, limit (1–96; default 48) and an opaque cursor. It returns results, total, offset, next_cursor and revision. Cursors are tied to the filters, page size and pinned metadata revision; restart browsing if any change. This endpoint uses the existing metadata and precomputed date/row-ID ordering, with a bounded filtered-order cache. It does not query vectors or load original images.

Search index and reproducibility

The two collections use the same pinned google/siglip2-so400m-patch16-256 model (e8708ab72d125807e45b36fb7d4e0aacbb59f379). No new inference was needed for this integration.

serving.json is the authoritative, immutable Lance artifact pin, deployed atomically with the app. With no file present, the original LANCE_REPO, LANCE_REVISION, and LANCE_RUN environment variables are used for rollback. Keep SEARCH_BACKEND=lance; NumPy is the legacy BL-only path.

build_combined.py imports original BL vectors plus completed Britannica embedding shards, validates every source ID/geometry/metadata record and finite unit vector, and verifies every float and ID after Lance ingestion. It builds IVF-RQ with 256 partitions; serving uses 64 minimum probes and 20× refinement. The full metadata/index snapshot is downloaded locally at startup; original page images remain in the buckets.

prepare_cutouts.py joins existing masks to all 411,385 indexed Britannica illustrations by stable ID, validates source/model/geometry and builds a compressed SQLite lookup with 411,383 usable masks (578 MB); two empty predictions retain rectangular downloads only. cutouts.json pins that artifact independently of Lance; no embeddings or inference are repeated. Masks stay on disk. PNGs and rectangular JPEGs share the bounded image cache. These are model predictions, so retain the original crop option for imperfect masks.

prepare_originals.py verifies all 92,196 Britannica original-page paths and records their Xet object hashes in originals.parquet. Native downloads verify those identities; JPEG previews verify the SHA-256 saved by the embedding run. The independent full-vector check and six image-query recall checks are recorded in the artifact's manifest.json; these mechanical checks are not a general relevance evaluation.

The combined source contains 1,080,814 BL images and 411,385 Britannica figure crops. Britannica crop metadata is pinned to dataset revision d14ad4cf2717f97b63c668c3d6a83e6257791e33, score ≥0.30. No image files are duplicated into the index.

API and map

search_collections accepts query, image type, year bounds, result count, positive/negative row IDs, text weight and dataset (all, bl, britannica). Previous search, search_reference and search_feedback positional APIs remain available. Row IDs are temporary index references; use asset_id for durable records. Each result carries bucket_path (the source object in the public bucket); it is not named path because gradio_client treats any path key as a file to download and fails with 403. Near-identical results (the same engraving reprinted across editions, cosine ≥ 0.95) are collapsed, so a page can return fewer than k rows.

The existing Explore map remains an explicitly labelled 6,000-image British Library sample. Its original UMAP coordinates and BL row IDs are preserved. Find similar searches the full index using the selected collection filter. Lasso selections are temporary; ZIP export, saved collections and annotation submission are not implemented.

Development checks

For the full pinned CPU runtime, use Linux and Python 3.12.

uv venv --python 3.12
uv pip install -r requirements.txt pytest psutil
PYTHONPATH=. uv run --no-project pytest tests/test_combined.py tests/test_cutouts.py tests/test_search_backend.py tests/test_bl_cache.py tests/test_display_assets.py
node tests/atlas-geometry.cjs

Sources: British Library dataset, Britannica dataset, Britannica page store.

Contributors

davanstrien

21 commits

CF