webscout 8.3__py3-none-any.whl → 8.3.2__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.

Potentially problematic release.


This version of webscout might be problematic. Click here for more details.

Files changed (120) hide show
  1. webscout/AIauto.py +4 -4
  2. webscout/AIbase.py +61 -1
  3. webscout/AIutel.py +46 -53
  4. webscout/Bing_search.py +418 -0
  5. webscout/Extra/YTToolkit/ytapi/patterns.py +45 -45
  6. webscout/Extra/YTToolkit/ytapi/stream.py +1 -1
  7. webscout/Extra/YTToolkit/ytapi/video.py +10 -10
  8. webscout/Extra/autocoder/autocoder_utiles.py +1 -1
  9. webscout/Extra/gguf.py +706 -177
  10. webscout/Litlogger/formats.py +9 -0
  11. webscout/Litlogger/handlers.py +18 -0
  12. webscout/Litlogger/logger.py +43 -1
  13. webscout/Provider/AISEARCH/genspark_search.py +7 -7
  14. webscout/Provider/AISEARCH/scira_search.py +3 -2
  15. webscout/Provider/GeminiProxy.py +140 -0
  16. webscout/Provider/LambdaChat.py +7 -1
  17. webscout/Provider/MCPCore.py +78 -75
  18. webscout/Provider/OPENAI/BLACKBOXAI.py +1046 -1017
  19. webscout/Provider/OPENAI/GeminiProxy.py +328 -0
  20. webscout/Provider/OPENAI/Qwen3.py +303 -303
  21. webscout/Provider/OPENAI/README.md +5 -0
  22. webscout/Provider/OPENAI/README_AUTOPROXY.md +238 -0
  23. webscout/Provider/OPENAI/TogetherAI.py +355 -0
  24. webscout/Provider/OPENAI/__init__.py +16 -1
  25. webscout/Provider/OPENAI/autoproxy.py +332 -0
  26. webscout/Provider/OPENAI/base.py +101 -14
  27. webscout/Provider/OPENAI/chatgpt.py +15 -2
  28. webscout/Provider/OPENAI/chatgptclone.py +14 -3
  29. webscout/Provider/OPENAI/deepinfra.py +339 -328
  30. webscout/Provider/OPENAI/e2b.py +295 -74
  31. webscout/Provider/OPENAI/mcpcore.py +109 -70
  32. webscout/Provider/OPENAI/opkfc.py +18 -6
  33. webscout/Provider/OPENAI/scirachat.py +59 -50
  34. webscout/Provider/OPENAI/toolbaz.py +2 -10
  35. webscout/Provider/OPENAI/writecream.py +166 -166
  36. webscout/Provider/OPENAI/x0gpt.py +367 -367
  37. webscout/Provider/OPENAI/xenai.py +514 -0
  38. webscout/Provider/OPENAI/yep.py +389 -383
  39. webscout/Provider/STT/__init__.py +3 -0
  40. webscout/Provider/STT/base.py +281 -0
  41. webscout/Provider/STT/elevenlabs.py +265 -0
  42. webscout/Provider/TTI/__init__.py +4 -1
  43. webscout/Provider/TTI/aiarta.py +399 -365
  44. webscout/Provider/TTI/base.py +74 -2
  45. webscout/Provider/TTI/bing.py +231 -0
  46. webscout/Provider/TTI/fastflux.py +63 -30
  47. webscout/Provider/TTI/gpt1image.py +149 -0
  48. webscout/Provider/TTI/imagen.py +196 -0
  49. webscout/Provider/TTI/magicstudio.py +60 -29
  50. webscout/Provider/TTI/piclumen.py +43 -32
  51. webscout/Provider/TTI/pixelmuse.py +232 -225
  52. webscout/Provider/TTI/pollinations.py +43 -32
  53. webscout/Provider/TTI/together.py +287 -0
  54. webscout/Provider/TTI/utils.py +2 -1
  55. webscout/Provider/TTS/README.md +1 -0
  56. webscout/Provider/TTS/__init__.py +2 -1
  57. webscout/Provider/TTS/freetts.py +140 -0
  58. webscout/Provider/TTS/speechma.py +45 -39
  59. webscout/Provider/TogetherAI.py +366 -0
  60. webscout/Provider/UNFINISHED/ChutesAI.py +314 -0
  61. webscout/Provider/UNFINISHED/fetch_together_models.py +95 -0
  62. webscout/Provider/XenAI.py +324 -0
  63. webscout/Provider/__init__.py +8 -0
  64. webscout/Provider/deepseek_assistant.py +378 -0
  65. webscout/Provider/scira_chat.py +3 -2
  66. webscout/Provider/toolbaz.py +0 -1
  67. webscout/auth/__init__.py +44 -0
  68. webscout/auth/api_key_manager.py +189 -0
  69. webscout/auth/auth_system.py +100 -0
  70. webscout/auth/config.py +76 -0
  71. webscout/auth/database.py +400 -0
  72. webscout/auth/exceptions.py +67 -0
  73. webscout/auth/middleware.py +248 -0
  74. webscout/auth/models.py +130 -0
  75. webscout/auth/providers.py +257 -0
  76. webscout/auth/rate_limiter.py +254 -0
  77. webscout/auth/request_models.py +127 -0
  78. webscout/auth/request_processing.py +226 -0
  79. webscout/auth/routes.py +526 -0
  80. webscout/auth/schemas.py +103 -0
  81. webscout/auth/server.py +312 -0
  82. webscout/auth/static/favicon.svg +11 -0
  83. webscout/auth/swagger_ui.py +203 -0
  84. webscout/auth/templates/components/authentication.html +237 -0
  85. webscout/auth/templates/components/base.html +103 -0
  86. webscout/auth/templates/components/endpoints.html +750 -0
  87. webscout/auth/templates/components/examples.html +491 -0
  88. webscout/auth/templates/components/footer.html +75 -0
  89. webscout/auth/templates/components/header.html +27 -0
  90. webscout/auth/templates/components/models.html +286 -0
  91. webscout/auth/templates/components/navigation.html +70 -0
  92. webscout/auth/templates/static/api.js +455 -0
  93. webscout/auth/templates/static/icons.js +168 -0
  94. webscout/auth/templates/static/main.js +784 -0
  95. webscout/auth/templates/static/particles.js +201 -0
  96. webscout/auth/templates/static/styles.css +3353 -0
  97. webscout/auth/templates/static/ui.js +374 -0
  98. webscout/auth/templates/swagger_ui.html +170 -0
  99. webscout/client.py +49 -3
  100. webscout/litagent/Readme.md +12 -3
  101. webscout/litagent/agent.py +99 -62
  102. webscout/scout/core/scout.py +104 -26
  103. webscout/scout/element.py +139 -18
  104. webscout/swiftcli/core/cli.py +14 -3
  105. webscout/swiftcli/decorators/output.py +59 -9
  106. webscout/update_checker.py +31 -49
  107. webscout/version.py +1 -1
  108. webscout/webscout_search.py +4 -12
  109. webscout/webscout_search_async.py +3 -10
  110. webscout/yep_search.py +2 -11
  111. {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/METADATA +41 -11
  112. {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/RECORD +116 -68
  113. {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/entry_points.txt +1 -1
  114. webscout/Provider/HF_space/__init__.py +0 -0
  115. webscout/Provider/HF_space/qwen_qwen2.py +0 -206
  116. webscout/Provider/OPENAI/api.py +0 -1035
  117. webscout/Provider/TTI/artbit.py +0 -0
  118. {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/WHEEL +0 -0
  119. {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/licenses/LICENSE.md +0 -0
  120. {webscout-8.3.dist-info → webscout-8.3.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,149 @@
1
+ import requests
2
+ import random
3
+ import string
4
+ from typing import Optional, List, Dict, Any
5
+ from webscout.Provider.TTI.utils import (
6
+ ImageData,
7
+ ImageResponse
8
+ )
9
+ from webscout.Provider.TTI.base import TTICompatibleProvider, BaseImages
10
+ from io import BytesIO
11
+ import os
12
+ import tempfile
13
+ from webscout.litagent import LitAgent
14
+ import time
15
+ from requests.adapters import HTTPAdapter
16
+ from urllib3.util.retry import Retry
17
+
18
+
19
+ class Images(BaseImages):
20
+ def __init__(self, client):
21
+ self._client = client
22
+ self.base_url = "https://gpt1image.exomlapi.com"
23
+ # Create a session - it will automatically get proxies from the global monkey patch!
24
+ self.session = requests.Session()
25
+ self._setup_session_with_retries()
26
+
27
+ def _setup_session_with_retries(self):
28
+ """Setup session with retry strategy and timeout configurations"""
29
+ # Configure retry strategy
30
+ retry_strategy = Retry(
31
+ total=3,
32
+ status_forcelist=[429, 500, 502, 503, 504],
33
+ backoff_factor=1,
34
+ allowed_methods=["HEAD", "GET", "OPTIONS", "POST"],
35
+ )
36
+
37
+ adapter = HTTPAdapter(max_retries=retry_strategy)
38
+ self.session.mount("http://", adapter)
39
+ self.session.mount("https://", adapter)
40
+
41
+ # Set timeouts
42
+ # self.session.timeout = (10, 30) # (connect_timeout, read_timeout)
43
+ # Unlimited timeout: do not set session timeout here
44
+
45
+ def build_headers(self, extra: Optional[Dict[str, str]] = None) -> Dict[str, str]:
46
+ agent = LitAgent()
47
+ fp = agent.generate_fingerprint("chrome")
48
+ headers = {
49
+ "Content-Type": "application/json",
50
+ "accept": fp["accept"],
51
+ "accept-language": fp["accept_language"],
52
+ "origin": self.base_url,
53
+ "referer": f"{self.base_url}/",
54
+ "user-agent": fp["user_agent"],
55
+ "sec-ch-ua": fp["sec_ch_ua"],
56
+ "sec-ch-ua-mobile": "?0",
57
+ "sec-ch-ua-platform": '"Windows"',
58
+ "sec-fetch-dest": "empty",
59
+ "sec-fetch-mode": "cors",
60
+ "sec-fetch-site": "same-origin",
61
+ "x-forwarded-for": fp["x-forwarded-for"],
62
+ "x-real-ip": fp["x-real-ip"],
63
+ "x-request-id": fp["x-request-id"],
64
+ }
65
+ if extra:
66
+ headers.update(extra)
67
+ return headers
68
+
69
+ def create(
70
+ self,
71
+ model: str = None,
72
+ prompt: str = None,
73
+ n: int = 1,
74
+ size: str = "1024x1024",
75
+ response_format: str = "url",
76
+ user: Optional[str] = None,
77
+ style: str = None,
78
+ aspect_ratio: str = None,
79
+ timeout: int = 60,
80
+ image_format: str = "png",
81
+ enhance: bool = True,
82
+ **kwargs,
83
+ ) -> ImageResponse:
84
+ if not prompt:
85
+ raise ValueError(
86
+ "Describe the image you want to create (use the 'prompt' property)."
87
+ )
88
+ body = {
89
+ "prompt": prompt,
90
+ "n": n,
91
+ "size": size,
92
+ "is_enhance": enhance,
93
+ "response_format": response_format,
94
+ }
95
+ try:
96
+ # Use direct session.request instead of request_with_proxy_fallback
97
+ resp = self.session.request(
98
+ "post",
99
+ f"{self.base_url}/v1/images/generations",
100
+ json=body,
101
+ headers=self.build_headers(),
102
+ timeout=timeout,
103
+ )
104
+ data = resp.json()
105
+ if not data.get("data") or len(data["data"]) == 0:
106
+ error_info = (
107
+ f", server info: {data.get('error')}" if data.get("error") else ""
108
+ )
109
+ raise RuntimeError(
110
+ f"Failed to process image. No data found{error_info}."
111
+ )
112
+ result = data["data"]
113
+ result_data = []
114
+ for item in result:
115
+ if response_format == "url":
116
+ result_data.append(ImageData(url=item.get("url")))
117
+ else:
118
+ result_data.append(ImageData(b64_json=item.get("b64_json")))
119
+ return ImageResponse(data=result_data)
120
+ except Exception as e:
121
+ raise RuntimeError(f"An error occurred: {str(e)}")
122
+
123
+
124
+ class GPT1Image(TTICompatibleProvider):
125
+ AVAILABLE_MODELS = ["gpt1image"]
126
+
127
+ def __init__(self):
128
+ self.images = Images(self)
129
+
130
+ @property
131
+ def models(self):
132
+ class _ModelList:
133
+ def list(inner_self):
134
+ return type(self).AVAILABLE_MODELS
135
+
136
+ return _ModelList()
137
+
138
+
139
+ if __name__ == "__main__":
140
+ from rich import print
141
+
142
+ client = GPT1Image()
143
+ response = client.images.create(
144
+ prompt="A futuristic robot in a neon city",
145
+ response_format="url",
146
+ n=1,
147
+ timeout=None,
148
+ )
149
+ print(response)
@@ -0,0 +1,196 @@
1
+ import requests
2
+ import base64
3
+ from typing import Optional, List, Dict, Any
4
+ from webscout.Provider.TTI.utils import (
5
+ ImageData,
6
+ ImageResponse,
7
+ )
8
+ from webscout.Provider.TTI.base import TTICompatibleProvider, BaseImages
9
+ from webscout.litagent import LitAgent
10
+ import time
11
+
12
+
13
+ class Images(BaseImages):
14
+ def __init__(self, client):
15
+ self._client = client
16
+
17
+ def create(
18
+ self,
19
+ *,
20
+ model: str,
21
+ prompt: str,
22
+ n: int = 1,
23
+ size: str = "1024x1024",
24
+ response_format: str = "url",
25
+ user: Optional[str] = None,
26
+ style: str = "none",
27
+ aspect_ratio: str = "1:1",
28
+ timeout: int = 60,
29
+ image_format: str = "png",
30
+ seed: Optional[int] = None,
31
+ **kwargs,
32
+ ) -> ImageResponse:
33
+ """
34
+ Create images using the Imagen API.
35
+
36
+ Args:
37
+ model: The model to use (e.g., "imagen_3_5")
38
+ prompt: The text prompt for image generation
39
+ n: Number of images to generate
40
+ size: Image size (e.g., "1024x1024")
41
+ response_format: "url" or "b64_json"
42
+ timeout: Request timeout in seconds
43
+ **kwargs: Additional parameters
44
+
45
+ Returns:
46
+ ImageResponse: The generated images
47
+ """
48
+ if not prompt:
49
+ raise ValueError("Prompt is required!")
50
+
51
+ result_data = []
52
+
53
+ for _ in range(n):
54
+ # Prepare the request payload
55
+ payload = {
56
+ "prompt": prompt,
57
+ "model": model,
58
+ "size": size,
59
+ "response_format": "url", # Always request URL from API
60
+ }
61
+
62
+ try:
63
+ # Make the API request
64
+ resp = self._client.session.request(
65
+ "post",
66
+ self._client.api_endpoint,
67
+ json=payload,
68
+ timeout=timeout,
69
+ )
70
+ resp.raise_for_status()
71
+
72
+ # Parse the response
73
+ result = resp.json()
74
+
75
+ if not result or "data" not in result:
76
+ raise RuntimeError("Invalid response from Imagen API")
77
+
78
+ # Process each image in the response
79
+ for item in result["data"]:
80
+ if response_format == "url":
81
+ if "url" in item and item["url"]:
82
+ result_data.append(ImageData(url=item["url"]))
83
+ else:
84
+ raise RuntimeError("No URL found in API response")
85
+
86
+ elif response_format == "b64_json":
87
+ if "url" in item and item["url"]:
88
+ # Download the image and convert to base64
89
+ img_resp = self._client.session.request(
90
+ "get",
91
+ item["url"],
92
+ timeout=timeout,
93
+ )
94
+ img_resp.raise_for_status()
95
+ img_bytes = img_resp.content
96
+ b64_string = base64.b64encode(img_bytes).decode("utf-8")
97
+ result_data.append(ImageData(b64_json=b64_string))
98
+ elif "b64_json" in item and item["b64_json"]:
99
+ result_data.append(ImageData(b64_json=item["b64_json"]))
100
+ else:
101
+ raise RuntimeError("No image data found in API response")
102
+
103
+ else:
104
+ raise ValueError("response_format must be 'url' or 'b64_json'")
105
+
106
+ except requests.exceptions.RequestException as e:
107
+ raise RuntimeError(f"Failed to generate image with Imagen API: {e}")
108
+ except Exception as e:
109
+ raise RuntimeError(f"Error processing Imagen API response: {e}")
110
+
111
+ return ImageResponse(created=int(time.time()), data=result_data)
112
+
113
+
114
+ class ImagenAI(TTICompatibleProvider):
115
+ """
116
+ Imagen API provider for text-to-image generation.
117
+
118
+ This provider interfaces with the Imagen API at imagen.exomlapi.com
119
+ to generate images from text prompts.
120
+ """
121
+
122
+ AVAILABLE_MODELS = ["imagen_3_5", "imagen_3"]
123
+
124
+ def __init__(self, api_key: Optional[str] = None):
125
+ """
126
+ Initialize the Imagen API client.
127
+
128
+ Args:
129
+ api_key: Optional API key for authentication (if required)
130
+ """
131
+ self.api_endpoint = "https://imagen.exomlapi.com/v1/images/generations"
132
+ self.session = requests.Session()
133
+ self.user_agent = LitAgent().random()
134
+ self.api_key = api_key
135
+
136
+ # Set up headers based on the provided request details
137
+ self.headers = {
138
+ "accept": "*/*",
139
+ "accept-encoding": "gzip, deflate, br, zstd",
140
+ "accept-language": "en-US,en;q=0.9,en-IN;q=0.8",
141
+ "content-type": "application/json",
142
+ "dnt": "1",
143
+ "origin": "https://imagen.exomlapi.com",
144
+ "referer": "https://imagen.exomlapi.com/",
145
+ "sec-ch-ua": '"Chromium";v="136", "Microsoft Edge";v="136", "Not.A/Brand";v="99"',
146
+ "sec-ch-ua-mobile": "?0",
147
+ "sec-ch-ua-platform": '"Windows"',
148
+ "sec-fetch-dest": "empty",
149
+ "sec-fetch-mode": "cors",
150
+ "sec-fetch-site": "same-origin",
151
+ "sec-gpc": "1",
152
+ "user-agent": self.user_agent,
153
+ }
154
+
155
+ # Add API key to headers if provided
156
+ if self.api_key:
157
+ self.headers["authorization"] = f"Bearer {self.api_key}"
158
+
159
+ self.session.headers.update(self.headers)
160
+ self.images = Images(self)
161
+
162
+ @property
163
+ def models(self):
164
+ """
165
+ Get available models for the Imagen API.
166
+
167
+ Returns:
168
+ Object with list() method that returns available models
169
+ """
170
+
171
+ class _ModelList:
172
+ def list(inner_self):
173
+ return type(self).AVAILABLE_MODELS
174
+
175
+ return _ModelList()
176
+
177
+
178
+ if __name__ == "__main__":
179
+ from rich import print
180
+
181
+ # Example usage
182
+ client = ImagenAI()
183
+
184
+ try:
185
+ response = client.images.create(
186
+ model="imagen_3_5",
187
+ prompt="red car",
188
+ response_format="url",
189
+ n=1,
190
+ size="1024x1024",
191
+ timeout=30,
192
+ )
193
+ print("Generated image successfully:")
194
+ print(response)
195
+ except Exception as e:
196
+ print(f"Error: {e}")
@@ -4,7 +4,10 @@ import uuid
4
4
  import time
5
5
  import tempfile
6
6
  from typing import Optional, List
7
- from webscout.Provider.TTI.utils import ImageData, ImageResponse
7
+ from webscout.Provider.TTI.utils import (
8
+ ImageData,
9
+ ImageResponse
10
+ )
8
11
  from webscout.Provider.TTI.base import TTICompatibleProvider, BaseImages
9
12
  from io import BytesIO
10
13
  from webscout.litagent import LitAgent
@@ -14,11 +17,13 @@ try:
14
17
  except ImportError:
15
18
  Image = None
16
19
 
20
+
17
21
  class Images(BaseImages):
18
22
  def __init__(self, client):
19
23
  self._client = client
20
24
 
21
- def create(self,
25
+ def create(
26
+ self,
22
27
  model: str = "magicstudio",
23
28
  prompt: str = None,
24
29
  n: int = 1,
@@ -29,7 +34,7 @@ class Images(BaseImages):
29
34
  aspect_ratio: str = None,
30
35
  timeout: int = 60,
31
36
  image_format: str = "jpg",
32
- **kwargs
37
+ **kwargs,
33
38
  ) -> ImageResponse:
34
39
  if not prompt:
35
40
  raise ValueError("Prompt is required!")
@@ -43,7 +48,7 @@ class Images(BaseImages):
43
48
  "Origin": "https://magicstudio.com",
44
49
  "Referer": "https://magicstudio.com/ai-art-generator/",
45
50
  "DNT": "1",
46
- "Sec-GPC": "1"
51
+ "Sec-GPC": "1",
47
52
  }
48
53
  session = requests.Session()
49
54
  session.headers.update(headers)
@@ -57,7 +62,11 @@ class Images(BaseImages):
57
62
  "user_is_subscribed": "false",
58
63
  "client_id": uuid.uuid4().hex,
59
64
  }
60
- resp = session.post(api_url, data=form_data, timeout=timeout)
65
+ resp = session.post(
66
+ api_url,
67
+ data=form_data,
68
+ timeout=timeout,
69
+ )
61
70
  resp.raise_for_status()
62
71
  img_bytes = resp.content
63
72
  # Convert to png or jpeg in memory if needed
@@ -65,7 +74,10 @@ class Images(BaseImages):
65
74
  with BytesIO(img_bytes) as input_io:
66
75
  with Image.open(input_io) as im:
67
76
  out_io = BytesIO()
68
- if image_format.lower() == "jpeg" or image_format.lower() == "jpg":
77
+ if (
78
+ image_format.lower() == "jpeg"
79
+ or image_format.lower() == "jpg"
80
+ ):
69
81
  im = im.convert("RGB")
70
82
  im.save(out_io, format="JPEG")
71
83
  else:
@@ -73,37 +85,43 @@ class Images(BaseImages):
73
85
  img_bytes = out_io.getvalue()
74
86
  images.append(img_bytes)
75
87
  if response_format == "url":
88
+
76
89
  def upload_file_with_retry(img_bytes, image_format, max_retries=3):
77
90
  ext = "jpg" if image_format.lower() in ("jpeg", "jpg") else "png"
78
91
  for attempt in range(max_retries):
79
92
  tmp_path = None
80
93
  try:
81
- with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as tmp:
94
+ with tempfile.NamedTemporaryFile(
95
+ suffix=f".{ext}", delete=False
96
+ ) as tmp:
82
97
  tmp.write(img_bytes)
83
98
  tmp.flush()
84
99
  tmp_path = tmp.name
85
- with open(tmp_path, 'rb') as f:
100
+ with open(tmp_path, "rb") as f:
86
101
  files = {
87
- 'fileToUpload': (f'image.{ext}', f, f'image/{ext}')
102
+ "fileToUpload": (f"image.{ext}", f, f"image/{ext}")
88
103
  }
89
- data = {
90
- 'reqtype': 'fileupload',
91
- 'json': 'true'
92
- }
93
- headers = {'User-Agent': agent.random()}
104
+ data = {"reqtype": "fileupload", "json": "true"}
105
+ headers = {"User-Agent": agent.random()}
94
106
  if attempt > 0:
95
- headers['Connection'] = 'close'
96
- resp = requests.post("https://catbox.moe/user/api.php", files=files, data=data, headers=headers, timeout=timeout)
107
+ headers["Connection"] = "close"
108
+ resp = requests.post(
109
+ "https://catbox.moe/user/api.php",
110
+ files=files,
111
+ data=data,
112
+ headers=headers,
113
+ timeout=timeout,
114
+ )
97
115
  if resp.status_code == 200 and resp.text.strip():
98
116
  text = resp.text.strip()
99
- if text.startswith('http'):
117
+ if text.startswith("http"):
100
118
  return text
101
119
  try:
102
120
  result = resp.json()
103
121
  if "url" in result:
104
122
  return result["url"]
105
123
  except Exception:
106
- if 'http' in text:
124
+ if "http" in text:
107
125
  return text
108
126
  except Exception:
109
127
  if attempt < max_retries - 1:
@@ -115,22 +133,27 @@ class Images(BaseImages):
115
133
  except Exception:
116
134
  pass
117
135
  return None
136
+
118
137
  def upload_file_alternative(img_bytes, image_format):
119
138
  try:
120
- ext = "jpg" if image_format.lower() in ("jpeg", "jpg") else "png"
121
- with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as tmp:
139
+ ext = (
140
+ "jpg" if image_format.lower() in ("jpeg", "jpg") else "png"
141
+ )
142
+ with tempfile.NamedTemporaryFile(
143
+ suffix=f".{ext}", delete=False
144
+ ) as tmp:
122
145
  tmp.write(img_bytes)
123
146
  tmp.flush()
124
147
  tmp_path = tmp.name
125
148
  try:
126
149
  if not os.path.isfile(tmp_path):
127
150
  return None
128
- with open(tmp_path, 'rb') as img_file:
129
- files = {'file': img_file}
130
- alt_resp = requests.post('https://0x0.st', files=files)
151
+ with open(tmp_path, "rb") as img_file:
152
+ files = {"file": img_file}
153
+ alt_resp = requests.post("https://0x0.st", files=files)
131
154
  alt_resp.raise_for_status()
132
155
  image_url = alt_resp.text.strip()
133
- if not image_url.startswith('http'):
156
+ if not image_url.startswith("http"):
134
157
  return None
135
158
  return image_url
136
159
  except Exception:
@@ -142,32 +165,36 @@ class Images(BaseImages):
142
165
  pass
143
166
  except Exception:
144
167
  return None
168
+
145
169
  uploaded_url = upload_file_with_retry(img_bytes, image_format)
146
170
  if not uploaded_url:
147
171
  uploaded_url = upload_file_alternative(img_bytes, image_format)
148
172
  if uploaded_url:
149
173
  urls.append(uploaded_url)
150
174
  else:
151
- raise RuntimeError("Failed to upload image to catbox.moe using all available methods")
175
+ raise RuntimeError(
176
+ "Failed to upload image to catbox.moe using all available methods"
177
+ )
152
178
  result_data = []
153
179
  if response_format == "url":
154
180
  for url in urls:
155
181
  result_data.append(ImageData(url=url))
156
182
  elif response_format == "b64_json":
157
183
  import base64
184
+
158
185
  for img in images:
159
186
  b64 = base64.b64encode(img).decode("utf-8")
160
187
  result_data.append(ImageData(b64_json=b64))
161
188
  else:
162
189
  raise ValueError("response_format must be 'url' or 'b64_json'")
163
190
  from time import time as _time
164
- return ImageResponse(
165
- created=int(_time()),
166
- data=result_data
167
- )
191
+
192
+ return ImageResponse(created=int(_time()), data=result_data)
193
+
168
194
 
169
195
  class MagicStudioAI(TTICompatibleProvider):
170
196
  AVAILABLE_MODELS = ["magicstudio"]
197
+
171
198
  def __init__(self):
172
199
  self.api_endpoint = "https://ai-api.magicstudio.com/api/ai-art-generator"
173
200
  self.session = requests.Session()
@@ -182,15 +209,19 @@ class MagicStudioAI(TTICompatibleProvider):
182
209
  }
183
210
  self.session.headers.update(self.headers)
184
211
  self.images = Images(self)
212
+
185
213
  @property
186
214
  def models(self):
187
215
  class _ModelList:
188
216
  def list(inner_self):
189
217
  return type(self).AVAILABLE_MODELS
218
+
190
219
  return _ModelList()
191
220
 
221
+
192
222
  if __name__ == "__main__":
193
223
  from rich import print
224
+
194
225
  client = MagicStudioAI()
195
226
  response = client.images.create(
196
227
  prompt="A cool cyberpunk city at night",