Recast
REST로 분석된 동영상을 내 출연진으로 다시 생성하세요. 실행 견적을 받아 구매하고, 대화형 게이트에 답하고, 오디오를 리믹스하거나, 직접 쓴 스크립트를 가져옵니다.
Nodaro Cloud에서 사용할 수 있습니다
Recast API는 분석된 동영상을 내 출연진으로 다시 생성합니다. 실행 견적을 받고, 계획을 구매하고, 장면별로 렌더링하며, 대화형 실행에서는 진행 중에 출연진, 장면 스틸, 음악을 고릅니다. 영화를 JSON 스크립트로 써서 가져올 수도 있으므로, 원본 동영상이 전혀 없어도 됩니다. recast.nodaro.ai를 움직이는 엔진입니다.
Recast는 Nodaro Cloud에서만 실행되며, 셀프 호스팅 설치에서는 라우트가 404로 응답합니다. 셀프 호스팅 설치에서는 워크플로에서 동영상 분석 노드로 동영상을 분해하고 동영상 생성으로 장면을 다시 생성하세요. 라우트는 Bearer 토큰을 받습니다. 인증을 참조하세요.
엔드포인트
| 메서드 | 경로 | 하는 일 | 비용 |
|---|---|---|---|
POST | /v1/recast/estimate | 실행 견적을 받습니다. | 무료 |
POST | /v1/recast | 실행을 만듭니다. 이때 계획을 구매합니다. | 견적을 받은 계획 |
GET | /v1/recast/:id | 실행을 폴링하고 대기 중인 게이트를 읽습니다. | 무료 |
POST | /v1/recast/:id/start | planned 실행의 렌더링을 시작합니다. | 계획에 포함 |
POST | /v1/recast/:id/select | 대기 중인 게이트에 답합니다. | 무료 |
POST | /v1/recast/:id/estimate-rescore | 새 사운드트랙이나 새 믹스의 견적을 받습니다. | 무료 |
POST | /v1/recast/:id/rescore | 견적을 받은 오디오 변경을 적용합니다. | 견적 가격 |
GET | /v1/video-analysis/authoring-skill | 스크립트 작성 가이드를 가져옵니다. | 무료 |
POST | /v1/video-analysis/import/validate | 스크립트를 검증합니다. | 무료 |
POST | /v1/video-analysis/import | 스크립트를 완료된 분석으로 가져옵니다. | 무료 |
실행 견적 받기와 만들기
실행은 분석 작업에서 시작합니다. 동영상 분석 노드로 분석한 동영상이거나 가져온 스크립트입니다. 먼저 견적을 받으세요. POST /v1/recast/estimate는 실행을 만들 때 쓸 설정을 받아 { totalCredits, breakdown }을 반환합니다.
그다음 POST /v1/recast가 실행을 만들고 계획을 구매합니다. 이 라우트는 { recastId }를 반환합니다. 본문에는 실행이 연결될 내 워크플로의 ID인 workflowId가 필요합니다. 이 값이 없으면 라우트는 400 workflow_id_required로 응답하고, 알 수 없거나 다른 사람의 ID이면 404 workflow_not_found로 응답합니다.
curl -X POST https://app.nodaro.ai/v1/recast/estimate \
-H "Authorization: Bearer $NODARO_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "analysisJobId": "6c1e8a3f-9b2d-4f5a-8e7c-3d1b9a5f2e6c", "resolution": "720p", "interactive": true }'
curl -X POST https://app.nodaro.ai/v1/recast \
-H "Authorization: Bearer $NODARO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"workflowId": "8d3f5b7a-1c9e-4a2d-b6f8-4e2a7c9d1b3f",
"analysisJobId": "6c1e8a3f-9b2d-4f5a-8e7c-3d1b9a5f2e6c",
"resolution": "720p",
"interactive": true,
"clientCapabilities": ["sheet-gate"]
}'import { createClient, StaticTokenAuth } from '@nodaro/sdk'
const client = createClient({
baseUrl: 'https://app.nodaro.ai',
auth: new StaticTokenAuth(process.env.NODARO_API_KEY!),
})
const quote = await client.recast.estimate({ analysisJobId, resolution: '720p', interactive: true })
console.log(quote.totalCredits, quote.breakdown)
const { recastId } = await client.recast.create({
workflowId,
analysisJobId,
resolution: '720p',
interactive: true,
clientCapabilities: ['sheet-gate'],
})nodaro recast estimate --analysis-job <jobId> --resolution 720p --json
nodaro recast create --workflow <workflowId> --analysis-job <jobId> --resolution 720p --json속성
타입
렌더 설정 묶음을 다시 사용하려면 recast-render 프리셋으로 저장하세요. 프리셋을 참조하세요.
실행 추적
GET /v1/recast/:id는 { status, interactive?, capabilities?, audio? }를 반환합니다. 상태는 planning, planned, generating을 거쳐 completed 또는 failed가 됩니다. planned 실행은 POST /v1/recast/:id/start를 기다립니다. 이 라우트가 렌더링을 시작하고 { gvpJobId? }를 반환합니다. 시작 라우트는 멱등이며 추가 비용이 들지 않습니다. 계획의 견적에 렌더링이 이미 포함되어 있기 때문입니다.
curl https://app.nodaro.ai/v1/recast/2e9b4d6f-8a1c-4e3b-9f5d-7c2a4e6b8d1f \
-H "Authorization: Bearer $NODARO_API_KEY"
curl -X POST https://app.nodaro.ai/v1/recast/2e9b4d6f-8a1c-4e3b-9f5d-7c2a4e6b8d1f/start \
-H "Authorization: Bearer $NODARO_API_KEY"const run = await client.recast.get(recastId)
if (run.status === 'planned') await client.recast.start(recastId)nodaro recast status <recastId> --json
nodaro recast start <recastId>대화형 게이트에 답하기
대화형 실행은 서버가 진행합니다. Nodaro가 선택이 필요 없는 단계를 모두 진행하므로, 나는 폴링하고 게이트에 답하기만 하면 됩니다. 게이트가 대기 중이면 상태의 interactive.next에 그 이름이 나옵니다. 게이트는 다음 순서로 열립니다.
gate | 고르는 것 |
|---|---|
cast | 출연진 한 명당 포트레이트 하나입니다. |
sheet | 사람에 한해, 실행이 제공하는 경우입니다. 선택한 얼굴을 공유하는 아이덴티티 시트 3개 중 하나로, 체형과 의상을 고릅니다. |
anchors | 장면 세그먼트의 스틸입니다. |
music | 영화의 한 섹션에 쓸 음악입니다. |
게이트는 생성 요청의 clientCapabilities에 선언한 종류(예: sheet-gate)에 대해서만 열립니다. 그 밖의 게이트는 자동으로 결정되므로, 클라이언트가 답할 수 없는 질문을 받는 일은 없습니다.
POST /v1/recast/:id/select로 답하세요. 선택은 무료입니다.
| 필드 | 하는 일 |
|---|---|
gate | cast, sheet, anchors 또는 music입니다. |
picks | cast와 sheet의 경우: 대기 중인 게이트가 보여 주는 형태로 된 내 선택입니다. |
segment, anchorPicks | anchors의 경우: 세그먼트와, 선택한 스틸인 { start?, end? }입니다. |
section, musicPick | music의 경우: 섹션과 선택한 트랙입니다. |
finishAuto | true이면 이 게이트와 남은 모든 게이트를 자동 평가 AI에 맡깁니다. |
await client.recast.resolveGate(recastId, { gate: 'cast', picks })
await client.recast.resolveGate(recastId, { gate: 'music', section: 0, musicPick: 1, finishAuto: true })방치된 대화형 실행도 안전합니다. 기다리다가 기한이 지나면 스스로 결정합니다.
사운드트랙이나 믹스 변경
테이크가 완료된 후에는 동영상을 다시 렌더링하지 않고도 음악을 바꾸거나 균형을 다시 맞출 수 있습니다. 상태에 capabilities.audioLayers: 1이 있고 테이크에 audio 매니페스트가 있을 때만 작동합니다.
interface RecastAudioManifestV1 {
version: 1
revision: string
mode: 'bed' | 'replace'
present: { music?: true; video?: true }
layers: { music?: { url: string }; video?: { url: string } }
bakedEffectiveGain: { music?: number; video?: number }
pendingRescore?: {
jobId: string
requestId: string
state: 'pending' | 'running'
expectedAudioRevision: string
requestedEffectiveGain: { music?: number; video?: number }
}
}present는 테이크에 있는 오디오 레인을 나열합니다.music과,bed모드에서는 원래video사운드입니다.layers는 브라우저에서 재생할 수 있는 미리보기 파일이 있는 레인만 나열합니다.layers에 없는 레인도 다운로드에는 들어 있을 수 있습니다.bakedEffectiveGain은 현재 파일에서 각 레인의 레벨로, 단위는 퍼센트입니다.- 상태의
resultUrl이 받게 되는 유일한 동영상 URL입니다.
견적 후 적용
견적과 적용에는 같은 변경 내용을 보냅니다. 음악 교체는 최대 하나만 보내세요. audioUrl 하나 또는 brief가 있는 sections 하나 이상이며, 여기에 원하는 완전한 mix를 더합니다. 믹스만 보내도 유효합니다.
{
"expectedAudioRevision": "server-revision",
"sections": [{ "index": 0, "brief": "Sparse analogue pulse" }],
"mix": {
"music": { "gain": 60, "muted": false },
"video": { "gain": 85, "muted": false }
}
}- 견적.
POST /v1/recast/:id/estimate-rescore는 무료이며{ credits, audioRevision, noOp }을 반환합니다. 잔액이 부족해도 가격을 반환합니다. - 적용.
POST /v1/recast/:id/rescore는 같은 본문에requestId(UUID)와 같은expectedAudioRevision을 더해 받습니다.{ recastId, jobId }를 반환하며, 바뀌는 것이 없으면{ recastId, noOp: true, audioRevision }을 반환합니다. 바뀌는 것이 없는 요청은 크레딧을 예약하지 않으며 작업도 만들지 않습니다. - 추적. 상태를 폴링하세요.
audio.pendingRescore가 진행 중인 변경을 보여 주며, 새로 고침해도 유지되고, 새 리비전이 게시되거나 변경이 실패하면 사라집니다. 다음 변경 전에 상태를 다시 읽으세요.
게인은 0~200 사이의 퍼센트이며, 음소거된 레인은 0으로 계산됩니다. present에 있는 레인이나 이 요청이 추가하는 음악만 지정하세요. replace 모드 테이크에는 video 레인이 없으며, 결과에서 모든 레인을 무음으로 만들 수는 없습니다. requestId는 똑같은 요청을 다시 시도할 때만 재사용하세요.
음악을 교체할 때는 완전한 mix를 함께 보내세요. 생략은 결과가 고정된 표준 레벨과 일치할 때만 가능합니다. bed 모드에서는 음악 35와 동영상 100, replace 모드에서는 음악 100입니다. 그 밖의 현재 레벨에서는 409 legacy_mix_mismatch로 응답합니다.
curl -X POST https://app.nodaro.ai/v1/recast/2e9b4d6f-8a1c-4e3b-9f5d-7c2a4e6b8d1f/rescore \
-H "Authorization: Bearer $NODARO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"requestId": "4f6a8c1e-3b5d-4e7f-9a2c-6d8b1f3e5a7c",
"expectedAudioRevision": "server-revision",
"mix": { "music": { "gain": 60, "muted": false }, "video": { "gain": 85, "muted": false } }
}'const status = await client.recast.get(recastId)
const revision = status.audio?.revision
if (status.capabilities?.audioLayers === 1 && revision) {
const operation = {
expectedAudioRevision: revision,
mix: { music: { gain: 60, muted: false }, video: { gain: 85, muted: false } },
}
const quote = await client.recast.estimateRescore(recastId, operation)
if (!quote.noOp) {
await client.recast.rescore(recastId, { ...operation, requestId: crypto.randomUUID() })
}
}스크립트를 영화로 가져오기
영화를 JSON 문서로 쓰고(대개 언어 모델의 도움을 받아), 원본 동영상 없이 Recast로 렌더링할 수 있습니다. 세 라우트 모두 무료입니다.
작성 가이드 읽기
GET /v1/video-analysis/authoring-skill은 가이드를 Markdown으로 반환합니다. 문서의 필드, 허용되는 값, 제한, 오디오 규칙, 검증된 예시가 들어 있습니다. 스크립트를 쓰는 모델에게 이 가이드를 주세요.
스크립트가 유효해질 때까지 검증
{ "script": { … } }와 함께 POST /v1/video-analysis/import/validate를 보내면 { valid, errors, warnings }를 반환합니다. 각 오류에는 path, message, 그리고 대개 수정 루프용으로 쓴 hint가 있습니다. 각 경로를 고치고, valid가 true가 될 때까지 다시 검증하세요.
가져오기
{ "script": { … }, "rightsAttested": true }와 함께 POST /v1/video-analysis/import를 보내면 스크립트를 완료된 분석으로 저장하고 { jobId, created, warnings, json }을 반환합니다. json은 서버가 도출한 필드를 더한 내 문서이므로, 이것을 기준 문서로 보관하세요. 같은 스크립트를 다시 가져오면 같은 jobId가 created: false와 함께 반환됩니다.
Recast 실행
그 jobId를 analysisJobId로 하고 fidelity: "faithful"과 rightsAttested: true를 지정해 실행을 만드세요.
rightsAttested: true는 필수입니다. 직접 작성한 Recast는 브랜드 이름을 포함해 쓴 그대로 렌더링되므로, 이 값으로 스크립트가 내 작품임을 확인합니다. 이 값이 없으면 가져오기는 403 rights_attestation_required로 응답합니다.
문서는 다음 부분으로 구성됩니다.
| 부분 | 담는 내용 |
|---|---|
meta | durationSec, width, height, aspectRatio(너비와 높이에 맞는 16:9 또는 9:16), 그리고 프로젝트 이름이 되는 필수 title입니다. |
look | 선택입니다. 영화의 전체적인 룩입니다. |
slots | 출연진과 배경으로, 각각 person, object 또는 background 중 하나의 role이 있습니다. |
scenes | 장면으로, 0부터 빠짐없이 번호를 매기며 각각 8초 이하입니다. 전체 길이는 4초부터 플랫폼의 실행 한도까지입니다. |
실행 한도를 넘는 문서는 잘리지 않고 거부됩니다. sceneNumber, slotRefs, visualResolved는 쓰지 마세요. 서버가 이 값을 도출하며 내가 쓴 값은 무시합니다. 그래서 편집기에서 JSON 복사로 복사한 분석도 그대로 가져올 수 있습니다.
curl https://app.nodaro.ai/v1/video-analysis/authoring-skill \
-H "Authorization: Bearer $NODARO_API_KEY" > recast-authoring.md
curl -X POST https://app.nodaro.ai/v1/video-analysis/import \
-H "Authorization: Bearer $NODARO_API_KEY" \
-H "Content-Type: application/json" \
-d "{ \"script\": $(cat script.json), \"rightsAttested\": true }"const guide = await client.recast.authoringSkill()
const check = await client.recast.validateScript(script)
if (check.valid) {
const { jobId } = await client.recast.importScript(script, { rightsAttested: true })
}nodaro recast skill > recast-authoring.md
nodaro recast validate --file script.json
nodaro recast import --file script.json --rights-attested --jsonMCP에서 사용
AI 어시스턴트는 get_recast_authoring_skill, validate_recast_script, import_recast_script, start_recast, get_recast_status, resolve_recast_gate로 같은 루프를 실행합니다. start_recast는 먼저 가격을 보여 주고, 확인을 위해 다시 호출했을 때만 크레딧을 씁니다. MCP로 Recast 사용을 참조하세요.
오류
| 상태 | 코드 | 의미 |
|---|---|---|
400 | workflow_id_required | workflowId 없이 POST /v1/recast를 보냈습니다. |
400 | validation_error, duplicate_section, unknown_section, all_audio_silent | 요청이나 오디오 변경이 잘못되었습니다. |
402 | insufficient_credits | 계정의 크레딧이 계획이나 오디오 변경에 부족합니다. |
403 | rights_attestation_required | 스크립트 가져오기에 rightsAttested: true가 없습니다. |
404 | workflow_not_found | 워크플로가 존재하지 않거나 내 것이 아닙니다. |
404 | not_found | 실행이 존재하지 않거나, 셀프 호스팅 인스턴스입니다. |
409 | audio_layers_unavailable, audio_layer_unavailable, audio_preview_unavailable | 테이크에 리비전이 있는 오디오가 없거나, 지정한 레인이 없거나, 쓸 수 있는 미리보기가 없습니다. |
409 | rescore_sections_unavailable, legacy_mix_mismatch | 이 테이크에서는 음악 섹션을 교체할 수 없거나, mix 없는 교체가 현재 레벨과 맞지 않습니다. |
409 | stale_audio_revision, rescore_in_progress, idempotency_conflict | 오디오가 바뀌었거나, 다른 변경이 실행 중이거나, requestId가 다른 요청에 재사용되었습니다. 상태를 읽고 다시 시도하세요. |
자주 묻는 질문
Recast란 무엇인가요?
Recast는 분석된 동영상을 장면별로 내 출연진과 함께 다시 생성합니다. 원본은 Nodaro가 분석한 실제 동영상일 수도 있고, 내가 JSON으로 써서 가져온 시나리오일 수도 있습니다. recast.nodaro.ai를 움직이는 엔진입니다.
결제하기 전에 Recast 비용을 어떻게 알 수 있나요?
실행을 만들 때와 같은 설정으로 POST /v1/recast/estimate를 호출하세요. 크레딧 총액과 내역을 반환하며, 무료입니다. 그다음 POST /v1/recast가 계획을 구매합니다.
원본 동영상 없이 영화를 만들 수 있나요?
네. 영화를 JSON 스크립트로 쓰고, 무료로 검증한 다음, 가져오세요. 가져오기는 fidelity를 faithful로 설정해 Recast할 분석을 만들므로, 모든 장면이 쓴 그대로 렌더링됩니다.
대화형 실행이 시트 게이트에서 멈추지 않는 이유는 무엇인가요?
게이트는 생성 요청의 clientCapabilities에서 내 클라이언트가 답할 수 있다고 선언한 경우에만 열립니다. 선언하지 않은 게이트 종류는 자동으로 결정됩니다.
Recast는 셀프 호스팅 설치에서도 작동하나요?
아니요. Recast 라우트는 Nodaro Cloud에서만 실행되며, 셀프 호스팅 설치에서는 404로 응답합니다.
관련 문서
Recast
동영상 분석
프리셋
보이스 및 미디어
작업
최종 업데이트