Nodaro ドキュメント
ドキュメントノードリファレンスモデルAI エージェント(MCP)開発者向けセルフホスティングリサーチ
TypeScript SDK

スタジオプロダクション

TypeScript から、プランでスタジオプロダクションを作成し、操作で編集し、静止画とクリップを生成し、計画フレームをレビューし、共有またはコピーします。

Nodaro Cloud で利用できます

スタジオプロダクションは、設定に映画のショットを保持する Nodaro のワークフローです。各ショットには、構図を決めた静止画、任意のアニメーションクリップ、そしてそれらを作ったプラン、ルック、キャストの割り当て、ボイスがあります。client.studio はプロダクションを読み書きするので、スクリプト、AI アシスタント、スタジオアプリが、1 つのプロダクションを一緒に操作できます。client.shots は、共有リンクの背後にある、共有されたショットのレコードを保存します。これらのメソッドは、スタジオプロダクション API を呼び出します。作成ガイドについては、MCP で使うスタジオプロダクションを参照してください。

スタジオプロダクションは、Nodaro Cloud 上で動作します。ルートが提供されていない環境では、すべてのメソッドが NotFoundError をスローします。利用できるかどうかを一度確認するには、client.studio.productions.list() を呼び出してください。プロダクション機能がある環境は空のページを返し、ない環境は NotFoundError をスローします。

2 種類のメソッド

client.studio には 2 つの層があります。どちらも、同じプロダクションを操作します。

層用途返すもの
client.studio.productions.*プロダクションのドキュメントです。プランからの作成、操作による編集、静止画とクリップの生成、ボイスと音楽の追加、共有とコピーです。ペイロードそのもの
client.studio.*計画フレームです。対応状況、キーフレームの生成とレビュー、バンドル、エディターの保存、リビジョンを確認したうえでのリンク共有です。API の { data } エンベロープ

エンベロープには型が付きますが、プロダクションのドキュメントには付きません。プロダクション、ショット、操作は、オープンな JSON である Record<string, unknown> です。分岐に使うものにはすべて型が付きます。version、rebased、receipts、warnings、見積もりの credits、実行の jobIds です。操作の語彙はサーバーから得られます。skill() から読み取ってください。

client.studio.productions のメソッド

メソッド内容
skill()作成ガイド、カタログ、プランのスキーマ、操作ガイドを読み取ります
validatePlan(plan)プランを無料でチェックします
list(opts?)自分のプロダクションを一覧表示します
get(productionId, opts?)プロダクションを読み取ります
exportPlan(productionId, opts?)書き出しの手順を計画し、料金を出します
create(input?)プロダクションを作成します。プランから作成することもできます
ops(productionId, input)操作のバッチを適用するか、プレビューします
reconcile(productionId)完了した生成を結果に反映します
importPlan(productionId, plan, opts?)プランのシーンをプロダクションに追加します
describe(productionId, input)ブリーフをシーンに変換します
generate()、generateStill()、generateClip()ショットのフレームを決めるか、アニメーションにします
frame(productionId, input)ショットのクリップから静止画を取り出します
voice(productionId, input)ショットのセリフを読み上げます
revoice(productionId, input)ショットのクリップに含まれる声を差し替えます
music(productionId, input)映画にサウンドトラックを付けます
share()、unshare()、clone()共有リンクを開く、閉じる、またはプロダクションをコピーします

client.studio.productions

productions.skill()

作成ガイド、カタログ全体、プランの JSON Schema、操作ガイドを返します。サーバーが実行しているバージョンから生成されます。無料です。

skill(): Promise<{ skill: string; catalog: string; schema: Record<string, unknown>; operating: string; generatedFrom: object }>
const { skill, schema, operating } = await client.studio.productions.skill()

operating には、ops() が受け付ける操作が一覧になっています。語彙をハードコードせず、実行時に読み取ってください。

productions.validatePlan(plan)

プランがプロダクションになる前に、そのプランをチェックします。無料で、何も保存せず、キャストの名前を自分のライブラリと照合します。valid が true になるまで errors を直してチェックを繰り返し、そのあと create({ plan }) を呼び出してください。

validatePlan(plan: Record<string, unknown>): Promise<{
  valid: boolean
  errors: Array<{ path: string; message: string; hint?: string }>
  warnings: Array<{ path: string; message: string; hint?: string }>
  summary?: { name?: string; scenes: number; shots: number; cast: number; bound: number }
}>

Prop

Type

const check = await client.studio.productions.validatePlan(plan)
if (!check.valid) console.log(check.errors)

summary.bound は、自分のライブラリのキャラクターと一致した、キャストのエントリーの数です。

productions.list(opts?)

自分のプロダクションを、新しい順に一覧表示します。

list(opts?: { limit?: number; cursor?: string; includeArchived?: boolean }): Promise<{ data: StudioProduction[]; nextCursor?: string }>

Prop

Type

const { data: productions } = await client.studio.productions.list({ limit: 20 })

productions.get(productionId, opts?)

プロダクションを読み取ります。純粋な読み取りであり、完了したジョブを結果に反映することはありません。ジョブの完了を待っている場合は、先に reconcile() を呼び出してください。

get(productionId: string, opts?: { detail?: "summary" | "full"; shotId?: string }): Promise<StudioProduction>

Prop

Type

const production = await client.studio.productions.get(productionId, { detail: "full" })

productions.exportPlan(productionId, opts?)

映画を組み立てる手順を、順番どおりに、料金とともに返します。何も実行せず、何も消費しません。手順は、通常のノードのメソッドで自分で実行してください。

exportPlan(productionId: string, opts?: { upscale?: boolean }): Promise<{
  canExport: boolean
  steps: Array<{ id: string; label: string; node: string; creditModel: string; credits: number | null; params: Record<string, unknown> }>
  resultStepId: string | null
  estimate: number | null
  unpriced: string[]
}>

Prop

Type

const plan = await client.studio.productions.exportPlan(productionId)
console.log(plan.canExport, plan.estimate)
for (const step of plan.steps) console.log(step.id, step.label, step.node, step.credits)

canExport は、プロダクションのクリップが 2 本未満の場合に false になります。estimate は、いずれかの手順に料金がない場合に null になります。合計の一部だけを示すと、実際より低い金額に見えてしまうためです。unpriced には、それらの手順のモデルが示されます。各手順の node はノードタイプで、merge-video-audio、combine-videos、video-upscale などです。

productions.create(input?)

プロダクションを作成します。同じ呼び出しで、任意でプランを反映することもできます。

create(input?: { name?: string; plan?: Record<string, unknown> }): Promise<{
  production: StudioProduction
  warnings?: Array<{ path: string; message: string; hint?: string }>
  summary?: { shotsAdded: number; castEnrolled: number; castBound: number }
}>

Prop

Type

const { production, summary } = await client.studio.productions.create({ name: "Rome chase", plan })

productions.ops(productionId, input)

プロダクションに、操作のバッチを適用します。すべての変更は操作であり、ショットの ID、ロールのスラッグ、結果のジョブ ID など、安定したキーで指定します。位置で指定することはありません。

ops(productionId: string, input: StudioOpsRequest): Promise<StudioOpsResponse>
ops(productionId: string, input: StudioOpsRequest & { dryRun: true }): Promise<StudioOpsDryRunResponse>

Prop

Type

const result = await client.studio.productions.ops(productionId, {
  ops: [/* operations from the operating guide */],
  baseVersion: version,
  clientRequestId: crypto.randomUUID(),
})
version = result.version // carry it forward as the next baseVersion
for (const r of result.receipts) console.log(r.summary)
  • アトミックです。不正な操作が 1 つでもあると、バッチ全体が StudioOpError で拒否されます。その opIndex が、その操作を示します。何も書き込まれません。
  • リベースされます。2 人が同時に 1 つのプロダクションを編集できます。古いバージョンをもとに組み立てたバッチも、最新のバージョンに適用され、rebased は true になります。
  • レシートです。receipts には、操作ごとに過去形の 1 行が入ります。たとえば「Deleted take 2 of Shot 1 (in the bin)」のようなものです。操作の影響が、その名前の対象を超えて及ぶ場合、その impact に、更新すべき keyframeIds と shotIds が示されます。
  • 応答をそのまま採用します。手元のコピーを production に置き換え、version を次に持ち越してください。古いコピーにマージしないでください。

バッチをプレビューする。dryRun: true を指定すると、応答は、そのバッチが何を行うかを示すだけになります。そのため、アシスタントの編集を、先に人が承認できます。応答には dryRun、version、receipts、warnings が含まれ、production は含まれません。各レシートには class が加わります。S は安全、D は削除、P は作品にアクセスできる人の変更、$ はクレジットの消費です。操作がゴミ箱に何かを入れた場合にのみ、restorable も加わります。restorable ?? false として読み取ってください。

dryRun: true は、呼び出し自体のオブジェクトの中に、リテラルとして書いてください。変数を経由して渡すと、型が boolean に広がってしまい、実際にはプレビューのままなのに、呼び出しの型は適用として扱われてしまいます。

プレビューは、リクエストを 2 回送信します。まず、デプロイメントがプレビューに対応していることを確認する空のバッチを送り、次に自分のバッチを送ります。そうしないと、プレビューに対応していないデプロイメントは、警告なしにバッチを適用してしまいます。この結果、2 種類のエラーが起こり得ます。

import { StudioPreviewAppliedError, StudioPreviewUnavailable } from "@nodaro/sdk"

try {
  const preview = await client.studio.productions.ops(productionId, { ops, baseVersion, dryRun: true })
  for (const r of preview.receipts) console.log(r.class, r.summary, r.restorable ?? false)
} catch (err) {
  if (err instanceof StudioPreviewUnavailable) {
    // Nothing was sent. Say that no preview is available; do not apply the batch instead.
  } else if (err instanceof StudioPreviewAppliedError) {
    // The batch was applied. Adopt err.applied.production and err.applied.version.
    // Do not send it again. When err.applied is undefined, read the production first.
  } else {
    throw err
  }
}

productions.reconcile(productionId)

前回確認して以降に完了したすべての生成を結果に反映し、まだ実行中のものを報告します。アプリを開かなくても、完了したジョブを結果に変える唯一の呼び出しであり、何かが反映されたときにしか書き込みを行いません。

reconcile(productionId: string): Promise<{
  landed: string[]
  pending: string[]
  failed: string[]
  warnings: string[]
  production: StudioProduction
  version: number
}>

Prop

Type

const { landed, pending } = await client.studio.productions.reconcile(productionId)

landed には、そのメディアがプロダクションに反映されたジョブが一覧になります。pending には、まだ実行中のジョブが、failed には、失敗またはキャンセルされたジョブが一覧になります。

productions.importPlan(productionId, plan, opts?)

既存のプロダクションに、プランのシーンを追加します。

importPlan(productionId: string, plan: Record<string, unknown>, opts?: { mode?: "append" }): Promise<{
  production: StudioProduction
  warnings?: Array<{ path: string; message: string; hint?: string }>
  summary?: { shotsAdded: number; castEnrolled: number; castBound: number }
}>

Prop

Type

await client.studio.productions.importPlan(productionId, extraScenesPlan)

productions.describe(productionId, input)

監督(Director)を使って、ブリーフをシーンに変換します。ジョブを開始し、すぐに応答を返します。シーンは reconcile() を通じて反映されます。プロダクションは、その実行が保留中の下書きとして記録された状態で返ってきます。

describe(productionId: string, input: {
  brief: string
  llmModel: string
  mode?: "append" | "replace"
  label?: string
  clientRequestId?: string
}): Promise<{ production: StudioProduction; jobId: string }>

Prop

Type

const { jobId } = await client.studio.productions.describe(productionId, {
  brief: "A courier races across Rome in the rain to deliver a violin.",
  llmModel,
})

静止画とクリップを生成する

generateStill() はショットのフレームを決め、generateClip() はそれをアニメーションにし、generate() は kind に応じてどちらかを行います。実行は、ジョブを送信し、プロダクションに保留中のマーカーを記録して、応答を返します。何分も待つことはありません。リクエストは、ショット自身のプラン、ルック、リファレンスからサーバー側で組み立てられるため、スクリプトからの呼び出しも、アプリでのクリックも、同じメディアを作ります。

generate(productionId: string, input: StudioGenerateRequest): Promise<StudioGenerateResult>
generateStill(productionId: string, shotId: string, opts?: StudioGenerateOptions): Promise<StudioGenerateResult>
generateClip(productionId: string, shotId: string, opts?: StudioGenerateOptions): Promise<StudioGenerateResult>

Prop

Type

import { isStudioGenerateEstimate } from "@nodaro/sdk"

const quote = await client.studio.productions.generateStill(productionId, "shot-2", { count: 2, dryRun: true })
if (isStudioGenerateEstimate(quote)) console.log(quote.credits) // null means unpriced, not free

const run = await client.studio.productions.generateStill(productionId, "shot-2", {
  count: 2,
  clientRequestId: crypto.randomUUID(),
})
  • 先に見積もります。dryRun: true は実行の料金を見積もるだけで、何も書き込みません。応答は isStudioGenerateEstimate() で絞り込みます。
  • 安全に再試行します。同じ clientRequestId を使うと、再試行は、最初の呼び出しで開始したジョブを、deduped: true の印とともに返し、何も送信せず、新たな料金もかかりません。トークンなしで、有料の呼び出しを再試行しないでください。このページのすべての有料の呼び出しがこれを受け付けます。frame() と voice() も含みます。
  • レーンは自動で選ばれます。クリップの場合、動画のルートはショットの入力から選ばれ、lane として返されます。generate-video または text-to-video です。

productions.frame(productionId, input)

ショットの有効なクリップから静止画を取り出し、target が示す場所に置きます。数秒で終わるジョブの完了を待ってから、変更後のプロダクションと、画像の url を返します。

frame(productionId: string, input: {
  shotId: string
  mode?: "first" | "last" | "timestamp"
  timestamp?: number
  target?: "new-shot" | "start-frame" | "end-frame" | "still"
  clientRequestId?: string
}): Promise<StudioMediaResponse>

Prop

Type

const { url } = await client.studio.productions.frame(productionId, { shotId: "shot-2", mode: "last" })

productions.voice(productionId, input)

ショットのセリフを読み上げ、そのショットに記録します。ジョブの完了を待ちます。

voice(productionId: string, input: {
  shotId: string
  text: string
  voiceId?: string
  voiceType?: "premade" | "custom" | "library"
  ttsProvider?: string
  delivery?: Record<string, number>
  clientRequestId?: string
}): Promise<StudioMediaResponse>

Prop

Type

await client.studio.productions.voice(productionId, { shotId: "shot-3", text: "We're out of time." })

productions.revoice(productionId, input)

ショットの有効なクリップに含まれる声を差し替えます。数分かかるため、jobId を返し、新しいクリップはそのマーカーを通じて反映されます。

revoice(productionId: string, input: { shotId: string; plan: Record<string, unknown>; clientRequestId?: string }): Promise<{ production: StudioProduction; jobId: string }>

Prop

Type

const { jobId } = await client.studio.productions.revoice(productionId, {
  shotId: "shot-3",
  plan: recastPlan, // the speaker-ordered plan the voice recast route takes
})

productions.music(productionId, input)

映画にサウンドトラックを付けます。完成したトラックは、その保留中のマーカーを通じて反映されます。

music(productionId: string, input: {
  prompt: string
  duration?: number
  instrumental?: boolean
  vocalGender?: string
  model?: string
  clientRequestId?: string
}): Promise<{ production: StudioProduction; jobId: string }>

Prop

Type

const { jobId } = await client.studio.productions.music(productionId, {
  prompt: "Tense strings building to a chase",
  instrumental: true,
})

共有とコピー

share() はリンクによる共有ビューを開き、unshare() は再び閉じます。共有は独立した呼び出しであり、操作の一部になることはありません。そのため、作品を見られる人が、編集の副作用として変わることはありません。clone() は、自分が所有している、または閲覧できるプロダクションを、自分のスタジオのプロジェクトにコピーします。

share(productionId: string): Promise<StudioProduction>
unshare(productionId: string): Promise<StudioProduction>
clone(productionId: string, input?: { name?: string }): Promise<StudioProduction>

Prop

Type

await client.studio.productions.share(productionId)
const copy = await client.studio.productions.clone(productionId, { name: "Rome chase, take 2" })

コピーは、非公開で、アーカイブされていない状態で始まります。共有とアーカイブの状態は引き継がれません。コピーは自分から見えるソースの状態をもとに作られるため、ほかの人のゴミ箱の中身が一緒に来ることはありません。

client.studio:計画フレーム

これらのメソッドは、計画フレームとそのレビューを扱います。コントロールを提示する前に capabilities() を確認し、プロダクションを開き直すときは、一度 reconcile() を呼び出してください。送信への応答が失われている場合があるためです。ここにあるメソッドは、そのメソッドを呼び出さない限り、生成を開始したり候補を採用したりすることはありません。

メソッド内容
capabilities()プランのバージョンと、このデプロイメントが対応している操作を読み取ります
skill()、list()、validatePlan()、create()productions 層と同じ読み取りと作成を、エンベロープの形で行います
get(id, options?)プロダクションを、その対応状況とともに読み取ります
edit(id, input)リビジョンの条件付きで、操作を適用します
saveEditorState(id, input)読み込んだリビジョンに対して、通常のエディターのフィールドを保存します
generateKeyframe(id, input)計画フレームを、採用せずに生成します
generateShot(id, input)静止画またはクリップを見積もるか、送信します
acceptKeyframe(id, review, concurrency?)レビュー済みの候補を採用します
reconcile(id)何も採用せずに、完了したジョブを記録します
setShared(id, input)レビュー済みのリビジョンに結び付けて、共有または共有解除します
clone(id, input?)保存済みのプロダクションをコピーします
importBundle(input)移植可能なプロダクションをインポートします
appendBundle(id, input)プロダクションにバンドルを追加します

studio.capabilities()

プランのバージョンと、このデプロイメントが対応している計画フレームの操作を返します。

capabilities(): Promise<{ data: StudioProductionCapabilities }>
const { data: caps } = await client.studio.capabilities()
if (caps.operations.generateKeyframes) showGenerateFrameButton()

operations には、操作ごとに 1 つのフラグがあります。readKeyframes、editKeyframes、generateKeyframes、acceptKeyframes、rejectKeyframes、editSequencePlans、generateLinkedClips、retakeLinkedClips、saveEditorState、revisionedSharing、editableSharedCopies、cloneLinkedProductions、importPlannedBundles、importLinkedBundles、appendPlannedBundles、appendLinkedBundles です。automaticAcceptance と unattendedGeneration は、常に false です。

studio.skill()、list()、validatePlan()、create()

productions.skill()、list()、validatePlan()、create() と同じ呼び出しで、{ data } エンベロープで返されます。list() では、行は response.data.data に入ります。

skill(): Promise<{ data: Record<string, unknown> }>
list(options?: { limit?: number; cursor?: string; includeArchived?: boolean }): Promise<{ data: {
  data: Array<{ id: string; name: string; version: number; updatedAt: string; thumbnailUrl: string | null; shared: boolean; archived: boolean; shotCount: number }>
  nextCursor?: string
} }>
validatePlan(plan: Record<string, unknown>): Promise<{ data: { valid: boolean; errors: object[]; warnings: object[]; summary?: object } }>
create(input: { name?: string; plan?: Record<string, unknown> }): Promise<{ data: StudioProductionReply }>

Prop

Type

const { data: page } = await client.studio.list({ limit: 20 })
for (const row of page.data) console.log(row.name, row.shotCount)

studio.get(id, options?)

プロダクションを、その対応状況とともに読み取ります。ジョブを結果に反映することはありません。

get(id: string, options?: { detail?: "summary" | "full"; shotId?: string }): Promise<{ data: StudioProductionReply }>

Prop

Type

const { data: { production } } = await client.studio.get(productionId, { detail: "full" })
const frame = production.keyframes?.[0] // { id, label, revision, previewUrl, acceptedUrl, pending, ... }

studio.edit(id, input)

リビジョンの条件付きで操作を適用し(POST .../:id/ops)、エンベロープの形で返します。remove_shot、restore_trashed、purge_trashed には、厳密な baseVersion を使ってください。また、シーンを削除する前に、結び付けられたシーケンスのセグメントを切り離してください。

edit(id: string, input: { ops: Array<{ op: string; [field: string]: unknown }>; baseVersion?: number; strict?: boolean; clientRequestId?: string }): Promise<{ data: StudioProductionReply & { version: number; rebased: boolean; receipts: object[] } }>

Prop

Type

await client.studio.edit(productionId, {
  ops: [{ op: "reject_keyframe_result", keyframeId, expectedRevision, resultKey, expectedAcceptedResultKey, reason: "Face drifted" }],
  baseVersion: version,
  strict: true,
})

edit() で送る、計画フレームの操作の例です。

  • reject_keyframe_result は、生成を行わずに Needs revision を記録します。operations.rejectKeyframes が必要です。
  • update_sequence_plan は、シーケンスの順番に並んだセグメント(それぞれ { shotId, startKeyframeId, endKeyframeId })を編集し、シーンの ID はそのまま保ちます。operations.editSequencePlans が必要です。
  • detach_sequence_segment は、mode を clear または keep-accepted に設定して、1 つのセグメントを独立させます。operations.editSequencePlans が必要です。
  • purge_trashed は、表示しているゴミ箱のエントリーを空にし、clear_trash はすべてのゴミ箱を、計画フレームも含めて空にします。

studio.saveEditorState(id, input)

読み込んだリビジョンに対して、通常のエディターのフィールドを保存します。先に operations.saveEditorState を確認してください。保存は常に厳密です。競合すると 409 で失敗するため、ローカルの下書きを保持したまま、解決する前に読み込み直してください。

saveEditorState(id: string, input: { expectedVersion: number; graph: object; clientRequestId?: string })

Prop

Type

await client.studio.saveEditorState(productionId, { expectedVersion: version, graph })

この保存では、フレームのプラン、採用状態、エンドポイントの結び付け、ジョブの履歴、保護されたゴミ箱のエントリー、共有設定は変更できません。それらには、それぞれ専用のアクションを使ってください。

studio.generateKeyframe(id, input)

計画フレームを、採用せずに生成します。フレームの生成には、見積もりのためのドライランはありません。

generateKeyframe(id: string, input: { keyframeId: string; expectedRevision: number; clientRequestId?: string; overrides?: Record<string, unknown> }): Promise<{ data: { jobIds: string[]; deduped?: true; lane?: string } }>

Prop

Type

const { data: caps } = await client.studio.capabilities()
const { data: { production } } = await client.studio.get(productionId, { detail: "full" })
const frame = production.keyframes?.[0]

if (frame && caps.operations.generateKeyframes) {
  const { data: generation } = await client.studio.generateKeyframe(productionId, {
    keyframeId: frame.id,
    expectedRevision: frame.revision,
    clientRequestId: crypto.randomUUID(),
  })
  // follow generation.jobIds with client.jobs, then call reconcile()
}

生成は、候補を採用するものではなく、キャラクターのポートレートを作成するものでもありません。説明しかないキャストのリファレンスには、ポートレートは必要ありません。

studio.generateShot(id, input)

ショットの静止画またはクリップを、見積もるか送信します。

generateShot(id: string, input: StudioShotGenerationInput): Promise<{ data: StudioGenerationReply }>

Prop

Type

const { data: quote } = await client.studio.generateShot(productionId, { kind: "clip", shotId, dryRun: true })
if ("inputHash" in quote) {
  await client.studio.generateShot(productionId, {
    kind: "clip",
    shotId,
    expectedInputHash: quote.inputHash,
    clientRequestId: crypto.randomUUID(),
  })
}

リンクされたクリップ。計画フレームの間のクリップの見積もりには、inputHash、採用済みの endpointPins、正規化された長さ、解像度、アスペクト比、サウンドの設定、そして料金に使われた creditIdentifier が含まれます。確認した inputHash を、expectedInputHash として渡してください。見積もり以降に、設定または採用済みのフレームが変わっていた場合、呼び出しは、何かが送信される前に 409 sequence_quote_changed で失敗します。新しい見積もりを求めてください。見積もりに含まれるクレジットは概算であり、生成では現在の料金が確保されます。

撮り直し。operations.retakeLinkedClips が true の場合、kind: "clip" と shotId とともに retakeResultKey を渡し、dryRun: true で見積もります。確認した expectedInputHash と新しい clientRequestId を付けて送信し、mode、overrides、count は省略してください。撮り直しは、プランや採用状態が変わった後でも、元のリクエストと保持されているフレーム画像を再利用します。以前のテイクは履歴に残ります。検証できる元のリクエストや保持された画像がないテイクは拒否され、撮り直しは同じ動画のバイトデータを再現するものではありません。

studio.acceptKeyframe(id, review, concurrency?)

計画フレームの、レビュー済みの候補を採用します。これは独立した、明示的なステップです。生成がこれを呼び出すことはありません。

acceptKeyframe(id: string, review: StudioKeyframeAcceptanceInput, concurrency?: { baseVersion?: number; strict?: boolean; clientRequestId?: string })

Prop

Type

await client.studio.acceptKeyframe(productionId, {
  keyframeId: frame.id,
  expectedRevision: frame.revision,
  resultKey,
  expectedAcceptedResultKey: frame.acceptedResultKey,
  requirementChecks, // one { requirementId, outcome } per requirement of the frame
})

競合が起きると、通常のエラーがスローされます。SDK が、自分の判断でほかの結果を選んだり、新しいリビジョンに対して再試行したりすることはありません。

studio.reconcile(id)

完了したジョブを、候補を採用せず、生成も開始せずに記録します。ゴミ箱にあるシーンのジョブも確認します。完了したクリップは、そのシーンの保存されたグラフに残っており、restore_trashed で復元できます。

reconcile(id: string): Promise<{ data: StudioProductionReply & { landed: string[]; pending: string[]; failed: string[]; version: number } }>

Prop

Type

const { data } = await client.studio.reconcile(productionId)
console.log(data.landed, data.pending)

studio.setShared(id, input)

プロダクションを、レビューしたリビジョンに結び付けて、共有するか共有を解除します。operations.revisionedSharing を確認し、expectedVersion を渡してください。同時に編集があった場合は 409 workflow_conflict で失敗し、SDK が再試行することはありません。公開範囲を変更できる呼び出し元だけが使えます。

setShared(id: string, input: { shared: boolean; allowEditableCopy?: boolean; expectedVersion?: number }): Promise<{ data: StudioProductionReply }>

Prop

Type

await client.studio.setShared(productionId, { shared: true, allowEditableCopy: true, expectedVersion: version })

allowEditableCopy を使うと、オーナーまたはワークスペースの管理者は、リンクの閲覧者が、保存済みのプラン、プロンプト、キャストの説明、保持されているリファレンスの入力、テイクの履歴をコピーできるようにできます。ゴミ箱と非公開のレビューメモは、決して含まれません。コピーは非公開の状態で始まり、フレームは 1 つも採用されていません。コピーの許可をオフにするか共有を解除すると、新しいコピーはできなくなります。すでに作られたコピーは、独立したまま残ります。

studio.clone(id, input?)

保存済みのプロダクションをコピーします。リンクされたフレームを持つプロダクションをコピーする前に operations.cloneLinkedProductions を確認し、読み込んだ expectedVersion を渡してください。ソースが変わっていた場合は、409 で失敗します。

clone(id: string, input?: { name?: string; projectId?: string; expectedVersion?: number }): Promise<{ data: StudioProductionReply }>

Prop

Type

const { data: { production: copy } } = await client.studio.clone(productionId, {
  name: "Rome chase copy",
  expectedVersion: version,
})

コピーは非公開の状態で始まります。フレームの入力は保持され、自分のストレージの使用量に数えられます。フレーム、シーン、シーケンスの ID は新しくなり、実行中のジョブや採用済みのフレームは引き継がれません。それらのフレームに依存するメディアを生成する前に、フレームをレビューして採用してください。コピー自体は、生成を送信しません。

studio.importBundle(input)

移植可能なプロダクションを、新しい非公開のプロダクションとして、新しいシーン、フレーム、シーケンスの ID でインポートします(POST .../import-bundle)。メディアを含まないレシピやプランには operations.importPlannedBundles を、保持されたフレームのメディアを含むバンドルには importLinkedBundles を確認してください。

importBundle(input: { bundle: Record<string, unknown>; projectId?: string }): Promise<{ data: StudioProductionReply }>

Prop

Type

const { data: { production } } = await client.studio.importBundle({ bundle })

リンクされたバンドルは、そのソースのプロダクションを名指しします。サーバーは、何かをコピーする前に、それを所有しているかを確認し、保持されているすべての画像を検証します。アクセス権がない場合や、来歴が偽装されている場合は、新しいプロダクションが作られる前に、インポートが拒否されます。どちらの種類のインポートも、採用状態や実行中のジョブを引き継がず、メディアを生成することもありません。

studio.appendBundle(id, input)

完全なバンドルを、編集可能なプロダクションに、新しい ID と正確なリビジョンチェックとともに追加します(POST .../:id/import-bundle)。OAuth トークンには workflows:write が必要で、プロダクションへの編集権限も必要です。先に appendPlannedBundles または appendLinkedBundles を確認してください。

appendBundle(id: string, input: { bundle: Record<string, unknown>; expectedVersion: number; afterShotId?: string; applyFilm?: boolean }): Promise<{
  data: { production: StudioProductionRecord; importedShotIds: string[]; importedKeyframeIds: string[] }
}>

Prop

Type

const { data } = await client.studio.appendBundle(productionId, { bundle, expectedVersion: version })
console.log(data.importedShotIds)

既存のシーン、フレーム、ジョブ、共有、その他の設定はそのまま残ります。インポートされたキャストのロールは統合されます。インポートされたフレームは、もう一度採用する必要があります。不明な afterShotId や、古い expectedVersion を指定すると失敗します。

client.shots

共有とリミックスのための、/s/:id の共有リンクの背後にあるショットのレコードです。ショットは、ビルダーの状態を保存します。ピッカーの選択、プロンプト、対象のモデル、@ メンションのリファレンス、結果の URL です。これらは、推測できない 12 文字の ID で保存され、この ID は共有キーでもあります。ショットは、デフォルトでは非公開です。共有は、自分で行う公開範囲の変更です。

create(input?: CreateShotInput): Promise<{ id: string }>
get(id: string): Promise<{ shot: Shot }>
update(id: string, input: UpdateShotInput): Promise<{ shot: Shot }>
delete(id: string): Promise<void>

Prop

Type

const { id } = await client.shots.create({ mode: "single", freeText: "A lighthouse in a storm", models: ["nano-banana-2"] })
await client.shots.update(id, { visibility: "public" }) // anyone with the id can now read it
const { shot } = await client.shots.get(id)

公開されたショットは、その ID を持つ誰でも読み取れます。非公開のショットは、オーナーだけが読み取れ、それ以外の人には NotFoundError が返されます。ショットを更新または削除できるのは、オーナーだけです。

よくある質問

最終更新

目次