md2star.preprocessing.alt_text module

Opt-in alt-text drafting for empty image alts via a local Ollama vision model.

Gated by the same --lint flag as md2star.preprocessing.lint:

  • No flag, or --no-lint → skip the pass entirely.

  • --lint + Ollama installed → describe each ![](src) whose alt is

    empty and whose src resolves to a readable local file; URLs / data URIs / missing files / non-empty alts pass through untouched.

  • --lint + Ollama missing → quiet skip (the lint pass already

    printed the install hint).

Language + context (aligned with the suite’s front-vision skill):

  • The alt text is written in the document’s own language, auto-detected from the surrounding prose (any language, not a hardcoded EN/FR toggle) — a French document gets French alt text. English is the fallback when detection fails.

  • Each image’s surrounding text (nearest heading + nearby prose) is passed to the model so it describes what the image means in place, not just its pixels.

The vision model is chosen by the suite’s model picker, best_engine_ai_helper.vision_model() — the VLM selected by best-engine-ai-helper pull for this machine, or a safe multimodal default (qwen3-vl:8b) when detection has never run. Override with MD2STAR_ALT_TEXT_MODEL.

Per-image results are cached in $XDG_CACHE_HOME/md2star/alt-text/ keyed by <image-md5>_<model>_<lang+context-hash>.txt so a re-run in a different language or surrounding context re-drafts rather than serving a stale caption.

Like the text lint, the transport is transparent: the md2star[ai] extra routes through the official ollama client, and its absence falls back to a hand-rolled urllib.request POST with no change in behaviour.

Author

[Warith HARCHAOUI](https://linkedin.com/in/warith-harchaoui/)

md2star.preprocessing.alt_text.fill_empty_alt_text(content, base_dir='.', model=None)[source]

Replace ![](src) empty-alt images with an LLM-generated description.

Mirrors md2star.preprocessing.lint.lint_with_llm()’s safety net: if Ollama is missing, the daemon is unreachable, the vision model is not pulled (and cannot be pulled), or the request fails, the original content is returned unchanged. The pass is never load-bearing.

Parameters:
  • content (str)

  • base_dir (str)

  • model (str | None)

Return type:

str