webscout 8.2.9__py3-none-any.whl → 2026.1.19__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- webscout/AIauto.py +524 -251
- webscout/AIbase.py +247 -319
- webscout/AIutel.py +68 -703
- webscout/Bard.py +1072 -1026
- webscout/Extra/GitToolkit/__init__.py +10 -10
- webscout/Extra/GitToolkit/gitapi/__init__.py +20 -12
- webscout/Extra/GitToolkit/gitapi/gist.py +142 -0
- webscout/Extra/GitToolkit/gitapi/organization.py +91 -0
- webscout/Extra/GitToolkit/gitapi/repository.py +308 -195
- webscout/Extra/GitToolkit/gitapi/search.py +162 -0
- webscout/Extra/GitToolkit/gitapi/trending.py +236 -0
- webscout/Extra/GitToolkit/gitapi/user.py +128 -96
- webscout/Extra/GitToolkit/gitapi/utils.py +82 -62
- webscout/Extra/YTToolkit/README.md +443 -375
- webscout/Extra/YTToolkit/YTdownloader.py +953 -957
- webscout/Extra/YTToolkit/__init__.py +3 -3
- webscout/Extra/YTToolkit/transcriber.py +595 -476
- webscout/Extra/YTToolkit/ytapi/README.md +230 -44
- webscout/Extra/YTToolkit/ytapi/__init__.py +22 -6
- webscout/Extra/YTToolkit/ytapi/captions.py +190 -0
- webscout/Extra/YTToolkit/ytapi/channel.py +302 -307
- webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
- webscout/Extra/YTToolkit/ytapi/extras.py +178 -118
- webscout/Extra/YTToolkit/ytapi/hashtag.py +120 -0
- webscout/Extra/YTToolkit/ytapi/https.py +89 -88
- webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
- webscout/Extra/YTToolkit/ytapi/playlist.py +59 -59
- webscout/Extra/YTToolkit/ytapi/pool.py +8 -8
- webscout/Extra/YTToolkit/ytapi/query.py +143 -40
- webscout/Extra/YTToolkit/ytapi/shorts.py +122 -0
- webscout/Extra/YTToolkit/ytapi/stream.py +68 -63
- webscout/Extra/YTToolkit/ytapi/suggestions.py +97 -0
- webscout/Extra/YTToolkit/ytapi/utils.py +66 -62
- webscout/Extra/YTToolkit/ytapi/video.py +403 -232
- webscout/Extra/__init__.py +2 -3
- webscout/Extra/gguf.py +1298 -684
- webscout/Extra/tempmail/README.md +487 -487
- webscout/Extra/tempmail/__init__.py +28 -28
- webscout/Extra/tempmail/async_utils.py +143 -141
- webscout/Extra/tempmail/base.py +172 -161
- webscout/Extra/tempmail/cli.py +191 -187
- webscout/Extra/tempmail/emailnator.py +88 -84
- webscout/Extra/tempmail/mail_tm.py +378 -361
- webscout/Extra/tempmail/temp_mail_io.py +304 -292
- webscout/Extra/weather.py +196 -194
- webscout/Extra/weather_ascii.py +17 -15
- webscout/Provider/AISEARCH/PERPLEXED_search.py +175 -0
- webscout/Provider/AISEARCH/Perplexity.py +292 -333
- webscout/Provider/AISEARCH/README.md +106 -279
- webscout/Provider/AISEARCH/__init__.py +16 -9
- webscout/Provider/AISEARCH/brave_search.py +298 -0
- webscout/Provider/AISEARCH/iask_search.py +357 -410
- webscout/Provider/AISEARCH/monica_search.py +200 -220
- webscout/Provider/AISEARCH/webpilotai_search.py +242 -255
- webscout/Provider/Algion.py +413 -0
- webscout/Provider/Andi.py +74 -69
- webscout/Provider/Apriel.py +313 -0
- webscout/Provider/Ayle.py +323 -0
- webscout/Provider/ChatSandbox.py +329 -342
- webscout/Provider/ClaudeOnline.py +365 -0
- webscout/Provider/Cohere.py +232 -208
- webscout/Provider/DeepAI.py +367 -0
- webscout/Provider/Deepinfra.py +467 -340
- webscout/Provider/EssentialAI.py +217 -0
- webscout/Provider/ExaAI.py +274 -261
- webscout/Provider/Gemini.py +175 -169
- webscout/Provider/GithubChat.py +385 -369
- webscout/Provider/Gradient.py +286 -0
- webscout/Provider/Groq.py +556 -801
- webscout/Provider/HadadXYZ.py +323 -0
- webscout/Provider/HeckAI.py +392 -375
- webscout/Provider/HuggingFace.py +387 -0
- webscout/Provider/IBM.py +340 -0
- webscout/Provider/Jadve.py +317 -291
- webscout/Provider/K2Think.py +306 -0
- webscout/Provider/Koboldai.py +221 -384
- webscout/Provider/Netwrck.py +273 -270
- webscout/Provider/Nvidia.py +310 -0
- webscout/Provider/OPENAI/DeepAI.py +489 -0
- webscout/Provider/OPENAI/K2Think.py +423 -0
- webscout/Provider/OPENAI/PI.py +463 -0
- webscout/Provider/OPENAI/README.md +890 -952
- webscout/Provider/OPENAI/TogetherAI.py +405 -0
- webscout/Provider/OPENAI/TwoAI.py +255 -357
- webscout/Provider/OPENAI/__init__.py +148 -40
- webscout/Provider/OPENAI/ai4chat.py +348 -293
- webscout/Provider/OPENAI/akashgpt.py +436 -0
- webscout/Provider/OPENAI/algion.py +303 -0
- webscout/Provider/OPENAI/{exachat.py → ayle.py} +365 -444
- webscout/Provider/OPENAI/base.py +253 -249
- webscout/Provider/OPENAI/cerebras.py +296 -0
- webscout/Provider/OPENAI/chatgpt.py +870 -556
- webscout/Provider/OPENAI/chatsandbox.py +233 -173
- webscout/Provider/OPENAI/deepinfra.py +403 -322
- webscout/Provider/OPENAI/e2b.py +2370 -1414
- webscout/Provider/OPENAI/elmo.py +278 -0
- webscout/Provider/OPENAI/exaai.py +452 -417
- webscout/Provider/OPENAI/freeassist.py +446 -0
- webscout/Provider/OPENAI/gradient.py +448 -0
- webscout/Provider/OPENAI/groq.py +380 -364
- webscout/Provider/OPENAI/hadadxyz.py +292 -0
- webscout/Provider/OPENAI/heckai.py +333 -308
- webscout/Provider/OPENAI/huggingface.py +321 -0
- webscout/Provider/OPENAI/ibm.py +425 -0
- webscout/Provider/OPENAI/llmchat.py +253 -0
- webscout/Provider/OPENAI/llmchatco.py +378 -335
- webscout/Provider/OPENAI/meta.py +541 -0
- webscout/Provider/OPENAI/netwrck.py +374 -357
- webscout/Provider/OPENAI/nvidia.py +317 -0
- webscout/Provider/OPENAI/oivscode.py +348 -287
- webscout/Provider/OPENAI/openrouter.py +328 -0
- webscout/Provider/OPENAI/pydantic_imports.py +1 -172
- webscout/Provider/OPENAI/sambanova.py +397 -0
- webscout/Provider/OPENAI/sonus.py +305 -304
- webscout/Provider/OPENAI/textpollinations.py +370 -339
- webscout/Provider/OPENAI/toolbaz.py +375 -413
- webscout/Provider/OPENAI/typefully.py +419 -355
- webscout/Provider/OPENAI/typliai.py +279 -0
- webscout/Provider/OPENAI/utils.py +314 -318
- webscout/Provider/OPENAI/wisecat.py +359 -387
- webscout/Provider/OPENAI/writecream.py +185 -163
- webscout/Provider/OPENAI/x0gpt.py +462 -365
- webscout/Provider/OPENAI/zenmux.py +380 -0
- webscout/Provider/OpenRouter.py +386 -0
- webscout/Provider/Openai.py +337 -496
- webscout/Provider/PI.py +443 -429
- webscout/Provider/QwenLM.py +346 -254
- webscout/Provider/STT/__init__.py +28 -0
- webscout/Provider/STT/base.py +303 -0
- webscout/Provider/STT/elevenlabs.py +264 -0
- webscout/Provider/Sambanova.py +317 -0
- webscout/Provider/TTI/README.md +69 -82
- webscout/Provider/TTI/__init__.py +37 -7
- webscout/Provider/TTI/base.py +147 -64
- webscout/Provider/TTI/claudeonline.py +393 -0
- webscout/Provider/TTI/magicstudio.py +292 -201
- webscout/Provider/TTI/miragic.py +180 -0
- webscout/Provider/TTI/pollinations.py +331 -221
- webscout/Provider/TTI/together.py +334 -0
- webscout/Provider/TTI/utils.py +14 -11
- webscout/Provider/TTS/README.md +186 -192
- webscout/Provider/TTS/__init__.py +43 -10
- webscout/Provider/TTS/base.py +523 -159
- webscout/Provider/TTS/deepgram.py +286 -156
- webscout/Provider/TTS/elevenlabs.py +189 -111
- webscout/Provider/TTS/freetts.py +218 -0
- webscout/Provider/TTS/murfai.py +288 -113
- webscout/Provider/TTS/openai_fm.py +364 -129
- webscout/Provider/TTS/parler.py +203 -111
- webscout/Provider/TTS/qwen.py +334 -0
- webscout/Provider/TTS/sherpa.py +286 -0
- webscout/Provider/TTS/speechma.py +693 -580
- webscout/Provider/TTS/streamElements.py +275 -333
- webscout/Provider/TTS/utils.py +280 -280
- webscout/Provider/TextPollinationsAI.py +331 -308
- webscout/Provider/TogetherAI.py +450 -0
- webscout/Provider/TwoAI.py +309 -475
- webscout/Provider/TypliAI.py +311 -305
- webscout/Provider/UNFINISHED/ChatHub.py +219 -209
- webscout/Provider/{OPENAI/glider.py → UNFINISHED/ChutesAI.py} +331 -326
- webscout/Provider/{GizAI.py → UNFINISHED/GizAI.py} +300 -295
- webscout/Provider/{Marcus.py → UNFINISHED/Marcus.py} +218 -198
- webscout/Provider/UNFINISHED/Qodo.py +481 -0
- webscout/Provider/{MCPCore.py → UNFINISHED/XenAI.py} +330 -315
- webscout/Provider/UNFINISHED/Youchat.py +347 -330
- webscout/Provider/UNFINISHED/aihumanizer.py +41 -0
- webscout/Provider/UNFINISHED/grammerchecker.py +37 -0
- webscout/Provider/UNFINISHED/liner.py +342 -0
- webscout/Provider/UNFINISHED/liner_api_request.py +246 -263
- webscout/Provider/{samurai.py → UNFINISHED/samurai.py} +231 -224
- webscout/Provider/WiseCat.py +256 -233
- webscout/Provider/WrDoChat.py +390 -370
- webscout/Provider/__init__.py +115 -174
- webscout/Provider/ai4chat.py +181 -174
- webscout/Provider/akashgpt.py +330 -335
- webscout/Provider/cerebras.py +397 -290
- webscout/Provider/cleeai.py +236 -213
- webscout/Provider/elmo.py +291 -283
- webscout/Provider/geminiapi.py +343 -208
- webscout/Provider/julius.py +245 -223
- webscout/Provider/learnfastai.py +333 -325
- webscout/Provider/llama3mitril.py +230 -215
- webscout/Provider/llmchat.py +308 -258
- webscout/Provider/llmchatco.py +321 -306
- webscout/Provider/meta.py +996 -801
- webscout/Provider/oivscode.py +332 -309
- webscout/Provider/searchchat.py +316 -292
- webscout/Provider/sonus.py +264 -258
- webscout/Provider/toolbaz.py +359 -353
- webscout/Provider/turboseek.py +332 -266
- webscout/Provider/typefully.py +262 -202
- webscout/Provider/x0gpt.py +332 -299
- webscout/__init__.py +31 -39
- webscout/__main__.py +5 -5
- webscout/cli.py +585 -524
- webscout/client.py +1497 -70
- webscout/conversation.py +140 -436
- webscout/exceptions.py +383 -362
- webscout/litagent/__init__.py +29 -29
- webscout/litagent/agent.py +492 -455
- webscout/litagent/constants.py +60 -60
- webscout/models.py +505 -181
- webscout/optimizers.py +74 -420
- webscout/prompt_manager.py +376 -288
- webscout/sanitize.py +1514 -0
- webscout/scout/README.md +452 -404
- webscout/scout/__init__.py +8 -8
- webscout/scout/core/__init__.py +7 -7
- webscout/scout/core/crawler.py +330 -210
- webscout/scout/core/scout.py +800 -607
- webscout/scout/core/search_result.py +51 -96
- webscout/scout/core/text_analyzer.py +64 -63
- webscout/scout/core/text_utils.py +412 -277
- webscout/scout/core/web_analyzer.py +54 -52
- webscout/scout/element.py +872 -478
- webscout/scout/parsers/__init__.py +70 -69
- webscout/scout/parsers/html5lib_parser.py +182 -172
- webscout/scout/parsers/html_parser.py +238 -236
- webscout/scout/parsers/lxml_parser.py +203 -178
- webscout/scout/utils.py +38 -37
- webscout/search/__init__.py +47 -0
- webscout/search/base.py +201 -0
- webscout/search/bing_main.py +45 -0
- webscout/search/brave_main.py +92 -0
- webscout/search/duckduckgo_main.py +57 -0
- webscout/search/engines/__init__.py +127 -0
- webscout/search/engines/bing/__init__.py +15 -0
- webscout/search/engines/bing/base.py +35 -0
- webscout/search/engines/bing/images.py +114 -0
- webscout/search/engines/bing/news.py +96 -0
- webscout/search/engines/bing/suggestions.py +36 -0
- webscout/search/engines/bing/text.py +109 -0
- webscout/search/engines/brave/__init__.py +19 -0
- webscout/search/engines/brave/base.py +47 -0
- webscout/search/engines/brave/images.py +213 -0
- webscout/search/engines/brave/news.py +353 -0
- webscout/search/engines/brave/suggestions.py +318 -0
- webscout/search/engines/brave/text.py +167 -0
- webscout/search/engines/brave/videos.py +364 -0
- webscout/search/engines/duckduckgo/__init__.py +25 -0
- webscout/search/engines/duckduckgo/answers.py +80 -0
- webscout/search/engines/duckduckgo/base.py +189 -0
- webscout/search/engines/duckduckgo/images.py +100 -0
- webscout/search/engines/duckduckgo/maps.py +183 -0
- webscout/search/engines/duckduckgo/news.py +70 -0
- webscout/search/engines/duckduckgo/suggestions.py +22 -0
- webscout/search/engines/duckduckgo/text.py +221 -0
- webscout/search/engines/duckduckgo/translate.py +48 -0
- webscout/search/engines/duckduckgo/videos.py +80 -0
- webscout/search/engines/duckduckgo/weather.py +84 -0
- webscout/search/engines/mojeek.py +61 -0
- webscout/search/engines/wikipedia.py +77 -0
- webscout/search/engines/yahoo/__init__.py +41 -0
- webscout/search/engines/yahoo/answers.py +19 -0
- webscout/search/engines/yahoo/base.py +34 -0
- webscout/search/engines/yahoo/images.py +323 -0
- webscout/search/engines/yahoo/maps.py +19 -0
- webscout/search/engines/yahoo/news.py +258 -0
- webscout/search/engines/yahoo/suggestions.py +140 -0
- webscout/search/engines/yahoo/text.py +273 -0
- webscout/search/engines/yahoo/translate.py +19 -0
- webscout/search/engines/yahoo/videos.py +302 -0
- webscout/search/engines/yahoo/weather.py +220 -0
- webscout/search/engines/yandex.py +67 -0
- webscout/search/engines/yep/__init__.py +13 -0
- webscout/search/engines/yep/base.py +34 -0
- webscout/search/engines/yep/images.py +101 -0
- webscout/search/engines/yep/suggestions.py +38 -0
- webscout/search/engines/yep/text.py +99 -0
- webscout/search/http_client.py +172 -0
- webscout/search/results.py +141 -0
- webscout/search/yahoo_main.py +57 -0
- webscout/search/yep_main.py +48 -0
- webscout/server/__init__.py +48 -0
- webscout/server/config.py +78 -0
- webscout/server/exceptions.py +69 -0
- webscout/server/providers.py +286 -0
- webscout/server/request_models.py +131 -0
- webscout/server/request_processing.py +404 -0
- webscout/server/routes.py +642 -0
- webscout/server/server.py +351 -0
- webscout/server/ui_templates.py +1171 -0
- webscout/swiftcli/__init__.py +79 -95
- webscout/swiftcli/core/__init__.py +7 -7
- webscout/swiftcli/core/cli.py +574 -297
- webscout/swiftcli/core/context.py +98 -104
- webscout/swiftcli/core/group.py +268 -241
- webscout/swiftcli/decorators/__init__.py +28 -28
- webscout/swiftcli/decorators/command.py +243 -221
- webscout/swiftcli/decorators/options.py +247 -220
- webscout/swiftcli/decorators/output.py +392 -252
- webscout/swiftcli/exceptions.py +21 -21
- webscout/swiftcli/plugins/__init__.py +9 -9
- webscout/swiftcli/plugins/base.py +134 -135
- webscout/swiftcli/plugins/manager.py +269 -269
- webscout/swiftcli/utils/__init__.py +58 -59
- webscout/swiftcli/utils/formatting.py +251 -252
- webscout/swiftcli/utils/parsing.py +368 -267
- webscout/update_checker.py +280 -136
- webscout/utils.py +28 -14
- webscout/version.py +2 -1
- webscout/version.py.bak +3 -0
- webscout/zeroart/__init__.py +218 -135
- webscout/zeroart/base.py +70 -66
- webscout/zeroart/effects.py +155 -101
- webscout/zeroart/fonts.py +1799 -1239
- webscout-2026.1.19.dist-info/METADATA +638 -0
- webscout-2026.1.19.dist-info/RECORD +312 -0
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/WHEEL +1 -1
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/entry_points.txt +1 -1
- webscout/DWEBS.py +0 -520
- webscout/Extra/Act.md +0 -309
- webscout/Extra/GitToolkit/gitapi/README.md +0 -110
- webscout/Extra/autocoder/__init__.py +0 -9
- webscout/Extra/autocoder/autocoder.py +0 -1105
- webscout/Extra/autocoder/autocoder_utiles.py +0 -332
- webscout/Extra/gguf.md +0 -430
- webscout/Extra/weather.md +0 -281
- webscout/Litlogger/README.md +0 -10
- webscout/Litlogger/__init__.py +0 -15
- webscout/Litlogger/formats.py +0 -4
- webscout/Litlogger/handlers.py +0 -103
- webscout/Litlogger/levels.py +0 -13
- webscout/Litlogger/logger.py +0 -92
- webscout/Provider/AI21.py +0 -177
- webscout/Provider/AISEARCH/DeepFind.py +0 -254
- webscout/Provider/AISEARCH/felo_search.py +0 -202
- webscout/Provider/AISEARCH/genspark_search.py +0 -324
- webscout/Provider/AISEARCH/hika_search.py +0 -186
- webscout/Provider/AISEARCH/scira_search.py +0 -298
- webscout/Provider/Aitopia.py +0 -316
- webscout/Provider/AllenAI.py +0 -440
- webscout/Provider/Blackboxai.py +0 -791
- webscout/Provider/ChatGPTClone.py +0 -237
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/Cloudflare.py +0 -324
- webscout/Provider/ExaChat.py +0 -358
- webscout/Provider/Flowith.py +0 -217
- webscout/Provider/FreeGemini.py +0 -250
- webscout/Provider/Glider.py +0 -225
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/HuggingFaceChat.py +0 -469
- webscout/Provider/Hunyuan.py +0 -283
- webscout/Provider/LambdaChat.py +0 -411
- webscout/Provider/Llama3.py +0 -259
- webscout/Provider/Nemotron.py +0 -218
- webscout/Provider/OLLAMA.py +0 -396
- webscout/Provider/OPENAI/BLACKBOXAI.py +0 -766
- webscout/Provider/OPENAI/Cloudflare.py +0 -378
- webscout/Provider/OPENAI/FreeGemini.py +0 -283
- webscout/Provider/OPENAI/NEMOTRON.py +0 -232
- webscout/Provider/OPENAI/Qwen3.py +0 -283
- webscout/Provider/OPENAI/api.py +0 -969
- webscout/Provider/OPENAI/c4ai.py +0 -373
- webscout/Provider/OPENAI/chatgptclone.py +0 -494
- webscout/Provider/OPENAI/copilot.py +0 -242
- webscout/Provider/OPENAI/flowith.py +0 -162
- webscout/Provider/OPENAI/freeaichat.py +0 -359
- webscout/Provider/OPENAI/mcpcore.py +0 -389
- webscout/Provider/OPENAI/multichat.py +0 -376
- webscout/Provider/OPENAI/opkfc.py +0 -496
- webscout/Provider/OPENAI/scirachat.py +0 -477
- webscout/Provider/OPENAI/standardinput.py +0 -433
- webscout/Provider/OPENAI/typegpt.py +0 -364
- webscout/Provider/OPENAI/uncovrAI.py +0 -463
- webscout/Provider/OPENAI/venice.py +0 -431
- webscout/Provider/OPENAI/yep.py +0 -382
- webscout/Provider/OpenGPT.py +0 -209
- webscout/Provider/Perplexitylabs.py +0 -415
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/StandardInput.py +0 -290
- webscout/Provider/TTI/aiarta.py +0 -365
- webscout/Provider/TTI/artbit.py +0 -0
- webscout/Provider/TTI/fastflux.py +0 -200
- webscout/Provider/TTI/piclumen.py +0 -203
- webscout/Provider/TTI/pixelmuse.py +0 -225
- webscout/Provider/TTS/gesserit.py +0 -128
- webscout/Provider/TTS/sthir.py +0 -94
- webscout/Provider/TeachAnything.py +0 -229
- webscout/Provider/UNFINISHED/puterjs.py +0 -635
- webscout/Provider/UNFINISHED/test_lmarena.py +0 -119
- webscout/Provider/Venice.py +0 -258
- webscout/Provider/VercelAI.py +0 -253
- webscout/Provider/Writecream.py +0 -246
- webscout/Provider/WritingMate.py +0 -269
- webscout/Provider/asksteve.py +0 -220
- webscout/Provider/chatglm.py +0 -215
- webscout/Provider/copilot.py +0 -425
- webscout/Provider/freeaichat.py +0 -285
- webscout/Provider/granite.py +0 -235
- webscout/Provider/hermes.py +0 -266
- webscout/Provider/koala.py +0 -170
- webscout/Provider/lmarena.py +0 -198
- webscout/Provider/multichat.py +0 -364
- webscout/Provider/scira_chat.py +0 -299
- webscout/Provider/scnet.py +0 -243
- webscout/Provider/talkai.py +0 -194
- webscout/Provider/typegpt.py +0 -289
- webscout/Provider/uncovr.py +0 -368
- webscout/Provider/yep.py +0 -389
- webscout/litagent/Readme.md +0 -276
- webscout/litprinter/__init__.py +0 -59
- webscout/swiftcli/Readme.md +0 -323
- webscout/tempid.py +0 -128
- webscout/webscout_search.py +0 -1184
- webscout/webscout_search_async.py +0 -654
- webscout/yep_search.py +0 -347
- webscout/zeroart/README.md +0 -89
- webscout-8.2.9.dist-info/METADATA +0 -1033
- webscout-8.2.9.dist-info/RECORD +0 -289
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/top_level.txt +0 -0
|
@@ -1,129 +1,364 @@
|
|
|
1
|
-
##################################################################################
|
|
2
|
-
## OpenAI.fm TTS Provider ##
|
|
3
|
-
##################################################################################
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
from
|
|
10
|
-
|
|
11
|
-
from
|
|
12
|
-
from webscout.
|
|
13
|
-
from webscout.Provider.TTS.base import BaseTTSProvider
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
""
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
1
|
+
##################################################################################
|
|
2
|
+
## OpenAI.fm TTS Provider ##
|
|
3
|
+
##################################################################################
|
|
4
|
+
import pathlib
|
|
5
|
+
import tempfile
|
|
6
|
+
from typing import Any, Generator, List, Optional, Union, cast
|
|
7
|
+
|
|
8
|
+
import requests
|
|
9
|
+
from litprinter import ic
|
|
10
|
+
|
|
11
|
+
from webscout import exceptions
|
|
12
|
+
from webscout.litagent import LitAgent
|
|
13
|
+
from webscout.Provider.TTS.base import BaseTTSProvider
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class OpenAIFMTTS(BaseTTSProvider):
|
|
17
|
+
"""
|
|
18
|
+
Text-to-speech provider using the OpenAI.fm API with OpenAI-compatible interface.
|
|
19
|
+
|
|
20
|
+
This provider follows the OpenAI TTS API structure with support for:
|
|
21
|
+
- Multiple TTS models (gpt-4o-mini-tts, tts-1, tts-1-hd)
|
|
22
|
+
- 11 built-in voices optimized for English
|
|
23
|
+
- Voice instructions for controlling speech aspects
|
|
24
|
+
- Multiple output formats
|
|
25
|
+
- Streaming support
|
|
26
|
+
"""
|
|
27
|
+
required_auth = False
|
|
28
|
+
|
|
29
|
+
# Request headers
|
|
30
|
+
headers = {
|
|
31
|
+
"accept": "*/*",
|
|
32
|
+
"accept-language": "en-US,en;q=0.9",
|
|
33
|
+
"cache-control": "no-cache",
|
|
34
|
+
"pragma": "no-cache",
|
|
35
|
+
"sec-fetch-dest": "audio",
|
|
36
|
+
"sec-fetch-mode": "no-cors",
|
|
37
|
+
"sec-fetch-site": "same-origin",
|
|
38
|
+
"user-agent": LitAgent().random(),
|
|
39
|
+
"referer": "https://www.openai.fm"
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Override supported models for OpenAI.fm
|
|
43
|
+
SUPPORTED_MODELS = [
|
|
44
|
+
"gpt-4o-mini-tts", # Latest intelligent realtime model
|
|
45
|
+
"tts-1", # Lower latency model
|
|
46
|
+
"tts-1-hd" # Higher quality model
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
# OpenAI.fm supported voices (11 built-in voices)
|
|
50
|
+
SUPPORTED_VOICES = [
|
|
51
|
+
"alloy", # Neutral voice with balanced tone
|
|
52
|
+
"ash", # Calm and thoughtful male voice
|
|
53
|
+
"ballad", # Soft and melodic voice
|
|
54
|
+
"coral", # Warm and inviting female voice
|
|
55
|
+
"echo", # Clear and precise voice
|
|
56
|
+
"fable", # Authoritative and narrative voice
|
|
57
|
+
"nova", # Energetic and bright female voice
|
|
58
|
+
"onyx", # Deep and resonant male voice
|
|
59
|
+
"sage", # Measured and contemplative voice
|
|
60
|
+
"shimmer" # Bright and optimistic voice
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
# Voice mapping for API compatibility
|
|
64
|
+
voice_mapping = {
|
|
65
|
+
"alloy": "alloy",
|
|
66
|
+
"ash": "ash",
|
|
67
|
+
"ballad": "ballad",
|
|
68
|
+
"coral": "coral",
|
|
69
|
+
"echo": "echo",
|
|
70
|
+
"fable": "fable",
|
|
71
|
+
"nova": "nova",
|
|
72
|
+
"onyx": "onyx",
|
|
73
|
+
"sage": "sage",
|
|
74
|
+
"shimmer": "shimmer"
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
def __init__(self, timeout: int = 20, proxies: Optional[dict] = None):
|
|
78
|
+
"""
|
|
79
|
+
Initialize the OpenAI.fm TTS client.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
timeout (int): Request timeout in seconds
|
|
83
|
+
proxies (dict): Proxy configuration
|
|
84
|
+
"""
|
|
85
|
+
super().__init__()
|
|
86
|
+
self.api_url = "https://www.openai.fm/api/generate"
|
|
87
|
+
self.session = requests.Session()
|
|
88
|
+
self.session.headers.update(self.headers)
|
|
89
|
+
if proxies:
|
|
90
|
+
self.session.proxies.update(proxies)
|
|
91
|
+
self.timeout = timeout
|
|
92
|
+
|
|
93
|
+
def tts(
|
|
94
|
+
self,
|
|
95
|
+
text: str,
|
|
96
|
+
voice: Optional[str] = None,
|
|
97
|
+
verbose: bool = False,
|
|
98
|
+
**kwargs
|
|
99
|
+
) -> str:
|
|
100
|
+
"""
|
|
101
|
+
Convert text to speech using OpenAI.fm API with OpenAI-compatible parameters.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
text (str): The text to convert to speech (max 10,000 characters)
|
|
105
|
+
model (str): The TTS model to use (gpt-4o-mini-tts, tts-1, tts-1-hd)
|
|
106
|
+
voice (str): The voice to use for TTS (alloy, ash, ballad, coral, echo, fable, nova, onyx, sage, shimmer)
|
|
107
|
+
response_format (str): Audio format (mp3, opus, aac, flac, wav, pcm)
|
|
108
|
+
instructions (str): Voice instructions for controlling speech aspects like accent, tone, speed
|
|
109
|
+
verbose (bool): Whether to print debug information
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
str: Path to the generated audio file
|
|
113
|
+
|
|
114
|
+
Raises:
|
|
115
|
+
ValueError: If input parameters are invalid
|
|
116
|
+
exceptions.FailedToGenerateResponseError: If there is an error generating or saving the audio
|
|
117
|
+
"""
|
|
118
|
+
# Extract optional parameters from kwargs
|
|
119
|
+
model = kwargs.get("model", "gpt-4o-mini-tts")
|
|
120
|
+
response_format = kwargs.get("response_format", "mp3")
|
|
121
|
+
instructions = kwargs.get("instructions", None)
|
|
122
|
+
|
|
123
|
+
# Validate input parameters
|
|
124
|
+
if not text or not isinstance(text, str):
|
|
125
|
+
raise ValueError("Input text must be a non-empty string")
|
|
126
|
+
if len(text) > 10000:
|
|
127
|
+
raise ValueError("Input text exceeds maximum allowed length of 10,000 characters")
|
|
128
|
+
|
|
129
|
+
# Validate model, voice, and format using base class methods
|
|
130
|
+
model = self.validate_model(model)
|
|
131
|
+
voice = self.validate_voice(voice or "coral")
|
|
132
|
+
response_format = self.validate_format(response_format)
|
|
133
|
+
|
|
134
|
+
# Map voice to API format
|
|
135
|
+
voice_id = self.voice_mapping.get(voice, voice)
|
|
136
|
+
|
|
137
|
+
# Set default instructions if not provided
|
|
138
|
+
if instructions is None:
|
|
139
|
+
instructions = "Speak in a cheerful and positive tone."
|
|
140
|
+
|
|
141
|
+
# Create temporary file with appropriate extension
|
|
142
|
+
file_extension = f".{response_format}" if response_format != "pcm" else ".wav"
|
|
143
|
+
with tempfile.NamedTemporaryFile(suffix=file_extension, dir=self.temp_dir, delete=False) as temp_file:
|
|
144
|
+
filename = pathlib.Path(temp_file.name)
|
|
145
|
+
|
|
146
|
+
# Prepare parameters for the API request
|
|
147
|
+
params = {
|
|
148
|
+
"input": text,
|
|
149
|
+
"prompt": instructions,
|
|
150
|
+
"voice": voice_id,
|
|
151
|
+
"model": model,
|
|
152
|
+
"response_format": response_format
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
# Make the API request
|
|
157
|
+
response = self.session.get(
|
|
158
|
+
self.api_url,
|
|
159
|
+
params=params,
|
|
160
|
+
timeout=self.timeout
|
|
161
|
+
)
|
|
162
|
+
response.raise_for_status()
|
|
163
|
+
|
|
164
|
+
# Validate response content
|
|
165
|
+
if not response.content:
|
|
166
|
+
raise exceptions.FailedToGenerateResponseError("Empty response from API")
|
|
167
|
+
|
|
168
|
+
# Save the audio file
|
|
169
|
+
with open(filename, "wb") as f:
|
|
170
|
+
f.write(response.content)
|
|
171
|
+
|
|
172
|
+
if verbose:
|
|
173
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
174
|
+
ic("Speech generated successfully")
|
|
175
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
176
|
+
ic(f"Model: {model}")
|
|
177
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
178
|
+
ic(f"Voice: {voice}")
|
|
179
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
180
|
+
ic(f"Format: {response_format}")
|
|
181
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
182
|
+
ic(f"Audio saved to {filename}")
|
|
183
|
+
|
|
184
|
+
return filename.as_posix()
|
|
185
|
+
|
|
186
|
+
except requests.exceptions.RequestException as e:
|
|
187
|
+
if verbose:
|
|
188
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
189
|
+
ic(f"Failed to generate speech: {e}")
|
|
190
|
+
raise exceptions.FailedToGenerateResponseError(
|
|
191
|
+
f"Failed to generate speech: {e}"
|
|
192
|
+
)
|
|
193
|
+
except Exception as e:
|
|
194
|
+
if verbose:
|
|
195
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
196
|
+
ic(f"Unexpected error: {e}")
|
|
197
|
+
raise exceptions.FailedToGenerateResponseError(
|
|
198
|
+
f"Unexpected error during speech generation: {e}"
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
def create_speech(
|
|
202
|
+
self,
|
|
203
|
+
input_text: str,
|
|
204
|
+
model: Optional[str] = "gpt-4o-mini-tts",
|
|
205
|
+
voice: Optional[str] = "alloy",
|
|
206
|
+
response_format: Optional[str] = "mp3",
|
|
207
|
+
instructions: Optional[str] = None,
|
|
208
|
+
verbose: bool = False,
|
|
209
|
+
**kwargs: Any
|
|
210
|
+
) -> str:
|
|
211
|
+
"""
|
|
212
|
+
OpenAI-compatible speech creation interface.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
input_text (str): The text to convert to speech
|
|
216
|
+
model (str): The TTS model to use
|
|
217
|
+
voice (str): The voice to use
|
|
218
|
+
response_format (str): Audio format
|
|
219
|
+
instructions (str): Voice instructions
|
|
220
|
+
verbose (bool): Whether to print debug information
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
str: Path to the generated audio file
|
|
224
|
+
"""
|
|
225
|
+
return self.tts(
|
|
226
|
+
text=input_text,
|
|
227
|
+
voice=voice or "alloy",
|
|
228
|
+
model=model or "gpt-4o-mini-tts",
|
|
229
|
+
response_format=response_format or "mp3",
|
|
230
|
+
verbose=verbose
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def with_streaming_response(self):
|
|
234
|
+
"""
|
|
235
|
+
Return a streaming response context manager (OpenAI-compatible).
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
StreamingResponseContextManager: Context manager for streaming responses
|
|
239
|
+
"""
|
|
240
|
+
return StreamingResponseContextManager(self)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
class StreamingResponseContextManager:
|
|
244
|
+
"""
|
|
245
|
+
Context manager for streaming TTS responses (OpenAI-compatible).
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
def __init__(self, tts_provider: OpenAIFMTTS):
|
|
249
|
+
self.tts_provider = tts_provider
|
|
250
|
+
self.audio_file = None
|
|
251
|
+
|
|
252
|
+
def create(
|
|
253
|
+
self,
|
|
254
|
+
input_text: str,
|
|
255
|
+
model: Optional[str] = "gpt-4o-mini-tts",
|
|
256
|
+
voice: Optional[str] = "coral",
|
|
257
|
+
response_format: Optional[str] = "mp3",
|
|
258
|
+
instructions: Optional[str] = None
|
|
259
|
+
):
|
|
260
|
+
"""
|
|
261
|
+
Create speech with streaming capability.
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
input_text (str): The text to convert to speech
|
|
265
|
+
model (str): The TTS model to use
|
|
266
|
+
voice (str): The voice to use
|
|
267
|
+
response_format (str): Audio format
|
|
268
|
+
instructions (str): Voice instructions
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
StreamingResponse: Streaming response object
|
|
272
|
+
"""
|
|
273
|
+
self.audio_file = self.tts_provider.create_speech(
|
|
274
|
+
input_text=input_text,
|
|
275
|
+
model=model,
|
|
276
|
+
voice=voice,
|
|
277
|
+
response_format=response_format,
|
|
278
|
+
instructions=instructions
|
|
279
|
+
)
|
|
280
|
+
return StreamingResponse(self.audio_file)
|
|
281
|
+
|
|
282
|
+
def __enter__(self):
|
|
283
|
+
return self
|
|
284
|
+
|
|
285
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
286
|
+
pass
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class StreamingResponse:
|
|
290
|
+
"""
|
|
291
|
+
Streaming response object for TTS audio (OpenAI-compatible).
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
def __init__(self, audio_file: str):
|
|
295
|
+
self.audio_file = audio_file
|
|
296
|
+
|
|
297
|
+
def __enter__(self):
|
|
298
|
+
"""Enter the context manager."""
|
|
299
|
+
return self
|
|
300
|
+
|
|
301
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
302
|
+
"""Exit the context manager."""
|
|
303
|
+
pass
|
|
304
|
+
|
|
305
|
+
def stream_to_file(self, file_path: str, chunk_size: int = 1024):
|
|
306
|
+
"""
|
|
307
|
+
Stream audio content to a file.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
file_path (str): Destination file path
|
|
311
|
+
chunk_size (int): Size of chunks to read/write
|
|
312
|
+
"""
|
|
313
|
+
import shutil
|
|
314
|
+
shutil.copy2(self.audio_file, file_path)
|
|
315
|
+
|
|
316
|
+
def iter_bytes(self, chunk_size: int = 1024):
|
|
317
|
+
"""
|
|
318
|
+
Iterate over audio bytes in chunks.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
chunk_size (int): Size of chunks to yield
|
|
322
|
+
|
|
323
|
+
Yields:
|
|
324
|
+
bytes: Audio data chunks
|
|
325
|
+
"""
|
|
326
|
+
with open(self.audio_file, 'rb') as f:
|
|
327
|
+
while chunk := f.read(chunk_size):
|
|
328
|
+
yield chunk
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
if __name__ == "__main__":
|
|
332
|
+
# Example usage demonstrating OpenAI-compatible interface
|
|
333
|
+
tts_provider = OpenAIFMTTS()
|
|
334
|
+
|
|
335
|
+
try:
|
|
336
|
+
# Basic usage
|
|
337
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
338
|
+
ic("Testing basic speech generation...")
|
|
339
|
+
audio_file = tts_provider.create_speech(
|
|
340
|
+
input_text="Today is a wonderful day to build something people love!",
|
|
341
|
+
model="gpt-4o-mini-tts",
|
|
342
|
+
voice="coral",
|
|
343
|
+
instructions="Speak in a cheerful and positive tone."
|
|
344
|
+
)
|
|
345
|
+
print(f"Audio file generated: {audio_file}")
|
|
346
|
+
|
|
347
|
+
# Streaming usage
|
|
348
|
+
ic.configureOutput(prefix='DEBUG| ')
|
|
349
|
+
ic("Testing streaming response...")
|
|
350
|
+
with tts_provider.with_streaming_response().create(
|
|
351
|
+
input_text="This is a streaming test.",
|
|
352
|
+
voice="alloy",
|
|
353
|
+
response_format="wav"
|
|
354
|
+
) as response:
|
|
355
|
+
response.stream_to_file("streaming_test.wav")
|
|
356
|
+
ic.configureOutput(prefix='INFO| ')
|
|
357
|
+
ic("Streaming audio saved to streaming_test.wav")
|
|
358
|
+
|
|
359
|
+
except exceptions.FailedToGenerateResponseError as e:
|
|
360
|
+
ic.configureOutput(prefix='ERROR| ')
|
|
361
|
+
ic(f"Error: {e}")
|
|
362
|
+
except Exception as e:
|
|
363
|
+
ic.configureOutput(prefix='ERROR| ')
|
|
364
|
+
ic(f"Unexpected error: {e}")
|