Browse Source

fix: fill in the settings the server reports as default, and say which it does not report

Fill in was leaving settings behind. Two different reasons, treated as one.

Empty was being skipped. The server reports rng_type, lora_apply_mode, backend,
rpc_servers and model_args as empty strings, and empty is an ANSWER - it means
the server is using its own default. Skipping them left the form half agreeing
with the server, with no way to tell which half. They are now filled in, which
took the count from 16 settings to 22.

Absent is different, and is now said out loud. The server does not report
weight_type, prediction, sampler_rng_type or tensor_type_rules at all, and does
not report a component it has not loaded. Those are left alone and named:
"The server does not report clipG, clipL, controlnet, t5xxl, taesd, so they were
left as they are."

An empty option now says what it means. Weight Type reads "auto - use the
weights in the file", Prediction Type "auto - detect from the model", Sampler
RNG "same as RNG above". They read "Select..." before, which looks like a
setting nobody filled in rather than a deliberate choice - and the generic
select was adding that placeholder on top of the schema's own empty option,
taking its place and hiding the label. It now only adds one when the schema has
not given empty a meaning of its own.

force_sdxl_vae_conv_scale is a setting too - the server reports it and the node
did not have it.

Verified against the live server: 22 settings filled, the unreported ones named,
and every auto-meaning dropdown showing its own label. Full suite 58/58.
fszontagh 1 month ago
parent
commit
7b7a065b9d
2 changed files with 45 additions and 9 deletions
  1. 19 4
      nodes/sdcpp/sdcpp-model-load.js
  2. 26 5
      webui/src/components/workflow/NodeConfigModal.tsx

+ 19 - 4
nodes/sdcpp/sdcpp-model-load.js

@@ -33,7 +33,7 @@ const configSchema = {
                                      'streamLayers', 'maxVram', 'nThreads', 'weightType'] },
         { title: 'Advanced', fields: ['vaeFormat', 'prediction', 'rngType', 'samplerRngType',
                                       'loraApplyMode', 'vaeConvDirect', 'diffusionConvDirect',
-                                      'taePreviewOnly', 'backend', 'paramsBackend', 'rpcServers',
+                                      'taePreviewOnly', 'forceSdxlVaeConvScale', 'backend', 'paramsBackend', 'rpcServers',
                                       'modelArgs', 'tensorTypeRules', 'options', 'timeout'] }
     ],
     // Pressing this asks the server what it has loaded and writes it into the
@@ -68,6 +68,12 @@ const configSchema = {
             'loadOptions.vae_conv_direct': 'vaeConvDirect',
             'loadOptions.diffusion_conv_direct': 'diffusionConvDirect',
             'loadOptions.tae_preview_only': 'taePreviewOnly',
+            'loadOptions.force_sdxl_vae_conv_scale': 'forceSdxlVaeConvScale',
+            'loadOptions.rng_type': 'rngType',
+            'loadOptions.lora_apply_mode': 'loraApplyMode',
+            'loadOptions.backend': 'backend',
+            'loadOptions.rpc_servers': 'rpcServers',
+            'loadOptions.model_args': 'modelArgs',
             'loadOptions.backend': 'backend',
             'loadOptions.params_backend': 'paramsBackend',
             'loadOptions.rpc_servers': 'rpcServers',
@@ -205,32 +211,40 @@ const configSchema = {
         weightType: {
             type: 'string', title: 'Weight Type',
             enum: ['', 'f32', 'f16', 'bf16', 'q8_0', 'q5_0', 'q5_1', 'q4_0', 'q4_1', 'q4_k', 'q5_k', 'q6_k', 'q8_k', 'q3_k', 'q2_k', 'mxfp4', 'nvfp4', 'q1_0'],
-            default: '', description: 'Force a quantisation. Empty takes it from the file'
+            enumLabels: ['auto - use the weights in the file', 'f32', 'f16', 'bf16', 'q8_0', 'q5_0', 'q5_1', 'q4_0', 'q4_1', 'q4_k', 'q5_k', 'q6_k', 'q8_k', 'q3_k', 'q2_k', 'mxfp4', 'nvfp4', 'q1_0'],
+            default: '', description: 'Force a quantisation. Left on auto, sd.cpp uses whatever the model file holds'
         },
         vaeFormat: {
             type: 'string', title: 'VAE Format',
             enum: ['', 'auto', 'flux', 'sd3', 'flux2', 'wan'],
+            enumLabels: ['not set - leave it to the server', 'auto - detect from the file', 'flux', 'sd3', 'flux2', 'wan'],
             default: '', description: 'Override VAE format detection'
         },
         prediction: {
             type: 'string', title: 'Prediction Type',
             enum: ['', 'eps', 'v', 'edm_v', 'sd3_flow', 'flux_flow', 'flux2_flow', 'sefi_flow', 'minit2i_flow'],
-            default: '', description: 'Override the prediction type. Empty is detected'
+            enumLabels: ['auto - detect from the model', 'eps', 'v', 'edm_v', 'sd3_flow', 'flux_flow', 'flux2_flow', 'sefi_flow', 'minit2i_flow'],
+            default: '', description: 'Override the prediction type. Left on auto it is detected from the model'
         },
         rngType: {
             type: 'string', title: 'RNG', enum: ['', 'cuda', 'std_default', 'cpu'],
+            enumLabels: ['server default', 'cuda', 'std_default', 'cpu'],
             default: '', description: 'Affects whether a seed reproduces across backends'
         },
         samplerRngType: {
             type: 'string', title: 'Sampler RNG', enum: ['', 'cuda', 'std_default', 'cpu'],
-            default: '', description: 'Override the RNG for sampling only'
+            enumLabels: ['same as RNG above', 'cuda', 'std_default', 'cpu'],
+            default: '',
+            description: 'Override the RNG for sampling only. The server does not report this one, so Fill in leaves it alone'
         },
         loraApplyMode: {
             type: 'string', title: 'LoRA Apply Mode', enum: ['', 'auto', 'immediately', 'at_runtime'],
+            enumLabels: ['server default', 'auto', 'immediately', 'at_runtime'],
             default: '', description: 'When a LoRA named in a prompt is applied'
         },
         vaeConvDirect: { type: 'boolean', title: 'Direct VAE Convolution', description: 'Use the ggml_conv2d_direct path for the VAE' },
         diffusionConvDirect: { type: 'boolean', title: 'Direct Diffusion Convolution', description: 'Use the ggml_conv2d_direct path for the diffusion model' },
+        forceSdxlVaeConvScale: { type: 'boolean', title: 'Force SDXL VAE Conv Scale', description: 'SDXL-specific VAE convolution scaling' },
         taePreviewOnly: { type: 'boolean', title: 'TAESD For Preview Only', description: 'Load TAESD purely to render progress previews, skipping the full VAE' },
         backend: { type: 'string', title: 'Backend', description: 'Per-component placement, such as te=cpu,vae=cpu,controlnet=cpu' },
         paramsBackend: { type: 'string', title: 'Parameter Backend', description: 'Global parameter placement, such as *=cpu to hold weights in system RAM' },
@@ -388,6 +402,7 @@ const LOAD_OPTIONS = [
     { setting: 'vaeConvDirect', server: 'vae_conv_direct' },
     { setting: 'diffusionConvDirect', server: 'diffusion_conv_direct' },
     { setting: 'taePreviewOnly', server: 'tae_preview_only' },
+    { setting: 'forceSdxlVaeConvScale', server: 'force_sdxl_vae_conv_scale' },
     { setting: 'backend', server: 'backend' },
     { setting: 'paramsBackend', server: 'params_backend' },
     { setting: 'rpcServers', server: 'rpc_servers' },

+ 26 - 5
webui/src/components/workflow/NodeConfigModal.tsx

@@ -136,11 +136,18 @@ export function NodeConfigModal({
 
       const next: Record<string, any> = { ...editingConfig }
       const filled: string[] = []
+      const notReported: string[] = []
       for (const [from, to] of Object.entries((prefill.map || {}) as Record<string, string>)) {
         const value = readPath(output, from)
-        // A component the server does not have comes back empty or absent.
-        // Writing that would blank a value the person had already set.
-        if (value === undefined || value === null || value === '') continue
+        // Absent and empty are different answers. Absent means the service does
+        // not report this at all, so there is nothing to say and whatever is
+        // already in the box stays. Empty is an answer - it means the service is
+        // using its own default - and writing it is what makes the form agree
+        // with the service instead of only half agreeing.
+        if (value === undefined || value === null) {
+          notReported.push(to)
+          continue
+        }
         next[to] = value
         filled.push(to)
       }
@@ -155,7 +162,17 @@ export function NodeConfigModal({
       }
 
       onConfigChange(next)
-      setPrefilling({ busy: false, error: false, message: `Filled in ${filled.join(', ')}.` })
+      setPrefilling({
+        busy: false,
+        error: false,
+        message:
+          `Filled in ${filled.length} setting${filled.length === 1 ? '' : 's'}.` +
+          (notReported.length > 0
+            ? ` The server does not report ${notReported.join(', ')}, so ${
+                notReported.length === 1 ? 'it was' : 'they were'
+              } left as ${notReported.length === 1 ? 'it is' : 'they are'}.`
+            : ''),
+      })
     } catch (error: any) {
       const detail = error?.response?.data?.error || error?.message || 'Could not reach the server'
       setPrefilling({ busy: false, error: true, message: detail })
@@ -672,7 +689,11 @@ export function NodeConfigModal({
                         }
                         className="w-full px-3 py-2 border border-gray-200 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-900 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-primary-500 focus:border-primary-500"
                       >
-                        <option value="">Select...</option>
+                        {/* Only when the schema has not given "" a meaning of
+                            its own. Several settings use it for "auto" or
+                            "server default", and a placeholder above that would
+                            take its place and hide the label explaining it. */}
+                        {!prop.enum.includes('') && <option value="">Select...</option>}
                         {prop.enum.map((opt: string, idx: number) => (
                           <option key={opt} value={opt}>
                             {prop.enumLabels?.[idx] || opt}