fotohub 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fotohub-1.0.0/.gitignore +18 -0
- fotohub-1.0.0/LICENSE +21 -0
- fotohub-1.0.0/PKG-INFO +521 -0
- fotohub-1.0.0/README.md +487 -0
- fotohub-1.0.0/fotohub/__init__.py +101 -0
- fotohub-1.0.0/fotohub/client.py +1150 -0
- fotohub-1.0.0/fotohub/exceptions.py +121 -0
- fotohub-1.0.0/fotohub/models.py +288 -0
- fotohub-1.0.0/fotohub/py.typed +0 -0
- fotohub-1.0.0/fotohub/streaming.py +130 -0
- fotohub-1.0.0/pyproject.toml +67 -0
fotohub-1.0.0/.gitignore
ADDED
fotohub-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 FOTOhub
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
fotohub-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fotohub
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for the FOTOhub AI Platform
|
|
5
|
+
Project-URL: Homepage, https://fotohub.app
|
|
6
|
+
Project-URL: Documentation, https://docs.fotohub.app/sdk/python
|
|
7
|
+
Project-URL: Repository, https://github.com/fotohubapp/sdk-python
|
|
8
|
+
Project-URL: Issues, https://github.com/fotohubapp/sdk-python/issues
|
|
9
|
+
Author-email: FOTOhub <dev@fotohub.app>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai,fotohub,image-generation,llm,music-generation,video-generation
|
|
13
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Requires-Dist: httpx>=0.24
|
|
26
|
+
Requires-Dist: pydantic>=2.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: mypy>=1.5; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-httpx>=0.21; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<img src="https://static.fotohub.app/brand/fotohub-logo-dark.png" alt="FOTOhub" width="280" />
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<strong>Official Python SDK for the FOTOhub AI Platform</strong>
|
|
41
|
+
</p>
|
|
42
|
+
|
|
43
|
+
<p align="center">
|
|
44
|
+
<a href="https://pypi.org/project/fotohub/"><img src="https://img.shields.io/pypi/v/fotohub?color=blue&label=PyPI" alt="PyPI Version" /></a>
|
|
45
|
+
<a href="https://pypi.org/project/fotohub/"><img src="https://img.shields.io/pypi/pyversions/fotohub" alt="Python Versions" /></a>
|
|
46
|
+
<a href="https://github.com/fotohubapp/sdk-python/blob/main/LICENSE"><img src="https://img.shields.io/github/license/fotohubapp/sdk-python" alt="License" /></a>
|
|
47
|
+
<a href="https://pypi.org/project/fotohub/"><img src="https://img.shields.io/pypi/dm/fotohub?color=green" alt="Downloads" /></a>
|
|
48
|
+
<a href="https://docs.fotohub.app/sdk/python"><img src="https://img.shields.io/badge/docs-fotohub.app-blue" alt="Documentation" /></a>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<p align="center">
|
|
52
|
+
Generate images, videos, music, and chat with LLMs — all through a single, unified Python client.<br/>
|
|
53
|
+
Supports 80+ AI models from 10+ providers with built-in credit management.
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Features
|
|
59
|
+
|
|
60
|
+
- **Image Generation** — 25+ models including SeedDream 5.0, Flux, SDXL, Midjourney-style, and more
|
|
61
|
+
- **Video Generation** — Async job-based video creation with polling and image-to-video
|
|
62
|
+
- **Music Generation** — AI-powered music and audio creation
|
|
63
|
+
- **Chat / LLM** — OpenAI-compatible chat completions with streaming support
|
|
64
|
+
- **Gabriel AI** — Intent orchestration engine for natural-language workflows
|
|
65
|
+
- **Storage** — S3 bucket provisioning with presigned upload/download URLs
|
|
66
|
+
- **Translation** — Multi-language translation (no auth required)
|
|
67
|
+
- **Fully Typed** — Complete type annotations with Pydantic v2 models
|
|
68
|
+
- **Sync + Async** — Both synchronous and asynchronous clients included
|
|
69
|
+
- **Automatic Retries** — Exponential backoff with configurable retry logic
|
|
70
|
+
- **Streaming** — Real-time SSE streaming for chat completions
|
|
71
|
+
|
|
72
|
+
## Installation
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pip install fotohub
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Requires Python 3.9 or higher.
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from fotohub import FotoHub
|
|
84
|
+
|
|
85
|
+
client = FotoHub(api_key="fh_live_...")
|
|
86
|
+
|
|
87
|
+
# Generate an image
|
|
88
|
+
result = client.generate_image(prompt="A mountain landscape at golden hour")
|
|
89
|
+
print(result.images[0].url)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Authentication
|
|
93
|
+
|
|
94
|
+
Get your API key from [fotohub.app/settings/api](https://fotohub.app/settings/api).
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from fotohub import FotoHub
|
|
98
|
+
|
|
99
|
+
# Option 1: Pass directly
|
|
100
|
+
client = FotoHub(api_key="fh_live_...")
|
|
101
|
+
|
|
102
|
+
# Option 2: Environment variable
|
|
103
|
+
# export FOTOHUB_API_KEY=fh_live_...
|
|
104
|
+
client = FotoHub()
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The SDK authenticates via both `Authorization: Bearer` and `x-api-key` headers.
|
|
108
|
+
|
|
109
|
+
## Usage Examples
|
|
110
|
+
|
|
111
|
+
### Image Generation
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from fotohub import FotoHub
|
|
115
|
+
|
|
116
|
+
client = FotoHub(api_key="fh_live_...")
|
|
117
|
+
|
|
118
|
+
# Basic generation (default: SeedDream 5.0 Lite)
|
|
119
|
+
result = client.generate_image(
|
|
120
|
+
prompt="A serene Japanese garden with cherry blossoms",
|
|
121
|
+
)
|
|
122
|
+
print(result.images[0].url)
|
|
123
|
+
|
|
124
|
+
# Advanced options
|
|
125
|
+
result = client.generate_image(
|
|
126
|
+
prompt="Cyberpunk cityscape at night, neon reflections on wet streets",
|
|
127
|
+
model="flux-1-schnell",
|
|
128
|
+
width=1280,
|
|
129
|
+
height=720,
|
|
130
|
+
num_images=2,
|
|
131
|
+
negative_prompt="blurry, low quality",
|
|
132
|
+
seed=42,
|
|
133
|
+
guidance_scale=7.5,
|
|
134
|
+
steps=30,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
for image in result.images:
|
|
138
|
+
print(f"{image.url} — {image.width}x{image.height}, {image.credits_used} credits")
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Video Generation
|
|
142
|
+
|
|
143
|
+
Video generation is asynchronous — submit a job and poll for the result.
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from fotohub import FotoHub
|
|
147
|
+
|
|
148
|
+
client = FotoHub(api_key="fh_live_...")
|
|
149
|
+
|
|
150
|
+
# Start a video generation job
|
|
151
|
+
job = client.generate_video(
|
|
152
|
+
prompt="A drone shot flying over a tropical beach at sunrise",
|
|
153
|
+
duration=5.0,
|
|
154
|
+
aspect_ratio="16:9",
|
|
155
|
+
)
|
|
156
|
+
print(f"Job started: {job.job_id}")
|
|
157
|
+
|
|
158
|
+
# Poll until complete (blocks up to 10 minutes)
|
|
159
|
+
result = client.poll_video(job.job_id, poll_interval=5.0, max_wait=600)
|
|
160
|
+
|
|
161
|
+
if result.status == "completed":
|
|
162
|
+
print(f"Video: {result.video_url}")
|
|
163
|
+
else:
|
|
164
|
+
print(f"Failed: {result.error}")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Image-to-Video:**
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
job = client.generate_video(
|
|
171
|
+
prompt="Camera slowly zooms in, subtle parallax motion",
|
|
172
|
+
image_url="https://example.com/photo.jpg",
|
|
173
|
+
)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Music Generation
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
from fotohub import FotoHub
|
|
180
|
+
|
|
181
|
+
client = FotoHub(api_key="fh_live_...")
|
|
182
|
+
|
|
183
|
+
result = client.generate_music(
|
|
184
|
+
prompt="Upbeat electronic track with heavy bass and synth arpeggios",
|
|
185
|
+
duration=30.0,
|
|
186
|
+
)
|
|
187
|
+
print(f"Audio: {result.audio.url}")
|
|
188
|
+
print(f"Duration: {result.audio.duration}s")
|
|
189
|
+
print(f"Credits used: {result.credits_used}")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Chat Completions (OpenAI-Compatible)
|
|
193
|
+
|
|
194
|
+
```python
|
|
195
|
+
from fotohub import FotoHub
|
|
196
|
+
|
|
197
|
+
client = FotoHub(api_key="fh_live_...")
|
|
198
|
+
|
|
199
|
+
response = client.chat(
|
|
200
|
+
messages=[
|
|
201
|
+
{"role": "system", "content": "You are a helpful assistant."},
|
|
202
|
+
{"role": "user", "content": "Explain quantum computing in simple terms."},
|
|
203
|
+
],
|
|
204
|
+
model="gpt-4o",
|
|
205
|
+
temperature=0.7,
|
|
206
|
+
max_tokens=1000,
|
|
207
|
+
)
|
|
208
|
+
print(response.choices[0].message.content)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Streaming Chat
|
|
212
|
+
|
|
213
|
+
```python
|
|
214
|
+
from fotohub import FotoHub
|
|
215
|
+
|
|
216
|
+
client = FotoHub(api_key="fh_live_...")
|
|
217
|
+
|
|
218
|
+
stream = client.chat(
|
|
219
|
+
messages=[{"role": "user", "content": "Write a short poem about the sea."}],
|
|
220
|
+
stream=True,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
for chunk in stream:
|
|
224
|
+
if chunk.delta_content:
|
|
225
|
+
print(chunk.delta_content, end="", flush=True)
|
|
226
|
+
print()
|
|
227
|
+
|
|
228
|
+
# Or collect the entire response at once:
|
|
229
|
+
stream = client.chat(messages=[...], stream=True)
|
|
230
|
+
full_text = stream.collect()
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Gabriel AI (Intent Orchestration)
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
from fotohub import FotoHub
|
|
237
|
+
|
|
238
|
+
client = FotoHub() # No API key needed
|
|
239
|
+
|
|
240
|
+
result = client.gabriel(
|
|
241
|
+
message="I want to create a logo for my coffee shop",
|
|
242
|
+
context={"user_tier": "pro"},
|
|
243
|
+
)
|
|
244
|
+
print(f"Intent: {result.intent}")
|
|
245
|
+
print(f"Response: {result.response}")
|
|
246
|
+
print(f"Suggested actions: {result.actions}")
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Storage & S3 Buckets
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
from fotohub import FotoHub
|
|
253
|
+
|
|
254
|
+
client = FotoHub(api_key="fh_live_...")
|
|
255
|
+
|
|
256
|
+
# List buckets
|
|
257
|
+
buckets = client.list_buckets()
|
|
258
|
+
for bucket in buckets.buckets:
|
|
259
|
+
print(f"{bucket.name} ({bucket.region}) — {bucket.object_count} objects")
|
|
260
|
+
|
|
261
|
+
# Provision a dedicated S3 bucket
|
|
262
|
+
provision = client.provision_s3_bucket(name="my-media-bucket", region="eu-central-1")
|
|
263
|
+
print(f"Bucket ID: {provision.bucket_id}")
|
|
264
|
+
print(f"Endpoint: {provision.endpoint}")
|
|
265
|
+
|
|
266
|
+
# Presigned upload
|
|
267
|
+
upload = client.presign_upload(
|
|
268
|
+
bucket_id="bucket-123",
|
|
269
|
+
key="images/photo.jpg",
|
|
270
|
+
content_type="image/jpeg",
|
|
271
|
+
expires_in=3600,
|
|
272
|
+
)
|
|
273
|
+
# Use upload.url with PUT request to upload your file
|
|
274
|
+
|
|
275
|
+
# Presigned download
|
|
276
|
+
download = client.presign_download(bucket_id="bucket-123", key="images/photo.jpg")
|
|
277
|
+
print(f"Download: {download.url}")
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Translation (No Auth Required)
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
from fotohub import FotoHub
|
|
284
|
+
|
|
285
|
+
client = FotoHub() # No API key needed
|
|
286
|
+
|
|
287
|
+
result = client.translate(text="Hello, how are you?", target_language="pl")
|
|
288
|
+
print(result.translated_text) # "Cześć, jak się masz?"
|
|
289
|
+
print(result.source_language) # "en"
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Usage Analytics
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
from fotohub import FotoHub
|
|
296
|
+
|
|
297
|
+
client = FotoHub(api_key="fh_live_...")
|
|
298
|
+
|
|
299
|
+
usage = client.get_usage(start_date="2026-07-01", end_date="2026-07-18", category="image")
|
|
300
|
+
print(f"Total credits: {usage.total_credits_used}")
|
|
301
|
+
for record in usage.records:
|
|
302
|
+
print(f" {record.date}: {record.credits_used} credits ({record.request_count} requests)")
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Async Client
|
|
306
|
+
|
|
307
|
+
Every method is available as an async variant via `AsyncFotoHub`:
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
import asyncio
|
|
311
|
+
from fotohub import AsyncFotoHub
|
|
312
|
+
|
|
313
|
+
async def main():
|
|
314
|
+
async with AsyncFotoHub(api_key="fh_live_...") as client:
|
|
315
|
+
# Generate images concurrently
|
|
316
|
+
import asyncio as aio
|
|
317
|
+
results = await aio.gather(
|
|
318
|
+
client.generate_image(prompt="A sunset over mountains"),
|
|
319
|
+
client.generate_image(prompt="A forest in morning mist"),
|
|
320
|
+
client.generate_image(prompt="An ocean wave at golden hour"),
|
|
321
|
+
)
|
|
322
|
+
for r in results:
|
|
323
|
+
print(r.images[0].url)
|
|
324
|
+
|
|
325
|
+
# Async streaming chat
|
|
326
|
+
stream = await client.chat(
|
|
327
|
+
messages=[{"role": "user", "content": "Hello!"}],
|
|
328
|
+
stream=True,
|
|
329
|
+
)
|
|
330
|
+
async for chunk in stream:
|
|
331
|
+
if chunk.delta_content:
|
|
332
|
+
print(chunk.delta_content, end="")
|
|
333
|
+
print()
|
|
334
|
+
|
|
335
|
+
asyncio.run(main())
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Error Handling
|
|
339
|
+
|
|
340
|
+
The SDK raises typed exceptions for all error conditions:
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
from fotohub import (
|
|
344
|
+
FotoHub,
|
|
345
|
+
AuthError,
|
|
346
|
+
InsufficientCreditsError,
|
|
347
|
+
RateLimitError,
|
|
348
|
+
ValidationError,
|
|
349
|
+
ServerError,
|
|
350
|
+
TimeoutError,
|
|
351
|
+
VideoJobTimeoutError,
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
client = FotoHub(api_key="fh_live_...")
|
|
355
|
+
|
|
356
|
+
try:
|
|
357
|
+
result = client.generate_image(prompt="test")
|
|
358
|
+
except AuthError as e:
|
|
359
|
+
# Invalid or missing API key (HTTP 401/403)
|
|
360
|
+
print(f"Authentication failed: {e}")
|
|
361
|
+
except InsufficientCreditsError as e:
|
|
362
|
+
# Not enough credits (HTTP 402)
|
|
363
|
+
print(f"Need credits! Required: {e.credits_required}, Available: {e.credits_available}")
|
|
364
|
+
except RateLimitError as e:
|
|
365
|
+
# Too many requests (HTTP 429)
|
|
366
|
+
print(f"Rate limited. Retry after {e.retry_after}s")
|
|
367
|
+
except ValidationError as e:
|
|
368
|
+
# Invalid parameters (HTTP 400/422)
|
|
369
|
+
print(f"Invalid request: {e.errors}")
|
|
370
|
+
except ServerError as e:
|
|
371
|
+
# Server error (HTTP 5xx)
|
|
372
|
+
print(f"Server error: {e}")
|
|
373
|
+
except TimeoutError as e:
|
|
374
|
+
# Request timed out
|
|
375
|
+
print(f"Timed out: {e}")
|
|
376
|
+
except VideoJobTimeoutError as e:
|
|
377
|
+
# Video polling exceeded max_wait
|
|
378
|
+
print(f"Video job {e.job_id} timed out")
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Exception Hierarchy
|
|
382
|
+
|
|
383
|
+
| Exception | HTTP Status | Description |
|
|
384
|
+
|-----------|-------------|-------------|
|
|
385
|
+
| `FotoHubError` | Any | Base exception for all SDK errors |
|
|
386
|
+
| `AuthError` | 401, 403 | Invalid or missing API key |
|
|
387
|
+
| `InsufficientCreditsError` | 402 | Account lacks sufficient credits |
|
|
388
|
+
| `RateLimitError` | 429 | Rate limit exceeded |
|
|
389
|
+
| `ValidationError` | 400, 422 | Invalid request parameters |
|
|
390
|
+
| `ServerError` | 5xx | Server-side error |
|
|
391
|
+
| `TimeoutError` | — | Request timed out or connection failed |
|
|
392
|
+
| `VideoJobTimeoutError` | — | Video polling exceeded `max_wait` |
|
|
393
|
+
|
|
394
|
+
All exceptions include `status_code` and `response_body` attributes for debugging.
|
|
395
|
+
|
|
396
|
+
## Configuration
|
|
397
|
+
|
|
398
|
+
```python
|
|
399
|
+
from fotohub import FotoHub
|
|
400
|
+
|
|
401
|
+
client = FotoHub(
|
|
402
|
+
api_key="fh_live_...",
|
|
403
|
+
base_url="https://apis.fotohub.app", # Custom API endpoint
|
|
404
|
+
timeout=120.0, # Request timeout (seconds)
|
|
405
|
+
max_retries=3, # Max retry attempts
|
|
406
|
+
)
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Environment Variables
|
|
410
|
+
|
|
411
|
+
| Variable | Description | Default |
|
|
412
|
+
|----------|-------------|---------|
|
|
413
|
+
| `FOTOHUB_API_KEY` | API key for authentication | — |
|
|
414
|
+
| `FOTOHUB_BASE_URL` | Override API base URL | `https://apis.fotohub.app` |
|
|
415
|
+
|
|
416
|
+
### Retry Behavior
|
|
417
|
+
|
|
418
|
+
The SDK automatically retries on transient failures:
|
|
419
|
+
|
|
420
|
+
- **HTTP 429** — Rate limit (respects `Retry-After` header)
|
|
421
|
+
- **HTTP 500, 502, 503, 504** — Server errors
|
|
422
|
+
- **Connection timeouts** — Network failures
|
|
423
|
+
|
|
424
|
+
Backoff schedule: `0.5s → 1s → 2s → 4s → ...` (capped at 30s).
|
|
425
|
+
|
|
426
|
+
## Context Managers
|
|
427
|
+
|
|
428
|
+
Both clients support context managers for automatic resource cleanup:
|
|
429
|
+
|
|
430
|
+
```python
|
|
431
|
+
# Sync
|
|
432
|
+
with FotoHub(api_key="fh_live_...") as client:
|
|
433
|
+
result = client.generate_image(prompt="test")
|
|
434
|
+
|
|
435
|
+
# Async
|
|
436
|
+
async with AsyncFotoHub(api_key="fh_live_...") as client:
|
|
437
|
+
result = await client.generate_image(prompt="test")
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
## API Reference
|
|
441
|
+
|
|
442
|
+
### `FotoHub` / `AsyncFotoHub`
|
|
443
|
+
|
|
444
|
+
| Method | Description |
|
|
445
|
+
|--------|-------------|
|
|
446
|
+
| `generate_image(prompt, *, model, width, height, num_images, ...)` | Generate images from text |
|
|
447
|
+
| `generate_video(prompt, *, model, duration, image_url, aspect_ratio, ...)` | Start video generation job |
|
|
448
|
+
| `poll_video(job_id, *, poll_interval, max_wait)` | Poll video job until completion |
|
|
449
|
+
| `generate_music(prompt, *, model, duration, ...)` | Generate music from text |
|
|
450
|
+
| `chat(messages, *, model, stream, temperature, max_tokens, ...)` | Chat completion (streaming supported) |
|
|
451
|
+
| `translate(text, *, target_language, source_language)` | Translate text between languages |
|
|
452
|
+
| `gabriel(message, *, context)` | Intent orchestration via Gabriel AI |
|
|
453
|
+
| `get_usage(*, start_date, end_date, category)` | Retrieve usage analytics |
|
|
454
|
+
| `list_buckets()` | List storage buckets |
|
|
455
|
+
| `create_bucket(name, *, region)` | Create a storage bucket |
|
|
456
|
+
| `provision_s3_bucket(*, name, region)` | Provision a dedicated S3 bucket |
|
|
457
|
+
| `presign_upload(bucket_id, *, key, content_type, expires_in)` | Get presigned upload URL |
|
|
458
|
+
| `presign_download(bucket_id, *, key, expires_in)` | Get presigned download URL |
|
|
459
|
+
|
|
460
|
+
## Type Safety
|
|
461
|
+
|
|
462
|
+
The SDK ships with a `py.typed` marker and full type annotations. All response models are Pydantic v2 `BaseModel` subclasses:
|
|
463
|
+
|
|
464
|
+
```python
|
|
465
|
+
from fotohub import FotoHub, ImageGenerationResponse, ImageResult
|
|
466
|
+
|
|
467
|
+
client = FotoHub(api_key="fh_live_...")
|
|
468
|
+
|
|
469
|
+
result: ImageGenerationResponse = client.generate_image(prompt="test")
|
|
470
|
+
image: ImageResult = result.images[0]
|
|
471
|
+
|
|
472
|
+
# All fields are fully typed
|
|
473
|
+
print(image.url) # str
|
|
474
|
+
print(image.width) # int
|
|
475
|
+
print(image.credits_used) # float
|
|
476
|
+
print(image.generation_time_ms) # Optional[int]
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
## Requirements
|
|
480
|
+
|
|
481
|
+
| Dependency | Version |
|
|
482
|
+
|-----------|---------|
|
|
483
|
+
| Python | >= 3.9 |
|
|
484
|
+
| httpx | >= 0.24 |
|
|
485
|
+
| pydantic | >= 2.0 |
|
|
486
|
+
|
|
487
|
+
## Contributing
|
|
488
|
+
|
|
489
|
+
We welcome contributions! To get started:
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
# Clone the repository
|
|
493
|
+
git clone https://github.com/fotohubapp/sdk-python.git
|
|
494
|
+
cd sdk-python
|
|
495
|
+
|
|
496
|
+
# Install development dependencies
|
|
497
|
+
pip install -e ".[dev]"
|
|
498
|
+
|
|
499
|
+
# Run tests
|
|
500
|
+
pytest
|
|
501
|
+
|
|
502
|
+
# Run linting
|
|
503
|
+
ruff check .
|
|
504
|
+
|
|
505
|
+
# Run type checking
|
|
506
|
+
mypy fotohub/
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
Please ensure all tests pass and type checks are clean before submitting a pull request.
|
|
510
|
+
|
|
511
|
+
## Links
|
|
512
|
+
|
|
513
|
+
- [Documentation](https://docs.fotohub.app/sdk/python)
|
|
514
|
+
- [API Reference](https://docs.fotohub.app/api)
|
|
515
|
+
- [FOTOhub Platform](https://fotohub.app)
|
|
516
|
+
- [Changelog](https://github.com/fotohubapp/sdk-python/releases)
|
|
517
|
+
- [Issue Tracker](https://github.com/fotohubapp/sdk-python/issues)
|
|
518
|
+
|
|
519
|
+
## License
|
|
520
|
+
|
|
521
|
+
MIT License. See [LICENSE](LICENSE) for details.
|