webscout 8.2.1__tar.gz → 8.2.3__tar.gz
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.
Potentially problematic release.
This version of webscout might be problematic. Click here for more details.
- {webscout-8.2.1/webscout.egg-info → webscout-8.2.3}/PKG-INFO +1 -1
- webscout-8.2.3/webscout/AIbase.py +260 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Bard.py +5 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/tempmail/__init__.py +2 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/tempmail/base.py +6 -1
- webscout-8.2.3/webscout/Extra/tempmail/emailnator.py +84 -0
- webscout-8.2.3/webscout/Local/__init__.py +12 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Local/cli.py +178 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Local/llm.py +104 -5
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Local/model_manager.py +48 -0
- webscout-8.2.3/webscout/Local/server.py +721 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Cloudflare.py +5 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Gemini.py +2 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/e2b.py +159 -1
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/textpollinations.py +90 -44
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/toolbaz.py +4 -4
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/__init__.py +1 -0
- webscout-8.2.3/webscout/Provider/TTS/base.py +159 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/deepgram.py +16 -16
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/elevenlabs.py +5 -5
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/gesserit.py +6 -5
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/murfai.py +7 -7
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/parler.py +6 -6
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/speechma.py +22 -22
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/streamElements.py +7 -7
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TextPollinationsAI.py +56 -41
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/toolbaz.py +4 -4
- webscout-8.2.3/webscout/version.py +2 -0
- {webscout-8.2.1 → webscout-8.2.3/webscout.egg-info}/PKG-INFO +1 -1
- {webscout-8.2.1 → webscout-8.2.3}/webscout.egg-info/SOURCES.txt +2 -0
- webscout-8.2.1/webscout/AIbase.py +0 -123
- webscout-8.2.1/webscout/Local/__init__.py +0 -6
- webscout-8.2.1/webscout/Local/server.py +0 -187
- webscout-8.2.1/webscout/version.py +0 -2
- {webscout-8.2.1 → webscout-8.2.3}/LICENSE.md +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/README.md +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/inferno/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/inferno/__main__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/inferno/cli.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/setup.cfg +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/setup.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/AIauto.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/AIutel.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/DWEBS.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/GitToolkit/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/GitToolkit/gitapi/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/GitToolkit/gitapi/repository.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/GitToolkit/gitapi/user.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/GitToolkit/gitapi/utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/YTdownloader.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/transcriber.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/channel.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/errors.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/extras.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/https.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/patterns.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/playlist.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/pool.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/query.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/stream.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/YTToolkit/ytapi/video.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/autocoder/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/autocoder/autocoder.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/autocoder/autocoder_utiles.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/gguf.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/tempmail/async_utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/tempmail/cli.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/tempmail/mail_tm.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/tempmail/temp_mail_io.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/weather.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Extra/weather_ascii.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/LLM.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/core/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/core/level.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/core/logger.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/handlers/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/handlers/console.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/handlers/file.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/handlers/network.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/styles/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/styles/colors.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/styles/formats.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/styles/text.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/utils/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/utils/detectors.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Litlogger/utils/formatters.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Local/__main__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Local/api.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Local/config.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Local/utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AI21.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/DeepFind.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/ISou.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/Perplexity.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/felo_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/genspark_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/hika_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/iask_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/monica_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/scira_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AISEARCH/webpilotai_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Aitopia.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/AllenAI.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Andi.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Blackboxai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/C4ai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/ChatGPTClone.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/ChatGPTES.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/ChatGPTGratis.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Chatify.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Cohere.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/DeepSeek.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Deepinfra.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/ElectronHub.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/ExaAI.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/ExaChat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Free2GPT.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/GPTWeb.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/GithubChat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Glider.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Groq.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/HF_space/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/HF_space/qwen_qwen2.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/HeckAI.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/HuggingFaceChat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Hunyuan.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Jadve.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Koboldai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/LambdaChat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Llama.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Llama3.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Marcus.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Netwrck.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OLLAMA.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/base.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/c4ai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/chatgpt.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/chatgptclone.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/deepinfra.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/exaai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/exachat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/freeaichat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/glider.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/heckai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/llmchatco.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/netwrck.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/opkfc.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/scirachat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/sonus.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/standardinput.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/typegpt.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/uncovrAI.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/venice.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/wisecat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/writecream.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/x0gpt.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OPENAI/yep.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/OpenGPT.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Openai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/PI.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Perplexitylabs.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Phind.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/PizzaGPT.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/QwenLM.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Reka.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/StandardInput.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/AiForce/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/AiForce/async_aiforce.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/AiForce/sync_aiforce.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/FreeAIPlayground/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/FreeAIPlayground/async_freeaiplayground.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/FreeAIPlayground/sync_freeaiplayground.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/ImgSys/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/ImgSys/async_imgsys.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/ImgSys/sync_imgsys.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/MagicStudio/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/MagicStudio/async_magicstudio.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/MagicStudio/sync_magicstudio.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/Nexra/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/Nexra/async_nexra.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/Nexra/sync_nexra.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/PollinationsAI/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/PollinationsAI/async_pollinations.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/PollinationsAI/sync_pollinations.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/aiarta/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/aiarta/async_aiarta.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/aiarta/sync_aiarta.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/artbit/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/artbit/async_artbit.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/artbit/sync_artbit.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/fastflux/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/fastflux/async_fastflux.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/fastflux/sync_fastflux.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/huggingface/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/huggingface/async_huggingface.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/huggingface/sync_huggingface.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/piclumen/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/piclumen/async_piclumen.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/piclumen/sync_piclumen.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/pixelmuse/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/pixelmuse/async_pixelmuse.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/pixelmuse/sync_pixelmuse.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/talkai/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/talkai/async_talkai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTI/talkai/sync_talkai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TTS/utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TeachAnything.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/TwoAI.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Venice.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/VercelAI.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/WebSim.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/WiseCat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Writecream.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/WritingMate.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/Youchat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/ai4chat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/aimathgpt.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/akashgpt.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/askmyai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/asksteve.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/bagoodex.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/cerebras.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/chatglm.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/cleeai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/copilot.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/elmo.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/freeaichat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/gaurish.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/geminiapi.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/geminiprorealtime.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/granite.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/hermes.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/julius.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/koala.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/labyrinth.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/learnfastai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/lepton.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/llama3mitril.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/llamatutor.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/llmchat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/llmchatco.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/meta.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/multichat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/promptrefine.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/scira_chat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/scnet.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/searchchat.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/sonus.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/talkai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/turboseek.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/tutorai.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/typefully.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/typegpt.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/uncovr.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/x0gpt.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/Provider/yep.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/__main__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/cli.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/conversation.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/exceptions.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/litagent/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/litagent/agent.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/litagent/constants.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/litprinter/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/models.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/optimizers.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/prompt_manager.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/core/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/core/crawler.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/core/scout.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/core/search_result.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/core/text_analyzer.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/core/text_utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/core/web_analyzer.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/core.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/element.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/parsers/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/parsers/html5lib_parser.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/parsers/html_parser.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/parsers/lxml_parser.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/scout/utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/swiftcli/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/tempid.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/update_checker.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/utils.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/webscout_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/webscout_search_async.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/yep_search.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/zeroart/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/zeroart/base.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/zeroart/effects.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout/zeroart/fonts.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout.egg-info/dependency_links.txt +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout.egg-info/entry_points.txt +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout.egg-info/requires.txt +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webscout.egg-info/top_level.txt +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/__init__.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/classifier.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/keywords.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/language.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/ner.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/normalizer.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/processor.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/sentiment.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/stemmer.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/tagger.py +0 -0
- {webscout-8.2.1 → webscout-8.2.3}/webstoken/tokenizer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: webscout
|
|
3
|
-
Version: 8.2.
|
|
3
|
+
Version: 8.2.3
|
|
4
4
|
Summary: Search for anything using Google, DuckDuckGo, phind.com, Contains AI models, can transcribe yt videos, temporary email and phone number generation, has TTS support, webai (terminal gpt and open interpreter) and offline LLMs and more
|
|
5
5
|
Author: OEvortex
|
|
6
6
|
Author-email: helpingai5@gmail.com
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import AsyncGenerator, List, Union, Generator, Optional
|
|
4
|
+
from typing_extensions import TypeAlias
|
|
5
|
+
|
|
6
|
+
# Type aliases for better readability
|
|
7
|
+
Response: TypeAlias = dict[str, Union[str, bool, None]]
|
|
8
|
+
ImageData: TypeAlias = Union[bytes, str, Generator[bytes, None, None]]
|
|
9
|
+
AsyncImageData: TypeAlias = Union[bytes, str, AsyncGenerator[bytes, None]]
|
|
10
|
+
|
|
11
|
+
class AIProviderError(Exception):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
class Provider(ABC):
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def ask(
|
|
18
|
+
self,
|
|
19
|
+
prompt: str,
|
|
20
|
+
stream: bool = False,
|
|
21
|
+
raw: bool = False,
|
|
22
|
+
optimizer: Optional[str] = None,
|
|
23
|
+
conversationally: bool = False,
|
|
24
|
+
) -> Response:
|
|
25
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
def chat(
|
|
29
|
+
self,
|
|
30
|
+
prompt: str,
|
|
31
|
+
stream: bool = False,
|
|
32
|
+
optimizer: Optional[str] = None,
|
|
33
|
+
conversationally: bool = False,
|
|
34
|
+
) -> str:
|
|
35
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def get_message(self, response: Response) -> str:
|
|
39
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
40
|
+
|
|
41
|
+
class AsyncProvider(ABC):
|
|
42
|
+
|
|
43
|
+
@abstractmethod
|
|
44
|
+
async def ask(
|
|
45
|
+
self,
|
|
46
|
+
prompt: str,
|
|
47
|
+
stream: bool = False,
|
|
48
|
+
raw: bool = False,
|
|
49
|
+
optimizer: Optional[str] = None,
|
|
50
|
+
conversationally: bool = False,
|
|
51
|
+
) -> Response:
|
|
52
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
async def chat(
|
|
56
|
+
self,
|
|
57
|
+
prompt: str,
|
|
58
|
+
stream: bool = False,
|
|
59
|
+
optimizer: Optional[str] = None,
|
|
60
|
+
conversationally: bool = False,
|
|
61
|
+
) -> str:
|
|
62
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
async def get_message(self, response: Response) -> str:
|
|
66
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
67
|
+
|
|
68
|
+
class TTSProvider(ABC):
|
|
69
|
+
|
|
70
|
+
@abstractmethod
|
|
71
|
+
def tts(self, text: str, voice: str = None, verbose: bool = False) -> str:
|
|
72
|
+
"""Convert text to speech and save to a temporary file.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
text (str): The text to convert to speech
|
|
76
|
+
voice (str, optional): The voice to use. Defaults to provider's default voice.
|
|
77
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
str: Path to the generated audio file
|
|
81
|
+
"""
|
|
82
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
83
|
+
|
|
84
|
+
def save_audio(self, audio_file: str, destination: str = None, verbose: bool = False) -> str:
|
|
85
|
+
"""Save audio to a specific destination.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
audio_file (str): Path to the source audio file
|
|
89
|
+
destination (str, optional): Destination path. Defaults to current directory with timestamp.
|
|
90
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
str: Path to the saved audio file
|
|
94
|
+
"""
|
|
95
|
+
import shutil
|
|
96
|
+
import os
|
|
97
|
+
from pathlib import Path
|
|
98
|
+
import time
|
|
99
|
+
|
|
100
|
+
source_path = Path(audio_file)
|
|
101
|
+
|
|
102
|
+
if not source_path.exists():
|
|
103
|
+
raise FileNotFoundError(f"Audio file not found: {audio_file}")
|
|
104
|
+
|
|
105
|
+
if destination is None:
|
|
106
|
+
# Create a default destination with timestamp in current directory
|
|
107
|
+
timestamp = int(time.time())
|
|
108
|
+
destination = os.path.join(os.getcwd(), f"tts_audio_{timestamp}{source_path.suffix}")
|
|
109
|
+
|
|
110
|
+
# Ensure the destination directory exists
|
|
111
|
+
os.makedirs(os.path.dirname(os.path.abspath(destination)), exist_ok=True)
|
|
112
|
+
|
|
113
|
+
# Copy the file
|
|
114
|
+
shutil.copy2(source_path, destination)
|
|
115
|
+
|
|
116
|
+
if verbose:
|
|
117
|
+
print(f"[debug] Audio saved to {destination}")
|
|
118
|
+
|
|
119
|
+
return destination
|
|
120
|
+
|
|
121
|
+
def stream_audio(self, text: str, voice: str = None, chunk_size: int = 1024, verbose: bool = False) -> Generator[bytes, None, None]:
|
|
122
|
+
"""Stream audio in chunks.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
text (str): The text to convert to speech
|
|
126
|
+
voice (str, optional): The voice to use. Defaults to provider's default voice.
|
|
127
|
+
chunk_size (int, optional): Size of audio chunks to yield. Defaults to 1024.
|
|
128
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
129
|
+
|
|
130
|
+
Yields:
|
|
131
|
+
Generator[bytes, None, None]: Audio data chunks
|
|
132
|
+
"""
|
|
133
|
+
# Generate the audio file
|
|
134
|
+
audio_file = self.tts(text, voice=voice, verbose=verbose)
|
|
135
|
+
|
|
136
|
+
# Stream the file in chunks
|
|
137
|
+
with open(audio_file, 'rb') as f:
|
|
138
|
+
while chunk := f.read(chunk_size):
|
|
139
|
+
yield chunk
|
|
140
|
+
|
|
141
|
+
class AsyncTTSProvider(ABC):
|
|
142
|
+
|
|
143
|
+
@abstractmethod
|
|
144
|
+
async def tts(self, text: str, voice: str = None, verbose: bool = False) -> str:
|
|
145
|
+
"""Convert text to speech and save to a temporary file asynchronously.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
text (str): The text to convert to speech
|
|
149
|
+
voice (str, optional): The voice to use. Defaults to provider's default voice.
|
|
150
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
str: Path to the generated audio file
|
|
154
|
+
"""
|
|
155
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
156
|
+
|
|
157
|
+
async def save_audio(self, audio_file: str, destination: str = None, verbose: bool = False) -> str:
|
|
158
|
+
"""Save audio to a specific destination asynchronously.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
audio_file (str): Path to the source audio file
|
|
162
|
+
destination (str, optional): Destination path. Defaults to current directory with timestamp.
|
|
163
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
str: Path to the saved audio file
|
|
167
|
+
"""
|
|
168
|
+
import shutil
|
|
169
|
+
import os
|
|
170
|
+
from pathlib import Path
|
|
171
|
+
import time
|
|
172
|
+
import asyncio
|
|
173
|
+
|
|
174
|
+
source_path = Path(audio_file)
|
|
175
|
+
|
|
176
|
+
if not source_path.exists():
|
|
177
|
+
raise FileNotFoundError(f"Audio file not found: {audio_file}")
|
|
178
|
+
|
|
179
|
+
if destination is None:
|
|
180
|
+
# Create a default destination with timestamp in current directory
|
|
181
|
+
timestamp = int(time.time())
|
|
182
|
+
destination = os.path.join(os.getcwd(), f"tts_audio_{timestamp}{source_path.suffix}")
|
|
183
|
+
|
|
184
|
+
# Ensure the destination directory exists
|
|
185
|
+
os.makedirs(os.path.dirname(os.path.abspath(destination)), exist_ok=True)
|
|
186
|
+
|
|
187
|
+
# Copy the file using asyncio to avoid blocking
|
|
188
|
+
await asyncio.to_thread(shutil.copy2, source_path, destination)
|
|
189
|
+
|
|
190
|
+
if verbose:
|
|
191
|
+
print(f"[debug] Audio saved to {destination}")
|
|
192
|
+
|
|
193
|
+
return destination
|
|
194
|
+
|
|
195
|
+
async def stream_audio(self, text: str, voice: str = None, chunk_size: int = 1024, verbose: bool = False) -> AsyncGenerator[bytes, None]:
|
|
196
|
+
"""Stream audio in chunks asynchronously.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
text (str): The text to convert to speech
|
|
200
|
+
voice (str, optional): The voice to use. Defaults to provider's default voice.
|
|
201
|
+
chunk_size (int, optional): Size of audio chunks to yield. Defaults to 1024.
|
|
202
|
+
verbose (bool, optional): Whether to print debug information. Defaults to False.
|
|
203
|
+
|
|
204
|
+
Yields:
|
|
205
|
+
AsyncGenerator[bytes, None]: Audio data chunks
|
|
206
|
+
"""
|
|
207
|
+
import aiofiles
|
|
208
|
+
|
|
209
|
+
# Generate the audio file
|
|
210
|
+
audio_file = await self.tts(text, voice=voice, verbose=verbose)
|
|
211
|
+
|
|
212
|
+
# Stream the file in chunks
|
|
213
|
+
async with aiofiles.open(audio_file, 'rb') as f:
|
|
214
|
+
while chunk := await f.read(chunk_size):
|
|
215
|
+
yield chunk
|
|
216
|
+
|
|
217
|
+
class ImageProvider(ABC):
|
|
218
|
+
|
|
219
|
+
@abstractmethod
|
|
220
|
+
def generate(self, prompt: str, amount: int = 1) -> List[bytes]:
|
|
221
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
222
|
+
|
|
223
|
+
@abstractmethod
|
|
224
|
+
def save(
|
|
225
|
+
self,
|
|
226
|
+
response: List[bytes],
|
|
227
|
+
name: Optional[str] = None,
|
|
228
|
+
dir: Optional[Union[str, Path]] = None
|
|
229
|
+
) -> List[str]:
|
|
230
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
231
|
+
|
|
232
|
+
class AsyncImageProvider(ABC):
|
|
233
|
+
|
|
234
|
+
@abstractmethod
|
|
235
|
+
async def generate(
|
|
236
|
+
self,
|
|
237
|
+
prompt: str,
|
|
238
|
+
amount: int = 1
|
|
239
|
+
) -> Union[AsyncGenerator[bytes, None], List[bytes]]:
|
|
240
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
241
|
+
|
|
242
|
+
@abstractmethod
|
|
243
|
+
async def save(
|
|
244
|
+
self,
|
|
245
|
+
response: Union[AsyncGenerator[bytes, None], List[bytes]],
|
|
246
|
+
name: Optional[str] = None,
|
|
247
|
+
dir: Optional[Union[str, Path]] = None
|
|
248
|
+
) -> List[str]:
|
|
249
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
250
|
+
|
|
251
|
+
class AISearch(ABC):
|
|
252
|
+
|
|
253
|
+
@abstractmethod
|
|
254
|
+
def search(
|
|
255
|
+
self,
|
|
256
|
+
prompt: str,
|
|
257
|
+
stream: bool = False,
|
|
258
|
+
raw: bool = False,
|
|
259
|
+
) -> Response:
|
|
260
|
+
raise NotImplementedError("Method needs to be implemented in subclass")
|
|
@@ -76,6 +76,11 @@ class Model(Enum):
|
|
|
76
76
|
{"x-goog-ext-525001261-jspb": '[null,null,null,null,"203e6bb81620bcfe"]'},
|
|
77
77
|
True,
|
|
78
78
|
)
|
|
79
|
+
G_2_5_FLASH = (
|
|
80
|
+
"gemini-2.5-flash",
|
|
81
|
+
{"x-goog-ext-525001261-jspb": '[1,null,null,null,"35609594dbe934d8"]'},
|
|
82
|
+
False,
|
|
83
|
+
)
|
|
79
84
|
|
|
80
85
|
def __init__(self, name, header, advanced_only):
|
|
81
86
|
self.model_name = name
|
|
@@ -12,6 +12,7 @@ from .base import (
|
|
|
12
12
|
)
|
|
13
13
|
from .mail_tm import MailTM, MailTMAsync
|
|
14
14
|
from .temp_mail_io import TempMailIO, TempMailIOAsync
|
|
15
|
+
from .emailnator import EmailnatorProvider
|
|
15
16
|
|
|
16
17
|
__all__ = [
|
|
17
18
|
'TempMailProvider',
|
|
@@ -20,6 +21,7 @@ __all__ = [
|
|
|
20
21
|
'MailTMAsync',
|
|
21
22
|
'TempMailIO',
|
|
22
23
|
'TempMailIOAsync',
|
|
24
|
+
'EmailnatorProvider',
|
|
23
25
|
'get_random_email',
|
|
24
26
|
'get_disposable_email',
|
|
25
27
|
'get_provider'
|
|
@@ -99,7 +99,7 @@ def get_provider(provider_name: str = "mailtm", async_provider: bool = False) ->
|
|
|
99
99
|
Get a temporary email provider instance
|
|
100
100
|
|
|
101
101
|
Args:
|
|
102
|
-
provider_name: Name of the provider to use ("mailtm" or "
|
|
102
|
+
provider_name: Name of the provider to use ("mailtm", "tempmailio", or "emailnator")
|
|
103
103
|
async_provider: Whether to return an async provider
|
|
104
104
|
|
|
105
105
|
Returns:
|
|
@@ -109,6 +109,8 @@ def get_provider(provider_name: str = "mailtm", async_provider: bool = False) ->
|
|
|
109
109
|
if provider_name.lower() == "tempmailio":
|
|
110
110
|
from .temp_mail_io import TempMailIOAsync
|
|
111
111
|
return TempMailIOAsync()
|
|
112
|
+
elif provider_name.lower() == "emailnator":
|
|
113
|
+
raise NotImplementedError("Emailnator async provider not implemented.")
|
|
112
114
|
else:
|
|
113
115
|
from .mail_tm import MailTMAsync
|
|
114
116
|
return MailTMAsync()
|
|
@@ -116,6 +118,9 @@ def get_provider(provider_name: str = "mailtm", async_provider: bool = False) ->
|
|
|
116
118
|
if provider_name.lower() == "tempmailio":
|
|
117
119
|
from .temp_mail_io import TempMailIO
|
|
118
120
|
return TempMailIO()
|
|
121
|
+
elif provider_name.lower() == "emailnator":
|
|
122
|
+
from .emailnator import EmailnatorProvider
|
|
123
|
+
return EmailnatorProvider()
|
|
119
124
|
else:
|
|
120
125
|
from .mail_tm import MailTM
|
|
121
126
|
return MailTM()
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Emailnator Provider Implementation
|
|
3
|
+
Synchronous provider for Emailnator.com
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import List, Dict
|
|
7
|
+
from time import sleep
|
|
8
|
+
from requests import Session
|
|
9
|
+
from webscout.litagent import LitAgent
|
|
10
|
+
from .base import TempMailProvider
|
|
11
|
+
from json import loads
|
|
12
|
+
from re import findall
|
|
13
|
+
|
|
14
|
+
class EmailnatorProvider(TempMailProvider):
|
|
15
|
+
def __init__(self):
|
|
16
|
+
self.client = Session()
|
|
17
|
+
self.client.get("https://www.emailnator.com/", timeout=6)
|
|
18
|
+
self.cookies = self.client.cookies.get_dict()
|
|
19
|
+
self.user_agent = LitAgent()
|
|
20
|
+
self.client.headers = {
|
|
21
|
+
"authority": "www.emailnator.com",
|
|
22
|
+
"origin": "https://www.emailnator.com",
|
|
23
|
+
"referer": "https://www.emailnator.com/",
|
|
24
|
+
"user-agent": self.user_agent.random(),
|
|
25
|
+
"x-xsrf-token": self.client.cookies.get("XSRF-TOKEN")[:-3] + "=",
|
|
26
|
+
}
|
|
27
|
+
self.email = None
|
|
28
|
+
self._messages = []
|
|
29
|
+
self._account_deleted = False
|
|
30
|
+
|
|
31
|
+
def create_account(self) -> bool:
|
|
32
|
+
response = self.client.post(
|
|
33
|
+
"https://www.emailnator.com/generate-email",
|
|
34
|
+
json={"email": ["plusGmail", "dotGmail"]},
|
|
35
|
+
)
|
|
36
|
+
self.email = loads(response.text)["email"][0]
|
|
37
|
+
return bool(self.email)
|
|
38
|
+
|
|
39
|
+
def get_messages(self) -> List[Dict]:
|
|
40
|
+
# Wait for at least one message
|
|
41
|
+
for _ in range(30): # Wait up to 60 seconds
|
|
42
|
+
sleep(2)
|
|
43
|
+
mail_token = self.client.post(
|
|
44
|
+
"https://www.emailnator.com/message-list", json={"email": self.email}
|
|
45
|
+
)
|
|
46
|
+
mail_token = loads(mail_token.text)["messageData"]
|
|
47
|
+
if len(mail_token) > 1:
|
|
48
|
+
break
|
|
49
|
+
else:
|
|
50
|
+
return []
|
|
51
|
+
# Get message details
|
|
52
|
+
messages = []
|
|
53
|
+
for msg in mail_token[1:]:
|
|
54
|
+
msg_id = msg["messageID"]
|
|
55
|
+
mail_context = self.client.post(
|
|
56
|
+
"https://www.emailnator.com/message-list",
|
|
57
|
+
json={"email": self.email, "messageID": msg_id},
|
|
58
|
+
)
|
|
59
|
+
# The response is HTML, so we just store it as body
|
|
60
|
+
messages.append({
|
|
61
|
+
"msg_id": msg_id,
|
|
62
|
+
"from": msg.get("from", ""),
|
|
63
|
+
"subject": msg.get("subject", ""),
|
|
64
|
+
"body": mail_context.text,
|
|
65
|
+
})
|
|
66
|
+
self._messages = messages
|
|
67
|
+
return messages
|
|
68
|
+
|
|
69
|
+
def check_new_messages(self) -> List[Dict]:
|
|
70
|
+
current = self.get_messages()
|
|
71
|
+
if not self._messages:
|
|
72
|
+
return current
|
|
73
|
+
# Return only new messages
|
|
74
|
+
old_ids = {m["msg_id"] for m in self._messages}
|
|
75
|
+
new_msgs = [m for m in current if m["msg_id"] not in old_ids]
|
|
76
|
+
return new_msgs
|
|
77
|
+
|
|
78
|
+
def delete_account(self) -> bool:
|
|
79
|
+
# Emailnator does not support explicit account deletion, so just mark as deleted
|
|
80
|
+
self._account_deleted = True
|
|
81
|
+
return True
|
|
82
|
+
|
|
83
|
+
def get_account_info(self) -> Dict:
|
|
84
|
+
return {"email": self.email, "deleted": self._account_deleted}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Webscout.Local - A llama-cpp-python based LLM serving tool with Ollama-compatible API
|
|
3
|
+
"""
|
|
4
|
+
from webscout.version import __version__
|
|
5
|
+
|
|
6
|
+
# Import main components for easier access
|
|
7
|
+
from .llm import LLMInterface
|
|
8
|
+
from .model_manager import ModelManager
|
|
9
|
+
from .server import start_server
|
|
10
|
+
|
|
11
|
+
# Define what's available when using `from webscout.Local import *`
|
|
12
|
+
__all__ = ["LLMInterface", "ModelManager", "start_server"]
|
|
@@ -17,6 +17,16 @@ console: Console = Console()
|
|
|
17
17
|
|
|
18
18
|
model_manager: ModelManager = ModelManager()
|
|
19
19
|
|
|
20
|
+
# RAM requirements for different model sizes
|
|
21
|
+
RAM_REQUIREMENTS = {
|
|
22
|
+
"1B": "2 GB",
|
|
23
|
+
"3B": "4 GB",
|
|
24
|
+
"7B": "8 GB",
|
|
25
|
+
"13B": "16 GB",
|
|
26
|
+
"33B": "32 GB",
|
|
27
|
+
"70B": "64 GB",
|
|
28
|
+
}
|
|
29
|
+
|
|
20
30
|
@app.command("serve")
|
|
21
31
|
def run_model(
|
|
22
32
|
model_string: str = typer.Argument(..., help="Model to run (format: 'name', 'repo_id' or 'repo_id:filename')"),
|
|
@@ -55,6 +65,16 @@ def run_model(
|
|
|
55
65
|
console.print(f"[bold red]Error downloading model: {str(e)}[/bold red]")
|
|
56
66
|
return
|
|
57
67
|
|
|
68
|
+
# Check RAM requirements
|
|
69
|
+
ram_requirement = "Unknown"
|
|
70
|
+
for size, ram in RAM_REQUIREMENTS.items():
|
|
71
|
+
if size in model_name:
|
|
72
|
+
ram_requirement = ram
|
|
73
|
+
break
|
|
74
|
+
|
|
75
|
+
if ram_requirement != "Unknown":
|
|
76
|
+
console.print(f"[yellow]This model requires approximately {ram_requirement} of RAM[/yellow]")
|
|
77
|
+
|
|
58
78
|
# Try to load the model to verify it works
|
|
59
79
|
try:
|
|
60
80
|
llm = LLMInterface(model_name)
|
|
@@ -96,12 +116,42 @@ def list_models() -> None:
|
|
|
96
116
|
table.add_column("Name", style="cyan")
|
|
97
117
|
table.add_column("Repository", style="green")
|
|
98
118
|
table.add_column("Filename", style="blue")
|
|
119
|
+
table.add_column("Size", style="magenta")
|
|
120
|
+
table.add_column("Downloaded", style="yellow")
|
|
99
121
|
|
|
100
122
|
for model in models:
|
|
123
|
+
# Get file size in human-readable format
|
|
124
|
+
file_path = model.get("path")
|
|
125
|
+
file_size = "Unknown"
|
|
126
|
+
if file_path:
|
|
127
|
+
try:
|
|
128
|
+
import os
|
|
129
|
+
size_bytes = os.path.getsize(file_path)
|
|
130
|
+
# Convert to human-readable format
|
|
131
|
+
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
|
|
132
|
+
if size_bytes < 1024.0 or unit == 'TB':
|
|
133
|
+
file_size = f"{size_bytes:.2f} {unit}"
|
|
134
|
+
break
|
|
135
|
+
size_bytes /= 1024.0
|
|
136
|
+
except Exception:
|
|
137
|
+
pass
|
|
138
|
+
|
|
139
|
+
# Format downloaded date
|
|
140
|
+
downloaded_at = model.get("downloaded_at", "Unknown")
|
|
141
|
+
if downloaded_at != "Unknown":
|
|
142
|
+
try:
|
|
143
|
+
import datetime
|
|
144
|
+
dt = datetime.datetime.fromisoformat(downloaded_at)
|
|
145
|
+
downloaded_at = dt.strftime("%Y-%m-%d %H:%M")
|
|
146
|
+
except Exception:
|
|
147
|
+
pass
|
|
148
|
+
|
|
101
149
|
table.add_row(
|
|
102
150
|
model["name"],
|
|
103
151
|
model.get("repo_id", "Unknown"),
|
|
104
152
|
model.get("filename", "Unknown"),
|
|
153
|
+
file_size,
|
|
154
|
+
downloaded_at,
|
|
105
155
|
)
|
|
106
156
|
|
|
107
157
|
console.print(table)
|
|
@@ -181,6 +231,16 @@ def chat(
|
|
|
181
231
|
console.print(f"[bold red]Error downloading model: {str(e)}[/bold red]")
|
|
182
232
|
return
|
|
183
233
|
|
|
234
|
+
# Check RAM requirements
|
|
235
|
+
ram_requirement = "Unknown"
|
|
236
|
+
for size, ram in RAM_REQUIREMENTS.items():
|
|
237
|
+
if size in model_name:
|
|
238
|
+
ram_requirement = ram
|
|
239
|
+
break
|
|
240
|
+
|
|
241
|
+
if ram_requirement != "Unknown":
|
|
242
|
+
console.print(f"[yellow]This model requires approximately {ram_requirement} of RAM[/yellow]")
|
|
243
|
+
|
|
184
244
|
# Load the model
|
|
185
245
|
try:
|
|
186
246
|
llm = LLMInterface(model_name)
|
|
@@ -325,6 +385,124 @@ def chat(
|
|
|
325
385
|
# Add extra spacing after the response
|
|
326
386
|
console.print("")
|
|
327
387
|
|
|
388
|
+
@app.command("copy")
|
|
389
|
+
def copy_model(
|
|
390
|
+
source: str = typer.Argument(..., help="Name of the source model"),
|
|
391
|
+
destination: str = typer.Argument(..., help="Name for the destination model"),
|
|
392
|
+
) -> None:
|
|
393
|
+
"""
|
|
394
|
+
Copy a model to a new name.
|
|
395
|
+
"""
|
|
396
|
+
try:
|
|
397
|
+
if model_manager.copy_model(source, destination):
|
|
398
|
+
console.print(f"[bold green]Model {source} copied to {destination} successfully[/bold green]")
|
|
399
|
+
else:
|
|
400
|
+
console.print(f"[bold red]Failed to copy model {source} to {destination}[/bold red]")
|
|
401
|
+
except Exception as e:
|
|
402
|
+
console.print(f"[bold red]Error copying model: {str(e)}[/bold red]")
|
|
403
|
+
|
|
404
|
+
@app.command("show")
|
|
405
|
+
def show_model(
|
|
406
|
+
model_name: str = typer.Argument(..., help="Name of the model to show information for"),
|
|
407
|
+
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed information"),
|
|
408
|
+
) -> None:
|
|
409
|
+
"""
|
|
410
|
+
Show detailed information about a model.
|
|
411
|
+
"""
|
|
412
|
+
model_info = model_manager.get_model_info(model_name)
|
|
413
|
+
|
|
414
|
+
if not model_info:
|
|
415
|
+
console.print(f"[yellow]Model {model_name} not found.[/yellow]")
|
|
416
|
+
return
|
|
417
|
+
|
|
418
|
+
# Create a table for basic information
|
|
419
|
+
table = Table(title=f"Model Information: {model_name}")
|
|
420
|
+
table.add_column("Property", style="cyan")
|
|
421
|
+
table.add_column("Value", style="green")
|
|
422
|
+
|
|
423
|
+
# Add basic properties
|
|
424
|
+
table.add_row("Name", model_info["name"])
|
|
425
|
+
table.add_row("Repository", model_info.get("repo_id", "Unknown"))
|
|
426
|
+
table.add_row("Filename", model_info.get("filename", "Unknown"))
|
|
427
|
+
|
|
428
|
+
# Get file size in human-readable format
|
|
429
|
+
file_path = model_info.get("path")
|
|
430
|
+
if file_path:
|
|
431
|
+
try:
|
|
432
|
+
import os
|
|
433
|
+
size_bytes = os.path.getsize(file_path)
|
|
434
|
+
# Convert to human-readable format
|
|
435
|
+
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
|
|
436
|
+
if size_bytes < 1024.0 or unit == 'TB':
|
|
437
|
+
file_size = f"{size_bytes:.2f} {unit}"
|
|
438
|
+
break
|
|
439
|
+
size_bytes /= 1024.0
|
|
440
|
+
table.add_row("Size", file_size)
|
|
441
|
+
except Exception:
|
|
442
|
+
table.add_row("Size", "Unknown")
|
|
443
|
+
|
|
444
|
+
# Format downloaded date
|
|
445
|
+
downloaded_at = model_info.get("downloaded_at", "Unknown")
|
|
446
|
+
if downloaded_at != "Unknown":
|
|
447
|
+
try:
|
|
448
|
+
import datetime
|
|
449
|
+
dt = datetime.datetime.fromisoformat(downloaded_at)
|
|
450
|
+
downloaded_at = dt.strftime("%Y-%m-%d %H:%M")
|
|
451
|
+
except Exception:
|
|
452
|
+
pass
|
|
453
|
+
table.add_row("Downloaded", downloaded_at)
|
|
454
|
+
|
|
455
|
+
# Add copied information if available
|
|
456
|
+
if "copied_from" in model_info:
|
|
457
|
+
table.add_row("Copied From", model_info["copied_from"])
|
|
458
|
+
copied_at = model_info.get("copied_at", "Unknown")
|
|
459
|
+
if copied_at != "Unknown":
|
|
460
|
+
try:
|
|
461
|
+
import datetime
|
|
462
|
+
dt = datetime.datetime.fromisoformat(copied_at)
|
|
463
|
+
copied_at = dt.strftime("%Y-%m-%d %H:%M")
|
|
464
|
+
except Exception:
|
|
465
|
+
pass
|
|
466
|
+
table.add_row("Copied At", copied_at)
|
|
467
|
+
|
|
468
|
+
# Estimate RAM requirements based on model name
|
|
469
|
+
ram_requirement = "Unknown"
|
|
470
|
+
for size, ram in RAM_REQUIREMENTS.items():
|
|
471
|
+
if size in model_name:
|
|
472
|
+
ram_requirement = ram
|
|
473
|
+
break
|
|
474
|
+
table.add_row("Estimated RAM", ram_requirement)
|
|
475
|
+
|
|
476
|
+
# Print the table
|
|
477
|
+
console.print(table)
|
|
478
|
+
|
|
479
|
+
# If verbose, show all properties
|
|
480
|
+
if verbose:
|
|
481
|
+
console.print("\n[bold]Detailed Information:[/bold]")
|
|
482
|
+
for key, value in model_info.items():
|
|
483
|
+
if key not in ["name", "repo_id", "filename", "path", "downloaded_at", "copied_from", "copied_at"]:
|
|
484
|
+
console.print(f"[cyan]{key}:[/cyan] {value}")
|
|
485
|
+
|
|
486
|
+
@app.command("ps")
|
|
487
|
+
def list_running_models() -> None:
|
|
488
|
+
"""
|
|
489
|
+
List running models.
|
|
490
|
+
"""
|
|
491
|
+
from .server import loaded_models
|
|
492
|
+
|
|
493
|
+
if not loaded_models:
|
|
494
|
+
console.print("[yellow]No models currently running.[/yellow]")
|
|
495
|
+
return
|
|
496
|
+
|
|
497
|
+
table = Table(title="Running Models")
|
|
498
|
+
table.add_column("Name", style="cyan")
|
|
499
|
+
table.add_column("Status", style="green")
|
|
500
|
+
|
|
501
|
+
for name in loaded_models.keys():
|
|
502
|
+
table.add_row(name, "Running")
|
|
503
|
+
|
|
504
|
+
console.print(table)
|
|
505
|
+
|
|
328
506
|
@app.command("version")
|
|
329
507
|
def version() -> None:
|
|
330
508
|
"""
|