選択結果の出力形式を整理。明示的な空候補に対応し、ノードのタイトル表示を改善。
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
- **区切りは `|` または実際の改行**
|
||||
- `|` と改行の両方を区切りとして扱うので、混在していても動くぞ。
|
||||
- 区切り文字が連続して出現した場合は、候補から取り除かれることに注意じゃ。
|
||||
- 明示的に空白文字列を候補として返却させたい場合は、明示的に `()` と指定するのじゃ。
|
||||
|
||||
- **候補の前後の `,` と空白を自動で整理**
|
||||
- `town,`
|
||||
@@ -23,10 +25,6 @@
|
||||
- `castle, fortress,`
|
||||
のような書き方でも大丈夫じゃ。
|
||||
|
||||
- **プロンプト結合向けの返り値**
|
||||
- 選ばれた候補の前後に `,` を付けて返すぞ。
|
||||
- 例: `coffee shop` → `,coffee shop,`
|
||||
|
||||
- **現在の選択結果をタイトル表示**
|
||||
- 実行時にノードタイトルが `Choice: coffee shop` のように更新されるぞ。
|
||||
- KSamplerのプレビューと見比べやすいのじゃ。
|
||||
@@ -34,6 +32,12 @@
|
||||
- **複数設置に対応**
|
||||
- 背景用、時間帯用、天気用など、複数ノードを置いてそれぞれ別々に使えるぞ。
|
||||
|
||||
- **ファイル名向けの返り値**
|
||||
- ファイル名向けに安全化した文字列 `selected_text_safe` を出力するのじゃ。
|
||||
|
||||
- **明示的な空候補 `()` に対応**
|
||||
- `()` が選ばれた場合、プロンプト向け出力は空文字に、ファイル名向け出力は `empty` になるのじゃ。
|
||||
|
||||
## 導入方法
|
||||
|
||||
ComfyUIの `custom_nodes` ディレクトリで、以下のコマンドを打ち込むのじゃ!
|
||||
@@ -47,7 +51,7 @@ git clone https://github.com/ruminar/ComfyUI-PromptRandomChoice.git
|
||||
1. `Prompt Random Choice` ノードを置く
|
||||
2. `options_text` に候補を入れる (入力例を参照)
|
||||
3. 必要に応じて `change_every` を選ぶ (NEW)
|
||||
4. `prompt_text` を文字列結合ノードなどでポジティブプロンプトへ足す
|
||||
4. `selected_text` を `Join String Multi` などの文字列結合ノードへ繋ぎ、ポジティブプロンプトへ足す
|
||||
5. キューを好きなだけ積む
|
||||
|
||||
<br/>
|
||||
@@ -95,6 +99,15 @@ flower field|
|
||||
starry sky|
|
||||
coffee shop|
|
||||
```
|
||||
### 何も追加しない候補
|
||||
|
||||
`()` は明示的な空候補として扱われます。
|
||||
|
||||
```text
|
||||
()|(full body:0.9)
|
||||
```
|
||||
|
||||
この例では、何も追加しない場合と、`(full body:0.9)` を追加する場合をランダムに切り替えられます。
|
||||
|
||||
### 選ばれやすさを調整したい場合
|
||||
|
||||
@@ -112,13 +125,20 @@ day|day|day|sunset|night
|
||||
- `\n` という文字列は区切りとして扱わない
|
||||
- 各候補の前後の空白と `,` を trim
|
||||
- 空候補は無視
|
||||
- 有効な候補が1件も無い場合は空文字 `""` を返す
|
||||
- 候補があれば `,selected,` を返す
|
||||
- `()` は明示的な空候補として扱う
|
||||
- `change_every` が 1 なら毎回選び直す
|
||||
- `change_every` が 2 以上なら、その回数ぶん同じ候補を維持する
|
||||
- 実行時にタイトルへ `Choice: lake` や `Choice: (empty) (2/3)` のように表示する
|
||||
|
||||
## 出力
|
||||
|
||||
- `prompt_text`
|
||||
- 例: `,coffee shop,` (結合しやすいように、前後をtrimしてから`,`を付与します)
|
||||
- `selected_text`
|
||||
trim後の選択文字列です。
|
||||
`()` が選ばれた場合は空文字 `""` になります。
|
||||
|
||||
- `selected_text_safe`
|
||||
ファイル名向けに安全化した出力です。
|
||||
`selected_text` が空なら `empty` を返します。
|
||||
|
||||
<br/>
|
||||
|
||||
@@ -154,8 +174,3 @@ GPL-3.0(ComfyUI本体の掟に従っておるぞ!)
|
||||
|
||||
## 宣伝画像
|
||||
|
||||
<img width="1024" height="1536" alt="PromptRandomChoice説明画像v0 2 0" src="https://github.com/user-attachments/assets/84bd447c-5b17-409b-aa3e-cfe4bf369bed" />
|
||||
※ 区切り文字は 改行 または `|` です。カンマは候補の前後に付いた場合だけ自動で取り除きます。 <br/><br/>
|
||||
|
||||
(最初の版)
|
||||
<img width="1024" height="1536" alt="PromptRandomChoice説明画像" src="https://github.com/user-attachments/assets/e5308bd1-82cb-4f9b-bd89-0dbddb7a009e" />
|
||||
|
||||
+10
-3
@@ -1,6 +1,10 @@
|
||||
# v0.2.0
|
||||
## v0.3.0
|
||||
|
||||
change_everyを追加したのじゃ!
|
||||
- 出力を整理
|
||||
- `selected_text` : プロンプト向け出力
|
||||
- `selected_text_safe` : ファイル名向け出力
|
||||
- 明示的な空候補 `()` に対応
|
||||
- `()` が選ばれた場合、プロンプト向け出力は空文字になり、ファイル名向け出力は `empty` になります
|
||||
|
||||
`ComfyUI-PromptRandomChoice` は、プロンプト候補リストから実行のたびにランダムで1項目を選び、ポジティブプロンプトなどへ追加しやすい形で出力する ComfyUI カスタムノードです。
|
||||
|
||||
@@ -9,7 +13,8 @@ change_everyを追加したのじゃ!
|
||||
- プロンプト候補から実行ごとにランダムで1項目を選択
|
||||
- 候補は `|` または実際の改行で区切り
|
||||
- 候補の前後にある空白や `,` を自動で trim
|
||||
- 選ばれた候補を `,coffee shop,` のように前後カンマ付きで出力
|
||||
- 選ばれた候補を `selected_text` として通常の文字列で出力
|
||||
- ファイル名向けに安全化した `selected_text_safe` を出力
|
||||
- `change_every` に対応
|
||||
- `1` なら毎回選び直し
|
||||
- `3` なら同じ候補を3回返してから次を選択
|
||||
@@ -20,6 +25,8 @@ change_everyを追加したのじゃ!
|
||||
- 背景用、時間帯用、天気用などを別々にランダム化可能
|
||||
- 同じ候補を複数回書くことで、選ばれやすさを調整可能
|
||||
- 例: `day|day|day|sunset|night`
|
||||
- 明示的な空候補 `()` に対応
|
||||
- `()` が選ばれた場合、プロンプト向け出力は空文字になり、ファイル名向け出力は `empty` になります
|
||||
|
||||
## 注意
|
||||
|
||||
|
||||
@@ -26,12 +26,38 @@ def _split_options(options_text: str):
|
||||
options = []
|
||||
for part in parts:
|
||||
item = str(part).strip(" \t\r\n,")
|
||||
if item:
|
||||
options.append(item)
|
||||
|
||||
# Empty parts caused by repeated delimiters are ignored.
|
||||
if not item:
|
||||
continue
|
||||
|
||||
# Explicit empty choice.
|
||||
# Example: ()|(full body:0.9)
|
||||
if item == "()":
|
||||
options.append("")
|
||||
continue
|
||||
|
||||
options.append(item)
|
||||
|
||||
return options
|
||||
|
||||
|
||||
def _safe_text(value: str):
|
||||
text = str(value or "")
|
||||
|
||||
if not text:
|
||||
return "empty"
|
||||
|
||||
text = text.replace("\\", "/").replace("/", "_")
|
||||
text = re.sub(r'[<>:"|?*\x00-\x1f]', "_", text)
|
||||
text = re.sub(r"[\s,]+", "_", text)
|
||||
text = text.replace("(", "_").replace(")", "_")
|
||||
text = re.sub(r"_+", "_", text)
|
||||
text = text.strip().strip("._-")
|
||||
|
||||
return text or "empty"
|
||||
|
||||
|
||||
class PromptRandomChoice:
|
||||
def __init__(self):
|
||||
self._current_choice = None
|
||||
@@ -62,8 +88,8 @@ class PromptRandomChoice:
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("prompt_text",)
|
||||
RETURN_TYPES = ("STRING", "STRING")
|
||||
RETURN_NAMES = ("selected_text", "selected_text_safe")
|
||||
FUNCTION = "pick"
|
||||
CATEGORY = "utils/prompt"
|
||||
|
||||
@@ -90,11 +116,11 @@ class PromptRandomChoice:
|
||||
self._reset_state()
|
||||
return {
|
||||
"ui": {
|
||||
"selected_text": [""],
|
||||
"selected_text_title": ["(empty)"],
|
||||
"repeat_index": [0],
|
||||
"change_every": [change_every],
|
||||
},
|
||||
"result": ("",),
|
||||
"result": ("", "empty"),
|
||||
}
|
||||
|
||||
state_changed = (
|
||||
@@ -113,16 +139,17 @@ class PromptRandomChoice:
|
||||
self._last_options_key = options_key
|
||||
self._last_change_every = change_every
|
||||
|
||||
selected = self._current_choice
|
||||
prompt_text = f",{selected},"
|
||||
selected_text = str(self._current_choice or "")
|
||||
selected_text_safe = _safe_text(selected_text)
|
||||
selected_text_title = selected_text if selected_text else "(empty)"
|
||||
|
||||
return {
|
||||
"ui": {
|
||||
"selected_text": [selected],
|
||||
"selected_text_title": [selected_text_title],
|
||||
"repeat_index": [self._repeat_index],
|
||||
"change_every": [change_every],
|
||||
},
|
||||
"result": (prompt_text,),
|
||||
"result": (selected_text, selected_text_safe),
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,16 +24,14 @@ app.registerExtension({
|
||||
nodeType.prototype.onExecuted = function (message) {
|
||||
originalOnExecuted?.apply(this, arguments);
|
||||
|
||||
const selected = message?.selected_text?.[0] ?? "";
|
||||
const selectedTitle = message?.selected_text_title?.[0] ?? "(empty)";
|
||||
const repeatIndex = Number(message?.repeat_index?.[0] ?? 0);
|
||||
const changeEvery = Number(message?.change_every?.[0] ?? 1);
|
||||
|
||||
if (!selected) {
|
||||
this.title = "Prompt Random Choice";
|
||||
} else if (changeEvery <= 1) {
|
||||
this.title = `Choice: ${shorten(selected)}`;
|
||||
if (changeEvery <= 1) {
|
||||
this.title = `Choice: ${shorten(selectedTitle)}`;
|
||||
} else {
|
||||
this.title = `Choice: ${shorten(selected)} (${repeatIndex}/${changeEvery})`;
|
||||
this.title = `Choice: ${shorten(selectedTitle)} (${repeatIndex}/${changeEvery})`;
|
||||
}
|
||||
|
||||
this.setDirtyCanvas?.(true, true);
|
||||
|
||||
Reference in New Issue
Block a user