B0yko / tern
git clone https://github.com/B0yko/tern.git
Local AI search for podcast and video archives on Apple Silicon: Whisper speech, Apple Vision OCR and SigLIP-2 visual search fused into one ranked list, with a trim editor and FCPXML export. FastAPI, vanilla JS, Tauri. Source-visible, all rights reserved.
+0
stars, 24h · #31,289
+~0
stars, 7 days · #31,764
+219
stars, 30 days · #2,353
219
★ total
1
forks · 0 open issues
Star history (as recorded here)
LanguagePython
License—
Created2026-09-24 (28d ago)
Last push23d ago
Watchers1
OwnerUser
GitHub topics
apple-siliconapple-visionchromadbfastapifcpxmlffmpeglocal-firstmacosmultimodal-searchocrpodcastsemantic-searchsiglipspeech-to-textsqlite-fts5taurivector-searchvideo-searchwhisperwhisper-cpp
Links
- GitHub: github.com/B0yko/tern
- Homepage: https://boiko.ai/work/tern/
- Releases · Issues · Hacker News mentions
README excerpt
Tern Local search for podcast and video archives. Find any moment by what was said , what was on screen , or what was in the frame , on-device, on Apple Silicon. 3 search channels speech · on-screen text · picture On-device no media leaves the Mac 539 tests pipeline · API · licence rules 5 export formats MP4 · MP3 · SRT · CSV · FCPXML *Visual search: no transcript and no filename to match, only the frame. The clip is then trimmed in place, ready to export.* ## Contents - What it does - How it works - Engineering notes - Running it from source - Tests - Layout - Status - License ## What it does Point Tern at a folder of audio, video and photos. It indexes every file three ways and answers a query from all three at once: - **Speech.** whisper.cpp (Whisper Large v3 Turbo, Q5) transcribes every file, with word-level timestamps. Silero VAD marks the speech regions, and segments Whisper produces outside them are dropped, because Whisper hallucinates text on silence. - **On-screen text.** Apple Vision reads every video keyframe and every image, through a small Swift sidecar. - **The picture itself.** SigLIP-2 embeds every keyframe, so you can describe what you remember seeing rather than what the file was called. Results from all three are fused into one ranked list. A moment that matches on more than one channel ranks higher and is badged as a multi-channel hit. A trim editor exports any hit as MP4 or MP3; SRT subtitles, CSV and an FCPXML timeline for Final Cut Pro export from the result list. Media and the index never leave the Mac: transcription, OCR and embedding all run locally. The network is used to fetch the models on first use (the Hugging Face library also revalidates its cached copy when it loads one), to activate a licence, for the update check, and to open Apple Maps when you click a photo's location. *`hurricane` against NASA footage: the caption burned into the video and the narration match the same moments, so the hits are badged On-screen + Speech.* *Speech search narrowing as you type, across several episodes of a synthetic demo podcast (the episodes are not included in this repository).* The trim editor: a keyframe filmstrip, a zoomed working strip, snapping and frame stepping. Export FCPXML sends every hit to Final Cut Pro as one timeline, one marker per moment. ## How it works ### From a query to one ranked list Each channel is searched on its own, so one failing channel degrades the list instead of blanking it. The noise floor exists because SigLIP always returns its nearest frames, even for a query that matches nothing; it is computed from picture scores only, and it never drops a hit that another channel confirmed. ### Components [code] The dependency arrow points one way, `app → api → service_pipeline`. The indexing and search library has no HTTP layer in it, so it is tested without a server, and the API is a thin, validated wrapper over it. ARCHITECTURE.md goes through the pipeline, the storage split, the