@fudrouter/fsrouter 0.6.59 → 0.6.61
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.
- package/package.json +1 -1
- package/open-sse/AGENTS.md +0 -39
- package/open-sse/config/anthropicHeaders.js +0 -87
- package/open-sse/config/appConstants.js +0 -238
- package/open-sse/config/audioRegistry.js +0 -506
- package/open-sse/config/cliFingerprints.js +0 -304
- package/open-sse/config/codexInstructions.js +0 -119
- package/open-sse/config/codexQuotaScopes.js +0 -42
- package/open-sse/config/constants.js +0 -4
- package/open-sse/config/contextEditing.js +0 -68
- package/open-sse/config/credentialLoader.js +0 -83
- package/open-sse/config/defaultThinkingSignature.js +0 -12
- package/open-sse/config/embeddingRegistry.js +0 -264
- package/open-sse/config/errorConfig.js +0 -96
- package/open-sse/config/freeModelCatalog.data.js +0 -121
- package/open-sse/config/freeModelCatalog.js +0 -90
- package/open-sse/config/freeTierCatalog.js +0 -81
- package/open-sse/config/googleTtsLanguages.js +0 -62
- package/open-sse/config/imageParamDefs.js +0 -360
- package/open-sse/config/imageRegistry.js +0 -493
- package/open-sse/config/kiroConstants.js +0 -268
- package/open-sse/config/mediaConfig.js +0 -27
- package/open-sse/config/mediaServiceKinds.js +0 -71
- package/open-sse/config/models.js +0 -13
- package/open-sse/config/moderationRegistry.js +0 -71
- package/open-sse/config/musicRegistry.js +0 -99
- package/open-sse/config/ocrRegistry.js +0 -61
- package/open-sse/config/ollamaModels.js +0 -19
- package/open-sse/config/providerErrorRules.js +0 -114
- package/open-sse/config/providerFieldStrips.js +0 -35
- package/open-sse/config/providerHeaderProfiles.js +0 -191
- package/open-sse/config/providerModels.js +0 -106
- package/open-sse/config/providerRegistry.js +0 -16
- package/open-sse/config/providers.js +0 -19
- package/open-sse/config/registryUtils.js +0 -106
- package/open-sse/config/rerankRegistry.js +0 -177
- package/open-sse/config/runtimeConfig.js +0 -96
- package/open-sse/config/runway.js +0 -39
- package/open-sse/config/searchRegistry.js +0 -153
- package/open-sse/config/toolCloaking.js +0 -199
- package/open-sse/config/ttsModels.js +0 -129
- package/open-sse/config/videoRegistry.js +0 -207
- package/open-sse/executors/adapta-web.js +0 -435
- package/open-sse/executors/antigravity.js +0 -534
- package/open-sse/executors/antigravityUpstreamError.js +0 -13
- package/open-sse/executors/auggie.js +0 -437
- package/open-sse/executors/azure-openai.js +0 -32
- package/open-sse/executors/azure.js +0 -57
- package/open-sse/executors/base.js +0 -181
- package/open-sse/executors/bedrock.js +0 -633
- package/open-sse/executors/blackbox-web.js +0 -578
- package/open-sse/executors/chatgpt-web.js +0 -2042
- package/open-sse/executors/chipotle.js +0 -357
- package/open-sse/executors/claude-web-with-auto-refresh.js +0 -73
- package/open-sse/executors/claude-web.js +0 -586
- package/open-sse/executors/cliproxyapi.js +0 -296
- package/open-sse/executors/cloudflare-ai.js +0 -46
- package/open-sse/executors/codebuddy-cn.js +0 -40
- package/open-sse/executors/codex.js +0 -1324
- package/open-sse/executors/commandCode.js +0 -558
- package/open-sse/executors/commandcode.js +0 -88
- package/open-sse/executors/copilot-m365-connection.js +0 -176
- package/open-sse/executors/copilot-m365-frames.js +0 -192
- package/open-sse/executors/copilot-m365-web.js +0 -299
- package/open-sse/executors/copilot-web.js +0 -580
- package/open-sse/executors/cursor.js +0 -795
- package/open-sse/executors/deepseek-web-with-auto-refresh.js +0 -150
- package/open-sse/executors/deepseek-web.js +0 -875
- package/open-sse/executors/default.js +0 -430
- package/open-sse/executors/devin-cli.js +0 -351
- package/open-sse/executors/doubao-web.js +0 -550
- package/open-sse/executors/duckduckgo-web.js +0 -629
- package/open-sse/executors/forceResponsesUpstream.js +0 -33
- package/open-sse/executors/gemini-business.js +0 -320
- package/open-sse/executors/gemini-cli.js +0 -89
- package/open-sse/executors/gemini-web.js +0 -297
- package/open-sse/executors/github.js +0 -379
- package/open-sse/executors/gitlab.js +0 -569
- package/open-sse/executors/glm.js +0 -361
- package/open-sse/executors/grok-cli.js +0 -119
- package/open-sse/executors/grok-web.js +0 -345
- package/open-sse/executors/huggingchat.js +0 -467
- package/open-sse/executors/iflow.js +0 -108
- package/open-sse/executors/index.js +0 -78
- package/open-sse/executors/inner-ai.js +0 -527
- package/open-sse/executors/kimchi.js +0 -123
- package/open-sse/executors/kimi-web.js +0 -325
- package/open-sse/executors/kimi.js +0 -97
- package/open-sse/executors/kiro.js +0 -503
- package/open-sse/executors/kiroThinking.js +0 -44
- package/open-sse/executors/lmarena.js +0 -395
- package/open-sse/executors/mimo-free.js +0 -167
- package/open-sse/executors/mimocode.js +0 -392
- package/open-sse/executors/ninerouter.js +0 -155
- package/open-sse/executors/nlpcloud.js +0 -438
- package/open-sse/executors/ollama-local.js +0 -14
- package/open-sse/executors/opencode-go.js +0 -41
- package/open-sse/executors/opencode.js +0 -32
- package/open-sse/executors/perplexity-web.js +0 -581
- package/open-sse/executors/poe-web.js +0 -133
- package/open-sse/executors/pollinations.js +0 -95
- package/open-sse/executors/puter.js +0 -31
- package/open-sse/executors/qoder.js +0 -448
- package/open-sse/executors/qwen-web.js +0 -372
- package/open-sse/executors/qwen.js +0 -129
- package/open-sse/executors/t3-chat-web.js +0 -417
- package/open-sse/executors/theoldllm.js +0 -290
- package/open-sse/executors/trae.js +0 -418
- package/open-sse/executors/v0-vercel-web.js +0 -141
- package/open-sse/executors/venice-web.js +0 -142
- package/open-sse/executors/vertex.js +0 -131
- package/open-sse/executors/vertexMedia.js +0 -236
- package/open-sse/executors/windsurf.js +0 -560
- package/open-sse/executors/xai.js +0 -46
- package/open-sse/executors/xiaomi-tokenplan.js +0 -19
- package/open-sse/executors/yuanbao-web.js +0 -385
- package/open-sse/executors/zed-hosted.js +0 -281
- package/open-sse/executors/zenmux-free.js +0 -247
- package/open-sse/handlers/audioSpeech.js +0 -759
- package/open-sse/handlers/audioTranscription.js +0 -395
- package/open-sse/handlers/audioTranslation.js +0 -181
- package/open-sse/handlers/chatCore/nonStreamingHandler.js +0 -300
- package/open-sse/handlers/chatCore/requestDetail.js +0 -102
- package/open-sse/handlers/chatCore/sseToJsonHandler.js +0 -231
- package/open-sse/handlers/chatCore/streamingHandler.js +0 -95
- package/open-sse/handlers/chatCore.js +0 -404
- package/open-sse/handlers/embeddingProviders/_base.js +0 -4
- package/open-sse/handlers/embeddingProviders/gemini.js +0 -54
- package/open-sse/handlers/embeddingProviders/index.js +0 -23
- package/open-sse/handlers/embeddingProviders/openai.js +0 -39
- package/open-sse/handlers/embeddingProviders/openaiCompatNode.js +0 -13
- package/open-sse/handlers/embeddingsCore.js +0 -126
- package/open-sse/handlers/fetch/index.js +0 -237
- package/open-sse/handlers/imageGenerationCore.js +0 -230
- package/open-sse/handlers/imageProviders/_base.js +0 -31
- package/open-sse/handlers/imageProviders/antigravity.js +0 -73
- package/open-sse/handlers/imageProviders/blackForestLabs.js +0 -63
- package/open-sse/handlers/imageProviders/cloudflareAi.js +0 -207
- package/open-sse/handlers/imageProviders/codex.js +0 -217
- package/open-sse/handlers/imageProviders/comfyui.js +0 -25
- package/open-sse/handlers/imageProviders/falAi.js +0 -62
- package/open-sse/handlers/imageProviders/gemini.js +0 -40
- package/open-sse/handlers/imageProviders/huggingface.js +0 -38
- package/open-sse/handlers/imageProviders/index.js +0 -44
- package/open-sse/handlers/imageProviders/leonardo.js +0 -435
- package/open-sse/handlers/imageProviders/nanobanana.js +0 -79
- package/open-sse/handlers/imageProviders/openai.js +0 -61
- package/open-sse/handlers/imageProviders/runwayml.js +0 -72
- package/open-sse/handlers/imageProviders/sdwebui.js +0 -36
- package/open-sse/handlers/imageProviders/stabilityAi.js +0 -59
- package/open-sse/handlers/imageProviders/weavy.js +0 -222
- package/open-sse/handlers/moderations.js +0 -92
- package/open-sse/handlers/ocr.js +0 -89
- package/open-sse/handlers/rerank.js +0 -223
- package/open-sse/handlers/responseSanitizer/reasoning.js +0 -144
- package/open-sse/handlers/responsesHandler.js +0 -99
- package/open-sse/handlers/search/callers.js +0 -371
- package/open-sse/handlers/search/chatSearch.js +0 -409
- package/open-sse/handlers/search/index.js +0 -201
- package/open-sse/handlers/search/normalizers.js +0 -223
- package/open-sse/handlers/search.js +0 -1056
- package/open-sse/handlers/sseParser.js +0 -469
- package/open-sse/handlers/sttCore.js +0 -193
- package/open-sse/handlers/ttsCore.js +0 -74
- package/open-sse/handlers/ttsProviders/_base.js +0 -39
- package/open-sse/handlers/ttsProviders/edgeTts.js +0 -89
- package/open-sse/handlers/ttsProviders/elevenlabs.js +0 -48
- package/open-sse/handlers/ttsProviders/gemini.js +0 -117
- package/open-sse/handlers/ttsProviders/genericFormats.js +0 -169
- package/open-sse/handlers/ttsProviders/googleTts.js +0 -54
- package/open-sse/handlers/ttsProviders/index.js +0 -50
- package/open-sse/handlers/ttsProviders/localDevice.js +0 -87
- package/open-sse/handlers/ttsProviders/minimax.js +0 -59
- package/open-sse/handlers/ttsProviders/openai.js +0 -30
- package/open-sse/handlers/ttsProviders/openrouter.js +0 -70
- package/open-sse/handlers/usageExtractor.js +0 -93
- package/open-sse/handlers/videoGenerationCore.js +0 -119
- package/open-sse/handlers/videoProviders/index.js +0 -22
- package/open-sse/handlers/videoProviders/leonardo.js +0 -511
- package/open-sse/handlers/videoProviders/weavy.js +0 -198
- package/open-sse/handlers/webFetch.js +0 -200
- package/open-sse/index.js +0 -79
- package/open-sse/mcp-server/audit.js +0 -283
- package/open-sse/mcp-server/catalog.js +0 -184
- package/open-sse/mcp-server/descriptionCompressor.js +0 -175
- package/open-sse/mcp-server/httpAuthContext.js +0 -32
- package/open-sse/mcp-server/httpTransport.js +0 -229
- package/open-sse/mcp-server/index.js +0 -33
- package/open-sse/mcp-server/mcpCallerIdentity.js +0 -21
- package/open-sse/mcp-server/runtimeHeartbeat.js +0 -110
- package/open-sse/mcp-server/schemas/a2a.js +0 -153
- package/open-sse/mcp-server/schemas/audit.js +0 -17
- package/open-sse/mcp-server/schemas/index.js +0 -166
- package/open-sse/mcp-server/schemas/pickFastestModel.js +0 -90
- package/open-sse/mcp-server/schemas/toolDefinition.js +0 -0
- package/open-sse/mcp-server/schemas/toolSearch.js +0 -32
- package/open-sse/mcp-server/schemas/tools.js +0 -1219
- package/open-sse/mcp-server/scopeEnforcement.js +0 -80
- package/open-sse/mcp-server/server.js +0 -1168
- package/open-sse/mcp-server/toolCardinality.js +0 -78
- package/open-sse/mcp-server/toolSearch/catalog.js +0 -66
- package/open-sse/mcp-server/toolSearch/handler.js +0 -20
- package/open-sse/mcp-server/toolSearch/index.js +0 -10
- package/open-sse/mcp-server/toolSearch/register.js +0 -21
- package/open-sse/mcp-server/toolSearch/search.js +0 -55
- package/open-sse/mcp-server/toolSearch/signature.js +0 -67
- package/open-sse/mcp-server/tools/advancedTools.js +0 -893
- package/open-sse/mcp-server/tools/agentSkillTools.js +0 -69
- package/open-sse/mcp-server/tools/compressionTools.js +0 -309
- package/open-sse/mcp-server/tools/gamificationTools.js +0 -134
- package/open-sse/mcp-server/tools/githubSkillTools.js +0 -102
- package/open-sse/mcp-server/tools/memoryTools.js +0 -118
- package/open-sse/mcp-server/tools/notionTools.js +0 -101
- package/open-sse/mcp-server/tools/obsidianTools.js +0 -307
- package/open-sse/mcp-server/tools/pickFastestModel.js +0 -223
- package/open-sse/mcp-server/tools/pluginTools.js +0 -181
- package/open-sse/mcp-server/tools/poolTools.js +0 -139
- package/open-sse/mcp-server/tools/skillTools.js +0 -113
- package/open-sse/package.json +0 -10
- package/open-sse/providers/REGISTRY_TEMPLATE.js +0 -98
- package/open-sse/providers/capabilities.js +0 -293
- package/open-sse/providers/index.js +0 -51
- package/open-sse/providers/models/helpers.js +0 -20
- package/open-sse/providers/models/namePatterns.js +0 -33
- package/open-sse/providers/models/schema.js +0 -40
- package/open-sse/providers/pricing.js +0 -308
- package/open-sse/providers/registry/alicode-intl.js +0 -30
- package/open-sse/providers/registry/alicode.js +0 -31
- package/open-sse/providers/registry/anthropic.js +0 -37
- package/open-sse/providers/registry/antigravity.js +0 -81
- package/open-sse/providers/registry/assemblyai.js +0 -38
- package/open-sse/providers/registry/aws-polly.js +0 -45
- package/open-sse/providers/registry/azure.js +0 -21
- package/open-sse/providers/registry/black-forest-labs.js +0 -32
- package/open-sse/providers/registry/blackbox.js +0 -41
- package/open-sse/providers/registry/brave-search.js +0 -35
- package/open-sse/providers/registry/byteplus.js +0 -35
- package/open-sse/providers/registry/cartesia.js +0 -36
- package/open-sse/providers/registry/cerebras.js +0 -31
- package/open-sse/providers/registry/chutes.js +0 -24
- package/open-sse/providers/registry/claude.js +0 -87
- package/open-sse/providers/registry/cline.js +0 -51
- package/open-sse/providers/registry/clinepass.js +0 -57
- package/open-sse/providers/registry/cloudflare-ai.js +0 -55
- package/open-sse/providers/registry/codebuddy-cn.js +0 -77
- package/open-sse/providers/registry/codex.js +0 -100
- package/open-sse/providers/registry/cohere.js +0 -27
- package/open-sse/providers/registry/comfyui.js +0 -20
- package/open-sse/providers/registry/commandcode.js +0 -43
- package/open-sse/providers/registry/coqui.js +0 -30
- package/open-sse/providers/registry/cursor.js +0 -58
- package/open-sse/providers/registry/deepgram.js +0 -33
- package/open-sse/providers/registry/deepseek.js +0 -51
- package/open-sse/providers/registry/digitalocean.js +0 -92
- package/open-sse/providers/registry/edge-tts.js +0 -24
- package/open-sse/providers/registry/elevenlabs.js +0 -35
- package/open-sse/providers/registry/exa.js +0 -50
- package/open-sse/providers/registry/fal-ai.js +0 -34
- package/open-sse/providers/registry/featherless.js +0 -34
- package/open-sse/providers/registry/firecrawl.js +0 -34
- package/open-sse/providers/registry/fireworks.js +0 -29
- package/open-sse/providers/registry/gemini-cli.js +0 -58
- package/open-sse/providers/registry/gemini.js +0 -83
- package/open-sse/providers/registry/github.js +0 -88
- package/open-sse/providers/registry/gitlab.js +0 -32
- package/open-sse/providers/registry/glm-cn.js +0 -35
- package/open-sse/providers/registry/glm.js +0 -58
- package/open-sse/providers/registry/google-pse.js +0 -35
- package/open-sse/providers/registry/google-tts.js +0 -24
- package/open-sse/providers/registry/grok-cli.js +0 -86
- package/open-sse/providers/registry/grok-web.js +0 -39
- package/open-sse/providers/registry/groq.js +0 -37
- package/open-sse/providers/registry/huggingface.js +0 -34
- package/open-sse/providers/registry/hyperbolic.js +0 -35
- package/open-sse/providers/registry/ibm-bob.js +0 -27
- package/open-sse/providers/registry/iflow.js +0 -52
- package/open-sse/providers/registry/index.js +0 -210
- package/open-sse/providers/registry/inworld.js +0 -36
- package/open-sse/providers/registry/jina-ai.js +0 -42
- package/open-sse/providers/registry/jina-reader.js +0 -34
- package/open-sse/providers/registry/kilocode.js +0 -51
- package/open-sse/providers/registry/kimchi.js +0 -49
- package/open-sse/providers/registry/kimi-coding.js +0 -65
- package/open-sse/providers/registry/kimi.js +0 -56
- package/open-sse/providers/registry/kiro.js +0 -115
- package/open-sse/providers/registry/linkup.js +0 -34
- package/open-sse/providers/registry/local-device.js +0 -24
- package/open-sse/providers/registry/mimo-free.js +0 -24
- package/open-sse/providers/registry/minimax-cn.js +0 -76
- package/open-sse/providers/registry/minimax.js +0 -83
- package/open-sse/providers/registry/mistral.js +0 -34
- package/open-sse/providers/registry/mmf.js +0 -19
- package/open-sse/providers/registry/nanobanana.js +0 -35
- package/open-sse/providers/registry/nebius.js +0 -27
- package/open-sse/providers/registry/nvidia.js +0 -43
- package/open-sse/providers/registry/ollama-local.js +0 -19
- package/open-sse/providers/registry/ollama.js +0 -36
- package/open-sse/providers/registry/openai.js +0 -84
- package/open-sse/providers/registry/opencode-go.js +0 -41
- package/open-sse/providers/registry/opencode.js +0 -25
- package/open-sse/providers/registry/openrouter.js +0 -60
- package/open-sse/providers/registry/perplexity-agent.js +0 -49
- package/open-sse/providers/registry/perplexity-web.js +0 -33
- package/open-sse/providers/registry/perplexity.js +0 -37
- package/open-sse/providers/registry/playht.js +0 -36
- package/open-sse/providers/registry/qoder.js +0 -54
- package/open-sse/providers/registry/qwen.js +0 -33
- package/open-sse/providers/registry/recraft.js +0 -24
- package/open-sse/providers/registry/runwayml.js +0 -30
- package/open-sse/providers/registry/sdwebui.js +0 -20
- package/open-sse/providers/registry/searchapi.js +0 -35
- package/open-sse/providers/registry/searxng.js +0 -35
- package/open-sse/providers/registry/serper.js +0 -35
- package/open-sse/providers/registry/siliconflow.js +0 -39
- package/open-sse/providers/registry/stability-ai.js +0 -31
- package/open-sse/providers/registry/tavily.js +0 -50
- package/open-sse/providers/registry/together.js +0 -31
- package/open-sse/providers/registry/topaz.js +0 -19
- package/open-sse/providers/registry/tortoise.js +0 -30
- package/open-sse/providers/registry/venice.js +0 -56
- package/open-sse/providers/registry/vercel-ai-gateway.js +0 -41
- package/open-sse/providers/registry/vertex-partner.js +0 -29
- package/open-sse/providers/registry/vertex.js +0 -32
- package/open-sse/providers/registry/volcengine-ark.js +0 -35
- package/open-sse/providers/registry/voyage-ai.js +0 -30
- package/open-sse/providers/registry/xai.js +0 -45
- package/open-sse/providers/registry/xiaomi-mimo.js +0 -46
- package/open-sse/providers/registry/xiaomi-tokenplan.js +0 -63
- package/open-sse/providers/registry/youcom.js +0 -35
- package/open-sse/providers/schema.js +0 -76
- package/open-sse/providers/shared.js +0 -74
- package/open-sse/providers/thinkingLevels.js +0 -48
- package/open-sse/rtk/applyFilter.js +0 -15
- package/open-sse/rtk/autodetect.js +0 -111
- package/open-sse/rtk/caveman.js +0 -100
- package/open-sse/rtk/cavemanPrompts.js +0 -78
- package/open-sse/rtk/constants.js +0 -55
- package/open-sse/rtk/filters/buildOutput.js +0 -127
- package/open-sse/rtk/filters/dedupLog.js +0 -44
- package/open-sse/rtk/filters/find.js +0 -50
- package/open-sse/rtk/filters/gitDiff.js +0 -92
- package/open-sse/rtk/filters/gitLog.js +0 -99
- package/open-sse/rtk/filters/gitStatus.js +0 -117
- package/open-sse/rtk/filters/grep.js +0 -48
- package/open-sse/rtk/filters/ls.js +0 -79
- package/open-sse/rtk/filters/readNumbered.js +0 -27
- package/open-sse/rtk/filters/searchList.js +0 -52
- package/open-sse/rtk/filters/smartTruncate.js +0 -15
- package/open-sse/rtk/filters/tree.js +0 -32
- package/open-sse/rtk/headroom.js +0 -215
- package/open-sse/rtk/index.js +0 -155
- package/open-sse/rtk/paleo.js +0 -47
- package/open-sse/rtk/ponytail.js +0 -9
- package/open-sse/rtk/ponytailPrompt.js +0 -52
- package/open-sse/rtk/ponytailPrompts.js +0 -76
- package/open-sse/rtk/pxpipe.js +0 -104
- package/open-sse/rtk/registry.js +0 -38
- package/open-sse/rtk/systemInject.js +0 -98
- package/open-sse/services/accountFallback.js +0 -323
- package/open-sse/services/antigravityHeaders.js +0 -91
- package/open-sse/services/antigravityVersion.js +0 -154
- package/open-sse/services/clinepassModels.js +0 -63
- package/open-sse/services/codexQuotaFetcher.js +0 -312
- package/open-sse/services/codexVerbosity.js +0 -30
- package/open-sse/services/combo/context.js +0 -12
- package/open-sse/services/combo/fingerprintExpansion.js +0 -51
- package/open-sse/services/combo/headroomRanking.js +0 -28
- package/open-sse/services/combo/quotaExhaustionCutoff.js +0 -87
- package/open-sse/services/combo/quotaScoring.js +0 -226
- package/open-sse/services/combo/quotaShareConcurrency.js +0 -25
- package/open-sse/services/combo/quotaShareInflight.js +0 -50
- package/open-sse/services/combo/quotaShareStrategy.js +0 -130
- package/open-sse/services/combo/resolveAutoStrategy.js +0 -231
- package/open-sse/services/combo/responseValidation.js +0 -140
- package/open-sse/services/combo/runtimeUnits.js +0 -195
- package/open-sse/services/combo/sessionStickiness.js +0 -128
- package/open-sse/services/combo/shadowRouting.js +0 -131
- package/open-sse/services/combo/targetExhaustion.js +0 -75
- package/open-sse/services/combo/targetSorters.js +0 -126
- package/open-sse/services/combo/targetTimeoutRunner.js +0 -65
- package/open-sse/services/combo/validateQuality.js +0 -271
- package/open-sse/services/combo.js +0 -571
- package/open-sse/services/comboAgentMiddleware.js +0 -91
- package/open-sse/services/comboConfig.js +0 -153
- package/open-sse/services/comboManifestMetrics.js +0 -10
- package/open-sse/services/comboMetrics.js +0 -278
- package/open-sse/services/compact.js +0 -71
- package/open-sse/services/copilotModels.js +0 -155
- package/open-sse/services/emergencyFallback.js +0 -109
- package/open-sse/services/errorClassifier.js +0 -190
- package/open-sse/services/evalRouting.js +0 -201
- package/open-sse/services/freeWebSearch.js +0 -4
- package/open-sse/services/fusion.js +0 -223
- package/open-sse/services/intentClassifier.js +0 -631
- package/open-sse/services/kimchiModels.js +0 -176
- package/open-sse/services/kiroModels.js +0 -332
- package/open-sse/services/model.js +0 -136
- package/open-sse/services/modelCapabilities.js +0 -5
- package/open-sse/services/modelDeprecation.js +0 -101
- package/open-sse/services/modelFamilyFallback.js +0 -166
- package/open-sse/services/oauthCredentialManager.js +0 -156
- package/open-sse/services/pipeline.js +0 -107
- package/open-sse/services/projectId.js +0 -306
- package/open-sse/services/provider.js +0 -169
- package/open-sse/services/providerCooldownTracker.js +0 -94
- package/open-sse/services/providerDefaultRateLimit.js +0 -11
- package/open-sse/services/proxyAutoSelector.js +0 -24
- package/open-sse/services/qoderModels.js +0 -214
- package/open-sse/services/quotaFetchThrottle.js +0 -103
- package/open-sse/services/quotaMonitor.js +0 -310
- package/open-sse/services/quotaPreflight.js +0 -266
- package/open-sse/services/rateLimitManager/headers.js +0 -56
- package/open-sse/services/rateLimitManager.js +0 -616
- package/open-sse/services/rateLimitSemaphore.js +0 -112
- package/open-sse/services/responsesInputSanitizer.js +0 -99
- package/open-sse/services/slidingWindowLimiter.js +0 -44
- package/open-sse/services/streamRecovery.js +0 -355
- package/open-sse/services/taskAwareRouter.js +0 -227
- package/open-sse/services/taskAwareRouting.js +0 -332
- package/open-sse/services/thinkingBudget.js +0 -247
- package/open-sse/services/tokenRefresh/dedup.js +0 -31
- package/open-sse/services/tokenRefresh/providers.js +0 -624
- package/open-sse/services/tokenRefresh.js +0 -254
- package/open-sse/services/usage/claude.js +0 -147
- package/open-sse/services/usage/codebuddy-cn.js +0 -138
- package/open-sse/services/usage/codex.js +0 -267
- package/open-sse/services/usage/github.js +0 -100
- package/open-sse/services/usage/google.js +0 -241
- package/open-sse/services/usage/grok-cli.js +0 -274
- package/open-sse/services/usage/kiro.js +0 -188
- package/open-sse/services/usage/minimax.js +0 -234
- package/open-sse/services/usage/misc.js +0 -288
- package/open-sse/services/usage/shared.js +0 -70
- package/open-sse/services/usage.js +0 -62
- package/open-sse/services/usageDb.js +0 -2
- package/open-sse/services/webSearchRouting.js +0 -25
- package/open-sse/services/wildcardRouter.js +0 -59
- package/open-sse/shared/clineAuth.js +0 -37
- package/open-sse/shared/machineId.js +0 -19
- package/open-sse/shared/qoder/constants.js +0 -64
- package/open-sse/shared/qoder/cosy.js +0 -175
- package/open-sse/shared/qoder/encoding.js +0 -55
- package/open-sse/transformer/responsesTransformer.js +0 -439
- package/open-sse/transformer/streamToJsonConverter.js +0 -103
- package/open-sse/translator/concerns/chunk.js +0 -11
- package/open-sse/translator/concerns/finishReason.js +0 -63
- package/open-sse/translator/concerns/image.js +0 -124
- package/open-sse/translator/concerns/json.js +0 -5
- package/open-sse/translator/concerns/message.js +0 -7
- package/open-sse/translator/concerns/modality.js +0 -155
- package/open-sse/translator/concerns/paramSupport.js +0 -75
- package/open-sse/translator/concerns/prefetch.js +0 -96
- package/open-sse/translator/concerns/reasoning.js +0 -24
- package/open-sse/translator/concerns/thinking.js +0 -53
- package/open-sse/translator/concerns/thinkingUnified.js +0 -329
- package/open-sse/translator/concerns/toolCall.js +0 -153
- package/open-sse/translator/concerns/usage.js +0 -69
- package/open-sse/translator/formats/claude.js +0 -368
- package/open-sse/translator/formats/gemini.js +0 -380
- package/open-sse/translator/formats/maxTokens.js +0 -34
- package/open-sse/translator/formats/openai.js +0 -134
- package/open-sse/translator/formats/responsesApi.js +0 -141
- package/open-sse/translator/formats.js +0 -36
- package/open-sse/translator/helpers/claudeHelper.js +0 -216
- package/open-sse/translator/helpers/geminiHelper.js +0 -372
- package/open-sse/translator/helpers/imageHelper.js +0 -34
- package/open-sse/translator/helpers/maxTokensHelper.js +0 -27
- package/open-sse/translator/helpers/openaiHelper.js +0 -130
- package/open-sse/translator/helpers/responsesApiHelper.js +0 -139
- package/open-sse/translator/helpers/toolCallHelper.js +0 -148
- package/open-sse/translator/index.js +0 -252
- package/open-sse/translator/request/antigravity-to-openai.js +0 -242
- package/open-sse/translator/request/claude-to-kiro.js +0 -478
- package/open-sse/translator/request/claude-to-openai.js +0 -263
- package/open-sse/translator/request/gemini-to-openai.js +0 -152
- package/open-sse/translator/request/openai-responses.js +0 -385
- package/open-sse/translator/request/openai-to-claude.js +0 -383
- package/open-sse/translator/request/openai-to-commandcode.js +0 -176
- package/open-sse/translator/request/openai-to-cursor.js +0 -185
- package/open-sse/translator/request/openai-to-gemini.js +0 -442
- package/open-sse/translator/request/openai-to-kiro.js +0 -607
- package/open-sse/translator/request/openai-to-kiro.old.js +0 -278
- package/open-sse/translator/request/openai-to-ollama.js +0 -195
- package/open-sse/translator/request/openai-to-vertex.js +0 -42
- package/open-sse/translator/response/claude-to-openai.js +0 -195
- package/open-sse/translator/response/commandcode-to-openai.js +0 -188
- package/open-sse/translator/response/cursor-to-openai.js +0 -30
- package/open-sse/translator/response/gemini-to-openai.js +0 -147
- package/open-sse/translator/response/kiro-to-claude.js +0 -261
- package/open-sse/translator/response/kiro-to-openai.js +0 -160
- package/open-sse/translator/response/ollama-to-openai.js +0 -134
- package/open-sse/translator/response/openai-responses.js +0 -535
- package/open-sse/translator/response/openai-to-antigravity.js +0 -123
- package/open-sse/translator/response/openai-to-claude.js +0 -265
- package/open-sse/translator/schema/blocks.js +0 -43
- package/open-sse/translator/schema/defaults.js +0 -7
- package/open-sse/translator/schema/finishReasons.js +0 -27
- package/open-sse/translator/schema/index.js +0 -8
- package/open-sse/translator/schema/roles.js +0 -16
- package/open-sse/utils/agentGoalPolicy.js +0 -85
- package/open-sse/utils/aiSdkCompat.js +0 -75
- package/open-sse/utils/bypassHandler.js +0 -298
- package/open-sse/utils/cacheControlPolicy.js +0 -189
- package/open-sse/utils/claudeCloaking.js +0 -155
- package/open-sse/utils/claudeHeaderCache.js +0 -70
- package/open-sse/utils/claudeSignature.js +0 -41
- package/open-sse/utils/clientDetector.js +0 -63
- package/open-sse/utils/codebuddySanitizer.js +0 -96
- package/open-sse/utils/composerToolCalls.js +0 -158
- package/open-sse/utils/cors.js +0 -13
- package/open-sse/utils/cursorChecksum.js +0 -149
- package/open-sse/utils/cursorImages.js +0 -224
- package/open-sse/utils/cursorProtobuf.js +0 -904
- package/open-sse/utils/cursorVersionDetector.js +0 -55
- package/open-sse/utils/debugLog.js +0 -14
- package/open-sse/utils/diagnostics.js +0 -143
- package/open-sse/utils/error.js +0 -164
- package/open-sse/utils/estimateSize.js +0 -33
- package/open-sse/utils/finishReason.js +0 -32
- package/open-sse/utils/flattenToolHistory.js +0 -68
- package/open-sse/utils/headers.js +0 -36
- package/open-sse/utils/heapPressure.js +0 -35
- package/open-sse/utils/jsonToSse.js +0 -125
- package/open-sse/utils/keepaliveThreshold.js +0 -40
- package/open-sse/utils/logger.js +0 -104
- package/open-sse/utils/noThinkingAlias.js +0 -74
- package/open-sse/utils/number.js +0 -7
- package/open-sse/utils/ollamaTransform.js +0 -85
- package/open-sse/utils/opencodeHeaders.js +0 -47
- package/open-sse/utils/progressTracker.js +0 -81
- package/open-sse/utils/providerRequestLogging.js +0 -219
- package/open-sse/utils/proxyFetch.js +0 -369
- package/open-sse/utils/reasoningContentInjector.js +0 -79
- package/open-sse/utils/reasoningFields.js +0 -70
- package/open-sse/utils/requestLogger.js +0 -260
- package/open-sse/utils/responsesInputNormalization.js +0 -92
- package/open-sse/utils/responsesStatePolicy.js +0 -52
- package/open-sse/utils/responsesStreamHelpers.js +0 -49
- package/open-sse/utils/sessionManager.js +0 -240
- package/open-sse/utils/sleep.js +0 -6
- package/open-sse/utils/sse.js +0 -14
- package/open-sse/utils/sseConstants.js +0 -23
- package/open-sse/utils/sseHeartbeat.js +0 -104
- package/open-sse/utils/stream.js +0 -517
- package/open-sse/utils/streamFailureFinalization.js +0 -134
- package/open-sse/utils/streamHandler.js +0 -250
- package/open-sse/utils/streamHelpers.js +0 -137
- package/open-sse/utils/textualToolCall.js +0 -104
- package/open-sse/utils/thinkCloseMarker.js +0 -72
- package/open-sse/utils/thinkTagParser.js +0 -146
- package/open-sse/utils/toolCallArguments.js +0 -12
- package/open-sse/utils/toolDeduper.js +0 -49
- package/open-sse/utils/toolSources.js +0 -31
- package/open-sse/utils/upstreamResponseHeaders.js +0 -25
- package/open-sse/utils/urlSanitize.js +0 -15
- package/open-sse/utils/usageTracking.js +0 -347
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { Buffer } from "node:buffer";
|
|
2
|
-
import { createErrorResult } from "../utils/error.js";
|
|
3
|
-
import { HTTP_STATUS } from "../config/runtimeConfig.js";
|
|
4
|
-
import { getTtsAdapter, synthesizeViaConfig } from "./ttsProviders/index.js";
|
|
5
|
-
|
|
6
|
-
// Re-export voice fetchers + voices APIs for backward compat with existing routes
|
|
7
|
-
export {
|
|
8
|
-
VOICE_FETCHERS,
|
|
9
|
-
fetchEdgeTtsVoices,
|
|
10
|
-
fetchLocalDeviceVoices,
|
|
11
|
-
fetchElevenLabsVoices,
|
|
12
|
-
} from "./ttsProviders/index.js";
|
|
13
|
-
|
|
14
|
-
// ── Response Formatter (DRY) ───────────────────────────────────
|
|
15
|
-
function createTtsResponse(base64Audio, format, responseFormat) {
|
|
16
|
-
const audioBuffer = Buffer.from(base64Audio, "base64");
|
|
17
|
-
|
|
18
|
-
// JSON format: return base64 encoded audio
|
|
19
|
-
if (responseFormat === "json") {
|
|
20
|
-
return {
|
|
21
|
-
success: true,
|
|
22
|
-
response: new Response(JSON.stringify({ audio: base64Audio, format }), {
|
|
23
|
-
headers: {
|
|
24
|
-
"Content-Type": "application/json",
|
|
25
|
-
"Access-Control-Allow-Origin": "*",
|
|
26
|
-
},
|
|
27
|
-
}),
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Binary format (default): return raw audio
|
|
32
|
-
return {
|
|
33
|
-
success: true,
|
|
34
|
-
response: new Response(audioBuffer, {
|
|
35
|
-
headers: {
|
|
36
|
-
"Content-Type": `audio/${format}`,
|
|
37
|
-
"Content-Length": String(audioBuffer.length),
|
|
38
|
-
"Access-Control-Allow-Origin": "*",
|
|
39
|
-
},
|
|
40
|
-
}),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// ── Core handler ───────────────────────────────────────────────
|
|
45
|
-
/**
|
|
46
|
-
* Synthesize text to audio. Provider logic lives in `./ttsProviders/{id}.js`
|
|
47
|
-
* or is dispatched generically via `ttsConfig.format`.
|
|
48
|
-
*
|
|
49
|
-
* @returns {Promise<{success, response, status?, error?}>}
|
|
50
|
-
*/
|
|
51
|
-
export async function handleTtsCore({ provider, model, input, credentials, responseFormat = "mp3", language }) {
|
|
52
|
-
if (!input?.trim()) {
|
|
53
|
-
return createErrorResult(HTTP_STATUS.BAD_REQUEST, "Missing required field: input");
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
// Special-case adapters (google-tts, edge-tts, local-device, elevenlabs, openai, openrouter, gemini)
|
|
58
|
-
const adapter = getTtsAdapter(provider);
|
|
59
|
-
if (adapter) {
|
|
60
|
-
const result = await adapter.synthesize(input.trim(), model, credentials, responseFormat, { language });
|
|
61
|
-
// Adapter may return a full {success, response} (legacy) or {base64, format}
|
|
62
|
-
if (result.success !== undefined) return result;
|
|
63
|
-
return createTtsResponse(result.base64, result.format, responseFormat);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Generic config-driven (hyperbolic, deepgram, nvidia, huggingface, inworld, cartesia, playht, coqui, tortoise, qwen, ...)
|
|
67
|
-
const result = await synthesizeViaConfig(provider, input.trim(), model, credentials);
|
|
68
|
-
if (result) return createTtsResponse(result.base64, result.format, responseFormat);
|
|
69
|
-
|
|
70
|
-
return createErrorResult(HTTP_STATUS.BAD_REQUEST, `Provider '${provider}' does not support TTS via this route.`);
|
|
71
|
-
} catch (err) {
|
|
72
|
-
return createErrorResult(HTTP_STATUS.BAD_GATEWAY, err.message || "TTS synthesis failed");
|
|
73
|
-
}
|
|
74
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// Shared TTS helpers
|
|
2
|
-
import { Buffer } from "node:buffer";
|
|
3
|
-
|
|
4
|
-
export const UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
|
|
5
|
-
|
|
6
|
-
// Convert upstream Response (binary audio) to { base64, format }
|
|
7
|
-
export async function responseToBase64(res, defaultFormat = "mp3") {
|
|
8
|
-
const buf = await res.arrayBuffer();
|
|
9
|
-
if (buf.byteLength < 100) throw new Error("Upstream returned empty audio");
|
|
10
|
-
const ctype = res.headers.get("content-type") || "";
|
|
11
|
-
let format = defaultFormat;
|
|
12
|
-
if (ctype.includes("wav")) format = "wav";
|
|
13
|
-
else if (ctype.includes("mpeg") || ctype.includes("mp3")) format = "mp3";
|
|
14
|
-
else if (ctype.includes("ogg")) format = "ogg";
|
|
15
|
-
return { base64: Buffer.from(buf).toString("base64"), format };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export async function throwUpstreamError(res) {
|
|
19
|
-
const text = await res.text().catch(() => "");
|
|
20
|
-
let msg = `Upstream error (${res.status})`;
|
|
21
|
-
try {
|
|
22
|
-
const parsed = JSON.parse(text);
|
|
23
|
-
msg = parsed?.error?.message || parsed?.message || parsed?.detail?.message || (typeof parsed?.detail === "string" ? parsed.detail : null) || text || msg;
|
|
24
|
-
} catch { msg = text || msg; }
|
|
25
|
-
throw new Error(msg);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Parse `model` string as "modelId/voiceId" — match against known model list (longest prefix wins)
|
|
29
|
-
export function parseModelVoice(model, defaultModel = "", defaultVoice = "", knownModels = []) {
|
|
30
|
-
if (!model) return { modelId: defaultModel, voiceId: defaultVoice };
|
|
31
|
-
const known = knownModels.map((m) => m.id || m).filter(Boolean).sort((a, b) => b.length - a.length);
|
|
32
|
-
for (const id of known) {
|
|
33
|
-
if (model === id) return { modelId: id, voiceId: defaultVoice };
|
|
34
|
-
if (model.startsWith(`${id}/`)) return { modelId: id, voiceId: model.slice(id.length + 1) };
|
|
35
|
-
}
|
|
36
|
-
const idx = model.lastIndexOf("/");
|
|
37
|
-
if (idx > 0) return { modelId: model.slice(0, idx), voiceId: model.slice(idx + 1) };
|
|
38
|
-
return { modelId: defaultModel || model, voiceId: defaultVoice || model };
|
|
39
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
// Microsoft Edge / Bing TTS (no auth) — via Bing translator endpoint
|
|
2
|
-
import { Buffer } from "node:buffer";
|
|
3
|
-
import { UA } from "./_base.js";
|
|
4
|
-
|
|
5
|
-
const REFRESH_MS = 5 * 60 * 1000; // token TTL ~1h, refresh early
|
|
6
|
-
const VOICES_TTL = 24 * 60 * 60 * 1000;
|
|
7
|
-
|
|
8
|
-
const cache = { token: null, tokenTime: 0 };
|
|
9
|
-
let _voicesCache = null;
|
|
10
|
-
let _voicesCacheTime = 0;
|
|
11
|
-
|
|
12
|
-
async function getToken() {
|
|
13
|
-
const now = Date.now();
|
|
14
|
-
if (cache.token && now - cache.tokenTime < REFRESH_MS) return cache.token;
|
|
15
|
-
const res = await fetch("https://www.bing.com/translator", {
|
|
16
|
-
headers: { "User-Agent": UA, "Accept-Language": "vi,en-US;q=0.9,en;q=0.8" },
|
|
17
|
-
});
|
|
18
|
-
if (!res.ok) throw new Error(`Bing translator fetch failed: ${res.status}`);
|
|
19
|
-
const rawCookies = res.headers.getSetCookie?.() || [];
|
|
20
|
-
const cookie = rawCookies.map((c) => c.split(";")[0]).join("; ");
|
|
21
|
-
const html = await res.text();
|
|
22
|
-
const match = html.match(/params_AbusePreventionHelper\s*=\s*\[([^,]+),([^,]+),/);
|
|
23
|
-
if (!match) throw new Error("Failed to parse Bing token");
|
|
24
|
-
cache.token = { key: match[1], token: match[2].replace(/"/g, ""), cookie };
|
|
25
|
-
cache.tokenTime = now;
|
|
26
|
-
return cache.token;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function ttsRequest(text, voiceId, token) {
|
|
30
|
-
const parts = voiceId.split("-");
|
|
31
|
-
const xmlLang = parts.slice(0, 2).join("-");
|
|
32
|
-
const gender = voiceId.toLowerCase().includes("male") ? "Male" : "Female";
|
|
33
|
-
const ssml = `<speak version='1.0' xml:lang='${xmlLang}'><voice xml:lang='${xmlLang}' xml:gender='${gender}' name='${voiceId}'><prosody rate='0.00%'>${text}</prosody></voice></speak>`;
|
|
34
|
-
const body = new URLSearchParams();
|
|
35
|
-
body.append("ssml", ssml);
|
|
36
|
-
body.append("token", token.token);
|
|
37
|
-
body.append("key", token.key);
|
|
38
|
-
return fetch("https://www.bing.com/tfettts?isVertical=1&&IG=1&IID=translator.5023&SFX=1", {
|
|
39
|
-
method: "POST",
|
|
40
|
-
body: body.toString(),
|
|
41
|
-
headers: {
|
|
42
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
43
|
-
"Accept": "*/*",
|
|
44
|
-
"Origin": "https://www.bing.com",
|
|
45
|
-
"Referer": "https://www.bing.com/translator",
|
|
46
|
-
"User-Agent": UA,
|
|
47
|
-
...(token.cookie ? { "Cookie": token.cookie } : {}),
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export async function fetchEdgeTtsVoices() {
|
|
53
|
-
const now = Date.now();
|
|
54
|
-
if (_voicesCache && now - _voicesCacheTime < VOICES_TTL) return _voicesCache;
|
|
55
|
-
const res = await fetch(
|
|
56
|
-
"https://speech.platform.bing.com/consumer/speech/synthesize/readaloud/voices/list?trustedclienttoken=6A5AA1D4EAFF4E9FB37E23D68491D6F4",
|
|
57
|
-
{ headers: { "User-Agent": UA } }
|
|
58
|
-
);
|
|
59
|
-
if (!res.ok) throw new Error(`Edge TTS voices fetch failed: ${res.status}`);
|
|
60
|
-
const voices = await res.json();
|
|
61
|
-
_voicesCache = voices;
|
|
62
|
-
_voicesCacheTime = now;
|
|
63
|
-
return voices;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export default {
|
|
67
|
-
noAuth: true,
|
|
68
|
-
async synthesize(text, model) {
|
|
69
|
-
const voiceId = model || "vi-VN-HoaiMyNeural";
|
|
70
|
-
let token = await getToken();
|
|
71
|
-
let res = await ttsRequest(text, voiceId, token);
|
|
72
|
-
|
|
73
|
-
// 429/403: invalidate cache and retry once
|
|
74
|
-
if (res.status === 429 || res.status === 403) {
|
|
75
|
-
cache.token = null;
|
|
76
|
-
cache.tokenTime = 0;
|
|
77
|
-
token = await getToken();
|
|
78
|
-
res = await ttsRequest(text, voiceId, token);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (!res.ok) {
|
|
82
|
-
const body = await res.text().catch(() => "");
|
|
83
|
-
throw new Error(`Bing TTS failed: ${res.status}${body ? " - " + body : ""}`);
|
|
84
|
-
}
|
|
85
|
-
const buf = await res.arrayBuffer();
|
|
86
|
-
if (buf.byteLength < 1024) throw new Error("Bing TTS returned empty audio");
|
|
87
|
-
return { base64: Buffer.from(buf).toString("base64"), format: "mp3" };
|
|
88
|
-
},
|
|
89
|
-
};
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
// ElevenLabs TTS — voice id with optional model_id prefix
|
|
2
|
-
import { Buffer } from "node:buffer";
|
|
3
|
-
|
|
4
|
-
const VOICES_TTL = 24 * 60 * 60 * 1000;
|
|
5
|
-
const _voicesCache = new Map(); // by API key
|
|
6
|
-
|
|
7
|
-
export async function fetchElevenLabsVoices(apiKey) {
|
|
8
|
-
if (!apiKey) throw new Error("ElevenLabs API key required");
|
|
9
|
-
const now = Date.now();
|
|
10
|
-
const cached = _voicesCache.get(apiKey);
|
|
11
|
-
if (cached && now - cached.time < VOICES_TTL) return cached.voices;
|
|
12
|
-
|
|
13
|
-
const res = await fetch("https://api.elevenlabs.io/v1/voices", {
|
|
14
|
-
headers: { "xi-api-key": apiKey, "Content-Type": "application/json" },
|
|
15
|
-
});
|
|
16
|
-
if (!res.ok) throw new Error(`ElevenLabs voices fetch failed: ${res.status}`);
|
|
17
|
-
const data = await res.json();
|
|
18
|
-
// Normalize: derive lang from labels for grouping
|
|
19
|
-
const voices = (data.voices || []).map((v) => ({ ...v, lang: v.labels?.language || "en" }));
|
|
20
|
-
_voicesCache.set(apiKey, { voices, time: now });
|
|
21
|
-
return voices;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default {
|
|
25
|
-
async synthesize(text, model, credentials) {
|
|
26
|
-
if (!credentials?.apiKey) throw new Error("ElevenLabs API key required");
|
|
27
|
-
let modelId = "eleven_flash_v2_5";
|
|
28
|
-
let voiceId = model;
|
|
29
|
-
if (model && model.includes("/")) [modelId, voiceId] = model.split("/");
|
|
30
|
-
|
|
31
|
-
const res = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, {
|
|
32
|
-
method: "POST",
|
|
33
|
-
headers: { "xi-api-key": credentials.apiKey, "Content-Type": "application/json" },
|
|
34
|
-
body: JSON.stringify({
|
|
35
|
-
text,
|
|
36
|
-
model_id: modelId,
|
|
37
|
-
voice_settings: { stability: 0.5, similarity_boost: 0.75 },
|
|
38
|
-
}),
|
|
39
|
-
});
|
|
40
|
-
if (!res.ok) {
|
|
41
|
-
const err = await res.json().catch(() => ({}));
|
|
42
|
-
throw new Error(err?.detail?.message || `ElevenLabs TTS failed: ${res.status}`);
|
|
43
|
-
}
|
|
44
|
-
const buf = await res.arrayBuffer();
|
|
45
|
-
if (buf.byteLength < 1024) throw new Error("ElevenLabs TTS returned empty audio");
|
|
46
|
-
return { base64: Buffer.from(buf).toString("base64"), format: "mp3" };
|
|
47
|
-
},
|
|
48
|
-
};
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
// Gemini TTS — generateContent with AUDIO modality returns PCM L16, wrap as WAV
|
|
2
|
-
import { Buffer } from "node:buffer";
|
|
3
|
-
|
|
4
|
-
const DEFAULT_MODEL = "gemini-2.5-flash-preview-tts";
|
|
5
|
-
const DEFAULT_VOICE = "Kore";
|
|
6
|
-
const KNOWN_MODELS = ["gemini-2.5-flash-preview-tts", "gemini-2.5-pro-preview-tts"];
|
|
7
|
-
|
|
8
|
-
// Parse "model/voice" — if input doesn't match a known TTS model, treat it as voice with default model
|
|
9
|
-
function parseGeminiModelVoice(input) {
|
|
10
|
-
if (!input) return { modelId: DEFAULT_MODEL, voiceId: DEFAULT_VOICE };
|
|
11
|
-
for (const id of KNOWN_MODELS) {
|
|
12
|
-
if (input === id) return { modelId: id, voiceId: DEFAULT_VOICE };
|
|
13
|
-
if (input.startsWith(`${id}/`)) return { modelId: id, voiceId: input.slice(id.length + 1) };
|
|
14
|
-
}
|
|
15
|
-
return { modelId: DEFAULT_MODEL, voiceId: input };
|
|
16
|
-
}
|
|
17
|
-
// Gemini returns PCM 16-bit signed mono @ 24kHz
|
|
18
|
-
const SAMPLE_RATE = 24000;
|
|
19
|
-
const CHANNELS = 1;
|
|
20
|
-
const BITS_PER_SAMPLE = 16;
|
|
21
|
-
|
|
22
|
-
// Build WAV header for raw PCM payload
|
|
23
|
-
function pcmToWav(pcmBuffer) {
|
|
24
|
-
const dataSize = pcmBuffer.length;
|
|
25
|
-
const byteRate = SAMPLE_RATE * CHANNELS * BITS_PER_SAMPLE / 8;
|
|
26
|
-
const blockAlign = CHANNELS * BITS_PER_SAMPLE / 8;
|
|
27
|
-
const header = Buffer.alloc(44);
|
|
28
|
-
header.write("RIFF", 0);
|
|
29
|
-
header.writeUInt32LE(36 + dataSize, 4);
|
|
30
|
-
header.write("WAVE", 8);
|
|
31
|
-
header.write("fmt ", 12);
|
|
32
|
-
header.writeUInt32LE(16, 16);
|
|
33
|
-
header.writeUInt16LE(1, 20);
|
|
34
|
-
header.writeUInt16LE(CHANNELS, 22);
|
|
35
|
-
header.writeUInt32LE(SAMPLE_RATE, 24);
|
|
36
|
-
header.writeUInt32LE(byteRate, 28);
|
|
37
|
-
header.writeUInt16LE(blockAlign, 32);
|
|
38
|
-
header.writeUInt16LE(BITS_PER_SAMPLE, 34);
|
|
39
|
-
header.write("data", 36);
|
|
40
|
-
header.writeUInt32LE(dataSize, 40);
|
|
41
|
-
return Buffer.concat([header, pcmBuffer]);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Build TTS prompt: add "Say [in {language}]:" prefix to force TTS mode
|
|
45
|
-
function buildPrompt(text, language) {
|
|
46
|
-
if (/:\s/.test(text)) return text; // user already provided style instruction
|
|
47
|
-
return language ? `Say in ${language}: ${text}` : `Say: ${text}`;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export default {
|
|
51
|
-
async synthesize(text, model, credentials, _responseFormat, opts = {}) {
|
|
52
|
-
if (!credentials?.apiKey) throw new Error("No Gemini API key configured");
|
|
53
|
-
const { modelId, voiceId } = parseGeminiModelVoice(model);
|
|
54
|
-
const url = `https://generativelanguage.googleapis.com/v1beta/models/${modelId}:generateContent?key=${credentials.apiKey}`;
|
|
55
|
-
const res = await fetch(url, {
|
|
56
|
-
method: "POST",
|
|
57
|
-
headers: { "Content-Type": "application/json" },
|
|
58
|
-
body: JSON.stringify({
|
|
59
|
-
contents: [{ parts: [{ text: buildPrompt(text, opts.language) }] }],
|
|
60
|
-
generationConfig: {
|
|
61
|
-
responseModalities: ["AUDIO"],
|
|
62
|
-
speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: voiceId } } },
|
|
63
|
-
},
|
|
64
|
-
}),
|
|
65
|
-
});
|
|
66
|
-
if (!res.ok) {
|
|
67
|
-
const err = await res.json().catch(() => ({}));
|
|
68
|
-
throw new Error(err?.error?.message || `Gemini TTS failed: ${res.status}`);
|
|
69
|
-
}
|
|
70
|
-
const data = await res.json();
|
|
71
|
-
const b64 = data?.candidates?.[0]?.content?.parts?.find((p) => p.inlineData?.data)?.inlineData?.data;
|
|
72
|
-
if (!b64) {
|
|
73
|
-
const reason = data?.candidates?.[0]?.finishReason || data?.promptFeedback?.blockReason || "unknown";
|
|
74
|
-
throw new Error(`Gemini TTS returned no audio (finishReason: ${reason}, voice: ${voiceId}, model: ${modelId})`);
|
|
75
|
-
}
|
|
76
|
-
const wav = pcmToWav(Buffer.from(b64, "base64"));
|
|
77
|
-
return { base64: wav.toString("base64"), format: "wav" };
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// Voice fetcher — return prebuilt voices (Gemini has no list API)
|
|
82
|
-
const PREBUILT_VOICES = [
|
|
83
|
-
{ id: "Zephyr", lang: "en", gender: "Female" },
|
|
84
|
-
{ id: "Puck", lang: "en", gender: "Male" },
|
|
85
|
-
{ id: "Charon", lang: "en", gender: "Male" },
|
|
86
|
-
{ id: "Kore", lang: "en", gender: "Female" },
|
|
87
|
-
{ id: "Fenrir", lang: "en", gender: "Male" },
|
|
88
|
-
{ id: "Leda", lang: "en", gender: "Female" },
|
|
89
|
-
{ id: "Orus", lang: "en", gender: "Male" },
|
|
90
|
-
{ id: "Aoede", lang: "en", gender: "Female" },
|
|
91
|
-
{ id: "Callirrhoe", lang: "en", gender: "Female" },
|
|
92
|
-
{ id: "Autonoe", lang: "en", gender: "Female" },
|
|
93
|
-
{ id: "Enceladus", lang: "en", gender: "Male" },
|
|
94
|
-
{ id: "Iapetus", lang: "en", gender: "Male" },
|
|
95
|
-
{ id: "Umbriel", lang: "en", gender: "Male" },
|
|
96
|
-
{ id: "Algieba", lang: "en", gender: "Male" },
|
|
97
|
-
{ id: "Despina", lang: "en", gender: "Female" },
|
|
98
|
-
{ id: "Erinome", lang: "en", gender: "Female" },
|
|
99
|
-
{ id: "Algenib", lang: "en", gender: "Male" },
|
|
100
|
-
{ id: "Rasalgethi", lang: "en", gender: "Male" },
|
|
101
|
-
{ id: "Laomedeia", lang: "en", gender: "Female" },
|
|
102
|
-
{ id: "Achernar", lang: "en", gender: "Female" },
|
|
103
|
-
{ id: "Alnilam", lang: "en", gender: "Male" },
|
|
104
|
-
{ id: "Schedar", lang: "en", gender: "Male" },
|
|
105
|
-
{ id: "Gacrux", lang: "en", gender: "Female" },
|
|
106
|
-
{ id: "Pulcherrima", lang: "en", gender: "Female" },
|
|
107
|
-
{ id: "Achird", lang: "en", gender: "Male" },
|
|
108
|
-
{ id: "Zubenelgenubi", lang: "en", gender: "Male" },
|
|
109
|
-
{ id: "Vindemiatrix", lang: "en", gender: "Female" },
|
|
110
|
-
{ id: "Sadachbia", lang: "en", gender: "Male" },
|
|
111
|
-
{ id: "Sadaltager", lang: "en", gender: "Male" },
|
|
112
|
-
{ id: "Sulafat", lang: "en", gender: "Female" },
|
|
113
|
-
];
|
|
114
|
-
|
|
115
|
-
export async function fetchGeminiVoices() {
|
|
116
|
-
return PREBUILT_VOICES.map((v) => ({ voice_id: v.id, name: v.id, labels: { language: v.lang, gender: v.gender } }));
|
|
117
|
-
}
|
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
// Generic config-driven TTS handlers — dispatched by ttsConfig.format.
|
|
2
|
-
// Each handler accepts { baseUrl, apiKey, text, modelId, voiceId } and returns { base64, format }.
|
|
3
|
-
import { responseToBase64, throwUpstreamError } from "./_base.js";
|
|
4
|
-
import minimaxTts from "./minimax.js";
|
|
5
|
-
|
|
6
|
-
// Hyperbolic: POST { text } → { audio: base64 }
|
|
7
|
-
async function hyperbolic({ baseUrl, apiKey, text }) {
|
|
8
|
-
const res = await fetch(baseUrl, {
|
|
9
|
-
method: "POST",
|
|
10
|
-
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
11
|
-
body: JSON.stringify({ text }),
|
|
12
|
-
});
|
|
13
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
14
|
-
const data = await res.json();
|
|
15
|
-
return { base64: data.audio, format: "mp3" };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Deepgram: model via query, Token auth, returns binary
|
|
19
|
-
async function deepgram({ baseUrl, apiKey, text, modelId }) {
|
|
20
|
-
const url = new URL(baseUrl);
|
|
21
|
-
url.searchParams.set("model", modelId || "aura-asteria-en");
|
|
22
|
-
const res = await fetch(url.toString(), {
|
|
23
|
-
method: "POST",
|
|
24
|
-
headers: { "Content-Type": "application/json", "Authorization": `Token ${apiKey}` },
|
|
25
|
-
body: JSON.stringify({ text }),
|
|
26
|
-
});
|
|
27
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
28
|
-
return responseToBase64(res, "mp3");
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Nvidia NIM: POST { input: { text }, voice, model } → binary
|
|
32
|
-
async function nvidia({ baseUrl, apiKey, text, modelId, voiceId }) {
|
|
33
|
-
const res = await fetch(baseUrl, {
|
|
34
|
-
method: "POST",
|
|
35
|
-
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
36
|
-
body: JSON.stringify({ input: { text }, voice: voiceId || "default", model: modelId }),
|
|
37
|
-
});
|
|
38
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
39
|
-
return responseToBase64(res, "wav");
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// HuggingFace: POST {baseUrl}/{modelId} { inputs: text } → binary
|
|
43
|
-
async function huggingface({ baseUrl, apiKey, text, modelId }) {
|
|
44
|
-
if (!modelId || modelId.includes("..")) throw new Error("Invalid HuggingFace model ID");
|
|
45
|
-
const res = await fetch(`${baseUrl}/${modelId}`, {
|
|
46
|
-
method: "POST",
|
|
47
|
-
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
48
|
-
body: JSON.stringify({ inputs: text }),
|
|
49
|
-
});
|
|
50
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
51
|
-
return responseToBase64(res, "wav");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Inworld: Basic auth, JSON { audioContent }
|
|
55
|
-
async function inworld({ baseUrl, apiKey, text, modelId, voiceId }) {
|
|
56
|
-
const res = await fetch(baseUrl, {
|
|
57
|
-
method: "POST",
|
|
58
|
-
headers: { "Content-Type": "application/json", "Authorization": `Basic ${apiKey}` },
|
|
59
|
-
body: JSON.stringify({
|
|
60
|
-
text,
|
|
61
|
-
voiceId: voiceId || "Alex",
|
|
62
|
-
modelId: modelId || "inworld-tts-1.5-mini",
|
|
63
|
-
audioConfig: { audioEncoding: "MP3" },
|
|
64
|
-
}),
|
|
65
|
-
});
|
|
66
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
67
|
-
const data = await res.json();
|
|
68
|
-
if (!data.audioContent) throw new Error("Inworld TTS returned no audio");
|
|
69
|
-
return { base64: data.audioContent, format: "mp3" };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Cartesia: X-API-Key header
|
|
73
|
-
async function cartesia({ baseUrl, apiKey, text, modelId, voiceId }) {
|
|
74
|
-
const res = await fetch(baseUrl, {
|
|
75
|
-
method: "POST",
|
|
76
|
-
headers: {
|
|
77
|
-
"Content-Type": "application/json",
|
|
78
|
-
"X-API-Key": apiKey,
|
|
79
|
-
"Cartesia-Version": "2024-06-10",
|
|
80
|
-
},
|
|
81
|
-
body: JSON.stringify({
|
|
82
|
-
model_id: modelId || "sonic-2",
|
|
83
|
-
transcript: text,
|
|
84
|
-
...(voiceId ? { voice: { mode: "id", id: voiceId } } : {}),
|
|
85
|
-
output_format: { container: "mp3", bit_rate: 128000, sample_rate: 44100 },
|
|
86
|
-
}),
|
|
87
|
-
});
|
|
88
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
89
|
-
return responseToBase64(res, "mp3");
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// PlayHT: token format "userId:apiKey", voice = s3 URL
|
|
93
|
-
async function playht({ baseUrl, apiKey, text, modelId, voiceId }) {
|
|
94
|
-
const [userId, key] = (apiKey || ":").split(":");
|
|
95
|
-
const res = await fetch(baseUrl, {
|
|
96
|
-
method: "POST",
|
|
97
|
-
headers: {
|
|
98
|
-
"Content-Type": "application/json",
|
|
99
|
-
"Accept": "audio/mpeg",
|
|
100
|
-
"X-USER-ID": userId || "",
|
|
101
|
-
"Authorization": `Bearer ${key || apiKey}`,
|
|
102
|
-
},
|
|
103
|
-
body: JSON.stringify({
|
|
104
|
-
text,
|
|
105
|
-
voice: voiceId || "s3://voice-cloning-zero-shot/d9ff78ba-d016-47f6-b0ef-dd630f59414e/female-cs/manifest.json",
|
|
106
|
-
voice_engine: modelId || "PlayDialog",
|
|
107
|
-
output_format: "mp3",
|
|
108
|
-
speed: 1,
|
|
109
|
-
}),
|
|
110
|
-
});
|
|
111
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
112
|
-
return responseToBase64(res, "mp3");
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Coqui (local, noAuth): POST { text, speaker_id } → WAV
|
|
116
|
-
async function coqui({ baseUrl, text, voiceId }) {
|
|
117
|
-
const res = await fetch(baseUrl, {
|
|
118
|
-
method: "POST",
|
|
119
|
-
headers: { "Content-Type": "application/json" },
|
|
120
|
-
body: JSON.stringify({ text, ...(voiceId ? { speaker_id: voiceId } : {}) }),
|
|
121
|
-
});
|
|
122
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
123
|
-
return responseToBase64(res, "wav");
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Tortoise (local, noAuth)
|
|
127
|
-
async function tortoise({ baseUrl, text, voiceId }) {
|
|
128
|
-
const res = await fetch(baseUrl, {
|
|
129
|
-
method: "POST",
|
|
130
|
-
headers: { "Content-Type": "application/json" },
|
|
131
|
-
body: JSON.stringify({ text, voice: voiceId || "random" }),
|
|
132
|
-
});
|
|
133
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
134
|
-
return responseToBase64(res, "wav");
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// OpenAI-compatible upstream (qwen3-tts, etc.)
|
|
138
|
-
async function openaiCompat({ baseUrl, apiKey, text, modelId, voiceId }) {
|
|
139
|
-
const headers = { "Content-Type": "application/json" };
|
|
140
|
-
if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
|
|
141
|
-
const res = await fetch(baseUrl, {
|
|
142
|
-
method: "POST",
|
|
143
|
-
headers,
|
|
144
|
-
body: JSON.stringify({
|
|
145
|
-
model: modelId,
|
|
146
|
-
input: text,
|
|
147
|
-
voice: voiceId || "alloy",
|
|
148
|
-
response_format: "mp3",
|
|
149
|
-
speed: 1.0,
|
|
150
|
-
}),
|
|
151
|
-
});
|
|
152
|
-
if (!res.ok) await throwUpstreamError(res);
|
|
153
|
-
return responseToBase64(res, "mp3");
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// format → handler dispatcher
|
|
157
|
-
export const FORMAT_HANDLERS = {
|
|
158
|
-
hyperbolic,
|
|
159
|
-
deepgram,
|
|
160
|
-
"nvidia-tts": nvidia,
|
|
161
|
-
"huggingface-tts": huggingface,
|
|
162
|
-
inworld,
|
|
163
|
-
cartesia,
|
|
164
|
-
playht,
|
|
165
|
-
coqui,
|
|
166
|
-
tortoise,
|
|
167
|
-
openai: openaiCompat,
|
|
168
|
-
"minimax-tts": minimaxTts,
|
|
169
|
-
};
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// Google Translate TTS (no auth) — scrape token + batchexecute RPC
|
|
2
|
-
import { UA } from "./_base.js";
|
|
3
|
-
|
|
4
|
-
const REFRESH_MS = 11 * 60 * 1000;
|
|
5
|
-
const cache = { token: null, tokenTime: 0 };
|
|
6
|
-
let _idx = 0;
|
|
7
|
-
|
|
8
|
-
async function getToken() {
|
|
9
|
-
const now = Date.now();
|
|
10
|
-
if (cache.token && now - cache.tokenTime < REFRESH_MS) return cache.token;
|
|
11
|
-
const res = await fetch("https://translate.google.com/", { headers: { "User-Agent": UA } });
|
|
12
|
-
if (!res.ok) throw new Error(`Google translate fetch failed: ${res.status}`);
|
|
13
|
-
const html = await res.text();
|
|
14
|
-
const fSid = html.match(/"FdrFJe":"(.*?)"/)?.[1];
|
|
15
|
-
const bl = html.match(/"cfb2h":"(.*?)"/)?.[1];
|
|
16
|
-
if (!fSid || !bl) throw new Error("Failed to parse Google token");
|
|
17
|
-
cache.token = { "f.sid": fSid, bl };
|
|
18
|
-
cache.tokenTime = now;
|
|
19
|
-
return cache.token;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export default {
|
|
23
|
-
noAuth: true,
|
|
24
|
-
async synthesize(text, model) {
|
|
25
|
-
const lang = model || "en";
|
|
26
|
-
const token = await getToken();
|
|
27
|
-
const cleanText = text.replace(/[@^*()\\/\-_+=><"'\u201c\u201d\u3010\u3011]/g, " ").replaceAll(", ", ". ");
|
|
28
|
-
const rpcId = "jQ1olc";
|
|
29
|
-
const reqId = (++_idx * 100000) + Math.floor(1000 + Math.random() * 9000);
|
|
30
|
-
const query = new URLSearchParams({
|
|
31
|
-
rpcids: rpcId,
|
|
32
|
-
"f.sid": token["f.sid"],
|
|
33
|
-
bl: token.bl,
|
|
34
|
-
hl: lang,
|
|
35
|
-
"soc-app": 1, "soc-platform": 1, "soc-device": 1,
|
|
36
|
-
_reqid: reqId,
|
|
37
|
-
rt: "c",
|
|
38
|
-
});
|
|
39
|
-
const payload = [cleanText, lang, null, "undefined", [0]];
|
|
40
|
-
const body = new URLSearchParams();
|
|
41
|
-
body.append("f.req", JSON.stringify([[[rpcId, JSON.stringify(payload), null, "generic"]]]));
|
|
42
|
-
const res = await fetch(`https://translate.google.com/_/TranslateWebserverUi/data/batchexecute?${query}`, {
|
|
43
|
-
method: "POST",
|
|
44
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded", "Referer": "https://translate.google.com/" },
|
|
45
|
-
body: body.toString(),
|
|
46
|
-
});
|
|
47
|
-
if (!res.ok) throw new Error(`Google TTS failed: ${res.status}`);
|
|
48
|
-
const data = await res.text();
|
|
49
|
-
const split = JSON.parse(data.split("\n")[3]);
|
|
50
|
-
const base64 = JSON.parse(split[0][2])[0];
|
|
51
|
-
if (!base64 || base64.length < 100) throw new Error("Google TTS returned empty audio");
|
|
52
|
-
return { base64, format: "mp3" };
|
|
53
|
-
},
|
|
54
|
-
};
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// TTS provider registry
|
|
2
|
-
import googleTts from "./googleTts.js";
|
|
3
|
-
import edgeTts, { fetchEdgeTtsVoices } from "./edgeTts.js";
|
|
4
|
-
import localDevice, { fetchLocalDeviceVoices } from "./localDevice.js";
|
|
5
|
-
import elevenlabs, { fetchElevenLabsVoices } from "./elevenlabs.js";
|
|
6
|
-
import openai from "./openai.js";
|
|
7
|
-
import openrouter from "./openrouter.js";
|
|
8
|
-
import gemini, { fetchGeminiVoices } from "./gemini.js";
|
|
9
|
-
import { FORMAT_HANDLERS } from "./genericFormats.js";
|
|
10
|
-
import { parseModelVoice } from "./_base.js";
|
|
11
|
-
|
|
12
|
-
// Special providers with custom synthesize() logic
|
|
13
|
-
const SPECIAL_ADAPTERS = {
|
|
14
|
-
"google-tts": googleTts,
|
|
15
|
-
"edge-tts": edgeTts,
|
|
16
|
-
"local-device": localDevice,
|
|
17
|
-
elevenlabs,
|
|
18
|
-
openai,
|
|
19
|
-
openrouter,
|
|
20
|
-
gemini,
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export function getTtsAdapter(provider) {
|
|
24
|
-
return SPECIAL_ADAPTERS[provider] || null;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Generic config-driven dispatcher (uses ttsConfig.format)
|
|
28
|
-
export async function synthesizeViaConfig(provider, text, model, credentials) {
|
|
29
|
-
const { AI_PROVIDERS } = await import("@/shared/constants/providers");
|
|
30
|
-
const cfg = AI_PROVIDERS[provider]?.ttsConfig;
|
|
31
|
-
if (!cfg) return null;
|
|
32
|
-
const handler = FORMAT_HANDLERS[cfg.format];
|
|
33
|
-
if (!handler) return null;
|
|
34
|
-
const apiKey = credentials?.apiKey;
|
|
35
|
-
if (cfg.authType !== "none" && !apiKey) throw new Error(`${provider} API key required`);
|
|
36
|
-
const defaultModel = cfg.models?.[0]?.id || "";
|
|
37
|
-
const { modelId, voiceId } = parseModelVoice(model, defaultModel, "", cfg.models || []);
|
|
38
|
-
return handler({ baseUrl: cfg.baseUrl, apiKey, text, modelId, voiceId });
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Voice fetchers (used by /api/media-providers/tts/voices route)
|
|
42
|
-
export const VOICE_FETCHERS = {
|
|
43
|
-
"edge-tts": fetchEdgeTtsVoices,
|
|
44
|
-
"local-device": fetchLocalDeviceVoices,
|
|
45
|
-
elevenlabs: fetchElevenLabsVoices,
|
|
46
|
-
gemini: fetchGeminiVoices,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// Re-export for backward compat
|
|
50
|
-
export { fetchEdgeTtsVoices, fetchLocalDeviceVoices, fetchElevenLabsVoices, fetchGeminiVoices };
|