improvement(elevenlabs): wire stability and similarity_boost end-to-end (#4679)

* improvement(elevenlabs): wire stability and similarity_boost end-to-end

* fix(elevenlabs): guard NaN in voice settings and always send both knobs together
This commit is contained in:
Waleed
2026-05-20 13:46:29 -07:00
committed by GitHub
parent a1b2130256
commit 7e678552d6
5 changed files with 61 additions and 20 deletions
+20 -2
View File
@@ -35,8 +35,17 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
)
if (!parsed.success) return parsed.response
const { text, voiceId, apiKey, modelId, workspaceId, workflowId, executionId } =
parsed.data.body
const {
text,
voiceId,
apiKey,
modelId,
stability,
similarityBoost,
workspaceId,
workflowId,
executionId,
} = parsed.data.body
const voiceIdValidation = validateAlphanumericId(voiceId, 'voiceId', 255)
if (!voiceIdValidation.isValid) {
@@ -57,6 +66,14 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
const endpoint = `https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`
const hasVoiceSetting = stability !== undefined || similarityBoost !== undefined
const voiceSettings = hasVoiceSetting
? {
stability: stability ?? 0.5,
similarity_boost: similarityBoost ?? 0.75,
}
: undefined
const response = await fetch(endpoint, {
method: 'POST',
headers: {
@@ -67,6 +84,7 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
body: JSON.stringify({
text,
model_id: modelId,
...(voiceSettings ? { voice_settings: voiceSettings } : {}),
}),
signal: AbortSignal.timeout(DEFAULT_EXECUTION_TIMEOUT_MS),
})
+33 -7
View File
@@ -5,7 +5,7 @@ import type { ElevenLabsBlockResponse } from '@/tools/elevenlabs/types'
export const ElevenLabsBlock: BlockConfig<ElevenLabsBlockResponse> = {
type: 'elevenlabs',
name: 'ElevenLabs',
description: 'Convert TTS using ElevenLabs',
description: 'Convert text to speech with ElevenLabs',
authMode: AuthMode.ApiKey,
longDescription: 'Integrate ElevenLabs into the workflow. Can convert text to speech.',
docsLink: 'https://docs.sim.ai/tools/elevenlabs',
@@ -42,6 +42,21 @@ export const ElevenLabsBlock: BlockConfig<ElevenLabsBlockResponse> = {
{ label: 'eleven_flash_v2_5', id: 'eleven_flash_v2_5' },
{ label: 'eleven_v3', id: 'eleven_v3' },
],
value: () => 'eleven_monolingual_v1',
},
{
id: 'stability',
title: 'Stability',
type: 'short-input',
placeholder: '0.0 to 1.0 (e.g., 0.5)',
mode: 'advanced',
},
{
id: 'similarityBoost',
title: 'Similarity Boost',
type: 'short-input',
placeholder: '0.0 to 1.0 (e.g., 0.75)',
mode: 'advanced',
},
{
id: 'apiKey',
@@ -57,12 +72,21 @@ export const ElevenLabsBlock: BlockConfig<ElevenLabsBlockResponse> = {
access: ['elevenlabs_tts'],
config: {
tool: () => 'elevenlabs_tts',
params: (params) => ({
apiKey: params.apiKey,
text: params.text,
voiceId: params.voiceId,
modelId: params.modelId,
}),
params: (params) => {
const parseUnitInterval = (value: unknown): number | undefined => {
if (value === undefined || value === null || value === '') return undefined
const n = Number(value)
return Number.isFinite(n) ? n : undefined
}
return {
apiKey: params.apiKey,
text: params.text,
voiceId: params.voiceId,
modelId: params.modelId,
stability: parseUnitInterval(params.stability),
similarityBoost: parseUnitInterval(params.similarityBoost),
}
},
},
},
@@ -70,6 +94,8 @@ export const ElevenLabsBlock: BlockConfig<ElevenLabsBlockResponse> = {
text: { type: 'string', description: 'Text to convert' },
voiceId: { type: 'string', description: 'Voice identifier' },
modelId: { type: 'string', description: 'Model identifier' },
stability: { type: 'number', description: 'Voice stability 0.0-1.0' },
similarityBoost: { type: 'number', description: 'Similarity boost 0.0-1.0' },
apiKey: { type: 'string', description: 'ElevenLabs API key' },
},
@@ -7,6 +7,8 @@ export const ttsToolBodySchema = z.object({
voiceId: z.string({ error: 'Missing required parameters' }).min(1, 'Missing required parameters'),
apiKey: z.string({ error: 'Missing required parameters' }).min(1, 'Missing required parameters'),
modelId: z.string().optional().default('eleven_monolingual_v1'),
stability: z.coerce.number().min(0).max(1).optional(),
similarityBoost: z.coerce.number().min(0).max(1).optional(),
workspaceId: z.string().optional(),
workflowId: z.string().optional(),
executionId: z.string().optional(),
+4 -4
View File
@@ -4,7 +4,7 @@ import type { ToolConfig } from '@/tools/types'
export const elevenLabsTtsTool: ToolConfig<ElevenLabsTtsParams, ElevenLabsTtsResponse> = {
id: 'elevenlabs_tts',
name: 'ElevenLabs TTS',
description: 'Convert TTS using ElevenLabs voices',
description: 'Convert text to speech using ElevenLabs voices',
version: '1.0.0',
params: {
@@ -34,7 +34,7 @@ export const elevenLabsTtsTool: ToolConfig<ElevenLabsTtsParams, ElevenLabsTtsRes
description:
'Voice stability setting from 0.0 to 1.0 (e.g., 0.5 for balanced, 0.75 for more stable). Higher values produce more consistent output',
},
similarity: {
similarityBoost: {
type: 'number',
required: false,
visibility: 'user-or-llm',
@@ -52,7 +52,7 @@ export const elevenLabsTtsTool: ToolConfig<ElevenLabsTtsParams, ElevenLabsTtsRes
request: {
url: '/api/tools/tts',
method: 'POST',
headers: (params) => ({
headers: () => ({
'Content-Type': 'application/json',
}),
body: (
@@ -65,7 +65,7 @@ export const elevenLabsTtsTool: ToolConfig<ElevenLabsTtsParams, ElevenLabsTtsRes
voiceId: params.voiceId,
modelId: params.modelId || 'eleven_monolingual_v1',
stability: params.stability,
similarity: params.similarity,
similarityBoost: params.similarityBoost,
workspaceId: params._context?.workspaceId,
workflowId: params._context?.workflowId,
executionId: params._context?.executionId,
+2 -7
View File
@@ -7,7 +7,7 @@ export interface ElevenLabsTtsParams {
voiceId: string
modelId?: string
stability?: number
similarity?: number
similarityBoost?: number
}
export interface ElevenLabsTtsResponse extends ToolResponse {
@@ -17,9 +17,4 @@ export interface ElevenLabsTtsResponse extends ToolResponse {
}
}
export interface ElevenLabsBlockResponse extends ToolResponse {
output: {
audioUrl: string
audioFile?: UserFile
}
}
export type ElevenLabsBlockResponse = ElevenLabsTtsResponse