dikdimon commited on
Commit
d7cdd26
·
verified ·
1 Parent(s): d6f45e7

Update negative_rejection_steering/scripts/negative_rejection_steering_script.py

Browse files
negative_rejection_steering/scripts/negative_rejection_steering_script.py CHANGED
@@ -66,15 +66,73 @@ def calc_nrs(x_orig, cond, uncond, sigma, skew, stretch, squash):
66
  return (x_div - (x_orig - x_final)) * (sig_root / sig_tens)
67
 
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  # ==============================================================================
70
  # ЧАСТЬ 2: Перехват управления (Hooking)
71
  # ==============================================================================
72
 
73
- # Хук 1: Сохраняем Sigma и Input Latent
74
  def hook_cfg_denoiser_params(params):
75
  if hasattr(params.denoiser, 'p') and getattr(params.denoiser.p, '_nrs_enabled', False):
76
  params.denoiser.p._nrs_current_sigma = params.sigma
77
  params.denoiser.p._nrs_current_x_in = params.x
 
 
 
 
 
 
 
 
 
78
 
79
  script_callbacks.on_cfg_denoiser(hook_cfg_denoiser_params)
80
 
@@ -82,7 +140,7 @@ script_callbacks.on_cfg_denoiser(hook_cfg_denoiser_params)
82
  if not hasattr(sd_samplers_cfg_denoiser.CFGDenoiser, 'original_combine_denoised_nrs_backup'):
83
  sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup = sd_samplers_cfg_denoiser.CFGDenoiser.combine_denoised
84
 
85
- # Хук 2: Подменная функция
86
  def hijacked_combine_denoised(self, x_out, conds_list, uncond, cond_scale):
87
  # Проверка активности NRS
88
  if not getattr(self, 'p', None) or not getattr(self.p, '_nrs_enabled', False):
@@ -92,8 +150,77 @@ def hijacked_combine_denoised(self, x_out, conds_list, uncond, cond_scale):
92
  return sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup(self, x_out, conds_list, uncond, cond_scale)
93
 
94
  try:
95
- skew, stretch, squash = self.p._nrs_params
 
 
 
 
 
 
 
 
 
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  denoised_uncond = x_out[-uncond.shape[0]:]
98
  denoised = torch.clone(denoised_uncond)
99
 
@@ -132,11 +259,11 @@ def hijacked_combine_denoised(self, x_out, conds_list, uncond, cond_scale):
132
 
133
 
134
  # ==============================================================================
135
- # ЧАСТЬ 3: Интерфейс (UI) с пояснениями
136
  # ==============================================================================
137
  class NRSScript(scripts.Script):
138
  def title(self):
139
- return "Negative Rejection Steering"
140
 
141
  def show(self, is_img2img):
142
  return scripts.AlwaysVisible
@@ -164,10 +291,15 @@ class NRSScript(scripts.Script):
164
  1. **Skew** ≈ Половина вашего обычного CFG (например, **3.0** - **4.0**).
165
  2. **Stretch** ≈ Ваш обычный CFG (например, **6.0** - **7.0**).
166
  3. **Squash** ≈ Оставьте **0.0** для начала.
 
 
 
 
 
167
  """)
168
 
169
- # --- ЭЛЕМЕНТЫ УПРАВЛЕНИЯ ---
170
- gr.HTML("<div style='margin-bottom: 0.5em; opacity: 0.8; font-size: 0.9em; border-bottom: 1px solid #444;'>Настройки</div>")
171
 
172
  with gr.Row():
173
  skew = gr.Slider(
@@ -187,14 +319,249 @@ class NRSScript(scripts.Script):
187
  info="0.0 = Макс. эффект. 1.0 = Ослабление (больше деталей, меньше контраста)."
188
  )
189
 
190
- return [enabled, skew, stretch, squash]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
 
192
- def process(self, p, enabled, skew, stretch, squash):
 
 
 
 
 
 
193
  p._nrs_enabled = enabled
194
  p._nrs_params = (skew, stretch, squash)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
 
196
  if enabled:
197
  sd_samplers_cfg_denoiser.CFGDenoiser.combine_denoised = hijacked_combine_denoised
 
 
 
198
 
199
  def postprocess(self, p, processed, *args):
200
  pass
 
66
  return (x_div - (x_orig - x_final)) * (sig_root / sig_tens)
67
 
68
 
69
+ # ==============================================================================
70
+ # ЧАСТЬ 1.5: Утилиты для управления шагами
71
+ # ==============================================================================
72
+ def should_apply_at_step(current_step, total_steps, start_step, end_step, start_frac, end_frac, step_mode):
73
+ """
74
+ Определяет, нужно ли применять эффект на текущем шаге
75
+
76
+ Args:
77
+ current_step: Текущий шаг сэмплера
78
+ total_steps: Общее количество шагов
79
+ start_step: Начальный абсолютный шаг
80
+ end_step: Конечный абсолютный шаг
81
+ start_frac: Начальная доля (0.0-1.0)
82
+ end_frac: Конечная доля (0.0-1.0)
83
+ step_mode: Режим ("Absolute Steps" или "Fraction of Steps")
84
+
85
+ Returns:
86
+ bool: True если эффект должен применяться
87
+ """
88
+ if step_mode == "Absolute Steps":
89
+ # Абсолютные шаги
90
+ effective_start = max(0, start_step)
91
+ effective_end = min(total_steps, end_step) if end_step > 0 else total_steps
92
+ return effective_start <= current_step < effective_end
93
+ else:
94
+ # Доли от общего количества шагов
95
+ effective_start = int(total_steps * max(0.0, min(1.0, start_frac)))
96
+ effective_end = int(total_steps * max(0.0, min(1.0, end_frac)))
97
+ if effective_end == 0:
98
+ effective_end = total_steps
99
+ return effective_start <= current_step < effective_end
100
+
101
+
102
+ def get_param_value_at_step(base_value, current_step, total_steps, start_step, end_step,
103
+ start_frac, end_frac, step_mode, enabled):
104
+ """
105
+ Возвращает значение параметра для текущего шага
106
+ Если шаг вне диапазона - возвращает 0.0
107
+ """
108
+ if not enabled:
109
+ return base_value
110
+
111
+ if should_apply_at_step(current_step, total_steps, start_step, end_step,
112
+ start_frac, end_frac, step_mode):
113
+ return base_value
114
+ else:
115
+ return 0.0
116
+
117
+
118
  # ==============================================================================
119
  # ЧАСТЬ 2: Перехват управления (Hooking)
120
  # ==============================================================================
121
 
122
+ # Хук 1: Сохраняем Sigma, Input Latent и текущий шаг
123
  def hook_cfg_denoiser_params(params):
124
  if hasattr(params.denoiser, 'p') and getattr(params.denoiser.p, '_nrs_enabled', False):
125
  params.denoiser.p._nrs_current_sigma = params.sigma
126
  params.denoiser.p._nrs_current_x_in = params.x
127
+
128
+ # Определяем текущий шаг
129
+ if hasattr(params, 'sampling_step'):
130
+ params.denoiser.p._nrs_current_step = params.sampling_step
131
+ elif hasattr(params.denoiser, 'step'):
132
+ params.denoiser.p._nrs_current_step = params.denoiser.step
133
+ else:
134
+ # Fallback: пытаемся определить по sigma
135
+ params.denoiser.p._nrs_current_step = getattr(params.denoiser.p, '_nrs_current_step', 0)
136
 
137
  script_callbacks.on_cfg_denoiser(hook_cfg_denoiser_params)
138
 
 
140
  if not hasattr(sd_samplers_cfg_denoiser.CFGDenoiser, 'original_combine_denoised_nrs_backup'):
141
  sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup = sd_samplers_cfg_denoiser.CFGDenoiser.combine_denoised
142
 
143
+ # Хук 2: Подменная функция с поддержкой step control
144
  def hijacked_combine_denoised(self, x_out, conds_list, uncond, cond_scale):
145
  # Проверка активности NRS
146
  if not getattr(self, 'p', None) or not getattr(self.p, '_nrs_enabled', False):
 
150
  return sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup(self, x_out, conds_list, uncond, cond_scale)
151
 
152
  try:
153
+ # Получаем базовые параметры
154
+ base_skew, base_stretch, base_squash = self.p._nrs_params
155
+
156
+ # Получаем настройки step control
157
+ step_control_enabled = getattr(self.p, '_nrs_step_control_enabled', False)
158
+ step_control_mode = getattr(self.p, '_nrs_step_control_mode', 'Global')
159
+
160
+ # Определяем текущий и общий шаги
161
+ current_step = getattr(self.p, '_nrs_current_step', 0)
162
+ total_steps = getattr(self.p, 'steps', 20)
163
 
164
+ # Если step control включен, вычисляем эффективные значения параметров
165
+ if step_control_enabled:
166
+ if step_control_mode == 'Global':
167
+ # Глобальный режим - одни настройки для всех
168
+ global_settings = getattr(self.p, '_nrs_global_step_settings', {})
169
+ start_step = global_settings.get('start_step', 0)
170
+ end_step = global_settings.get('end_step', total_steps)
171
+ start_frac = global_settings.get('start_frac', 0.0)
172
+ end_frac = global_settings.get('end_frac', 1.0)
173
+ step_mode = global_settings.get('step_mode', 'Absolute Steps')
174
+
175
+ # Проверяем, нужно ли применять эффекты
176
+ if not should_apply_at_step(current_step, total_steps, start_step, end_step,
177
+ start_frac, end_frac, step_mode):
178
+ # Вне диапазона - используем fallback
179
+ return sd_samplers_cfg_denoiser.CFGDenoiser.original_combine_denoised_nrs_backup(
180
+ self, x_out, conds_list, uncond, cond_scale)
181
+
182
+ skew, stretch, squash = base_skew, base_stretch, base_squash
183
+ else:
184
+ # Индивидуальный режим - отдельные настройки для каждого параметра
185
+ individual_settings = getattr(self.p, '_nrs_individual_step_settings', {})
186
+
187
+ skew_settings = individual_settings.get('skew', {})
188
+ skew = get_param_value_at_step(
189
+ base_skew, current_step, total_steps,
190
+ skew_settings.get('start_step', 0),
191
+ skew_settings.get('end_step', total_steps),
192
+ skew_settings.get('start_frac', 0.0),
193
+ skew_settings.get('end_frac', 1.0),
194
+ skew_settings.get('step_mode', 'Absolute Steps'),
195
+ skew_settings.get('enabled', True)
196
+ )
197
+
198
+ stretch_settings = individual_settings.get('stretch', {})
199
+ stretch = get_param_value_at_step(
200
+ base_stretch, current_step, total_steps,
201
+ stretch_settings.get('start_step', 0),
202
+ stretch_settings.get('end_step', total_steps),
203
+ stretch_settings.get('start_frac', 0.0),
204
+ stretch_settings.get('end_frac', 1.0),
205
+ stretch_settings.get('step_mode', 'Absolute Steps'),
206
+ stretch_settings.get('enabled', True)
207
+ )
208
+
209
+ squash_settings = individual_settings.get('squash', {})
210
+ squash = get_param_value_at_step(
211
+ base_squash, current_step, total_steps,
212
+ squash_settings.get('start_step', 0),
213
+ squash_settings.get('end_step', total_steps),
214
+ squash_settings.get('start_frac', 0.0),
215
+ squash_settings.get('end_frac', 1.0),
216
+ squash_settings.get('step_mode', 'Absolute Steps'),
217
+ squash_settings.get('enabled', True)
218
+ )
219
+ else:
220
+ # Step control выключен - используем базовые значения
221
+ skew, stretch, squash = base_skew, base_stretch, base_squash
222
+
223
+ # Основная логика NRS
224
  denoised_uncond = x_out[-uncond.shape[0]:]
225
  denoised = torch.clone(denoised_uncond)
226
 
 
259
 
260
 
261
  # ==============================================================================
262
+ # ЧАСТЬ 3: Интерфейс (UI) с расширенными настройками
263
  # ==============================================================================
264
  class NRSScript(scripts.Script):
265
  def title(self):
266
+ return "Negative Rejection Steering (Enhanced)"
267
 
268
  def show(self, is_img2img):
269
  return scripts.AlwaysVisible
 
291
  1. **Skew** ≈ Половина вашего обычного CFG (например, **3.0** - **4.0**).
292
  2. **Stretch** ≈ Ваш обычный CFG (например, **6.0** - **7.0**).
293
  3. **Squash** ≈ Оставьте **0.0** для начала.
294
+
295
+ ### ⏱️ Step Control (Управление шагами):
296
+ Позволяет применять NRS только на определенных шагах генерации.
297
+ - **Global Mode**: Одинаковые настройки для всех трех параметров
298
+ - **Individual Mode**: Отдельные настройки для каждого параметра (Skew, Stretch, Squash)
299
  """)
300
 
301
+ # --- ОСНОВНЫЕ ПАРАМЕТРЫ ---
302
+ gr.HTML("<div style='margin-bottom: 0.5em; opacity: 0.8; font-size: 0.9em; border-bottom: 1px solid #444;'>Основные настройки</div>")
303
 
304
  with gr.Row():
305
  skew = gr.Slider(
 
319
  info="0.0 = Макс. эффект. 1.0 = Ослабление (больше деталей, меньше контраста)."
320
  )
321
 
322
+ # --- STEP CONTROL ---
323
+ with gr.Accordion("⏱️ Step Control (Управление шагами)", open=False):
324
+ with gr.Row():
325
+ step_control_enabled = gr.Checkbox(
326
+ label="Включить Step Control",
327
+ value=False,
328
+ info="Применять NRS только на определенных шагах"
329
+ )
330
+ step_control_mode = gr.Radio(
331
+ label="Режим управления",
332
+ choices=["Global", "Individual"],
333
+ value="Global",
334
+ info="Global: общие настройки | Individual: настройки для каждого параметра"
335
+ )
336
+
337
+ # ГЛОБАЛЬНЫЕ НАСТРОЙКИ
338
+ with gr.Group(visible=True) as global_group:
339
+ gr.HTML("<div style='margin: 0.5em 0; font-weight: bold;'>Глобальные настройки (для всех параметров)</div>")
340
+
341
+ global_step_mode = gr.Radio(
342
+ label="Режим шагов",
343
+ choices=["Absolute Steps", "Fraction of Steps"],
344
+ value="Absolute Steps",
345
+ info="Absolute: номера шагов | Fraction: доли от общего числа"
346
+ )
347
+
348
+ with gr.Row():
349
+ global_start_step = gr.Slider(
350
+ label="Start Step (абсолютный)",
351
+ minimum=0, maximum=150, step=1, value=0,
352
+ visible=True
353
+ )
354
+ global_end_step = gr.Slider(
355
+ label="End Step (абсолютный, 0=конец)",
356
+ minimum=0, maximum=150, step=1, value=0,
357
+ visible=True
358
+ )
359
+
360
+ with gr.Row():
361
+ global_start_frac = gr.Slider(
362
+ label="Start (доля от общего числа)",
363
+ minimum=0.0, maximum=1.0, step=0.01, value=0.0,
364
+ visible=False
365
+ )
366
+ global_end_frac = gr.Slider(
367
+ label="End (доля от общего числа)",
368
+ minimum=0.0, maximum=1.0, step=0.01, value=1.0,
369
+ visible=False
370
+ )
371
+
372
+ # ИНДИВИДУАЛЬНЫЕ НАСТРОЙКИ
373
+ with gr.Group(visible=False) as individual_group:
374
+ gr.HTML("<div style='margin: 0.5em 0; font-weight: bold;'>Индивидуальные настройки</div>")
375
+
376
+ # SKEW
377
+ with gr.Accordion("Skew (Композиция) - Step Settings", open=False):
378
+ skew_step_enabled = gr.Checkbox(label="Включить управление шагами для Skew", value=True)
379
+ skew_step_mode = gr.Radio(
380
+ label="Режим",
381
+ choices=["Absolute Steps", "Fraction of Steps"],
382
+ value="Absolute Steps"
383
+ )
384
+ with gr.Row():
385
+ skew_start_step = gr.Slider(label="Start Step", minimum=0, maximum=150, step=1, value=0, visible=True)
386
+ skew_end_step = gr.Slider(label="End Step (0=конец)", minimum=0, maximum=150, step=1, value=0, visible=True)
387
+ with gr.Row():
388
+ skew_start_frac = gr.Slider(label="Start (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=0.0, visible=False)
389
+ skew_end_frac = gr.Slider(label="End (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=1.0, visible=False)
390
+
391
+ # STRETCH
392
+ with gr.Accordion("Stretch (Цвета/Текстура) - Step Settings", open=False):
393
+ stretch_step_enabled = gr.Checkbox(label="Включить управление шагами для Stretch", value=True)
394
+ stretch_step_mode = gr.Radio(
395
+ label="Режим",
396
+ choices=["Absolute Steps", "Fraction of Steps"],
397
+ value="Absolute Steps"
398
+ )
399
+ with gr.Row():
400
+ stretch_start_step = gr.Slider(label="Start Step", minimum=0, maximum=150, step=1, value=0, visible=True)
401
+ stretch_end_step = gr.Slider(label="End Step (0=конец)", minimum=0, maximum=150, step=1, value=0, visible=True)
402
+ with gr.Row():
403
+ stretch_start_frac = gr.Slider(label="Start (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=0.0, visible=False)
404
+ stretch_end_frac = gr.Slider(label="End (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=1.0, visible=False)
405
+
406
+ # SQUASH
407
+ with gr.Accordion("Squash (Защита от пережарки) - Step Settings", open=False):
408
+ squash_step_enabled = gr.Checkbox(label="Включить управление шагами для Squash", value=True)
409
+ squash_step_mode = gr.Radio(
410
+ label="Режим",
411
+ choices=["Absolute Steps", "Fraction of Steps"],
412
+ value="Absolute Steps"
413
+ )
414
+ with gr.Row():
415
+ squash_start_step = gr.Slider(label="Start Step", minimum=0, maximum=150, step=1, value=0, visible=True)
416
+ squash_end_step = gr.Slider(label="End Step (0=конец)", minimum=0, maximum=150, step=1, value=0, visible=True)
417
+ with gr.Row():
418
+ squash_start_frac = gr.Slider(label="Start (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=0.0, visible=False)
419
+ squash_end_frac = gr.Slider(label="End (fraction)", minimum=0.0, maximum=1.0, step=0.01, value=1.0, visible=False)
420
+
421
+ # Переключение видимости групп при изменении режима
422
+ def update_mode_visibility(mode):
423
+ return {
424
+ global_group: gr.update(visible=(mode == "Global")),
425
+ individual_group: gr.update(visible=(mode == "Individual"))
426
+ }
427
+
428
+ step_control_mode.change(
429
+ fn=update_mode_visibility,
430
+ inputs=[step_control_mode],
431
+ outputs=[global_group, individual_group]
432
+ )
433
+
434
+ # Переключение между абсолютными и дробными шагами (GLOBAL)
435
+ def update_global_step_inputs(mode):
436
+ is_absolute = (mode == "Absolute Steps")
437
+ return {
438
+ global_start_step: gr.update(visible=is_absolute),
439
+ global_end_step: gr.update(visible=is_absolute),
440
+ global_start_frac: gr.update(visible=not is_absolute),
441
+ global_end_frac: gr.update(visible=not is_absolute)
442
+ }
443
+
444
+ global_step_mode.change(
445
+ fn=update_global_step_inputs,
446
+ inputs=[global_step_mode],
447
+ outputs=[global_start_step, global_end_step, global_start_frac, global_end_frac]
448
+ )
449
+
450
+ # Переключение для SKEW
451
+ def update_skew_step_inputs(mode):
452
+ is_absolute = (mode == "Absolute Steps")
453
+ return {
454
+ skew_start_step: gr.update(visible=is_absolute),
455
+ skew_end_step: gr.update(visible=is_absolute),
456
+ skew_start_frac: gr.update(visible=not is_absolute),
457
+ skew_end_frac: gr.update(visible=not is_absolute)
458
+ }
459
+
460
+ skew_step_mode.change(
461
+ fn=update_skew_step_inputs,
462
+ inputs=[skew_step_mode],
463
+ outputs=[skew_start_step, skew_end_step, skew_start_frac, skew_end_frac]
464
+ )
465
+
466
+ # Переключение для STRETCH
467
+ def update_stretch_step_inputs(mode):
468
+ is_absolute = (mode == "Absolute Steps")
469
+ return {
470
+ stretch_start_step: gr.update(visible=is_absolute),
471
+ stretch_end_step: gr.update(visible=is_absolute),
472
+ stretch_start_frac: gr.update(visible=not is_absolute),
473
+ stretch_end_frac: gr.update(visible=not is_absolute)
474
+ }
475
+
476
+ stretch_step_mode.change(
477
+ fn=update_stretch_step_inputs,
478
+ inputs=[stretch_step_mode],
479
+ outputs=[stretch_start_step, stretch_end_step, stretch_start_frac, stretch_end_frac]
480
+ )
481
+
482
+ # Переключение для SQUASH
483
+ def update_squash_step_inputs(mode):
484
+ is_absolute = (mode == "Absolute Steps")
485
+ return {
486
+ squash_start_step: gr.update(visible=is_absolute),
487
+ squash_end_step: gr.update(visible=is_absolute),
488
+ squash_start_frac: gr.update(visible=not is_absolute),
489
+ squash_end_frac: gr.update(visible=not is_absolute)
490
+ }
491
+
492
+ squash_step_mode.change(
493
+ fn=update_squash_step_inputs,
494
+ inputs=[squash_step_mode],
495
+ outputs=[squash_start_step, squash_end_step, squash_start_frac, squash_end_frac]
496
+ )
497
+
498
+ return [
499
+ enabled, skew, stretch, squash,
500
+ step_control_enabled, step_control_mode,
501
+ # Global
502
+ global_step_mode, global_start_step, global_end_step, global_start_frac, global_end_frac,
503
+ # Skew
504
+ skew_step_enabled, skew_step_mode, skew_start_step, skew_end_step, skew_start_frac, skew_end_frac,
505
+ # Stretch
506
+ stretch_step_enabled, stretch_step_mode, stretch_start_step, stretch_end_step, stretch_start_frac, stretch_end_frac,
507
+ # Squash
508
+ squash_step_enabled, squash_step_mode, squash_start_step, squash_end_step, squash_start_frac, squash_end_frac
509
+ ]
510
 
511
+ def process(self, p, enabled, skew, stretch, squash,
512
+ step_control_enabled, step_control_mode,
513
+ global_step_mode, global_start_step, global_end_step, global_start_frac, global_end_frac,
514
+ skew_step_enabled, skew_step_mode, skew_start_step, skew_end_step, skew_start_frac, skew_end_frac,
515
+ stretch_step_enabled, stretch_step_mode, stretch_start_step, stretch_end_step, stretch_start_frac, stretch_end_frac,
516
+ squash_step_enabled, squash_step_mode, squash_start_step, squash_end_step, squash_start_frac, squash_end_frac):
517
+
518
  p._nrs_enabled = enabled
519
  p._nrs_params = (skew, stretch, squash)
520
+ p._nrs_step_control_enabled = step_control_enabled
521
+ p._nrs_step_control_mode = step_control_mode
522
+
523
+ # Сохраняем глобальные настройки
524
+ p._nrs_global_step_settings = {
525
+ 'step_mode': global_step_mode,
526
+ 'start_step': global_start_step,
527
+ 'end_step': global_end_step,
528
+ 'start_frac': global_start_frac,
529
+ 'end_frac': global_end_frac
530
+ }
531
+
532
+ # Сохраняем индивидуальные настройки
533
+ p._nrs_individual_step_settings = {
534
+ 'skew': {
535
+ 'enabled': skew_step_enabled,
536
+ 'step_mode': skew_step_mode,
537
+ 'start_step': skew_start_step,
538
+ 'end_step': skew_end_step,
539
+ 'start_frac': skew_start_frac,
540
+ 'end_frac': skew_end_frac
541
+ },
542
+ 'stretch': {
543
+ 'enabled': stretch_step_enabled,
544
+ 'step_mode': stretch_step_mode,
545
+ 'start_step': stretch_start_step,
546
+ 'end_step': stretch_end_step,
547
+ 'start_frac': stretch_start_frac,
548
+ 'end_frac': stretch_end_frac
549
+ },
550
+ 'squash': {
551
+ 'enabled': squash_step_enabled,
552
+ 'step_mode': squash_step_mode,
553
+ 'start_step': squash_start_step,
554
+ 'end_step': squash_end_step,
555
+ 'start_frac': squash_start_frac,
556
+ 'end_frac': squash_end_frac
557
+ }
558
+ }
559
 
560
  if enabled:
561
  sd_samplers_cfg_denoiser.CFGDenoiser.combine_denoised = hijacked_combine_denoised
562
+
563
+ # Инициализируем счетчик шагов
564
+ p._nrs_current_step = 0
565
 
566
  def postprocess(self, p, processed, *args):
567
  pass