8000 feat(describe): describe pictures on this machine with Moondream by adeelahmad · Pull Request #518 · adeelahmad/lense · GitHub
[go: up one dir, main page]

Skip to content

feat(describe): describe pictures on this machine with Moondream - #518

Merged
adeelahmad merged 7 commits into
mainfrom
claude/project-thread-ogtvpr
Oct 18, 2026
Merged

adeelahmad merged 7 commits into
mainfrom
claude/project-thread-ogtvpr

Conversation

@adeelahmad
Copy link
Copy Markdown
Owner

Requested by Adeel · project thread

Description

Before: pictures were described by the provider's vision model or, since #477, by Florence-2 on this server.

After: Settings → LLM provider → Describing pictures also offers Moondream on this server (llm.describe_engine moondream), with a Moondream model choice (llm.moondream_model): Moondream 3 Preview (the default when Moondream is picked, about 19 GB, needs an NVIDIA GPU with 20 GB or a Mac with 32 GB; BSL 1.1, not open source) or Moondream 2 (Apache-2.0, about 3.7 GB, runs on a CPU, slowly). No picture leaves the machine. The default engine stays the provider's model.

How: moondream.py loads the model with transformers at a pinned revision (trust_remote_code, since Moondream's code ships with its weights) and calls its caption(image, length="normal"), the same for both models. The moondream extra (PyTorch and transformers) and the weights are a component fetched the first time a job waits at the describe step, and only where the chosen model can run: moondream.cannot_run reads the machine (GPUs and their memory, Apple silicon, RAM) and, where it can't, the step's log and the picture_descriptions MCP tool say why and suggest Moondream 2 or Florence-2, instead of fetching 19 GB. Each picture is a model.describe ledger row. PyTorch's threads are capped at OMP_THREAD_LIMIT when that is lower, since PyTorch's CPU kernels otherwise write nonsense (found by the real-model test).

Checked here: Moondream 2 at the pinned revision describes a photo well through Lens's own code but took 3 to 6 minutes a picture on four shared CPU cores (Florence-2 base: about 3 s). Moondream 3 Preview was not run here (no GPU); its code at the pinned revision was read and uses the same call. An opt-in test (LENS_TEST_MOONDREAM=1) fetches PyTorch, transformers and Moondream 2 through the component and describes a picture.

Motivation and Context

Adeel asked to use Moondream 3 and/or Microsoft Florence for visual descriptions. Florence-2 landed in #477; this adds Moondream as an opt-in engine, since Moondream 3's weights are BSL 1.1 and need a GPU or a large Mac.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change; ! in the title)

Checklist:

  • The title is a Conventional Commit.
  • My code follows the code style of this project (make hooks checks it on commit).
  • I added or updated tests.
  • My change requires documentation updates, and I have updated docs/ accordingly.
  • Users need more than the title to understand it, so I wrote it under ## Unreleased in CHANGELOG.md.

Done questions (AGENTS.md)

  • Goal: Moondream 3 (and Moondream 2) describe pictures on this machine; merged on green CI (local CI run before pushing).
  • Agents: set_picture_descriptions takes moondream_model; picture_descriptions says whether it can run here and why not.
  • Zero setup: PyTorch, transformers and the weights are fetched on first use; nothing to install or edit.
  • Fewest clicks: one select for the engine, one for the model, with a default.
  • Configurable: llm.describe_engine and llm.moondream_model in Settings with defaults; nothing in the wizard.
  • Light: off by default; nothing is fetched unless picked, and never where the model can't run.
  • Private and secure: pictures stay on the machine; threat model row added (remote code pinned to a revision).
  • Cost: no provider call; each picture is a model.describe ledger row.
  • User decides: the default engine is unchanged; Moondream only when an admin picks it.
  • Upgrades: new settings keys with defaults; no stored-data change.
  • Honest: docs and the select say Moondream 3 is BSL 1.1, not open source, and give the measured CPU time; the README lists it as built, with its checks in docs/requirements.md.
  • Tests, docs and generated files updated (make openapi gave no changes).
  • Open: Moondream 3's BSL 1.1 weights are an opt-in download, never a dependency; PyTorch (BSD) and transformers (Apache-2.0) are an opt-in extra, so Lens stays MIT.
  • Result reported with evidence; "refine later" items in DEVLOG.md.
  • Reuse: the describe step, components, machine probe, activity ledger and MCP tools from feat(describe): describe pictures on this machine with Florence-2 #477 and before; transformers runs the model with Moondream's own code.

Generated by Claude Code

Settings → LLM provider → Describing pictures can also have M87 Labs' Moondream
caption each page and shot (llm.describe_engine moondream) through transformers
and PyTorch, the moondream extra fetched on first use: Moondream 3 Preview
(BSL 1.1, about 19 GB, an NVIDIA GPU or a Mac with 32 GB) or Moondream 2
(Apache-2.0, about 3.7 GB, on a CPU, slowly), pinned to a revision.
moondream.cannot_run keeps the model from being fetched where it can't run and
the step says why. Agents choose it with set_picture_descriptions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013kCtgLNMjPQYdZpV5gbwUW
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013kCtgLNMjPQYdZpV5gbwUW
@adeelahmad adeelahmad self-assigned this Oct 17, 2026
…-ogtvpr

# Conflicts:
#	README.md
#	docs/requirements.md
#	threat-model.yaml
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013kCtgLNMjPQYdZpV5gbwUW
@adeelahmad
adeelahmad merged commit 2079b99 into main Oct 18, 2026
20 checks passed
@adeelahmad
adeelahmad deleted the claude/project-thread-ogtvpr branch October 18, 2026 01:04
adeelahmad pushed a commit that referenced this pull request Oct 18, 2026
The threat model workflow's validate job wants a change to threat-model.md to change a companion too (#507): the Kokoro row is documented, so the JSON's documented count goes up by one, as #518 did for Moondream.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH
adeelahmad added a commit that referenced this pull request Oct 18, 2026
…ine (#538)

* feat(voice): read answers and podcasts aloud with Kokoro on this machine

Kokoro v1.0 (hexgrad's Kokoro-82M, Apache-2.0) as a text-to-speech provider, voice.tts_provider "kokoro": spoken
answers and podcast hosts are read on the server's own CPU through kokoro-onnx on ONNX Runtime, in any of its 54
voices across nine languages, with nothing sent anywhere and nothing billed. It's opt-in and fetched once it's picked:
the `kokoro` extra (espeak-ng and phonemizer are GPL-3.0, so they stay out of the default install), and the model
(voice.kokoro_model: fp32, fp16 or int8) and voices files from kokoro-onnx's release, checked against their SHA-256.
Settings → AI assistant → Voice offers it with the model size and the voice picker; a podcast's second host gets a
voice in the first host's language. kokoro.yml fetches and reads with each model on x64 and arm64.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* test(settings): carry ai.auto_title in the Kokoro settings fixture

main's conversation titles (#531) added ai.auto_title to the section the Kokoro settings test renders, so its fixture
names it too; without it Save sent an ai update beside the voice one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(threat-model): count the Kokoro row in the JSON companion

The threat model workflow's validate job wants a change to threat-model.md to change a companion too (#507): the Kokoro row is documented, so the JSON's documented count goes up by one, as #518 did for Moondream.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* fix(voice): offer Kokoro in full precision and 8-bit only

On GitHub's arm64 runner, ONNX Runtime's CPU provider returned an empty waveform for kokoro-onnx's fp16 export, and kokoro-onnx's pause insertion then failed on a zero-size array. On x64 it was no faster than fp32, so voice.kokoro_model is now fp32 (the default) or int8, and the fp16 file is no longer pinned.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* test(settings): carry the research section in the Kokoro settings fixture

Main's deep research (#517) added a research section to Settings › AI assistant, so the fixture carries its defaults and Save sends only the voice change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* test(settings): carry ai.compact_at in the Kokoro settings fixture

Main added ai.compact_at (summarise long conversations early), so the fixture carries its default and Save sends only the voice change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(readme): list answers about Lens itself as built, now that #400 is released

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(changelog): name the Kokoro fragment after its pull request

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(threat-model): count the Kokoro entries against main's newest model

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

* docs(readme): take Kokoro out of In progress, now that it's built

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dzm4YHdHn2qZy7aXer3KeH

---------

Co-authored-by: Adeel Ahmad <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0