Multimodal Microservice Embedder

February 19, 2026 ยท View on GitHub

The Multimodal Microservice Embedder generates embeddings for both text and images via an external microservice. It works with any embedding service that implements the standard API, enabling cross-modal similarity search where text and image embeddings exist in the same vector space.

Features

  • Cross-modal search: Find images similar to text queries and vice versa
  • Model-agnostic: Works with any embedding service implementing the standard API
  • Configurable dimensions: Support for different embedding models and vector sizes
  • Batch processing: Embed multiple texts (up to 100) or images (up to 20) in one request
  • Cloud Run IAM auth: Optional Google Cloud Run authentication

Configuration

Configure the embedder via environment variables:

Service Connection

# Option 1: Set host and port separately (recommended)
MULTIMODAL_EMBEDDER_HOST=multimodal-embedder  # Service hostname (default)
MULTIMODAL_EMBEDDER_PORT=8000                  # Service port (default)

# Option 2: Set full URL directly (overrides host:port)
MULTIMODAL_EMBEDDER_URL=http://multimodal-embedder:8000

Vector Dimensions

The vector size must match the embedding model used by your microservice:

# Default (768) - works with CLIP ViT-L-14, many transformer models
MULTIMODAL_EMBEDDER_VECTOR_SIZE=768

# Other common dimensions
MULTIMODAL_EMBEDDER_VECTOR_SIZE=512   # CLIP ViT-B-32, smaller models
MULTIMODAL_EMBEDDER_VECTOR_SIZE=1024  # Larger models
MULTIMODAL_EMBEDDER_VECTOR_SIZE=1536  # OpenAI-compatible models

Authentication

# API key for the microservice (optional)
MULTIMODAL_EMBEDDER_API_KEY=your-api-key

Embedding Weights

When combining text and image embeddings for multimodal annotations:

# Weight for text component (default: 0.3)
MULTIMODAL_TEXT_WEIGHT=0.3

# Weight for image component (default: 0.7)
MULTIMODAL_IMAGE_WEIGHT=0.7

Example Configurations

Local Docker Compose (Default)

No configuration needed - uses defaults:

  • Host: multimodal-embedder
  • Port: 8000
  • Vector size: 768

External Cloud Service

MULTIMODAL_EMBEDDER_HOST=embeddings.example.com
MULTIMODAL_EMBEDDER_PORT=443
MULTIMODAL_EMBEDDER_URL=https://embeddings.example.com
MULTIMODAL_EMBEDDER_VECTOR_SIZE=768
MULTIMODAL_EMBEDDER_API_KEY=sk-your-api-key

Google Cloud Run

MULTIMODAL_EMBEDDER_URL=https://embedder-abc123-uc.a.run.app
MULTIMODAL_EMBEDDER_VECTOR_SIZE=768
# IAM auth is auto-detected for Cloud Run URLs

Custom Model with Different Dimensions

# Using a model with 512-dimensional embeddings
MULTIMODAL_EMBEDDER_VECTOR_SIZE=512

API Specification

Any microservice implementing these endpoints will work with the embedder:

EndpointMethodDescriptionRequestResponse
/embeddingsPOSTSingle text{"text": "..."}{"embeddings": [[...]]}
/embeddings/imagePOSTSingle image{"image": "<base64>"}{"embeddings": [[...]]}
/embeddings/batchPOSTBatch text (max 100){"texts": [...]}{"embeddings": [[...], ...]}
/embeddings/image/batchPOSTBatch images (max 20){"images": [...]}{"embeddings": [[...], ...]}

Response Format

All endpoints return embeddings in the same format:

{
  "embeddings": [
    [0.123, -0.456, 0.789, ...]  // Vector of configured dimension
  ]
}

For batch endpoints, the array contains one vector per input item.

Usage in Code

from opencontractserver.pipeline.embedders.multimodal_microservice import (
    CLIPMicroserviceEmbedder
)

embedder = CLIPMicroserviceEmbedder()

# Check configured vector size
print(f"Vector size: {embedder.vector_size}")

# Text embedding
text_vector = embedder.embed_text("contract clause about payment terms")

# Image embedding (base64-encoded)
image_vector = embedder.embed_image(base64_image_data)

# Batch operations
text_vectors = embedder.embed_texts_batch(["text1", "text2", "text3"])
image_vectors = embedder.embed_images_batch([base64_img1, base64_img2])

Error Handling

The embedder distinguishes between retriable and non-retriable errors:

Error TypeHTTP StatusBehavior
Client error4xxNot retried (invalid input)
Server error5xxRetried with backoff
Timeout-Not retried
Connection error-Not retried

Timeouts

  • Single text/image: 30 seconds
  • Batch text: 60 seconds
  • Batch images: 120 seconds

Supported File Types

  • PDF
  • TXT
  • DOCX

Building a Compatible Microservice

To build your own embedding microservice, implement the four endpoints above. Example using FastAPI:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class TextRequest(BaseModel):
    text: str

class ImageRequest(BaseModel):
    image: str  # base64

@app.post("/embeddings")
def embed_text(req: TextRequest):
    vector = your_model.encode_text(req.text)
    return {"embeddings": [vector.tolist()]}

@app.post("/embeddings/image")
def embed_image(req: ImageRequest):
    vector = your_model.encode_image(req.image)
    return {"embeddings": [vector.tolist()]}

# ... batch endpoints similarly

See Also