webscout 8.2.9__py3-none-any.whl → 8.3.1__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.
- webscout/AIauto.py +6 -6
- webscout/AIbase.py +61 -1
- webscout/Extra/YTToolkit/ytapi/patterns.py +45 -45
- webscout/Extra/YTToolkit/ytapi/stream.py +1 -1
- webscout/Extra/YTToolkit/ytapi/video.py +10 -10
- webscout/Extra/autocoder/autocoder_utiles.py +1 -1
- webscout/Litlogger/formats.py +9 -0
- webscout/Litlogger/handlers.py +18 -0
- webscout/Litlogger/logger.py +43 -1
- webscout/Provider/AISEARCH/scira_search.py +3 -2
- webscout/Provider/Blackboxai.py +2 -0
- webscout/Provider/ChatSandbox.py +2 -1
- webscout/Provider/Deepinfra.py +1 -1
- webscout/Provider/HeckAI.py +1 -1
- webscout/Provider/LambdaChat.py +8 -1
- webscout/Provider/MCPCore.py +7 -3
- webscout/Provider/OPENAI/BLACKBOXAI.py +396 -113
- webscout/Provider/OPENAI/Cloudflare.py +31 -14
- webscout/Provider/OPENAI/FalconH1.py +457 -0
- webscout/Provider/OPENAI/FreeGemini.py +29 -13
- webscout/Provider/OPENAI/NEMOTRON.py +26 -14
- webscout/Provider/OPENAI/PI.py +427 -0
- webscout/Provider/OPENAI/Qwen3.py +161 -140
- webscout/Provider/OPENAI/README.md +3 -0
- webscout/Provider/OPENAI/TogetherAI.py +355 -0
- webscout/Provider/OPENAI/TwoAI.py +29 -12
- webscout/Provider/OPENAI/__init__.py +4 -1
- webscout/Provider/OPENAI/ai4chat.py +33 -23
- webscout/Provider/OPENAI/api.py +375 -24
- webscout/Provider/OPENAI/autoproxy.py +39 -0
- webscout/Provider/OPENAI/base.py +91 -12
- webscout/Provider/OPENAI/c4ai.py +31 -10
- webscout/Provider/OPENAI/chatgpt.py +56 -24
- webscout/Provider/OPENAI/chatgptclone.py +46 -16
- webscout/Provider/OPENAI/chatsandbox.py +7 -3
- webscout/Provider/OPENAI/copilot.py +26 -10
- webscout/Provider/OPENAI/deepinfra.py +29 -12
- webscout/Provider/OPENAI/e2b.py +358 -158
- webscout/Provider/OPENAI/exaai.py +13 -10
- webscout/Provider/OPENAI/exachat.py +10 -6
- webscout/Provider/OPENAI/flowith.py +7 -3
- webscout/Provider/OPENAI/freeaichat.py +10 -6
- webscout/Provider/OPENAI/glider.py +10 -6
- webscout/Provider/OPENAI/heckai.py +11 -8
- webscout/Provider/OPENAI/llmchatco.py +9 -7
- webscout/Provider/OPENAI/mcpcore.py +10 -7
- webscout/Provider/OPENAI/multichat.py +3 -1
- webscout/Provider/OPENAI/netwrck.py +10 -6
- webscout/Provider/OPENAI/oivscode.py +12 -9
- webscout/Provider/OPENAI/opkfc.py +31 -8
- webscout/Provider/OPENAI/scirachat.py +17 -10
- webscout/Provider/OPENAI/sonus.py +10 -6
- webscout/Provider/OPENAI/standardinput.py +18 -9
- webscout/Provider/OPENAI/textpollinations.py +14 -7
- webscout/Provider/OPENAI/toolbaz.py +16 -11
- webscout/Provider/OPENAI/typefully.py +14 -7
- webscout/Provider/OPENAI/typegpt.py +10 -6
- webscout/Provider/OPENAI/uncovrAI.py +22 -8
- webscout/Provider/OPENAI/venice.py +10 -6
- webscout/Provider/OPENAI/writecream.py +13 -10
- webscout/Provider/OPENAI/x0gpt.py +11 -9
- webscout/Provider/OPENAI/yep.py +12 -10
- webscout/Provider/PI.py +2 -1
- webscout/Provider/STT/__init__.py +3 -0
- webscout/Provider/STT/base.py +281 -0
- webscout/Provider/STT/elevenlabs.py +265 -0
- webscout/Provider/TTI/__init__.py +3 -1
- webscout/Provider/TTI/aiarta.py +399 -365
- webscout/Provider/TTI/base.py +74 -2
- webscout/Provider/TTI/fastflux.py +63 -30
- webscout/Provider/TTI/gpt1image.py +149 -0
- webscout/Provider/TTI/imagen.py +196 -0
- webscout/Provider/TTI/magicstudio.py +60 -29
- webscout/Provider/TTI/piclumen.py +43 -32
- webscout/Provider/TTI/pixelmuse.py +232 -225
- webscout/Provider/TTI/pollinations.py +43 -32
- webscout/Provider/TTI/together.py +287 -0
- webscout/Provider/TTI/utils.py +2 -1
- webscout/Provider/TTS/README.md +1 -0
- webscout/Provider/TTS/__init__.py +2 -1
- webscout/Provider/TTS/freetts.py +140 -0
- webscout/Provider/UNFINISHED/ChutesAI.py +314 -0
- webscout/Provider/UNFINISHED/fetch_together_models.py +95 -0
- webscout/Provider/__init__.py +3 -2
- webscout/Provider/granite.py +41 -6
- webscout/Provider/oivscode.py +37 -37
- webscout/Provider/scira_chat.py +3 -2
- webscout/Provider/scnet.py +1 -0
- webscout/Provider/toolbaz.py +0 -1
- webscout/litagent/Readme.md +12 -3
- webscout/litagent/agent.py +99 -62
- webscout/version.py +1 -1
- {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/METADATA +2 -1
- {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/RECORD +98 -87
- {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/WHEEL +1 -1
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/TTI/artbit.py +0 -0
- {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/entry_points.txt +0 -0
- {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.2.9.dist-info → webscout-8.3.1.dist-info}/top_level.txt +0 -0
|
@@ -1,225 +1,232 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
from typing import Optional, List, Dict, Any
|
|
3
|
-
from webscout.Provider.TTI.utils import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import
|
|
8
|
-
from
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
image_format:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
with
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
"
|
|
202
|
-
"
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
)
|
|
225
|
-
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Optional, List, Dict, Any
|
|
3
|
+
from webscout.Provider.TTI.utils import (
|
|
4
|
+
ImageData,
|
|
5
|
+
ImageResponse,
|
|
6
|
+
)
|
|
7
|
+
from webscout.Provider.TTI.base import TTICompatibleProvider, BaseImages
|
|
8
|
+
from io import BytesIO
|
|
9
|
+
import os
|
|
10
|
+
import tempfile
|
|
11
|
+
from webscout.litagent import LitAgent
|
|
12
|
+
import time
|
|
13
|
+
import json
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
from PIL import Image
|
|
17
|
+
except ImportError:
|
|
18
|
+
Image = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Images(BaseImages):
|
|
22
|
+
def __init__(self, client: "PixelMuse"):
|
|
23
|
+
self._client = client
|
|
24
|
+
|
|
25
|
+
def create(
|
|
26
|
+
self,
|
|
27
|
+
*,
|
|
28
|
+
model: str,
|
|
29
|
+
prompt: str,
|
|
30
|
+
n: int = 1,
|
|
31
|
+
size: str = "1024x1024",
|
|
32
|
+
response_format: str = "url",
|
|
33
|
+
user: Optional[str] = None,
|
|
34
|
+
style: str = "none",
|
|
35
|
+
aspect_ratio: str = "1:1",
|
|
36
|
+
timeout: int = 60,
|
|
37
|
+
image_format: str = "png",
|
|
38
|
+
**kwargs,
|
|
39
|
+
) -> ImageResponse:
|
|
40
|
+
"""
|
|
41
|
+
image_format: "png" or "jpeg"
|
|
42
|
+
"""
|
|
43
|
+
if Image is None:
|
|
44
|
+
raise ImportError("Pillow (PIL) is required for image format conversion.")
|
|
45
|
+
|
|
46
|
+
images = []
|
|
47
|
+
urls = []
|
|
48
|
+
|
|
49
|
+
def upload_file_with_retry(img_bytes, image_format, max_retries=3):
|
|
50
|
+
"""Upload file with retry logic using requests and tempfile"""
|
|
51
|
+
ext = "jpg" if image_format.lower() == "jpeg" else "png"
|
|
52
|
+
for attempt in range(max_retries):
|
|
53
|
+
tmp_path = None
|
|
54
|
+
try:
|
|
55
|
+
with tempfile.NamedTemporaryFile(
|
|
56
|
+
suffix=f".{ext}", delete=False
|
|
57
|
+
) as tmp:
|
|
58
|
+
tmp.write(img_bytes)
|
|
59
|
+
tmp.flush()
|
|
60
|
+
tmp_path = tmp.name
|
|
61
|
+
with open(tmp_path, "rb") as f:
|
|
62
|
+
files = {"fileToUpload": (f"image.{ext}", f, f"image/{ext}")}
|
|
63
|
+
data = {"reqtype": "fileupload", "json": "true"}
|
|
64
|
+
headers = {"User-Agent": LitAgent().random()}
|
|
65
|
+
if attempt > 0:
|
|
66
|
+
headers["Connection"] = "close"
|
|
67
|
+
resp = requests.post(
|
|
68
|
+
"https://catbox.moe/user/api.php",
|
|
69
|
+
files=files,
|
|
70
|
+
data=data,
|
|
71
|
+
headers=headers,
|
|
72
|
+
timeout=timeout,
|
|
73
|
+
)
|
|
74
|
+
if resp.status_code == 200 and resp.text.strip():
|
|
75
|
+
text = resp.text.strip()
|
|
76
|
+
if text.startswith("http"):
|
|
77
|
+
return text
|
|
78
|
+
try:
|
|
79
|
+
result = resp.json()
|
|
80
|
+
if "url" in result:
|
|
81
|
+
return result["url"]
|
|
82
|
+
except json.JSONDecodeError:
|
|
83
|
+
if "http" in text:
|
|
84
|
+
return text
|
|
85
|
+
except Exception:
|
|
86
|
+
if attempt < max_retries - 1:
|
|
87
|
+
time.sleep(1 * (attempt + 1))
|
|
88
|
+
finally:
|
|
89
|
+
if tmp_path and os.path.isfile(tmp_path):
|
|
90
|
+
try:
|
|
91
|
+
os.remove(tmp_path)
|
|
92
|
+
except Exception:
|
|
93
|
+
pass
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
def upload_file_alternative(img_bytes, image_format):
|
|
97
|
+
"""Alternative upload method: save to temp file and upload to 0x0.st"""
|
|
98
|
+
try:
|
|
99
|
+
ext = "jpg" if image_format.lower() == "jpeg" else "png"
|
|
100
|
+
with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as tmp:
|
|
101
|
+
tmp.write(img_bytes)
|
|
102
|
+
tmp.flush()
|
|
103
|
+
tmp_path = tmp.name
|
|
104
|
+
try:
|
|
105
|
+
if not os.path.isfile(tmp_path):
|
|
106
|
+
return None
|
|
107
|
+
with open(tmp_path, "rb") as img_file:
|
|
108
|
+
files = {"file": img_file}
|
|
109
|
+
response = requests.post("https://0x0.st", files=files)
|
|
110
|
+
response.raise_for_status()
|
|
111
|
+
image_url = response.text.strip()
|
|
112
|
+
if not image_url.startswith("http"):
|
|
113
|
+
return None
|
|
114
|
+
return image_url
|
|
115
|
+
except Exception:
|
|
116
|
+
return None
|
|
117
|
+
finally:
|
|
118
|
+
try:
|
|
119
|
+
os.remove(tmp_path)
|
|
120
|
+
except Exception:
|
|
121
|
+
pass
|
|
122
|
+
except Exception:
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
for _ in range(n):
|
|
126
|
+
resp = self._client.session.post(
|
|
127
|
+
self._client.api_endpoint,
|
|
128
|
+
json={
|
|
129
|
+
"prompt": prompt,
|
|
130
|
+
"model": model,
|
|
131
|
+
"style": style,
|
|
132
|
+
"aspect_ratio": aspect_ratio,
|
|
133
|
+
},
|
|
134
|
+
timeout=timeout,
|
|
135
|
+
)
|
|
136
|
+
resp.raise_for_status()
|
|
137
|
+
data = resp.json()
|
|
138
|
+
|
|
139
|
+
if "output" in data and len(data["output"]) > 0:
|
|
140
|
+
image_url = data["output"][0]
|
|
141
|
+
img_resp = self._client.session.get(image_url, timeout=timeout)
|
|
142
|
+
img_resp.raise_for_status()
|
|
143
|
+
webp_bytes = img_resp.content
|
|
144
|
+
|
|
145
|
+
# Convert webp to png or jpeg in memory
|
|
146
|
+
with BytesIO(webp_bytes) as input_io:
|
|
147
|
+
with Image.open(input_io) as im:
|
|
148
|
+
out_io = BytesIO()
|
|
149
|
+
if image_format.lower() == "jpeg":
|
|
150
|
+
im = im.convert("RGB")
|
|
151
|
+
im.save(out_io, format="JPEG")
|
|
152
|
+
else:
|
|
153
|
+
im.save(out_io, format="PNG")
|
|
154
|
+
img_bytes = out_io.getvalue()
|
|
155
|
+
|
|
156
|
+
images.append(img_bytes)
|
|
157
|
+
|
|
158
|
+
if response_format == "url":
|
|
159
|
+
# Try primary upload method with retries
|
|
160
|
+
uploaded_url = upload_file_with_retry(img_bytes, image_format)
|
|
161
|
+
|
|
162
|
+
# If primary method fails, try alternative
|
|
163
|
+
if not uploaded_url:
|
|
164
|
+
uploaded_url = upload_file_alternative(img_bytes, image_format)
|
|
165
|
+
|
|
166
|
+
if uploaded_url:
|
|
167
|
+
urls.append(uploaded_url)
|
|
168
|
+
else:
|
|
169
|
+
raise RuntimeError(
|
|
170
|
+
"Failed to upload image to catbox.moe using all available methods"
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
raise RuntimeError("No image data received from PixelMuse")
|
|
174
|
+
|
|
175
|
+
result_data = []
|
|
176
|
+
if response_format == "url":
|
|
177
|
+
for url in urls:
|
|
178
|
+
result_data.append(ImageData(url=url))
|
|
179
|
+
elif response_format == "b64_json":
|
|
180
|
+
import base64
|
|
181
|
+
|
|
182
|
+
for img in images:
|
|
183
|
+
b64 = base64.b64encode(img).decode("utf-8")
|
|
184
|
+
result_data.append(ImageData(b64_json=b64))
|
|
185
|
+
else:
|
|
186
|
+
raise ValueError("response_format must be 'url' or 'b64_json'")
|
|
187
|
+
|
|
188
|
+
from time import time as _time
|
|
189
|
+
|
|
190
|
+
return ImageResponse(created=int(_time()), data=result_data)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class PixelMuse(TTICompatibleProvider):
|
|
194
|
+
AVAILABLE_MODELS = ["flux-schnell", "imagen-3-fast", "imagen-3", "recraft-v3"]
|
|
195
|
+
|
|
196
|
+
def __init__(self):
|
|
197
|
+
self.api_endpoint = "https://www.pixelmuse.studio/api/predictions"
|
|
198
|
+
self.session = requests.Session()
|
|
199
|
+
self.user_agent = LitAgent().random()
|
|
200
|
+
self.headers = {
|
|
201
|
+
"accept": "*/*",
|
|
202
|
+
"accept-language": "en-US,en;q=0.9",
|
|
203
|
+
"content-type": "application/json",
|
|
204
|
+
"origin": "https://www.pixelmuse.studio",
|
|
205
|
+
"referer": "https://www.pixelmuse.studio/",
|
|
206
|
+
"user-agent": self.user_agent,
|
|
207
|
+
}
|
|
208
|
+
self.session.headers.update(self.headers)
|
|
209
|
+
self.images = Images(self)
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def models(self):
|
|
213
|
+
class _ModelList:
|
|
214
|
+
def list(inner_self):
|
|
215
|
+
return type(self).AVAILABLE_MODELS
|
|
216
|
+
|
|
217
|
+
return _ModelList()
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
# Example usage:
|
|
221
|
+
if __name__ == "__main__":
|
|
222
|
+
from rich import print
|
|
223
|
+
|
|
224
|
+
client = PixelMuse()
|
|
225
|
+
response = client.images.create(
|
|
226
|
+
model="flux-schnell",
|
|
227
|
+
prompt="a white siamese cat",
|
|
228
|
+
response_format="url",
|
|
229
|
+
n=4,
|
|
230
|
+
timeout=30,
|
|
231
|
+
)
|
|
232
|
+
print(response)
|
|
@@ -2,7 +2,10 @@ import requests
|
|
|
2
2
|
from typing import Optional, List, Dict, Any, Union
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from requests.exceptions import RequestException
|
|
5
|
-
from webscout.Provider.TTI.utils import
|
|
5
|
+
from webscout.Provider.TTI.utils import (
|
|
6
|
+
ImageData,
|
|
7
|
+
ImageResponse
|
|
8
|
+
)
|
|
6
9
|
from webscout.Provider.TTI.base import TTICompatibleProvider, BaseImages
|
|
7
10
|
from io import BytesIO
|
|
8
11
|
import os
|
|
@@ -17,6 +20,7 @@ try:
|
|
|
17
20
|
except ImportError:
|
|
18
21
|
Image = None
|
|
19
22
|
|
|
23
|
+
|
|
20
24
|
class Images(BaseImages):
|
|
21
25
|
def __init__(self, client):
|
|
22
26
|
self._client = client
|
|
@@ -35,7 +39,7 @@ class Images(BaseImages):
|
|
|
35
39
|
timeout: int = 60,
|
|
36
40
|
image_format: str = "png",
|
|
37
41
|
seed: Optional[int] = None,
|
|
38
|
-
**kwargs
|
|
42
|
+
**kwargs,
|
|
39
43
|
) -> ImageResponse:
|
|
40
44
|
"""
|
|
41
45
|
image_format: "png" or "jpeg"
|
|
@@ -52,32 +56,35 @@ class Images(BaseImages):
|
|
|
52
56
|
for attempt in range(max_retries):
|
|
53
57
|
tmp_path = None
|
|
54
58
|
try:
|
|
55
|
-
with tempfile.NamedTemporaryFile(
|
|
59
|
+
with tempfile.NamedTemporaryFile(
|
|
60
|
+
suffix=f".{ext}", delete=False
|
|
61
|
+
) as tmp:
|
|
56
62
|
tmp.write(img_bytes)
|
|
57
63
|
tmp.flush()
|
|
58
64
|
tmp_path = tmp.name
|
|
59
|
-
with open(tmp_path,
|
|
60
|
-
files = {
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
data = {
|
|
64
|
-
'reqtype': 'fileupload',
|
|
65
|
-
'json': 'true'
|
|
66
|
-
}
|
|
67
|
-
headers = {'User-Agent': LitAgent().random()}
|
|
65
|
+
with open(tmp_path, "rb") as f:
|
|
66
|
+
files = {"fileToUpload": (f"image.{ext}", f, f"image/{ext}")}
|
|
67
|
+
data = {"reqtype": "fileupload", "json": "true"}
|
|
68
|
+
headers = {"User-Agent": LitAgent().random()}
|
|
68
69
|
if attempt > 0:
|
|
69
|
-
headers[
|
|
70
|
-
resp = requests.post(
|
|
70
|
+
headers["Connection"] = "close"
|
|
71
|
+
resp = requests.post(
|
|
72
|
+
"https://catbox.moe/user/api.php",
|
|
73
|
+
files=files,
|
|
74
|
+
data=data,
|
|
75
|
+
headers=headers,
|
|
76
|
+
timeout=timeout,
|
|
77
|
+
)
|
|
71
78
|
if resp.status_code == 200 and resp.text.strip():
|
|
72
79
|
text = resp.text.strip()
|
|
73
|
-
if text.startswith(
|
|
80
|
+
if text.startswith("http"):
|
|
74
81
|
return text
|
|
75
82
|
try:
|
|
76
83
|
result = resp.json()
|
|
77
84
|
if "url" in result:
|
|
78
85
|
return result["url"]
|
|
79
86
|
except json.JSONDecodeError:
|
|
80
|
-
if
|
|
87
|
+
if "http" in text:
|
|
81
88
|
return text
|
|
82
89
|
except Exception:
|
|
83
90
|
if attempt < max_retries - 1:
|
|
@@ -100,12 +107,12 @@ class Images(BaseImages):
|
|
|
100
107
|
try:
|
|
101
108
|
if not os.path.isfile(tmp_path):
|
|
102
109
|
return None
|
|
103
|
-
with open(tmp_path,
|
|
104
|
-
files = {
|
|
105
|
-
response = requests.post(
|
|
110
|
+
with open(tmp_path, "rb") as img_file:
|
|
111
|
+
files = {"file": img_file}
|
|
112
|
+
response = requests.post("https://0x0.st", files=files)
|
|
106
113
|
response.raise_for_status()
|
|
107
114
|
image_url = response.text.strip()
|
|
108
|
-
if not image_url.startswith(
|
|
115
|
+
if not image_url.startswith("http"):
|
|
109
116
|
return None
|
|
110
117
|
return image_url
|
|
111
118
|
except Exception:
|
|
@@ -132,7 +139,10 @@ class Images(BaseImages):
|
|
|
132
139
|
query = "&".join(f"{k}={v}" for k, v in params.items())
|
|
133
140
|
url = f"{base_url}?{query}"
|
|
134
141
|
try:
|
|
135
|
-
resp = self._client.session.get(
|
|
142
|
+
resp = self._client.session.get(
|
|
143
|
+
url,
|
|
144
|
+
timeout=timeout,
|
|
145
|
+
)
|
|
136
146
|
resp.raise_for_status()
|
|
137
147
|
img_bytes = resp.content
|
|
138
148
|
except RequestException as e:
|
|
@@ -158,7 +168,9 @@ class Images(BaseImages):
|
|
|
158
168
|
if uploaded_url:
|
|
159
169
|
urls.append(uploaded_url)
|
|
160
170
|
else:
|
|
161
|
-
raise RuntimeError(
|
|
171
|
+
raise RuntimeError(
|
|
172
|
+
"Failed to upload image to catbox.moe using all available methods"
|
|
173
|
+
)
|
|
162
174
|
|
|
163
175
|
result_data = []
|
|
164
176
|
if response_format == "url":
|
|
@@ -166,6 +178,7 @@ class Images(BaseImages):
|
|
|
166
178
|
result_data.append(ImageData(url=url))
|
|
167
179
|
elif response_format == "b64_json":
|
|
168
180
|
import base64
|
|
181
|
+
|
|
169
182
|
for img in images:
|
|
170
183
|
b64 = base64.b64encode(img).decode("utf-8")
|
|
171
184
|
result_data.append(ImageData(b64_json=b64))
|
|
@@ -173,17 +186,12 @@ class Images(BaseImages):
|
|
|
173
186
|
raise ValueError("response_format must be 'url' or 'b64_json'")
|
|
174
187
|
|
|
175
188
|
from time import time as _time
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
)
|
|
189
|
+
|
|
190
|
+
return ImageResponse(created=int(_time()), data=result_data)
|
|
191
|
+
|
|
180
192
|
|
|
181
193
|
class PollinationsAI(TTICompatibleProvider):
|
|
182
|
-
AVAILABLE_MODELS = [
|
|
183
|
-
"flux",
|
|
184
|
-
"turbo",
|
|
185
|
-
"gptimage"
|
|
186
|
-
]
|
|
194
|
+
AVAILABLE_MODELS = ["flux", "turbo", "gptimage"]
|
|
187
195
|
|
|
188
196
|
def __init__(self):
|
|
189
197
|
self.api_endpoint = "https://image.pollinations.ai/prompt"
|
|
@@ -205,10 +213,13 @@ class PollinationsAI(TTICompatibleProvider):
|
|
|
205
213
|
class _ModelList:
|
|
206
214
|
def list(inner_self):
|
|
207
215
|
return type(self).AVAILABLE_MODELS
|
|
216
|
+
|
|
208
217
|
return _ModelList()
|
|
209
218
|
|
|
219
|
+
|
|
210
220
|
if __name__ == "__main__":
|
|
211
221
|
from rich import print
|
|
222
|
+
|
|
212
223
|
client = PollinationsAI()
|
|
213
224
|
response = client.images.create(
|
|
214
225
|
model="flux",
|
|
@@ -216,6 +227,6 @@ if __name__ == "__main__":
|
|
|
216
227
|
response_format="url",
|
|
217
228
|
n=4,
|
|
218
229
|
timeout=30,
|
|
219
|
-
seed=None # You can set a specific seed for reproducibility
|
|
230
|
+
seed=None, # You can set a specific seed for reproducibility
|
|
220
231
|
)
|
|
221
232
|
print(response)
|