リリースノートを追加し、PromptRandomChoiceノードにchange_everyオプションを実装
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# v0.2.0
|
||||
|
||||
change_everyを追加したのじゃ!
|
||||
|
||||
`ComfyUI-PromptRandomChoice` は、プロンプト候補リストから実行のたびにランダムで1項目を選び、ポジティブプロンプトなどへ追加しやすい形で出力する ComfyUI カスタムノードです。
|
||||
|
||||
## 主な機能
|
||||
|
||||
- プロンプト候補から実行ごとにランダムで1項目を選択
|
||||
- 候補は `|` または実際の改行で区切り
|
||||
- 候補の前後にある空白や `,` を自動で trim
|
||||
- 選ばれた候補を `,coffee shop,` のように前後カンマ付きで出力
|
||||
- `change_every` に対応
|
||||
- `1` なら毎回選び直し
|
||||
- `3` なら同じ候補を3回返してから次を選択
|
||||
- 実行中の選択結果をノードタイトルに表示
|
||||
- 例: `Choice: coffee shop`
|
||||
- 例: `Choice: lake (2/3)`
|
||||
- 複数ノード設置に対応
|
||||
- 背景用、時間帯用、天気用などを別々にランダム化可能
|
||||
- 同じ候補を複数回書くことで、選ばれやすさを調整可能
|
||||
- 例: `day|day|day|sunset|night`
|
||||
|
||||
## 注意
|
||||
|
||||
区切り文字は **実際の改行** または **`|`** です。
|
||||
|
||||
`,` は区切り文字ではありません。
|
||||
ただし、各候補の前後に付いている `,` は自動で取り除きます。
|
||||
|
||||
詳しい使い方は README.md を参照してください。
|
||||
|
||||
## ライセンス
|
||||
|
||||
GPL-3.0
|
||||
@@ -1,4 +1,3 @@
|
||||
import random
|
||||
import re
|
||||
import secrets
|
||||
import time
|
||||
@@ -22,9 +21,6 @@ coffee shop,"""
|
||||
|
||||
def _split_options(options_text: str):
|
||||
text = str(options_text or "")
|
||||
|
||||
# Split by "|" or actual newlines only.
|
||||
# Do not treat literal "\\n" text as a delimiter.
|
||||
parts = re.split(r"\||\r?\n", text)
|
||||
|
||||
options = []
|
||||
@@ -37,6 +33,12 @@ def _split_options(options_text: str):
|
||||
|
||||
|
||||
class PromptRandomChoice:
|
||||
def __init__(self):
|
||||
self._current_choice = None
|
||||
self._repeat_index = 0
|
||||
self._last_options_key = None
|
||||
self._last_change_every = None
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
@@ -48,6 +50,15 @@ class PromptRandomChoice:
|
||||
"default": DEFAULT_OPTIONS_TEXT,
|
||||
},
|
||||
),
|
||||
"change_every": (
|
||||
"INT",
|
||||
{
|
||||
"default": 1,
|
||||
"min": 1,
|
||||
"max": 999999,
|
||||
"step": 1,
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -58,30 +69,58 @@ class PromptRandomChoice:
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, **kwargs):
|
||||
# Force execution for every queued run so the random choice changes.
|
||||
return time.time_ns()
|
||||
|
||||
def pick(self, options_text):
|
||||
def _reset_state(self):
|
||||
self._current_choice = None
|
||||
self._repeat_index = 0
|
||||
self._last_options_key = None
|
||||
self._last_change_every = None
|
||||
|
||||
def _select_new_choice(self, options):
|
||||
self._current_choice = secrets.choice(options)
|
||||
self._repeat_index = 1
|
||||
|
||||
def pick(self, options_text, change_every):
|
||||
options = _split_options(options_text)
|
||||
change_every = max(1, int(change_every))
|
||||
options_key = tuple(options)
|
||||
|
||||
if not options:
|
||||
self._reset_state()
|
||||
return {
|
||||
"ui": {
|
||||
"selected_text": [""],
|
||||
"repeat_index": [0],
|
||||
"change_every": [change_every],
|
||||
},
|
||||
"result": ("",),
|
||||
}
|
||||
|
||||
# Do not use random.choice here.
|
||||
# Some ComfyUI workflows/extensions may reset Python's global random state
|
||||
# from the generation seed, which can make random.choice repeat the same
|
||||
# index every queued run. secrets.choice uses OS entropy instead.
|
||||
selected = secrets.choice(options)
|
||||
state_changed = (
|
||||
self._last_options_key != options_key
|
||||
or self._last_change_every != change_every
|
||||
or self._current_choice not in options
|
||||
)
|
||||
|
||||
if state_changed or self._current_choice is None:
|
||||
self._select_new_choice(options)
|
||||
elif self._repeat_index < change_every:
|
||||
self._repeat_index += 1
|
||||
else:
|
||||
self._select_new_choice(options)
|
||||
|
||||
self._last_options_key = options_key
|
||||
self._last_change_every = change_every
|
||||
|
||||
selected = self._current_choice
|
||||
prompt_text = f",{selected},"
|
||||
|
||||
return {
|
||||
"ui": {
|
||||
"selected_text": [selected],
|
||||
"repeat_index": [self._repeat_index],
|
||||
"change_every": [change_every],
|
||||
},
|
||||
"result": (prompt_text,),
|
||||
}
|
||||
|
||||
@@ -25,10 +25,15 @@ app.registerExtension({
|
||||
originalOnExecuted?.apply(this, arguments);
|
||||
|
||||
const selected = message?.selected_text?.[0] ?? "";
|
||||
if (selected) {
|
||||
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)}`;
|
||||
} else {
|
||||
this.title = "Prompt Random Choice";
|
||||
this.title = `Choice: ${shorten(selected)} (${repeatIndex}/${changeEvery})`;
|
||||
}
|
||||
|
||||
this.setDirtyCanvas?.(true, true);
|
||||
|
||||
Reference in New Issue
Block a user