webscout 8.2.2__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 -143
- webscout/AIbase.py +247 -123
- webscout/AIutel.py +68 -132
- webscout/Bard.py +1072 -535
- webscout/Extra/GitToolkit/__init__.py +2 -2
- 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 -0
- 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 -0
- 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 -45
- 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 +189 -18
- webscout/Extra/__init__.py +2 -3
- webscout/Extra/gguf.py +1298 -682
- webscout/Extra/tempmail/README.md +488 -0
- 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 +237 -304
- webscout/Provider/AISEARCH/README.md +106 -0
- webscout/Provider/AISEARCH/__init__.py +16 -10
- webscout/Provider/AISEARCH/brave_search.py +298 -0
- webscout/Provider/AISEARCH/iask_search.py +130 -209
- webscout/Provider/AISEARCH/monica_search.py +200 -246
- webscout/Provider/AISEARCH/webpilotai_search.py +242 -281
- 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 -0
- webscout/Provider/ClaudeOnline.py +365 -0
- webscout/Provider/Cohere.py +232 -208
- webscout/Provider/DeepAI.py +367 -0
- webscout/Provider/Deepinfra.py +343 -173
- webscout/Provider/EssentialAI.py +217 -0
- webscout/Provider/ExaAI.py +274 -261
- webscout/Provider/Gemini.py +60 -54
- webscout/Provider/GithubChat.py +385 -367
- webscout/Provider/Gradient.py +286 -0
- webscout/Provider/Groq.py +556 -670
- webscout/Provider/HadadXYZ.py +323 -0
- webscout/Provider/HeckAI.py +392 -233
- webscout/Provider/HuggingFace.py +387 -0
- webscout/Provider/IBM.py +340 -0
- webscout/Provider/Jadve.py +317 -266
- webscout/Provider/K2Think.py +306 -0
- webscout/Provider/Koboldai.py +221 -381
- webscout/Provider/Netwrck.py +273 -228
- 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 -0
- webscout/Provider/OPENAI/TogetherAI.py +405 -0
- webscout/Provider/OPENAI/TwoAI.py +255 -0
- webscout/Provider/OPENAI/__init__.py +148 -25
- webscout/Provider/OPENAI/ai4chat.py +348 -0
- webscout/Provider/OPENAI/akashgpt.py +436 -0
- webscout/Provider/OPENAI/algion.py +303 -0
- webscout/Provider/OPENAI/ayle.py +365 -0
- webscout/Provider/OPENAI/base.py +253 -46
- webscout/Provider/OPENAI/cerebras.py +296 -0
- webscout/Provider/OPENAI/chatgpt.py +514 -193
- webscout/Provider/OPENAI/chatsandbox.py +233 -0
- webscout/Provider/OPENAI/deepinfra.py +403 -272
- webscout/Provider/OPENAI/e2b.py +2370 -1350
- webscout/Provider/OPENAI/elmo.py +278 -0
- webscout/Provider/OPENAI/exaai.py +186 -138
- webscout/Provider/OPENAI/freeassist.py +446 -0
- webscout/Provider/OPENAI/gradient.py +448 -0
- webscout/Provider/OPENAI/groq.py +380 -0
- webscout/Provider/OPENAI/hadadxyz.py +292 -0
- webscout/Provider/OPENAI/heckai.py +100 -104
- 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 -327
- webscout/Provider/OPENAI/meta.py +541 -0
- webscout/Provider/OPENAI/netwrck.py +110 -84
- webscout/Provider/OPENAI/nvidia.py +317 -0
- webscout/Provider/OPENAI/oivscode.py +348 -0
- webscout/Provider/OPENAI/openrouter.py +328 -0
- webscout/Provider/OPENAI/pydantic_imports.py +1 -0
- webscout/Provider/OPENAI/sambanova.py +397 -0
- webscout/Provider/OPENAI/sonus.py +126 -115
- webscout/Provider/OPENAI/textpollinations.py +218 -133
- webscout/Provider/OPENAI/toolbaz.py +136 -166
- webscout/Provider/OPENAI/typefully.py +419 -0
- webscout/Provider/OPENAI/typliai.py +279 -0
- webscout/Provider/OPENAI/utils.py +314 -211
- webscout/Provider/OPENAI/wisecat.py +103 -125
- webscout/Provider/OPENAI/writecream.py +185 -156
- webscout/Provider/OPENAI/x0gpt.py +227 -136
- webscout/Provider/OPENAI/zenmux.py +380 -0
- webscout/Provider/OpenRouter.py +386 -0
- webscout/Provider/Openai.py +337 -496
- webscout/Provider/PI.py +443 -344
- 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 -0
- webscout/Provider/TTI/__init__.py +37 -12
- webscout/Provider/TTI/base.py +147 -0
- webscout/Provider/TTI/claudeonline.py +393 -0
- webscout/Provider/TTI/magicstudio.py +292 -0
- webscout/Provider/TTI/miragic.py +180 -0
- webscout/Provider/TTI/pollinations.py +331 -0
- webscout/Provider/TTI/together.py +334 -0
- webscout/Provider/TTI/utils.py +14 -0
- webscout/Provider/TTS/README.md +186 -0
- webscout/Provider/TTS/__init__.py +43 -7
- webscout/Provider/TTS/base.py +523 -0
- 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 -0
- 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 -180
- webscout/Provider/TTS/streamElements.py +275 -333
- webscout/Provider/TTS/utils.py +280 -280
- webscout/Provider/TextPollinationsAI.py +221 -121
- webscout/Provider/TogetherAI.py +450 -0
- webscout/Provider/TwoAI.py +309 -199
- webscout/Provider/TypliAI.py +311 -0
- webscout/Provider/UNFINISHED/ChatHub.py +219 -0
- webscout/Provider/{OPENAI/glider.py → UNFINISHED/ChutesAI.py} +160 -145
- webscout/Provider/UNFINISHED/GizAI.py +300 -0
- webscout/Provider/UNFINISHED/Marcus.py +218 -0
- webscout/Provider/UNFINISHED/Qodo.py +481 -0
- webscout/Provider/UNFINISHED/XenAI.py +330 -0
- webscout/Provider/{Youchat.py → UNFINISHED/Youchat.py} +64 -47
- 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 -0
- webscout/Provider/UNFINISHED/samurai.py +231 -0
- webscout/Provider/WiseCat.py +256 -196
- webscout/Provider/WrDoChat.py +390 -0
- webscout/Provider/__init__.py +115 -198
- webscout/Provider/ai4chat.py +181 -202
- webscout/Provider/akashgpt.py +330 -342
- webscout/Provider/cerebras.py +397 -242
- webscout/Provider/cleeai.py +236 -213
- webscout/Provider/elmo.py +291 -234
- webscout/Provider/geminiapi.py +343 -208
- webscout/Provider/julius.py +245 -223
- webscout/Provider/learnfastai.py +333 -266
- webscout/Provider/llama3mitril.py +230 -180
- webscout/Provider/llmchat.py +308 -213
- webscout/Provider/llmchatco.py +321 -311
- webscout/Provider/meta.py +996 -794
- webscout/Provider/oivscode.py +332 -0
- webscout/Provider/searchchat.py +316 -293
- webscout/Provider/sonus.py +264 -208
- webscout/Provider/toolbaz.py +359 -320
- webscout/Provider/turboseek.py +332 -219
- webscout/Provider/typefully.py +262 -280
- webscout/Provider/x0gpt.py +332 -256
- webscout/__init__.py +31 -38
- webscout/__main__.py +5 -5
- webscout/cli.py +585 -293
- webscout/client.py +1497 -0
- webscout/conversation.py +140 -565
- webscout/exceptions.py +383 -339
- 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 +32 -378
- webscout/prompt_manager.py +376 -274
- webscout/sanitize.py +1514 -0
- webscout/scout/README.md +452 -0
- webscout/scout/__init__.py +8 -8
- webscout/scout/core/__init__.py +7 -7
- webscout/scout/core/crawler.py +330 -140
- webscout/scout/core/scout.py +800 -568
- 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 -460
- 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 -809
- webscout/swiftcli/core/__init__.py +7 -0
- webscout/swiftcli/core/cli.py +574 -0
- webscout/swiftcli/core/context.py +98 -0
- webscout/swiftcli/core/group.py +268 -0
- webscout/swiftcli/decorators/__init__.py +28 -0
- webscout/swiftcli/decorators/command.py +243 -0
- webscout/swiftcli/decorators/options.py +247 -0
- webscout/swiftcli/decorators/output.py +392 -0
- webscout/swiftcli/exceptions.py +21 -0
- webscout/swiftcli/plugins/__init__.py +9 -0
- webscout/swiftcli/plugins/base.py +134 -0
- webscout/swiftcli/plugins/manager.py +269 -0
- webscout/swiftcli/utils/__init__.py +58 -0
- webscout/swiftcli/utils/formatting.py +251 -0
- webscout/swiftcli/utils/parsing.py +368 -0
- 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 -55
- webscout/zeroart/base.py +70 -60
- webscout/zeroart/effects.py +155 -99
- webscout/zeroart/fonts.py +1799 -816
- webscout-2026.1.19.dist-info/METADATA +638 -0
- webscout-2026.1.19.dist-info/RECORD +312 -0
- {webscout-8.2.2.dist-info → webscout-2026.1.19.dist-info}/WHEEL +1 -1
- webscout-2026.1.19.dist-info/entry_points.txt +4 -0
- webscout-2026.1.19.dist-info/top_level.txt +1 -0
- inferno/__init__.py +0 -6
- inferno/__main__.py +0 -9
- inferno/cli.py +0 -6
- webscout/DWEBS.py +0 -477
- webscout/Extra/autocoder/__init__.py +0 -9
- webscout/Extra/autocoder/autocoder.py +0 -849
- webscout/Extra/autocoder/autocoder_utiles.py +0 -332
- webscout/LLM.py +0 -442
- webscout/Litlogger/__init__.py +0 -67
- webscout/Litlogger/core/__init__.py +0 -6
- webscout/Litlogger/core/level.py +0 -23
- webscout/Litlogger/core/logger.py +0 -165
- webscout/Litlogger/handlers/__init__.py +0 -12
- webscout/Litlogger/handlers/console.py +0 -33
- webscout/Litlogger/handlers/file.py +0 -143
- webscout/Litlogger/handlers/network.py +0 -173
- webscout/Litlogger/styles/__init__.py +0 -7
- webscout/Litlogger/styles/colors.py +0 -249
- webscout/Litlogger/styles/formats.py +0 -458
- webscout/Litlogger/styles/text.py +0 -87
- webscout/Litlogger/utils/__init__.py +0 -6
- webscout/Litlogger/utils/detectors.py +0 -153
- webscout/Litlogger/utils/formatters.py +0 -200
- webscout/Local/__init__.py +0 -12
- webscout/Local/__main__.py +0 -9
- webscout/Local/api.py +0 -576
- webscout/Local/cli.py +0 -516
- webscout/Local/config.py +0 -75
- webscout/Local/llm.py +0 -287
- webscout/Local/model_manager.py +0 -253
- webscout/Local/server.py +0 -721
- webscout/Local/utils.py +0 -93
- webscout/Provider/AI21.py +0 -177
- webscout/Provider/AISEARCH/DeepFind.py +0 -250
- webscout/Provider/AISEARCH/ISou.py +0 -256
- webscout/Provider/AISEARCH/felo_search.py +0 -228
- webscout/Provider/AISEARCH/genspark_search.py +0 -208
- webscout/Provider/AISEARCH/hika_search.py +0 -194
- webscout/Provider/AISEARCH/scira_search.py +0 -324
- webscout/Provider/Aitopia.py +0 -292
- webscout/Provider/AllenAI.py +0 -413
- webscout/Provider/Blackboxai.py +0 -229
- webscout/Provider/C4ai.py +0 -432
- webscout/Provider/ChatGPTClone.py +0 -226
- webscout/Provider/ChatGPTES.py +0 -237
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/Chatify.py +0 -175
- webscout/Provider/Cloudflare.py +0 -273
- webscout/Provider/DeepSeek.py +0 -196
- webscout/Provider/ElectronHub.py +0 -709
- webscout/Provider/ExaChat.py +0 -342
- webscout/Provider/Free2GPT.py +0 -241
- webscout/Provider/GPTWeb.py +0 -193
- webscout/Provider/Glider.py +0 -211
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/HuggingFaceChat.py +0 -462
- webscout/Provider/Hunyuan.py +0 -272
- webscout/Provider/LambdaChat.py +0 -392
- webscout/Provider/Llama.py +0 -200
- webscout/Provider/Llama3.py +0 -204
- webscout/Provider/Marcus.py +0 -148
- webscout/Provider/OLLAMA.py +0 -396
- webscout/Provider/OPENAI/c4ai.py +0 -367
- webscout/Provider/OPENAI/chatgptclone.py +0 -460
- webscout/Provider/OPENAI/exachat.py +0 -433
- webscout/Provider/OPENAI/freeaichat.py +0 -352
- webscout/Provider/OPENAI/opkfc.py +0 -488
- webscout/Provider/OPENAI/scirachat.py +0 -463
- webscout/Provider/OPENAI/standardinput.py +0 -425
- webscout/Provider/OPENAI/typegpt.py +0 -346
- webscout/Provider/OPENAI/uncovrAI.py +0 -455
- webscout/Provider/OPENAI/venice.py +0 -413
- webscout/Provider/OPENAI/yep.py +0 -327
- webscout/Provider/OpenGPT.py +0 -199
- webscout/Provider/Perplexitylabs.py +0 -415
- webscout/Provider/Phind.py +0 -535
- webscout/Provider/PizzaGPT.py +0 -198
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/StandardInput.py +0 -278
- webscout/Provider/TTI/AiForce/__init__.py +0 -22
- webscout/Provider/TTI/AiForce/async_aiforce.py +0 -224
- webscout/Provider/TTI/AiForce/sync_aiforce.py +0 -245
- webscout/Provider/TTI/FreeAIPlayground/__init__.py +0 -9
- webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +0 -181
- webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +0 -180
- webscout/Provider/TTI/ImgSys/__init__.py +0 -23
- webscout/Provider/TTI/ImgSys/async_imgsys.py +0 -202
- webscout/Provider/TTI/ImgSys/sync_imgsys.py +0 -195
- webscout/Provider/TTI/MagicStudio/__init__.py +0 -2
- webscout/Provider/TTI/MagicStudio/async_magicstudio.py +0 -111
- webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +0 -109
- webscout/Provider/TTI/Nexra/__init__.py +0 -22
- webscout/Provider/TTI/Nexra/async_nexra.py +0 -286
- webscout/Provider/TTI/Nexra/sync_nexra.py +0 -258
- webscout/Provider/TTI/PollinationsAI/__init__.py +0 -23
- webscout/Provider/TTI/PollinationsAI/async_pollinations.py +0 -311
- webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +0 -265
- webscout/Provider/TTI/aiarta/__init__.py +0 -2
- webscout/Provider/TTI/aiarta/async_aiarta.py +0 -482
- webscout/Provider/TTI/aiarta/sync_aiarta.py +0 -440
- webscout/Provider/TTI/artbit/__init__.py +0 -22
- webscout/Provider/TTI/artbit/async_artbit.py +0 -155
- webscout/Provider/TTI/artbit/sync_artbit.py +0 -148
- webscout/Provider/TTI/fastflux/__init__.py +0 -22
- webscout/Provider/TTI/fastflux/async_fastflux.py +0 -261
- webscout/Provider/TTI/fastflux/sync_fastflux.py +0 -252
- webscout/Provider/TTI/huggingface/__init__.py +0 -22
- webscout/Provider/TTI/huggingface/async_huggingface.py +0 -199
- webscout/Provider/TTI/huggingface/sync_huggingface.py +0 -195
- webscout/Provider/TTI/piclumen/__init__.py +0 -23
- webscout/Provider/TTI/piclumen/async_piclumen.py +0 -268
- webscout/Provider/TTI/piclumen/sync_piclumen.py +0 -233
- webscout/Provider/TTI/pixelmuse/__init__.py +0 -4
- webscout/Provider/TTI/pixelmuse/async_pixelmuse.py +0 -249
- webscout/Provider/TTI/pixelmuse/sync_pixelmuse.py +0 -182
- webscout/Provider/TTI/talkai/__init__.py +0 -4
- webscout/Provider/TTI/talkai/async_talkai.py +0 -229
- webscout/Provider/TTI/talkai/sync_talkai.py +0 -207
- webscout/Provider/TTS/gesserit.py +0 -127
- webscout/Provider/TeachAnything.py +0 -187
- webscout/Provider/Venice.py +0 -219
- webscout/Provider/VercelAI.py +0 -234
- webscout/Provider/WebSim.py +0 -228
- webscout/Provider/Writecream.py +0 -211
- webscout/Provider/WritingMate.py +0 -197
- webscout/Provider/aimathgpt.py +0 -189
- webscout/Provider/askmyai.py +0 -158
- webscout/Provider/asksteve.py +0 -203
- webscout/Provider/bagoodex.py +0 -145
- webscout/Provider/chatglm.py +0 -205
- webscout/Provider/copilot.py +0 -428
- webscout/Provider/freeaichat.py +0 -271
- webscout/Provider/gaurish.py +0 -244
- webscout/Provider/geminiprorealtime.py +0 -160
- webscout/Provider/granite.py +0 -187
- webscout/Provider/hermes.py +0 -219
- webscout/Provider/koala.py +0 -268
- webscout/Provider/labyrinth.py +0 -340
- webscout/Provider/lepton.py +0 -194
- webscout/Provider/llamatutor.py +0 -192
- webscout/Provider/multichat.py +0 -325
- webscout/Provider/promptrefine.py +0 -193
- webscout/Provider/scira_chat.py +0 -277
- webscout/Provider/scnet.py +0 -187
- webscout/Provider/talkai.py +0 -194
- webscout/Provider/tutorai.py +0 -252
- webscout/Provider/typegpt.py +0 -232
- webscout/Provider/uncovr.py +0 -312
- webscout/Provider/yep.py +0 -376
- webscout/litprinter/__init__.py +0 -59
- webscout/scout/core.py +0 -881
- webscout/tempid.py +0 -128
- webscout/webscout_search.py +0 -1346
- webscout/webscout_search_async.py +0 -877
- webscout/yep_search.py +0 -297
- webscout-8.2.2.dist-info/METADATA +0 -734
- webscout-8.2.2.dist-info/RECORD +0 -309
- webscout-8.2.2.dist-info/entry_points.txt +0 -5
- webscout-8.2.2.dist-info/top_level.txt +0 -3
- webstoken/__init__.py +0 -30
- webstoken/classifier.py +0 -189
- webstoken/keywords.py +0 -216
- webstoken/language.py +0 -128
- webstoken/ner.py +0 -164
- webstoken/normalizer.py +0 -35
- webstoken/processor.py +0 -77
- webstoken/sentiment.py +0 -206
- webstoken/stemmer.py +0 -73
- webstoken/tagger.py +0 -60
- webstoken/tokenizer.py +0 -158
- {webscout-8.2.2.dist-info → webscout-2026.1.19.dist-info/licenses}/LICENSE.md +0 -0
|
@@ -1,482 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
AsyncAIArtaImager - Your go-to async provider for generating fire images with AI Arta! ⚡
|
|
3
|
-
|
|
4
|
-
Examples:
|
|
5
|
-
>>> from webscout import AsyncAIArtaImager
|
|
6
|
-
>>> import asyncio
|
|
7
|
-
>>>
|
|
8
|
-
>>> async def example():
|
|
9
|
-
... # Initialize with logging
|
|
10
|
-
... provider = AsyncAIArtaImager(logging=True)
|
|
11
|
-
...
|
|
12
|
-
... # Generate a single image
|
|
13
|
-
... images = await provider.generate("A beautiful sunset over mountains")
|
|
14
|
-
... paths = await provider.save(images)
|
|
15
|
-
...
|
|
16
|
-
... # Generate multiple images with parameters
|
|
17
|
-
... images = await provider.generate(
|
|
18
|
-
... prompt="Epic dragon in cyberpunk city",
|
|
19
|
-
... amount=2,
|
|
20
|
-
... model="fantasy_art",
|
|
21
|
-
... negative_prompt="ugly, deformed",
|
|
22
|
-
... guidance_scale=7,
|
|
23
|
-
... num_inference_steps=30
|
|
24
|
-
... )
|
|
25
|
-
... paths = await provider.save(images, name="dragon", dir="outputs")
|
|
26
|
-
>>>
|
|
27
|
-
>>> # Run the example
|
|
28
|
-
>>> asyncio.run(example())
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
import aiohttp
|
|
32
|
-
import asyncio
|
|
33
|
-
import json
|
|
34
|
-
import os
|
|
35
|
-
import time
|
|
36
|
-
from pathlib import Path
|
|
37
|
-
from typing import List, Optional, Union, Dict, Any, AsyncGenerator
|
|
38
|
-
import aiofiles
|
|
39
|
-
|
|
40
|
-
from webscout.AIbase import AsyncImageProvider
|
|
41
|
-
from webscout.litagent import LitAgent
|
|
42
|
-
|
|
43
|
-
class AsyncAIArtaImager(AsyncImageProvider):
|
|
44
|
-
"""Your go-to async provider for generating fire images with AI Arta! ⚡
|
|
45
|
-
|
|
46
|
-
Examples:
|
|
47
|
-
>>> provider = AsyncAIArtaImager()
|
|
48
|
-
>>> async def example():
|
|
49
|
-
... # Basic usage
|
|
50
|
-
... images = await provider.generate("Cool art")
|
|
51
|
-
... paths = await provider.save(images)
|
|
52
|
-
>>>
|
|
53
|
-
>>> # Advanced usage
|
|
54
|
-
>>> provider = AsyncAIArtaImager(timeout=120)
|
|
55
|
-
>>> async def example():
|
|
56
|
-
... images = await provider.generate(
|
|
57
|
-
... prompt="Epic dragon",
|
|
58
|
-
... amount=2,
|
|
59
|
-
... model="fantasy_art",
|
|
60
|
-
... negative_prompt="ugly, deformed"
|
|
61
|
-
... )
|
|
62
|
-
... paths = await provider.save(images, name="dragon", dir="my_art")
|
|
63
|
-
"""
|
|
64
|
-
|
|
65
|
-
# API endpoints
|
|
66
|
-
url = "https://img-gen-prod.ai-arta.com"
|
|
67
|
-
auth_url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/signupNewUser?key=AIzaSyB3-71wG0fIt0shj0ee4fvx1shcjJHGrrQ"
|
|
68
|
-
token_refresh_url = "https://securetoken.googleapis.com/v1/token?key=AIzaSyB3-71wG0fIt0shj0ee4fvx1shcjJHGrrQ"
|
|
69
|
-
image_generation_url = "https://img-gen-prod.ai-arta.com/api/v1/text2image"
|
|
70
|
-
status_check_url = "https://img-gen-prod.ai-arta.com/api/v1/text2image/{record_id}/status"
|
|
71
|
-
|
|
72
|
-
# Available models
|
|
73
|
-
AVAILABLE_MODELS = {
|
|
74
|
-
"flux": "Flux",
|
|
75
|
-
"medieval": "Medieval",
|
|
76
|
-
"vincent_van_gogh": "Vincent Van Gogh",
|
|
77
|
-
"f_dev": "F Dev",
|
|
78
|
-
"low_poly": "Low Poly",
|
|
79
|
-
"dreamshaper_xl": "Dreamshaper-xl",
|
|
80
|
-
"anima_pencil_xl": "Anima-pencil-xl",
|
|
81
|
-
"biomech": "Biomech",
|
|
82
|
-
"trash_polka": "Trash Polka",
|
|
83
|
-
"no_style": "No Style",
|
|
84
|
-
"cheyenne_xl": "Cheyenne-xl",
|
|
85
|
-
"chicano": "Chicano",
|
|
86
|
-
"embroidery_tattoo": "Embroidery tattoo",
|
|
87
|
-
"red_and_black": "Red and Black",
|
|
88
|
-
"fantasy_art": "Fantasy Art",
|
|
89
|
-
"watercolor": "Watercolor",
|
|
90
|
-
"dotwork": "Dotwork",
|
|
91
|
-
"old_school_colored": "Old school colored",
|
|
92
|
-
"realistic_tattoo": "Realistic tattoo",
|
|
93
|
-
"japanese_2": "Japanese_2",
|
|
94
|
-
"realistic_stock_xl": "Realistic-stock-xl",
|
|
95
|
-
"f_pro": "F Pro",
|
|
96
|
-
"revanimated": "RevAnimated",
|
|
97
|
-
"katayama_mix_xl": "Katayama-mix-xl",
|
|
98
|
-
"sdxl_l": "SDXL L",
|
|
99
|
-
"cor_epica_xl": "Cor-epica-xl",
|
|
100
|
-
"anime_tattoo": "Anime tattoo",
|
|
101
|
-
"new_school": "New School",
|
|
102
|
-
"death_metal": "Death metal",
|
|
103
|
-
"old_school": "Old School",
|
|
104
|
-
"juggernaut_xl": "Juggernaut-xl",
|
|
105
|
-
"photographic": "Photographic",
|
|
106
|
-
"sdxl_1_0": "SDXL 1.0",
|
|
107
|
-
"graffiti": "Graffiti",
|
|
108
|
-
"mini_tattoo": "Mini tattoo",
|
|
109
|
-
"surrealism": "Surrealism",
|
|
110
|
-
"neo_traditional": "Neo-traditional",
|
|
111
|
-
"on_limbs_black": "On limbs black",
|
|
112
|
-
# "yamers_realistic_xl": "Yamers-realistic-xl",
|
|
113
|
-
# "pony_xl": "Pony-xl",
|
|
114
|
-
# "playground_xl": "Playground-xl",
|
|
115
|
-
# "anything_xl": "Anything-xl",
|
|
116
|
-
# "flame_design": "Flame design",
|
|
117
|
-
# "kawaii": "Kawaii",
|
|
118
|
-
# "cinematic_art": "Cinematic Art",
|
|
119
|
-
# "professional": "Professional",
|
|
120
|
-
# "flux_black_ink": "Flux Black Ink"
|
|
121
|
-
}
|
|
122
|
-
models = list(AVAILABLE_MODELS.keys())
|
|
123
|
-
|
|
124
|
-
def __init__(self, timeout: int = 60, proxies: dict = None, logging: bool = True):
|
|
125
|
-
"""Initialize your async AIArtaImager provider with custom settings ⚙️
|
|
126
|
-
|
|
127
|
-
Args:
|
|
128
|
-
timeout (int): HTTP request timeout in seconds (default: 60)
|
|
129
|
-
proxies (dict, optional): Proxy configuration for requests
|
|
130
|
-
logging (bool): Enable/disable logging (default: True)
|
|
131
|
-
"""
|
|
132
|
-
self.headers = {
|
|
133
|
-
"Accept": "application/json",
|
|
134
|
-
"Accept-Language": "en-US,en;q=0.5",
|
|
135
|
-
"User-Agent": LitAgent().random()
|
|
136
|
-
}
|
|
137
|
-
self.timeout = timeout
|
|
138
|
-
self.proxies = proxies
|
|
139
|
-
self.prompt: str = "AI-generated image - webscout"
|
|
140
|
-
self.image_extension: str = "png"
|
|
141
|
-
self.logging = logging
|
|
142
|
-
|
|
143
|
-
if self.logging and False: # Disabled logger
|
|
144
|
-
print("AsyncAIArtaImager initialized! Ready to create some fire art! 🚀")
|
|
145
|
-
|
|
146
|
-
async def get_auth_file(self) -> Path:
|
|
147
|
-
"""Get path to authentication file"""
|
|
148
|
-
path = Path(os.path.join(os.path.expanduser("~"), ".ai_arta_cookies"))
|
|
149
|
-
path.mkdir(exist_ok=True)
|
|
150
|
-
filename = f"auth_{self.__class__.__name__}.json"
|
|
151
|
-
return path / filename
|
|
152
|
-
|
|
153
|
-
async def create_token(self, path: Path) -> Dict[str, Any]:
|
|
154
|
-
"""Create a new authentication token"""
|
|
155
|
-
# Step 1: Generate Authentication Token
|
|
156
|
-
auth_payload = {"clientType": "CLIENT_TYPE_ANDROID"}
|
|
157
|
-
|
|
158
|
-
async with aiohttp.ClientSession(headers=self.headers) as session:
|
|
159
|
-
async with session.post(
|
|
160
|
-
self.auth_url,
|
|
161
|
-
json=auth_payload,
|
|
162
|
-
timeout=self.timeout,
|
|
163
|
-
proxy=self.proxies.get('http') if self.proxies else None
|
|
164
|
-
) as response:
|
|
165
|
-
response.raise_for_status()
|
|
166
|
-
auth_data = await response.json()
|
|
167
|
-
|
|
168
|
-
auth_token = auth_data.get("idToken")
|
|
169
|
-
|
|
170
|
-
if not auth_token:
|
|
171
|
-
if self.logging:
|
|
172
|
-
print("Failed to obtain authentication token 😢")
|
|
173
|
-
raise Exception("Failed to obtain authentication token.")
|
|
174
|
-
|
|
175
|
-
async with aiofiles.open(path, 'w') as f:
|
|
176
|
-
await f.write(json.dumps(auth_data))
|
|
177
|
-
|
|
178
|
-
return auth_data
|
|
179
|
-
|
|
180
|
-
async def refresh_token(self, refresh_token: str) -> tuple[str, str]:
|
|
181
|
-
"""Refresh authentication token"""
|
|
182
|
-
payload = {
|
|
183
|
-
"grant_type": "refresh_token",
|
|
184
|
-
"refresh_token": refresh_token,
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
async with aiohttp.ClientSession(headers=self.headers) as session:
|
|
188
|
-
async with session.post(
|
|
189
|
-
self.token_refresh_url,
|
|
190
|
-
data=payload,
|
|
191
|
-
timeout=self.timeout,
|
|
192
|
-
proxy=self.proxies.get('http') if self.proxies else None
|
|
193
|
-
) as response:
|
|
194
|
-
response.raise_for_status()
|
|
195
|
-
response_data = await response.json()
|
|
196
|
-
|
|
197
|
-
return response_data.get("id_token"), response_data.get("refresh_token")
|
|
198
|
-
|
|
199
|
-
async def read_and_refresh_token(self) -> Dict[str, Any]:
|
|
200
|
-
"""Read token from file and refresh if needed"""
|
|
201
|
-
path = await self.get_auth_file()
|
|
202
|
-
|
|
203
|
-
if path.is_file():
|
|
204
|
-
async with aiofiles.open(path, 'r') as f:
|
|
205
|
-
auth_data = json.loads(await f.read())
|
|
206
|
-
|
|
207
|
-
diff = time.time() - os.path.getmtime(path)
|
|
208
|
-
expires_in = int(auth_data.get("expiresIn"))
|
|
209
|
-
|
|
210
|
-
if diff < expires_in:
|
|
211
|
-
if diff > expires_in / 2:
|
|
212
|
-
# Refresh token if it's older than half its lifetime
|
|
213
|
-
if self.logging:
|
|
214
|
-
print("Refreshing authentication token... 🔄")
|
|
215
|
-
auth_data["idToken"], auth_data["refreshToken"] = await self.refresh_token(
|
|
216
|
-
auth_data.get("refreshToken")
|
|
217
|
-
)
|
|
218
|
-
async with aiofiles.open(path, 'w') as f:
|
|
219
|
-
await f.write(json.dumps(auth_data))
|
|
220
|
-
return auth_data
|
|
221
|
-
|
|
222
|
-
# Create new token if file doesn't exist or token expired
|
|
223
|
-
if self.logging:
|
|
224
|
-
print("Creating new authentication token... 🔑")
|
|
225
|
-
return await self.create_token(path)
|
|
226
|
-
|
|
227
|
-
def get_model(self, model_name: str) -> str:
|
|
228
|
-
"""Get actual model name from alias"""
|
|
229
|
-
if model_name.lower() in self.AVAILABLE_MODELS:
|
|
230
|
-
return self.AVAILABLE_MODELS[model_name.lower()]
|
|
231
|
-
return model_name
|
|
232
|
-
|
|
233
|
-
async def generate(
|
|
234
|
-
self,
|
|
235
|
-
prompt: str,
|
|
236
|
-
amount: int = 1,
|
|
237
|
-
model: str = "Flux",
|
|
238
|
-
negative_prompt: str = "blurry, deformed hands, ugly",
|
|
239
|
-
guidance_scale: int = 7,
|
|
240
|
-
num_inference_steps: int = 30,
|
|
241
|
-
aspect_ratio: str = "1:1",
|
|
242
|
-
max_retries: int = 3,
|
|
243
|
-
retry_delay: int = 5,
|
|
244
|
-
**kwargs
|
|
245
|
-
) -> List[bytes]:
|
|
246
|
-
"""Generate some fire images from your prompt asynchronously! ⚡
|
|
247
|
-
|
|
248
|
-
Examples:
|
|
249
|
-
>>> provider = AsyncAIArtaImager()
|
|
250
|
-
>>> async def example():
|
|
251
|
-
... # Basic usage
|
|
252
|
-
... images = await provider.generate("Cool art")
|
|
253
|
-
... # Advanced usage
|
|
254
|
-
... images = await provider.generate(
|
|
255
|
-
... prompt="Epic dragon",
|
|
256
|
-
... amount=2,
|
|
257
|
-
... model="fantasy_art",
|
|
258
|
-
... negative_prompt="ugly, deformed"
|
|
259
|
-
... )
|
|
260
|
-
|
|
261
|
-
Args:
|
|
262
|
-
prompt (str): Your image description
|
|
263
|
-
amount (int): How many images you want (default: 1)
|
|
264
|
-
model (str): Model to use - check AVAILABLE_MODELS (default: "flux")
|
|
265
|
-
negative_prompt (str): What you don't want in the image
|
|
266
|
-
guidance_scale (int): Controls how closely the model follows your prompt
|
|
267
|
-
num_inference_steps (int): More steps = better quality but slower
|
|
268
|
-
aspect_ratio (str): Image aspect ratio (default: "1:1")
|
|
269
|
-
max_retries (int): Max retry attempts if something fails
|
|
270
|
-
retry_delay (int): Seconds to wait between retries
|
|
271
|
-
**kwargs: Additional parameters for future compatibility
|
|
272
|
-
|
|
273
|
-
Returns:
|
|
274
|
-
List[bytes]: Your generated images
|
|
275
|
-
|
|
276
|
-
Raises:
|
|
277
|
-
ValueError: If the inputs ain't valid
|
|
278
|
-
Exception: If the API calls fail after retries
|
|
279
|
-
"""
|
|
280
|
-
if not prompt:
|
|
281
|
-
raise ValueError("Yo fam, the prompt can't be empty! 🤔")
|
|
282
|
-
if not isinstance(amount, int) or amount < 1:
|
|
283
|
-
raise ValueError("Amount needs to be a positive number! 📈")
|
|
284
|
-
|
|
285
|
-
model_name = self.get_model(model)
|
|
286
|
-
self.prompt = prompt
|
|
287
|
-
response = []
|
|
288
|
-
|
|
289
|
-
if self.logging:
|
|
290
|
-
print(f"Generating {amount} images with {model_name}... 🎨")
|
|
291
|
-
|
|
292
|
-
# Step 1: Get Authentication Token
|
|
293
|
-
auth_data = await self.read_and_refresh_token()
|
|
294
|
-
|
|
295
|
-
# Headers for generation requests
|
|
296
|
-
gen_headers = {
|
|
297
|
-
"Authorization": auth_data.get("idToken"),
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
async with aiohttp.ClientSession(headers={**self.headers, **gen_headers}) as session:
|
|
301
|
-
for i in range(amount):
|
|
302
|
-
# Step 2: Generate Image
|
|
303
|
-
image_payload = {
|
|
304
|
-
"prompt": prompt,
|
|
305
|
-
"negative_prompt": negative_prompt,
|
|
306
|
-
"style": model_name,
|
|
307
|
-
"images_num": "1", # Generate 1 at a time
|
|
308
|
-
"cfg_scale": str(guidance_scale),
|
|
309
|
-
"steps": str(num_inference_steps),
|
|
310
|
-
"aspect_ratio": aspect_ratio,
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
for attempt in range(max_retries):
|
|
314
|
-
try:
|
|
315
|
-
if self.logging:
|
|
316
|
-
print(f"Starting generation for image {i+1}/{amount}... ⏳")
|
|
317
|
-
|
|
318
|
-
# Submit generation request
|
|
319
|
-
async with session.post(
|
|
320
|
-
self.image_generation_url,
|
|
321
|
-
data=image_payload,
|
|
322
|
-
timeout=self.timeout,
|
|
323
|
-
proxy=self.proxies.get('http') if self.proxies else None
|
|
324
|
-
) as image_response:
|
|
325
|
-
image_response.raise_for_status()
|
|
326
|
-
image_data = await image_response.json()
|
|
327
|
-
|
|
328
|
-
record_id = image_data.get("record_id")
|
|
329
|
-
|
|
330
|
-
if not record_id:
|
|
331
|
-
if self.logging:
|
|
332
|
-
print("Failed to initiate image generation 😢")
|
|
333
|
-
raise Exception(f"Failed to initiate image generation: {image_data}")
|
|
334
|
-
|
|
335
|
-
# Step 3: Check Generation Status
|
|
336
|
-
status_url = self.status_check_url.format(record_id=record_id)
|
|
337
|
-
|
|
338
|
-
counter = 0
|
|
339
|
-
dots = [".", "..", "...", "...."]
|
|
340
|
-
|
|
341
|
-
while True:
|
|
342
|
-
async with session.get(
|
|
343
|
-
status_url,
|
|
344
|
-
timeout=self.timeout,
|
|
345
|
-
proxy=self.proxies.get('http') if self.proxies else None
|
|
346
|
-
) as status_response:
|
|
347
|
-
status_data = await status_response.json()
|
|
348
|
-
|
|
349
|
-
status = status_data.get("status")
|
|
350
|
-
|
|
351
|
-
if status == "DONE":
|
|
352
|
-
image_urls = [image["url"] for image in status_data.get("response", [])]
|
|
353
|
-
|
|
354
|
-
if not image_urls:
|
|
355
|
-
if self.logging:
|
|
356
|
-
print("No image URLs in response 😢")
|
|
357
|
-
raise Exception("No image URLs in response")
|
|
358
|
-
|
|
359
|
-
# Download the generated image
|
|
360
|
-
async with session.get(image_urls[0]) as img_response:
|
|
361
|
-
img_response.raise_for_status()
|
|
362
|
-
response.append(await img_response.read())
|
|
363
|
-
|
|
364
|
-
if self.logging:
|
|
365
|
-
print(f"Successfully generated image {i+1}/{amount}! 🎨")
|
|
366
|
-
break
|
|
367
|
-
|
|
368
|
-
elif status in ("IN_QUEUE", "IN_PROGRESS"):
|
|
369
|
-
status_text = "Waiting" if status == "IN_QUEUE" else "Generating"
|
|
370
|
-
if self.logging:
|
|
371
|
-
print(f"{status_text}{dots[counter % 4]}")
|
|
372
|
-
await asyncio.sleep(5) # Poll every 5 seconds
|
|
373
|
-
counter += 1
|
|
374
|
-
|
|
375
|
-
else:
|
|
376
|
-
if self.logging:
|
|
377
|
-
print(f"Generation failed with status: {status} 😢")
|
|
378
|
-
raise Exception(f"Image generation failed with status: {status}")
|
|
379
|
-
|
|
380
|
-
# If we got here, we successfully generated an image
|
|
381
|
-
break
|
|
382
|
-
|
|
383
|
-
except Exception as e:
|
|
384
|
-
if attempt == max_retries - 1:
|
|
385
|
-
if self.logging:
|
|
386
|
-
print(f"Failed after {max_retries} attempts: {e} 😢")
|
|
387
|
-
raise
|
|
388
|
-
else:
|
|
389
|
-
if self.logging:
|
|
390
|
-
print(f"Attempt {attempt + 1} failed. Retrying in {retry_delay} seconds... 🔄")
|
|
391
|
-
await asyncio.sleep(retry_delay)
|
|
392
|
-
|
|
393
|
-
if self.logging:
|
|
394
|
-
print(f"Successfully generated {len(response)} images! 🎉")
|
|
395
|
-
return response
|
|
396
|
-
|
|
397
|
-
async def save(
|
|
398
|
-
self,
|
|
399
|
-
response: Union[List[bytes], AsyncGenerator[bytes, None]],
|
|
400
|
-
name: Optional[str] = None,
|
|
401
|
-
dir: Optional[Union[str, Path]] = None,
|
|
402
|
-
filenames_prefix: str = "",
|
|
403
|
-
) -> List[str]:
|
|
404
|
-
"""Save your fire generated images asynchronously! 💾
|
|
405
|
-
|
|
406
|
-
Examples:
|
|
407
|
-
>>> provider = AsyncAIArtaImager()
|
|
408
|
-
>>> async def example():
|
|
409
|
-
... images = await provider.generate("Cool art")
|
|
410
|
-
... # Save with default settings
|
|
411
|
-
... paths = await provider.save(images)
|
|
412
|
-
... # Save with custom name and directory
|
|
413
|
-
... paths = await provider.save(
|
|
414
|
-
... images,
|
|
415
|
-
... name="my_art",
|
|
416
|
-
... dir="my_images",
|
|
417
|
-
... filenames_prefix="test_"
|
|
418
|
-
... )
|
|
419
|
-
|
|
420
|
-
Args:
|
|
421
|
-
response (Union[List[bytes], AsyncGenerator[bytes, None]]): Your generated images
|
|
422
|
-
name (Optional[str]): Custom name for your images
|
|
423
|
-
dir (Optional[Union[str, Path]]): Where to save the images (default: current directory)
|
|
424
|
-
filenames_prefix (str): Prefix for your image files
|
|
425
|
-
|
|
426
|
-
Returns:
|
|
427
|
-
List[str]: Paths to your saved images
|
|
428
|
-
"""
|
|
429
|
-
save_dir = dir if dir else os.getcwd()
|
|
430
|
-
if not os.path.exists(save_dir):
|
|
431
|
-
os.makedirs(save_dir)
|
|
432
|
-
if self.logging:
|
|
433
|
-
print(f"Created directory: {save_dir} 📁")
|
|
434
|
-
|
|
435
|
-
name = self.prompt if name is None else name
|
|
436
|
-
|
|
437
|
-
# Clean up name for filename use
|
|
438
|
-
safe_name = "".join(c if c.isalnum() or c in "_-" else "_" for c in name)
|
|
439
|
-
safe_name = safe_name[:50] # Truncate if too long
|
|
440
|
-
|
|
441
|
-
# Handle both List[bytes] and AsyncGenerator
|
|
442
|
-
if isinstance(response, list):
|
|
443
|
-
image_list = response
|
|
444
|
-
else:
|
|
445
|
-
image_list = [chunk async for chunk in response]
|
|
446
|
-
|
|
447
|
-
if self.logging:
|
|
448
|
-
print(f"Saving {len(image_list)} images... 💾")
|
|
449
|
-
|
|
450
|
-
saved_paths = []
|
|
451
|
-
|
|
452
|
-
async def save_single_image(image_bytes: bytes, index: int) -> str:
|
|
453
|
-
filename = f"{filenames_prefix}{safe_name}_{index}.{self.image_extension}"
|
|
454
|
-
filepath = os.path.join(save_dir, filename)
|
|
455
|
-
|
|
456
|
-
async with aiofiles.open(filepath, "wb") as f:
|
|
457
|
-
await f.write(image_bytes)
|
|
458
|
-
|
|
459
|
-
if self.logging:
|
|
460
|
-
print(f"Saved image to: {filepath} 💾")
|
|
461
|
-
return filename
|
|
462
|
-
|
|
463
|
-
tasks = [save_single_image(img, i) for i, img in enumerate(image_list)]
|
|
464
|
-
saved_paths = await asyncio.gather(*tasks)
|
|
465
|
-
|
|
466
|
-
if self.logging:
|
|
467
|
-
print(f"Images saved successfully! Check {dir} 🎉")
|
|
468
|
-
return saved_paths
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
if __name__ == "__main__":
|
|
472
|
-
# Example usage
|
|
473
|
-
async def main():
|
|
474
|
-
provider = AsyncAIArtaImager()
|
|
475
|
-
try:
|
|
476
|
-
images = await provider.generate("A beautiful sunset over mountains", amount=1)
|
|
477
|
-
paths = await provider.save(images, dir="generated_images")
|
|
478
|
-
print(f"Images saved to: {paths}")
|
|
479
|
-
except Exception as e:
|
|
480
|
-
print(f"An error occurred: {e}")
|
|
481
|
-
|
|
482
|
-
asyncio.run(main())
|