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,303 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base classes for OpenAI-compatible STT providers.
|
|
3
|
+
|
|
4
|
+
This module provides the base structure for STT providers that follow
|
|
5
|
+
the OpenAI Whisper API interface pattern.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
import time
|
|
12
|
+
from abc import ABC, abstractmethod
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, BinaryIO, Dict, Generator, List, Optional, Union, cast
|
|
15
|
+
|
|
16
|
+
# Import OpenAI response types from the main OPENAI module
|
|
17
|
+
try:
|
|
18
|
+
from webscout.Provider.OPENAI.utils import (
|
|
19
|
+
ChatCompletion as _ChatCompletion,
|
|
20
|
+
)
|
|
21
|
+
from webscout.Provider.OPENAI.utils import (
|
|
22
|
+
ChatCompletionChunk as _ChatCompletionChunk,
|
|
23
|
+
)
|
|
24
|
+
from webscout.Provider.OPENAI.utils import (
|
|
25
|
+
ChatCompletionMessage as _Message,
|
|
26
|
+
)
|
|
27
|
+
from webscout.Provider.OPENAI.utils import (
|
|
28
|
+
Choice as _Choice,
|
|
29
|
+
)
|
|
30
|
+
from webscout.Provider.OPENAI.utils import (
|
|
31
|
+
ChoiceDelta as _ChoiceDelta,
|
|
32
|
+
)
|
|
33
|
+
from webscout.Provider.OPENAI.utils import (
|
|
34
|
+
CompletionUsage as _Usage,
|
|
35
|
+
)
|
|
36
|
+
from webscout.Provider.OPENAI.utils import (
|
|
37
|
+
count_tokens as _count_tokens,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
ChatCompletion = _ChatCompletion
|
|
41
|
+
ChatCompletionChunk = _ChatCompletionChunk
|
|
42
|
+
Choice = _Choice
|
|
43
|
+
ChoiceDelta = _ChoiceDelta
|
|
44
|
+
Message = _Message
|
|
45
|
+
Usage = _Usage
|
|
46
|
+
count_tokens = _count_tokens
|
|
47
|
+
except ImportError:
|
|
48
|
+
# Fallback if pydantic_imports is not available
|
|
49
|
+
from dataclasses import dataclass
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class Usage:
|
|
53
|
+
prompt_tokens: int = 0
|
|
54
|
+
completion_tokens: int = 0
|
|
55
|
+
total_tokens: int = 0
|
|
56
|
+
|
|
57
|
+
@dataclass
|
|
58
|
+
class Message:
|
|
59
|
+
role: str
|
|
60
|
+
content: str
|
|
61
|
+
|
|
62
|
+
@dataclass
|
|
63
|
+
class Choice:
|
|
64
|
+
index: int
|
|
65
|
+
message: Message
|
|
66
|
+
finish_reason: Optional[str] = None
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class ChoiceDelta:
|
|
70
|
+
content: Optional[str] = None
|
|
71
|
+
role: Optional[str] = None
|
|
72
|
+
|
|
73
|
+
@dataclass
|
|
74
|
+
class ChatCompletionChunk:
|
|
75
|
+
id: str
|
|
76
|
+
choices: List[Dict[str, Any]]
|
|
77
|
+
created: int
|
|
78
|
+
model: str
|
|
79
|
+
object: str = "chat.completion.chunk"
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class ChatCompletion:
|
|
83
|
+
id: str
|
|
84
|
+
choices: List[Choice]
|
|
85
|
+
created: int
|
|
86
|
+
model: str
|
|
87
|
+
usage: Usage
|
|
88
|
+
object: str = "chat.completion"
|
|
89
|
+
|
|
90
|
+
def count_tokens(text: str) -> int:
|
|
91
|
+
return len(text.split())
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class TranscriptionResponse:
|
|
95
|
+
"""Response object that mimics OpenAI's transcription response."""
|
|
96
|
+
|
|
97
|
+
def __init__(self, data: Dict[str, Any], response_format: str = "json"):
|
|
98
|
+
self._data = data
|
|
99
|
+
self._response_format = response_format
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def text(self) -> str:
|
|
103
|
+
"""Get the transcribed text."""
|
|
104
|
+
return self._data.get("text", "")
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def language(self) -> Optional[str]:
|
|
108
|
+
"""Get the detected language."""
|
|
109
|
+
return self._data.get("language")
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def duration(self) -> Optional[float]:
|
|
113
|
+
"""Get the audio duration."""
|
|
114
|
+
return self._data.get("duration")
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def segments(self) -> Optional[list]:
|
|
118
|
+
"""Get the segments with timestamps."""
|
|
119
|
+
return self._data.get("segments")
|
|
120
|
+
|
|
121
|
+
@property
|
|
122
|
+
def words(self) -> Optional[list]:
|
|
123
|
+
"""Get the words with timestamps."""
|
|
124
|
+
return self._data.get("words")
|
|
125
|
+
|
|
126
|
+
def __str__(self) -> str:
|
|
127
|
+
"""Return string representation based on response format."""
|
|
128
|
+
if self._response_format == "text":
|
|
129
|
+
return self.text
|
|
130
|
+
elif self._response_format == "srt":
|
|
131
|
+
return self._to_srt()
|
|
132
|
+
elif self._response_format == "vtt":
|
|
133
|
+
return self._to_vtt()
|
|
134
|
+
else: # json or verbose_json
|
|
135
|
+
return json.dumps(self._data, indent=2)
|
|
136
|
+
|
|
137
|
+
def _to_srt(self) -> str:
|
|
138
|
+
"""Convert to SRT subtitle format."""
|
|
139
|
+
if not self.segments:
|
|
140
|
+
return ""
|
|
141
|
+
|
|
142
|
+
srt_content = []
|
|
143
|
+
for i, segment in enumerate(self.segments, 1):
|
|
144
|
+
start_time = self._format_time_srt(segment.get("start", 0))
|
|
145
|
+
end_time = self._format_time_srt(segment.get("end", 0))
|
|
146
|
+
text = segment.get("text", "").strip()
|
|
147
|
+
|
|
148
|
+
srt_content.append(f"{i}")
|
|
149
|
+
srt_content.append(f"{start_time} --> {end_time}")
|
|
150
|
+
srt_content.append(text)
|
|
151
|
+
srt_content.append("")
|
|
152
|
+
|
|
153
|
+
return "\n".join(srt_content)
|
|
154
|
+
|
|
155
|
+
def _to_vtt(self) -> str:
|
|
156
|
+
"""Convert to VTT subtitle format."""
|
|
157
|
+
if not self.segments:
|
|
158
|
+
return "WEBVTT\n\n"
|
|
159
|
+
|
|
160
|
+
vtt_content = ["WEBVTT", ""]
|
|
161
|
+
for segment in self.segments:
|
|
162
|
+
start_time = self._format_time_vtt(segment.get("start", 0))
|
|
163
|
+
end_time = self._format_time_vtt(segment.get("end", 0))
|
|
164
|
+
text = segment.get("text", "").strip()
|
|
165
|
+
|
|
166
|
+
vtt_content.append(f"{start_time} --> {end_time}")
|
|
167
|
+
vtt_content.append(text)
|
|
168
|
+
vtt_content.append("")
|
|
169
|
+
|
|
170
|
+
return "\n".join(vtt_content)
|
|
171
|
+
|
|
172
|
+
def _format_time_srt(self, seconds: float) -> str:
|
|
173
|
+
"""Format time for SRT format (HH:MM:SS,mmm)."""
|
|
174
|
+
hours = int(seconds // 3600)
|
|
175
|
+
minutes = int((seconds % 3600) // 60)
|
|
176
|
+
secs = int(seconds % 60)
|
|
177
|
+
millisecs = int((seconds % 1) * 1000)
|
|
178
|
+
return f"{hours:02d}:{minutes:02d}:{secs:02d},{millisecs:03d}"
|
|
179
|
+
|
|
180
|
+
def _format_time_vtt(self, seconds: float) -> str:
|
|
181
|
+
"""Format time for VTT format (HH:MM:SS.mmm)."""
|
|
182
|
+
hours = int(seconds // 3600)
|
|
183
|
+
minutes = int((seconds % 3600) // 60)
|
|
184
|
+
secs = int(seconds % 60)
|
|
185
|
+
millisecs = int((seconds % 1) * 1000)
|
|
186
|
+
return f"{hours:02d}:{minutes:02d}:{secs:02d}.{millisecs:03d}"
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class BaseSTTTranscriptions(ABC):
|
|
190
|
+
"""Base class for STT transcriptions interface."""
|
|
191
|
+
|
|
192
|
+
def __init__(self, client):
|
|
193
|
+
self._client = client
|
|
194
|
+
|
|
195
|
+
@abstractmethod
|
|
196
|
+
def create(
|
|
197
|
+
self,
|
|
198
|
+
*,
|
|
199
|
+
model: str,
|
|
200
|
+
file: Union[BinaryIO, str, Path],
|
|
201
|
+
language: Optional[str] = None,
|
|
202
|
+
prompt: Optional[str] = None,
|
|
203
|
+
response_format: str = "json",
|
|
204
|
+
temperature: Optional[float] = None,
|
|
205
|
+
timestamp_granularities: Optional[List[str]] = None,
|
|
206
|
+
stream: bool = False,
|
|
207
|
+
timeout: Optional[int] = None,
|
|
208
|
+
proxies: Optional[dict] = None,
|
|
209
|
+
**kwargs: Any,
|
|
210
|
+
) -> Union[TranscriptionResponse, Generator[str, None, None]]:
|
|
211
|
+
"""
|
|
212
|
+
Create a transcription of the given audio file.
|
|
213
|
+
|
|
214
|
+
Args:
|
|
215
|
+
model: Model to use for transcription
|
|
216
|
+
file: Audio file to transcribe
|
|
217
|
+
language: Language of the audio (ISO-639-1 format)
|
|
218
|
+
prompt: Optional text to guide the model's style
|
|
219
|
+
response_format: Format of the response
|
|
220
|
+
temperature: Sampling temperature (0 to 1)
|
|
221
|
+
timestamp_granularities: Timestamp granularities to include
|
|
222
|
+
stream: Whether to stream the response
|
|
223
|
+
timeout: Request timeout
|
|
224
|
+
proxies: Proxy configuration
|
|
225
|
+
**kwargs: Additional parameters
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
TranscriptionResponse or generator of SSE strings if streaming
|
|
229
|
+
"""
|
|
230
|
+
raise NotImplementedError
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class BaseSTTAudio(ABC):
|
|
234
|
+
"""Base class for STT audio interface."""
|
|
235
|
+
|
|
236
|
+
def __init__(self, client):
|
|
237
|
+
self.transcriptions = self._create_transcriptions(client)
|
|
238
|
+
|
|
239
|
+
@abstractmethod
|
|
240
|
+
def _create_transcriptions(self, client) -> BaseSTTTranscriptions:
|
|
241
|
+
"""Create the transcriptions interface."""
|
|
242
|
+
raise NotImplementedError
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class BaseSTTChat:
|
|
246
|
+
"""Base chat interface for STT providers (placeholder for consistency)."""
|
|
247
|
+
|
|
248
|
+
def __init__(self, client):
|
|
249
|
+
_ = client # Unused but kept for interface consistency
|
|
250
|
+
self.completions = None # STT providers don't have completions
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class STTCompatibleProvider(ABC):
|
|
254
|
+
"""
|
|
255
|
+
Abstract Base Class for STT providers mimicking the OpenAI structure.
|
|
256
|
+
Requires a nested 'audio.transcriptions' structure.
|
|
257
|
+
"""
|
|
258
|
+
|
|
259
|
+
audio: BaseSTTAudio
|
|
260
|
+
|
|
261
|
+
@abstractmethod
|
|
262
|
+
def __init__(self, **kwargs: Any):
|
|
263
|
+
"""Initialize the STT provider."""
|
|
264
|
+
pass
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
@abstractmethod
|
|
268
|
+
def models(self) -> STTModels:
|
|
269
|
+
"""
|
|
270
|
+
Property that returns an object with a .list() method returning available models.
|
|
271
|
+
"""
|
|
272
|
+
raise NotImplementedError
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
class STTModels:
|
|
276
|
+
"""Models interface for STT providers."""
|
|
277
|
+
|
|
278
|
+
def __init__(self, available_models: List[str]):
|
|
279
|
+
self._available_models = available_models
|
|
280
|
+
|
|
281
|
+
def list(self) -> List[Dict[str, Any]]:
|
|
282
|
+
"""List available models."""
|
|
283
|
+
return [
|
|
284
|
+
{"id": model, "object": "model", "created": int(time.time()), "owned_by": "webscout"}
|
|
285
|
+
for model in self._available_models
|
|
286
|
+
]
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
__all__ = [
|
|
290
|
+
"TranscriptionResponse",
|
|
291
|
+
"BaseSTTTranscriptions",
|
|
292
|
+
"BaseSTTAudio",
|
|
293
|
+
"BaseSTTChat",
|
|
294
|
+
"STTCompatibleProvider",
|
|
295
|
+
"STTModels",
|
|
296
|
+
"ChatCompletion",
|
|
297
|
+
"ChatCompletionChunk",
|
|
298
|
+
"Choice",
|
|
299
|
+
"ChoiceDelta",
|
|
300
|
+
"Message",
|
|
301
|
+
"Usage",
|
|
302
|
+
"count_tokens",
|
|
303
|
+
]
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ElevenLabs STT provider with OpenAI-compatible interface.
|
|
3
|
+
|
|
4
|
+
This module provides an OpenAI Whisper API-compatible interface for ElevenLabs
|
|
5
|
+
speech-to-text transcription service.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, BinaryIO, Generator, List, Optional, Union, cast
|
|
10
|
+
|
|
11
|
+
import requests
|
|
12
|
+
|
|
13
|
+
from webscout import exceptions
|
|
14
|
+
from webscout.litagent import LitAgent
|
|
15
|
+
from webscout.Provider.STT.base import (
|
|
16
|
+
BaseSTTAudio,
|
|
17
|
+
BaseSTTTranscriptions,
|
|
18
|
+
STTCompatibleProvider,
|
|
19
|
+
STTModels,
|
|
20
|
+
TranscriptionResponse,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class ElevenLabsTranscriptions(BaseSTTTranscriptions):
|
|
25
|
+
"""ElevenLabs transcriptions interface."""
|
|
26
|
+
|
|
27
|
+
def create(
|
|
28
|
+
self,
|
|
29
|
+
*,
|
|
30
|
+
model: str,
|
|
31
|
+
file: Union[BinaryIO, str, Path],
|
|
32
|
+
language: Optional[str] = None,
|
|
33
|
+
prompt: Optional[str] = None,
|
|
34
|
+
response_format: str = "json",
|
|
35
|
+
temperature: Optional[float] = None,
|
|
36
|
+
timestamp_granularities: Optional[List[str]] = None,
|
|
37
|
+
stream: bool = False,
|
|
38
|
+
timeout: Optional[int] = None,
|
|
39
|
+
proxies: Optional[dict] = None,
|
|
40
|
+
**kwargs: Any,
|
|
41
|
+
) -> Union[TranscriptionResponse, Generator[str, None, None]]:
|
|
42
|
+
"""Create a transcription using ElevenLabs API."""
|
|
43
|
+
# Always use file as file-like object
|
|
44
|
+
if isinstance(file, (str, Path)):
|
|
45
|
+
audio_file = open(str(file), "rb")
|
|
46
|
+
close_file = True
|
|
47
|
+
else:
|
|
48
|
+
audio_file = file
|
|
49
|
+
close_file = False
|
|
50
|
+
try:
|
|
51
|
+
if stream:
|
|
52
|
+
return self._create_stream(
|
|
53
|
+
audio_file=audio_file,
|
|
54
|
+
model=model,
|
|
55
|
+
language=language,
|
|
56
|
+
prompt=prompt,
|
|
57
|
+
response_format=response_format,
|
|
58
|
+
temperature=temperature,
|
|
59
|
+
timestamp_granularities=timestamp_granularities,
|
|
60
|
+
timeout=timeout,
|
|
61
|
+
proxies=proxies,
|
|
62
|
+
**kwargs,
|
|
63
|
+
)
|
|
64
|
+
else:
|
|
65
|
+
result = self._create_non_stream(
|
|
66
|
+
audio_file=audio_file,
|
|
67
|
+
model=model,
|
|
68
|
+
language=language,
|
|
69
|
+
prompt=prompt,
|
|
70
|
+
response_format=response_format,
|
|
71
|
+
temperature=temperature,
|
|
72
|
+
timestamp_granularities=timestamp_granularities,
|
|
73
|
+
timeout=timeout,
|
|
74
|
+
proxies=proxies,
|
|
75
|
+
**kwargs,
|
|
76
|
+
)
|
|
77
|
+
return result
|
|
78
|
+
finally:
|
|
79
|
+
if close_file:
|
|
80
|
+
audio_file.close()
|
|
81
|
+
|
|
82
|
+
def _create_non_stream(
|
|
83
|
+
self,
|
|
84
|
+
audio_file: BinaryIO,
|
|
85
|
+
model: str,
|
|
86
|
+
language: Optional[str] = None,
|
|
87
|
+
prompt: Optional[str] = None,
|
|
88
|
+
response_format: str = "json",
|
|
89
|
+
temperature: Optional[float] = None,
|
|
90
|
+
timestamp_granularities: Optional[List[str]] = None,
|
|
91
|
+
timeout: Optional[int] = None,
|
|
92
|
+
proxies: Optional[dict] = None,
|
|
93
|
+
**kwargs: Any,
|
|
94
|
+
) -> TranscriptionResponse:
|
|
95
|
+
"""Create non-streaming transcription."""
|
|
96
|
+
try:
|
|
97
|
+
headers = {
|
|
98
|
+
"Accept": "application/json, text/plain, */*",
|
|
99
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
100
|
+
"User-Agent": LitAgent().random(),
|
|
101
|
+
}
|
|
102
|
+
api_url = self._client.api_url
|
|
103
|
+
if getattr(self._client, "allow_unauthenticated", False):
|
|
104
|
+
if "?" in api_url:
|
|
105
|
+
api_url += "&allow_unauthenticated=1"
|
|
106
|
+
else:
|
|
107
|
+
api_url += "?allow_unauthenticated=1"
|
|
108
|
+
files = {
|
|
109
|
+
"file": audio_file,
|
|
110
|
+
"model_id": (None, self._client.model_id),
|
|
111
|
+
"tag_audio_events": (None, "true" if self._client.tag_audio_events else "false"),
|
|
112
|
+
"diarize": (None, "true" if self._client.diarize else "false"),
|
|
113
|
+
}
|
|
114
|
+
if language:
|
|
115
|
+
files["language"] = (None, language)
|
|
116
|
+
response = requests.post(
|
|
117
|
+
api_url,
|
|
118
|
+
files=files,
|
|
119
|
+
headers=headers,
|
|
120
|
+
timeout=timeout or self._client.timeout,
|
|
121
|
+
proxies=proxies or getattr(self._client, "proxies", None),
|
|
122
|
+
)
|
|
123
|
+
if response.status_code != 200:
|
|
124
|
+
raise exceptions.FailedToGenerateResponseError(
|
|
125
|
+
f"ElevenLabs API returned error: {response.status_code} - {response.text}"
|
|
126
|
+
)
|
|
127
|
+
result = response.json()
|
|
128
|
+
simple_result = {"text": result.get("text", "")}
|
|
129
|
+
return TranscriptionResponse(simple_result, response_format)
|
|
130
|
+
except Exception as e:
|
|
131
|
+
raise exceptions.FailedToGenerateResponseError(
|
|
132
|
+
f"ElevenLabs transcription failed: {str(e)}"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
def _create_stream(
|
|
136
|
+
self,
|
|
137
|
+
audio_file: BinaryIO,
|
|
138
|
+
model: str,
|
|
139
|
+
language: Optional[str] = None,
|
|
140
|
+
prompt: Optional[str] = None,
|
|
141
|
+
response_format: str = "json",
|
|
142
|
+
temperature: Optional[float] = None,
|
|
143
|
+
timestamp_granularities: Optional[List[str]] = None,
|
|
144
|
+
timeout: Optional[int] = None,
|
|
145
|
+
proxies: Optional[dict] = None,
|
|
146
|
+
**kwargs: Any,
|
|
147
|
+
) -> Generator[str, None, None]:
|
|
148
|
+
"""Create streaming transcription using requests.post(..., stream=True)."""
|
|
149
|
+
headers = {
|
|
150
|
+
"Accept": "application/json, text/plain, */*",
|
|
151
|
+
"Accept-Language": "en-US,en;q=0.9",
|
|
152
|
+
"User-Agent": LitAgent().random(),
|
|
153
|
+
}
|
|
154
|
+
api_url = self._client.api_url
|
|
155
|
+
if getattr(self._client, "allow_unauthenticated", False):
|
|
156
|
+
if "?" in api_url:
|
|
157
|
+
api_url += "&allow_unauthenticated=1"
|
|
158
|
+
else:
|
|
159
|
+
api_url += "?allow_unauthenticated=1"
|
|
160
|
+
files = {
|
|
161
|
+
"file": audio_file,
|
|
162
|
+
"model_id": (None, self._client.model_id),
|
|
163
|
+
"tag_audio_events": (None, "true" if self._client.tag_audio_events else "false"),
|
|
164
|
+
"diarize": (None, "true" if self._client.diarize else "false"),
|
|
165
|
+
}
|
|
166
|
+
if language:
|
|
167
|
+
files["language"] = (None, language)
|
|
168
|
+
response = requests.post(
|
|
169
|
+
api_url,
|
|
170
|
+
files=files,
|
|
171
|
+
headers=headers,
|
|
172
|
+
timeout=timeout or self._client.timeout,
|
|
173
|
+
proxies=proxies or getattr(self._client, "proxies", None),
|
|
174
|
+
stream=True,
|
|
175
|
+
)
|
|
176
|
+
if response.status_code != 200:
|
|
177
|
+
raise exceptions.FailedToGenerateResponseError(
|
|
178
|
+
f"ElevenLabs API returned error: {response.status_code} - {response.text}"
|
|
179
|
+
)
|
|
180
|
+
# Stream the response, decode utf-8
|
|
181
|
+
for line in response.iter_lines(decode_unicode=True):
|
|
182
|
+
if line:
|
|
183
|
+
yield line
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class ElevenLabsAudio(BaseSTTAudio):
|
|
187
|
+
"""ElevenLabs audio interface."""
|
|
188
|
+
|
|
189
|
+
def _create_transcriptions(self, client) -> ElevenLabsTranscriptions:
|
|
190
|
+
return ElevenLabsTranscriptions(client)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class ElevenLabsSTT(STTCompatibleProvider):
|
|
194
|
+
"""
|
|
195
|
+
OpenAI-compatible client for ElevenLabs STT API.
|
|
196
|
+
|
|
197
|
+
Usage:
|
|
198
|
+
client = ElevenLabsSTT()
|
|
199
|
+
audio_file = open("audio.mp3", "rb")
|
|
200
|
+
transcription = client.audio.transcriptions.create(
|
|
201
|
+
model="scribe_v1",
|
|
202
|
+
file=audio_file,
|
|
203
|
+
response_format="text"
|
|
204
|
+
)
|
|
205
|
+
print(transcription.text)
|
|
206
|
+
"""
|
|
207
|
+
|
|
208
|
+
AVAILABLE_MODELS = [
|
|
209
|
+
"scribe_v1",
|
|
210
|
+
]
|
|
211
|
+
|
|
212
|
+
def __init__(
|
|
213
|
+
self,
|
|
214
|
+
model_id: str = "scribe_v1",
|
|
215
|
+
allow_unauthenticated: bool = True,
|
|
216
|
+
tag_audio_events: bool = True,
|
|
217
|
+
diarize: bool = True,
|
|
218
|
+
timeout: int = 60,
|
|
219
|
+
proxies: Optional[dict] = None,
|
|
220
|
+
):
|
|
221
|
+
"""Initialize ElevenLabs STT provider."""
|
|
222
|
+
self.model_id = model_id
|
|
223
|
+
self.allow_unauthenticated = allow_unauthenticated
|
|
224
|
+
self.tag_audio_events = tag_audio_events
|
|
225
|
+
self.diarize = diarize
|
|
226
|
+
self.timeout = timeout
|
|
227
|
+
self.proxies = proxies
|
|
228
|
+
|
|
229
|
+
# API configuration
|
|
230
|
+
self.api_url = "https://api.elevenlabs.io/v1/speech-to-text"
|
|
231
|
+
|
|
232
|
+
# Initialize interfaces
|
|
233
|
+
self.audio = ElevenLabsAudio(self)
|
|
234
|
+
self._models = STTModels(self.AVAILABLE_MODELS)
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def models(self):
|
|
238
|
+
"""Get models interface."""
|
|
239
|
+
return self._models
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
if __name__ == "__main__":
|
|
243
|
+
from rich import print
|
|
244
|
+
|
|
245
|
+
client = ElevenLabsSTT()
|
|
246
|
+
|
|
247
|
+
# Example audio file path - replace with your own
|
|
248
|
+
audio_file_path = r"C:\Users\koula\Downloads\audio_2025-05-12_22-30-47.ogg"
|
|
249
|
+
|
|
250
|
+
print("=== Non-streaming example ===")
|
|
251
|
+
with open(audio_file_path, "rb") as audio_file:
|
|
252
|
+
transcription = client.audio.transcriptions.create(
|
|
253
|
+
model="scribe_v1", file=audio_file, stream=False
|
|
254
|
+
)
|
|
255
|
+
if hasattr(transcription, 'text'):
|
|
256
|
+
print(transcription.text)
|
|
257
|
+
|
|
258
|
+
print("\n=== Streaming example ===")
|
|
259
|
+
with open(audio_file_path, "rb") as audio_file:
|
|
260
|
+
stream_gen = client.audio.transcriptions.create(
|
|
261
|
+
model="scribe_v1", file=audio_file, stream=True
|
|
262
|
+
)
|
|
263
|
+
for chunk in cast(Generator[str, None, None], stream_gen):
|
|
264
|
+
print(chunk.strip())
|