webscout 8.3.7__py3-none-any.whl → 2025.10.13__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 +250 -250
- webscout/AIbase.py +379 -379
- webscout/AIutel.py +60 -60
- webscout/Bard.py +1012 -1012
- webscout/Bing_search.py +417 -417
- webscout/DWEBS.py +529 -529
- webscout/Extra/Act.md +309 -309
- webscout/Extra/GitToolkit/__init__.py +10 -10
- webscout/Extra/GitToolkit/gitapi/README.md +110 -110
- webscout/Extra/GitToolkit/gitapi/__init__.py +11 -11
- webscout/Extra/GitToolkit/gitapi/repository.py +195 -195
- webscout/Extra/GitToolkit/gitapi/user.py +96 -96
- webscout/Extra/GitToolkit/gitapi/utils.py +61 -61
- webscout/Extra/YTToolkit/README.md +375 -375
- webscout/Extra/YTToolkit/YTdownloader.py +956 -956
- webscout/Extra/YTToolkit/__init__.py +2 -2
- webscout/Extra/YTToolkit/transcriber.py +475 -475
- webscout/Extra/YTToolkit/ytapi/README.md +44 -44
- webscout/Extra/YTToolkit/ytapi/__init__.py +6 -6
- webscout/Extra/YTToolkit/ytapi/channel.py +307 -307
- webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
- webscout/Extra/YTToolkit/ytapi/extras.py +118 -118
- webscout/Extra/YTToolkit/ytapi/https.py +88 -88
- webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
- webscout/Extra/YTToolkit/ytapi/playlist.py +58 -58
- webscout/Extra/YTToolkit/ytapi/pool.py +7 -7
- webscout/Extra/YTToolkit/ytapi/query.py +39 -39
- webscout/Extra/YTToolkit/ytapi/stream.py +62 -62
- webscout/Extra/YTToolkit/ytapi/utils.py +62 -62
- webscout/Extra/YTToolkit/ytapi/video.py +232 -232
- webscout/Extra/autocoder/__init__.py +9 -9
- webscout/Extra/autocoder/autocoder.py +1105 -1105
- webscout/Extra/autocoder/autocoder_utiles.py +332 -332
- webscout/Extra/gguf.md +429 -429
- webscout/Extra/gguf.py +1213 -1213
- webscout/Extra/tempmail/README.md +487 -487
- webscout/Extra/tempmail/__init__.py +27 -27
- webscout/Extra/tempmail/async_utils.py +140 -140
- webscout/Extra/tempmail/base.py +160 -160
- webscout/Extra/tempmail/cli.py +186 -186
- webscout/Extra/tempmail/emailnator.py +84 -84
- webscout/Extra/tempmail/mail_tm.py +360 -360
- webscout/Extra/tempmail/temp_mail_io.py +291 -291
- webscout/Extra/weather.md +281 -281
- webscout/Extra/weather.py +193 -193
- webscout/Litlogger/README.md +10 -10
- webscout/Litlogger/__init__.py +15 -15
- webscout/Litlogger/formats.py +13 -13
- webscout/Litlogger/handlers.py +121 -121
- webscout/Litlogger/levels.py +13 -13
- webscout/Litlogger/logger.py +134 -134
- webscout/Provider/AISEARCH/Perplexity.py +332 -332
- webscout/Provider/AISEARCH/README.md +279 -279
- webscout/Provider/AISEARCH/__init__.py +16 -1
- webscout/Provider/AISEARCH/felo_search.py +206 -206
- webscout/Provider/AISEARCH/genspark_search.py +323 -323
- webscout/Provider/AISEARCH/hika_search.py +185 -185
- webscout/Provider/AISEARCH/iask_search.py +410 -410
- webscout/Provider/AISEARCH/monica_search.py +219 -219
- webscout/Provider/AISEARCH/scira_search.py +316 -316
- webscout/Provider/AISEARCH/stellar_search.py +177 -177
- webscout/Provider/AISEARCH/webpilotai_search.py +255 -255
- webscout/Provider/Aitopia.py +314 -314
- webscout/Provider/Andi.py +1 -1
- webscout/Provider/Apriel.py +306 -0
- webscout/Provider/ChatGPTClone.py +237 -236
- webscout/Provider/ChatSandbox.py +343 -343
- webscout/Provider/Cloudflare.py +324 -324
- webscout/Provider/Cohere.py +208 -208
- webscout/Provider/Deepinfra.py +370 -366
- webscout/Provider/ExaAI.py +260 -260
- webscout/Provider/ExaChat.py +308 -308
- webscout/Provider/Flowith.py +221 -221
- webscout/Provider/GMI.py +293 -0
- webscout/Provider/Gemini.py +164 -164
- webscout/Provider/GeminiProxy.py +167 -167
- webscout/Provider/GithubChat.py +371 -372
- webscout/Provider/Groq.py +800 -800
- webscout/Provider/HeckAI.py +383 -383
- webscout/Provider/Jadve.py +282 -282
- webscout/Provider/K2Think.py +307 -307
- webscout/Provider/Koboldai.py +205 -205
- webscout/Provider/LambdaChat.py +423 -423
- webscout/Provider/Nemotron.py +244 -244
- webscout/Provider/Netwrck.py +248 -248
- webscout/Provider/OLLAMA.py +395 -395
- webscout/Provider/OPENAI/Cloudflare.py +393 -393
- webscout/Provider/OPENAI/FalconH1.py +451 -451
- webscout/Provider/OPENAI/FreeGemini.py +296 -296
- webscout/Provider/OPENAI/K2Think.py +431 -431
- webscout/Provider/OPENAI/NEMOTRON.py +240 -240
- webscout/Provider/OPENAI/PI.py +427 -427
- webscout/Provider/OPENAI/README.md +959 -959
- webscout/Provider/OPENAI/TogetherAI.py +345 -345
- webscout/Provider/OPENAI/TwoAI.py +465 -465
- webscout/Provider/OPENAI/__init__.py +33 -18
- webscout/Provider/OPENAI/base.py +248 -248
- webscout/Provider/OPENAI/chatglm.py +528 -0
- webscout/Provider/OPENAI/chatgpt.py +592 -592
- webscout/Provider/OPENAI/chatgptclone.py +521 -521
- webscout/Provider/OPENAI/chatsandbox.py +202 -202
- webscout/Provider/OPENAI/deepinfra.py +318 -314
- webscout/Provider/OPENAI/e2b.py +1665 -1665
- webscout/Provider/OPENAI/exaai.py +420 -420
- webscout/Provider/OPENAI/exachat.py +452 -452
- webscout/Provider/OPENAI/friendli.py +232 -232
- webscout/Provider/OPENAI/{refact.py → gmi.py} +324 -274
- webscout/Provider/OPENAI/groq.py +364 -364
- webscout/Provider/OPENAI/heckai.py +314 -314
- webscout/Provider/OPENAI/llmchatco.py +337 -337
- webscout/Provider/OPENAI/netwrck.py +355 -355
- webscout/Provider/OPENAI/oivscode.py +290 -290
- webscout/Provider/OPENAI/opkfc.py +518 -518
- webscout/Provider/OPENAI/pydantic_imports.py +1 -1
- webscout/Provider/OPENAI/scirachat.py +535 -535
- webscout/Provider/OPENAI/sonus.py +308 -308
- webscout/Provider/OPENAI/standardinput.py +442 -442
- webscout/Provider/OPENAI/textpollinations.py +340 -340
- webscout/Provider/OPENAI/toolbaz.py +419 -416
- webscout/Provider/OPENAI/typefully.py +362 -362
- webscout/Provider/OPENAI/utils.py +295 -295
- webscout/Provider/OPENAI/venice.py +436 -436
- webscout/Provider/OPENAI/wisecat.py +387 -387
- webscout/Provider/OPENAI/writecream.py +166 -166
- webscout/Provider/OPENAI/x0gpt.py +378 -378
- webscout/Provider/OPENAI/yep.py +389 -389
- webscout/Provider/OpenGPT.py +230 -230
- webscout/Provider/Openai.py +243 -243
- webscout/Provider/PI.py +405 -405
- webscout/Provider/Perplexitylabs.py +430 -430
- webscout/Provider/QwenLM.py +272 -272
- webscout/Provider/STT/__init__.py +16 -1
- webscout/Provider/Sambanova.py +257 -257
- webscout/Provider/StandardInput.py +309 -309
- webscout/Provider/TTI/README.md +82 -82
- webscout/Provider/TTI/__init__.py +33 -18
- webscout/Provider/TTI/aiarta.py +413 -413
- webscout/Provider/TTI/base.py +136 -136
- webscout/Provider/TTI/bing.py +243 -243
- webscout/Provider/TTI/gpt1image.py +149 -149
- webscout/Provider/TTI/imagen.py +196 -196
- webscout/Provider/TTI/infip.py +211 -211
- webscout/Provider/TTI/magicstudio.py +232 -232
- webscout/Provider/TTI/monochat.py +219 -219
- webscout/Provider/TTI/piclumen.py +214 -214
- webscout/Provider/TTI/pixelmuse.py +232 -232
- webscout/Provider/TTI/pollinations.py +232 -232
- webscout/Provider/TTI/together.py +288 -288
- webscout/Provider/TTI/utils.py +12 -12
- webscout/Provider/TTI/venice.py +367 -367
- webscout/Provider/TTS/README.md +192 -192
- webscout/Provider/TTS/__init__.py +33 -18
- webscout/Provider/TTS/parler.py +110 -110
- webscout/Provider/TTS/streamElements.py +333 -333
- webscout/Provider/TTS/utils.py +280 -280
- webscout/Provider/TeachAnything.py +237 -237
- webscout/Provider/TextPollinationsAI.py +310 -310
- webscout/Provider/TogetherAI.py +356 -356
- webscout/Provider/TwoAI.py +312 -312
- webscout/Provider/TypliAI.py +311 -311
- webscout/Provider/UNFINISHED/ChatHub.py +208 -208
- webscout/Provider/UNFINISHED/ChutesAI.py +313 -313
- webscout/Provider/UNFINISHED/GizAI.py +294 -294
- webscout/Provider/UNFINISHED/Marcus.py +198 -198
- webscout/Provider/UNFINISHED/Qodo.py +477 -477
- webscout/Provider/UNFINISHED/VercelAIGateway.py +338 -338
- webscout/Provider/UNFINISHED/XenAI.py +324 -324
- webscout/Provider/UNFINISHED/Youchat.py +330 -330
- webscout/Provider/UNFINISHED/liner.py +334 -0
- webscout/Provider/UNFINISHED/liner_api_request.py +262 -262
- webscout/Provider/UNFINISHED/puterjs.py +634 -634
- webscout/Provider/UNFINISHED/samurai.py +223 -223
- webscout/Provider/UNFINISHED/test_lmarena.py +119 -119
- webscout/Provider/Venice.py +250 -250
- webscout/Provider/VercelAI.py +256 -256
- webscout/Provider/WiseCat.py +231 -231
- webscout/Provider/WrDoChat.py +366 -366
- webscout/Provider/__init__.py +33 -18
- webscout/Provider/ai4chat.py +174 -174
- webscout/Provider/akashgpt.py +331 -331
- webscout/Provider/cerebras.py +446 -446
- webscout/Provider/chatglm.py +394 -301
- webscout/Provider/cleeai.py +211 -211
- webscout/Provider/elmo.py +282 -282
- webscout/Provider/geminiapi.py +208 -208
- webscout/Provider/granite.py +261 -261
- webscout/Provider/hermes.py +263 -263
- webscout/Provider/julius.py +223 -223
- webscout/Provider/learnfastai.py +309 -309
- webscout/Provider/llama3mitril.py +214 -214
- webscout/Provider/llmchat.py +243 -243
- webscout/Provider/llmchatco.py +290 -290
- webscout/Provider/meta.py +801 -801
- webscout/Provider/oivscode.py +309 -309
- webscout/Provider/scira_chat.py +383 -383
- webscout/Provider/searchchat.py +292 -292
- webscout/Provider/sonus.py +258 -258
- webscout/Provider/toolbaz.py +370 -367
- webscout/Provider/turboseek.py +273 -273
- webscout/Provider/typefully.py +207 -207
- webscout/Provider/yep.py +372 -372
- webscout/__init__.py +27 -31
- webscout/__main__.py +5 -5
- webscout/auth/api_key_manager.py +189 -189
- webscout/auth/config.py +175 -175
- webscout/auth/models.py +185 -185
- webscout/auth/routes.py +663 -664
- webscout/auth/simple_logger.py +236 -236
- webscout/cli.py +523 -523
- webscout/conversation.py +438 -438
- webscout/exceptions.py +361 -361
- webscout/litagent/Readme.md +298 -298
- webscout/litagent/__init__.py +28 -28
- webscout/litagent/agent.py +581 -581
- webscout/litagent/constants.py +59 -59
- webscout/litprinter/__init__.py +58 -58
- webscout/models.py +181 -181
- webscout/optimizers.py +419 -419
- webscout/prompt_manager.py +288 -288
- webscout/sanitize.py +1078 -1078
- webscout/scout/README.md +401 -401
- webscout/scout/__init__.py +8 -8
- webscout/scout/core/__init__.py +6 -6
- webscout/scout/core/crawler.py +297 -297
- webscout/scout/core/scout.py +706 -706
- webscout/scout/core/search_result.py +95 -95
- webscout/scout/core/text_analyzer.py +62 -62
- webscout/scout/core/text_utils.py +277 -277
- webscout/scout/core/web_analyzer.py +51 -51
- webscout/scout/element.py +599 -599
- webscout/scout/parsers/__init__.py +69 -69
- webscout/scout/parsers/html5lib_parser.py +172 -172
- webscout/scout/parsers/html_parser.py +236 -236
- webscout/scout/parsers/lxml_parser.py +178 -178
- webscout/scout/utils.py +37 -37
- webscout/search/__init__.py +51 -0
- webscout/search/base.py +195 -0
- webscout/search/duckduckgo_main.py +54 -0
- webscout/search/engines/__init__.py +48 -0
- webscout/search/engines/bing.py +84 -0
- webscout/search/engines/bing_news.py +52 -0
- webscout/search/engines/brave.py +43 -0
- webscout/search/engines/duckduckgo/__init__.py +25 -0
- webscout/search/engines/duckduckgo/answers.py +78 -0
- webscout/search/engines/duckduckgo/base.py +187 -0
- webscout/search/engines/duckduckgo/images.py +97 -0
- webscout/search/engines/duckduckgo/maps.py +168 -0
- webscout/search/engines/duckduckgo/news.py +68 -0
- webscout/search/engines/duckduckgo/suggestions.py +21 -0
- webscout/search/engines/duckduckgo/text.py +211 -0
- webscout/search/engines/duckduckgo/translate.py +47 -0
- webscout/search/engines/duckduckgo/videos.py +63 -0
- webscout/search/engines/duckduckgo/weather.py +74 -0
- webscout/search/engines/mojeek.py +37 -0
- webscout/search/engines/wikipedia.py +56 -0
- webscout/search/engines/yahoo.py +65 -0
- webscout/search/engines/yahoo_news.py +64 -0
- webscout/search/engines/yandex.py +43 -0
- webscout/search/engines/yep/__init__.py +13 -0
- webscout/search/engines/yep/base.py +32 -0
- webscout/search/engines/yep/images.py +99 -0
- webscout/search/engines/yep/suggestions.py +35 -0
- webscout/search/engines/yep/text.py +114 -0
- webscout/search/http_client.py +156 -0
- webscout/search/results.py +137 -0
- webscout/search/yep_main.py +44 -0
- webscout/swiftcli/Readme.md +323 -323
- webscout/swiftcli/__init__.py +95 -95
- webscout/swiftcli/core/__init__.py +7 -7
- webscout/swiftcli/core/cli.py +308 -308
- webscout/swiftcli/core/context.py +104 -104
- webscout/swiftcli/core/group.py +241 -241
- webscout/swiftcli/decorators/__init__.py +28 -28
- webscout/swiftcli/decorators/command.py +221 -221
- webscout/swiftcli/decorators/options.py +220 -220
- webscout/swiftcli/decorators/output.py +302 -302
- webscout/swiftcli/exceptions.py +21 -21
- webscout/swiftcli/plugins/__init__.py +9 -9
- webscout/swiftcli/plugins/base.py +135 -135
- webscout/swiftcli/plugins/manager.py +269 -269
- webscout/swiftcli/utils/__init__.py +59 -59
- webscout/swiftcli/utils/formatting.py +252 -252
- webscout/swiftcli/utils/parsing.py +267 -267
- webscout/update_checker.py +117 -117
- webscout/version.py +1 -1
- webscout/version.py.bak +2 -0
- webscout/zeroart/README.md +89 -89
- webscout/zeroart/__init__.py +134 -134
- webscout/zeroart/base.py +66 -66
- webscout/zeroart/effects.py +100 -100
- webscout/zeroart/fonts.py +1238 -1238
- {webscout-8.3.7.dist-info → webscout-2025.10.13.dist-info}/METADATA +936 -937
- webscout-2025.10.13.dist-info/RECORD +329 -0
- webscout/Provider/AISEARCH/DeepFind.py +0 -254
- webscout/Provider/OPENAI/Qwen3.py +0 -303
- webscout/Provider/OPENAI/qodo.py +0 -630
- webscout/Provider/OPENAI/xenai.py +0 -514
- webscout/tempid.py +0 -134
- webscout/webscout_search.py +0 -1183
- webscout/webscout_search_async.py +0 -649
- webscout/yep_search.py +0 -346
- webscout-8.3.7.dist-info/RECORD +0 -301
- {webscout-8.3.7.dist-info → webscout-2025.10.13.dist-info}/WHEEL +0 -0
- {webscout-8.3.7.dist-info → webscout-2025.10.13.dist-info}/entry_points.txt +0 -0
- {webscout-8.3.7.dist-info → webscout-2025.10.13.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.3.7.dist-info → webscout-2025.10.13.dist-info}/top_level.txt +0 -0
webscout/Provider/TTI/bing.py
CHANGED
|
@@ -1,243 +1,243 @@
|
|
|
1
|
-
import requests
|
|
2
|
-
import time
|
|
3
|
-
import tempfile
|
|
4
|
-
import os
|
|
5
|
-
from typing import Optional
|
|
6
|
-
from webscout.Provider.TTI.utils import ImageData, ImageResponse
|
|
7
|
-
from webscout.Provider.TTI.base import TTICompatibleProvider, BaseImages
|
|
8
|
-
from io import BytesIO
|
|
9
|
-
from webscout.litagent import LitAgent
|
|
10
|
-
|
|
11
|
-
try:
|
|
12
|
-
from PIL import Image
|
|
13
|
-
except ImportError:
|
|
14
|
-
Image = None
|
|
15
|
-
|
|
16
|
-
class Images(BaseImages):
|
|
17
|
-
def __init__(self, client):
|
|
18
|
-
self._client = client
|
|
19
|
-
|
|
20
|
-
def create(
|
|
21
|
-
self,
|
|
22
|
-
*,
|
|
23
|
-
model: str = "dalle",
|
|
24
|
-
prompt: str,
|
|
25
|
-
n: int = 1,
|
|
26
|
-
size: str = "1024x1024",
|
|
27
|
-
response_format: str = "url",
|
|
28
|
-
user: Optional[str] = None,
|
|
29
|
-
style: str = "none",
|
|
30
|
-
aspect_ratio: str = "1:1",
|
|
31
|
-
timeout: int = 60,
|
|
32
|
-
image_format: str = "png",
|
|
33
|
-
seed: Optional[int] = None,
|
|
34
|
-
**kwargs
|
|
35
|
-
) -> ImageResponse:
|
|
36
|
-
if not prompt:
|
|
37
|
-
raise ValueError("Parameter 'prompt' is required")
|
|
38
|
-
if Image is None:
|
|
39
|
-
raise ImportError("Pillow (PIL) is required for image format conversion.")
|
|
40
|
-
agent = LitAgent()
|
|
41
|
-
session = self._client.session
|
|
42
|
-
headers = self._client.headers
|
|
43
|
-
images = []
|
|
44
|
-
urls = []
|
|
45
|
-
|
|
46
|
-
# Map model names to Bing model codes
|
|
47
|
-
model_mapping = {
|
|
48
|
-
"dalle": "0",
|
|
49
|
-
"gpt4o": "1",
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
# Get the appropriate model code
|
|
53
|
-
model_code = model_mapping.get(model.lower(), "4")
|
|
54
|
-
|
|
55
|
-
for _ in range(n):
|
|
56
|
-
data = {
|
|
57
|
-
"q": prompt,
|
|
58
|
-
"rt": "4",
|
|
59
|
-
"mdl": model_code,
|
|
60
|
-
"FORM": "GENCRE"
|
|
61
|
-
}
|
|
62
|
-
response = session.post(
|
|
63
|
-
"https://www.bing.com/images/create",
|
|
64
|
-
data=data,
|
|
65
|
-
headers=headers,
|
|
66
|
-
allow_redirects=False,
|
|
67
|
-
timeout=timeout
|
|
68
|
-
)
|
|
69
|
-
redirect_url = response.headers.get("Location")
|
|
70
|
-
if not redirect_url:
|
|
71
|
-
raise Exception("Failed to get redirect URL")
|
|
72
|
-
from urllib.parse import urlparse, parse_qs
|
|
73
|
-
query = urlparse(redirect_url).query
|
|
74
|
-
request_id = parse_qs(query).get("id", [None])[0]
|
|
75
|
-
if not request_id:
|
|
76
|
-
raise Exception("ID not found in URL")
|
|
77
|
-
polling_url = f"https://www.bing.com/images/create/async/results/{request_id}?q={requests.utils.quote(prompt)}"
|
|
78
|
-
attempts = 0
|
|
79
|
-
img_url = None
|
|
80
|
-
while attempts < 10:
|
|
81
|
-
time.sleep(3)
|
|
82
|
-
try:
|
|
83
|
-
poll_resp = session.get(polling_url, headers=headers, timeout=timeout)
|
|
84
|
-
from bs4 import BeautifulSoup
|
|
85
|
-
soup = BeautifulSoup(poll_resp.text, "html.parser")
|
|
86
|
-
imgs = [img["src"].split("?")[0] for img in soup.select(".img_cont .mimg") if img.get("src")]
|
|
87
|
-
if imgs:
|
|
88
|
-
img_url = imgs[0]
|
|
89
|
-
break
|
|
90
|
-
except Exception:
|
|
91
|
-
pass
|
|
92
|
-
attempts += 1
|
|
93
|
-
if not img_url:
|
|
94
|
-
raise Exception("Failed to get images after polling.")
|
|
95
|
-
img_bytes = session.get(img_url, headers=headers, timeout=timeout).content
|
|
96
|
-
# Convert to png or jpeg in memory
|
|
97
|
-
with BytesIO(img_bytes) as input_io:
|
|
98
|
-
with Image.open(input_io) as im:
|
|
99
|
-
out_io = BytesIO()
|
|
100
|
-
if image_format.lower() == "jpeg":
|
|
101
|
-
im = im.convert("RGB")
|
|
102
|
-
im.save(out_io, format="JPEG")
|
|
103
|
-
else:
|
|
104
|
-
im.save(out_io, format="PNG")
|
|
105
|
-
img_bytes = out_io.getvalue()
|
|
106
|
-
images.append(img_bytes)
|
|
107
|
-
if response_format == "url":
|
|
108
|
-
def upload_file_with_retry(img_bytes, image_format, max_retries=3):
|
|
109
|
-
ext = "jpg" if image_format.lower() == "jpeg" else "png"
|
|
110
|
-
for attempt in range(max_retries):
|
|
111
|
-
tmp_path = None
|
|
112
|
-
try:
|
|
113
|
-
with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as tmp:
|
|
114
|
-
tmp.write(img_bytes)
|
|
115
|
-
tmp.flush()
|
|
116
|
-
tmp_path = tmp.name
|
|
117
|
-
with open(tmp_path, "rb") as f:
|
|
118
|
-
files = {"fileToUpload": (f"image.{ext}", f, f"image/{ext}")}
|
|
119
|
-
data = {"reqtype": "fileupload", "json": "true"}
|
|
120
|
-
headers2 = {"User-Agent": agent.random()}
|
|
121
|
-
if attempt > 0:
|
|
122
|
-
headers2["Connection"] = "close"
|
|
123
|
-
resp2 = requests.post(
|
|
124
|
-
"https://catbox.moe/user/api.php",
|
|
125
|
-
files=files,
|
|
126
|
-
data=data,
|
|
127
|
-
headers=headers2,
|
|
128
|
-
timeout=timeout,
|
|
129
|
-
)
|
|
130
|
-
if resp2.status_code == 200 and resp2.text.strip():
|
|
131
|
-
text = resp2.text.strip()
|
|
132
|
-
if text.startswith("http"):
|
|
133
|
-
return text
|
|
134
|
-
try:
|
|
135
|
-
result = resp2.json()
|
|
136
|
-
if "url" in result:
|
|
137
|
-
return result["url"]
|
|
138
|
-
except Exception:
|
|
139
|
-
if "http" in text:
|
|
140
|
-
return text
|
|
141
|
-
except Exception:
|
|
142
|
-
if attempt < max_retries - 1:
|
|
143
|
-
time.sleep(1 * (attempt + 1))
|
|
144
|
-
finally:
|
|
145
|
-
if tmp_path and os.path.isfile(tmp_path):
|
|
146
|
-
try:
|
|
147
|
-
os.remove(tmp_path)
|
|
148
|
-
except Exception:
|
|
149
|
-
pass
|
|
150
|
-
return None
|
|
151
|
-
def upload_file_alternative(img_bytes, image_format):
|
|
152
|
-
try:
|
|
153
|
-
ext = "jpg" if image_format.lower() == "jpeg" else "png"
|
|
154
|
-
with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as tmp:
|
|
155
|
-
tmp.write(img_bytes)
|
|
156
|
-
tmp.flush()
|
|
157
|
-
tmp_path = tmp.name
|
|
158
|
-
try:
|
|
159
|
-
if not os.path.isfile(tmp_path):
|
|
160
|
-
return None
|
|
161
|
-
with open(tmp_path, "rb") as img_file:
|
|
162
|
-
files = {"file": img_file}
|
|
163
|
-
alt_resp = requests.post("https://0x0.st", files=files)
|
|
164
|
-
alt_resp.raise_for_status()
|
|
165
|
-
image_url = alt_resp.text.strip()
|
|
166
|
-
if not image_url.startswith("http"):
|
|
167
|
-
return None
|
|
168
|
-
return image_url
|
|
169
|
-
except Exception:
|
|
170
|
-
return None
|
|
171
|
-
finally:
|
|
172
|
-
try:
|
|
173
|
-
os.remove(tmp_path)
|
|
174
|
-
except Exception:
|
|
175
|
-
pass
|
|
176
|
-
except Exception:
|
|
177
|
-
return None
|
|
178
|
-
uploaded_url = upload_file_with_retry(img_bytes, image_format)
|
|
179
|
-
if not uploaded_url:
|
|
180
|
-
uploaded_url = upload_file_alternative(img_bytes, image_format)
|
|
181
|
-
if uploaded_url:
|
|
182
|
-
urls.append(uploaded_url)
|
|
183
|
-
else:
|
|
184
|
-
raise RuntimeError(
|
|
185
|
-
"Failed to upload image to catbox.moe using all available methods"
|
|
186
|
-
)
|
|
187
|
-
result_data = []
|
|
188
|
-
if response_format == "url":
|
|
189
|
-
for url in urls:
|
|
190
|
-
result_data.append(ImageData(url=url))
|
|
191
|
-
elif response_format == "b64_json":
|
|
192
|
-
import base64
|
|
193
|
-
for img in images:
|
|
194
|
-
b64 = base64.b64encode(img).decode("utf-8")
|
|
195
|
-
result_data.append(ImageData(b64_json=b64))
|
|
196
|
-
else:
|
|
197
|
-
raise ValueError("response_format must be 'url' or 'b64_json'")
|
|
198
|
-
from time import time as _time
|
|
199
|
-
return ImageResponse(created=int(_time()), data=result_data)
|
|
200
|
-
|
|
201
|
-
class BingImageAI(TTICompatibleProvider):
|
|
202
|
-
AVAILABLE_MODELS = ["bing"]
|
|
203
|
-
def __init__(self, cookie: Optional[str] = None):
|
|
204
|
-
self.session = requests.Session()
|
|
205
|
-
self.user_agent = LitAgent().random()
|
|
206
|
-
self.headers = {
|
|
207
|
-
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
|
208
|
-
"accept-language": "id-ID,id;q=0.9",
|
|
209
|
-
"cache-control": "max-age=0",
|
|
210
|
-
"content-type": "application/x-www-form-urlencoded",
|
|
211
|
-
"origin": "https://www.bing.com",
|
|
212
|
-
"referer": "https://www.bing.com/images/create?&wlexpsignin=1",
|
|
213
|
-
"sec-ch-ua": '"Chromium";v="131", "Not_A Brand";v="24", "Microsoft Edge Simulate";v="131", "Lemur";v="131"',
|
|
214
|
-
"sec-ch-ua-mobile": "?1",
|
|
215
|
-
"sec-fetch-site": "same-origin",
|
|
216
|
-
"sec-fetch-mode": "navigate",
|
|
217
|
-
"sec-fetch-dest": "document",
|
|
218
|
-
"upgrade-insecure-requests": "1",
|
|
219
|
-
"user-agent": self.user_agent,
|
|
220
|
-
}
|
|
221
|
-
self.session.headers.update(self.headers)
|
|
222
|
-
self.cookie = cookie
|
|
223
|
-
if cookie:
|
|
224
|
-
self.session.cookies.set("_U", cookie, domain="bing.com")
|
|
225
|
-
self.images = Images(self)
|
|
226
|
-
@property
|
|
227
|
-
def models(self):
|
|
228
|
-
class _ModelList:
|
|
229
|
-
def list(inner_self):
|
|
230
|
-
return type(self).AVAILABLE_MODELS
|
|
231
|
-
return _ModelList()
|
|
232
|
-
|
|
233
|
-
if __name__ == "__main__":
|
|
234
|
-
from rich import print
|
|
235
|
-
client = BingImageAI(cookie="1QyBY4Z1eHBW6fbI25kdM5TrlRGWzn5PFySapCOfvvz04zaounFG660EipVJSOXXvcdeXXLwsWHdDI8bNymucF_QnMHSlY1mc0pPI7e9Ar6o-_7e9Ik5QOe1nkJIe5vz22pibioTqx0IfVKwmVbX22A3bFD7ODaSZalKFr-AuxgAaRVod-giTTry6Ei7RVgisF7BHlkMPPwtCeO234ujgug")
|
|
236
|
-
response = client.images.create(
|
|
237
|
-
model="gpt4o",
|
|
238
|
-
prompt="A cat riding a bicycle",
|
|
239
|
-
response_format="url",
|
|
240
|
-
n=4,
|
|
241
|
-
timeout=30
|
|
242
|
-
)
|
|
243
|
-
print(response)
|
|
1
|
+
import requests
|
|
2
|
+
import time
|
|
3
|
+
import tempfile
|
|
4
|
+
import os
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from webscout.Provider.TTI.utils import ImageData, ImageResponse
|
|
7
|
+
from webscout.Provider.TTI.base import TTICompatibleProvider, BaseImages
|
|
8
|
+
from io import BytesIO
|
|
9
|
+
from webscout.litagent import LitAgent
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from PIL import Image
|
|
13
|
+
except ImportError:
|
|
14
|
+
Image = None
|
|
15
|
+
|
|
16
|
+
class Images(BaseImages):
|
|
17
|
+
def __init__(self, client):
|
|
18
|
+
self._client = client
|
|
19
|
+
|
|
20
|
+
def create(
|
|
21
|
+
self,
|
|
22
|
+
*,
|
|
23
|
+
model: str = "dalle",
|
|
24
|
+
prompt: str,
|
|
25
|
+
n: int = 1,
|
|
26
|
+
size: str = "1024x1024",
|
|
27
|
+
response_format: str = "url",
|
|
28
|
+
user: Optional[str] = None,
|
|
29
|
+
style: str = "none",
|
|
30
|
+
aspect_ratio: str = "1:1",
|
|
31
|
+
timeout: int = 60,
|
|
32
|
+
image_format: str = "png",
|
|
33
|
+
seed: Optional[int] = None,
|
|
34
|
+
**kwargs
|
|
35
|
+
) -> ImageResponse:
|
|
36
|
+
if not prompt:
|
|
37
|
+
raise ValueError("Parameter 'prompt' is required")
|
|
38
|
+
if Image is None:
|
|
39
|
+
raise ImportError("Pillow (PIL) is required for image format conversion.")
|
|
40
|
+
agent = LitAgent()
|
|
41
|
+
session = self._client.session
|
|
42
|
+
headers = self._client.headers
|
|
43
|
+
images = []
|
|
44
|
+
urls = []
|
|
45
|
+
|
|
46
|
+
# Map model names to Bing model codes
|
|
47
|
+
model_mapping = {
|
|
48
|
+
"dalle": "0",
|
|
49
|
+
"gpt4o": "1",
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Get the appropriate model code
|
|
53
|
+
model_code = model_mapping.get(model.lower(), "4")
|
|
54
|
+
|
|
55
|
+
for _ in range(n):
|
|
56
|
+
data = {
|
|
57
|
+
"q": prompt,
|
|
58
|
+
"rt": "4",
|
|
59
|
+
"mdl": model_code,
|
|
60
|
+
"FORM": "GENCRE"
|
|
61
|
+
}
|
|
62
|
+
response = session.post(
|
|
63
|
+
"https://www.bing.com/images/create",
|
|
64
|
+
data=data,
|
|
65
|
+
headers=headers,
|
|
66
|
+
allow_redirects=False,
|
|
67
|
+
timeout=timeout
|
|
68
|
+
)
|
|
69
|
+
redirect_url = response.headers.get("Location")
|
|
70
|
+
if not redirect_url:
|
|
71
|
+
raise Exception("Failed to get redirect URL")
|
|
72
|
+
from urllib.parse import urlparse, parse_qs
|
|
73
|
+
query = urlparse(redirect_url).query
|
|
74
|
+
request_id = parse_qs(query).get("id", [None])[0]
|
|
75
|
+
if not request_id:
|
|
76
|
+
raise Exception("ID not found in URL")
|
|
77
|
+
polling_url = f"https://www.bing.com/images/create/async/results/{request_id}?q={requests.utils.quote(prompt)}"
|
|
78
|
+
attempts = 0
|
|
79
|
+
img_url = None
|
|
80
|
+
while attempts < 10:
|
|
81
|
+
time.sleep(3)
|
|
82
|
+
try:
|
|
83
|
+
poll_resp = session.get(polling_url, headers=headers, timeout=timeout)
|
|
84
|
+
from bs4 import BeautifulSoup
|
|
85
|
+
soup = BeautifulSoup(poll_resp.text, "html.parser")
|
|
86
|
+
imgs = [img["src"].split("?")[0] for img in soup.select(".img_cont .mimg") if img.get("src")]
|
|
87
|
+
if imgs:
|
|
88
|
+
img_url = imgs[0]
|
|
89
|
+
break
|
|
90
|
+
except Exception:
|
|
91
|
+
pass
|
|
92
|
+
attempts += 1
|
|
93
|
+
if not img_url:
|
|
94
|
+
raise Exception("Failed to get images after polling.")
|
|
95
|
+
img_bytes = session.get(img_url, headers=headers, timeout=timeout).content
|
|
96
|
+
# Convert to png or jpeg in memory
|
|
97
|
+
with BytesIO(img_bytes) as input_io:
|
|
98
|
+
with Image.open(input_io) as im:
|
|
99
|
+
out_io = BytesIO()
|
|
100
|
+
if image_format.lower() == "jpeg":
|
|
101
|
+
im = im.convert("RGB")
|
|
102
|
+
im.save(out_io, format="JPEG")
|
|
103
|
+
else:
|
|
104
|
+
im.save(out_io, format="PNG")
|
|
105
|
+
img_bytes = out_io.getvalue()
|
|
106
|
+
images.append(img_bytes)
|
|
107
|
+
if response_format == "url":
|
|
108
|
+
def upload_file_with_retry(img_bytes, image_format, max_retries=3):
|
|
109
|
+
ext = "jpg" if image_format.lower() == "jpeg" else "png"
|
|
110
|
+
for attempt in range(max_retries):
|
|
111
|
+
tmp_path = None
|
|
112
|
+
try:
|
|
113
|
+
with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as tmp:
|
|
114
|
+
tmp.write(img_bytes)
|
|
115
|
+
tmp.flush()
|
|
116
|
+
tmp_path = tmp.name
|
|
117
|
+
with open(tmp_path, "rb") as f:
|
|
118
|
+
files = {"fileToUpload": (f"image.{ext}", f, f"image/{ext}")}
|
|
119
|
+
data = {"reqtype": "fileupload", "json": "true"}
|
|
120
|
+
headers2 = {"User-Agent": agent.random()}
|
|
121
|
+
if attempt > 0:
|
|
122
|
+
headers2["Connection"] = "close"
|
|
123
|
+
resp2 = requests.post(
|
|
124
|
+
"https://catbox.moe/user/api.php",
|
|
125
|
+
files=files,
|
|
126
|
+
data=data,
|
|
127
|
+
headers=headers2,
|
|
128
|
+
timeout=timeout,
|
|
129
|
+
)
|
|
130
|
+
if resp2.status_code == 200 and resp2.text.strip():
|
|
131
|
+
text = resp2.text.strip()
|
|
132
|
+
if text.startswith("http"):
|
|
133
|
+
return text
|
|
134
|
+
try:
|
|
135
|
+
result = resp2.json()
|
|
136
|
+
if "url" in result:
|
|
137
|
+
return result["url"]
|
|
138
|
+
except Exception:
|
|
139
|
+
if "http" in text:
|
|
140
|
+
return text
|
|
141
|
+
except Exception:
|
|
142
|
+
if attempt < max_retries - 1:
|
|
143
|
+
time.sleep(1 * (attempt + 1))
|
|
144
|
+
finally:
|
|
145
|
+
if tmp_path and os.path.isfile(tmp_path):
|
|
146
|
+
try:
|
|
147
|
+
os.remove(tmp_path)
|
|
148
|
+
except Exception:
|
|
149
|
+
pass
|
|
150
|
+
return None
|
|
151
|
+
def upload_file_alternative(img_bytes, image_format):
|
|
152
|
+
try:
|
|
153
|
+
ext = "jpg" if image_format.lower() == "jpeg" else "png"
|
|
154
|
+
with tempfile.NamedTemporaryFile(suffix=f".{ext}", delete=False) as tmp:
|
|
155
|
+
tmp.write(img_bytes)
|
|
156
|
+
tmp.flush()
|
|
157
|
+
tmp_path = tmp.name
|
|
158
|
+
try:
|
|
159
|
+
if not os.path.isfile(tmp_path):
|
|
160
|
+
return None
|
|
161
|
+
with open(tmp_path, "rb") as img_file:
|
|
162
|
+
files = {"file": img_file}
|
|
163
|
+
alt_resp = requests.post("https://0x0.st", files=files)
|
|
164
|
+
alt_resp.raise_for_status()
|
|
165
|
+
image_url = alt_resp.text.strip()
|
|
166
|
+
if not image_url.startswith("http"):
|
|
167
|
+
return None
|
|
168
|
+
return image_url
|
|
169
|
+
except Exception:
|
|
170
|
+
return None
|
|
171
|
+
finally:
|
|
172
|
+
try:
|
|
173
|
+
os.remove(tmp_path)
|
|
174
|
+
except Exception:
|
|
175
|
+
pass
|
|
176
|
+
except Exception:
|
|
177
|
+
return None
|
|
178
|
+
uploaded_url = upload_file_with_retry(img_bytes, image_format)
|
|
179
|
+
if not uploaded_url:
|
|
180
|
+
uploaded_url = upload_file_alternative(img_bytes, image_format)
|
|
181
|
+
if uploaded_url:
|
|
182
|
+
urls.append(uploaded_url)
|
|
183
|
+
else:
|
|
184
|
+
raise RuntimeError(
|
|
185
|
+
"Failed to upload image to catbox.moe using all available methods"
|
|
186
|
+
)
|
|
187
|
+
result_data = []
|
|
188
|
+
if response_format == "url":
|
|
189
|
+
for url in urls:
|
|
190
|
+
result_data.append(ImageData(url=url))
|
|
191
|
+
elif response_format == "b64_json":
|
|
192
|
+
import base64
|
|
193
|
+
for img in images:
|
|
194
|
+
b64 = base64.b64encode(img).decode("utf-8")
|
|
195
|
+
result_data.append(ImageData(b64_json=b64))
|
|
196
|
+
else:
|
|
197
|
+
raise ValueError("response_format must be 'url' or 'b64_json'")
|
|
198
|
+
from time import time as _time
|
|
199
|
+
return ImageResponse(created=int(_time()), data=result_data)
|
|
200
|
+
|
|
201
|
+
class BingImageAI(TTICompatibleProvider):
|
|
202
|
+
AVAILABLE_MODELS = ["bing"]
|
|
203
|
+
def __init__(self, cookie: Optional[str] = None):
|
|
204
|
+
self.session = requests.Session()
|
|
205
|
+
self.user_agent = LitAgent().random()
|
|
206
|
+
self.headers = {
|
|
207
|
+
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
|
208
|
+
"accept-language": "id-ID,id;q=0.9",
|
|
209
|
+
"cache-control": "max-age=0",
|
|
210
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
211
|
+
"origin": "https://www.bing.com",
|
|
212
|
+
"referer": "https://www.bing.com/images/create?&wlexpsignin=1",
|
|
213
|
+
"sec-ch-ua": '"Chromium";v="131", "Not_A Brand";v="24", "Microsoft Edge Simulate";v="131", "Lemur";v="131"',
|
|
214
|
+
"sec-ch-ua-mobile": "?1",
|
|
215
|
+
"sec-fetch-site": "same-origin",
|
|
216
|
+
"sec-fetch-mode": "navigate",
|
|
217
|
+
"sec-fetch-dest": "document",
|
|
218
|
+
"upgrade-insecure-requests": "1",
|
|
219
|
+
"user-agent": self.user_agent,
|
|
220
|
+
}
|
|
221
|
+
self.session.headers.update(self.headers)
|
|
222
|
+
self.cookie = cookie
|
|
223
|
+
if cookie:
|
|
224
|
+
self.session.cookies.set("_U", cookie, domain="bing.com")
|
|
225
|
+
self.images = Images(self)
|
|
226
|
+
@property
|
|
227
|
+
def models(self):
|
|
228
|
+
class _ModelList:
|
|
229
|
+
def list(inner_self):
|
|
230
|
+
return type(self).AVAILABLE_MODELS
|
|
231
|
+
return _ModelList()
|
|
232
|
+
|
|
233
|
+
if __name__ == "__main__":
|
|
234
|
+
from rich import print
|
|
235
|
+
client = BingImageAI(cookie="1QyBY4Z1eHBW6fbI25kdM5TrlRGWzn5PFySapCOfvvz04zaounFG660EipVJSOXXvcdeXXLwsWHdDI8bNymucF_QnMHSlY1mc0pPI7e9Ar6o-_7e9Ik5QOe1nkJIe5vz22pibioTqx0IfVKwmVbX22A3bFD7ODaSZalKFr-AuxgAaRVod-giTTry6Ei7RVgisF7BHlkMPPwtCeO234ujgug")
|
|
236
|
+
response = client.images.create(
|
|
237
|
+
model="gpt4o",
|
|
238
|
+
prompt="A cat riding a bicycle",
|
|
239
|
+
response_format="url",
|
|
240
|
+
n=4,
|
|
241
|
+
timeout=30
|
|
242
|
+
)
|
|
243
|
+
print(response)
|