> For clean Markdown of any page, append `.md` to the page URL.
> For a complete documentation index, see https://docs.sarvam.ai/llms.txt.
> For full documentation content in one file, see https://docs.sarvam.ai/llms-full.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.sarvam.ai/_mcp/server.

# Deploy Sarvam Vision

> Deploy the Sarvam Vision document-intelligence model on Amazon SageMaker — real-time, async, and batch — from your AWS Marketplace subscription. OCR and parse PDFs and images across 23 languages.

Deploy **Sarvam Vision** — a 3B-parameter document-intelligence model — as a SageMaker endpoint in your own account. It performs OCR and document parsing (tables, layout, reading order) across 23 languages and returns clean **HTML or Markdown**. The full, runnable notebook lives in [`sarvamai/amazon-sagemaker-examples`](https://github.com/sarvamai/amazon-sagemaker-examples/tree/main/vision/ocr3b).

## Prerequisites

Complete [Get started on SageMaker](/api/self-hosted/sagemaker/get-started): subscribe to the [Sarvam Vision listing](https://aws.amazon.com/marketplace/pp/prodview-exwi6jgzqsqc2), copy your **model package ARN**, and have an **execution role ARN** ready.

## 1. Configure

```python Configuration
import boto3

region = boto3.Session().region_name
role   = "arn:aws:iam::<account>:role/<your-sagemaker-execution-role>"
model_package_arn = "arn:aws:sagemaker:<region>:<vendor>:model-package/<vision-package-id>"

realtime_instance = "ml.g6e.xlarge"   # real-time / async (recommended default: ~2 concurrent docs)
batch_instance    = "ml.g6.xlarge"    # batch
endpoint_name     = "sarvam-vision"

sm      = boto3.client("sagemaker", region_name=region)
runtime = boto3.client("sagemaker-runtime", region_name=region)
```

## 2. Deploy a real-time endpoint

#### Create the model (network isolation on)

```python
sm.create_model(
    ModelName=endpoint_name,
    PrimaryContainer={"ModelPackageName": model_package_arn},
    ExecutionRoleArn=role,
    EnableNetworkIsolation=True,
)
```

#### Create the endpoint config and endpoint

```python
sm.create_endpoint_config(
    EndpointConfigName=endpoint_name,
    ProductionVariants=[{
        "VariantName": "AllTraffic",
        "ModelName": endpoint_name,
        "InstanceType": realtime_instance,
        "InitialInstanceCount": 2,   # >= 2 for production (survives an instance/AZ loss)
        # the ~6 GB model loads in 60-120 s; give startup room or the endpoint fails
        "ContainerStartupHealthCheckTimeoutInSeconds": 900,
        "ModelDataDownloadTimeoutInSeconds": 1200,
    }],
)
sm.create_endpoint(EndpointName=endpoint_name, EndpointConfigName=endpoint_name)
sm.get_waiter("endpoint_in_service").wait(EndpointName=endpoint_name)
```

## 3. Invoke it

Send a **single PDF**, individual **PNG/JPG** page images, or a flat **ZIP** of page images as the request body, with a `Content-Type` that matches the bytes. Pass options — `language`, `output_format` (`md`/`html`/`json`), `filename` — as **custom attributes**. The full request and response contract is in the [API reference](/api/self-hosted/sagemaker/api-vision).

```python Invoke
import json

with open("invoice.pdf", "rb") as f:
    resp = runtime.invoke_endpoint(
        EndpointName=endpoint_name,
        ContentType="application/pdf",                      # must match the bytes
        Accept="application/json",
        CustomAttributes="language=hi-IN,output_format=md,filename=invoice.pdf",
        Body=f.read(),
    )

body = json.loads(resp["Body"].read())
print(body["result"]["text"])   # merged document text, structure preserved
```

**Sync is for small documents at low concurrency — prefer [async](#prefer-async-for-documents) for everything else.** Every sync request must finish inside AWS's hard **60-second** `InvokeEndpoint` timeout, so keep sync documents to **5 pages or fewer** (the container hard-caps any document at **500 pages** → `413`). Send multi-page or bursty work to async or batch.

### Concurrency

Because each sync request must finish inside the 60-second timeout, an instance serves a bounded number of documents at once. That capacity scales with the **`ml.g6e`** instance size — a document fans out across the instance's GPUs. See the [recommended instances and concurrency table](/api/self-hosted/sagemaker/get-started#recommended-instances) for the per-instance numbers.

Send more concurrent documents than the instance can handle and requests queue past 60 seconds and time out. For heavy, bursty, or high-concurrency workloads, size up the `ml.g6e` instance or — better — use **async** (below), which queues work and never hits the sync timeout.

## Prefer async for documents

Async is the **recommended path for almost all document workloads**. It queues requests, supports payloads up to **50 MB** and minutes-long processing, scales to zero when idle, and never hits the 60-second sync timeout.

Async is **not automatic** — it's a deploy-time choice. Add an `AsyncInferenceConfig` (with an S3 output path) to the endpoint configuration, grant the execution role S3 access, then invoke with `invoke_endpoint_async`.

```python
sm.create_endpoint_config(
    EndpointConfigName=endpoint_name,
    ProductionVariants=[{
        "VariantName": "AllTraffic", "ModelName": endpoint_name,
        "InstanceType": realtime_instance, "InitialInstanceCount": 1,
    }],
    AsyncInferenceConfig={
        "OutputConfig": {"S3OutputPath": "s3://<your-bucket>/vision/out/"},
    },
)
```

* **Async** — submit a job and read the result from S3 when ready; supports large documents, high concurrency, and scale-to-zero.
* **Batch transform** — process a whole S3 prefix of documents in one job, then shut the instances down.

Reserve **sync** for small, latency-sensitive, one-off documents at low concurrency; send everything else to async or batch. Both use the same model package — see [Operations](/api/self-hosted/sagemaker/operations) for autoscaling and sizing.

## Clean up

```python Cleanup
sm.delete_endpoint(EndpointName=endpoint_name)
sm.delete_endpoint_config(EndpointConfigName=endpoint_name)
sm.delete_model(ModelName=endpoint_name)
```