Docs do Nodaro
DocumentaçãoReferência de nósModelosAgentes de IA (MCP)DesenvolvedoresSelf-hostingPesquisa
SDK para TypeScript

Vozes e áudio

Navegue pelas vozes, troque e substitua vozes, crie novas vozes, duble vídeos e separe, mixe e transcreva áudio em TypeScript com o SDK do Nodaro.

client.voices trabalha com vozes da ElevenLabs: lista e pesquisa vozes, troca a voz de uma gravação, dá uma nova voz a cada falante, cria novas vozes e dubla áudio e vídeo para outros idiomas. client.audio oferece os blocos de áudio separadamente: separação, isolamento de voz, efeitos, mixagem, volume, junção e transcrição. Todo método de geração retorna um jobId; consulte-o periodicamente com client.jobs.getStatus(). Os métodos chamam a API REST de voz e mídia.

Métodos

MétodoO que faz
voices.list()Lista as vozes prontas
voices.searchLibrary(params?)Pesquisa a Biblioteca de vozes da comunidade
voices.listClones()Lista seus clones de voz existentes
voices.deleteClone(id)Exclui um dos seus clones de voz
voices.createClone() e createCloneFromFile()Descontinuados
voices.change(input)Substitui a voz em uma gravação ou em um vídeo
voices.recast(input)Dá uma voz diferente a cada falante
voices.analyze(input)Detecta os falantes antes de uma troca de vozes
voices.exportMix(input)Renderiza um vídeo a partir de stems de voz mixados
voices.design(input)Cria uma nova voz a partir de uma descrição
voices.remix(input)Fala um texto em uma voz que você descreve
voices.dub(input)Dubla áudio ou vídeo para outro idioma
voices.textToDialogue(input)Dá voz a um roteiro com vários falantes em um único arquivo de áudio
audio.separate(input)Divide uma faixa em stems
audio.isolate(input)Mantém a voz principal e remove o ruído
audio.applyFx(input)Adiciona reverberação, eco, telefone ou megafone
audio.mix(input)Sobrepõe várias faixas em uma só
audio.adjustVolume(input)Muda o nível, normaliza ou aplica fade
audio.combine(input)Junta segmentos de áudio em sequência
audio.transcribe(input)Transforma fala em texto, com os tempos das palavras

client.voices: vozes

voices.list()

Lista as vozes prontas da ElevenLabs (GET /v1/voices). Quando o servidor não tem uma chave da ElevenLabs configurada, ele retorna, em vez disso, um conjunto selecionado.

list(): Promise<Voice[]>
const voices = await client.voices.list()

voices.searchLibrary(params?)

Pesquisa a Biblioteca de vozes da comunidade (GET /v1/voices/library). Todos os parâmetros são opcionais, e valores vazios são omitidos para que os padrões do servidor se apliquem. hasMore, na resposta, indica se existe outra página.

searchLibrary(params?: VoiceLibraryParams): Promise<{ voices: Voice[]; hasMore: boolean }>

Prop

Type

const { voices, hasMore } = await client.voices.searchLibrary({ search: "deep", language: "en" })
const voice = voices[0]

await client.nodes.run("text-to-speech", {
  text: "Hello!",
  voice: voice.voice_id,
  voiceType: "library",
  ...(voice.recommendedProvider ? { provider: voice.recommendedProvider } : {}),
})

Cada voz pode trazer duas indicações sobre os modelos de fala em que foi verificada:

  • recommendedProvider é o melhor modelo para a voz. Apps sem um seletor de modelo devem enviá-lo como provider para o Texto para fala (Text to Speech), para que a voz soe como a prévia dela na biblioteca.
  • verifiedProviders lista todos os modelos em que a voz foi verificada. Apps com um seletor de modelo devem substituir a escolha do usuário só quando ela não estiver nessa lista.

voices.listClones()

Lista seus clones de voz (GET /v1/voice-clones). Os clones feitos antes de a clonagem ser descontinuada continuam funcionando como IDs de voz em qualquer lugar que aceite uma voz.

listClones(): Promise<VoiceClone[]>
const clones = await client.voices.listClones()

voices.deleteClone(id)

Exclui um dos seus clones de voz (DELETE /v1/voice-clones/:id).

deleteClone(id: string): Promise<void>

Prop

Type

await client.voices.deleteClone(cloneId)

voices.createClone() e createCloneFromFile()

A clonagem de voz não é mais oferecida no Nodaro. Ela foi descontinuada em setembro de 2026. Os dois métodos continuam no cliente e estão marcados como obsoletos. Eles falham com um NodaroError cujo code é voice_cloning_retired, com status 410. Para uma nova voz personalizada, use design().

client.voices: modificador de voz

voices.change(input)

Substitui a voz de uma gravação, ou de um vídeo inteiro com fala, por outra voz (POST /v1/voice-changer), como faz o nó Modificador de voz (Voice Changer). Com videoUrl, o servidor extrai o áudio do vídeo, troca a voz e coloca a nova voz de volta na imagem original.

change(input: {
  voiceId: string
  audioUrl?: string
  videoUrl?: string
  model?: string
  stability?: number
  similarityBoost?: number
  style?: number
  useSpeakerBoost?: boolean
  seed?: number
  removeBackgroundNoise?: boolean
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.change({
  videoUrl: "https://example.com/talking.mp4",
  voiceId: "Aria",
})
// the finished job's output_data has videoUrl and audioUrl

voices.recast(input)

Dá uma voz diferente a cada falante detectado em uma gravação (POST /v1/voice-changer-pro), como faz o nó Modificador de voz Pro (Voice Changer Pro). O método roda no Nodaro Cloud, custa créditos e é executado como um job.

recast(input: VoiceChangerProInput): Promise<{ jobId: string }>

Prop

Type

Cada entrada de orderedVoices é uma destas opções:

  • Um ID de voz: o nome de uma voz pronta, como "Rachel", ou um ID de voz da ElevenLabs.
  • null: uma posição que mantém a voz original. Esse falante mantém a própria voz, enquanto os falantes seguintes continuam tendo a voz trocada. As posições que mantêm a voz original não custam nada, porque só os falantes com voz trocada são cobrados.
  • Um objeto com voiceId e as configurações desse falante: stability, similarityBoost e style, de 0 a 1, useSpeakerBoost e um seed de 0 a 4.294.967.295. volumeMode é "match" (o padrão, o nível do falante original), "normalize" ou "manual", com volume em porcentagem de 0 a 200. engine: "v3" fala a linha de novo a partir da transcrição, com suporte a [audio tags], em vez de converter a fala gravada.

O falante 0 recebe orderedVoices[0], o falante 1 recebe orderedVoices[1], e assim por diante. Os falantes depois da última entrada mantêm a própria voz. A voz e a música são sempre separadas primeiro. preserveBackground só decide se a música volta.

voiceFx.preset é um ambiente de reverberação (room, bathroom, car, hall, concert-hall, church, cave, arena ou outdoor), telephone, megaphone, echo ou custom. As predefinições de reverberação usam wetDryMix de 0 a 100. echo e custom usam delayMs de 20 a 2.000 e decay de 0 a 1.

// Recast speakers 0 and 2, and keep speaker 1's own voice
const { jobId } = await client.voices.recast({
  audioUrl: "https://example.com/panel.mp3",
  orderedVoices: ["Rachel", null, "Aria"],
})

// Repeatable voices, a hall reverb, and finer separation
const { jobId: tuned } = await client.voices.recast({
  audioUrl: "https://example.com/dialogue.mp3",
  orderedVoices: [
    { voiceId: "Rachel", seed: 12345, stability: 0.6 },
    { voiceId: "Aria", seed: 67890, volumeMode: "manual", volume: 120 },
  ],
  voiceFx: { preset: "hall", wetDryMix: 35 },
  separationQuality: "best",
})

No modo de vídeo, o output_data do job concluído tem videoUrl e audioUrl.

voices.analyze(input)

Detecta os falantes de um clipe sem trocar as vozes (POST /v1/voice-changer-pro/analyze). O método separa a voz da música uma vez e descobre quem fala quando. Ele roda no Nodaro Cloud, com preço fixo, como um job.

analyze(input: {
  audioUrl?: string
  videoUrl?: string
  separationQuality?: "fast" | "best"
  suggestTitle?: boolean
}): Promise<{ jobId: string }>

Prop

Type

O output_data do job concluído é um VcpAnalysis: os vocalsUrl e backgroundUrl separados, os speakers detectados (cada um com id, os segments de tempo, firstStartSec, wordCount e um snippet de texto), languageCode com languageProbability e suggestedTitle, quando pedido. Passe-o como analysis para cada recast() seguinte, para que a troca de vozes reaproveite as faixas separadas e não pague de novo pela detecção.

voices.exportMix(input)

Renderiza o vídeo final a partir de um conjunto mixado de stems (POST /v1/voice-changer-pro/export). É a última etapa depois de recast({ output: "stems" }). O método roda no Nodaro Cloud, com preço fixo, como um job.

exportMix(input: {
  videoUrl: string
  tracks: Array<{ url: string; gain: number; muted: boolean; kind?: "voice" | "background" }>
  voiceFx?: { preset: AudioFxPreset; wetDryMix?: number; delayMs?: number; decay?: number }
}): Promise<{ jobId: string }>

Prop

Type

O fluxo interativo analisa uma vez, troca as vozes gerando stems e depois mixa e renderiza. Veja o fluxo com uma pequena função auxiliar de consulta periódica:

import type { VcpAnalysis } from "@nodaro/sdk"

async function outputOf(jobId: string): Promise<any> {
  for (;;) {
    const { data } = await client.jobs.getStatus(jobId)
    if (data.status === "completed") return data.output_data
    if (data.status === "failed" || data.status === "cancelled") throw new Error(data.error_message ?? data.status)
    await new Promise((resolve) => setTimeout(resolve, 2_000))
  }
}

const { jobId: analyzeJob } = await client.voices.analyze({ videoUrl })
const analysis = (await outputOf(analyzeJob)) as VcpAnalysis

const { jobId: recastJob } = await client.voices.recast({
  videoUrl,
  orderedVoices: ["Rachel", null, "Aria"],
  output: "stems",
  analysis,
})
const stems = await outputOf(recastJob)

const { jobId: exportJob } = await client.voices.exportMix({
  videoUrl,
  tracks: [
    { url: stems.tracks[0].url, gain: 100, muted: false },
    { url: stems.tracks[1].url, gain: 90, muted: false },
    { url: stems.backgroundUrl, gain: 70, muted: false, kind: "background" },
  ],
  voiceFx: { preset: "hall", wetDryMix: 25 },
})
const { videoUrl: finalVideo } = await outputOf(exportJob)

Os ganhos, os mudos e o efeito são aplicados quando o vídeo é renderizado, e a imagem é copiada como está. Por isso, a exportação corresponde à sua prévia, e você pode mudar a mixagem quantas vezes quiser antes de exportar. Uma mixagem com todas as faixas no mudo é recusada com um 400.

client.voices: criar e traduzir

voices.design(input)

Cria uma nova voz sintética a partir de uma descrição em texto (POST /v1/voice-design), como faz o nó Design de voz (Voice Design). O job concluído traz uma prévia em áudio e o ID da nova voz, que você pode usar em qualquer lugar que aceite uma voz.

design(input: {
  text: string
  voiceDescription: string
  model?: string
  loudness?: number
  guidanceScale?: number
  seed?: number
  quality?: number
  shouldEnhance?: boolean
  userPrompt?: string
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.design({
  text: "Welcome back. Tonight we follow the river north, into the mountains where the story began.",
  voiceDescription: "A calm, deep voice of an older male narrator with a slight British accent",
})

voices.remix(input)

Fala um texto em uma voz descrita em palavras simples, sem criar uma voz (POST /v1/voice-remix), como faz o nó Remix de voz (Voice Remix).

remix(input: { text: string; voiceDescription: string; userPrompt?: string }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.remix({
  text: "Your order is on its way.",
  voiceDescription: "A cheerful young woman, fast and upbeat",
})

voices.dub(input)

Dubla um áudio, ou um vídeo inteiro, para outro idioma, mantendo a voz de cada falante (POST /v1/dubbing), como faz o nó Dublagem (Dubbing). A dublagem de um vídeo retorna output_data.videoUrl, o clipe dublado, e output_data.audioUrl, só a faixa dublada.

dub(input: DubbingInput): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.dub({
  videoUrl: "https://example.com/interview.mp4",
  targetLanguage: "es",
  numSpeakers: 2,
})

O preço depende dos minutos do trecho dublado, com um mínimo de 1 minuto. Um trecho tem no máximo 30 minutos; por isso, use startTime e endTime em fontes mais longas.

voices.textToDialogue(input)

Dá voz a um roteiro com vários falantes em um único arquivo de áudio (POST /v1/text-to-dialogue), como faz o nó Texto para diálogo (Text to Dialogue) com o ElevenLabs Dialogue v3.

textToDialogue(input: {
  dialogue: Array<{ text: string; voice: string }>
  stability?: 0 | 0.5 | 1
  languageCode?: string
  seed?: number
  applyTextNormalization?: "auto" | "on" | "off"
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.voices.textToDialogue({
  dialogue: [
    { text: "Did you hear that?", voice: "Rachel" },
    { text: "[whispers] Stay behind me.", voice: "Callum" },
  ],
})

Um roteiro pode ter no máximo 5.000 caracteres, e menos de 2.000 dão a melhor qualidade. Ele pode usar no máximo 10 vozes diferentes. Vozes da biblioteca, vozes criadas com design de voz e clones existentes funcionam, combinados como você quiser. O output_data.audioUrl do job concluído é o arquivo.

client.audio

Os blocos de áudio que o Modificador de voz Pro usa internamente, disponíveis um a um. Todo método retorna um jobId.

audio.separate(input)

Divide uma faixa em stems (POST /v1/audio-separation), como faz o nó Separação de áudio (Audio Separation).

separate(input: { audioUrl: string; mode?: "vocal_instrumental" | "stems"; quality?: "auto" | "fast" | "best" }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.separate({ audioUrl: songUrl })
// output: vocalUrl and instrumentalUrl, or one URL per stem in stems mode

audio.isolate(input)

Mantém a voz principal e remove o ruído de fundo (POST /v1/audio-isolation), como faz o nó Extrator de voz (Voice Extractor).

isolate(input: { audioUrl: string }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.isolate({ audioUrl: interviewUrl })

audio.applyFx(input)

Adiciona um efeito de reverberação, eco, telefone ou megafone (POST /v1/audio-fx), como faz o nó Efeitos de áudio (Audio FX). As predefinições são as mesmas do voiceFx da troca de vozes.

applyFx(input: {
  audioUrl: string
  preset?: AudioFxPreset
  mix?: number
  delayMs?: number
  decay?: number
  eqLow?: number
  eqHigh?: number
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.applyFx({ audioUrl: lineUrl, preset: "telephone" })

audio.mix(input)

Sobrepõe várias faixas em uma só (POST /v1/mix-audio), como faz o nó Mixar áudio (Mix Audio).

mix(input: { audioUrls: string[]; trackVolumes?: number[] }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.mix({ audioUrls: [voiceUrl, musicUrl], trackVolumes: [100, 35] })

audio.adjustVolume(input)

Muda o nível de um arquivo de áudio, ou do áudio de um vídeo (POST /v1/adjust-volume), como faz o nó Ajustar volume (Adjust Volume).

adjustVolume(input: {
  audioUrl?: string
  videoUrl?: string
  volume?: number
  normalize?: boolean
  fadeIn?: number
  fadeOut?: number
}): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.adjustVolume({ audioUrl: musicUrl, volume: 60, fadeOut: 3 })

audio.combine(input)

Junta segmentos de áudio em sequência (POST /v1/combine-audio), como faz o nó Combinar áudio (Combine Audio).

combine(input: { segments: Array<{ url: string; startTime?: number; endTime?: number }> }): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.audio.combine({
  segments: [{ url: introUrl }, { url: episodeUrl, startTime: 4 }, { url: outroUrl }],
})

audio.transcribe(input)

Transforma em texto a fala de um arquivo de áudio ou de vídeo (POST /v1/transcribe), como faz o nó Transcrever (Transcribe).

transcribe(input: {
  audioUrl: string
  provider?: "elevenlabs-stt" | "incredibly-fast-whisper" | "whisper"
  language?: string
  diarize?: boolean
  tagAudioEvents?: boolean
  wordTimestamps?: boolean
}): Promise<{ jobId: string }>

Prop

Type

providerTempos das palavrasObservações
elevenlabs-sttSempreO único mecanismo que respeita diarize e tagAudioEvents.
incredibly-fast-whisperSó com wordTimestamps: trueSem a opção, o job é concluído e cobrado, com segmentos de frase e uma lista words vazia.
whisperNuncaSó segmentos de frase. wordTimestamps: true é recusado com 400 validation_error antes de qualquer gasto de créditos.

Omitir provider usa whisper; por isso, wordTimestamps: true sem um provider também recebe o 400. Para obter os tempos das palavras, indique elevenlabs-stt, ou incredibly-fast-whisper com wordTimestamps: true. As legendas cinéticas precisam deles.

const { jobId } = await client.audio.transcribe({ audioUrl: talkUrl, provider: "elevenlabs-stt" })

O output_data do job concluído é um TranscribeJobOutput:

CampoUnidadeConteúdo
textA transcrição inteira em uma única string.
languageO código do idioma detectado ou pedido.
wordsmilissegundosUma entrada por palavra: { text, startMs, endMs, speaker? }. Fica vazia quando os tempos das palavras não foram pedidos ao mecanismo.
jsonmilissegundosA transcrição normalizada, { version, language, words, segments? }, que client.edit aceita.
segmentssegundosOs intervalos brutos das frases, só dos mecanismos mais antigos. elevenlabs-stt não retorna nenhum; por isso, leia words.

words tem exatamente o formato das captions que client.media.addCaptions() aceita; assim, você pode corrigir uma transcrição e gravá-la como legendas no vídeo.

Perguntas frequentes

Última atualização

Nesta página