> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pixcraft.es/llms.txt
> Use this file to discover all available pages before exploring further.

# Python Integration

> Complete guide to integrating PixCraft API in Python.

# Python Integration Guide

This guide shows how to use the PixCraft API from Python using the `requests` library, plus an async version with `aiohttp`.

## Installation

```bash theme={null}
pip install requests
# For async version:
pip install aiohttp
```

## Basic usage with requests

```python theme={null}
import requests
import os

PIXCRAFT_API_KEY = os.environ['PIXCRAFT_API_KEY']
BASE_URL = 'https://www.pixcraft.es/api/v1'

def generate_pattern(image_url: str, niche: str, width_cm: int, height_cm: int) -> dict:
    response = requests.post(
        f'{BASE_URL}/generate',
        headers={'Authorization': f'Bearer {PIXCRAFT_API_KEY}'},
        json={
            'image_url': image_url,
            'niche': niche,
            'width_cm': width_cm,
            'height_cm': height_cm,
        }
    )
    response.raise_for_status()
    return response.json()

# Usage
pattern = generate_pattern('https://example.com/sunset.jpg', 'mosaics', 100, 100)
print(f"Generated {pattern['dimensions']['total_units']} tiles in {len(pattern['materials'])} colors")
```

## Generate and save a PDF

```python theme={null}
def generate_pdf(image_url: str, niche: str, width_cm: int, height_cm: int, output_path: str):
    response = requests.post(
        f'{BASE_URL}/generate/pdf',
        headers={'Authorization': f'Bearer {PIXCRAFT_API_KEY}'},
        json={
            'image_url': image_url,
            'niche': niche,
            'width_cm': width_cm,
            'height_cm': height_cm,
        }
    )
    response.raise_for_status()

    with open(output_path, 'wb') as f:
        f.write(response.content)
    print(f"PDF saved to {output_path}")

generate_pdf('https://example.com/photo.jpg', 'curtains', 200, 250, 'pattern.pdf')
```

## Process a local image

```python theme={null}
import base64

def process_local_image(file_path: str, niche: str, width_cm: int, height_cm: int) -> dict:
    with open(file_path, 'rb') as f:
        image_base64 = base64.b64encode(f.read()).decode('utf-8')

    response = requests.post(
        f'{BASE_URL}/generate',
        headers={'Authorization': f'Bearer {PIXCRAFT_API_KEY}'},
        json={
            'image': image_base64,
            'niche': niche,
            'width_cm': width_cm,
            'height_cm': height_cm,
        }
    )
    response.raise_for_status()
    return response.json()
```

## Async version with aiohttp

```python theme={null}
import aiohttp
import asyncio

async def generate_pattern_async(session: aiohttp.ClientSession, image_url: str, niche: str, width_cm: int, height_cm: int) -> dict:
    async with session.post(
        f'{BASE_URL}/generate',
        headers={'Authorization': f'Bearer {PIXCRAFT_API_KEY}'},
        json={
            'image_url': image_url,
            'niche': niche,
            'width_cm': width_cm,
            'height_cm': height_cm,
        }
    ) as response:
        response.raise_for_status()
        return await response.json()

async def process_batch(image_urls: list[str], niche: str, width_cm: int, height_cm: int):
    async with aiohttp.ClientSession() as session:
        tasks = [
            generate_pattern_async(session, url, niche, width_cm, height_cm)
            for url in image_urls
        ]
        return await asyncio.gather(*tasks)

# Usage
results = asyncio.run(process_batch(
    ['https://example.com/1.jpg', 'https://example.com/2.jpg'],
    'mosaics', 100, 100
))
```

## Error handling with retry

```python theme={null}
import time

def generate_with_retry(image_url: str, niche: str, width_cm: int, height_cm: int, max_retries: int = 3) -> dict:
    for attempt in range(max_retries):
        response = requests.post(
            f'{BASE_URL}/generate',
            headers={'Authorization': f'Bearer {PIXCRAFT_API_KEY}'},
            json={
                'image_url': image_url,
                'niche': niche,
                'width_cm': width_cm,
                'height_cm': height_cm,
            }
        )

        if response.status_code == 429:  # Rate limited
            delay = 2 ** attempt
            print(f"Rate limited. Retrying in {delay}s...")
            time.sleep(delay)
            continue

        response.raise_for_status()
        return response.json()

    raise Exception("Max retries exceeded")
```

## Django view example

```python theme={null}
from django.http import JsonResponse, HttpResponse
from django.views.decorators.http import require_POST
import json

@require_POST
def generate_pattern_view(request):
    body = json.loads(request.body)
    try:
        pattern = generate_pattern(
            body['image_url'],
            body['niche'],
            body['width_cm'],
            body['height_cm'],
        )
        return JsonResponse(pattern)
    except requests.HTTPError as e:
        return JsonResponse({'error': str(e)}, status=500)
```
