Repository navigation
feat: visual search, find similar items, and search inside linked PDFs - #135
Merged
Merged
Conversation
devnull03
force-pushed
the
feat/visual-search
branch
from
September 14, 2026 21:21
600042a to
1aa0b1c
Compare
devnull03
marked this pull request as ready for review
September 15, 2026 22:14
Table search gains a linked-files toggle, on by default. Each row's linked document is read once in the background, cached on disk beside the thumbnails, and matched with the same case/word/regex rules as cells. A hit lands on the cell that names the file.
Adds the visual-search crate: CLIP ViT-B/32 on the CPU through candle, a hand-rolled CLIP tokenizer, a checksum-verified download of the pinned weights, and an index of thumbnail embeddings kept on disk. The table search bar gains a Visual toggle that ranks rows by how well their linked file matches the query, offers the model download when it is missing, and indexes linked files in the background. The row and gallery context menu gains Find similar items.
Stat linked files and load the saved index before taking the lock the search bar ranks through, and save the index every 40 batches so quitting part-way through a first index keeps the work.
Taking the find-similar request through global_mut notified the same observer again, spinning the UI thread once indexing touched the global. Also gives the visual toggle a picture icon.
A visual or linked-file search now shows only its hit rows, visual ones best first, until the search is cleared or closed. A breadth slider replaces the fixed top 50 with a cut-off relative to the best hit. The find bar is drawn by the views panel, so it stays up and keeps its search across Table and Gallery, and the gallery scrolls to follow the selected hit. Replace is disabled during a visual search. Linked-file text is now opt-in, since turning it on filters.
Vectors now live in a __visual_index table inside the .qrate, created on first write, with the model that built them recorded in __settings. Paths are kept relative to the files folder and staleness is judged on file length, so a project copied with its files keeps its index. Each batch is written as it is embedded, outside the index lock. Replaces the global visual-index.bin.
Up and down buttons, and the arrow keys, open the next row in the view's order that has something to preview, and select it. During a search that is the next result.
…ottom right The viewer now opens the selected row's file whenever the selection moves, so stepping through search results from the find bar changes the image. The row buttons move from the top toolbar, where they repeated the find bar's, to left and right arrows in the bottom-right corner.
…ling The thumbnail memory cap called drop_image from the image loader, which gpui runs while painting. Freeing an image there could release a GPU texture a sprite earlier in the same frame still pointed at, and presenting that frame panicked in the DirectX atlas. The cap was also first-in-first-out, so a card on screen could be the one freed. Images now move to the back of the queue every time they are drawn, and releasing waits for the start of the next frame, then repaints every window so no cached view replays a freed sprite.
Also gives the viewer's row arrows the same ghost buttons as its zoom controls.
devnull03
force-pushed
the
feat/visual-search
branch
from
September 19, 2026 22:31
5b29a9a to
7d542b5
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Visual search and search inside linked PDFs. Design doc: Visual search, similar items, and linked-file text search.
What works
Search inside linked PDFs
preview::document_text) and cached beside the thumbnails.Visual search
visual-searchcrate: CLIP ViT-B/32 on the CPU through candle (pure Rust), with a hand-written CLIP tokenizer.openai/clip-vit-base-patch32@b33cedf, 605 MB), checked against its SHA-256 before it's moved into place.preview::thumbnail_pixels), so it covers everything qrate can preview. PDFs use their first page, video its poster frame, audio its cover art.Works in every view
ViewsPanelabove Table or Gallery. A search survives switching between them, and Find / Ctrl+F / Ctrl+H work in both.Storage
__visual_indextable created on first write. The model that built them is recorded in__settings, and a different model clears them.Docs
docs/visual-search.md: what it searches, installing the model, searching and the breadth slider, find similar items, indexing and where the index lives, searching inside linked PDFs, and the limits (one page or frame per file, no handwriting or printed text, English queries, never writes a cell).docs/index.md,docs/grid.md(the two search toggles, and the bar following the view),docs/files-and-photos.md(the viewer's row arrows), and the README (feature bullet, privacy paragraph, docs list).Crash fix: fast scrolling through thumbnails
This fixes a bug already on
main, not one this branch introduced. Scrolling quickly through a large gallery could abort the app with a panic in gpui's DirectX atlas (directx_atlas.rs:255,Option::unwrap()onNone). Windows reports the abort asSTATUS_STACK_BUFFER_OVERRUN.preview::retainenforces the 192 MB thumbnail memory cap. It calledcx.drop_imagestraight from the image loader, and gpui runs that loader while painting.retainnever frees anything itself. It queues areleasewithwindow.on_next_frame, which runs before the next frame is laid out.releaserepaints every window. Dock panels are cached views that replay their last paint's sprites, and those could include a freed image.Decisions worth reviewing
set_search_rowsoverrides the view's rows. Searches always scan the rows the column filters allow (filtered_rows), not the rows the previous search left, so typing more can widen results again. An insert or delete drops the narrowing, because it shifts source indices.tokenizersand its C oniguruma build.ponytail:shortcuts:Measured on this machine (16-core, CPU only)
Not done yet
POST /embeddings, for institutions hosting their own. The Islandora server-side design is in the Notion doc "Repository-wide visual search for Islandora 2".QuerySource::Searchstill matches cells only. Extending it means updatingAGENTS.md.Known limits
ponytail:).__visual_index.Verification
mainat 0.5.0-beta.1, with no conflicts../scripts/ci.sh(fmt, clippy-D warnings,cargo test --workspace) passed on Windows.Cargo.lockresolves with--lockedfor x86_64/aarch64 macOS and x86_64 Linux.visual-searchtests: ran against the downloaded weights.badf6a3) and the ranking and cutoff problems addressed here..qrate, and fast scrolling after the crash fix are covered by unit tests only.🤖 Generated with Claude Code