> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runanywhere.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Vision Language Models

> Ask a model about an image

```ts theme={null}
import { RunAnywhere, ImageInputs } from '@runanywhere/core'

const result = await RunAnywhere.vlm.generate(ImageInputs.file(path), 'What is in this photo?')

console.log(result.text)
```

## Signatures

```ts theme={null}
generate(image: ImageInput, prompt: string, options?: LlmOptions): Promise<GenerationResult>
generateStream(image: ImageInput, prompt: string, options?: LlmOptions): AsyncIterable<GenerationEvent>
```

## Building an ImageInput

<Note>
  The constructors are exported as `ImageInputs`, **plural**. Every other SDK names this singular,
  so copied examples will not resolve.
</Note>

```ts theme={null}
ImageInputs.file(path: string)
ImageInputs.bytes(data: Uint8Array)
ImageInputs.base64(value: string)
ImageInputs.rawRgb(data: Uint8Array, width: number, height: number)
ImageInputs.rawRgba(data: Uint8Array, width: number, height: number)
```

## From the image picker

```tsx theme={null}
import * as ImagePicker from 'expo-image-picker'

async function describe(): Promise<void> {
  const result = await ImagePicker.launchImageLibraryAsync({ base64: true })
  if (result.canceled) return

  const asset = result.assets[0]
  const image = asset.base64 ? ImageInputs.base64(asset.base64) : ImageInputs.file(asset.uri)

  const answer = await RunAnywhere.vlm.generate(image, 'Describe this image in one sentence.')

  setCaption(answer.text)
}
```

`base64` avoids a filesystem round trip, which matters on iOS where the picker hands you a
sandboxed URI.

## From the camera

```tsx theme={null}
const inFlight = useRef(false)

const onFrame = useCallback(async (uri: string) => {
  if (inFlight.current) return
  inFlight.current = true

  try {
    const result = await RunAnywhere.vlm.generate(ImageInputs.file(uri), 'What do you see?')
    setCaption(result.text)
  } finally {
    inFlight.current = false
  }
}, [])
```

Throttle it. A VLM pass costs far more than a camera frame interval, so run one at a time and
drop frames that arrive while a pass is in flight. Without the `inFlight` guard the queue grows
until the app runs out of memory.

## Streaming

```ts theme={null}
for await (const event of RunAnywhere.vlm.generateStream(image, 'Describe this in detail.')) {
  if (event.type === 'textDelta') setCaption((c) => c + event.text)
}
```

Buffer these on an interval rather than calling `setState` per token.

## Options

`vlm` takes the same `LlmOptions` as `llm`, so `maxOutputTokens`, `temperature`, and
`systemPrompt` all apply. Cap the output: a caption does not need 300 tokens.

## Models

VLM runs on the llama.cpp backend, so the model must be a GGUF vision model with its projector.
Install `@runanywhere/llamacpp` and pick a VLM entry from the catalog.

Vision models are larger than text models of the same parameter count, because the projector
ships alongside. Check the download size before offering one on cellular.
