vision

package
v0.10.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 31, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package vision turns images into searchable text: a vision LLM describes an image, and the resulting title/description/transcription is indexed as ordinary markdown by every backend (full-text, vector, metadata filtering).

The package is deliberately independent of the ingestion pipeline: it is used by convert/vision to index standalone image files, and by the markdown enrichment of embedded images. Callers pass an llm.Client already decorated with llmx.NewRetryClient (retry + rate limit), exactly as the HyDE and Judge retrieval stages do.

Index

Constants

View Source
const DefaultMaxImageBytes int64 = 10 << 20 // 10 MiB

DefaultMaxImageBytes bounds, by default, the size of an image submitted to the vision model. Providers reject oversized payloads anyway, and the base64 encoding inflates the request by a third.

View Source
const DefaultPrompt = `` /* 201-byte string literal not displayed */

DefaultPrompt asks for a dense, factual description. The description is what gets indexed and searched, so it must be rich in the vocabulary a user would actually type: named entities, object names, chart values, UI labels.

It is deliberately terse, and the detailed field requirements live in descriptionSchema instead. Spelling them out here made an OCR-specialized model (glm-ocr) — whose instinct is to transcribe whatever text it is handed — copy the instructions themselves into the answer, which would then have been indexed verbatim for every image. Keep any change to this prompt short and free of enumerations, and re-run the vision integration test: it asserts that no fragment of the prompt comes back in the answer.

View Source
const MaxTitleRunes = 120

MaxTitleRunes is the length beyond which a "title" is not one. The title becomes the heading of the emitted markdown, so a model answering with a whole paragraph — or with the instructions it was given — must not turn it into a monstrous `#` line.

View Source
const PromptVersion = "1"

PromptVersion identifies the default prompt. It participates in the cache key (see CachingDescriber): bump it whenever DefaultPrompt changes, so descriptions produced by an older prompt are not served from the cache.

Variables

View Source
var ErrImageTooLarge = errors.New("image too large")

ErrImageTooLarge is returned when an image exceeds the configured size limit. It is returned *before* any call to the model.

Functions

func Namespace

func Namespace(model, prompt string) string

Namespace derives a cache namespace identifying both the vision model and the prompt it was given: two descriptions may only share a cache entry when both match. Pass it to NewCachingDescriber.

Types

type CachingDescriber

type CachingDescriber struct {
	// contains filtered or unexported fields
}

CachingDescriber decorates a Describer with a persistent on-disk cache keyed by the *content* of the image — sha256(promptVersion, namespace, bytes) — sharded on the first hex byte below dir/vision, the same layout as llmx.CachingClient.

A dedicated cache is required: llmx.CachingClient deliberately refuses to cache any chat completion carrying an attachment (serializing the image into a JSON key would be wasteful), so vision calls would otherwise never be cached. Keying on the bytes rather than on the file path also means a renamed, moved or duplicated image is described only once, and a full re-index costs nothing.

The namespace must identify the vision model *and* its prompt — build it with Namespace(model, prompt) — otherwise switching model would serve descriptions produced by the previous one.

func NewCachingDescriber

func NewCachingDescriber(describer Describer, dir, namespace string) (*CachingDescriber, error)

NewCachingDescriber wraps describer with a cache rooted at dir (created if missing), keyed under namespace.

func (*CachingDescriber) Describe

func (c *CachingDescriber) Describe(ctx context.Context, mimeType string, data []byte) (*Description, error)

Describe implements Describer.

func (*CachingDescriber) MaxImageBytes

func (c *CachingDescriber) MaxImageBytes() int64

MaxImageBytes reports the limit of the wrapped describer, when it exposes one, so the decorator stays transparent to size-aware callers.

func (*CachingDescriber) Stats

func (c *CachingDescriber) Stats() (hits, misses int64)

Stats returns the number of cache hits and misses served so far.

type Describer

type Describer interface {
	Describe(ctx context.Context, mimeType string, data []byte) (*Description, error)
}

Describer produces a textual description of an image.

type Description

type Description struct {
	// Title is a short, one-line title for the image.
	Title string `json:"title"`
	// Description is the detailed markdown description: content, context,
	// notable elements, data of charts and diagrams.
	Description string `json:"description"`
	// Text is the text visible in the image, transcribed verbatim (implicit
	// OCR). Empty when the image carries no text.
	Text string `json:"text"`
}

Description is the structured result of describing an image.

func (*Description) IsEmpty

func (d *Description) IsEmpty() bool

IsEmpty reports whether the description carries no usable text at all.

type LLMDescriber

type LLMDescriber struct {
	// contains filtered or unexported fields
}

LLMDescriber describes images with a vision-capable chat model.

func NewLLMDescriber

func NewLLMDescriber(client llm.Client, funcs ...OptionFunc) *LLMDescriber

NewLLMDescriber builds a Describer on top of client, which must be a vision-capable chat model and is expected to be already decorated with llmx.NewRetryClient by the caller.

func (*LLMDescriber) Describe

func (d *LLMDescriber) Describe(ctx context.Context, mimeType string, data []byte) (*Description, error)

Describe implements Describer.

func (*LLMDescriber) MaxImageBytes

func (d *LLMDescriber) MaxImageBytes() int64

MaxImageBytes reports the configured image size limit, so callers can bound their reads before handing over the bytes.

func (*LLMDescriber) Prompt

func (d *LLMDescriber) Prompt() string

Prompt reports the effective description prompt (used to derive the cache namespace).

type OptionFunc

type OptionFunc func(opts *Options)

func WithMaxImageBytes

func WithMaxImageBytes(maxBytes int64) OptionFunc

WithMaxImageBytes bounds the size of an accepted image; <= 0 keeps the default (DefaultMaxImageBytes).

func WithPrompt

func WithPrompt(prompt string) OptionFunc

WithPrompt replaces the default description prompt. A custom prompt must be reflected in the cache namespace (see Namespace).

func WithStructuredOutput

func WithStructuredOutput(enabled bool) OptionFunc

WithStructuredOutput toggles the JSON response schema.

type Options

type Options struct {
	Prompt string
	// MaxImageBytes is the largest image accepted; above it Describe fails
	// with ErrImageTooLarge without calling the model.
	MaxImageBytes int64
	// StructuredOutput requests a JSON response matching Description. Disable
	// it for providers that reject a response schema; the whole reply then
	// lands in Description.
	StructuredOutput bool
}

Options configures an LLMDescriber.

func NewOptions

func NewOptions(funcs ...OptionFunc) *Options

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL