Skip to main content

StreamEmbed

Search your own screen history by describing what you saw. StreamEmbed indexes screenshots, from a folder or from your screen as you work, and finds a past screen from a sentence. Everything runs on your machine.

It embeds the pixels with Qwen3-VL-Embedding-2B, and encodes screenshots as a stream so that this keeps up on a laptop: blocks that repeat a neighbor are skipped, and the keys and values of blocks that did not change are reused from the previous frame.

Use

import streamembed as se

se.configure(index_type="flat")                      # optional; see below
se.build_index_from_directory("screenshots")         # a folder of .png / .jpg / .webp, searched recursively
capture = se.build_index_from_now(interval=10)       # capture the screen every 10 s, in the background

results = se.query_index("the flight search page with fares to Denver", top_k=10)
se.visualize_results(results)                        # writes an HTML page and opens it

capture.stop()

examples/main.py is a complete script.

Function What it does
available_index_types() ["flat", "binary"]
available_models() Model names: those in the model repo, then the built-in base models
configure(index_dir, index_type, model, models_repo, device, width) Where the index lives (default ./streamembed_index), the index type and the model. Optional
build_index_from_directory(directory, order="mtime") Index a folder as one stream. order="mtime" uses each file's time as its capture time; order="name" sorts by path
build_index_from_now(interval, duration=None, block=False) Capture the primary display every interval seconds, in the background. Returns a Capture with stop(), pause(), resume(), wait(), stats
query_index(query, top_k) Results with score, time, app, window title and the stored image path. A match within 30 s of a better one is dropped
visualize_results(results) A self-contained HTML page. Each result opens full size with the frames before and after it; arrow keys step through time

Screens that did not change are not stored again: a capture is encoded when more than 10 % of its kept blocks changed since the last stored one, or 30 s later if anything changed (the paper's change gate).

The index folder

File Content
frames.jsonl One line per stored screen: time, image path, app, window title
vectors.f16 One 2048-d fp16 vector per line of frames.jsonl
images/ The stored screenshots, 1280 px wide
seen.jsonl When an unchanged screen was still on screen
codes.bin, mu.npy binary only
thumbs/, results.html Made by visualize_results

Index types

Type Search
flat Exact inner product over every stored vector (fp16, 4 KB per frame)
binary Exact up to 1,000 frames. Beyond that, Hamming top 1,000 over 1-bit codes of the first 512 dimensions (64 B per frame, kept in memory), then exact re-rank. About 0.13 GB of memory per year of 5-s captures

An index folder can be reopened with the other type. It also records the encoder, and refuses vectors from a different one.

Models

A model is a base model from its own Hugging Face repository, pinned to a commit, plus two LoRAs from the StreamEmbed model repository: one for screenshots (a consistency adapter that keeps pruned, streamed frames close to full frames) and one for questions. Only the LoRAs live in the StreamEmbed repository; its models.json names each model's base repository, commit and files.

Model What it is
qwen3-vl-2b (default) Qwen3-VL-Embedding-2B with the StreamEmbed LoRAs
qwen3-vl-8b Qwen3-VL-Embedding-8B with the StreamEmbed LoRAs; needs a GPU with about 20 GB
qwen3-vl-2b-base Qwen3-VL-Embedding-2B without LoRAs; built in, needs no model repo

The model repository also holds LoRAs for SigLIP2 So400m, SigLIP2 Base and VultronRetrieverFlash 0.8B. available_models() lists them, but the stream encoder supports Qwen3-VL models only, so selecting one raises NotImplementedError when StreamEmbed first encodes.

configure(models_repo=...) or $STREAMEMBED_MODELS points to another Hugging Face repository or a local folder with the same layout. An index records its model and refuses vectors from another one.

The first run of qwen3-vl-2b downloads the base model (about 4 GB) and the LoRAs (70 MB each); after that nothing is downloaded. Encoding needs about 8 GB of memory and takes 0.7 to 1.3 s per frame on an M2 Pro GPU; the change gate skips screens that did not change.

Requirements

Python 3.12 or later on macOS (Apple silicon, tested) or Linux under X11 (capture not yet tested). On macOS, capturing the screen needs Screen Recording permission for the app that runs Python; build_index_from_now raises PermissionError until it is granted.

Dependencies are pinned to torch 2.8.0 and transformers 5.17.0: the stream encoder re-implements parts of the Qwen3-VL forward pass against transformers internals, and its outputs were checked for equality with these versions. Install StreamEmbed in its own environment (for example uv tool, pipx, or a venv) if your project needs other versions.

Privacy

  • Screenshots, vectors and metadata stay in the index folder (owner-only). Screenshots are stored unencrypted.
  • Capture is skipped when the screen is locked, when the frontmost app is a password manager, and when the frontmost window is a private browsing window. Other windows on screen are not checked; use capture.pause() for sensitive work.
  • Nothing is sent over the network after the model download.

Development

uv venv && uv pip install -e ".[dev]"
.venv/bin/python -m pytest          # API tests with a stand-in encoder; no model needed

src/streamembed/engine/ is the stream encoder from the paper's code and keeps its names: Token Pruning is spatial pruning, KV Reuse is temporal reuse.

License

Apache-2.0. See LICENSE and NOTICE; the model weights are downloaded under their own license.

Metadata

Release files for streamembed 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for streamembed 0.1.0
File Size Uploaded Provenance Actions
streamembed-0.1.0.tar.gz 44.0 kB Without provenance Details for streamembed-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for streamembed 0.1.0
File Interpreter ABI Platform Actions
streamembed-0.1.0-py3-none-any.whl Python 3 none any Details for streamembed-0.1.0-py3-none-any.whl

Total release size: 94.5 kB

Release files / streamembed-0.1.0.tar.gz

Download URL streamembed-0.1.0.tar.gz
Size 44.0 kB
Tags Source
SHA-256 checksum
How to use checksums
65135e53d5b4602874ecd3a374c268f1d6e9eaa0b91c8f9bedf3055e62e4a3a2
BLAKE2b-256 checksum
How to use checksums
3d01632f0ad18a3c7ddbe8054cfddf426adc895e029e939431af9c19dd90b76d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / streamembed-0.1.0-py3-none-any.whl

Download URL streamembed-0.1.0-py3-none-any.whl
Size 50.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b0d322797eb44dcbf2a8cbf3e9be3eed4bfaa4989c9486f0cbcf12492d617bd0
BLAKE2b-256 checksum
How to use checksums
4497adfaa26d7a25879b38624e83013f86b080484d17d4dd5faea9e84b107f75
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.4 {"installer":{"name":"uv","version":"0.13.4","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for streamembed 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page