# Python Client

> FlyMy.AI Models Python SDK: install, authenticate, predict synchronously or asynchronously, batch, stream, and handle errors.

## Installation

```bash
pip install flymyai
```

## Quick Start

```python
from flymyai import client, FlyMyAIPredictException
import base64

apikey = "fly-***"

fma_client = client(apikey=apikey)

model = "flymyai/SDXLTurbo"

payload = {
    "prompt": "A beautiful sunset over mountains, digital art",
    "negative_prompt": "blurry, low quality",
}

try:
    response = fma_client.predict(
        model=model,
        payload=payload
    )
    # Decode the base64 image
    image_data = base64.b64decode(response.output_data["sample"][0])
    with open("output.jpg", "wb") as f:
        f.write(image_data)
    print("Saved output.jpg")
except FlyMyAIPredictException as e:
    print(f"Error: {e}")
```

## Synchronous Mode

### Image Generation with SDXLTurbo

```python
from flymyai import client, FlyMyAIPredictException
import base64

apikey = "fly-***"
model = "flymyai/SDXLTurbo"

payload = {
    "prompt": "A futuristic cityscape with flying cars, neon lights, cyberpunk style",
    "negative_prompt": "blurry, low quality, distorted",
}

fma_client = client(apikey=apikey)
try:
    response = fma_client.predict(model=model, payload=payload)
    image_data = base64.b64decode(response.output_data["sample"][0])
    with open("cityscape.jpg", "wb") as f:
        f.write(image_data)
    print("Saved cityscape.jpg")
except FlyMyAIPredictException as e:
    print(f"Error: {e}")
```

### Image Generation with NanoBananaPro

```python
from flymyai import client, FlyMyAIPredictException
import base64

apikey = "fly-***"
model = "flymyai/nano-banana-pro"

payload = {
    "prompt": "A cute robot exploring an alien jungle, vibrant colors",
    "width": 1024,
    "height": 1024,
    "num_inference_steps": 4,
    "seed": 42
}

fma_client = client(apikey=apikey)
try:
    response = fma_client.predict(model=model, payload=payload)
    image_data = base64.b64decode(response.output_data["image"][0])
    with open("robot.png", "wb") as f:
        f.write(image_data)
    print("Saved robot.png")
except FlyMyAIPredictException as e:
    print(f"Error: {e}")
```

> **Note**
>
> Different models return output under different keys. For example, `SDXLTurbo` uses `sample`, while `nano-banana-pro` uses `image`. Check the model page on [FlyMy.AI](https://app.flymy.ai) for the exact output schema.

## Asynchronous Mode

For async operations, use `async_client` instead of `client`:

### Basic Async Usage

```python
import asyncio
from flymyai import async_client, FlyMyAIPredictException

async def generate_image():
    apikey = "fly-***"
    model = "flymyai/SDXLTurbo"

    fma_client = async_client(apikey=apikey)

    try:
        response = await fma_client.predict(
            model=model,
            payload={
                "prompt": "A magical forest",
                "negative_prompt": "blurry",
            }
        )
        print(f"Output keys: {list(response.output_data.keys())}")
    except FlyMyAIPredictException as e:
        print(f"Error: {e}")
    finally:
        await fma_client.close()

asyncio.run(generate_image())
```

### Parallel Async Requests

```python
import asyncio
from flymyai import async_client, FlyMyAIPredictException
import base64

async def generate_multiple_images():
    apikey = "fly-***"
    model = "flymyai/SDXLTurbo"

    fma_client = async_client(apikey=apikey)

    prompts = [
        "A magical forest at dawn",
        "A futuristic city at night",
        "An underwater coral reef",
    ]

    async def generate_single(prompt):
        try:
            response = await fma_client.predict(
                model=model,
                payload={
                    "prompt": prompt,
                    "negative_prompt": "blurry, low quality",
                }
            )
            return base64.b64decode(response.output_data["sample"][0])
        except FlyMyAIPredictException as e:
            print(f"Error with prompt '{prompt}': {e}")
            return None

    tasks = [generate_single(prompt) for prompt in prompts]
    results = await asyncio.gather(*tasks)

    for prompt, data in zip(prompts, results):
        if data:
            filename = prompt.replace(" ", "_")[:20] + ".jpg"
            with open(filename, "wb") as f:
                f.write(data)
            print(f"Saved {filename}")

    await fma_client.close()

asyncio.run(generate_multiple_images())
```

## Working with Files

```python
from flymyai import client, FlyMyAIPredictException
import pathlib

apikey = "fly-***"
model = "flymyai/resnet"

fma_client = client(apikey=apikey)

image_path = pathlib.Path("/path/to/image.png")

try:
    response = fma_client.predict(
        model=model,
        payload={"i_image": image_path}
    )
    print(f"Classification result: {response.output_data}")
except FlyMyAIPredictException as e:
    print(f"Error: {e}")
```

## Decoding Base64 Response

```python
from flymyai import client, FlyMyAIPredictException
import base64
from PIL import Image
import io

apikey = "fly-***"
model = "flymyai/nano-banana-pro"

fma_client = client(apikey=apikey)

try:
    response = fma_client.predict(
        model=model,
        payload={
            "prompt": "A beautiful sunset",
            "width": 1024,
            "height": 1024,
            "num_inference_steps": 4,
        }
    )

    # Decode base64 image from the response
    image_data = base64.b64decode(response.output_data["image"][0])
    image = Image.open(io.BytesIO(image_data))

    image.save("generated_image.png")
    print("Saved generated_image.png")
except FlyMyAIPredictException as e:
    print(f"Error: {e}")
```

### Bound the size before decoding

Base64 adds about 33 percent and can coexist with encoded, decoded, and SDK
copies in memory, so cap the encoded and decoded sizes before writing a file.
With the candidate SDK (`python -m pip install 'flymyai>=1.2.0rc12'`):

```python
import base64, os
import flymyai

response = flymyai.run(apikey=os.environ["FLYMYAI_API_KEY"],
    model="flymyai/nano-banana",
    payload={"prompt":"A single blue circle centered on a white square, flat icon"})
encoded = response.output_data["image"][0]
max_decoded = 20 * 1024 * 1024
max_encoded = 4 * ((max_decoded + 2) // 3)
if not isinstance(encoded, str) or len(encoded) > max_encoded:
    raise ValueError("Unexpectedly large encoded image")
image = base64.b64decode(encoded, validate=True)
if len(image) > max_decoded:
    raise ValueError("Unexpectedly large image")
with open("blue-circle.jpg", "wb") as output:
    output.write(image)
```

## Error Handling

The SDK provides error handling through the `FlyMyAIPredictException` class:

```python
from flymyai import client, FlyMyAIPredictException

fma_client = client(apikey="fly-***")

try:
    response = fma_client.predict(model="flymyai/SDXLTurbo", payload={"prompt": "test"})
except FlyMyAIPredictException as e:
    print(f"Prediction failed: {e}")
```

## Additional Resources

- [API Reference](https://docs.flymy.ai/api/overview.md)
- [GitHub Repository](https://github.com/FlyMyAI/flymyai-python)
