Skip to content

Python SDK

The official Python SDK for Splinterpic provides a Pythonic way to interact with the Splinterpic API.

Terminal window
pip install splinterpic
Terminal window
poetry add splinterpic
from splinterpic import SplinterpicClient
client = SplinterpicClient(base_url='https://your-worker.workers.dev')
# Generate an image
image = client.generate(
prompt='A beautiful mountain landscape at sunset',
model='@cf/black-forest-labs/flux-1-schnell'
)
print(f'Image URL: {image["r2_url"]}')

Until the official SDK is published, use this reference implementation:

import requests
from typing import Optional, Dict, List, Any
from dataclasses import dataclass
@dataclass
class SplinterpicConfig:
base_url: str
default_model: str = '@cf/black-forest-labs/flux-1-schnell'
timeout: int = 30
class SplinterpicClient:
"""Official Splinterpic Python client"""
def __init__(self, base_url: str, default_model: Optional[str] = None, timeout: int = 30):
self.base_url = base_url.rstrip('/')
self.default_model = default_model or '@cf/black-forest-labs/flux-1-schnell'
self.timeout = timeout
self.session = requests.Session()
self.session.headers.update({'Content-Type': 'application/json'})
def _request(self, method: str, endpoint: str, **kwargs) -> Any:
"""Make HTTP request to the API"""
url = f'{self.base_url}{endpoint}'
try:
response = self.session.request(
method,
url,
timeout=self.timeout,
**kwargs
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
error_data = e.response.json() if e.response.content else {}
raise SplinterpicError(
error_data.get('error', str(e)),
status_code=e.response.status_code,
details=error_data.get('details')
)
except requests.exceptions.RequestException as e:
raise SplinterpicError(f'Request failed: {str(e)}')
def generate(
self,
prompt: str,
model: Optional[str] = None,
template_id: Optional[str] = None
) -> Dict:
"""Generate a new AI image"""
data = {
'prompt': prompt,
'model': model or self.default_model
}
if template_id:
data['template_id'] = template_id
return self._request('POST', '/api/generate', json=data)
def list_images(self, limit: int = 20, offset: int = 0) -> Dict:
"""List generated images"""
params = {'limit': limit, 'offset': offset}
return self._request('GET', '/api/images', params=params)
def get_image(self, image_id: str) -> Dict:
"""Get a specific image"""
return self._request('GET', f'/api/images/{image_id}')
def delete_image(self, image_id: str) -> None:
"""Delete an image"""
self._request('DELETE', f'/api/images/{image_id}')
def list_collections(self) -> Dict:
"""List all collections"""
return self._request('GET', '/api/collections')
def create_collection(self, name: str, description: str) -> Dict:
"""Create a new collection"""
data = {'name': name, 'description': description}
return self._request('POST', '/api/collections', json=data)
def get_collection(self, collection_id: str) -> Dict:
"""Get collection details"""
return self._request('GET', f'/api/collections/{collection_id}')
def get_collection_images(self, collection_id: str) -> Dict:
"""List images in a collection"""
return self._request('GET', f'/api/collections/{collection_id}/images')
def delete_collection(self, collection_id: str) -> None:
"""Delete a collection"""
self._request('DELETE', f'/api/collections/{collection_id}')
def list_models(self) -> Dict:
"""List available AI models"""
return self._request('GET', '/api/models')
def get_model(self, model_id: str) -> Dict:
"""Get model details"""
from urllib.parse import quote
return self._request('GET', f'/api/models/{quote(model_id)}')
def get_usage_analytics(self) -> Dict:
"""Get usage analytics"""
return self._request('GET', '/api/analytics/usage')
def get_cost_analytics(self) -> Dict:
"""Get cost analytics"""
return self._request('GET', '/api/analytics/costs')
class SplinterpicError(Exception):
"""Base exception for Splinterpic SDK"""
def __init__(self, message: str, status_code: Optional[int] = None, details: Optional[Dict] = None):
super().__init__(message)
self.status_code = status_code
self.details = details
# Export
__all__ = ['SplinterpicClient', 'SplinterpicError', 'SplinterpicConfig']
from splinterpic import SplinterpicClient
client = SplinterpicClient(base_url='https://your-worker.workers.dev')
# Single image
image = client.generate(
prompt='A futuristic city with flying cars, cyberpunk style',
model='@cf/black-forest-labs/flux-1-schnell'
)
print(image)
# {
# 'id': 'img_abc123',
# 'r2_url': 'https://...',
# 'created_at': '2024-01-15T10:30:00.000Z'
# }
from concurrent.futures import ThreadPoolExecutor
prompts = [
'Mountain landscape at sunrise',
'Ocean waves during golden hour',
'Forest path in autumn'
]
def generate_image(prompt):
return client.generate(prompt=prompt)
# Generate in parallel
with ThreadPoolExecutor(max_workers=3) as executor:
images = list(executor.map(generate_image, prompts))
print(f'Generated {len(images)} images')
# Get first 50 images
response = client.list_images(limit=50, offset=0)
images = response['images']
pagination = response['pagination']
print(f"Found {pagination['total']} images")
# Paginate through all images
def get_all_images():
all_images = []
offset = 0
limit = 100
while True:
response = client.list_images(limit=limit, offset=offset)
all_images.extend(response['images'])
if not response['pagination']['has_more']:
break
offset += limit
return all_images
all_images = get_all_images()
print(f'Total images: {len(all_images)}')
# Create a collection
collection = client.create_collection(
name='Marketing Campaign 2024',
description='Q1 social media assets'
)
print(f"Created collection: {collection['id']}")
# List all collections
collections = client.list_collections()
for coll in collections['collections']:
print(f"- {coll['name']}")
# Get collection details
details = client.get_collection(collection['id'])
print(details)
# Delete a collection
client.delete_collection(collection['id'])
# List all available models
models_response = client.list_models()
for model in models_response['models']:
print(f"{model['name']}: ${model['cost_per_image']}/image")
# Get specific model details
flux_model = client.get_model('@cf/black-forest-labs/flux-1-schnell')
print(flux_model)
# Get usage statistics
usage = client.get_usage_analytics()
print(f"Total images generated: {usage['total_images']}")
# Get cost analytics
costs = client.get_cost_analytics()
print(f"Total cost: ${costs['total_cost']}")
print(f"Average per image: ${costs['average_cost']}")
from splinterpic import SplinterpicClient, SplinterpicError
client = SplinterpicClient(base_url='https://your-worker.workers.dev')
try:
image = client.generate(
prompt='A beautiful landscape',
model='@cf/black-forest-labs/flux-1-schnell'
)
except SplinterpicError as e:
print(f'Generation failed: {e}')
print(f'Status code: {e.status_code}')
print(f'Details: {e.details}')
import time
from splinterpic import SplinterpicClient, SplinterpicError
def generate_with_retry(client, prompt, max_retries=3):
"""Generate image with automatic retries"""
for attempt in range(max_retries):
try:
return client.generate(prompt=prompt)
except SplinterpicError as e:
if attempt == max_retries - 1:
raise
wait_time = (attempt + 1) * 1.0
print(f'Retry {attempt + 1}/{max_retries} after {wait_time}s...')
time.sleep(wait_time)
client = SplinterpicClient(base_url='https://your-worker.workers.dev')
image = generate_with_retry(client, 'A beautiful landscape')
from contextlib import contextmanager
@contextmanager
def splinterpic_client(base_url):
"""Context manager for Splinterpic client"""
client = SplinterpicClient(base_url=base_url)
try:
yield client
finally:
client.session.close()
# Usage
with splinterpic_client('https://your-worker.workers.dev') as client:
image = client.generate(prompt='A beautiful landscape')
print(image['r2_url'])

Full type annotations for better IDE support:

from typing import TypedDict, Optional, List
class Image(TypedDict):
id: str
prompt: str
model: str
r2_key: str
r2_url: str
width: int
height: int
created_at: str
user_id: str
cost: float
is_deleted: bool
class Pagination(TypedDict):
limit: int
offset: int
total: int
has_more: bool
class ListImagesResponse(TypedDict):
images: List[Image]
pagination: Pagination
class Collection(TypedDict):
id: str
name: str
description: str
created_at: str
user_id: str
class Model(TypedDict):
id: str
name: str
description: str
cost_per_image: float
is_recommended: bool

For async/await support, use httpx:

import httpx
from typing import Optional, Dict, Any
class AsyncSplinterpicClient:
"""Async Splinterpic Python client"""
def __init__(self, base_url: str, default_model: Optional[str] = None):
self.base_url = base_url.rstrip('/')
self.default_model = default_model or '@cf/black-forest-labs/flux-1-schnell'
self.client = httpx.AsyncClient(
headers={'Content-Type': 'application/json'},
timeout=30.0
)
async def _request(self, method: str, endpoint: str, **kwargs) -> Any:
"""Make async HTTP request to the API"""
url = f'{self.base_url}{endpoint}'
try:
response = await self.client.request(method, url, **kwargs)
response.raise_for_status()
return response.json()
except httpx.HTTPStatusError as e:
error_data = e.response.json() if e.response.content else {}
raise SplinterpicError(
error_data.get('error', str(e)),
status_code=e.response.status_code
)
async def generate(
self,
prompt: str,
model: Optional[str] = None
) -> Dict:
"""Generate a new AI image"""
data = {
'prompt': prompt,
'model': model or self.default_model
}
return await self._request('POST', '/api/generate', json=data)
async def close(self):
"""Close the HTTP client"""
await self.client.aclose()
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.close()
# Usage
import asyncio
async def main():
async with AsyncSplinterpicClient('https://your-worker.workers.dev') as client:
image = await client.generate(prompt='A beautiful landscape')
print(image['r2_url'])
asyncio.run(main())
from flask import Flask, request, jsonify
from splinterpic import SplinterpicClient
app = Flask(__name__)
client = SplinterpicClient(base_url='https://your-worker.workers.dev')
@app.route('/generate', methods=['POST'])
def generate_image():
try:
data = request.get_json()
prompt = data.get('prompt')
if not prompt:
return jsonify({'error': 'Prompt is required'}), 400
image = client.generate(prompt=prompt)
return jsonify(image)
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(debug=True)
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from splinterpic import SplinterpicClient, SplinterpicError
app = FastAPI()
client = SplinterpicClient(base_url='https://your-worker.workers.dev')
class GenerateRequest(BaseModel):
prompt: str
model: str = '@cf/black-forest-labs/flux-1-schnell'
@app.post('/generate')
async def generate_image(request: GenerateRequest):
try:
image = client.generate(
prompt=request.prompt,
model=request.model
)
return image
except SplinterpicError as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get('/images')
async def list_images(limit: int = 20, offset: int = 0):
try:
return client.list_images(limit=limit, offset=offset)
except SplinterpicError as e:
raise HTTPException(status_code=500, detail=str(e))
views.py
from django.http import JsonResponse
from django.views import View
from splinterpic import SplinterpicClient
import json
client = SplinterpicClient(base_url='https://your-worker.workers.dev')
class GenerateImageView(View):
def post(self, request):
try:
data = json.loads(request.body)
prompt = data.get('prompt')
if not prompt:
return JsonResponse({'error': 'Prompt is required'}, status=400)
image = client.generate(prompt=prompt)
return JsonResponse(image)
except Exception as e:
return JsonResponse({'error': str(e)}, status=500)
# urls.py
from django.urls import path
from .views import GenerateImageView
urlpatterns = [
path('api/generate/', GenerateImageView.as_view()),
]

Create a simple CLI tool:

import click
from splinterpic import SplinterpicClient
@click.group()
@click.option('--base-url', envvar='SPLINTERPIC_API_URL', required=True)
@click.pass_context
def cli(ctx, base_url):
"""Splinterpic CLI tool"""
ctx.obj = SplinterpicClient(base_url=base_url)
@cli.command()
@click.argument('prompt')
@click.option('--model', default='@cf/black-forest-labs/flux-1-schnell')
@click.pass_obj
def generate(client, prompt, model):
"""Generate an image"""
image = client.generate(prompt=prompt, model=model)
click.echo(f"Generated: {image['r2_url']}")
@cli.command()
@click.option('--limit', default=20)
@click.pass_obj
def list(client, limit):
"""List images"""
response = client.list_images(limit=limit)
for img in response['images']:
click.echo(f"{img['id']}: {img['prompt']}")
if __name__ == '__main__':
cli()

Usage:

Terminal window
export SPLINTERPIC_API_URL=https://your-worker.workers.dev
python cli.py generate "A beautiful landscape"
python cli.py list --limit=10