# ピッカー、プリセット、プロンプト

> TypeScript から、各ピッカーの有効な選択肢を読み取り、シーンの説明からピッカーを埋め、ノードプリセットを読み込み、プロンプトウィザードでプロンプトを改善します。

Source: https://nodaro.ai/ja/docs/developers/sdk/pickers-and-prompts

**ピッカー**は、[**ムード**（Mood）](https://nodaro.ai/docs/nodes/creative-controls/mood)や**レンズ**（Lens）といった、クリエイティブコントロールのノードです。選んだ内容が、検証済みの言い回しをプロンプトに加えます。**`client.pickerCatalogs`** と **`client.catalogs`** は、各ピッカーの有効な選択肢を返し、`analyzeText()` は、シーンの説明からピッカーを埋めます。**`client.presets`** は保存されたノードの設定を読み取り、**`client.promptHelper`** はプロンプトウィザードで、どの生成ノードのプロンプトも改善します。概念については、[クリエイティブコントロール](https://nodaro.ai/docs/guides/creative-controls)と[ピッカーカタログ](https://nodaro.ai/docs/developers/picker-catalogs)を参照してください。

## メソッド
| メソッド | 内容 |
| --- | --- |
| [`pickerCatalogs.list()`](#pickercatalogslist) | すべてのピッカーとそのカタログを一覧表示します |
| [`pickerCatalogs.get(nodeType, opts?)`](#pickercatalogsgetnodetype-opts) | 1 つのピッカーの選択肢を読み取ります |
| [`pickerCatalogs.analyzeText(params)`](#pickercatalogsanalyzetextparams) | テキストの説明から、ピッカーの選択を埋めます |
| [`catalogs.list(opts?)`](#catalogslistopts) | このデプロイメントの、すべてのカタログを 1 回の呼び出しで読み取ります |
| [`presets.list(nodeType?)`](#presetslistnodetype) | 自分の保存したプリセットを一覧表示します |
| [`presets.listGroups(nodeType?)`](#presetslistgroupsnodetype) | 自分のプリセットフォルダーとセクションを一覧表示します |
| [`presets.listFactory(nodeType)`](#presetslistfactorynodetype) | 1 つのノードタイプの標準プリセットを一覧表示します |
| [`promptHelper.analyze(input)`](#prompthelperanalyzeinput) | ざっくりしたアイデアを質問に変えます |
| [`promptHelper.generate(input)`](#prompthelpergenerateinput) | 答えからプロンプトを作成します |
| [`promptHelper.enhance(input)`](#prompthelperenhanceinput) | プロンプトを 1 段階で改善します |

## client.pickerCatalogs
ピッカーのノードの選択肢の一覧です。どちらの読み取りメソッドも公開されていて、トークンは不要で、サーバーが 5 分間キャッシュできます。コードが `@nodaro/shared` をインポートできる場合、同じカタログが型付きデータとしてそこにも含まれています。これらのメソッドは、それを同梱できないクライアント向けです。

### pickerCatalogs.list()
すべてのピッカーを一覧表示します（`GET /v1/picker-catalogs`）。

```ts
list(): Promise<{ data: PickerCatalogSummary[] }>
```

```ts
const { data: pickers } = await client.pickerCatalogs.list()
const mood = pickers.find((p) => p.nodeType === "mood")
```

各エントリーには、`nodeType`、`label`、`catalogId`、`kind`（`single` または `multi`）、単一次元のピッカーでは `valueField`、複数次元のピッカーでは `fields`、`optionCount`、そして画像がある選択肢の数である `imageCount` があります。

### pickerCatalogs.get(nodeType, opts?)
1 つのピッカーの選択肢を読み取ります（`GET /v1/picker-catalogs/:nodeType`）。ムードのような単一次元のピッカーには `options` があります。人物のような複数次元のピッカーには `dimensions` があり、それぞれ `{ field, label, options }` です。いくつかの単一次元のピッカーには、メインの選択のほかに追加の設定もあります。`transition` と `character-fx` には `position`、`duration`、`intensity` があり、`character-motion` には `position` と `pace` があります。

```ts
get(nodeType: string, opts?: { detail?: "compact" | "full"; category?: string; field?: string }): Promise<{ data: PickerCatalog }>
```

<TypeTable
type={{
nodeType: { type: 'string', required: true, description: "ピッカーのノードタイプで、たとえば mood、lens、person です。" },
detail: { type: '"compact" | "full"', default: '"compact"', description: "compact は id、label、category、term、icon、imageUrl を返します。full は、各選択肢の description と promptHint を追加します。" },
category: { type: 'string', description: "単一次元のピッカーで、このカテゴリーの選択肢だけに絞り込みます。" },
field: { type: 'string', description: "複数次元のピッカーの 1 つの次元、または単一次元のピッカーの追加の設定を 1 つだけ返します。" },
}}
/>

```ts
const { data } = await client.pickerCatalogs.get("mood", { detail: "full" })
const serene = data.options?.find((o) => o.id === "serene")
console.log(serene?.term)       // the short phrase, added in Compact mode
console.log(serene?.promptHint) // the full sentence, added in Full mode
```

不明なノードタイプには `NotFoundError` をスローします。

**`label` を表示し、`term` を追加します。**どちらの詳細レベルでも、すべての選択肢に `term` があります。プロンプトに入れる、短い専門用語です。`label` は表示専用です。一方からもう一方を導き出さないでください。`auto` や `none` のように何も追加しない選択肢は、`term` が空です。

**画像。**画像がある選択肢には、どちらの詳細レベルでも、絶対 URL の `imageUrl` があります。`person` と `styling` は `sections` も返します。エディターが設定をグループ分けするトピックで、それぞれ `{ label, fields, imageUrl? }` です。写真と、音楽やボイスのアートは、インストール環境自身が配信します。レンダリング済みのルックのプレビューは Nodaro CDN から配信され、返すのは Nodaro Cloud だけです。ファイル名にはコンテンツのハッシュが含まれるため、画像は期限なくキャッシュできます。

```ts
const { data: person } = await client.pickerCatalogs.get("person")
for (const section of person.sections ?? []) {
const settings = person.dimensions?.filter((d) => section.fields.includes(d.field)) ?? []
for (const setting of settings) {
for (const option of setting.options) renderTile(option.label, option.imageUrl)
}
}
```

**キャラクターモーション**（Character Motion）。`character-motion` の選択肢は、どちらの詳細レベルでも、任意の `motion` オブジェクトを持つことがあります。これは、その動きが必要とするものと残すものを示します。`requires`、開始と終了のポーズである `startPose` と `endPose`、`endVisibility`、`handsAfter`、`needsFreeHands`、`kind`、`fixedPace`、`counterpart`、検索用の `aliases`、そして `replacementId` を伴う `deprecated` です。フィールドがない場合は、不明を意味します。保存されたワークフローを読み込むときは、廃止された ID も動作するようにし、新しい選択肢には表示しないでください。[キャラクターモーション](https://nodaro.ai/docs/nodes/creative-controls/character-motion)を参照してください。

### pickerCatalogs.analyzeText(params)
自由記述のシーンの説明から、ピッカーの選択を埋めます（`POST /v1/text-to-picker`）。[**説明をピッカーへ**（Describe to Picker）](https://nodaro.ai/docs/nodes/image/describe-to-picker)のテキスト版です。ピッカーのタイプ、次元、選ばれた 1 つまたは複数の id の順にキーが付いた `pickerJson` を返します。ピッカーには、これをそのまま読み込んでから、ユーザーに調整させてください。クレジットがかかり、説明をピッカーへと同じ課金です。

```ts
analyzeText(params: TextToPickerParams): Promise<{
jobId: string
pickerJson: Record<string, Record<string, string | string[]>>
gaps?: { missingItems: object[]; missingCategories: object[] }
}>
```

<TypeTable
type={{
text: { type: 'string', required: true, description: "シーンまたはショットの説明です。" },
targetPickers: { type: 'string[]', description: "埋めるピッカーのタイプです。省略すると、分析できるすべてのピッカーが対象になります。" },
instructions: { type: 'string', description: "分析への追加の指示です。" },
llmModel: { type: 'string', description: "モデルの id です。" },
reasoningEffort: { type: 'string', description: "推論の強度で、モデルによって異なります。" },
origin: { type: 'string', description: "自分のアプリの名前で、ジョブに保存されます。" },
}}
/>

```ts
const { pickerJson, gaps } = await client.pickerCatalogs.analyzeText({
text: "Neon-soaked Tokyo alley at night, rain, handheld tracking shot, moody synthwave",
})
console.log(pickerJson["setting"], pickerJson["camera-motion"])
```

テキストが何も述べていない次元は省かれます。分析が推測することはありません。`gaps` は、テキストが説明している内容のうち、どのカタログの選択肢もうまく表せなかったものを、`missingItems` と `missingCategories` に一覧にします。ユーザーには「X は一致させられませんでした。自分で選んでください」のように表示します。

## client.catalogs
### catalogs.list(opts?)
すべてのピッカーカタログを、このデプロイメントが提供するとおりに、1 回の呼び出しで返します（`GET /v1/catalogs`）。デプロイメントは、選択肢を置き換え、拡張、非表示にするカタログパックを登録できます。自分でピッカーを描画するクライアントは、それらを反映させるため、この一覧を読み取ってください。これは公開されていて、5 分間キャッシュできます。

```ts
list(opts?: { detail?: "compact" | "full" }): Promise<{
curated: boolean
packs: number
version: number
data?: ProjectedCatalog[]
}>
```

<TypeTable
type={{
detail: { type: '"compact" | "full"', default: '"compact"', description: "compact は id、label、category、term、icon を返します。full は description と promptHint を追加します。" },
}}
/>

```ts
const { curated, data } = await client.catalogs.list({ detail: "full" })
if (curated) {
const setting = data?.find((c) => c.catalogId === "setting")
console.log(setting?.options?.[0]?.term)
}
```

`data` が含まれるのは、デプロイメントがカタログパックを登録している場合だけです（`curated: true`）。パックがない場合、カタログは標準のものです。`pickerCatalogs.get()` で 1 つずつ読み取ってください。選択肢は同じ `imageUrl` を持ち、`person` と `styling` は同じ `sections` を持ちます。

## client.presets
自分の保存したノードプリセットと、標準のノードプリセットを、読み取り専用で扱います。プリセットの `data` は、ノードの保存された設定です。プリセットを適用するには、ワークフローを構築するときに、その `data` をノードの data にマージします。OAuth トークンには `presets:read` スコープが必要です。[プリセット](https://nodaro.ai/docs/concepts/presets)を参照してください。

### presets.list(nodeType?)
自分の保存したプリセットを、新しい順に一覧表示します（`GET /v1/node-presets`）。

```ts
list(nodeType?: string): Promise<NodePreset[]>
```

<TypeTable
type={{
nodeType: { type: 'string', description: "このノードタイプのプリセットだけで、たとえば generate-image です。" },
}}
/>

```ts
const presets = await client.presets.list("generate-image")
const cinematic = presets.find((p) => p.name === "Cinematic Portrait")
// apply: spread cinematic.data into the node's data when you create the workflow
```

`NodePreset` には、`id`、`nodeType`、`name`、`description`、`data`、`groupId`、`tags`、`sortOrder`、`createdAt`、`updatedAt` があります。

### presets.listGroups(nodeType?)
自分のプリセットフォルダーとセクションを一覧表示します（`GET /v1/node-preset-groups`）。

```ts
listGroups(nodeType?: string): Promise<NodePresetGroup[]>
```

<TypeTable
type={{
nodeType: { type: 'string', description: "このノードタイプのグループだけです。" },
}}
/>

```ts
const groups = await client.presets.listGroups("generate-image")
```

各グループには、`id`、`nodeType`、`name`、`kind`（`folder` または `section`）、`sortOrder`、`createdAt`、`updatedAt` があります。

### presets.listFactory(nodeType)
1 つのノードタイプの標準プリセットを一覧表示します（`GET /v1/node-presets/factory`）。

```ts
listFactory(nodeType: string): Promise<{ data: FactoryPreset[] }>
```

<TypeTable
type={{
nodeType: { type: 'string', required: true, description: "ノードタイプで、たとえば generate-video です。" },
}}
/>

```ts
const { data } = await client.presets.listFactory("generate-video")
const orbit = data.find((p) => p.id === "generate-video/orbit-360")
```

## client.promptHelper
プロンプトウィザードです。生成ノード用のプロンプトを書く、AI による支援です。3 つのメソッドはすべて、そのリクエストを `POST /v1/prompt-helper/wizard` に送信し、呼び出しごとにクレジットがかかります。REST 版については、[プロンプトウィザード](https://nodaro.ai/docs/developers/api/prompt-wizard)を参照してください。

3 つのメソッドはすべて、次の共通フィールドを受け取ります。

<TypeTable
type={{
nodeType: { type: 'string', required: true, description: "プロンプトの対象となるノードで、たとえば generate-image や generate-video です。" },
provider: { type: 'string', description: "プロンプトの対象となるモデルです。" },
style: { type: 'string', description: "目指すスタイルです。" },
aspectRatio: { type: 'string', description: "目標とするフレームのアスペクト比です。" },
duration: { type: 'number', description: "動画の場合、目標とするクリップの長さです。" },
llmModel: { type: 'string', description: "プロンプトを書く言語モデルです。" },
reasoningEffort: { type: 'string', description: "none、low、medium、high、xhigh、max のいずれかで、モデルによって異なります。xhigh と max は、1 段階上のティアで課金されます。" },
advancedMode: { type: 'boolean', description: "Gemini モデル専用です。モデルの開発元自身の API を使います。1 段階上のティアで課金されます。" },
temperature: { type: 'number', description: "サンプリングの温度です。" },
maxTokens: { type: 'number', description: "トークン単位での、回答の最大の長さです。" },
nodeContext: { type: 'WizardNodeContext', description: "そのノードに何がつながっているかで、ウィザードが考慮できるようにします。" },
userPreference: { type: 'string', description: "従うべき好みです。" },
workflowId: { type: 'string', description: "この実行を紐付けるワークフローです。" },
}}
/>

CLI でも、`nodaro prompt wizard`、`analyze`、`generate`、`enhance` から、`--llm-model` と `--reasoning-effort` を使って同じことができます。[CLI](https://nodaro.ai/docs/developers/cli) を参照してください。

### promptHelper.analyze(input)
ざっくりしたアイデアを、そのノードタイプ向けのガイド付きの質問に変えます。回答してから、その答えを `generate()` に渡してください。

```ts
analyze(input: AnalyzeInput): Promise<{ jobId: string; questions: WizardQuestion[] }>
```

<TypeTable
type={{
prompt: { type: 'string', description: "ざっくりしたアイデアです。" },
'...': { type: 'common fields', description: "nodeType と、上記の共通フィールドです。" },
}}
/>

```ts
const { questions } = await client.promptHelper.analyze({
nodeType: "generate-image",
prompt: "a snow leopard",
})
```

### promptHelper.generate(input)
選んだ答えから、最適化された 1 つのプロンプトを作ります。各選択は `{ category, value, isCustom }` です。

```ts
generate(input: GenerateInput): Promise<{ jobId: string; prompt: string; recommendedModel?: RecommendedModel }>
```

<TypeTable
type={{
selections: { type: 'WizardSelection[]', required: true, description: "選んだ答えで、それぞれ { category, value, isCustom } です。" },
originalPrompt: { type: 'string', description: "質問のもとになった、ざっくりしたアイデアです。" },
'...': { type: 'common fields', description: "nodeType と、上記の共通フィールドです。" },
}}
/>

```ts
const { prompt, recommendedModel } = await client.promptHelper.generate({
nodeType: "generate-image",
selections: [{ category: "subject", value: "snow leopard", isCustom: false }],
})
```

### promptHelper.enhance(input)
質問を飛ばして、プロンプトを 1 段階で改善します。

```ts
enhance(input: EnhanceInput): Promise<{ jobId: string; prompt: string; recommendedModel?: RecommendedModel }>
```

<TypeTable
type={{
prompt: { type: 'string', description: "改善するプロンプトです。" },
'...': { type: 'common fields', description: "nodeType と、上記の共通フィールドです。" },
}}
/>

```ts
const { prompt } = await client.promptHelper.enhance({
nodeType: "generate-image",
prompt: "snow leopard on a rock",
reasoningEffort: "high",
})
```

## Frequently asked questions

### direction オブジェクトの有効な ID を見つけるには、どうすればよいですか？

すべてのピッカーについては client.pickerCatalogs.list() を、1 つのピッカーの選択肢については client.pickerCatalogs.get(nodeType) を呼び出します。各選択肢の id が、direction やピッカーのノードが受け付ける値です。

### label、term、promptHint は、どう違いますか？

label は表示名です。term は、プロンプトヒントがコンパクトのときにピッカーが追加する、短い専門用語です。promptHint は、プロンプトヒントがフルのときに追加される、より長い文で、detail が full の場合にだけ返されます。

### SDK でプロンプトを改善するには、どうすればよいですか？

対象の nodeType と自分のプロンプトを指定して、client.promptHelper.enhance を呼び出します。改善されたプロンプトが返され、推奨モデルが含まれることもあります。呼び出しごとにクレジットがかかります。

### SDK で、ノードプリセットを作成したり変更したりできますか？

いいえ。client.presets は、自分の保存したプリセット、そのグループ、標準プリセットを読み取ります。プリセットを適用するには、ワークフローを構築するときに、その data をノードの設定にマージします。
