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
webscout/AIbase.py
CHANGED
|
@@ -1,123 +1,247 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
self
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Dict, Generator, List, Optional, Union
|
|
4
|
+
|
|
5
|
+
from typing_extensions import TypeAlias
|
|
6
|
+
|
|
7
|
+
# Type aliases for better readability
|
|
8
|
+
Response: TypeAlias = Union[Dict[str, Any], Generator[Any, None, None], str]
|
|
9
|
+
|
|
10
|
+
class SearchResponse:
|
|
11
|
+
"""A wrapper class for search API responses.
|
|
12
|
+
|
|
13
|
+
This class automatically converts response objects to their text representation
|
|
14
|
+
when printed or converted to string.
|
|
15
|
+
|
|
16
|
+
Attributes:
|
|
17
|
+
text (str): The text content of the response
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
>>> response = SearchResponse("Hello, world!")
|
|
21
|
+
>>> print(response)
|
|
22
|
+
Hello, world!
|
|
23
|
+
>>> str(response)
|
|
24
|
+
'Hello, world!'
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, text: str):
|
|
27
|
+
self.text = text
|
|
28
|
+
|
|
29
|
+
def __str__(self):
|
|
30
|
+
return self.text
|
|
31
|
+
|
|
32
|
+
def __repr__(self):
|
|
33
|
+
return self.text
|
|
34
|
+
|
|
35
|
+
class AIProviderError(Exception):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
class ModelList(ABC):
|
|
39
|
+
@abstractmethod
|
|
40
|
+
def list(self) -> List[str]:
|
|
41
|
+
"""Return a list of available models"""
|
|
42
|
+
raise NotImplementedError
|
|
43
|
+
|
|
44
|
+
class SimpleModelList(ModelList):
|
|
45
|
+
def __init__(self, models: List[str]):
|
|
46
|
+
self._models = models
|
|
47
|
+
def list(self) -> List[str]:
|
|
48
|
+
return self._models
|
|
49
|
+
|
|
50
|
+
class Provider(ABC):
|
|
51
|
+
required_auth: bool = False
|
|
52
|
+
conversation: Any
|
|
53
|
+
|
|
54
|
+
def __init__(self, *args, **kwargs):
|
|
55
|
+
self._last_response: Dict[str, Any] = {}
|
|
56
|
+
self.conversation = None
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def last_response(self) -> Dict[str, Any]:
|
|
60
|
+
return self._last_response
|
|
61
|
+
|
|
62
|
+
@last_response.setter
|
|
63
|
+
def last_response(self, value: Dict[str, Any]):
|
|
64
|
+
self._last_response = value
|
|
65
|
+
|
|
66
|
+
@abstractmethod
|
|
67
|
+
def ask(
|
|
68
|
+
self,
|
|
69
|
+
prompt: str,
|
|
70
|
+
stream: bool = False,
|
|
71
|
+
raw: bool = False,
|
|
72
|
+
optimizer: Optional[str] = None,
|
|
73
|
+
conversationally: bool = False,
|
|
74
|
+
**kwargs: Any,
|
|
75
|
+
) -> Response:
|
|
76
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
77
|
+
|
|
78
|
+
@abstractmethod
|
|
79
|
+
def chat(
|
|
80
|
+
self,
|
|
81
|
+
prompt: str,
|
|
82
|
+
stream: bool = False,
|
|
83
|
+
optimizer: Optional[str] = None,
|
|
84
|
+
conversationally: bool = False,
|
|
85
|
+
**kwargs: Any,
|
|
86
|
+
) -> Union[str, Generator[str, None, None]]:
|
|
87
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
88
|
+
|
|
89
|
+
@abstractmethod
|
|
90
|
+
def get_message(self, response: Response) -> str:
|
|
91
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
92
|
+
|
|
93
|
+
class TTSProvider(ABC):
|
|
94
|
+
|
|
95
|
+
@abstractmethod
|
|
96
|
+
def tts(self, text: str, voice: Optional[str] = None, verbose: bool = False, **kwargs) -> str:
|
|
97
|
+
"""Convert text to speech and save to a temporary file.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
text (str): The text to convert to speech
|
|
101
|
+
voice (str, optional): The voice to use. Defaults to provider's default voice.
|
|
102
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
str: Path to the generated audio file
|
|
106
|
+
"""
|
|
107
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
108
|
+
|
|
109
|
+
def save_audio(self, audio_file: str, destination: Optional[str] = None, verbose: bool = False) -> str:
|
|
110
|
+
"""Save audio to a specific destination.
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
audio_file (str): Path to the source audio file
|
|
114
|
+
destination (str, optional): Destination path. Defaults to current directory with timestamp.
|
|
115
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
str: Path to the saved audio file
|
|
119
|
+
"""
|
|
120
|
+
import os
|
|
121
|
+
import shutil
|
|
122
|
+
import time
|
|
123
|
+
from pathlib import Path
|
|
124
|
+
|
|
125
|
+
source_path = Path(audio_file)
|
|
126
|
+
|
|
127
|
+
if not source_path.exists():
|
|
128
|
+
raise FileNotFoundError(f"Audio file not found: {audio_file}")
|
|
129
|
+
|
|
130
|
+
if destination is None:
|
|
131
|
+
# Create a default destination with timestamp in current directory
|
|
132
|
+
timestamp = int(time.time())
|
|
133
|
+
destination = os.path.join(os.getcwd(), f"tts_audio_{timestamp}{source_path.suffix}")
|
|
134
|
+
|
|
135
|
+
# Ensure the destination directory exists
|
|
136
|
+
os.makedirs(os.path.dirname(os.path.abspath(destination)), exist_ok=True)
|
|
137
|
+
|
|
138
|
+
# Copy the file
|
|
139
|
+
shutil.copy2(source_path, destination)
|
|
140
|
+
|
|
141
|
+
if verbose:
|
|
142
|
+
print(f"[debug] Audio saved to {destination}")
|
|
143
|
+
|
|
144
|
+
return destination
|
|
145
|
+
|
|
146
|
+
def stream_audio(
|
|
147
|
+
self,
|
|
148
|
+
text: str,
|
|
149
|
+
model: Optional[str] = None,
|
|
150
|
+
voice: Optional[str] = None,
|
|
151
|
+
response_format: Optional[str] = None,
|
|
152
|
+
instructions: Optional[str] = None,
|
|
153
|
+
chunk_size: int = 1024,
|
|
154
|
+
verbose: bool = False
|
|
155
|
+
) -> Generator[bytes, None, None]:
|
|
156
|
+
"""Stream audio in chunks.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
text (str): The text to convert to speech
|
|
160
|
+
model (str, optional): The model to use.
|
|
161
|
+
voice (str, optional): The voice to use. Defaults to provider's default voice.
|
|
162
|
+
response_format (str, optional): The audio format.
|
|
163
|
+
instructions (str, optional): Voice instructions.
|
|
164
|
+
chunk_size (int, optional): Size of audio chunks to yield. Defaults to 1024.
|
|
165
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
166
|
+
|
|
167
|
+
Yields:
|
|
168
|
+
Generator[bytes, None, None]: Audio data chunks
|
|
169
|
+
"""
|
|
170
|
+
# Generate the audio file
|
|
171
|
+
audio_file = self.tts(text, voice=voice, verbose=verbose)
|
|
172
|
+
|
|
173
|
+
# Stream the file in chunks
|
|
174
|
+
with open(audio_file, 'rb') as f:
|
|
175
|
+
while chunk := f.read(chunk_size):
|
|
176
|
+
yield chunk
|
|
177
|
+
|
|
178
|
+
class STTProvider(ABC):
|
|
179
|
+
"""Abstract base class for Speech-to-Text providers."""
|
|
180
|
+
|
|
181
|
+
@abstractmethod
|
|
182
|
+
def transcribe(self, audio_path: Union[str, Path], **kwargs) -> Dict[str, Any]:
|
|
183
|
+
"""Transcribe audio file to text.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
audio_path (Union[str, Path]): Path to the audio file
|
|
187
|
+
**kwargs: Additional provider-specific parameters
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Dict[str, Any]: Transcription result in OpenAI Whisper format
|
|
191
|
+
"""
|
|
192
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
193
|
+
|
|
194
|
+
@abstractmethod
|
|
195
|
+
def transcribe_from_url(self, audio_url: str, **kwargs) -> Dict[str, Any]:
|
|
196
|
+
"""Transcribe audio from URL to text.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
audio_url (str): URL of the audio file
|
|
200
|
+
**kwargs: Additional provider-specific parameters
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Dict[str, Any]: Transcription result in OpenAI Whisper format
|
|
204
|
+
"""
|
|
205
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class AISearch(ABC):
|
|
209
|
+
"""Abstract base class for AI-powered search providers.
|
|
210
|
+
|
|
211
|
+
This class defines the interface for AI search providers that can perform
|
|
212
|
+
web searches and return AI-generated responses based on search results.
|
|
213
|
+
|
|
214
|
+
All search providers should inherit from this class and implement the
|
|
215
|
+
required methods.
|
|
216
|
+
"""
|
|
217
|
+
|
|
218
|
+
@abstractmethod
|
|
219
|
+
def search(
|
|
220
|
+
self,
|
|
221
|
+
prompt: str,
|
|
222
|
+
stream: bool = False,
|
|
223
|
+
raw: bool = False,
|
|
224
|
+
**kwargs: Any,
|
|
225
|
+
) -> Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse], None, None], List[Any], Dict[str, Any], str]:
|
|
226
|
+
"""Search using the provider's API and get AI-generated responses.
|
|
227
|
+
|
|
228
|
+
This method sends a search query to the provider and returns the AI-generated response.
|
|
229
|
+
It supports both streaming and non-streaming modes, as well as raw response format.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
prompt (str): The search query or prompt to send to the API.
|
|
233
|
+
stream (bool, optional): If True, yields response chunks as they arrive.
|
|
234
|
+
If False, returns complete response. Defaults to False.
|
|
235
|
+
raw (bool, optional): If True, returns raw response dictionaries.
|
|
236
|
+
If False, returns SearchResponse objects that convert to text automatically.
|
|
237
|
+
Defaults to False.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse], None, None]]:
|
|
241
|
+
- If stream=False: Returns complete response as SearchResponse object
|
|
242
|
+
- If stream=True: Yields response chunks as either Dict or SearchResponse objects
|
|
243
|
+
|
|
244
|
+
Raises:
|
|
245
|
+
APIConnectionError: If the API request fails
|
|
246
|
+
"""
|
|
247
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
webscout/AIutel.py
CHANGED
|
@@ -1,132 +1,68 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
):
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"""Url pointing to executable for particular system
|
|
70
|
-
|
|
71
|
-
Args:
|
|
72
|
-
system (str, optional): system name. Defaults to platform.system().
|
|
73
|
-
|
|
74
|
-
Returns:
|
|
75
|
-
str: url
|
|
76
|
-
"""
|
|
77
|
-
for entry in self.latest()["assets"]:
|
|
78
|
-
if entry.get("target") == system:
|
|
79
|
-
return entry.get("url")
|
|
80
|
-
|
|
81
|
-
def latest(self, whole: bool = False, version: bool = False) -> dict:
|
|
82
|
-
"""Check Webscout latest version info
|
|
83
|
-
|
|
84
|
-
Args:
|
|
85
|
-
whole (bool, optional): Return whole json response. Defaults to False.
|
|
86
|
-
version (bool, optional): return version only. Defaults to False.
|
|
87
|
-
|
|
88
|
-
Returns:
|
|
89
|
-
bool|dict: version str or whole dict info
|
|
90
|
-
"""
|
|
91
|
-
import requests
|
|
92
|
-
|
|
93
|
-
data = requests.get(self.url).json()
|
|
94
|
-
if whole:
|
|
95
|
-
return data
|
|
96
|
-
|
|
97
|
-
elif version:
|
|
98
|
-
return data.get("tag_name")
|
|
99
|
-
|
|
100
|
-
else:
|
|
101
|
-
sorted = dict(
|
|
102
|
-
tag_name=data.get("tag_name"),
|
|
103
|
-
tarball_url=data.get("tarball_url"),
|
|
104
|
-
zipball_url=data.get("zipball_url"),
|
|
105
|
-
html_url=data.get("html_url"),
|
|
106
|
-
body=data.get("body"),
|
|
107
|
-
)
|
|
108
|
-
whole_assets = []
|
|
109
|
-
for entry in data.get("assets"):
|
|
110
|
-
url = entry.get("browser_download_url")
|
|
111
|
-
assets = dict(url=url, size=entry.get("size"))
|
|
112
|
-
if ".deb" in url:
|
|
113
|
-
assets["target"] = "Debian"
|
|
114
|
-
elif ".exe" in url:
|
|
115
|
-
assets["target"] = "Windows"
|
|
116
|
-
elif "macos" in url:
|
|
117
|
-
assets["target"] = "Mac"
|
|
118
|
-
elif "linux" in url:
|
|
119
|
-
assets["target"] = "Linux"
|
|
120
|
-
|
|
121
|
-
whole_assets.append(assets)
|
|
122
|
-
sorted["assets"] = whole_assets
|
|
123
|
-
|
|
124
|
-
return sorted
|
|
125
|
-
|
|
126
|
-
from .conversation import Conversation
|
|
127
|
-
|
|
128
|
-
from .optimizers import Optimizers
|
|
129
|
-
|
|
130
|
-
from .Extra.autocoder import AutoCoder
|
|
131
|
-
|
|
132
|
-
from .prompt_manager import AwesomePrompts
|
|
1
|
+
import functools
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
# --- Utility Decorators ---
|
|
5
|
+
from typing import Callable, Optional
|
|
6
|
+
|
|
7
|
+
from .conversation import Conversation # noqa: E402,F401
|
|
8
|
+
from .optimizers import Optimizers # noqa: E402,F401
|
|
9
|
+
from .prompt_manager import AwesomePrompts # noqa: E402,F401
|
|
10
|
+
from .sanitize import * # noqa: E402, F401, F403
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def timeIt(func: Callable):
|
|
14
|
+
"""
|
|
15
|
+
Decorator to measure execution time of a function (sync or async).
|
|
16
|
+
Prints: - Execution time for '{func.__name__}' : {elapsed:.6f} Seconds.
|
|
17
|
+
"""
|
|
18
|
+
import asyncio
|
|
19
|
+
GREEN_BOLD = "\033[1;92m"
|
|
20
|
+
RESET = "\033[0m"
|
|
21
|
+
@functools.wraps(func)
|
|
22
|
+
def sync_wrapper(*args, **kwargs):
|
|
23
|
+
start_time = time.time()
|
|
24
|
+
result = func(*args, **kwargs)
|
|
25
|
+
end_time = time.time()
|
|
26
|
+
print()
|
|
27
|
+
func_name = getattr(func, "__name__", str(func))
|
|
28
|
+
print(f"{GREEN_BOLD}- Execution time for '{func_name}' : {end_time - start_time:.6f} Seconds. {RESET}\n")
|
|
29
|
+
return result
|
|
30
|
+
|
|
31
|
+
@functools.wraps(func)
|
|
32
|
+
async def async_wrapper(*args, **kwargs):
|
|
33
|
+
start_time = time.time()
|
|
34
|
+
result = await func(*args, **kwargs)
|
|
35
|
+
end_time = time.time()
|
|
36
|
+
print()
|
|
37
|
+
func_name = getattr(func, "__name__", str(func))
|
|
38
|
+
print(f"{GREEN_BOLD}- Execution time for '{func_name}' : {end_time - start_time:.6f} Seconds. {RESET}\n")
|
|
39
|
+
return result
|
|
40
|
+
|
|
41
|
+
if asyncio.iscoroutinefunction(func):
|
|
42
|
+
return async_wrapper
|
|
43
|
+
else:
|
|
44
|
+
return sync_wrapper
|
|
45
|
+
|
|
46
|
+
def retry(retries: int = 3, delay: float = 1) -> Callable:
|
|
47
|
+
"""
|
|
48
|
+
Decorator to retry a function on exception.
|
|
49
|
+
"""
|
|
50
|
+
def decorator(func: Callable):
|
|
51
|
+
@functools.wraps(func)
|
|
52
|
+
def wrapper(*args, **kwargs):
|
|
53
|
+
last_exc = None
|
|
54
|
+
for attempt in range(retries):
|
|
55
|
+
try:
|
|
56
|
+
return func(*args, **kwargs)
|
|
57
|
+
except Exception as exc:
|
|
58
|
+
last_exc = exc
|
|
59
|
+
print(f"Attempt {attempt + 1} failed: {exc}. Retrying in {delay} seconds...")
|
|
60
|
+
time.sleep(delay)
|
|
61
|
+
# Ensure we have an exception to raise
|
|
62
|
+
if last_exc is not None:
|
|
63
|
+
raise last_exc
|
|
64
|
+
else:
|
|
65
|
+
func_name = getattr(func, "__name__", str(func))
|
|
66
|
+
raise RuntimeError(f"Function {func_name} failed after {retries} retries with no exception recorded")
|
|
67
|
+
return wrapper
|
|
68
|
+
return decorator
|