Skip to main content

Vision: Analyzing Images with AI

Send images to vision-capable models for analysis, description, and understanding. This example shows how to analyze an image from a URL using GPT-4o with high detail processing for better accuracy.
Response includes detailed image analysis:

Image Generation: Generating Images with AI

Generate images from text prompts using OpenAI-compatible image generation models.

Basic Image Generation

Generate an image from a text prompt using dall-e-3.
Response format:

Audio Understanding: Analyzing Audio with AI

If your chat application supports text input, you can add audio input and output-just include audio in the modalities array and use an audio model, like gpt-4o-audio-preview.

Audio Input to Model

Audio Output from Model

Text-to-Speech: Converting Text to Audio

Convert text into natural-sounding speech using AI voice models. This example demonstrates generating an MP3 audio file from text using the “alloy” voice. The result is returned as binary audio data.
Save audio to file:

Speech-to-Text: Transcribing Audio Files

Convert audio files into text using AI transcription models. This example shows how to transcribe an MP3 file using OpenAI’s Whisper model, with an optional context prompt to improve accuracy.
Response format:

Advanced Vision Examples

Multiple Images

Send multiple images in a single request for comparison or analysis. This is useful for comparing products, analyzing changes over time, or understanding relationships between different visual elements.

Base64 Images

Process local images by encoding them as base64 data URLs. This approach is ideal when you need to analyze images stored locally on your system without uploading them to external URLs first.

Audio Configuration Options

Voice Selection for Speech Synthesis

OpenAI provides six distinct voice options, each with different characteristics:
  • alloy - Balanced, natural voice
  • echo - Deep, resonant voice
  • fable - Expressive, storytelling voice
  • onyx - Strong, confident voice
  • nova - Bright, energetic voice
  • shimmer - Gentle, soothing voice

Audio Formats

Generate audio in different formats depending on your use case. MP3 for general use, Opus for web streaming, AAC for mobile apps, and FLAC for high-quality audio applications.

Transcription Options

Language Specification

Improve transcription accuracy by specifying the source language. This is particularly helpful for non-English audio or when the audio contains technical terms or specific domain vocabulary.

Response Formats

Choose between simple text output or detailed JSON responses with timestamps. The verbose JSON format provides word-level and segment-level timing information, useful for creating subtitles or analyzing speech patterns.

Multimodal Embeddings

Bifrost supports multimodal embeddings — generating vector representations that capture text, images, audio, video, and documents together. POST /v1/embeddings accepts every shape it always did (a string, an array of strings, token arrays) plus a multimodal form where each entry in input is an array of typed parts. All the parts in one entry produce one vector.

Content parts

Every media part is the same object: Validation runs before plugins and before the provider is called: each part must set exactly one modality, a media part must set exactly one of data or url, and an empty entry returns 400.

Request parameters

These top-level fields apply to every entry unless an entry overrides them (see Per-Item Parameters): Any other top-level field (for example Cohere’s input_type, Nova’s embeddingMode, or Gemini’s embedContentConfig) is forwarded to the provider as-is. encoding_format: "base64" works on every provider. Where the model has a native base64 output (OpenAI, Cohere Embed v4) it is forwarded; everywhere else Bifrost encodes the float vector as little-endian float32 base64, the same layout OpenAI uses.

Response fields

Each entry in data has index, object and embedding, plus three optional fields that are present only when a provider needs them:

Provider support

A part the target model cannot carry returns 400 naming the modality. Bifrost never drops a part silently.

Text Embedding (all providers)

The simplest form — pass a string or array of strings directly in input:

Gemini

gemini-embedding-2-preview accepts text, image, audio, video and file (PDF) parts, in any combination, in one entry. gemini-embedding-001 is text-only.
For PDFs, use the file part type:
How Gemini receives media:
  • Inline data is sent as inlineData.
  • A url is sent as fileData.fileUri. The Gemini API only resolves Files API URIs (https://generativelanguage.googleapis.com/v1beta/files/...) there, so upload large media first or send it inline. gs:// URIs are rejected with 400 on the Gemini provider; use Vertex for Cloud Storage media.
  • Multiple entries are sent as one :batchEmbedContents call, and task_type / title are applied to every entry. This is also the only provider that honours per-item params.
  • documentOcr and audioTrackExtraction go under embedContentConfig, the only place Gemini accepts them:
Token usage comes from Gemini’s usageMetadata.

Vertex AI

Vertex has three embedding APIs, and Bifrost picks the right one from the model name. Project and region come from the Vertex key configuration, not the request body.

gemini-embedding-2-preview on Vertex

Everything in the Gemini section applies, with one addition: gs:// URIs are accepted on image, audio, video and file parts, because Vertex resolves Cloud Storage itself. https:// URLs work when Vertex can fetch them; prefer gs:// for anything large.

multimodalembedding@001

This model returns a separate 1408-dimension vector per modality, all in the same embedding space. Image and video URLs must be gs://; inline base64 data URIs are also accepted.
Response contains one vector per modality:
Video is embedded as a sequence of segments. Add a video_config to the video part:
Each segment arrives as its own entry carrying a video_segment:
dimensions maps to the model’s parameters.dimension. This model does not report token usage, so usage is null.

Cohere

Cohere’s API has three mutually exclusive input fields, and Bifrost picks one from the content:
  • Images must be inline. Pass a data URI in url or data, or raw base64 in data with mime_type set; Cohere does not fetch remote URLs.
  • input_type defaults to search_document and is forwarded when set.
  • encoding_format maps to Cohere’s embedding_types unless you pass embedding_types yourself. When Cohere returns several representations for one input, each is a separate data entry labelled with its encoding_format.
  • Image inputs bill on Cohere’s image counter, surfaced as usage.prompt_tokens_details.image_tokens and counted into total_tokens, not prompt_tokens.
The drop-in /cohere/v2/embed route accepts Cohere’s native texts / images / inputs body for any provider and returns Cohere’s native envelope (embeddings, response_type: "embeddings_by_type", meta.billed_units).

Bedrock

Bedrock embedding models are routed by family, and each family has its own wire format and constraints.

Titan

amazon.titan-embed-image-v1 accepts one entry with text and at most one image. The image must be inline in the data field (a data URI or raw base64); Titan cannot fetch URLs, so a url returns 400.
  • dimensions (256, 384 or 1024) maps to embeddingConfig.outputEmbeddingLength.
  • The text models amazon.titan-embed-text-v1 and v2:0 take one entry per request; a batch returns 400 rather than being collapsed into one vector. encoding_format: "binary" is forwarded as Titan’s embeddingTypes on v2.

Cohere on Bedrock

cohere.embed-english-v3, cohere.embed-multilingual-v3 and cohere.embed-v4 follow the same texts[] / images[] / inputs[] selection as direct Cohere, with one Bedrock-specific rule: Embed v3 only accepts images[] when input_type is image. Image-only requests therefore go out as images[] with input_type defaulting to image, which both v3 and v4 accept. A caller-supplied input_type is always kept. Mixed text + image entries use inputs[] and need Embed v4.

Amazon Nova

amazon.nova-2-multimodal-embeddings-v1:0 embeds text, image, audio or video, one modality per entry and one entry per request. Mixing modalities returns 400.
  • Sources: inline data, or an s3://bucket/key URL that Nova reads directly. Any other URL returns 400.
  • Format: Nova requires a declared format per media part and checks it against the bytes. Bifrost derives it from mime_type, or from the S3 key’s extension, and returns 400 when it cannot. Supported: png, jpeg, webp, gif images; mp3, wav, ogg audio; mp4, mov, mkv, webm, flv, mpeg, wmv, 3gp video (sent to AWS as three_gp).
  • task_type maps to embeddingPurpose: GENERIC_INDEX (default), GENERIC_RETRIEVAL, TEXT_RETRIEVAL, IMAGE_RETRIEVAL, VIDEO_RETRIEVAL, AUDIO_RETRIEVAL, DOCUMENT_RETRIEVAL, CLASSIFICATION, CLUSTERING.
  • dimensions: 256, 384, 1024 or 3072 (default).
  • Nova-specific top-level fields: truncationMode (END default, START, NONE), detailLevel (STANDARD_IMAGE default, DOCUMENT_IMAGE for text-heavy pages; image parts only), embeddingMode (video only, below).
Video returns one audio_video vector by default. Set embeddingMode to AUDIO_VIDEO_SEPARATE to get an audio vector and a video vector from one input:
Nova and Cohere-on-Bedrock report token usage only in a response header, which Bifrost reads into usage. The native /bedrock/model/{modelId}/invoke route accepts Titan (inputText + inputImage), Nova (SINGLE_EMBEDDING) and Cohere (texts / images / inputs) bodies and returns each family’s own envelope.

OpenAI-compatible providers

OpenAI, Azure OpenAI, Mistral, Parasail and every other provider that speaks the OpenAI embeddings dialect accept text and tokens parts only, and the two cannot be mixed in one request. Only encoding_format and dimensions are sent on the wire; task_type, title and auto_truncate are not part of the OpenAI format and are not forwarded.

Per-Item Parameters

Every entry in input may instead be an object carrying its own params, which override the request-level ones for that entry alone. Use it when the items need different parameters — a query embedded with RETRIEVAL_QUERY alongside documents embedded with RETRIEVAL_DOCUMENT, say. Plain entries and entries with params can be mixed freely.
An item’s params replaces the request-level params rather than merging field by field, so repeat any request-level value you still want (as dimensions is repeated above).
Only providers whose wire format has one parameter block per item can honour this — currently Gemini (:batchEmbedContents). Everything else returns a 400 naming the offending item index rather than silently ignoring the override and returning a correct-looking but wrong vector.
Requests arriving on the GenAI drop-in routes (:embedContent, :batchEmbedContents) get the reverse treatment: when every requests[] entry carries the same taskType / outputDimensionality, those are hoisted to request level so the call works against non-Gemini providers too.

Things to know

  • Token usage is uneven across multimodal models. Vertex multimodalembedding@001 returns usage: null, Titan image-only inputs report zero tokens, and Cohere image tokens live under prompt_tokens_details. Budgets and cost metered on prompt_tokens do not see those inputs.
  • Semantic cache keys include task_type, title and auto_truncate, so a RETRIEVAL_QUERY request is never served a cached RETRIEVAL_DOCUMENT vector.
  • Logs store the full input in a dedicated embedding_input column and render it in the log detail view. Inline media above the large-payload threshold is redacted.
Check the Supported Providers page for more information on multimodal capabilities supported by each provider.

Next Steps

Now that you understand multimodal capabilities, explore these related topics:

Essential Topics

Advanced Topics