Skip to main content

sunra.ai Python Client

English | 简体中文

This is a Python client library for interacting with ML models deployed on sunra.ai.

Community

Join our Discord community to connect with other developers, get help, and stay updated with the latest features and announcements.

Getting Started

To install the client, run:

pip install sunra-client

Before using the client, you'll need to:

  1. Sign up at sunra.ai
  2. Get your API key from the dashboard
  3. Set your API key as an environment variable: export SUNRA_KEY=your-api-key

Configuration

There are two ways to configure your API key:

Method 1: Global Configuration (Recommended)

import sunra_client

# Configure the client with your API key
sunra_client.config(credentials="your-api-key")

# Now you can use the client without passing the key explicitly
response = sunra_client.subscribe(
    "black-forest-labs/flux-kontext-pro/text-to-image",
    arguments={"prompt": "a cute cat, realistic, orange"}
)

Method 2: Environment Variable

Set your API key as an environment variable:

export SUNRA_KEY=your-api-key

Method 3: Explicit Client Configuration

import sunra_client

# Create a client with explicit API key
client = sunra_client.SyncClient(key="your-api-key")

# Or for async client
async_client = sunra_client.AsyncClient(key="your-api-key")

Advanced Configuration

Custom HTTP Client Support

The Python SDK supports custom HTTP clients, allowing you to configure proxies, timeouts, and other HTTP settings. This is useful for enterprise environments or when you need specific network configurations.

Global HTTP Client Configuration

You can configure HTTP clients globally using the config function:

import httpx
import sunra_client

# Create custom HTTP clients with proxy settings
proxy_url = "http://proxy.company.com:8080"

sync_client = httpx.Client(
    proxy=proxy_url,
    timeout=30.0,
    headers={'User-Agent': 'my-app/1.0'}
)

async_client = httpx.AsyncClient(
    proxy=proxy_url,
    timeout=30.0,
    headers={'User-Agent': 'my-app/1.0'}
)

# Configure globally - affects all subsequent API calls
sunra_client.config(
    credentials="your-api-key",
    http_client=sync_client,
    async_http_client=async_client
)

# Now all calls will use the configured HTTP clients
response = sunra_client.subscribe(
    "black-forest-labs/flux-kontext-pro/text-to-image",
    {"prompt": "a beautiful landscape"}
)

# Async calls will use the configured async client
response = await sunra_client.subscribe_async(
    "black-forest-labs/flux-kontext-pro/text-to-image",
    {"prompt": "a beautiful landscape"}
)

Per-Client HTTP Configuration

You can also configure HTTP clients per individual client instance:

import httpx
import sunra_client

# Create a custom HTTP client with specific settings
custom_client = httpx.Client(
    proxy="http://proxy.company.com:8080",
    timeout=60.0,
    verify="/path/to/cert.pem",  # Custom SSL certificate
    headers={'User-Agent': 'my-app/1.0'}
)

# Create Sunra client with custom HTTP client
client = sunra_client.SyncClient(
    key="your-api-key",
    http_client=custom_client
)

# For async clients
async_custom_client = httpx.AsyncClient(
    proxy="http://proxy.company.com:8080",
    timeout=60.0,
    verify="/path/to/cert.pem"
)

async_client = sunra_client.AsyncClient(
    key="your-api-key", 
    http_client=async_custom_client
)

Common HTTP Client Configurations

Proxy Configuration:

import httpx

# HTTP proxy
client = httpx.Client(proxy="http://proxy.example.com:8080")

# HTTPS proxy
client = httpx.Client(proxy="https://proxy.example.com:8080")

# SOCKS proxy
client = httpx.Client(proxy="socks5://proxy.example.com:1080")

Timeout Configuration:

import httpx

# Set custom timeout (in seconds)
client = httpx.Client(timeout=30.0)

# More granular timeout control
client = httpx.Client(
    timeout=httpx.Timeout(
        connect=5.0,    # Time to establish connection
        read=30.0,      # Time to read response
        write=10.0,     # Time to send request
        pool=60.0       # Time to acquire connection from pool
    )
)

SSL/TLS Configuration:

import httpx

# Custom SSL certificate
client = httpx.Client(verify="/path/to/cert.pem")

# Disable SSL verification (not recommended for production)
client = httpx.Client(verify=False)

# Client certificate authentication
client = httpx.Client(cert="/path/to/client-cert.pem")

Connection Limits:

import httpx

# Configure connection pool limits
limits = httpx.Limits(
    max_keepalive_connections=20,
    max_connections=100
)

client = httpx.Client(limits=limits)

For more httpx configuration options, see the httpx documentation.

Usage Examples

Now you can use the client to interact with your models. Here's an example of how to use it:

import sunra_client

response = sunra_client.subscribe(
    "black-forest-labs/flux-kontext-pro/text-to-image",
    arguments={
      "prompt": "a cute cat, realistic, orange"
    },
    with_logs=True,
    on_enqueue=print,
    on_queue_update=print
)
print(response["images"][0]["url"])

Streaming Responses

You can stream real-time updates as your request is being processed:

import sunra_client

application = "black-forest-labs/flux-kontext-pro/text-to-image"
arguments = {"prompt": "a cute cat, realistic, orange"}

for event in sunra_client.stream(application, arguments):
    print(f"Received event: {event}")

Asynchronous Requests

The client also supports asynchronous requests out of the box. Here's an example:

import asyncio
import sunra_client

async def main():
    response = await sunra_client.subscribe_async(
        "black-forest-labs/flux-kontext-pro/text-to-image",
        arguments={"prompt": "a cute cat, realistic, orange"}
        with_logs=True,
        on_enqueue=print,
        on_queue_update=print
    )
    print(response["images"][0]["url"])

asyncio.run(main())

Queuing Requests

When you want to send a request and keep receiving updates on its status, you can use the submit method:

import asyncio
import sunra_client

async def main():
    response = await sunra_client.submit_async(
        "black-forest-labs/flux-kontext-pro/text-to-image",
        arguments={"prompt": "a cute cat, realistic, orange"}
    )

    async for event in response.iter_events():
        if isinstance(event, sunra_client.Queued):
            print("Queued. Position:", event.position)
        elif isinstance(event, (sunra_client.InProgress, sunra_client.Completed)):
            print(event)

    result = await response.get()
    print(result["images"][0]["url"])

asyncio.run(main())

File Upload Support

The client supports uploading files to sunra.ai:

import sunra_client
import io

# It is recommended to configure the client once,
# possibly in a central part of your application.
# This way you won't have to pass the key every time.
sunra_client.config(credentials="your-api-key")


# Upload a file from a local path
# The content type will be inferred from the file extension
file_url = sunra_client.upload_file("path/to/your/image.jpg")

# Upload raw binary data, e.g. from an in-memory image
with open("path/to/your/image.png", "rb") as f:
    image_data = f.read()

data_url = sunra_client.upload(
    data=image_data,
    content_type="image/png",
)

# You can then use the returned URL as input to a model
response = sunra_client.subscribe(
    "black-forest-labs/flux-kontext-pro/image-to-image",
    arguments={
        "image": file_url,
        "prompt": "a cat",
    },
)

File Upload Limits:

  • Maximum file size: 100MB
  • Supported formats: Images, videos, audio, documents, and other file types as supported by the specific model

Automatic Input Transformation

The Python SDK automatically transforms file inputs when you call submit() or subscribe(). This means you can pass various file types directly in your input arguments, and they will be automatically uploaded and replaced with URLs.

Supported Input Types

The SDK automatically handles:

  • PIL Image objects - Automatically uploaded as images
  • Base64 data URIs - Decoded and uploaded with appropriate content type
  • File paths - Local files uploaded to CDN
  • File-like objects - Objects with read() method (e.g., io.BytesIO, open file handles)

Automatic Transformation Example

import sunra_client
from PIL import Image
import io

# It is recommended to configure the client once.
sunra_client.config(credentials="your-api-key")

# Create a sample PIL image
image = Image.new("RGB", (1024, 1024), color="purple")

# You can pass the image directly - it will be automatically uploaded
# and the input will be updated with the returned URL.
response = sunra_client.subscribe(
    "black-forest-labs/flux-kontext-pro/image-to-image",
    arguments={
        "prompt": "A purple square",
        "image": image,  # The SDK will upload this PIL Image
    }
)

Manual Input Transformation

You can also manually transform inputs if needed:

# For async client
async_client = sunra_client.AsyncClient()
transformed = await async_client.transform_input({
    "image": pil_image,
    "files": ["file1.txt", "file2.jpg"],
    "data": data_uri,
    "metadata": {"nested": {"file": "path/to/file.pdf"}}
})

# For sync client
sync_client = sunra_client.SyncClient()
transformed = sync_client.transform_input({
    "image": pil_image,
    "document": "path/to/document.pdf"
})

Nested Object Support

The transformation works recursively on nested objects and arrays:

input_data = {
    "prompt": "Process these images",
    "images": [image1, image2, image3],  # All PIL images will be uploaded
    "settings": {
        "reference": "path/to/reference.jpg",  # Nested file path will be uploaded
        "masks": [mask1_data_uri, mask2_data_uri]  # Nested data URIs will be uploaded
    }
}

# All file inputs will be automatically transformed when submitted.

Example with an actual model:

```python
import sunra_client
from PIL import Image

sunra_client.config(credentials="your-api-key")

# Create a sample PIL image
image = Image.new("RGB", (512, 512), color = 'red')

# All file-like inputs will be automatically transformed when submitted
response = sunra_client.subscribe(
    "black-forest-labs/flux-kontext-pro/image-to-image",
    arguments={
        "prompt": "A red square",
        "image": image,
    }
)

print(response)

Error Handling

The client provides comprehensive error handling with detailed error information:

import sunra_client

try:
    response = sunra_client.subscribe(
        "black-forest-labs/flux-kontext-pro/text-to-image",
        arguments={
            "prompt": "a cute cat, realistic, orange",
            "seed": -2  # Invalid seed (should be >= 0)
        },
        with_logs=True,
        on_enqueue=print,
        on_queue_update=print
    )
    print(response["images"][0]["url"])
    
except sunra_client.SunraClientError as e:
    print(f"Error: {e}")
    
    # Access detailed error information
    print(f"Error Code: {e.code}")           # e.g., "invalid_input"
    print(f"Error Message: {e.message}")     # e.g., "Validation error: seed must be >= 0"
    print(f"Reason: {e.reason}")             # e.g., "input_validation_failed", or None
    print(f"Retryable: {e.retryable}")       # True / False, or None if the API gave no answer
    print(f"Error Details: {e.details}")     # Additional error details
    print(f"Timestamp: {e.timestamp}")       # When the API responded

Deciding whether to retry

Read e.retryable. It answers exactly one question — would submitting this identical request again have a different outcome? — and it is independent of e.code: the same code can be retryable in one failure and not in another.

except sunra_client.SunraClientError as e:
    if e.retryable is True:
        schedule_retry()
    elif e.retryable is False:
        report_to_user(e.message)   # retrying will not help; fix the input
    else:
        # The API published no verdict (an older prediction, or a failure it
        # never classified). Fall back to the per-code default documented at
        # https://platform.sunra.ai/platform/errors — never derive a verdict
        # from `e.code` yourself.
        fall_back_to_per_code_default(e.code)

e.reason names the specific cause behind e.code (input_fetch_failed, moderation_blocked, provider_rate_limited, …). Both code and reason are open sets: new values ship without a breaking-change announcement, so treat a reason you do not recognise as absent and an unknown code as internal_server_error, and log the raw value.

Two timestamps, two envelopes

For a prediction that failed, e.timestamp is when the API produced the error response, while e.prediction_error["timestamp"] is when the prediction itself failed — for a prediction fetched days later, these are days apart. Read e.prediction_error whenever you mean the failure:

except sunra_client.SunraClientError as e:
    if e.prediction_error:
        print(e.prediction_error["code"])       # "unsafe_content"
        print(e.prediction_error["reason"])     # "moderation_blocked"
        print(e.prediction_error["timestamp"])  # when the prediction failed

Error Types

The client handles different types of errors:

Validation Errors (from model processing):

try:
    response = sunra_client.subscribe(
        "black-forest-labs/flux-kontext-pro/text-to-image",
        arguments={"prompt": "test", "seed": -1}  # Invalid seed
    )
except sunra_client.SunraClientError as e:
    # e.code: "invalid_input"
    # e.reason: "input_validation_failed"
    # e.retryable: False
    # e.message: "Validation error: seed must be >= 0"
    pass

HTTP Errors (from API requests):

try:
    response = sunra_client.subscribe(
        "non-existent-model/endpoint",
        arguments={"prompt": "test"}
    )
except sunra_client.SunraClientError as e:
    # e.code: "Bad Request"
    # e.message: "Model endpoint is required"
    # e.timestamp: "2025-01-16T12:00:00.000Z"
    pass

Conditional Error Handling:

try:
    response = sunra_client.subscribe("model/endpoint", arguments={})
except sunra_client.SunraClientError as e:
    if e.code == "invalid_input":
        print("Please check your input parameters")
    elif e.code == "Bad Request":
        print("Invalid API request")
    else:
        print(f"Unexpected error: {e}")

Credits

This project is derived from:

and adapted to work with sunra.ai. The original projects are licensed under the MIT/Apache 2.0 License. We extend our gratitude to the original authors for their contributions.

Release files for sunra-client 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sunra-client 0.6.0
File Size Uploaded
sunra_client-0.6.0.tar.gz 23.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sunra-client 0.6.0
File Interpreter ABI Platform
sunra_client-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 40.2 kB

Release files / sunra_client-0.6.0.tar.gz

Download URL sunra_client-0.6.0.tar.gz
Size 23.2 kB
Tags Source
SHA-256 checksum
How to use checksums
3094ae5b3acd69fc861d818e456300608c9995c1ee99df88fb838b33f04ce097
BLAKE2b-256 checksum
How to use checksums
1f3195ece6253b81502985644433f321999f25f571476c4c58bd583e8dccf2ee
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / sunra_client-0.6.0-py3-none-any.whl

Download URL sunra_client-0.6.0-py3-none-any.whl
Size 17.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a2ecd3816491e63f980afbd3335af42de5db844719dc6982f392ceb9d5d52351
BLAKE2b-256 checksum
How to use checksums
cf2973882f4633f9f9ac6304584b25f77184edfe1940a6f1436c77e7f250905b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page