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
webscout/AIbase.py
CHANGED
|
@@ -1,319 +1,247 @@
|
|
|
1
|
-
from abc import ABC, abstractmethod
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
) -> Response:
|
|
76
|
-
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
77
|
-
|
|
78
|
-
@abstractmethod
|
|
79
|
-
|
|
80
|
-
self,
|
|
81
|
-
prompt: str,
|
|
82
|
-
stream: bool = False,
|
|
83
|
-
optimizer: Optional[str] = None,
|
|
84
|
-
conversationally: bool = False,
|
|
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
|
-
import os
|
|
121
|
-
|
|
122
|
-
import time
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
timestamp
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
"""
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
"""
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
Returns:
|
|
190
|
-
str:
|
|
191
|
-
"""
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
required methods.
|
|
249
|
-
"""
|
|
250
|
-
|
|
251
|
-
@abstractmethod
|
|
252
|
-
def search(
|
|
253
|
-
self,
|
|
254
|
-
prompt: str,
|
|
255
|
-
stream: bool = False,
|
|
256
|
-
raw: bool = False,
|
|
257
|
-
) -> Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse], None, None]]:
|
|
258
|
-
"""Search using the provider's API and get AI-generated responses.
|
|
259
|
-
|
|
260
|
-
This method sends a search query to the provider and returns the AI-generated response.
|
|
261
|
-
It supports both streaming and non-streaming modes, as well as raw response format.
|
|
262
|
-
|
|
263
|
-
Args:
|
|
264
|
-
prompt (str): The search query or prompt to send to the API.
|
|
265
|
-
stream (bool, optional): If True, yields response chunks as they arrive.
|
|
266
|
-
If False, returns complete response. Defaults to False.
|
|
267
|
-
raw (bool, optional): If True, returns raw response dictionaries.
|
|
268
|
-
If False, returns SearchResponse objects that convert to text automatically.
|
|
269
|
-
Defaults to False.
|
|
270
|
-
|
|
271
|
-
Returns:
|
|
272
|
-
Union[SearchResponse, Generator[Union[Dict[str, str], SearchResponse], None, None]]:
|
|
273
|
-
- If stream=False: Returns complete response as SearchResponse object
|
|
274
|
-
- If stream=True: Yields response chunks as either Dict or SearchResponse objects
|
|
275
|
-
|
|
276
|
-
Raises:
|
|
277
|
-
APIConnectionError: If the API request fails
|
|
278
|
-
"""
|
|
279
|
-
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
280
|
-
|
|
281
|
-
class AsyncAISearch(ABC):
|
|
282
|
-
"""Abstract base class for asynchronous AI-powered search providers.
|
|
283
|
-
|
|
284
|
-
This class defines the interface for asynchronous AI search providers that can perform
|
|
285
|
-
web searches and return AI-generated responses based on search results.
|
|
286
|
-
|
|
287
|
-
All asynchronous search providers should inherit from this class and implement the
|
|
288
|
-
required methods.
|
|
289
|
-
"""
|
|
290
|
-
|
|
291
|
-
@abstractmethod
|
|
292
|
-
async def search(
|
|
293
|
-
self,
|
|
294
|
-
prompt: str,
|
|
295
|
-
stream: bool = False,
|
|
296
|
-
raw: bool = False,
|
|
297
|
-
) -> Union[SearchResponse, AsyncGenerator[Union[Dict[str, str], SearchResponse], None]]:
|
|
298
|
-
"""Search using the provider's API and get AI-generated responses asynchronously.
|
|
299
|
-
|
|
300
|
-
This method sends a search query to the provider and returns the AI-generated response.
|
|
301
|
-
It supports both streaming and non-streaming modes, as well as raw response format.
|
|
302
|
-
|
|
303
|
-
Args:
|
|
304
|
-
prompt (str): The search query or prompt to send to the API.
|
|
305
|
-
stream (bool, optional): If True, yields response chunks as they arrive.
|
|
306
|
-
If False, returns complete response. Defaults to False.
|
|
307
|
-
raw (bool, optional): If True, returns raw response dictionaries.
|
|
308
|
-
If False, returns SearchResponse objects that convert to text automatically.
|
|
309
|
-
Defaults to False.
|
|
310
|
-
|
|
311
|
-
Returns:
|
|
312
|
-
Union[SearchResponse, AsyncGenerator[Union[Dict[str, str], SearchResponse], None]]:
|
|
313
|
-
- If stream=False: Returns complete response as SearchResponse object
|
|
314
|
-
- If stream=True: Yields response chunks as either Dict or SearchResponse objects
|
|
315
|
-
|
|
316
|
-
Raises:
|
|
317
|
-
APIConnectionError: If the API request fails
|
|
318
|
-
"""
|
|
319
|
-
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
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")
|