indoxrouter 0.1.15__py3-none-any.whl → 0.1.17__py3-none-any.whl

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/__init__.py CHANGED
@@ -30,7 +30,7 @@ For custom server URLs:
30
30
  ```
31
31
  """
32
32
 
33
- from .client import Client
33
+ from .client import Client, IndoxRouter
34
34
  from .exceptions import (
35
35
  IndoxRouterError,
36
36
  AuthenticationError,
@@ -39,13 +39,18 @@ from .exceptions import (
39
39
  ProviderError,
40
40
  ModelNotFoundError,
41
41
  ProviderNotFoundError,
42
+ ModelNotAvailableError,
42
43
  InvalidParametersError,
44
+ RequestError,
43
45
  InsufficientCreditsError,
46
+ ValidationError,
47
+ APIError,
44
48
  )
45
49
 
46
50
  __version__ = "0.2.1"
47
51
  __all__ = [
48
52
  "Client",
53
+ "IndoxRouter",
49
54
  "IndoxRouterError",
50
55
  "AuthenticationError",
51
56
  "NetworkError",
@@ -53,6 +58,10 @@ __all__ = [
53
58
  "ProviderError",
54
59
  "ModelNotFoundError",
55
60
  "ProviderNotFoundError",
61
+ "ModelNotAvailableError",
56
62
  "InvalidParametersError",
63
+ "RequestError",
57
64
  "InsufficientCreditsError",
65
+ "ValidationError",
66
+ "APIError",
58
67
  ]
indoxrouter/client.py CHANGED
@@ -57,10 +57,14 @@ from .exceptions import (
57
57
  NetworkError,
58
58
  ProviderNotFoundError,
59
59
  ModelNotFoundError,
60
+ ModelNotAvailableError,
60
61
  InvalidParametersError,
61
62
  RateLimitError,
62
63
  ProviderError,
64
+ RequestError,
63
65
  InsufficientCreditsError,
66
+ ValidationError,
67
+ APIError,
64
68
  )
65
69
  from .constants import (
66
70
  DEFAULT_BASE_URL,
@@ -316,29 +320,57 @@ class Client:
316
320
  if "provider" in error_message.lower():
317
321
  raise ProviderNotFoundError(error_message)
318
322
  elif "model" in error_message.lower():
319
- raise ModelNotFoundError(error_message)
323
+ # Check if it's a model not found vs model not available
324
+ if (
325
+ "not supported" in error_message.lower()
326
+ or "disabled" in error_message.lower()
327
+ or "unavailable" in error_message.lower()
328
+ ):
329
+ raise ModelNotAvailableError(error_message)
330
+ else:
331
+ raise ModelNotFoundError(error_message)
320
332
  else:
321
- raise NetworkError(
322
- f"Resource not found: {error_message} (URL: {url})"
323
- )
333
+ raise APIError(f"Resource not found: {error_message} (URL: {url})")
324
334
  elif status_code == 429:
325
335
  raise RateLimitError(f"Rate limit exceeded: {error_message}")
326
336
  elif status_code == 400:
327
- raise InvalidParametersError(f"Invalid parameters: {error_message}")
337
+ # Check if it's a validation error or invalid parameters
338
+ if (
339
+ "validation" in error_message.lower()
340
+ or "invalid format" in error_message.lower()
341
+ ):
342
+ raise ValidationError(f"Request validation failed: {error_message}")
343
+ else:
344
+ raise InvalidParametersError(f"Invalid parameters: {error_message}")
328
345
  elif status_code == 402:
329
346
  raise InsufficientCreditsError(f"Insufficient credits: {error_message}")
347
+ elif status_code == 422:
348
+ # Unprocessable Entity - typically validation errors
349
+ raise ValidationError(f"Request validation failed: {error_message}")
350
+ elif status_code == 503:
351
+ # Service Unavailable - model might be temporarily unavailable
352
+ if "model" in error_message.lower():
353
+ raise ModelNotAvailableError(
354
+ f"Model temporarily unavailable: {error_message}"
355
+ )
356
+ else:
357
+ raise APIError(f"Service unavailable: {error_message}")
330
358
  elif status_code == 500:
331
359
  # Provide more detailed information for server errors
332
360
  error_detail = error_data.get("detail", "No details provided")
333
361
  # Include the request data in the error message for better debugging
334
362
  request_data_str = json.dumps(data, indent=2) if data else "None"
335
- raise ProviderError(
363
+ raise RequestError(
336
364
  f"Server error (500): {error_detail}. URL: {url}.\n"
337
365
  f"Request data: {request_data_str}\n"
338
366
  f"This may indicate an issue with the server configuration or a problem with the provider service."
339
367
  )
368
+ elif status_code >= 400 and status_code < 500:
369
+ # Client errors
370
+ raise APIError(f"Client error ({status_code}): {error_message}")
340
371
  else:
341
- raise ProviderError(f"Provider error ({status_code}): {error_message}")
372
+ # Server errors
373
+ raise RequestError(f"Server error ({status_code}): {error_message}")
342
374
  except requests.RequestException as e:
343
375
  logger.error(f"Request exception: {str(e)}")
344
376
  raise NetworkError(f"Network error: {str(e)}")
@@ -503,6 +535,26 @@ class Client:
503
535
  n: int = 1,
504
536
  quality: str = "standard",
505
537
  style: str = "vivid",
538
+ # Standard parameters
539
+ response_format: Optional[str] = None,
540
+ user: Optional[str] = None,
541
+ # OpenAI-specific parameters
542
+ background: Optional[str] = None,
543
+ moderation: Optional[str] = None,
544
+ output_compression: Optional[int] = None,
545
+ output_format: Optional[str] = None,
546
+ # Google-specific parameters
547
+ negative_prompt: Optional[str] = None,
548
+ guidance_scale: Optional[float] = None,
549
+ seed: Optional[int] = None,
550
+ safety_filter_level: Optional[str] = None,
551
+ person_generation: Optional[str] = None,
552
+ include_safety_attributes: Optional[bool] = None,
553
+ include_rai_reason: Optional[bool] = None,
554
+ language: Optional[str] = None,
555
+ output_mime_type: Optional[str] = None,
556
+ add_watermark: Optional[bool] = None,
557
+ enhance_prompt: Optional[bool] = None,
506
558
  **kwargs,
507
559
  ) -> Dict[str, Any]:
508
560
  """
@@ -510,11 +562,35 @@ class Client:
510
562
 
511
563
  Args:
512
564
  prompt: Text prompt
513
- model: Model to use in the format "provider/model" (e.g., "openai/dall-e-3")
565
+ model: Model to use in the format "provider/model" (e.g., "openai/dall-e-3", "google/imagen-3.0-generate-002")
514
566
  size: Image size (e.g., "1024x1024")
515
567
  n: Number of images to generate
516
568
  quality: Image quality (e.g., "standard", "hd")
517
569
  style: Image style (e.g., "vivid", "natural")
570
+
571
+ # Standard parameters
572
+ response_format: Format of the response - "url" or "b64_json"
573
+ user: A unique identifier for the end-user
574
+
575
+ # OpenAI-specific parameters
576
+ background: Background style - "transparent", "opaque", or "auto"
577
+ moderation: Moderation level - "low" or "auto"
578
+ output_compression: Compression quality for output images (0-100)
579
+ output_format: Output format - "png", "jpeg", or "webp"
580
+
581
+ # Google-specific parameters
582
+ negative_prompt: Description of what to discourage in the generated images
583
+ guidance_scale: Controls how much the model adheres to the prompt
584
+ seed: Random seed for image generation
585
+ safety_filter_level: Filter level for safety filtering
586
+ person_generation: Controls generation of people ("dont_allow", "allow_adult", "allow_all")
587
+ include_safety_attributes: Whether to report safety scores of generated images
588
+ include_rai_reason: Whether to include filter reason if the image is filtered
589
+ language: Language of the text in the prompt
590
+ output_mime_type: MIME type of the generated image
591
+ add_watermark: Whether to add a watermark to the generated images
592
+ enhance_prompt: Whether to use prompt rewriting logic
593
+
518
594
  **kwargs: Additional parameters to pass to the API
519
595
 
520
596
  Returns:
@@ -529,6 +605,7 @@ class Client:
529
605
  if key not in ["return_generator"]: # List of parameters to exclude
530
606
  filtered_kwargs[key] = value
531
607
 
608
+ # Create the base request data
532
609
  data = {
533
610
  "prompt": prompt,
534
611
  "model": formatted_model,
@@ -536,9 +613,52 @@ class Client:
536
613
  "size": size,
537
614
  "quality": quality,
538
615
  "style": style,
539
- "additional_params": filtered_kwargs,
540
616
  }
541
617
 
618
+ # Add standard parameters if provided
619
+ if response_format is not None:
620
+ data["response_format"] = response_format
621
+ if user is not None:
622
+ data["user"] = user
623
+
624
+ # Add OpenAI-specific parameters if provided
625
+ if background is not None:
626
+ data["background"] = background
627
+ if moderation is not None:
628
+ data["moderation"] = moderation
629
+ if output_compression is not None:
630
+ data["output_compression"] = output_compression
631
+ if output_format is not None:
632
+ data["output_format"] = output_format
633
+
634
+ # Add Google-specific parameters if provided
635
+ if negative_prompt is not None:
636
+ data["negative_prompt"] = negative_prompt
637
+ if guidance_scale is not None:
638
+ data["guidance_scale"] = guidance_scale
639
+ if seed is not None:
640
+ data["seed"] = seed
641
+ if safety_filter_level is not None:
642
+ data["safety_filter_level"] = safety_filter_level
643
+ if person_generation is not None:
644
+ data["person_generation"] = person_generation
645
+ if include_safety_attributes is not None:
646
+ data["include_safety_attributes"] = include_safety_attributes
647
+ if include_rai_reason is not None:
648
+ data["include_rai_reason"] = include_rai_reason
649
+ if language is not None:
650
+ data["language"] = language
651
+ if output_mime_type is not None:
652
+ data["output_mime_type"] = output_mime_type
653
+ if add_watermark is not None:
654
+ data["add_watermark"] = add_watermark
655
+ if enhance_prompt is not None:
656
+ data["enhance_prompt"] = enhance_prompt
657
+
658
+ # Add any remaining parameters
659
+ if filtered_kwargs:
660
+ data["additional_params"] = filtered_kwargs
661
+
542
662
  return self._request("POST", IMAGE_ENDPOINT, data)
543
663
 
544
664
  def models(self, provider: Optional[str] = None) -> Dict[str, Any]:
indoxrouter/constants.py CHANGED
@@ -13,6 +13,10 @@ USE_COOKIES = True # Always use cookie-based authentication
13
13
  DEFAULT_MODEL = "openai/gpt-4o-mini"
14
14
  DEFAULT_EMBEDDING_MODEL = "openai/text-embedding-3-small"
15
15
  DEFAULT_IMAGE_MODEL = "openai/dall-e-3"
16
+ GOOGLE_IMAGE_MODEL = "google/imagen-3.0-generate-002"
17
+ XAI_IMAGE_MODEL = "xai/grok-2-image"
18
+ XAI_IMAGE_LATEST_MODEL = "xai/grok-2-image-latest"
19
+ XAI_IMAGE_SPECIFIC_MODEL = "xai/grok-2-image-1212"
16
20
 
17
21
  # API endpoints
18
22
  CHAT_ENDPOINT = "chat/completions"
indoxrouter/exceptions.py CHANGED
@@ -38,14 +38,20 @@ class ProviderError(IndoxRouterError):
38
38
  pass
39
39
 
40
40
 
41
+ class ProviderNotFoundError(ProviderError):
42
+ """Raised when a requested provider is not found."""
43
+
44
+ pass
45
+
46
+
41
47
  class ModelNotFoundError(ProviderError):
42
48
  """Raised when a requested model is not found."""
43
49
 
44
50
  pass
45
51
 
46
52
 
47
- class ProviderNotFoundError(ProviderError):
48
- """Raised when a requested provider is not found."""
53
+ class ModelNotAvailableError(ProviderError):
54
+ """Raised when a model is disabled or not supported by the provider."""
49
55
 
50
56
  pass
51
57
 
@@ -56,7 +62,25 @@ class InvalidParametersError(IndoxRouterError):
56
62
  pass
57
63
 
58
64
 
65
+ class RequestError(IndoxRouterError):
66
+ """Raised when a request to a provider fails."""
67
+
68
+ pass
69
+
70
+
59
71
  class InsufficientCreditsError(IndoxRouterError):
60
72
  """Raised when the user doesn't have enough credits."""
61
73
 
62
74
  pass
75
+
76
+
77
+ class ValidationError(IndoxRouterError):
78
+ """Raised when request validation fails."""
79
+
80
+ pass
81
+
82
+
83
+ class APIError(IndoxRouterError):
84
+ """Raised when the API returns an error."""
85
+
86
+ pass
@@ -1,9 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: indoxrouter
3
- Version: 0.1.15
3
+ Version: 0.1.17
4
4
  Summary: A unified client for various AI providers
5
5
  Author-email: indoxRouter Team <ashkan.eskandari.dev@gmail.com>
6
+ License: MIT
6
7
  Project-URL: Homepage, https://github.com/indoxrouter/indoxrouter
8
+ Project-URL: Repository, https://github.com/indoxrouter/indoxrouter
9
+ Project-URL: Issues, https://github.com/indoxrouter/indoxrouter/issues
10
+ Keywords: ai,api,client,openai,anthropic,google,mistral,xai,imagen,grok,image-generation
7
11
  Classifier: Development Status :: 3 - Alpha
8
12
  Classifier: Intended Audience :: Developers
9
13
  Classifier: Programming Language :: Python :: 3
@@ -129,13 +133,43 @@ print(f"First embedding: {response['data'][0]['embedding'][:5]}...")
129
133
  ### Image Generation
130
134
 
131
135
  ```python
136
+ # OpenAI Image Generation
132
137
  response = client.images(
133
138
  prompt="A serene landscape with mountains and a lake",
134
139
  model="openai/dall-e-3",
135
- size="1024x1024"
140
+ size="1024x1024",
141
+ quality="standard", # Options: standard, hd
142
+ style="vivid" # Options: vivid, natural
136
143
  )
137
144
 
138
145
  print(f"Image URL: {response['data'][0]['url']}")
146
+
147
+ # Google Imagen Image Generation
148
+ from indoxrouter.constants import GOOGLE_IMAGE_MODEL
149
+
150
+ response = client.images(
151
+ prompt="A robot holding a red skateboard in a futuristic city",
152
+ model=GOOGLE_IMAGE_MODEL,
153
+ n=2, # Generate 2 images
154
+ negative_prompt="broken, damaged, low quality",
155
+ guidance_scale=7.5, # Control adherence to prompt
156
+ seed=42, # For reproducible results
157
+ )
158
+
159
+ # xAI Grok Image Generation
160
+ from indoxrouter.constants import XAI_IMAGE_MODEL
161
+
162
+ response = client.images(
163
+ prompt="A cat in a tree",
164
+ model=XAI_IMAGE_MODEL,
165
+ n=1,
166
+ response_format="b64_json" # Get base64 encoded image
167
+ )
168
+
169
+ # Access base64 encoded image data
170
+ if "b64_json" in response["data"][0]:
171
+ b64_data = response["data"][0]["b64_json"]
172
+ # Use the base64 data (e.g., to display in HTML or save to file)
139
173
  ```
140
174
 
141
175
  ### Streaming Responses
@@ -0,0 +1,8 @@
1
+ indoxrouter/__init__.py,sha256=kwGvH8F5oqm2O4kLs-UtPfcY0AYiy5ZDUg-Sh3iYJA4,1627
2
+ indoxrouter/client.py,sha256=0FZ-7mgE_kxbRpmRwJrucpvHme4MQOToX2VqVw9PKQE,34706
3
+ indoxrouter/constants.py,sha256=GezZ9nuwK3A37xpWlcfXCrMsIIlCdP7xnvEkPBMyn5g,1383
4
+ indoxrouter/exceptions.py,sha256=qs7f9AnJ7SkOyf9N5qRaZIKpECE8uBq1Pvcg19Jif-U,1718
5
+ indoxrouter-0.1.17.dist-info/METADATA,sha256=XFpOPo3DdQQuiPzmAOTbQvVc0bJRxPgD6FkNLkEyMFA,6639
6
+ indoxrouter-0.1.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
7
+ indoxrouter-0.1.17.dist-info/top_level.txt,sha256=v6FGWkw0QAnXhyYtnXLI1cxzna0iveNvZUotVzCWabM,12
8
+ indoxrouter-0.1.17.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,8 +0,0 @@
1
- indoxrouter/__init__.py,sha256=28pdx482uGFF_S1msov0LTTGsFTvVBKRqMkDmoXWUBY,1416
2
- indoxrouter/client.py,sha256=ixzCJP28ddYFQxwRiqdY5Fp1CB978DJpI4yCiOI3s4o,28898
3
- indoxrouter/constants.py,sha256=tEmfhfCpuKVos1TxVhJfPlv1P0ePWnjnwso4ZHJ0VhM,1190
4
- indoxrouter/exceptions.py,sha256=0ULxtK9va4718PGTO5VoClXYEJeojpiM-7AganeiZZ4,1263
5
- indoxrouter-0.1.15.dist-info/METADATA,sha256=CeJbcb4OaBKSTWJjsGl4wOulialexUJN6MDLYniQj-g,5428
6
- indoxrouter-0.1.15.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
7
- indoxrouter-0.1.15.dist-info/top_level.txt,sha256=v6FGWkw0QAnXhyYtnXLI1cxzna0iveNvZUotVzCWabM,12
8
- indoxrouter-0.1.15.dist-info/RECORD,,