mirror of
https://github.com/simstudioai/sim.git
synced 2026-10-16 06:39:56 +08:00
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:
@@ -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),
|
||||
})
|
||||
|
||||
@@ -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,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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user