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
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Webscout OpenAI-Compatible API Server
|
|
3
|
+
|
|
4
|
+
A FastAPI-based server that provides OpenAI-compatible endpoints for various LLM providers.
|
|
5
|
+
Supports streaming and non-streaming chat completions with comprehensive error handling,
|
|
6
|
+
authentication, and provider management.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from contextlib import asynccontextmanager
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
import uvicorn
|
|
16
|
+
from fastapi import FastAPI
|
|
17
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
18
|
+
from fastapi.openapi.docs import get_swagger_ui_html
|
|
19
|
+
from starlette.responses import HTMLResponse
|
|
20
|
+
|
|
21
|
+
from .config import AppConfig, ServerConfig
|
|
22
|
+
from .providers import initialize_provider_map, initialize_tti_provider_map
|
|
23
|
+
from .routes import Api
|
|
24
|
+
from .ui_templates import LANDING_PAGE_HTML, SWAGGER_CSS
|
|
25
|
+
|
|
26
|
+
# Configuration constants
|
|
27
|
+
DEFAULT_PORT = 8000
|
|
28
|
+
DEFAULT_HOST = "0.0.0.0"
|
|
29
|
+
API_VERSION = "v1"
|
|
30
|
+
|
|
31
|
+
# Setup logging
|
|
32
|
+
# Using litprinter console instead of standard logging
|
|
33
|
+
|
|
34
|
+
# Global configuration instance - lazy initialization
|
|
35
|
+
config = None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def get_config() -> ServerConfig:
|
|
39
|
+
"""Get or create the global configuration instance."""
|
|
40
|
+
global config
|
|
41
|
+
if config is None:
|
|
42
|
+
config = ServerConfig()
|
|
43
|
+
return config
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@asynccontextmanager
|
|
47
|
+
async def lifespan(app: FastAPI):
|
|
48
|
+
"""Lifespan context manager for startup/shutdown events."""
|
|
49
|
+
# Startup
|
|
50
|
+
if hasattr(app.state, "startup_event"):
|
|
51
|
+
await app.state.startup_event()
|
|
52
|
+
yield
|
|
53
|
+
# Shutdown (if needed in the future)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def create_app():
|
|
57
|
+
"""Create and configure the FastAPI application."""
|
|
58
|
+
app_title = os.getenv("WEBSCOUT_API_TITLE", "Webscout API")
|
|
59
|
+
app_description = os.getenv(
|
|
60
|
+
"WEBSCOUT_API_DESCRIPTION", "OpenAI API compatible interface for various LLM providers"
|
|
61
|
+
)
|
|
62
|
+
app_version = os.getenv("WEBSCOUT_API_VERSION", "0.2.0")
|
|
63
|
+
app_docs_url = os.getenv("WEBSCOUT_API_DOCS_URL", "/docs")
|
|
64
|
+
app_redoc_url = os.getenv("WEBSCOUT_API_REDOC_URL", "/redoc")
|
|
65
|
+
app_openapi_url = os.getenv("WEBSCOUT_API_OPENAPI_URL", "/openapi.json")
|
|
66
|
+
|
|
67
|
+
app = FastAPI(
|
|
68
|
+
title=app_title,
|
|
69
|
+
description=app_description,
|
|
70
|
+
version=app_version,
|
|
71
|
+
docs_url=None, # Disable default docs
|
|
72
|
+
redoc_url=app_redoc_url,
|
|
73
|
+
openapi_url=app_openapi_url,
|
|
74
|
+
lifespan=lifespan,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Simple Custom Swagger UI with WebScout footer
|
|
78
|
+
@app.get(app_docs_url, include_in_schema=False)
|
|
79
|
+
async def custom_swagger_ui_html():
|
|
80
|
+
openapi_url = app.openapi_url or "/openapi.json"
|
|
81
|
+
swagger_response = get_swagger_ui_html(
|
|
82
|
+
openapi_url=openapi_url,
|
|
83
|
+
title=app.title + " - API Documentation",
|
|
84
|
+
)
|
|
85
|
+
html = bytes(swagger_response.body).decode("utf-8")
|
|
86
|
+
|
|
87
|
+
# Custom footer and styles
|
|
88
|
+
footer_html = """
|
|
89
|
+
<div class="webscout-footer">
|
|
90
|
+
Powered by <a href='https://github.com/OEvortex/Webscout' target='_blank'>WebScout</a>
|
|
91
|
+
</div>
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
# Inject custom CSS and footer
|
|
95
|
+
html = html.replace("</head>", f"<style>{SWAGGER_CSS}</style></head>")
|
|
96
|
+
html = html.replace("</body>", f"{footer_html}</body>")
|
|
97
|
+
return HTMLResponse(content=html)
|
|
98
|
+
|
|
99
|
+
# Add CORS middleware
|
|
100
|
+
app.add_middleware(
|
|
101
|
+
CORSMiddleware,
|
|
102
|
+
allow_origins=["*"],
|
|
103
|
+
allow_credentials=True,
|
|
104
|
+
allow_methods=["*"],
|
|
105
|
+
allow_headers=["*"],
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Initialize API routes
|
|
109
|
+
api = Api(app)
|
|
110
|
+
api.register_validation_exception_handler()
|
|
111
|
+
api.register_routes()
|
|
112
|
+
|
|
113
|
+
# Initialize providers
|
|
114
|
+
initialize_provider_map()
|
|
115
|
+
initialize_tti_provider_map()
|
|
116
|
+
|
|
117
|
+
# Root landing page
|
|
118
|
+
@app.get("/", include_in_schema=False)
|
|
119
|
+
async def root():
|
|
120
|
+
return HTMLResponse(content=LANDING_PAGE_HTML)
|
|
121
|
+
|
|
122
|
+
return app
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def create_app_debug():
|
|
126
|
+
"""Create app in debug mode."""
|
|
127
|
+
return create_app()
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def start_server(
|
|
131
|
+
port: int = DEFAULT_PORT,
|
|
132
|
+
host: str = DEFAULT_HOST,
|
|
133
|
+
default_provider: Optional[str] = None,
|
|
134
|
+
base_url: Optional[str] = None,
|
|
135
|
+
workers: int = 1,
|
|
136
|
+
log_level: str = "info",
|
|
137
|
+
debug: bool = False,
|
|
138
|
+
):
|
|
139
|
+
"""Start the API server with the given configuration."""
|
|
140
|
+
run_api(
|
|
141
|
+
host=host,
|
|
142
|
+
port=port,
|
|
143
|
+
default_provider=default_provider,
|
|
144
|
+
base_url=base_url,
|
|
145
|
+
workers=workers,
|
|
146
|
+
log_level=log_level,
|
|
147
|
+
debug=debug,
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def run_api(
|
|
152
|
+
host: str = "0.0.0.0",
|
|
153
|
+
port: Optional[int] = None,
|
|
154
|
+
default_provider: Optional[str] = None,
|
|
155
|
+
base_url: Optional[str] = None,
|
|
156
|
+
debug: bool = False,
|
|
157
|
+
workers: int = 1,
|
|
158
|
+
log_level: str = "info",
|
|
159
|
+
show_available_providers: bool = True,
|
|
160
|
+
) -> None:
|
|
161
|
+
"""Run the API server with configuration."""
|
|
162
|
+
print("Starting Webscout OpenAI API server...")
|
|
163
|
+
if port is None:
|
|
164
|
+
port = DEFAULT_PORT
|
|
165
|
+
|
|
166
|
+
AppConfig.set_config(
|
|
167
|
+
api_key=None,
|
|
168
|
+
default_provider=default_provider or AppConfig.default_provider,
|
|
169
|
+
base_url=base_url,
|
|
170
|
+
auth_required=False,
|
|
171
|
+
rate_limit_enabled=False,
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
if show_available_providers:
|
|
175
|
+
if not AppConfig.provider_map:
|
|
176
|
+
initialize_provider_map()
|
|
177
|
+
if not AppConfig.tti_provider_map:
|
|
178
|
+
initialize_tti_provider_map()
|
|
179
|
+
|
|
180
|
+
print("\n=== Webscout OpenAI API Server ===")
|
|
181
|
+
print(f"Server URL: http://{host if host != '0.0.0.0' else 'localhost'}:{port}")
|
|
182
|
+
if AppConfig.base_url:
|
|
183
|
+
print(f"Base Path: {AppConfig.base_url}")
|
|
184
|
+
api_endpoint_base = (
|
|
185
|
+
f"http://{host if host != '0.0.0.0' else 'localhost'}:{port}{AppConfig.base_url}"
|
|
186
|
+
)
|
|
187
|
+
else:
|
|
188
|
+
api_endpoint_base = f"http://{host if host != '0.0.0.0' else 'localhost'}:{port}"
|
|
189
|
+
|
|
190
|
+
print(f"API Endpoint: {api_endpoint_base}/v1/chat/completions")
|
|
191
|
+
print(f"Docs URL: {api_endpoint_base}/docs")
|
|
192
|
+
|
|
193
|
+
# Show authentication status
|
|
194
|
+
print("Authentication: 🔓 DISABLED")
|
|
195
|
+
|
|
196
|
+
# Show rate limiting status
|
|
197
|
+
print("Rate Limiting: ⚡ DISABLED")
|
|
198
|
+
|
|
199
|
+
print(f"Default Provider: {AppConfig.default_provider}")
|
|
200
|
+
print(f"Workers: {workers}")
|
|
201
|
+
print(f"Log Level: {log_level}")
|
|
202
|
+
print(f"Debug Mode: {'Enabled' if debug else 'Disabled'}")
|
|
203
|
+
|
|
204
|
+
providers = list(set(v.__name__ for v in AppConfig.provider_map.values()))
|
|
205
|
+
print(f"\n--- Available Providers ({len(providers)}) ---")
|
|
206
|
+
for i, provider_name in enumerate(sorted(providers), 1):
|
|
207
|
+
print(f"{i}. {provider_name}")
|
|
208
|
+
|
|
209
|
+
provider_class_names = set(v.__name__ for v in AppConfig.provider_map.values())
|
|
210
|
+
models = sorted(
|
|
211
|
+
[model for model in AppConfig.provider_map.keys() if model not in provider_class_names]
|
|
212
|
+
)
|
|
213
|
+
if models:
|
|
214
|
+
print(f"\n--- Available Models ({len(models)}) ---")
|
|
215
|
+
for i, model_name in enumerate(models, 1):
|
|
216
|
+
print(f"{i}. {model_name} (via {AppConfig.provider_map[model_name].__name__})")
|
|
217
|
+
else:
|
|
218
|
+
print("\nNo specific models registered. Use provider names as models.")
|
|
219
|
+
|
|
220
|
+
tti_providers = list(set(v.__name__ for v in AppConfig.tti_provider_map.values()))
|
|
221
|
+
print(f"\n--- Available TTI Providers ({len(tti_providers)}) ---")
|
|
222
|
+
for i, provider_name in enumerate(sorted(tti_providers), 1):
|
|
223
|
+
print(f"{i}. {provider_name}")
|
|
224
|
+
|
|
225
|
+
tti_models = sorted(
|
|
226
|
+
[model for model in AppConfig.tti_provider_map.keys() if model not in tti_providers]
|
|
227
|
+
)
|
|
228
|
+
if tti_models:
|
|
229
|
+
print(f"\n--- Available TTI Models ({len(tti_models)}) ---")
|
|
230
|
+
for i, model_name in enumerate(tti_models, 1):
|
|
231
|
+
print(f"{i}. {model_name} (via {AppConfig.tti_provider_map[model_name].__name__})")
|
|
232
|
+
else:
|
|
233
|
+
print("\nNo specific TTI models registered. Use TTI provider names as models.")
|
|
234
|
+
|
|
235
|
+
print("\nUse Ctrl+C to stop the server.")
|
|
236
|
+
print("=" * 40 + "\n")
|
|
237
|
+
|
|
238
|
+
uvicorn_app_str = (
|
|
239
|
+
"webscout.server.server:create_app_debug" if debug else "webscout.server.server:create_app"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# Configure uvicorn settings
|
|
243
|
+
log_level_str: str = log_level.lower() if log_level else ("debug" if debug else "info")
|
|
244
|
+
port_int: int = int(port)
|
|
245
|
+
|
|
246
|
+
# Add workers only if not in debug mode
|
|
247
|
+
if not debug and workers > 1:
|
|
248
|
+
print(f"Starting with {workers} workers...")
|
|
249
|
+
uvicorn.run(
|
|
250
|
+
app=uvicorn_app_str,
|
|
251
|
+
host=host,
|
|
252
|
+
port=port_int,
|
|
253
|
+
factory=True,
|
|
254
|
+
reload=debug,
|
|
255
|
+
log_level=log_level_str,
|
|
256
|
+
workers=workers,
|
|
257
|
+
)
|
|
258
|
+
elif debug:
|
|
259
|
+
print("Debug mode enabled - using single worker with reload...")
|
|
260
|
+
uvicorn.run(
|
|
261
|
+
app=uvicorn_app_str,
|
|
262
|
+
host=host,
|
|
263
|
+
port=port_int,
|
|
264
|
+
factory=True,
|
|
265
|
+
reload=debug,
|
|
266
|
+
log_level=log_level_str,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def main():
|
|
271
|
+
"""Main entry point for the webscout-server console script."""
|
|
272
|
+
import argparse
|
|
273
|
+
|
|
274
|
+
# Read environment variables with fallbacks
|
|
275
|
+
default_port = int(os.getenv("WEBSCOUT_PORT", os.getenv("PORT", DEFAULT_PORT)))
|
|
276
|
+
default_host = os.getenv("WEBSCOUT_HOST", DEFAULT_HOST)
|
|
277
|
+
default_workers = int(os.getenv("WEBSCOUT_WORKERS", "1"))
|
|
278
|
+
default_log_level = os.getenv("WEBSCOUT_LOG_LEVEL", "info")
|
|
279
|
+
default_provider = os.getenv("WEBSCOUT_DEFAULT_PROVIDER", os.getenv("DEFAULT_PROVIDER"))
|
|
280
|
+
default_base_url = os.getenv("WEBSCOUT_BASE_URL", os.getenv("BASE_URL"))
|
|
281
|
+
default_debug = os.getenv("WEBSCOUT_DEBUG", os.getenv("DEBUG", "false")).lower() == "true"
|
|
282
|
+
|
|
283
|
+
parser = argparse.ArgumentParser(description="Start Webscout OpenAI-compatible API server")
|
|
284
|
+
parser.add_argument(
|
|
285
|
+
"--port",
|
|
286
|
+
type=int,
|
|
287
|
+
default=default_port,
|
|
288
|
+
help=f"Port to run the server on (default: {default_port})",
|
|
289
|
+
)
|
|
290
|
+
parser.add_argument(
|
|
291
|
+
"--host",
|
|
292
|
+
type=str,
|
|
293
|
+
default=default_host,
|
|
294
|
+
help=f"Host to bind the server to (default: {default_host})",
|
|
295
|
+
)
|
|
296
|
+
parser.add_argument(
|
|
297
|
+
"--workers",
|
|
298
|
+
type=int,
|
|
299
|
+
default=default_workers,
|
|
300
|
+
help=f"Number of worker processes (default: {default_workers})",
|
|
301
|
+
)
|
|
302
|
+
parser.add_argument(
|
|
303
|
+
"--log-level",
|
|
304
|
+
type=str,
|
|
305
|
+
default=default_log_level,
|
|
306
|
+
choices=["debug", "info", "warning", "error", "critical"],
|
|
307
|
+
help=f"Log level (default: {default_log_level})",
|
|
308
|
+
)
|
|
309
|
+
parser.add_argument(
|
|
310
|
+
"--default-provider",
|
|
311
|
+
type=str,
|
|
312
|
+
default=default_provider,
|
|
313
|
+
help="Default provider to use (optional)",
|
|
314
|
+
)
|
|
315
|
+
parser.add_argument(
|
|
316
|
+
"--base-url",
|
|
317
|
+
type=str,
|
|
318
|
+
default=default_base_url,
|
|
319
|
+
help="Base URL for the API (optional, e.g., /api/v1)",
|
|
320
|
+
)
|
|
321
|
+
parser.add_argument(
|
|
322
|
+
"--debug", action="store_true", default=default_debug, help="Run in debug mode"
|
|
323
|
+
)
|
|
324
|
+
args = parser.parse_args()
|
|
325
|
+
|
|
326
|
+
# Print configuration summary
|
|
327
|
+
print("Configuration:")
|
|
328
|
+
print(f" Host: {args.host}")
|
|
329
|
+
print(f" Port: {args.port}")
|
|
330
|
+
print(f" Workers: {args.workers}")
|
|
331
|
+
print(f" Log Level: {args.log_level}")
|
|
332
|
+
print(f" Debug Mode: {args.debug}")
|
|
333
|
+
print(" Authentication: 🔓 DISABLED")
|
|
334
|
+
print(" Rate Limiting: ⚡ DISABLED")
|
|
335
|
+
print(f" Default Provider: {args.default_provider or 'Not set'}")
|
|
336
|
+
print(f" Base URL: {args.base_url or 'Not set'}")
|
|
337
|
+
print()
|
|
338
|
+
|
|
339
|
+
run_api(
|
|
340
|
+
host=args.host,
|
|
341
|
+
port=args.port,
|
|
342
|
+
workers=args.workers,
|
|
343
|
+
log_level=args.log_level,
|
|
344
|
+
default_provider=args.default_provider,
|
|
345
|
+
base_url=args.base_url,
|
|
346
|
+
debug=args.debug,
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
if __name__ == "__main__":
|
|
351
|
+
main()
|