indoxrouter 0.1.17__tar.gz → 0.1.19__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.
- {indoxrouter-0.1.17/indoxrouter.egg-info → indoxrouter-0.1.19}/PKG-INFO +1 -1
- indoxrouter-0.1.19/examples/google_image_generation.py +159 -0
- indoxrouter-0.1.19/examples/image_generation.py +141 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/indoxrouter/client.py +75 -12
- {indoxrouter-0.1.17 → indoxrouter-0.1.19/indoxrouter.egg-info}/PKG-INFO +1 -1
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/indoxrouter.egg-info/SOURCES.txt +4 -1
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/pyproject.toml +1 -1
- indoxrouter-0.1.19/tests/test_image.py +93 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/MANIFEST.in +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/README.md +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/cookbook/README.md +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/cookbook/indoxRouter_cookbook.ipynb +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/indoxrouter/__init__.py +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/indoxrouter/constants.py +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/indoxrouter/exceptions.py +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/indoxrouter.egg-info/dependency_links.txt +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/indoxrouter.egg-info/requires.txt +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/indoxrouter.egg-info/top_level.txt +0 -0
- {indoxrouter-0.1.17 → indoxrouter-0.1.19}/setup.cfg +0 -0
@@ -0,0 +1,159 @@
|
|
1
|
+
"""
|
2
|
+
Example script demonstrating image generation with Google's Imagen model through indoxRouter.
|
3
|
+
|
4
|
+
This script shows how to properly format parameters for Google's image generation API,
|
5
|
+
including the special handling of aspect ratios and other Google-specific parameters.
|
6
|
+
|
7
|
+
Requirements:
|
8
|
+
- Install indoxRouter: pip install indoxrouter
|
9
|
+
- Set INDOX_ROUTER_API_KEY environment variable with your API key
|
10
|
+
"""
|
11
|
+
|
12
|
+
import os
|
13
|
+
import base64
|
14
|
+
from io import BytesIO
|
15
|
+
import requests
|
16
|
+
from datetime import datetime
|
17
|
+
|
18
|
+
from indoxrouter import Client
|
19
|
+
|
20
|
+
# For displaying images in notebooks
|
21
|
+
try:
|
22
|
+
from IPython.display import Image, display
|
23
|
+
|
24
|
+
in_notebook = True
|
25
|
+
except ImportError:
|
26
|
+
in_notebook = False
|
27
|
+
|
28
|
+
# Initialize client with API key from environment variable
|
29
|
+
api_key = os.environ.get("INDOX_ROUTER_API_KEY")
|
30
|
+
if not api_key:
|
31
|
+
print("Please set the INDOX_ROUTER_API_KEY environment variable")
|
32
|
+
exit(1)
|
33
|
+
|
34
|
+
client = Client(api_key=api_key)
|
35
|
+
|
36
|
+
|
37
|
+
def save_image_from_url(url, filename):
|
38
|
+
"""Download and save an image from a URL."""
|
39
|
+
response = requests.get(url)
|
40
|
+
if response.status_code == 200:
|
41
|
+
with open(filename, "wb") as f:
|
42
|
+
f.write(response.content)
|
43
|
+
print(f"Image saved to {filename}")
|
44
|
+
else:
|
45
|
+
print(f"Failed to download image: {response.status_code}")
|
46
|
+
|
47
|
+
|
48
|
+
def save_image_from_b64(b64_data, filename):
|
49
|
+
"""Save an image from base64 data."""
|
50
|
+
image_data = base64.b64decode(b64_data)
|
51
|
+
with open(filename, "wb") as f:
|
52
|
+
f.write(image_data)
|
53
|
+
print(f"Image saved to {filename}")
|
54
|
+
|
55
|
+
|
56
|
+
def generate_google_image(prompt, aspect_ratio="1:1", **kwargs):
|
57
|
+
"""
|
58
|
+
Generate an image using Google's Imagen model.
|
59
|
+
|
60
|
+
Args:
|
61
|
+
prompt: The text prompt to generate an image from
|
62
|
+
aspect_ratio: The aspect ratio of the image (e.g., "1:1", "4:3", "16:9")
|
63
|
+
**kwargs: Additional parameters to pass to the API
|
64
|
+
"""
|
65
|
+
print(f"\n=== Generating image with Google Imagen ===")
|
66
|
+
print(f"Prompt: {prompt}")
|
67
|
+
print(f"Aspect ratio: {aspect_ratio}")
|
68
|
+
|
69
|
+
try:
|
70
|
+
# Generate the image
|
71
|
+
# Note: The client will automatically convert "1024x1024" to "1:1" for Google models,
|
72
|
+
# but it's more explicit to use the correct format directly
|
73
|
+
response = client.images(
|
74
|
+
prompt=prompt,
|
75
|
+
model="google/imagen-3.0-generate-002",
|
76
|
+
size=aspect_ratio, # Google uses aspect ratios instead of pixel dimensions
|
77
|
+
**kwargs,
|
78
|
+
)
|
79
|
+
|
80
|
+
print(f"Response received from Google:")
|
81
|
+
print(f"- Success: {response['success']}")
|
82
|
+
print(f"- Cost: ${response['usage']['cost']:.4f}")
|
83
|
+
|
84
|
+
# Check if we have image data
|
85
|
+
if "data" in response and response["data"]:
|
86
|
+
image_data = response["data"][0]
|
87
|
+
|
88
|
+
# Create a timestamp for unique filenames
|
89
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
90
|
+
|
91
|
+
if "url" in image_data and image_data["url"]:
|
92
|
+
filename = (
|
93
|
+
f"google_imagen_{aspect_ratio.replace(':', 'x')}_{timestamp}.png"
|
94
|
+
)
|
95
|
+
save_image_from_url(image_data["url"], filename)
|
96
|
+
|
97
|
+
# Display in notebook if possible
|
98
|
+
if in_notebook:
|
99
|
+
display(Image(url=image_data["url"]))
|
100
|
+
|
101
|
+
elif "b64_json" in image_data and image_data["b64_json"]:
|
102
|
+
filename = (
|
103
|
+
f"google_imagen_{aspect_ratio.replace(':', 'x')}_{timestamp}.png"
|
104
|
+
)
|
105
|
+
save_image_from_b64(image_data["b64_json"], filename)
|
106
|
+
|
107
|
+
# Display in notebook if possible
|
108
|
+
if in_notebook:
|
109
|
+
display(Image(data=base64.b64decode(image_data["b64_json"])))
|
110
|
+
else:
|
111
|
+
print("No image data found in response")
|
112
|
+
print("Response:", response)
|
113
|
+
|
114
|
+
except Exception as e:
|
115
|
+
print(f"Error generating image with Google Imagen: {str(e)}")
|
116
|
+
|
117
|
+
|
118
|
+
def main():
|
119
|
+
"""Main function demonstrating Google Imagen image generation."""
|
120
|
+
|
121
|
+
# Basic example with 1:1 aspect ratio (square image)
|
122
|
+
generate_google_image(
|
123
|
+
prompt="A tranquil zen garden with cherry blossoms and a small pond"
|
124
|
+
)
|
125
|
+
|
126
|
+
# Example with 16:9 aspect ratio (widescreen)
|
127
|
+
generate_google_image(
|
128
|
+
prompt="A wide panoramic view of a futuristic city skyline at sunset with flying vehicles",
|
129
|
+
aspect_ratio="16:9",
|
130
|
+
)
|
131
|
+
|
132
|
+
# Example with 9:16 aspect ratio (portrait/mobile)
|
133
|
+
generate_google_image(
|
134
|
+
prompt="A tall waterfall surrounded by lush greenery in a tropical forest",
|
135
|
+
aspect_ratio="9:16",
|
136
|
+
)
|
137
|
+
|
138
|
+
# Example with negative prompt to influence the generation
|
139
|
+
generate_google_image(
|
140
|
+
prompt="A detailed watercolor painting of a coastal village with boats in the harbor",
|
141
|
+
negative_prompt="dark, moody, sketch, black and white, blurry",
|
142
|
+
)
|
143
|
+
|
144
|
+
# Example with more parameters
|
145
|
+
generate_google_image(
|
146
|
+
prompt="A beautiful tiger resting in a lush jungle environment",
|
147
|
+
aspect_ratio="4:3",
|
148
|
+
negative_prompt="cartoon, illustration, low quality",
|
149
|
+
seed=123456, # Consistent results with the same seed
|
150
|
+
guidance_scale=7.5, # Controls how closely the model follows the prompt (usually between 1-20)
|
151
|
+
safety_filter_level="block_none", # Less restrictive safety filter
|
152
|
+
)
|
153
|
+
|
154
|
+
# Close the client when done
|
155
|
+
client.close()
|
156
|
+
|
157
|
+
|
158
|
+
if __name__ == "__main__":
|
159
|
+
main()
|
@@ -0,0 +1,141 @@
|
|
1
|
+
"""
|
2
|
+
Example script demonstrating image generation with various providers through indoxRouter.
|
3
|
+
|
4
|
+
This script shows how to generate images using different providers (OpenAI, xAI, Google)
|
5
|
+
and how to handle the responses to display or save the generated images.
|
6
|
+
|
7
|
+
Requirements:
|
8
|
+
- Install indoxRouter: pip install indoxrouter
|
9
|
+
- Set INDOX_ROUTER_API_KEY environment variable with your API key
|
10
|
+
"""
|
11
|
+
|
12
|
+
import os
|
13
|
+
import base64
|
14
|
+
from io import BytesIO
|
15
|
+
import requests
|
16
|
+
from datetime import datetime
|
17
|
+
|
18
|
+
from indoxrouter import Client
|
19
|
+
|
20
|
+
# For displaying images in notebooks
|
21
|
+
try:
|
22
|
+
from IPython.display import Image, display
|
23
|
+
|
24
|
+
in_notebook = True
|
25
|
+
except ImportError:
|
26
|
+
in_notebook = False
|
27
|
+
|
28
|
+
# Initialize client with API key from environment variable
|
29
|
+
client = Client()
|
30
|
+
|
31
|
+
|
32
|
+
def save_image_from_url(url, filename):
|
33
|
+
"""Download and save an image from a URL."""
|
34
|
+
response = requests.get(url)
|
35
|
+
if response.status_code == 200:
|
36
|
+
with open(filename, "wb") as f:
|
37
|
+
f.write(response.content)
|
38
|
+
print(f"Image saved to {filename}")
|
39
|
+
else:
|
40
|
+
print(f"Failed to download image: {response.status_code}")
|
41
|
+
|
42
|
+
|
43
|
+
def save_image_from_b64(b64_data, filename):
|
44
|
+
"""Save an image from base64 data."""
|
45
|
+
image_data = base64.b64decode(b64_data)
|
46
|
+
with open(filename, "wb") as f:
|
47
|
+
f.write(image_data)
|
48
|
+
print(f"Image saved to {filename}")
|
49
|
+
|
50
|
+
|
51
|
+
def generate_and_save_image(provider, model, prompt):
|
52
|
+
"""Generate an image and save it to a file."""
|
53
|
+
print(f"\n=== Generating image with {provider}/{model} ===")
|
54
|
+
print(f"Prompt: {prompt}")
|
55
|
+
|
56
|
+
try:
|
57
|
+
# Generate the image
|
58
|
+
response = client.images(
|
59
|
+
prompt=prompt,
|
60
|
+
model=f"{provider}/{model}",
|
61
|
+
size="1024x1024",
|
62
|
+
)
|
63
|
+
|
64
|
+
print(f"Response received from {provider}:")
|
65
|
+
print(f"- Success: {response['success']}")
|
66
|
+
print(f"- Cost: ${response['usage']['cost']:.4f}")
|
67
|
+
|
68
|
+
# Check if we have image data
|
69
|
+
if "data" in response and response["data"]:
|
70
|
+
image_data = response["data"][0]
|
71
|
+
|
72
|
+
# Create a timestamp for unique filenames
|
73
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
74
|
+
|
75
|
+
if "url" in image_data and image_data["url"]:
|
76
|
+
filename = f"{provider}_{model}_{timestamp}.png"
|
77
|
+
save_image_from_url(image_data["url"], filename)
|
78
|
+
|
79
|
+
# Display in notebook if possible
|
80
|
+
if in_notebook:
|
81
|
+
display(Image(url=image_data["url"]))
|
82
|
+
|
83
|
+
elif "b64_json" in image_data and image_data["b64_json"]:
|
84
|
+
filename = f"{provider}_{model}_{timestamp}.png"
|
85
|
+
save_image_from_b64(image_data["b64_json"], filename)
|
86
|
+
|
87
|
+
# Display in notebook if possible
|
88
|
+
if in_notebook:
|
89
|
+
display(Image(data=base64.b64decode(image_data["b64_json"])))
|
90
|
+
|
91
|
+
# Check for revised prompt (DALL-E 3 often revises prompts)
|
92
|
+
if "revised_prompt" in image_data and image_data["revised_prompt"]:
|
93
|
+
print(f"Revised prompt: {image_data['revised_prompt']}")
|
94
|
+
else:
|
95
|
+
print("No image data found in response")
|
96
|
+
print("Response:", response)
|
97
|
+
|
98
|
+
except Exception as e:
|
99
|
+
print(f"Error generating image with {provider}/{model}: {str(e)}")
|
100
|
+
|
101
|
+
|
102
|
+
# Example prompts
|
103
|
+
prompts = {
|
104
|
+
"landscape": "A beautiful mountain landscape with a lake at sunset",
|
105
|
+
"animal": "A cute puppy playing with a ball in a garden",
|
106
|
+
"abstract": "An abstract digital art piece with vibrant colors and geometric shapes",
|
107
|
+
"space": "A realistic view of Earth from space with the moon in the background",
|
108
|
+
}
|
109
|
+
|
110
|
+
|
111
|
+
def main():
|
112
|
+
# Test OpenAI models
|
113
|
+
generate_and_save_image("openai", "dall-e-2", prompts["landscape"])
|
114
|
+
generate_and_save_image("openai", "dall-e-3", prompts["animal"])
|
115
|
+
|
116
|
+
# Test with gpt-image-1 if available
|
117
|
+
try:
|
118
|
+
generate_and_save_image("openai", "gpt-image-1", prompts["abstract"])
|
119
|
+
except Exception as e:
|
120
|
+
print(f"gpt-image-1 test skipped: {str(e)}")
|
121
|
+
|
122
|
+
# Test xAI models
|
123
|
+
try:
|
124
|
+
generate_and_save_image("xai", "grok-2-image", prompts["space"])
|
125
|
+
except Exception as e:
|
126
|
+
print(f"xAI test skipped: {str(e)}")
|
127
|
+
|
128
|
+
# Test Google models
|
129
|
+
try:
|
130
|
+
generate_and_save_image(
|
131
|
+
"google", "imagen-3.0-generate-002", prompts["abstract"]
|
132
|
+
)
|
133
|
+
except Exception as e:
|
134
|
+
print(f"Google test skipped: {str(e)}")
|
135
|
+
|
136
|
+
# Close the client
|
137
|
+
client.close()
|
138
|
+
|
139
|
+
|
140
|
+
if __name__ == "__main__":
|
141
|
+
main()
|
@@ -399,6 +399,48 @@ class Client:
|
|
399
399
|
# is having issues with JSON formatted model strings
|
400
400
|
return model
|
401
401
|
|
402
|
+
def _format_image_size_for_provider(
|
403
|
+
self, size: str, provider: str, model: str
|
404
|
+
) -> str:
|
405
|
+
"""
|
406
|
+
Format the image size parameter based on the provider's requirements.
|
407
|
+
|
408
|
+
Google requires aspect ratios like "1:1", "4:3", etc. while OpenAI uses pixel dimensions
|
409
|
+
like "1024x1024", "512x512", etc.
|
410
|
+
|
411
|
+
Args:
|
412
|
+
size: The size parameter (e.g., "1024x1024")
|
413
|
+
provider: The provider name (e.g., "google", "openai")
|
414
|
+
model: The model name
|
415
|
+
|
416
|
+
Returns:
|
417
|
+
Formatted size parameter appropriate for the provider
|
418
|
+
"""
|
419
|
+
if provider.lower() == "google":
|
420
|
+
# Google uses aspect ratios instead of pixel dimensions
|
421
|
+
# Convert common pixel dimensions to aspect ratios
|
422
|
+
size_to_aspect_ratio = {
|
423
|
+
"1024x1024": "1:1",
|
424
|
+
"512x512": "1:1",
|
425
|
+
"256x256": "1:1",
|
426
|
+
"1024x768": "4:3",
|
427
|
+
"768x1024": "3:4",
|
428
|
+
"1024x1536": "2:3",
|
429
|
+
"1536x1024": "3:2",
|
430
|
+
"1792x1024": "16:9",
|
431
|
+
"1024x1792": "9:16",
|
432
|
+
}
|
433
|
+
|
434
|
+
# Check if size is already in aspect ratio format (contains a colon)
|
435
|
+
if ":" in size:
|
436
|
+
return size
|
437
|
+
|
438
|
+
# Convert to aspect ratio if we have a mapping, otherwise use default 1:1
|
439
|
+
return size_to_aspect_ratio.get(size, "1:1")
|
440
|
+
|
441
|
+
# For other providers, return the original size
|
442
|
+
return size
|
443
|
+
|
402
444
|
def chat(
|
403
445
|
self,
|
404
446
|
messages: List[Dict[str, str]],
|
@@ -531,10 +573,10 @@ class Client:
|
|
531
573
|
self,
|
532
574
|
prompt: str,
|
533
575
|
model: str = DEFAULT_IMAGE_MODEL,
|
534
|
-
size: str =
|
535
|
-
n: int =
|
536
|
-
quality: str =
|
537
|
-
style: str =
|
576
|
+
size: Optional[str] = None,
|
577
|
+
n: Optional[int] = None,
|
578
|
+
quality: Optional[str] = None,
|
579
|
+
style: Optional[str] = None,
|
538
580
|
# Standard parameters
|
539
581
|
response_format: Optional[str] = None,
|
540
582
|
user: Optional[str] = None,
|
@@ -563,10 +605,13 @@ class Client:
|
|
563
605
|
Args:
|
564
606
|
prompt: Text prompt
|
565
607
|
model: Model to use in the format "provider/model" (e.g., "openai/dall-e-3", "google/imagen-3.0-generate-002")
|
566
|
-
|
608
|
+
|
609
|
+
# Provider-specific parameters - will only be included if explicitly provided
|
610
|
+
# Note: Different providers support different parameters
|
611
|
+
size: Image size - For OpenAI: "1024x1024", "512x512", etc. For Google: "1:1", "4:3", etc.
|
567
612
|
n: Number of images to generate
|
568
|
-
quality: Image quality (e.g., "standard", "hd")
|
569
|
-
style: Image style (e.g., "vivid", "natural")
|
613
|
+
quality: Image quality (e.g., "standard", "hd") - supported by some providers
|
614
|
+
style: Image style (e.g., "vivid", "natural") - supported by some providers
|
570
615
|
|
571
616
|
# Standard parameters
|
572
617
|
response_format: Format of the response - "url" or "b64_json"
|
@@ -599,22 +644,40 @@ class Client:
|
|
599
644
|
# Format the model string
|
600
645
|
formatted_model = self._format_model_string(model)
|
601
646
|
|
647
|
+
# Extract provider from model string if present
|
648
|
+
provider = "openai" # Default provider
|
649
|
+
if "/" in model:
|
650
|
+
provider, _ = model.split("/", 1)
|
651
|
+
|
602
652
|
# Filter out problematic parameters
|
603
653
|
filtered_kwargs = {}
|
604
654
|
for key, value in kwargs.items():
|
605
655
|
if key not in ["return_generator"]: # List of parameters to exclude
|
606
656
|
filtered_kwargs[key] = value
|
607
657
|
|
608
|
-
# Create the base request data
|
658
|
+
# Create the base request data with only the required parameters
|
609
659
|
data = {
|
610
660
|
"prompt": prompt,
|
611
661
|
"model": formatted_model,
|
612
|
-
"n": n,
|
613
|
-
"size": size,
|
614
|
-
"quality": quality,
|
615
|
-
"style": style,
|
616
662
|
}
|
617
663
|
|
664
|
+
# Add optional parameters only if they are explicitly provided
|
665
|
+
if n is not None:
|
666
|
+
data["n"] = n
|
667
|
+
|
668
|
+
# Handle size parameter with provider-specific formatting
|
669
|
+
if size is not None:
|
670
|
+
formatted_size = self._format_image_size_for_provider(size, provider, model)
|
671
|
+
data["size"] = formatted_size
|
672
|
+
elif provider.lower() == "google":
|
673
|
+
# Default size for Google if not provided
|
674
|
+
data["size"] = "1:1"
|
675
|
+
|
676
|
+
if quality is not None:
|
677
|
+
data["quality"] = quality
|
678
|
+
if style is not None:
|
679
|
+
data["style"] = style
|
680
|
+
|
618
681
|
# Add standard parameters if provided
|
619
682
|
if response_format is not None:
|
620
683
|
data["response_format"] = response_format
|
@@ -3,6 +3,8 @@ README.md
|
|
3
3
|
pyproject.toml
|
4
4
|
cookbook/README.md
|
5
5
|
cookbook/indoxRouter_cookbook.ipynb
|
6
|
+
examples/google_image_generation.py
|
7
|
+
examples/image_generation.py
|
6
8
|
indoxrouter/__init__.py
|
7
9
|
indoxrouter/client.py
|
8
10
|
indoxrouter/constants.py
|
@@ -11,4 +13,5 @@ indoxrouter.egg-info/PKG-INFO
|
|
11
13
|
indoxrouter.egg-info/SOURCES.txt
|
12
14
|
indoxrouter.egg-info/dependency_links.txt
|
13
15
|
indoxrouter.egg-info/requires.txt
|
14
|
-
indoxrouter.egg-info/top_level.txt
|
16
|
+
indoxrouter.egg-info/top_level.txt
|
17
|
+
tests/test_image.py
|
@@ -0,0 +1,93 @@
|
|
1
|
+
"""
|
2
|
+
Test the image generation functionality of the IndoxRouter client.
|
3
|
+
"""
|
4
|
+
|
5
|
+
import unittest
|
6
|
+
from unittest.mock import patch, MagicMock
|
7
|
+
import os
|
8
|
+
from indoxrouter import Client
|
9
|
+
|
10
|
+
|
11
|
+
class TestImageGeneration(unittest.TestCase):
|
12
|
+
"""Test the image generation functionality."""
|
13
|
+
|
14
|
+
def setUp(self):
|
15
|
+
"""Set up the test case."""
|
16
|
+
# Use a mock API key for testing
|
17
|
+
self.api_key = "test_api_key"
|
18
|
+
|
19
|
+
# Create a patched client that doesn't make real API calls
|
20
|
+
with patch("indoxrouter.client.requests.Session") as mock_session:
|
21
|
+
# Mock successful authentication response
|
22
|
+
mock_response = MagicMock()
|
23
|
+
mock_response.status_code = 200
|
24
|
+
mock_response.json.return_value = {"access_token": "mock_token"}
|
25
|
+
mock_session.return_value.post.return_value = mock_response
|
26
|
+
|
27
|
+
# Create client with mocked session
|
28
|
+
self.client = Client(api_key=self.api_key)
|
29
|
+
self.client._request = MagicMock() # Replace _request with mock
|
30
|
+
|
31
|
+
def test_image_generation_response_format(self):
|
32
|
+
"""Test that the image generation response format is correct."""
|
33
|
+
# Mock response data that matches what we expect from the server
|
34
|
+
mock_response = {
|
35
|
+
"request_id": "test-request-id",
|
36
|
+
"created_at": "2025-05-29T11:39:24.621706",
|
37
|
+
"duration_ms": 12340.412378311157,
|
38
|
+
"provider": "openai",
|
39
|
+
"model": "dall-e-2",
|
40
|
+
"success": True,
|
41
|
+
"message": "",
|
42
|
+
"usage": {
|
43
|
+
"tokens_prompt": 0,
|
44
|
+
"tokens_completion": 0,
|
45
|
+
"tokens_total": 0,
|
46
|
+
"cost": 0.016,
|
47
|
+
"latency": 12.240789651870728,
|
48
|
+
"timestamp": "2025-05-29T11:39:24.612377",
|
49
|
+
},
|
50
|
+
"data": [
|
51
|
+
{
|
52
|
+
"url": "https://example.com/generated-image.png",
|
53
|
+
"revised_prompt": "A beautiful sunset over the ocean with clouds.",
|
54
|
+
}
|
55
|
+
],
|
56
|
+
}
|
57
|
+
|
58
|
+
# Set the mock response for the _request method
|
59
|
+
self.client._request.return_value = mock_response
|
60
|
+
|
61
|
+
# Call the images method
|
62
|
+
response = self.client.images(
|
63
|
+
prompt="A beautiful sunset over the ocean",
|
64
|
+
model="openai/dall-e-2",
|
65
|
+
size="1024x1024",
|
66
|
+
)
|
67
|
+
|
68
|
+
# Verify the client made the request with the correct parameters
|
69
|
+
self.client._request.assert_called_once()
|
70
|
+
call_args = self.client._request.call_args[0]
|
71
|
+
|
72
|
+
# Verify the response format
|
73
|
+
self.assertEqual(response["success"], True)
|
74
|
+
self.assertEqual(response["provider"], "openai")
|
75
|
+
self.assertEqual(response["model"], "dall-e-2")
|
76
|
+
|
77
|
+
# Verify the data contains the image URL
|
78
|
+
self.assertIn("data", response)
|
79
|
+
self.assertIsInstance(response["data"], list)
|
80
|
+
self.assertEqual(len(response["data"]), 1)
|
81
|
+
self.assertIn("url", response["data"][0])
|
82
|
+
self.assertEqual(
|
83
|
+
response["data"][0]["url"], "https://example.com/generated-image.png"
|
84
|
+
)
|
85
|
+
|
86
|
+
# Verify usage information
|
87
|
+
self.assertIn("usage", response)
|
88
|
+
self.assertIn("cost", response["usage"])
|
89
|
+
self.assertGreater(response["usage"]["cost"], 0)
|
90
|
+
|
91
|
+
|
92
|
+
if __name__ == "__main__":
|
93
|
+
unittest.main()
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|