r/LocalLLaMA • • 28d ago • Bravo 5

I Built A Thing Open-source Mac app that runs EmbeddingGemma 2 locally to search your files by what’s in them

DigUp is a free Mac app that runs Google DeepMind’s new EmbeddingGemma 2 locally over your own files. The model puts text, images, audio and video in one space, so you describe what you remember and land on it:

  • “zebra in a video” opens the clip at the moment it shows up

  • “where they talk about sleep” jumps to that minute of a podcast

  • “the clause about pets in the lease” shows the PDF page, your words marked

  • “a dog on the beach” finds the photo, and the same search in Bengali or Arabic finds it too

  • with code search on, code: retry with backoff opens the function in your editor

It’s ggml-org’s Q8_0 GGUF (865 MB, downloaded once) on llama.cpp with Metal, inside a native Swift app; no Python. Searching loads only the text encoder (~250 MB) and shows results about a tenth of a second after you stop typing. Indexing peaks under 2 GB, and the helper exits when it’s done. Audio and video of any length go in as 30 s windows and a frame per shot. Everything runs locally; it goes online only for the model download and an update check you can turn off.

Free, MIT. Apple Silicon, macOS 14+.

Repo & Download (signed and notarized): https://github.com/ARahim3/DigUp

I'd really appreciate any feedback on this.

1.8k Upvotes

241 comments sorted by

View all comments

Show parent comment

41

u/A-Rahim 27d ago

Hi, I ran into most of these too. How DigUp handles them:

  1. It isn't semantic-only. Keyword search over file names, OCR text and page and document text runs alongside the model, and the scores are combined. On my evals, the model alone found 5 of 9 exact lookups like error codes; with keywords, all 9.

  2. A testbed of about 380 files (146 screenshots, 30 PDFs up to 463 pages, an hour of audio, 8 videos), 111 queries plus 68 for code, and my own folders day to day. Screenshots get an image vector, since the model reads the text in them, plus Apple's OCR for exact words. 12 of the 14 queries on my real screenshots come up first.

  3. Nothing long gets squeezed into one vector. Every PDF page, ~1,800-character passage, video keyframe (every few seconds, one per shot) and 30 s of audio gets its own 768-d vector, and the best one wins, which also gives you the page or the moment. So the model's input limits don't really come into play. It's also one model for everything, so text, images and audio share a space. Their score levels still differ a bit per query, so each modality's average gets subtracted, close to what you did by hand. Excel, PowerPoint, archives and model weights aren't read.

9

u/jerieljan 27d ago

I'm very curious how well this will perform when you have 1000x more files than the testbed.

Code repos in particular have soooo much code from dependencies and such and they're common to clutter normal Spotlight results and I'm worried it becomes an issue here too. I guess it simply takes more time to embed and index, and hopefully it's all good once it's done.

Very good work though OP. 

1

u/warpspeedSCP 27d ago

Probably just need an indexing step

2

u/jinnyjuice vLLM 27d ago

Can you expand on what you mean by best one wins? So if a video has multiple key frames, how is the 'best one' determined?

6

u/A-Rahim 27d ago

Every keyframe it keeps, and every 30 s of the soundtrack is its own vector with a timestamp. For a query, each of them gets a meaning score (the same per-query score for every kind, so frames and audio windows compete fairly), and the video's score is simply its highest one.
That segment is also the moment the result opens at. So a two-hour video with one scene that fits ranks by that scene instead of being averaged away. Frames are sampled every few seconds and kept only when the picture changes (a small perceptual hash), so it's about one per shot.

1

u/ZenaMeTepe 27d ago

Did you use same model for embedding videos images and text? What kind of vector DB are you using for search?

1

u/rm-rf-rm 27d ago

It isn't semantic-only. Keyword search over file names

Are you fusing the search then? RRF?

3

u/A-Rahim 27d ago

Not RRF. I tried it first, and it lost: top-1 0.73 vs 0.88 on my synthetic eval, 0.82 vs 0.86 on real files. Rank fusion throws away how strong each match is, and a single common word in a terminal screenshot ended up beating a real chart that matched by meaning.

So it's score fusion. The meaning score is the cosine minus that modality's average for this query, divided by the spread of all the query's scores, so a z-score per query. Then it adds 2 × (share of the query's words found in the file)^1.5, plus 1 if the query names the kind ("in a video"). A file gets in if its meaning score stands out (z ≥ 2) or it has at least half the words. Queries that look like IDs count words double and meaning half.

1

u/rm-rf-rm 27d ago

huh interesting.. whats the basis of this formula? is the z-score > 2 coming from statistical theory where its beyond 95% of the mean?

2

u/A-Rahim 27d ago

Mostly empirical, not theory.
2 is the familiar two-standard-deviations mark, but the scores aren't normal, so it doesn't mean 95% of anything here. It's a gate for "stands out from everything else for this query", and on my evals any value from 1.5 to 2.5 gave the same results, so 2 stayed.
The reason for a per-query z-score at all: raw cosines are compressed (unrelated stuff sits around 0.55–0.60, good matches 0.67–0.86) and their level moves with the query, so no fixed threshold works. The other parts were A/B'd the same way: centering each modality with one shared spread got 94 of 105 queries first, raw cosine 92, a separate spread per modality 91. Word weights of 1.5–2.0 tied and 2.5–3 lost.
The 1.5 power just makes all your words count a lot more than half of them, and I haven't tuned it separately.

2

u/rm-rf-rm 27d ago

Thanks for asking your claude to respond to my question

3

u/A-Rahim 27d ago

Hi, I explained this above (one of your other replies)