|
|
@@ -51,6 +51,44 @@ KEEP_NAME = {
|
|
|
# sense to type into a form.
|
|
|
SKIP = {'title'}
|
|
|
|
|
|
+# Fields the endpoints accept that /options/generation does not describe yet.
|
|
|
+# They are in the OpenAPI request schemas, so they are real - the per-field
|
|
|
+# reference simply has not caught up. Declared here in the same shape the
|
|
|
+# reference uses, so that when it does catch up these can be deleted and
|
|
|
+# nothing else changes.
|
|
|
+UNDOCUMENTED = {
|
|
|
+ 'ip_adapter_image_base64': {
|
|
|
+ 'applies_to': ['txt2img', 'img2img', 'txt2vid'],
|
|
|
+ 'label': 'IP-Adapter Image (base64)', 'type': 'string', 'default': '',
|
|
|
+ 'description': 'A reference image whose style and subject guide the result, as base64. '
|
|
|
+ 'Needs an IP-Adapter loaded alongside the model - see the Load Model node.',
|
|
|
+ 'recommended': 'Take it from a Download or Fetch Output node rather than pasting one in.',
|
|
|
+ 'category': 'image_input',
|
|
|
+ },
|
|
|
+ 'ip_adapter_strength': {
|
|
|
+ 'applies_to': ['txt2img', 'img2img', 'txt2vid'],
|
|
|
+ 'label': 'IP-Adapter Strength', 'type': 'number', 'default': 1.0,
|
|
|
+ 'description': 'How strongly the reference image guides the result.',
|
|
|
+ 'recommended': '1.0 is the upstream default. Lower it when the reference is overwhelming the prompt.',
|
|
|
+ 'category': 'image_input',
|
|
|
+ },
|
|
|
+ 'ref_audios': {
|
|
|
+ 'applies_to': ['txt2vid'],
|
|
|
+ 'label': 'Reference Audios', 'type': 'array<string>', 'default': [],
|
|
|
+ 'description': 'Reference audio as base64-encoded WAV, mono or stereo PCM (i16/i24/i32/f32).',
|
|
|
+ 'recommended': 'For models that take audio guidance.',
|
|
|
+ 'category': 'video',
|
|
|
+ },
|
|
|
+ 'ref_videos': {
|
|
|
+ 'applies_to': ['txt2vid'],
|
|
|
+ 'label': 'Reference Videos', 'type': 'array<object>', 'default': [],
|
|
|
+ 'description': 'Reference videos. Each entry is an object with frames (base64 images), '
|
|
|
+ 'fps (default 24) and an optional audio_wav_base64.',
|
|
|
+ 'recommended': 'Built by an earlier node rather than typed.',
|
|
|
+ 'category': 'video',
|
|
|
+ },
|
|
|
+}
|
|
|
+
|
|
|
# Fields a node takes that the reference files under a different endpoint. The
|
|
|
# server documents ref_images and ref_image_args as txt2img fields, but the
|
|
|
# image-edit node posts them to /img2img and the server accepts them - so they
|
|
|
@@ -123,6 +161,9 @@ def prop_for(name: str, opt: dict) -> dict:
|
|
|
elif kind == 'array<number>':
|
|
|
prop['type'] = 'array'
|
|
|
prop['items'] = {'type': 'number'}
|
|
|
+ elif kind == 'array<object>':
|
|
|
+ prop['type'] = 'array'
|
|
|
+ prop['items'] = {'type': 'object'}
|
|
|
else:
|
|
|
prop['type'] = 'string'
|
|
|
if name in ('prompt', 'negative_prompt'):
|
|
|
@@ -140,9 +181,12 @@ def render_properties(props: dict, indent: str = ' ') -> str:
|
|
|
|
|
|
|
|
|
def build(reference: dict, endpoint: str, extra: list) -> tuple:
|
|
|
- options = reference['options']
|
|
|
+ options = dict(reference['options'])
|
|
|
categories = reference['categories']
|
|
|
|
|
|
+ for name, described in UNDOCUMENTED.items():
|
|
|
+ options[name] = {k: v for k, v in described.items() if k != 'category'}
|
|
|
+
|
|
|
applicable = [
|
|
|
(name, opt) for name, opt in options.items()
|
|
|
if (endpoint in opt.get('applies_to', []) or name in extra) and name not in SKIP
|
|
|
@@ -156,9 +200,17 @@ def build(reference: dict, endpoint: str, extra: list) -> tuple:
|
|
|
props[setting] = prop_for(name, opt)
|
|
|
table.append((setting, name))
|
|
|
|
|
|
+ # The undocumented fields belong in a group too, next to the ones they are
|
|
|
+ # related to rather than dumped in "Other".
|
|
|
+ extra_by_category: dict = {}
|
|
|
+ for name, described in UNDOCUMENTED.items():
|
|
|
+ if name in by_name:
|
|
|
+ extra_by_category.setdefault(described['category'], []).append(name)
|
|
|
+
|
|
|
groups = []
|
|
|
- for _, cat in categories.items():
|
|
|
- fields = [camel(n) for n in cat['options'] if n in by_name]
|
|
|
+ for cat_key, cat in categories.items():
|
|
|
+ fields = [camel(n) for n in list(cat['options']) + extra_by_category.get(cat_key, [])
|
|
|
+ if n in by_name]
|
|
|
if fields:
|
|
|
groups.append({'title': cat['label'], 'fields': fields})
|
|
|
# Core first, then the rest as the server lists them.
|