FrameScout — Offline AI Search: v3.1.0 — Codebase Refactor, GPU Inference & Full Source Release
LatestFrameScout — Offline AI Search: v3.1.0 — Codebase Refactor, GPU Inference & Full Source Release
Release date: 2026-09-23
This is primarily a maintenance and consolidation release, but it also ships two real improvements: GPU-accelerated embeddings (via DirectML) and video frame indexing (previously broken). It does not change the AI models or search quality, but it substantially cleans up the codebase, fixes a long list of latent bugs, refactors the Tauri/Rust entry structure, and — importantly — publishes the complete project source tree to the repository.
✨ What's New
- ⚡ GPU-Accelerated Embeddings (DirectML) — The Python worker now runs on
onnxruntime-directml. SigLIP 2 embedding inference is executed on the GPU via the DirectML execution provider on Windows, delivering a substantial speedup over the previous CPU path (most noticeable for video frame extraction and bulk image encoding). This works across NVIDIA / AMD / Intel GPUs with zero CUDA or driver-version juggling. (EasyOCR text recognition still runs on CPU — only the embedding step is GPU-accelerated.) - 🎬 Video Frame Indexing (previously broken) —
_handle_batchnow detects video files and extracts frames viaextract_video_frames; images still go throughload_image_pil. Each path yields multiple timestampedFrameResultentries, so videos finally enter the index instead of being silently dropped. - 🗄️ Multi-Frame Data Model — The
frame_vectorstable primary key changed frompathto(path, timestamp). Old single-frame databases are migrated automatically inside a transactional block (rename → create → copy → drop, with rollback on any failure). - 📦 Complete Source Tree Published — The full Rust, Vue, and Python source — including the
model_codemodule, all build configs (Cargo.toml,ai_worker.spec), docs (BUILD.md,READMEs), and the bundledprotoc.exe— is now committed. This is a true full-source Community Edition. - 🔀 Smart Folder Result Consistency —
applySmartFoldernow reusesnormalizeResults, so smart-folder results behave identically to manual search (videos get a 25s load timeout with "File Unavailable" fallback; low-confidence images auto-collapse). Applying a folder from "Show All" mode no longer leaves the pagination bar stuck.
🐛 Bug Fixes
- "Show All" mode exited on page turn — While in "Show All" (full-file preview) mode, turning pages previously triggered a background re-search/refresh that reset the view back to paginated browsing, kicking you out of Show All. The view mode is now preserved across page turns.
- Worker crash on startup with missing models —
main.pynow catchesFileNotFoundErrorand prints a cleanFATALmessage then exits, instead of dumping a raw traceback. - Latent
UnboundLocalErrorin the worker loop —task_idis now initialized at the top of the request loop, fixing a crash when an exception occurred duringrecv()/ParseFromString()(wherereqwas never assigned). - OCR config never honored — The long-dormant
single_file_ocr_configproto field (field 6) is now actually read; when set it drives per-fileenable_ocr/languages, otherwise behavior is unchanged (always OCR, defaulten). - Stale data & inconsistent dedup — Search dedup was verified to preserve each file's highest-scoring frame and its
timestamp(used for instant seek); clarifying comments added.index_cmd.rsnow refreshesvector_jsononON CONFLICT(path, timestamp)to avoid mixing a first-frame vector with a last-frame OCR text. - HTML injection in results —
escapeHtmlnow escapes&,",'in addition to</>, preventing path text from breaking thev-htmlrendering. - HMR event-loss — Four Vue composables (
useSearch,useEngineStatus,useLicense,useScanner) now resetlifecycleBoundinonUnmounted, so engine-status / scan-progress / key listeners re-bind correctly after hot reload. - Redundant license refresh — Removed a duplicate
emit('refresh-license')+checkLicense()inLicenseModaland the corresponding binding inApp.vue.
🔧 Under the Hood
- Tauri entry refactor —
lib.rsnow owns all 7 module declarations and the TauriBuilder(run()carries#[cfg_attr(mobile, tauri::mobile_entry_point)], Apache header preserved);main.rsis a 4-line shell callingframescout_ui_lib::run(). - Dependency & metadata cleanup — Removed unused
tauri-plugin-opener(no frontend calls, no capability);Cargo.tomlversion3.0.0 → 3.1.0(aligned withtauri.conf.json);keywordstrimmed to the crates.io 5-item limit. - Zero-warning builds — Fixed several
cfg-gated dead-code/unused-import warnings (guard.rs,verifier.rs,index_cmd.rs,storage/mod.rs); merged the duplicatePaginatedResultstruct intoPagedResponse; removed a deprecated_stateparam fromping_engine. - Python worker hygiene — Replaced
__import__("PIL")hacks with a properfrom PIL import Image; removed an unusedEMBEDDING_DIMimport; cleaned leftover comments and a duplicate docstring invideo_extractor.py; added acap.isOpened()guard. - Packaging robustness —
ai_worker.specno longer hardcodes an absolute.venvpath (now resolved relative toSPECPATH), so the build works after moving the venv or the repo.requirements.txtis now pinned to a single ONNX Runtime package (onnxruntime-directml) — the CPUonnxruntimeand DirectML packages both provide theonnxruntimemodule and overwrite each other, so they must never be co-installed. The DirectML build also bundlesDirectML.dllfor the GPU path. - Type safety / IDE — Added
pyrightconfig.json(correct filename for basedpyright) plus a hand-writtensearch_pb2.pyistub and type annotations acrossserver.py/config.py/engines/video_extractor.py, bringing the wholeinference-workerto 0 errors / 0 warnings under basedpyright. - Frame-extraction guards — Added
MAX_FRAMES_PER_VIDEOandMAX_FRAMES_PER_ENCODING_BATCH(config + constants) so long videos are bounded in time/memory and large batches don't overflow GPU memory; batching also isolates a single-file failure from the rest of the batch. - Extension whitelist single-source —
IMAGE_EXTENSIONS/VIDEO_EXTENSIONSnow live in Rustconstants.rsand Pythonvideo_extractor.pywith a cross-language "keep in sync" note;scan_folderuses the constant instead of inline literals.
📋 Upgrade Notes
- No model re-download required — SigLIP 2 ONNX models are unchanged since v3.0.1; existing
models/remain valid. - Existing databases auto-migrate — Single-frame
frame_vectorstables are upgraded to the composite(path, timestamp)key on first launch; your previously indexed images are preserved. (Videos were never stored before, so there is no legacy video data to migrate.) - If you build from source: re-run
pyinstallerperBUILD.mdwithonnxruntime-directmlactive (soDirectML.dllis bundled), then copy the completedist/ai_worker(including its_internal/folder) intosrc-tauri/bin/ai_worker— the onedir layout requires_internal/python312.dllto be present.
🙏 Tech Stack
Google SigLIP 2 · ONNX Runtime (DirectML / GPU) · EasyOCR (CPU) · Tauri · ZeroMQ · Protobuf · Rust + Vue 3
Full Changelog: v3.0.3...v3.1.0
The main Tauri application executable stays lightweight (~5 MB); the Python AI worker is bundled as a separate sidecar. Embedding inference now runs on your GPU via DirectML — noticeably faster than before — while OCR remains on CPU.