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

Edição

Edite podcasts e vídeos longos em TypeScript. Detecte silêncio, sincronize gravações, planeje cortes a partir de uma transcrição e renderize uma EDL.

client.edit reúne as ferramentas de edição para podcasts e vídeos longos. Ele encontra silêncios, mede o deslocamento de tempo entre várias gravações, planeja um corte a partir de uma transcrição e renderiza uma lista de decisões de edição (EDL) em um vídeo ou arquivo de áudio final. Quatro métodos iniciam um job e retornam { jobId }, que você consulta periodicamente com client.jobs.getStatus(). Um quinto, remapTranscript(), roda localmente, sem requisição.

Métodos

MétodoEndpointO que faz
edit.silenceDetect(input)POST /v1/silence-detectEncontra os trechos silenciosos de uma fonte de áudio ou vídeo
edit.audioSync(input)POST /v1/audio-syncMede o deslocamento de tempo entre gravações, de 2 a 6
edit.editPlan(input)POST /v1/edit-planPlaneja um corte mais enxuto, clipes curtos ou capítulos a partir de uma transcrição
edit.applyEdl(input)POST /v1/apply-edlRenderiza uma EDL em um vídeo ou um arquivo de áudio
edit.remapTranscript(edl, transcript)Nenhum, localMove os tempos de uma transcrição para a linha do tempo editada

Editar um podcast pelo código

Transcrever a gravação

Execute client.audio.transcribe() com um mecanismo que retorne os tempos por palavra. O output_data.json dele é a transcrição de que o plano precisa.

Encontrar o silêncio

Execute silenceDetect() na gravação principal. O output_data.json dele contém os trechos silenciosos.

Planejar o corte

Execute editPlan() no modo tighten com a transcrição, as fontes e o silêncio. Leia o plano com unwrapEditPlanOutput().

Renderizar

Passe o plano para applyEdl(). O job concluído contém o vídeo ou o áudio editado.

Enviar vídeoO episódioTranscreverTempos por palavraDetectar silêncioPlano de ediçãoEnxugarAplicar EDL
A mesma cadeia de edição em nós: transcrever e encontrar o silêncio, planejar um corte mais enxuto e depois renderizá-lo.
import { unwrapEditPlanOutput } 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, 3_000))
  }
}

// 1. Transcribe with word timings
const tr = await client.audio.transcribe({ audioUrl: masterUrl, provider: "elevenlabs-stt" })
const transcript = (await outputOf(tr.jobId)).json

// 2. Find the silence
const sd = await client.edit.silenceDetect({ audioUrl: masterUrl, thresholdDb: -35 })
const silence = (await outputOf(sd.jobId)).json

// 3. Plan a tighter cut
const plan = await client.edit.editPlan({
  mode: "tighten",
  planTier: "standard",
  transcript,
  sources: [{ id: "ep", url: masterUrl, kind: "video", role: "master-audio" }],
  silence,
})
const edl = unwrapEditPlanOutput(await outputOf(plan.jobId))

// 4. Render the plan
const render = await client.edit.applyEdl({ edl, output: "video", quality: "final" })
const { videoUrl } = await outputOf(render.jobId)

As mesmas etapas existem como nós: Transcrever (Transcribe), Detectar silêncio (Silence Detect), Plano de edição (Edit Plan) e Aplicar EDL (Apply EDL).

client.edit

edit.silenceDetect(input)

Encontra os trechos silenciosos de uma fonte de áudio ou vídeo. Roda no servidor, sem modelo de IA.

silenceDetect(input: SilenceDetectInput): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.edit.silenceDetect({ audioUrl: masterUrl, minSilenceMs: 900 })

O output_data.json do job concluído é um objeto SilenceRanges: { version, ranges: [{ startMs, endMs }], durationMs }. Passe o objeto inteiro como silence para editPlan().

edit.audioSync(input)

Mede, pelo som, o deslocamento entre os relógios de 2 a 6 gravações de uma mesma conversa, como faz o nó Sincronizar áudio (Audio Sync). Roda no servidor, sem modelo de IA. Custa 11 créditos por fonte depois da primeira: 11 para 2 fontes, 33 para 4 e 55 para 6.

audioSync(input: AudioSyncInput): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.edit.audioSync({
  sources: [
    { id: "mic", url: micUrl },
    { id: "camA", url: camAUrl },
  ],
  reference: "mic",
})

O output_data.json do job concluído é um AudioSyncResult:

{
  version: number
  reference: string // the source every offset is measured against
  offsets: Array<{
    sourceId: string
    offsetMs: number              // referenceMs = sourceMs + offsetMs
    confidence: number            // 0 to 1; below 0.5 a note asks you to check by ear
    driftMsPerHour: number | null // measured, never corrected; null when the overlap was too short
  }>
  notes: string[] // low confidence, drift above 33 ms over the overlap, no shared sound
}

Com a gravação principal como reference, cada offsetMs é exatamente o offsetMs dessa fonte na sua EDL. Uma requisição malformada é recusada com um NodaroError cujo code é validation_error, antes que qualquer crédito seja reservado. Isso inclui menos de 2 ou mais de 6 fontes, um id repetido ou um reference que não seja um dos ids.

edit.editPlan(input)

Planeja uma edição a partir de uma transcrição com tempos, como faz o nó Plano de edição. Escreve um de três tipos de plano: um corte mais enxuto da gravação inteira, um conjunto de clipes curtos ou capítulos.

editPlan(input: EditPlanInput): Promise<{ jobId: string }>

Prop

Type

import { unwrapEditPlanOutput } from "@nodaro/sdk"

const { jobId } = await client.edit.editPlan({
  mode: "clips",
  planTier: "standard",
  transcript,
  sources: [{ id: "ep", url: masterUrl, kind: "video", role: "master-audio" }],
  silence,
  count: 5,
  targetAspect: "9:16",
})
const { data } = await client.jobs.getStatus(jobId) // poll until completed
const clips = unwrapEditPlanOutput(data.output_data) // one EDL per clip

Leia a saída do job concluído com unwrapEditPlanOutput(). Essa função retorna um Edl no modo tighten, um array de Edl no modo clips e um ChapterSet no modo chapters.

Em uma instalação self-hosted, este método precisa de uma conexão com o Nodaro Cloud. Sem ela, falha com 503 nodaro_connection_required.

edit.applyEdl(input)

Renderiza uma lista de decisões de edição em um vídeo ou um arquivo de áudio, como faz o nó Aplicar EDL.

applyEdl(input: ApplyEdlInput): Promise<{ jobId: string }>

Prop

Type

const { jobId } = await client.edit.applyEdl({ edl, output: "video", quality: "proxy", crossfadeMs: 80 })

A EDL é verificada antes que qualquer crédito seja reservado. Uma fonte desconhecida, um segmento sem imagem em uma edição de vídeo ou mais de 180 minutos de saída em uma única renderização falham com um NodaroError cujo code é invalid_edl. A duração é medida depois dos crossfades. O message indica o problema, por exemplo, que a edição renderiza 200 minutos e precisa ser dividida em partes de no máximo 180 minutos.

edit.remapTranscript(edl, transcript)

Move uma transcrição para a linha do tempo de uma edição, localmente, sem requisição. Descarta as palavras dentro dos trechos cortados, recorta as palavras que atravessam um corte e desloca todos os tempos para a saída editada. applyEdl() faz o mesmo no servidor quando você passa um transcript para ele.

remapTranscript(edl: Edl, transcript: Transcript): Transcript

Prop

Type

const editedTranscript = client.edit.remapTranscript(edl, transcript)
// caption the edited video without another transcription

Use-o para legendar uma edição sem renderizar e sem uma segunda transcrição. Ele também é a opção mais rápida para uma transcrição grande quando você só precisa dos novos tempos.

Perguntas frequentes

Última atualização

Nesta página