webscout 8.2.9__py3-none-any.whl → 2026.1.19__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.
- webscout/AIauto.py +524 -251
- webscout/AIbase.py +247 -319
- webscout/AIutel.py +68 -703
- webscout/Bard.py +1072 -1026
- webscout/Extra/GitToolkit/__init__.py +10 -10
- webscout/Extra/GitToolkit/gitapi/__init__.py +20 -12
- webscout/Extra/GitToolkit/gitapi/gist.py +142 -0
- webscout/Extra/GitToolkit/gitapi/organization.py +91 -0
- webscout/Extra/GitToolkit/gitapi/repository.py +308 -195
- webscout/Extra/GitToolkit/gitapi/search.py +162 -0
- webscout/Extra/GitToolkit/gitapi/trending.py +236 -0
- webscout/Extra/GitToolkit/gitapi/user.py +128 -96
- webscout/Extra/GitToolkit/gitapi/utils.py +82 -62
- webscout/Extra/YTToolkit/README.md +443 -375
- webscout/Extra/YTToolkit/YTdownloader.py +953 -957
- webscout/Extra/YTToolkit/__init__.py +3 -3
- webscout/Extra/YTToolkit/transcriber.py +595 -476
- webscout/Extra/YTToolkit/ytapi/README.md +230 -44
- webscout/Extra/YTToolkit/ytapi/__init__.py +22 -6
- webscout/Extra/YTToolkit/ytapi/captions.py +190 -0
- webscout/Extra/YTToolkit/ytapi/channel.py +302 -307
- webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
- webscout/Extra/YTToolkit/ytapi/extras.py +178 -118
- webscout/Extra/YTToolkit/ytapi/hashtag.py +120 -0
- webscout/Extra/YTToolkit/ytapi/https.py +89 -88
- webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
- webscout/Extra/YTToolkit/ytapi/playlist.py +59 -59
- webscout/Extra/YTToolkit/ytapi/pool.py +8 -8
- webscout/Extra/YTToolkit/ytapi/query.py +143 -40
- webscout/Extra/YTToolkit/ytapi/shorts.py +122 -0
- webscout/Extra/YTToolkit/ytapi/stream.py +68 -63
- webscout/Extra/YTToolkit/ytapi/suggestions.py +97 -0
- webscout/Extra/YTToolkit/ytapi/utils.py +66 -62
- webscout/Extra/YTToolkit/ytapi/video.py +403 -232
- webscout/Extra/__init__.py +2 -3
- webscout/Extra/gguf.py +1298 -684
- webscout/Extra/tempmail/README.md +487 -487
- webscout/Extra/tempmail/__init__.py +28 -28
- webscout/Extra/tempmail/async_utils.py +143 -141
- webscout/Extra/tempmail/base.py +172 -161
- webscout/Extra/tempmail/cli.py +191 -187
- webscout/Extra/tempmail/emailnator.py +88 -84
- webscout/Extra/tempmail/mail_tm.py +378 -361
- webscout/Extra/tempmail/temp_mail_io.py +304 -292
- webscout/Extra/weather.py +196 -194
- webscout/Extra/weather_ascii.py +17 -15
- webscout/Provider/AISEARCH/PERPLEXED_search.py +175 -0
- webscout/Provider/AISEARCH/Perplexity.py +292 -333
- webscout/Provider/AISEARCH/README.md +106 -279
- webscout/Provider/AISEARCH/__init__.py +16 -9
- webscout/Provider/AISEARCH/brave_search.py +298 -0
- webscout/Provider/AISEARCH/iask_search.py +357 -410
- webscout/Provider/AISEARCH/monica_search.py +200 -220
- webscout/Provider/AISEARCH/webpilotai_search.py +242 -255
- webscout/Provider/Algion.py +413 -0
- webscout/Provider/Andi.py +74 -69
- webscout/Provider/Apriel.py +313 -0
- webscout/Provider/Ayle.py +323 -0
- webscout/Provider/ChatSandbox.py +329 -342
- webscout/Provider/ClaudeOnline.py +365 -0
- webscout/Provider/Cohere.py +232 -208
- webscout/Provider/DeepAI.py +367 -0
- webscout/Provider/Deepinfra.py +467 -340
- webscout/Provider/EssentialAI.py +217 -0
- webscout/Provider/ExaAI.py +274 -261
- webscout/Provider/Gemini.py +175 -169
- webscout/Provider/GithubChat.py +385 -369
- webscout/Provider/Gradient.py +286 -0
- webscout/Provider/Groq.py +556 -801
- webscout/Provider/HadadXYZ.py +323 -0
- webscout/Provider/HeckAI.py +392 -375
- webscout/Provider/HuggingFace.py +387 -0
- webscout/Provider/IBM.py +340 -0
- webscout/Provider/Jadve.py +317 -291
- webscout/Provider/K2Think.py +306 -0
- webscout/Provider/Koboldai.py +221 -384
- webscout/Provider/Netwrck.py +273 -270
- webscout/Provider/Nvidia.py +310 -0
- webscout/Provider/OPENAI/DeepAI.py +489 -0
- webscout/Provider/OPENAI/K2Think.py +423 -0
- webscout/Provider/OPENAI/PI.py +463 -0
- webscout/Provider/OPENAI/README.md +890 -952
- webscout/Provider/OPENAI/TogetherAI.py +405 -0
- webscout/Provider/OPENAI/TwoAI.py +255 -357
- webscout/Provider/OPENAI/__init__.py +148 -40
- webscout/Provider/OPENAI/ai4chat.py +348 -293
- webscout/Provider/OPENAI/akashgpt.py +436 -0
- webscout/Provider/OPENAI/algion.py +303 -0
- webscout/Provider/OPENAI/{exachat.py → ayle.py} +365 -444
- webscout/Provider/OPENAI/base.py +253 -249
- webscout/Provider/OPENAI/cerebras.py +296 -0
- webscout/Provider/OPENAI/chatgpt.py +870 -556
- webscout/Provider/OPENAI/chatsandbox.py +233 -173
- webscout/Provider/OPENAI/deepinfra.py +403 -322
- webscout/Provider/OPENAI/e2b.py +2370 -1414
- webscout/Provider/OPENAI/elmo.py +278 -0
- webscout/Provider/OPENAI/exaai.py +452 -417
- webscout/Provider/OPENAI/freeassist.py +446 -0
- webscout/Provider/OPENAI/gradient.py +448 -0
- webscout/Provider/OPENAI/groq.py +380 -364
- webscout/Provider/OPENAI/hadadxyz.py +292 -0
- webscout/Provider/OPENAI/heckai.py +333 -308
- webscout/Provider/OPENAI/huggingface.py +321 -0
- webscout/Provider/OPENAI/ibm.py +425 -0
- webscout/Provider/OPENAI/llmchat.py +253 -0
- webscout/Provider/OPENAI/llmchatco.py +378 -335
- webscout/Provider/OPENAI/meta.py +541 -0
- webscout/Provider/OPENAI/netwrck.py +374 -357
- webscout/Provider/OPENAI/nvidia.py +317 -0
- webscout/Provider/OPENAI/oivscode.py +348 -287
- webscout/Provider/OPENAI/openrouter.py +328 -0
- webscout/Provider/OPENAI/pydantic_imports.py +1 -172
- webscout/Provider/OPENAI/sambanova.py +397 -0
- webscout/Provider/OPENAI/sonus.py +305 -304
- webscout/Provider/OPENAI/textpollinations.py +370 -339
- webscout/Provider/OPENAI/toolbaz.py +375 -413
- webscout/Provider/OPENAI/typefully.py +419 -355
- webscout/Provider/OPENAI/typliai.py +279 -0
- webscout/Provider/OPENAI/utils.py +314 -318
- webscout/Provider/OPENAI/wisecat.py +359 -387
- webscout/Provider/OPENAI/writecream.py +185 -163
- webscout/Provider/OPENAI/x0gpt.py +462 -365
- webscout/Provider/OPENAI/zenmux.py +380 -0
- webscout/Provider/OpenRouter.py +386 -0
- webscout/Provider/Openai.py +337 -496
- webscout/Provider/PI.py +443 -429
- webscout/Provider/QwenLM.py +346 -254
- webscout/Provider/STT/__init__.py +28 -0
- webscout/Provider/STT/base.py +303 -0
- webscout/Provider/STT/elevenlabs.py +264 -0
- webscout/Provider/Sambanova.py +317 -0
- webscout/Provider/TTI/README.md +69 -82
- webscout/Provider/TTI/__init__.py +37 -7
- webscout/Provider/TTI/base.py +147 -64
- webscout/Provider/TTI/claudeonline.py +393 -0
- webscout/Provider/TTI/magicstudio.py +292 -201
- webscout/Provider/TTI/miragic.py +180 -0
- webscout/Provider/TTI/pollinations.py +331 -221
- webscout/Provider/TTI/together.py +334 -0
- webscout/Provider/TTI/utils.py +14 -11
- webscout/Provider/TTS/README.md +186 -192
- webscout/Provider/TTS/__init__.py +43 -10
- webscout/Provider/TTS/base.py +523 -159
- webscout/Provider/TTS/deepgram.py +286 -156
- webscout/Provider/TTS/elevenlabs.py +189 -111
- webscout/Provider/TTS/freetts.py +218 -0
- webscout/Provider/TTS/murfai.py +288 -113
- webscout/Provider/TTS/openai_fm.py +364 -129
- webscout/Provider/TTS/parler.py +203 -111
- webscout/Provider/TTS/qwen.py +334 -0
- webscout/Provider/TTS/sherpa.py +286 -0
- webscout/Provider/TTS/speechma.py +693 -580
- webscout/Provider/TTS/streamElements.py +275 -333
- webscout/Provider/TTS/utils.py +280 -280
- webscout/Provider/TextPollinationsAI.py +331 -308
- webscout/Provider/TogetherAI.py +450 -0
- webscout/Provider/TwoAI.py +309 -475
- webscout/Provider/TypliAI.py +311 -305
- webscout/Provider/UNFINISHED/ChatHub.py +219 -209
- webscout/Provider/{OPENAI/glider.py → UNFINISHED/ChutesAI.py} +331 -326
- webscout/Provider/{GizAI.py → UNFINISHED/GizAI.py} +300 -295
- webscout/Provider/{Marcus.py → UNFINISHED/Marcus.py} +218 -198
- webscout/Provider/UNFINISHED/Qodo.py +481 -0
- webscout/Provider/{MCPCore.py → UNFINISHED/XenAI.py} +330 -315
- webscout/Provider/UNFINISHED/Youchat.py +347 -330
- webscout/Provider/UNFINISHED/aihumanizer.py +41 -0
- webscout/Provider/UNFINISHED/grammerchecker.py +37 -0
- webscout/Provider/UNFINISHED/liner.py +342 -0
- webscout/Provider/UNFINISHED/liner_api_request.py +246 -263
- webscout/Provider/{samurai.py → UNFINISHED/samurai.py} +231 -224
- webscout/Provider/WiseCat.py +256 -233
- webscout/Provider/WrDoChat.py +390 -370
- webscout/Provider/__init__.py +115 -174
- webscout/Provider/ai4chat.py +181 -174
- webscout/Provider/akashgpt.py +330 -335
- webscout/Provider/cerebras.py +397 -290
- webscout/Provider/cleeai.py +236 -213
- webscout/Provider/elmo.py +291 -283
- webscout/Provider/geminiapi.py +343 -208
- webscout/Provider/julius.py +245 -223
- webscout/Provider/learnfastai.py +333 -325
- webscout/Provider/llama3mitril.py +230 -215
- webscout/Provider/llmchat.py +308 -258
- webscout/Provider/llmchatco.py +321 -306
- webscout/Provider/meta.py +996 -801
- webscout/Provider/oivscode.py +332 -309
- webscout/Provider/searchchat.py +316 -292
- webscout/Provider/sonus.py +264 -258
- webscout/Provider/toolbaz.py +359 -353
- webscout/Provider/turboseek.py +332 -266
- webscout/Provider/typefully.py +262 -202
- webscout/Provider/x0gpt.py +332 -299
- webscout/__init__.py +31 -39
- webscout/__main__.py +5 -5
- webscout/cli.py +585 -524
- webscout/client.py +1497 -70
- webscout/conversation.py +140 -436
- webscout/exceptions.py +383 -362
- webscout/litagent/__init__.py +29 -29
- webscout/litagent/agent.py +492 -455
- webscout/litagent/constants.py +60 -60
- webscout/models.py +505 -181
- webscout/optimizers.py +74 -420
- webscout/prompt_manager.py +376 -288
- webscout/sanitize.py +1514 -0
- webscout/scout/README.md +452 -404
- webscout/scout/__init__.py +8 -8
- webscout/scout/core/__init__.py +7 -7
- webscout/scout/core/crawler.py +330 -210
- webscout/scout/core/scout.py +800 -607
- webscout/scout/core/search_result.py +51 -96
- webscout/scout/core/text_analyzer.py +64 -63
- webscout/scout/core/text_utils.py +412 -277
- webscout/scout/core/web_analyzer.py +54 -52
- webscout/scout/element.py +872 -478
- webscout/scout/parsers/__init__.py +70 -69
- webscout/scout/parsers/html5lib_parser.py +182 -172
- webscout/scout/parsers/html_parser.py +238 -236
- webscout/scout/parsers/lxml_parser.py +203 -178
- webscout/scout/utils.py +38 -37
- webscout/search/__init__.py +47 -0
- webscout/search/base.py +201 -0
- webscout/search/bing_main.py +45 -0
- webscout/search/brave_main.py +92 -0
- webscout/search/duckduckgo_main.py +57 -0
- webscout/search/engines/__init__.py +127 -0
- webscout/search/engines/bing/__init__.py +15 -0
- webscout/search/engines/bing/base.py +35 -0
- webscout/search/engines/bing/images.py +114 -0
- webscout/search/engines/bing/news.py +96 -0
- webscout/search/engines/bing/suggestions.py +36 -0
- webscout/search/engines/bing/text.py +109 -0
- webscout/search/engines/brave/__init__.py +19 -0
- webscout/search/engines/brave/base.py +47 -0
- webscout/search/engines/brave/images.py +213 -0
- webscout/search/engines/brave/news.py +353 -0
- webscout/search/engines/brave/suggestions.py +318 -0
- webscout/search/engines/brave/text.py +167 -0
- webscout/search/engines/brave/videos.py +364 -0
- webscout/search/engines/duckduckgo/__init__.py +25 -0
- webscout/search/engines/duckduckgo/answers.py +80 -0
- webscout/search/engines/duckduckgo/base.py +189 -0
- webscout/search/engines/duckduckgo/images.py +100 -0
- webscout/search/engines/duckduckgo/maps.py +183 -0
- webscout/search/engines/duckduckgo/news.py +70 -0
- webscout/search/engines/duckduckgo/suggestions.py +22 -0
- webscout/search/engines/duckduckgo/text.py +221 -0
- webscout/search/engines/duckduckgo/translate.py +48 -0
- webscout/search/engines/duckduckgo/videos.py +80 -0
- webscout/search/engines/duckduckgo/weather.py +84 -0
- webscout/search/engines/mojeek.py +61 -0
- webscout/search/engines/wikipedia.py +77 -0
- webscout/search/engines/yahoo/__init__.py +41 -0
- webscout/search/engines/yahoo/answers.py +19 -0
- webscout/search/engines/yahoo/base.py +34 -0
- webscout/search/engines/yahoo/images.py +323 -0
- webscout/search/engines/yahoo/maps.py +19 -0
- webscout/search/engines/yahoo/news.py +258 -0
- webscout/search/engines/yahoo/suggestions.py +140 -0
- webscout/search/engines/yahoo/text.py +273 -0
- webscout/search/engines/yahoo/translate.py +19 -0
- webscout/search/engines/yahoo/videos.py +302 -0
- webscout/search/engines/yahoo/weather.py +220 -0
- webscout/search/engines/yandex.py +67 -0
- webscout/search/engines/yep/__init__.py +13 -0
- webscout/search/engines/yep/base.py +34 -0
- webscout/search/engines/yep/images.py +101 -0
- webscout/search/engines/yep/suggestions.py +38 -0
- webscout/search/engines/yep/text.py +99 -0
- webscout/search/http_client.py +172 -0
- webscout/search/results.py +141 -0
- webscout/search/yahoo_main.py +57 -0
- webscout/search/yep_main.py +48 -0
- webscout/server/__init__.py +48 -0
- webscout/server/config.py +78 -0
- webscout/server/exceptions.py +69 -0
- webscout/server/providers.py +286 -0
- webscout/server/request_models.py +131 -0
- webscout/server/request_processing.py +404 -0
- webscout/server/routes.py +642 -0
- webscout/server/server.py +351 -0
- webscout/server/ui_templates.py +1171 -0
- webscout/swiftcli/__init__.py +79 -95
- webscout/swiftcli/core/__init__.py +7 -7
- webscout/swiftcli/core/cli.py +574 -297
- webscout/swiftcli/core/context.py +98 -104
- webscout/swiftcli/core/group.py +268 -241
- webscout/swiftcli/decorators/__init__.py +28 -28
- webscout/swiftcli/decorators/command.py +243 -221
- webscout/swiftcli/decorators/options.py +247 -220
- webscout/swiftcli/decorators/output.py +392 -252
- webscout/swiftcli/exceptions.py +21 -21
- webscout/swiftcli/plugins/__init__.py +9 -9
- webscout/swiftcli/plugins/base.py +134 -135
- webscout/swiftcli/plugins/manager.py +269 -269
- webscout/swiftcli/utils/__init__.py +58 -59
- webscout/swiftcli/utils/formatting.py +251 -252
- webscout/swiftcli/utils/parsing.py +368 -267
- webscout/update_checker.py +280 -136
- webscout/utils.py +28 -14
- webscout/version.py +2 -1
- webscout/version.py.bak +3 -0
- webscout/zeroart/__init__.py +218 -135
- webscout/zeroart/base.py +70 -66
- webscout/zeroart/effects.py +155 -101
- webscout/zeroart/fonts.py +1799 -1239
- webscout-2026.1.19.dist-info/METADATA +638 -0
- webscout-2026.1.19.dist-info/RECORD +312 -0
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/WHEEL +1 -1
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/entry_points.txt +1 -1
- webscout/DWEBS.py +0 -520
- webscout/Extra/Act.md +0 -309
- webscout/Extra/GitToolkit/gitapi/README.md +0 -110
- webscout/Extra/autocoder/__init__.py +0 -9
- webscout/Extra/autocoder/autocoder.py +0 -1105
- webscout/Extra/autocoder/autocoder_utiles.py +0 -332
- webscout/Extra/gguf.md +0 -430
- webscout/Extra/weather.md +0 -281
- webscout/Litlogger/README.md +0 -10
- webscout/Litlogger/__init__.py +0 -15
- webscout/Litlogger/formats.py +0 -4
- webscout/Litlogger/handlers.py +0 -103
- webscout/Litlogger/levels.py +0 -13
- webscout/Litlogger/logger.py +0 -92
- webscout/Provider/AI21.py +0 -177
- webscout/Provider/AISEARCH/DeepFind.py +0 -254
- webscout/Provider/AISEARCH/felo_search.py +0 -202
- webscout/Provider/AISEARCH/genspark_search.py +0 -324
- webscout/Provider/AISEARCH/hika_search.py +0 -186
- webscout/Provider/AISEARCH/scira_search.py +0 -298
- webscout/Provider/Aitopia.py +0 -316
- webscout/Provider/AllenAI.py +0 -440
- webscout/Provider/Blackboxai.py +0 -791
- webscout/Provider/ChatGPTClone.py +0 -237
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/Cloudflare.py +0 -324
- webscout/Provider/ExaChat.py +0 -358
- webscout/Provider/Flowith.py +0 -217
- webscout/Provider/FreeGemini.py +0 -250
- webscout/Provider/Glider.py +0 -225
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/HuggingFaceChat.py +0 -469
- webscout/Provider/Hunyuan.py +0 -283
- webscout/Provider/LambdaChat.py +0 -411
- webscout/Provider/Llama3.py +0 -259
- webscout/Provider/Nemotron.py +0 -218
- webscout/Provider/OLLAMA.py +0 -396
- webscout/Provider/OPENAI/BLACKBOXAI.py +0 -766
- webscout/Provider/OPENAI/Cloudflare.py +0 -378
- webscout/Provider/OPENAI/FreeGemini.py +0 -283
- webscout/Provider/OPENAI/NEMOTRON.py +0 -232
- webscout/Provider/OPENAI/Qwen3.py +0 -283
- webscout/Provider/OPENAI/api.py +0 -969
- webscout/Provider/OPENAI/c4ai.py +0 -373
- webscout/Provider/OPENAI/chatgptclone.py +0 -494
- webscout/Provider/OPENAI/copilot.py +0 -242
- webscout/Provider/OPENAI/flowith.py +0 -162
- webscout/Provider/OPENAI/freeaichat.py +0 -359
- webscout/Provider/OPENAI/mcpcore.py +0 -389
- webscout/Provider/OPENAI/multichat.py +0 -376
- webscout/Provider/OPENAI/opkfc.py +0 -496
- webscout/Provider/OPENAI/scirachat.py +0 -477
- webscout/Provider/OPENAI/standardinput.py +0 -433
- webscout/Provider/OPENAI/typegpt.py +0 -364
- webscout/Provider/OPENAI/uncovrAI.py +0 -463
- webscout/Provider/OPENAI/venice.py +0 -431
- webscout/Provider/OPENAI/yep.py +0 -382
- webscout/Provider/OpenGPT.py +0 -209
- webscout/Provider/Perplexitylabs.py +0 -415
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/StandardInput.py +0 -290
- webscout/Provider/TTI/aiarta.py +0 -365
- webscout/Provider/TTI/artbit.py +0 -0
- webscout/Provider/TTI/fastflux.py +0 -200
- webscout/Provider/TTI/piclumen.py +0 -203
- webscout/Provider/TTI/pixelmuse.py +0 -225
- webscout/Provider/TTS/gesserit.py +0 -128
- webscout/Provider/TTS/sthir.py +0 -94
- webscout/Provider/TeachAnything.py +0 -229
- webscout/Provider/UNFINISHED/puterjs.py +0 -635
- webscout/Provider/UNFINISHED/test_lmarena.py +0 -119
- webscout/Provider/Venice.py +0 -258
- webscout/Provider/VercelAI.py +0 -253
- webscout/Provider/Writecream.py +0 -246
- webscout/Provider/WritingMate.py +0 -269
- webscout/Provider/asksteve.py +0 -220
- webscout/Provider/chatglm.py +0 -215
- webscout/Provider/copilot.py +0 -425
- webscout/Provider/freeaichat.py +0 -285
- webscout/Provider/granite.py +0 -235
- webscout/Provider/hermes.py +0 -266
- webscout/Provider/koala.py +0 -170
- webscout/Provider/lmarena.py +0 -198
- webscout/Provider/multichat.py +0 -364
- webscout/Provider/scira_chat.py +0 -299
- webscout/Provider/scnet.py +0 -243
- webscout/Provider/talkai.py +0 -194
- webscout/Provider/typegpt.py +0 -289
- webscout/Provider/uncovr.py +0 -368
- webscout/Provider/yep.py +0 -389
- webscout/litagent/Readme.md +0 -276
- webscout/litprinter/__init__.py +0 -59
- webscout/swiftcli/Readme.md +0 -323
- webscout/tempid.py +0 -128
- webscout/webscout_search.py +0 -1184
- webscout/webscout_search_async.py +0 -654
- webscout/yep_search.py +0 -347
- webscout/zeroart/README.md +0 -89
- webscout-8.2.9.dist-info/METADATA +0 -1033
- webscout-8.2.9.dist-info/RECORD +0 -289
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import random
|
|
3
|
+
from typing import Any, Dict, Optional, Union, cast
|
|
4
|
+
|
|
5
|
+
import requests
|
|
6
|
+
from requests.adapters import HTTPAdapter
|
|
7
|
+
from urllib3.util.retry import Retry
|
|
8
|
+
|
|
9
|
+
from webscout.AIbase import SimpleModelList
|
|
10
|
+
from webscout.litagent import LitAgent
|
|
11
|
+
from webscout.Provider.TTI.base import BaseImages, TTICompatibleProvider
|
|
12
|
+
from webscout.Provider.TTI.utils import ImageData, ImageResponse
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Images(BaseImages):
|
|
16
|
+
def __init__(self, client):
|
|
17
|
+
self._client = client
|
|
18
|
+
self.base_url = "https://api.together.xyz/v1"
|
|
19
|
+
# Create a session - it will automatically get proxies from the global monkey patch!
|
|
20
|
+
self.session = requests.Session()
|
|
21
|
+
self._setup_session_with_retries()
|
|
22
|
+
|
|
23
|
+
def _setup_session_with_retries(self):
|
|
24
|
+
"""Setup session with retry strategy and timeout configurations"""
|
|
25
|
+
# Configure retry strategy
|
|
26
|
+
retry_strategy = Retry(
|
|
27
|
+
total=3,
|
|
28
|
+
status_forcelist=[429, 500, 502, 503, 504],
|
|
29
|
+
backoff_factor=1,
|
|
30
|
+
allowed_methods=["HEAD", "GET", "OPTIONS", "POST"],
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
adapter = HTTPAdapter(max_retries=retry_strategy)
|
|
34
|
+
self.session.mount("http://", adapter)
|
|
35
|
+
self.session.mount("https://", adapter)
|
|
36
|
+
|
|
37
|
+
def build_headers(self, extra: Optional[Dict[str, str]] = None) -> Dict[str, str]:
|
|
38
|
+
"""Build headers with API authorization using consistent fingerprint"""
|
|
39
|
+
api_key = self._client.api_key
|
|
40
|
+
|
|
41
|
+
# Reuse or generate fingerprint once for the session
|
|
42
|
+
if not hasattr(self._client, "_fingerprint") or self._client._fingerprint is None:
|
|
43
|
+
self._client._fingerprint = self._generate_consistent_fingerprint()
|
|
44
|
+
|
|
45
|
+
fp = self._client._fingerprint
|
|
46
|
+
headers = {
|
|
47
|
+
"Authorization": f"Bearer {api_key}",
|
|
48
|
+
"Content-Type": "application/json",
|
|
49
|
+
"Accept": "application/json",
|
|
50
|
+
"Accept-Language": fp["accept_language"],
|
|
51
|
+
"User-Agent": fp["user_agent"],
|
|
52
|
+
"Sec-CH-UA": fp["sec_ch_ua"],
|
|
53
|
+
"Sec-CH-UA-Mobile": "?0",
|
|
54
|
+
"Sec-CH-UA-Platform": f'"{fp["platform"]}"',
|
|
55
|
+
"Origin": "https://api.together.xyz",
|
|
56
|
+
"Referer": "https://api.together.xyz/",
|
|
57
|
+
"Sec-Fetch-Dest": "empty",
|
|
58
|
+
"Sec-Fetch-Mode": "cors",
|
|
59
|
+
"Sec-Fetch-Site": "cross-site",
|
|
60
|
+
}
|
|
61
|
+
if extra:
|
|
62
|
+
headers.update(extra)
|
|
63
|
+
return headers
|
|
64
|
+
|
|
65
|
+
def _generate_consistent_fingerprint(self) -> Dict[str, str]:
|
|
66
|
+
"""
|
|
67
|
+
Generate a consistent browser fingerprint using the client's LitAgent.
|
|
68
|
+
"""
|
|
69
|
+
from webscout.litagent.constants import BROWSERS, FINGERPRINTS
|
|
70
|
+
|
|
71
|
+
agent = self._client._agent
|
|
72
|
+
user_agent = agent.browser("chrome")
|
|
73
|
+
|
|
74
|
+
accept_language = random.choice(FINGERPRINTS["accept_language"])
|
|
75
|
+
accept = random.choice(FINGERPRINTS["accept"])
|
|
76
|
+
platform = random.choice(FINGERPRINTS["platforms"])
|
|
77
|
+
|
|
78
|
+
# Generate sec-ch-ua for chrome
|
|
79
|
+
version = random.randint(*BROWSERS["chrome"])
|
|
80
|
+
sec_ch_ua_dict = cast(Dict[str, str], FINGERPRINTS["sec_ch_ua"])
|
|
81
|
+
sec_ch_ua = sec_ch_ua_dict["chrome"].format(version, version)
|
|
82
|
+
|
|
83
|
+
# Use the client's agent for consistent IP rotation
|
|
84
|
+
ip = agent.rotate_ip()
|
|
85
|
+
fingerprint = {
|
|
86
|
+
"user_agent": user_agent,
|
|
87
|
+
"accept_language": accept_language,
|
|
88
|
+
"accept": accept,
|
|
89
|
+
"sec_ch_ua": sec_ch_ua,
|
|
90
|
+
"platform": platform,
|
|
91
|
+
"x-forwarded-for": ip,
|
|
92
|
+
"x-real-ip": ip,
|
|
93
|
+
"x-client-ip": ip,
|
|
94
|
+
"forwarded": f"for={ip};proto=https",
|
|
95
|
+
"x-forwarded-proto": "https",
|
|
96
|
+
"x-request-id": agent.random_id(8)
|
|
97
|
+
if hasattr(agent, "random_id")
|
|
98
|
+
else "".join(random.choices("0123456789abcdef", k=8)),
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return fingerprint
|
|
102
|
+
|
|
103
|
+
def create(
|
|
104
|
+
self,
|
|
105
|
+
*,
|
|
106
|
+
model: str,
|
|
107
|
+
prompt: str,
|
|
108
|
+
n: int = 1,
|
|
109
|
+
size: str = "1024x1024",
|
|
110
|
+
response_format: str = "url",
|
|
111
|
+
user: Optional[str] = None,
|
|
112
|
+
style: str = "none",
|
|
113
|
+
aspect_ratio: str = "1:1",
|
|
114
|
+
timeout: Optional[int] = None,
|
|
115
|
+
image_format: str = "png",
|
|
116
|
+
seed: Optional[int] = None,
|
|
117
|
+
convert_format: bool = False,
|
|
118
|
+
enhance: bool = True,
|
|
119
|
+
steps: int = 20,
|
|
120
|
+
**kwargs,
|
|
121
|
+
) -> ImageResponse:
|
|
122
|
+
"""
|
|
123
|
+
Create images using Together.xyz image models
|
|
124
|
+
"""
|
|
125
|
+
if not prompt:
|
|
126
|
+
raise ValueError("Describe the image you want to create (use the 'prompt' property).")
|
|
127
|
+
|
|
128
|
+
if not self._client.api_key:
|
|
129
|
+
raise ValueError(
|
|
130
|
+
"API key is required for TogetherImage. Please provide it in __init__."
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Validate model
|
|
134
|
+
if model not in self._client.AVAILABLE_MODELS:
|
|
135
|
+
raise ValueError(
|
|
136
|
+
f"Model '{model}' not available. Choose from: {self._client.AVAILABLE_MODELS}"
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
# Parse size
|
|
140
|
+
if "x" in size:
|
|
141
|
+
width, height = map(int, size.split("x"))
|
|
142
|
+
else:
|
|
143
|
+
width = height = int(size)
|
|
144
|
+
|
|
145
|
+
# Build request body
|
|
146
|
+
body = {
|
|
147
|
+
"model": model,
|
|
148
|
+
"prompt": prompt,
|
|
149
|
+
"width": width,
|
|
150
|
+
"height": height,
|
|
151
|
+
# Clamp steps to 1-4 as required by Together.xyz API
|
|
152
|
+
"steps": min(max(steps, 1), 4),
|
|
153
|
+
"n": min(max(n, 1), 4), # Clamp between 1-4
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# Add optional parameters
|
|
157
|
+
if seed is not None:
|
|
158
|
+
body["seed"] = seed
|
|
159
|
+
|
|
160
|
+
# Add any additional kwargs
|
|
161
|
+
body.update(kwargs)
|
|
162
|
+
|
|
163
|
+
try:
|
|
164
|
+
resp = self.session.request(
|
|
165
|
+
"post",
|
|
166
|
+
f"{self.base_url}/images/generations",
|
|
167
|
+
json=body,
|
|
168
|
+
headers=self.build_headers(),
|
|
169
|
+
timeout=timeout,
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
data = resp.json()
|
|
173
|
+
|
|
174
|
+
# Check for errors
|
|
175
|
+
if "error" in data:
|
|
176
|
+
error_msg = data["error"].get("message", str(data["error"]))
|
|
177
|
+
raise RuntimeError(f"Together.xyz API error: {error_msg}")
|
|
178
|
+
|
|
179
|
+
if not data.get("data") or len(data["data"]) == 0:
|
|
180
|
+
raise RuntimeError("Failed to process image. No data found.")
|
|
181
|
+
|
|
182
|
+
result = data["data"]
|
|
183
|
+
result_data = []
|
|
184
|
+
|
|
185
|
+
for i, item in enumerate(result):
|
|
186
|
+
if response_format == "url":
|
|
187
|
+
if "url" in item:
|
|
188
|
+
result_data.append(ImageData(url=item["url"]))
|
|
189
|
+
else: # b64_json
|
|
190
|
+
if "b64_json" in item:
|
|
191
|
+
result_data.append(ImageData(b64_json=item["b64_json"]))
|
|
192
|
+
|
|
193
|
+
if not result_data:
|
|
194
|
+
raise RuntimeError("No valid image data found in response")
|
|
195
|
+
|
|
196
|
+
return ImageResponse(data=result_data)
|
|
197
|
+
|
|
198
|
+
except requests.exceptions.Timeout:
|
|
199
|
+
raise RuntimeError(
|
|
200
|
+
f"Request timed out after {timeout} seconds. Try reducing image size or steps."
|
|
201
|
+
)
|
|
202
|
+
except requests.exceptions.RequestException as e:
|
|
203
|
+
if hasattr(e, "response") and e.response is not None:
|
|
204
|
+
try:
|
|
205
|
+
print("[Together.xyz API error details]", e.response.text)
|
|
206
|
+
except Exception:
|
|
207
|
+
pass
|
|
208
|
+
raise RuntimeError(f"Network error: {str(e)}")
|
|
209
|
+
except json.JSONDecodeError:
|
|
210
|
+
raise RuntimeError("Invalid JSON response from Together.xyz API")
|
|
211
|
+
except Exception as e:
|
|
212
|
+
raise RuntimeError(f"An error occurred: {str(e)}")
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class TogetherImage(TTICompatibleProvider):
|
|
216
|
+
"""
|
|
217
|
+
Together.xyz Text-to-Image provider
|
|
218
|
+
Updated: 2025-12-19 12:10:00 UTC
|
|
219
|
+
Supports FLUX and other image generation models via Together.xyz API
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
# Provider status
|
|
223
|
+
required_auth: bool = True # Now requires user-provided API key
|
|
224
|
+
working: bool = True # Working as of 2025-12-19
|
|
225
|
+
|
|
226
|
+
# Image models from Together.xyz API (filtered for image type only)
|
|
227
|
+
AVAILABLE_MODELS = []
|
|
228
|
+
|
|
229
|
+
@classmethod
|
|
230
|
+
def get_models(cls, api_key: Optional[str] = None):
|
|
231
|
+
"""Fetch available image models from Together API."""
|
|
232
|
+
if not api_key:
|
|
233
|
+
# Return default models if no API key is provided
|
|
234
|
+
return [
|
|
235
|
+
"black-forest-labs/FLUX.1-canny",
|
|
236
|
+
"black-forest-labs/FLUX.1-depth",
|
|
237
|
+
"black-forest-labs/FLUX.1-dev",
|
|
238
|
+
"black-forest-labs/FLUX.1-dev-lora",
|
|
239
|
+
"black-forest-labs/FLUX.1-kontext-dev",
|
|
240
|
+
"black-forest-labs/FLUX.1-kontext-max",
|
|
241
|
+
"black-forest-labs/FLUX.1-kontext-pro",
|
|
242
|
+
"black-forest-labs/FLUX.1-krea-dev",
|
|
243
|
+
"black-forest-labs/FLUX.1-pro",
|
|
244
|
+
"black-forest-labs/FLUX.1-redux",
|
|
245
|
+
"black-forest-labs/FLUX.1-schnell",
|
|
246
|
+
"black-forest-labs/FLUX.1-schnell-Free",
|
|
247
|
+
"black-forest-labs/FLUX.1.1-pro",
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
headers = {"Authorization": f"Bearer {api_key}", "Accept": "application/json"}
|
|
252
|
+
|
|
253
|
+
response = requests.get(
|
|
254
|
+
"https://api.together.xyz/v1/models", headers=headers, timeout=30
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
if response.status_code != 200:
|
|
258
|
+
return cls.get_models(None)
|
|
259
|
+
|
|
260
|
+
models_data = response.json()
|
|
261
|
+
|
|
262
|
+
# Filter image models
|
|
263
|
+
image_models = []
|
|
264
|
+
if isinstance(models_data, list):
|
|
265
|
+
for model in models_data:
|
|
266
|
+
if isinstance(model, dict) and model.get("type", "").lower() == "image":
|
|
267
|
+
image_models.append(model["id"])
|
|
268
|
+
|
|
269
|
+
if image_models:
|
|
270
|
+
return sorted(image_models)
|
|
271
|
+
else:
|
|
272
|
+
return cls.get_models(None)
|
|
273
|
+
|
|
274
|
+
except Exception:
|
|
275
|
+
return cls.get_models(None)
|
|
276
|
+
|
|
277
|
+
@classmethod
|
|
278
|
+
def update_available_models(cls, api_key: Optional[str] = None):
|
|
279
|
+
"""Update the available models list from Together API"""
|
|
280
|
+
try:
|
|
281
|
+
models = cls.get_models(api_key)
|
|
282
|
+
if models and len(models) > 0:
|
|
283
|
+
cls.AVAILABLE_MODELS = models
|
|
284
|
+
except Exception:
|
|
285
|
+
cls.AVAILABLE_MODELS = cls.get_models(None)
|
|
286
|
+
|
|
287
|
+
def __init__(self, api_key: Optional[str] = None):
|
|
288
|
+
"""
|
|
289
|
+
Initialize the TogetherImage client.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
api_key (str, optional): Together.xyz API key.
|
|
293
|
+
"""
|
|
294
|
+
self.api_key = api_key
|
|
295
|
+
# Update available models if API key is provided
|
|
296
|
+
if api_key:
|
|
297
|
+
self.update_available_models(api_key)
|
|
298
|
+
else:
|
|
299
|
+
self.AVAILABLE_MODELS = self.get_models(None)
|
|
300
|
+
|
|
301
|
+
self.images = Images(self)
|
|
302
|
+
# Initialize LitAgent for consistent fingerprints across image generation requests
|
|
303
|
+
self._agent = LitAgent()
|
|
304
|
+
self._fingerprint = None
|
|
305
|
+
|
|
306
|
+
@property
|
|
307
|
+
def models(self) -> SimpleModelList:
|
|
308
|
+
return SimpleModelList(type(self).AVAILABLE_MODELS)
|
|
309
|
+
|
|
310
|
+
def convert_model_name(self, model: str) -> str:
|
|
311
|
+
"""Convert model alias to full model name"""
|
|
312
|
+
if model in self.AVAILABLE_MODELS:
|
|
313
|
+
return model
|
|
314
|
+
|
|
315
|
+
# Default to first available model
|
|
316
|
+
return self.AVAILABLE_MODELS[0]
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
if __name__ == "__main__":
|
|
320
|
+
from rich import print
|
|
321
|
+
|
|
322
|
+
client = TogetherImage(api_key="YOUR_API_KEY")
|
|
323
|
+
|
|
324
|
+
# Test with a sample prompt - now requires model and prompt as keyword args
|
|
325
|
+
response = client.images.create(
|
|
326
|
+
model="black-forest-labs/FLUX.1-schnell-Free", # Free FLUX model
|
|
327
|
+
prompt="A majestic dragon flying over a mystical forest, fantasy art, highly detailed",
|
|
328
|
+
size="1024x1024",
|
|
329
|
+
n=1,
|
|
330
|
+
steps=25,
|
|
331
|
+
response_format="url",
|
|
332
|
+
timeout=120,
|
|
333
|
+
)
|
|
334
|
+
print(response)
|
webscout/Provider/TTI/utils.py
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import time
|
|
2
|
+
from typing import List, Optional, Union, cast
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ImageData(BaseModel):
|
|
8
|
+
url: Optional[str] = None
|
|
9
|
+
b64_json: Optional[str] = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ImageResponse(BaseModel):
|
|
13
|
+
created: int = Field(default_factory=lambda: int(time.time()))
|
|
14
|
+
data: List[ImageData]
|