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
|
@@ -1,463 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
import uuid
|
|
3
|
-
import re
|
|
4
|
-
import json
|
|
5
|
-
import cloudscraper
|
|
6
|
-
from typing import List, Dict, Optional, Union, Generator, Any
|
|
7
|
-
|
|
8
|
-
from webscout.litagent import LitAgent
|
|
9
|
-
from .base import BaseChat, BaseCompletions, OpenAICompatibleProvider
|
|
10
|
-
from .utils import (
|
|
11
|
-
ChatCompletion,
|
|
12
|
-
ChatCompletionChunk,
|
|
13
|
-
Choice,
|
|
14
|
-
ChatCompletionMessage,
|
|
15
|
-
ChoiceDelta,
|
|
16
|
-
CompletionUsage,
|
|
17
|
-
format_prompt,
|
|
18
|
-
get_system_prompt,
|
|
19
|
-
get_last_user_message,
|
|
20
|
-
count_tokens
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
# ANSI escape codes for formatting
|
|
24
|
-
BOLD = "\033[1m"
|
|
25
|
-
RED = "\033[91m"
|
|
26
|
-
RESET = "\033[0m"
|
|
27
|
-
|
|
28
|
-
class Completions(BaseCompletions):
|
|
29
|
-
def __init__(self, client: 'UncovrAI'):
|
|
30
|
-
self._client = client
|
|
31
|
-
|
|
32
|
-
def create(
|
|
33
|
-
self,
|
|
34
|
-
*,
|
|
35
|
-
model: str,
|
|
36
|
-
messages: List[Dict[str, str]],
|
|
37
|
-
max_tokens: Optional[int] = None,
|
|
38
|
-
stream: bool = False,
|
|
39
|
-
temperature: Optional[float] = None,
|
|
40
|
-
top_p: Optional[float] = None,
|
|
41
|
-
**kwargs: Any
|
|
42
|
-
) -> Union[ChatCompletion, Generator[ChatCompletionChunk, None, None]]:
|
|
43
|
-
"""
|
|
44
|
-
Create a chat completion using the UncovrAI API.
|
|
45
|
-
|
|
46
|
-
Args:
|
|
47
|
-
model: The model to use for completion
|
|
48
|
-
messages: A list of messages in the conversation
|
|
49
|
-
max_tokens: Maximum number of tokens to generate
|
|
50
|
-
stream: Whether to stream the response
|
|
51
|
-
temperature: Controls randomness (mapped to UncovrAI's temperature)
|
|
52
|
-
top_p: Controls diversity (not directly used by UncovrAI)
|
|
53
|
-
**kwargs: Additional parameters
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
A ChatCompletion object or a generator of ChatCompletionChunk objects
|
|
57
|
-
"""
|
|
58
|
-
# Validate model
|
|
59
|
-
if model not in self._client.AVAILABLE_MODELS:
|
|
60
|
-
raise ValueError(f"Invalid model: {model}. Choose from: {self._client.AVAILABLE_MODELS}")
|
|
61
|
-
|
|
62
|
-
# Map temperature to UncovrAI's scale (0-100)
|
|
63
|
-
# Default to 32 (medium) if not provided
|
|
64
|
-
uncovr_temperature = 32
|
|
65
|
-
if temperature is not None:
|
|
66
|
-
# Map from 0-1 scale to 0-100 scale
|
|
67
|
-
uncovr_temperature = int(temperature * 100)
|
|
68
|
-
# Ensure it's within bounds
|
|
69
|
-
uncovr_temperature = max(0, min(100, uncovr_temperature))
|
|
70
|
-
|
|
71
|
-
# Map creativity from kwargs or use default
|
|
72
|
-
creativity = kwargs.get("creativity", "medium")
|
|
73
|
-
|
|
74
|
-
# Get focus and tools from kwargs or use defaults
|
|
75
|
-
selected_focus = kwargs.get("selected_focus", ["web"])
|
|
76
|
-
selected_tools = kwargs.get("selected_tools", ["quick-cards"])
|
|
77
|
-
|
|
78
|
-
# Generate request ID and timestamp
|
|
79
|
-
request_id = str(uuid.uuid4())
|
|
80
|
-
created_time = int(time.time())
|
|
81
|
-
|
|
82
|
-
# Format the conversation using utility functions
|
|
83
|
-
conversation_prompt = format_prompt(messages, add_special_tokens=False, do_continue=True)
|
|
84
|
-
|
|
85
|
-
# Prepare the request payload
|
|
86
|
-
payload = {
|
|
87
|
-
"content": conversation_prompt,
|
|
88
|
-
"chatId": self._client.chat_id,
|
|
89
|
-
"userMessageId": str(uuid.uuid4()),
|
|
90
|
-
"ai_config": {
|
|
91
|
-
"selectedFocus": selected_focus,
|
|
92
|
-
"selectedTools": selected_tools,
|
|
93
|
-
"agentId": "chat",
|
|
94
|
-
"modelId": model,
|
|
95
|
-
"temperature": uncovr_temperature,
|
|
96
|
-
"creativity": creativity
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
# Handle streaming response
|
|
101
|
-
if stream:
|
|
102
|
-
return self._handle_streaming_response(
|
|
103
|
-
payload=payload,
|
|
104
|
-
model=model,
|
|
105
|
-
request_id=request_id,
|
|
106
|
-
created_time=created_time
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
# Handle non-streaming response
|
|
110
|
-
return self._handle_non_streaming_response(
|
|
111
|
-
payload=payload,
|
|
112
|
-
model=model,
|
|
113
|
-
request_id=request_id,
|
|
114
|
-
created_time=created_time
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
def _handle_streaming_response(
|
|
118
|
-
self,
|
|
119
|
-
*,
|
|
120
|
-
payload: Dict[str, Any],
|
|
121
|
-
model: str,
|
|
122
|
-
request_id: str,
|
|
123
|
-
created_time: int
|
|
124
|
-
) -> Generator[ChatCompletionChunk, None, None]:
|
|
125
|
-
"""Handle streaming response from UncovrAI API."""
|
|
126
|
-
try:
|
|
127
|
-
with self._client.session.post(
|
|
128
|
-
self._client.url,
|
|
129
|
-
json=payload,
|
|
130
|
-
stream=True,
|
|
131
|
-
timeout=self._client.timeout
|
|
132
|
-
) as response:
|
|
133
|
-
if response.status_code != 200:
|
|
134
|
-
# If we get a non-200 response, try refreshing our identity once
|
|
135
|
-
if response.status_code in [403, 429]:
|
|
136
|
-
self._client.refresh_identity()
|
|
137
|
-
# Retry with new identity
|
|
138
|
-
with self._client.session.post(
|
|
139
|
-
self._client.url,
|
|
140
|
-
json=payload,
|
|
141
|
-
stream=True,
|
|
142
|
-
timeout=self._client.timeout
|
|
143
|
-
) as retry_response:
|
|
144
|
-
if not retry_response.ok:
|
|
145
|
-
raise IOError(
|
|
146
|
-
f"Failed to generate response after identity refresh - "
|
|
147
|
-
f"({retry_response.status_code}, {retry_response.reason}) - "
|
|
148
|
-
f"{retry_response.text}"
|
|
149
|
-
)
|
|
150
|
-
response = retry_response
|
|
151
|
-
else:
|
|
152
|
-
raise IOError(f"Request failed with status code {response.status_code}")
|
|
153
|
-
|
|
154
|
-
# Process the streaming response
|
|
155
|
-
streaming_text = ""
|
|
156
|
-
for line in response.iter_lines():
|
|
157
|
-
if line:
|
|
158
|
-
try:
|
|
159
|
-
line = line.decode('utf-8')
|
|
160
|
-
|
|
161
|
-
# Use regex to match content messages
|
|
162
|
-
content_match = re.match(r'^0:\s*"?(.*?)"?$', line)
|
|
163
|
-
if content_match: # Content message
|
|
164
|
-
content = content_match.group(1)
|
|
165
|
-
# Format the content to handle escape sequences
|
|
166
|
-
content = self._client.format_text(content)
|
|
167
|
-
streaming_text += content
|
|
168
|
-
|
|
169
|
-
# Create a chunk for this part of the response
|
|
170
|
-
delta = ChoiceDelta(content=content)
|
|
171
|
-
choice = Choice(
|
|
172
|
-
index=0,
|
|
173
|
-
delta=delta,
|
|
174
|
-
finish_reason=None
|
|
175
|
-
)
|
|
176
|
-
chunk = ChatCompletionChunk(
|
|
177
|
-
id=request_id,
|
|
178
|
-
choices=[choice],
|
|
179
|
-
created=created_time,
|
|
180
|
-
model=model
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
yield chunk
|
|
184
|
-
|
|
185
|
-
# Check for error messages
|
|
186
|
-
error_match = re.match(r'^2:\[{"type":"error","error":"(.*?)"}]$', line)
|
|
187
|
-
if error_match:
|
|
188
|
-
error_msg = error_match.group(1)
|
|
189
|
-
raise IOError(f"API Error: {error_msg}")
|
|
190
|
-
|
|
191
|
-
except (json.JSONDecodeError, UnicodeDecodeError):
|
|
192
|
-
continue
|
|
193
|
-
|
|
194
|
-
# Yield a final chunk with finish_reason="stop"
|
|
195
|
-
delta = ChoiceDelta()
|
|
196
|
-
choice = Choice(
|
|
197
|
-
index=0,
|
|
198
|
-
delta=delta,
|
|
199
|
-
finish_reason="stop"
|
|
200
|
-
)
|
|
201
|
-
chunk = ChatCompletionChunk(
|
|
202
|
-
id=request_id,
|
|
203
|
-
choices=[choice],
|
|
204
|
-
created=created_time,
|
|
205
|
-
model=model
|
|
206
|
-
)
|
|
207
|
-
yield chunk
|
|
208
|
-
|
|
209
|
-
except Exception as e:
|
|
210
|
-
print(f"{RED}Error during UncovrAI streaming request: {e}{RESET}")
|
|
211
|
-
raise IOError(f"UncovrAI streaming request failed: {e}") from e
|
|
212
|
-
|
|
213
|
-
def _handle_non_streaming_response(
|
|
214
|
-
self,
|
|
215
|
-
*,
|
|
216
|
-
payload: Dict[str, Any],
|
|
217
|
-
model: str,
|
|
218
|
-
request_id: str,
|
|
219
|
-
created_time: int
|
|
220
|
-
) -> ChatCompletion:
|
|
221
|
-
"""Handle non-streaming response from UncovrAI API."""
|
|
222
|
-
try:
|
|
223
|
-
response = self._client.session.post(
|
|
224
|
-
self._client.url,
|
|
225
|
-
json=payload,
|
|
226
|
-
timeout=self._client.timeout
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
if response.status_code != 200:
|
|
230
|
-
if response.status_code in [403, 429]:
|
|
231
|
-
self._client.refresh_identity()
|
|
232
|
-
response = self._client.session.post(
|
|
233
|
-
self._client.url,
|
|
234
|
-
json=payload,
|
|
235
|
-
timeout=self._client.timeout
|
|
236
|
-
)
|
|
237
|
-
if not response.ok:
|
|
238
|
-
raise IOError(
|
|
239
|
-
f"Failed to generate response after identity refresh - "
|
|
240
|
-
f"({response.status_code}, {response.reason}) - "
|
|
241
|
-
f"{response.text}"
|
|
242
|
-
)
|
|
243
|
-
else:
|
|
244
|
-
raise IOError(f"Request failed with status code {response.status_code}")
|
|
245
|
-
|
|
246
|
-
full_response = ""
|
|
247
|
-
for line in response.iter_lines():
|
|
248
|
-
if line:
|
|
249
|
-
try:
|
|
250
|
-
line = line.decode('utf-8')
|
|
251
|
-
content_match = re.match(r'^0:\s*"?(.*?)"?$', line)
|
|
252
|
-
if content_match:
|
|
253
|
-
content = content_match.group(1)
|
|
254
|
-
full_response += content
|
|
255
|
-
|
|
256
|
-
# Check for error messages
|
|
257
|
-
error_match = re.match(r'^2:\[{"type":"error","error":"(.*?)"}]$', line)
|
|
258
|
-
if error_match:
|
|
259
|
-
error_msg = error_match.group(1)
|
|
260
|
-
raise IOError(f"API Error: {error_msg}")
|
|
261
|
-
|
|
262
|
-
except (json.JSONDecodeError, UnicodeDecodeError):
|
|
263
|
-
continue
|
|
264
|
-
|
|
265
|
-
# Format the full response to handle escape sequences
|
|
266
|
-
full_response = self._client.format_text(full_response)
|
|
267
|
-
|
|
268
|
-
# Create message, choice, and usage objects
|
|
269
|
-
message = ChatCompletionMessage(
|
|
270
|
-
role="assistant",
|
|
271
|
-
content=full_response
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
choice = Choice(
|
|
275
|
-
index=0,
|
|
276
|
-
message=message,
|
|
277
|
-
finish_reason="stop"
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
# Estimate token usage using count_tokens
|
|
281
|
-
prompt_tokens = count_tokens(payload.get("content", ""))
|
|
282
|
-
completion_tokens = count_tokens(full_response)
|
|
283
|
-
total_tokens = prompt_tokens + completion_tokens
|
|
284
|
-
|
|
285
|
-
usage = CompletionUsage(
|
|
286
|
-
prompt_tokens=prompt_tokens,
|
|
287
|
-
completion_tokens=completion_tokens,
|
|
288
|
-
total_tokens=total_tokens
|
|
289
|
-
)
|
|
290
|
-
|
|
291
|
-
# Create the completion object
|
|
292
|
-
completion = ChatCompletion(
|
|
293
|
-
id=request_id,
|
|
294
|
-
choices=[choice],
|
|
295
|
-
created=created_time,
|
|
296
|
-
model=model,
|
|
297
|
-
usage=usage,
|
|
298
|
-
)
|
|
299
|
-
|
|
300
|
-
return completion
|
|
301
|
-
|
|
302
|
-
except Exception as e:
|
|
303
|
-
print(f"{RED}Error during UncovrAI non-stream request: {e}{RESET}")
|
|
304
|
-
raise IOError(f"UncovrAI request failed: {e}") from e
|
|
305
|
-
|
|
306
|
-
class Chat(BaseChat):
|
|
307
|
-
def __init__(self, client: 'UncovrAI'):
|
|
308
|
-
self.completions = Completions(client)
|
|
309
|
-
|
|
310
|
-
class UncovrAI(OpenAICompatibleProvider):
|
|
311
|
-
"""
|
|
312
|
-
OpenAI-compatible client for Uncovr AI API.
|
|
313
|
-
|
|
314
|
-
Usage:
|
|
315
|
-
client = UncovrAI()
|
|
316
|
-
response = client.chat.completions.create(
|
|
317
|
-
model="default",
|
|
318
|
-
messages=[{"role": "user", "content": "Hello!"}]
|
|
319
|
-
)
|
|
320
|
-
print(response.choices[0].message.content)
|
|
321
|
-
"""
|
|
322
|
-
|
|
323
|
-
AVAILABLE_MODELS = [
|
|
324
|
-
"default",
|
|
325
|
-
"gpt-4o-mini",
|
|
326
|
-
"gemini-2-flash",
|
|
327
|
-
"gemini-2-flash-lite",
|
|
328
|
-
"groq-llama-3-1-8b",
|
|
329
|
-
"o3-mini",
|
|
330
|
-
"deepseek-r1-distill-qwen-32b",
|
|
331
|
-
# The following models are not available in the free plan:
|
|
332
|
-
# "claude-3-7-sonnet",
|
|
333
|
-
# "gpt-4o",
|
|
334
|
-
# "claude-3-5-sonnet-v2",
|
|
335
|
-
# "deepseek-r1-distill-llama-70b",
|
|
336
|
-
# "gemini-2-flash-lite-preview",
|
|
337
|
-
# "qwen-qwq-32b"
|
|
338
|
-
]
|
|
339
|
-
|
|
340
|
-
def __init__(
|
|
341
|
-
self,
|
|
342
|
-
timeout: int = 30,
|
|
343
|
-
browser: str = "chrome",
|
|
344
|
-
chat_id: Optional[str] = None,
|
|
345
|
-
user_id: Optional[str] = None,
|
|
346
|
-
proxies: dict = {}
|
|
347
|
-
):
|
|
348
|
-
"""
|
|
349
|
-
Initialize the UncovrAI client.
|
|
350
|
-
|
|
351
|
-
Args:
|
|
352
|
-
timeout: Request timeout in seconds
|
|
353
|
-
browser: Browser name for LitAgent to generate fingerprint
|
|
354
|
-
chat_id: Optional chat ID (will generate one if not provided)
|
|
355
|
-
user_id: Optional user ID (will generate one if not provided)
|
|
356
|
-
proxies: Optional proxy configuration
|
|
357
|
-
"""
|
|
358
|
-
self.url = "https://uncovr.app/api/workflows/chat"
|
|
359
|
-
self.timeout = timeout
|
|
360
|
-
|
|
361
|
-
# Initialize LitAgent for user agent generation
|
|
362
|
-
self.agent = LitAgent()
|
|
363
|
-
|
|
364
|
-
# Use fingerprinting to create a consistent browser identity
|
|
365
|
-
self.fingerprint = self.agent.generate_fingerprint(browser)
|
|
366
|
-
|
|
367
|
-
# Use the fingerprint for headers
|
|
368
|
-
self.headers = {
|
|
369
|
-
"Accept": self.fingerprint["accept"],
|
|
370
|
-
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
371
|
-
"Accept-Language": self.fingerprint["accept_language"],
|
|
372
|
-
"Content-Type": "application/json",
|
|
373
|
-
"Origin": "https://uncovr.app",
|
|
374
|
-
"Referer": "https://uncovr.app/",
|
|
375
|
-
"Sec-CH-UA": self.fingerprint["sec_ch_ua"] or '"Not)A;Brand";v="99", "Microsoft Edge";v="127", "Chromium";v="127"',
|
|
376
|
-
"Sec-CH-UA-Mobile": "?0",
|
|
377
|
-
"Sec-CH-UA-Platform": f'"{self.fingerprint["platform"]}"',
|
|
378
|
-
"User-Agent": self.fingerprint["user_agent"],
|
|
379
|
-
"Sec-Fetch-Dest": "empty",
|
|
380
|
-
"Sec-Fetch-Mode": "cors",
|
|
381
|
-
"Sec-Fetch-Site": "same-origin"
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
# Use cloudscraper to bypass Cloudflare protection
|
|
385
|
-
self.session = cloudscraper.create_scraper()
|
|
386
|
-
self.session.headers.update(self.headers)
|
|
387
|
-
self.session.proxies.update(proxies)
|
|
388
|
-
|
|
389
|
-
# Set chat and user IDs
|
|
390
|
-
self.chat_id = chat_id or str(uuid.uuid4())
|
|
391
|
-
self.user_id = user_id or f"user_{str(uuid.uuid4())[:8].upper()}"
|
|
392
|
-
|
|
393
|
-
# Initialize chat interface
|
|
394
|
-
self.chat = Chat(self)
|
|
395
|
-
|
|
396
|
-
def refresh_identity(self, browser: str = None):
|
|
397
|
-
"""
|
|
398
|
-
Refreshes the browser identity fingerprint.
|
|
399
|
-
|
|
400
|
-
Args:
|
|
401
|
-
browser: Specific browser to use for the new fingerprint
|
|
402
|
-
"""
|
|
403
|
-
browser = browser or self.fingerprint.get("browser_type", "chrome")
|
|
404
|
-
self.fingerprint = self.agent.generate_fingerprint(browser)
|
|
405
|
-
|
|
406
|
-
# Update headers with new fingerprint
|
|
407
|
-
self.headers.update({
|
|
408
|
-
"Accept": self.fingerprint["accept"],
|
|
409
|
-
"Accept-Language": self.fingerprint["accept_language"],
|
|
410
|
-
"Sec-CH-UA": self.fingerprint["sec_ch_ua"] or self.headers["Sec-CH-UA"],
|
|
411
|
-
"Sec-CH-UA-Platform": f'"{self.fingerprint["platform"]}"',
|
|
412
|
-
"User-Agent": self.fingerprint["user_agent"],
|
|
413
|
-
})
|
|
414
|
-
|
|
415
|
-
# Update session headers
|
|
416
|
-
for header, value in self.headers.items():
|
|
417
|
-
self.session.headers[header] = value
|
|
418
|
-
|
|
419
|
-
return self.fingerprint
|
|
420
|
-
|
|
421
|
-
def format_text(self, text: str) -> str:
|
|
422
|
-
"""
|
|
423
|
-
Format text by replacing escaped newlines with actual newlines.
|
|
424
|
-
|
|
425
|
-
Args:
|
|
426
|
-
text: Text to format
|
|
427
|
-
|
|
428
|
-
Returns:
|
|
429
|
-
Formatted text
|
|
430
|
-
"""
|
|
431
|
-
# Use a more comprehensive approach to handle all escape sequences
|
|
432
|
-
try:
|
|
433
|
-
# First handle double backslashes to avoid issues
|
|
434
|
-
text = text.replace('\\\\', '\\')
|
|
435
|
-
|
|
436
|
-
# Handle common escape sequences
|
|
437
|
-
text = text.replace('\\n', '\n')
|
|
438
|
-
text = text.replace('\\r', '\r')
|
|
439
|
-
text = text.replace('\\t', '\t')
|
|
440
|
-
text = text.replace('\\"', '"')
|
|
441
|
-
text = text.replace("\\'", "'")
|
|
442
|
-
|
|
443
|
-
# Handle any remaining escape sequences using JSON decoding
|
|
444
|
-
try:
|
|
445
|
-
# Add quotes to make it a valid JSON string
|
|
446
|
-
json_str = f'"{text}"'
|
|
447
|
-
# Use json module to decode all escape sequences
|
|
448
|
-
decoded = json.loads(json_str)
|
|
449
|
-
return decoded
|
|
450
|
-
except json.JSONDecodeError:
|
|
451
|
-
# If JSON decoding fails, return the text with the replacements we've already done
|
|
452
|
-
return text
|
|
453
|
-
except Exception as e:
|
|
454
|
-
# If any error occurs, return the original text
|
|
455
|
-
print(f"{RED}Warning: Error formatting text: {e}{RESET}")
|
|
456
|
-
return text
|
|
457
|
-
|
|
458
|
-
@property
|
|
459
|
-
def models(self):
|
|
460
|
-
class _ModelList:
|
|
461
|
-
def list(inner_self):
|
|
462
|
-
return type(self).AVAILABLE_MODELS
|
|
463
|
-
return _ModelList()
|