SCM README

The project's README from github.com/allenv0/SCM. As one markdown file: README.md.

SCM — Screen Memories

Deep AI search for every photo and every frame of video in any folder on macOS. Local-first — no accounts, no cloud, no uploads. Inference runs on your Mac.

SCM demo — library grid SCM demo — scene search

What makes it different

Search modes: Files, Scenes, Dialogue, OCR, LLMs
Mode Finds
Files Whole photos/videos by meaning — vision rank with filename and phrase boosts
Scenes Moments inside video — search a shot, jump to its timecode
OCR Text visible in images and frames, matched literally (Tesseract; eng + 35 language toggles)
Dialogue Exact spoken words in videos (Whisper), tiered exactness
LLMs (opt-in) Local chat over the dialogue, OCR, and filenames your Mac already extracted — cited answers

Requirements

Download

The easiest install is via Homebrew (Apple Silicon, macOS 12+). The tap's cask clears the macOS quarantine flag automatically on every install and upgrade, so the app launches with no manual Gatekeeper steps:

brew tap allenv0/scm
brew trust allenv0/scm
brew install --cask allenv0/scm/scm

Upgrades keep the same behavior:

brew upgrade --cask allenv0/scm/scm

The tap lives at allenv0/homebrew-scm.

Development

bun run dev     # build the renderer bundle, then launch the Electron app
bun start       # launch the Electron app without rebuilding
bun run build   # just rebuild the renderer bundle into dist/

Building the app package (DMG / ZIP)

bun run dist            # signed if an identity is in the keychain
bun run dist:unsigned   # skip code-sign discovery

This runs two steps in sequence:

  1. vite build — compiles the React renderer into dist/ (picks up all changes under src/).
  2. electron-builder --mac — packages the app. It bundles the fresh dist/ bundle together with main.js, preload.js, main-lib/, and indexer/ (the file list is configured under build.files in package.json), then produces the installers.

Output: the installers land in dist-app/ (see build.directories.output in package.json) — look for SCM-0.2.4.dmg and SCM-0.2.4.zip.


Features

Files

Typing starts an instant filename-keyword pre-pass, then the vision model takes over: results are scored by cosine similarity against image embeddings, with gated phrase and filename boosts, an honesty floor calibrated per model, and a near-duplicate diversity filter. Every tile carries a "why it matched" badge (Visual match / Filename match / …) and a hover tooltip with the per-component score breakdown. CJK queries search as overlapping bigrams ("台北車站" also matches 台北, 車站).

Scenes

Every scene segment across all videos is scored, so a hit lands on the exact shot: tiles show the scene poster with a timecode badge, and opening the video jumps straight to that moment. A noise gate returns "no scene match" instead of flooding the grid with gibberish, and each video contributes at most 3 scenes.

OCR

Matches the fraction of query tokens literally visible in each image's OCR text — the filename is ignored and no vision model is involved, so it works even while the AI engine is warming up or offline. Matched words are boxed in amber on tiles and in the lightbox.

Dialogue

Exact literal retrieval over Whisper transcripts — no embeddings, no thresholds, works with the AI engine down. Results come in three tiers: Exact line (contiguous phrase in one utterance), Exact words (all words in one utterance or an ≤8s window), and Words spoken (all words in the same video). Matching words are highlighted in a speech snippet; opening a result seeks straight to the line.

LLMs (Ask)

Opt-in — nothing downloads or runs until enabled in Settings → LLMs Chat. A llama.cpp sidecar bound to loopback answers your question from evidence the app already extracted — dialogue lines, OCR text, and filename keyword hits — with numbered citations you can click, streamed token-by-token with a live tok/s readout. Leading /screenshots, /videos, /email narrow the corpus; Stop keeps the partial answer; empty evidence short-circuits before the model ever runs.

Chat model Size Notes
Qwen3 1.7B (default) ~1.1GB Fast everyday chat; fits 8GB Macs
Llama 3.2 3B ~2GB Stronger long answers; needs headroom

Tabs & library views

Email tab

Surfaces photos whose visible OCR text contains an email address — an overlapping view (a photo keeps its category too). Detection is OCR-tolerant: it reassembles addresses Tesseract fractures across word boxes, and handles comma-for-dot noise ("gmail,com"), split TLDs ("gmail. com"), bracketed obfuscation ("allen [at] gmail [dot] com"), and dictated addresses ("allen at gmail dot com"). Tiles show a contact strip; expand it to copy or compose.

Screenshots tab

Screenshot classification is rename-proof. Four signals, in priority order: a manual override (right-click any tile) → filename vocabulary (30+ localized OS screenshot names in 20+ languages) → a PNG/JPEG metadata probe (reads "screenshot" from PNG text chunks / EXIF UserComment, so a renamed Bildschirmfoto still classifies) → source-folder hint. Everything else lands in Projects.

Vision models

Four switchable models via ONNX Runtime; the active one is chosen per library:

Model Role Speed (CPU) Download
CLIP ViT-L/14@336 (default) Best real-world video scene-search ~480–570ms/img ~435MB
SigLIP-2-B/16 Fastest bulk import ~50–100ms/img ~412MB
SigLIP-2-L/16@256 High-detail (1024-dim) — small objects, signs, on-screen text ~200ms/img ~850MB
SigLIP-B/16@384 Maximum detail ~480ms/img ~214MB

Switching models re-embeds the whole library: the flip lands instantly with the tail filled in the background, and search falls back to filename keywords until it completes. Per-model text-mean centering de-biases text embeddings so similarity scores stay honest across models.

Video search pipeline

ffmpeg scans each video for shot boundaries and builds a segment plan sampled to the density you pick in Settings → Video Search — each preset shows its measured time and disk cost before you commit:

Preset Seconds per point Segment budget
Eco 60 4–32
Balanced (default) 30 8–128
Detailed 15 12–256
Ultra 5 16–1024
Ultra Pro 2.5 24–2048 (confirm required)

Each segment embeds its midpoint frame and keeps a poster; shot plans are cached per file (path + size + mtime + config fingerprint), so re-imports skip detection entirely.

Dialogue transcription: Whisper tiny.en (150MB, default) or base.en (300MB) — switching re-transcribes every video. Whole videos embed three frames (20/50/80%) averaged; GIFs embed an average of middle frames.

OCR

Tesseract runs in its own worker, separate from the vision model. English is always on; 35 more languages are toggleable in Settings → Photo Search (default: Simplified + Traditional Chinese, Japanese, Korean). Each language pack downloads once (~2.4–5MB; ~17MB for the default set), then everything is offline. Word boxes are stored with the text so matches highlight in place; CJK text is joined without spaces and email fragments fractured across word boxes are reassembled.

Import & library management

Privacy by construction

Settings & polish

A macOS-style settings sheet with ten panels (Library, Appearance, Grid, Smart Tabs, Photo Search, Video Search, LLMs Chat, Global Shortcut, Keyboard, Menu Bar). Around the core: light/dark/system theme, a CRT screen effect for the lightbox, 6 alternate app icons, menu-bar-only mode, a recordable global shortcut, a first-run onboarding tour, background-work trays (scenes / transcripts / OCR) with a global pause, and a status bar with version and indexed-video counts.

Notes

Testing

bun run test:all         # the full verification battery (unit + smoke suites)
bun run smoke:indexer    # headless smoke test of the CLIP indexer
bun test test/           # unit tests (pure modules, no Electron needed)
bun run lint             # eslint
bun run format:check     # prettier

Project layout

main.js             Electron main process: library, IPC, indexer worker pool, app:// protocol
preload.js          contextBridge — exposes window.memories to the renderer
main-lib/           main-process modules split out of main.js (settings, library store,
                    rank search, Ask retrieval, LLM sidecar config, embedding versions, …)
indexer/            vision/OCR/ASR workers (utility processes) + video utils + model registry
src/                React renderer (grid, search modes, lightbox, tabs, settings, onboarding)
scripts/            bench scripts, E2E drivers, the smoke battery (smoke-all.sh)
test/               unit + integration tests
MDs/                design docs, bench reports, plans
dist/               vite build output (renderer bundle)
dist-app/           electron-builder output (DMG / ZIP)

SCM (allenv0/SCM)

Searching Database…

486 ·GitHub
这是什么?SCM(Screen Memories)是一款 macOS 桌面应用,可在本地对你选定文件夹中的每张照片和每一帧视频进行深度 AI 搜索,让你按语义、屏幕文字或对话语音来搜索,全程不依赖云端。
这是网页服务,还是装在 Mac 上的东西?它是一款用 Electron 构建的原生 macOS 桌面应用,通过 electron-builder 打包成 DMG/ZIP,不是网页应用或云服务。
需要 API 密钥或自备 AI 模型吗?不需要任何 API 密钥 — 所有推理都在本机运行。首次使用某个模型时会一次性下载其权重(默认 CLIP 模型约 435MB),之后一切都能完全离线工作。
下载的应用能立刻运行吗?由于没有 Apple 开发者签名身份,DMG 是未签名的,首次启动时 macOS 可能要求你右键点击并选择“打开”;之后它仍然完全在本地运行。
它需要 Apple Silicon,还是 Intel Mac 也能运行?文档中的安装方式是 Apple Silicon 上运行 macOS 12+ 的 Homebrew,菜单栏/托盘功能也明确仅限 macOS;没有提到支持 Windows 或 Linux。
搜索时我的照片和视频数据会去哪里?不会离开你的 Mac — 它是本地优先的,没有账号、云同步或上传;媒体文件会被复制到应用管理的本地媒体库并从磁盘流式读取,只有模型权重和语言包会被下载。
有哪五种搜索模式?Files 按语义搜索整张照片/整段视频;Scenes 跳转到视频内匹配的时刻;OCR 匹配屏幕上的文字原文;Dialogue 通过 Whisper 精确匹配口语对话;还有一个可选的 LLMs(Ask)模式,让你基于应用已提取的内容进行对话。
我能和 AI 聊我的媒体内容吗?可以,可选开启的 Ask 模式会运行一个本地 llama.cpp 附属进程(默认 Qwen3 1.7B,或 Llama 3.2 3B),仅使用应用已提取的 OCR 文本、对话和文件名来回答问题,并提供可点击的编号引用。
可以更换驱动搜索的视觉模型吗?可以,四个 ONNX 视觉模型(默认 CLIP ViT-L/14@336、SigLIP-2-B/16、SigLIP-2-L/16@256、SigLIP-B/16@384)可以按媒体库切换,以速度换细节;切换后会在后台重新嵌入整个媒体库。
它也能搜索视频里的文字和语音吗?能 — Tesseract OCR 可以识别屏幕上的英文文字以及 35 种可切换的语言,Whisper 则转录对话以支持精确的口语搜索;即使视觉 AI 引擎正在预热或被禁用,两者也照常工作。
Creator
allenv0
Size
99.5 MB
Stars
486
Updated
CommitOct 16
Age
14d
Commits · 90 Days