dikdimon commited on
Commit
367aec1
·
verified ·
1 Parent(s): d2e1244

Upload 3 files

Browse files
sd_agga_schedulers.py ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import modules.sd_schedulers as sd_schedulers
2
+ import modules.shared as shared
3
+ from modules.sd_samplers_pseudo_hires import (
4
+ get_sigmas_agga_dmd,
5
+ get_sigmas_log_linear,
6
+ get_sigmas_dynamic_rho,
7
+ get_sigmas_pseudo_native,
8
+ get_sigmas_agga_smart,
9
+ get_sigmas_style_anchor,
10
+ get_sigmas_ultra_anchor,
11
+ get_sigmas_agga_ays_anchor,
12
+ get_sigmas_agga_double_anchor,
13
+ get_sigmas_agga_pixel_staircase,
14
+ get_sigmas_agga_pixel_staircase_v2,
15
+ get_sigmas_agga_lora_universal_bridge,
16
+ )
17
+
18
+ def register():
19
+
20
+ new_data = [
21
+ ('agga_dmd_p', 'AGGA DMD Power',
22
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_agga_dmd(n, sigma_min, sigma_max, device), 7.0),
23
+
24
+ ('agga_log', 'AGGA Log-Linear',
25
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_log_linear(n, sigma_min, sigma_max, device), -1),
26
+
27
+ ('agga_dyn_rho', 'AGGA Dynamic Rho',
28
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_dynamic_rho(n, sigma_min, sigma_max, device), -1),
29
+
30
+ ('agga_pseudo', 'AGGA Pseudo-Native',
31
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_pseudo_native(n, sigma_min, sigma_max, device), -1),
32
+
33
+ ('agga_smart', 'AGGA Smart-Automatic',
34
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_agga_smart(n, sigma_min, sigma_max, device), -1),
35
+
36
+ ('agga_ays_anchor', 'AGGA AYS-Anchor',
37
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_agga_ays_anchor(n, sigma_min, sigma_max, device), -1),
38
+
39
+ ('agga_style_anchor', 'AGGA Style-Anchor',
40
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_style_anchor(n, sigma_min, sigma_max, device), -1),
41
+
42
+ ('agga_style_Ultra', 'AGGA Style-Ultra',
43
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_ultra_anchor(n, sigma_min, sigma_max, device), -1),
44
+
45
+ ('agga_double_anchor', 'AGGA Double-Anchor',
46
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_agga_double_anchor(n, sigma_min, sigma_max, device), -1),
47
+
48
+ ('agga_LUB', 'AGGA UNIVERSAL BRIDGE',
49
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_agga_lora_universal_bridge(n, sigma_min, sigma_max, device), -1),
50
+
51
+ ('agga_pixel', 'AGGA Pixel Staircase',
52
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_agga_pixel_staircase(n, sigma_min, sigma_max, device), -1),
53
+
54
+ ('agga_pixel_v2', 'AGGA Pixel Staircase V2',
55
+ lambda n, sigma_min, sigma_max, device, **k: get_sigmas_agga_pixel_staircase_v2(n, sigma_min, sigma_max, device), -1),
56
+ ]
57
+
58
+ for name, label, func, rho in new_data:
59
+ if any(x.name == name for x in sd_schedulers.schedulers): continue
60
+
61
+ sched = sd_schedulers.Scheduler(name, label, func, default_rho=rho)
62
+ sd_schedulers.schedulers.append(sched)
63
+ sd_schedulers.schedulers_map.update({sched.name: sched, sched.label: sched})
64
+
65
+ print(f"[AGGA Module] {len(new_data)} Schedulers registered successfully.")
66
+
67
+ register()
sd_samplers_pseudo_hires.py ADDED
@@ -0,0 +1,1518 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from modules import shared
3
+ import torch.nn.functional as F
4
+ import inspect
5
+
6
+ # =====================================================
7
+ # SIGMAS BASE (COMPARTIDOS)
8
+ # =====================================================
9
+
10
+ def pseudo_hires_sigmas(n, sigma_min, sigma_max, device):
11
+ ramp = torch.linspace(0, 1, n, device=device)
12
+
13
+ sigmas = sigma_max * torch.exp(-ramp * 4.5)
14
+
15
+ p0 = int(n * 0.45)
16
+ p1 = int(n * 0.80)
17
+
18
+ sigmas[p0:p1] = sigmas[p0]
19
+ sigmas[p1:] = torch.linspace(sigmas[p1], sigma_min, n - p1, device=device)
20
+
21
+ sigmas[-2] = sigmas[-1]
22
+ return sigmas
23
+
24
+
25
+ # =====================================================
26
+ # PSEUDO-HIRES SOFT
27
+ # =====================================================
28
+
29
+ @torch.no_grad()
30
+ def sample_pseudo_hires_soft(
31
+ model,
32
+ x,
33
+ sigmas,
34
+ extra_args=None,
35
+ callback=None,
36
+ **kwargs
37
+ ):
38
+ extra_args = {} if extra_args is None else extra_args
39
+ s_in = x.new_ones([x.shape[0]])
40
+
41
+ total_steps = len(sigmas) - 1
42
+ shared.state.sampling_steps = total_steps
43
+
44
+ shared.state.job_count = 1
45
+ shared.state.job_no = 0
46
+
47
+ for i in range(total_steps):
48
+ shared.state.sampling_step = i + 1
49
+
50
+ sigma = sigmas[i]
51
+ sigma_next = sigmas[i + 1]
52
+ dt = sigma_next - sigma
53
+
54
+ denoised = model(x, sigma * s_in, **extra_args)
55
+ d = (x - denoised) / sigma
56
+
57
+ x = x + d * dt
58
+
59
+ if callback is not None:
60
+ callback({
61
+ "x": x,
62
+ "i": i,
63
+ "sigma": sigma,
64
+ "sampling_step": i + 1,
65
+ "sampling_steps": total_steps
66
+ })
67
+
68
+ return x
69
+
70
+
71
+ # =====================================================
72
+ # PSEUDO-HIRES SHARP
73
+ # =====================================================
74
+
75
+ @torch.no_grad()
76
+ def sample_pseudo_hires_sharp(
77
+ model,
78
+ x,
79
+ sigmas,
80
+ extra_args=None,
81
+ callback=None,
82
+ **kwargs
83
+ ):
84
+ extra_args = {} if extra_args is None else extra_args
85
+ s_in = x.new_ones([x.shape[0]])
86
+
87
+ total_steps = len(sigmas) - 1
88
+ shared.state.sampling_steps = total_steps
89
+
90
+ shared.state.job_count = 1
91
+ shared.state.job_no = 0
92
+
93
+ for i in range(total_steps):
94
+ shared.state.sampling_step = i + 1
95
+
96
+ sigma = sigmas[i]
97
+ sigma_next = sigmas[i + 1]
98
+ dt = sigma_next - sigma
99
+
100
+ denoised = model(x, sigma * s_in, **extra_args)
101
+ d = (x - denoised) / sigma
102
+
103
+ if i > total_steps * 0.65:
104
+ x = x + d * dt * 1.12
105
+ else:
106
+ x = x + d * dt
107
+
108
+ if callback is not None:
109
+ callback({
110
+ "x": x,
111
+ "i": i,
112
+ "sigma": sigma,
113
+ "sampling_step": i + 1,
114
+ "sampling_steps": total_steps
115
+ })
116
+
117
+ return x
118
+
119
+
120
+ # =====================================================
121
+ # PSEUDO-HIRES ULTRA
122
+ # =====================================================
123
+
124
+ @torch.no_grad()
125
+ def sample_pseudo_hires_ultra(
126
+ model,
127
+ x,
128
+ sigmas,
129
+ extra_args=None,
130
+ callback=None,
131
+ **kwargs
132
+ ):
133
+ extra_args = {} if extra_args is None else extra_args
134
+ s_in = x.new_ones([x.shape[0]])
135
+
136
+ total_steps = len(sigmas) - 1
137
+ shared.state.sampling_steps = total_steps
138
+
139
+ shared.state.job_count = 1
140
+ shared.state.job_no = 0
141
+
142
+ for i in range(total_steps):
143
+ shared.state.sampling_step = i + 1
144
+
145
+ sigma = sigmas[i]
146
+ sigma_next = sigmas[i + 1]
147
+ dt = sigma_next - sigma
148
+
149
+ denoised = model(x, sigma * s_in, **extra_args)
150
+ d = (x - denoised) / sigma
151
+
152
+ # ULTRA: refuerzo progresivo
153
+ if i > total_steps * 0.55:
154
+ boost = 1.18 + (i / total_steps) * 0.10
155
+ x = x + d * dt * boost
156
+ else:
157
+ x = x + d * dt
158
+
159
+ if callback is not None:
160
+ callback({
161
+ "x": x,
162
+ "i": i,
163
+ "sigma": sigma,
164
+ "sampling_step": i + 1,
165
+ "sampling_steps": total_steps
166
+ })
167
+
168
+ return x
169
+
170
+ # =====================================================
171
+ # DPM++ 2M PSEUDO-HIRES
172
+ # =====================================================
173
+
174
+ @torch.no_grad()
175
+ def sample_dpmpp_2m_pseudo_hires(
176
+ model,
177
+ x,
178
+ sigmas,
179
+ extra_args=None,
180
+ callback=None,
181
+ **kwargs
182
+ ):
183
+ extra_args = {} if extra_args is None else extra_args
184
+ s_in = x.new_ones([x.shape[0]])
185
+
186
+ total_steps = len(sigmas) - 1
187
+ shared.state.sampling_steps = total_steps
188
+
189
+ shared.state.job_count = 1
190
+ shared.state.job_no = 0
191
+
192
+ old_denoised = None
193
+
194
+ for i in range(total_steps):
195
+ shared.state.sampling_step = i + 1
196
+
197
+ sigma = sigmas[i]
198
+ sigma_next = sigmas[i + 1]
199
+ dt = sigma_next - sigma
200
+
201
+ denoised = model(x, sigma * s_in, **extra_args)
202
+
203
+ if old_denoised is None:
204
+ d = (x - denoised) / sigma
205
+ x = x + d * dt
206
+ else:
207
+ d = (x - denoised) / sigma
208
+ d_old = (x - old_denoised) / sigmas[max(i-1, 0)] if old_denoised is not None else d
209
+
210
+ correction = 0.5 * (d + d_old) * dt
211
+ x = x + correction * 1.0 # puedes ajustar el factor
212
+
213
+ # Boost progresivo (similar a Ultra, pero más suave para feeling DPM)
214
+ if i > total_steps * 0.60:
215
+ boost = 1.12 + (i / total_steps) * 0.08 # más conservador que Ultra
216
+ x = x + d * dt * boost
217
+
218
+ old_denoised = denoised
219
+
220
+ if callback is not None:
221
+ callback({
222
+ "x": x,
223
+ "i": i,
224
+ "sigma": sigma,
225
+ "sampling_step": i + 1,
226
+ "sampling_steps": total_steps
227
+ })
228
+
229
+ return x
230
+
231
+ # =====================================================
232
+ # AGGA SMART-COMBO V9 (Universal Fusion)
233
+ # =====================================================
234
+ @torch.no_grad()
235
+ def sample_agga_smart_combo(model, x, sigmas, extra_args=None, callback=None, **kwargs):
236
+ extra_args = extra_args or {}
237
+ s_in = x.new_ones([x.shape[0]])
238
+
239
+ total_steps = len(sigmas) - 1
240
+ shared.state.sampling_steps = total_steps
241
+
242
+ # ---------------------------------------------------------
243
+ # 1. Prompt Reader
244
+ # ---------------------------------------------------------
245
+ prompt_tags = ""
246
+ try:
247
+ # Buscamos en la pila de ejecución el objeto 'p' de A1111
248
+ for frame_info in inspect.stack():
249
+ if 'p' in frame_info.frame.f_locals:
250
+ p_obj = frame_info.frame.f_locals['p']
251
+ if hasattr(p_obj, 'prompt'):
252
+ prompt_tags = (str(p_obj.prompt) + " " + str(p_obj.all_prompts)).lower()
253
+ break
254
+ except:
255
+ pass
256
+
257
+ # ---------------------------------------------------------
258
+ # 2. CONFIGURACIÓN DE ESTRATEGIA
259
+ # ---------------------------------------------------------
260
+
261
+ # Valores por defecto
262
+ strategy = "AUTO"
263
+ engine_1 = "NONE"
264
+ engine_2 = "NONE"
265
+ split_ratio = 0.5 # 50% por defecto
266
+
267
+ # A) DETECCIÓN DE MODO FUSIÓN (Prioridad Alta)
268
+ if "fsn_" in prompt_tags:
269
+ strategy = "FUSION"
270
+
271
+ # Detectar combinaciones
272
+ if "euler_dpm" in prompt_tags:
273
+ engine_1, engine_2 = "EULER_A", "DPM2"
274
+ desc = "Euler A >> DPM++ 2M"
275
+ elif "native_flash" in prompt_tags:
276
+ engine_1, engine_2 = "NATIVE", "FLASH"
277
+ desc = "Native >> Flash V2"
278
+ elif "dpm_euler" in prompt_tags:
279
+ engine_1, engine_2 = "DPM2", "EULER_A"
280
+ desc = "DPM++ 2M >> Euler A"
281
+ elif "native_dpm" in prompt_tags:
282
+ engine_1, engine_2 = "NATIVE", "DPM2"
283
+ desc = "Native >> DPM++ 2M"
284
+ else:
285
+ # Fusión por defecto si solo pone 'fsn_'
286
+ engine_1, engine_2 = "EULER_A", "DPM2"
287
+ desc = "Standard Fusion"
288
+
289
+ # Detectar punto de corte personalizado (ej: split_70)
290
+ # Busca palabras como 'split_30', 'split_80'
291
+ import re
292
+ match = re.search(r'split_(\d+)', prompt_tags)
293
+ if match:
294
+ split_val = int(match.group(1))
295
+ split_ratio = split_val / 100.0
296
+
297
+ shared.state.textinfo = f"AGGA FUSION: [{desc}] @ {int(split_ratio*100)}%"
298
+
299
+ # B) MODO AUTOMÁTICO (Si no hay fusión)
300
+ else:
301
+ if total_steps > 15:
302
+ strategy = "HIGH_RES"
303
+ engine_1 = "FLASH" # Solo usa un motor
304
+ shared.state.textinfo = "AGGA High-Res: [Flash V2]"
305
+ else:
306
+ strategy = "SMART_LOW"
307
+ engine_1 = "SMART" # El motor se decide en el paso 0
308
+ shared.state.textinfo = "AGGA Smart: Analyzing..."
309
+
310
+ # ---------------------------------------------------------
311
+ # 3. BUCLE DE GENERACIÓN
312
+ # ---------------------------------------------------------
313
+
314
+ # Estados internos
315
+ old_denoised = None
316
+ h_last = None
317
+ current_engine = engine_1
318
+
319
+ # Helper para DPM
320
+ def t_fn(sigma): return -sigma.log()
321
+
322
+ for i in range(total_steps):
323
+ shared.state.sampling_step = i + 1
324
+ sigma = sigmas[i]
325
+ sigma_next = sigmas[i + 1]
326
+
327
+ # --- Predicción ---
328
+ denoised = model(x, sigma * s_in, **extra_args)
329
+
330
+ # --- LÓGICA DE CAMBIO DE MOTOR (Fusión) ---
331
+ if strategy == "FUSION":
332
+ switch_step = int(total_steps * split_ratio)
333
+
334
+ if i < switch_step:
335
+ new_engine = engine_1
336
+ else:
337
+ new_engine = engine_2
338
+
339
+ # Si cambiamos de motor, limpiamos la memoria del sampler anterior
340
+ if new_engine != current_engine:
341
+ old_denoised = None # Reset vital para DPM
342
+ current_engine = new_engine
343
+
344
+ # --- LÓGICA SMART (Análisis en paso 0) ---
345
+ if strategy == "SMART_LOW" and i == 0:
346
+ energy = denoised.std()
347
+ if energy < 0.88:
348
+ current_engine = "EULER_A"
349
+ tag = "Rescue: Euler A"
350
+ elif energy > 1.25:
351
+ current_engine = "DPM2"
352
+ tag = "Rescue: DPM++ 2M"
353
+ else:
354
+ current_engine = "NATIVE"
355
+ tag = "Native Optimized"
356
+ shared.state.textinfo = f"AGGA Smart: [{tag}]"
357
+
358
+ # -----------------------------------------------------
359
+ # EJECUCIÓN DE MOTORES
360
+ # -----------------------------------------------------
361
+
362
+ # === MOTOR: DPM++ 2M (Exacto) ===
363
+ if current_engine == "DPM2":
364
+ t, t_next = t_fn(sigma), t_fn(sigma_next)
365
+ h = t_next - t
366
+
367
+ if old_denoised is None or sigma_next == 0:
368
+ x = (sigma_next / sigma) * x - (-h).expm1() * denoised
369
+ else:
370
+ h_last = -sigmas[i-1].log() + sigmas[i].log()
371
+ r = h / h_last
372
+ denoised_d = (1 + 1 / (2 * r)) * denoised - (1 / (2 * r)) * old_denoised
373
+ x = (sigma_next / sigma) * x - (-h).expm1() * denoised_d
374
+
375
+ # === MOTOR: EULER ANCESTRAL (Exacto) ===
376
+ elif current_engine == "EULER_A":
377
+ sigma_up = (sigma_next ** 2 * (sigma ** 2 - sigma_next ** 2) / sigma ** 2) ** 0.5
378
+ sigma_down = (sigma_next ** 2 - sigma_up ** 2) ** 0.5
379
+ d = (x - denoised) / sigma
380
+
381
+ x = x + d * (sigma_down - sigma)
382
+ if sigma_next > 0:
383
+ x = x + torch.randn_like(x) * sigma_up
384
+
385
+ # === MOTOR: NATIVE (Turbo Stable) ===
386
+ elif current_engine == "NATIVE":
387
+ if i < total_steps - 1:
388
+ x = denoised + (x - denoised) * (sigma_next / sigma)
389
+ else:
390
+ x = denoised
391
+
392
+ # === MOTOR: FLASH V2 (Texturizado) ===
393
+ elif current_engine == "FLASH":
394
+ dt = sigma_next - sigma
395
+ if old_denoised is None:
396
+ d = (x - denoised) / sigma
397
+ x = x + d * dt * 1.05
398
+ else:
399
+ d = (x - denoised) / sigma
400
+ d_old = (x - old_denoised) / sigmas[max(i-1, 0)]
401
+ x = x + (0.6 * d + 0.4 * d_old) * dt
402
+
403
+ # Boost Lógico de Flash
404
+ if i > total_steps * 0.50:
405
+ progress = (i - total_steps * 0.50) / (total_steps * 0.50)
406
+ boost = 1.08 + progress * 0.18
407
+ x = x + d * dt * boost
408
+ if i == total_steps - 1:
409
+ x = x + (denoised - x) * 0.15
410
+
411
+ old_denoised = denoised
412
+ if callback: callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
413
+ if shared.state.interrupted: break
414
+
415
+ return torch.clamp(x, -5.0, 5.0)
416
+
417
+ # =====================================================
418
+ # AGGA PSEUDO-HIRES DETAIL
419
+ # =====================================================
420
+
421
+ @torch.no_grad()
422
+ def sample_pseudo_hires_detail(model, x, sigmas, extra_args=None, callback=None, **kwargs):
423
+ extra_args = extra_args or {}
424
+ s_in = x.new_ones([x.shape[0]])
425
+ total_steps = len(sigmas) - 1
426
+ shared.state.sampling_steps = total_steps
427
+
428
+ prev_x = x.clone()
429
+
430
+ def get_detail_mask(latent):
431
+ # Calculamos gradientes de forma más eficiente
432
+ dy = torch.abs(latent[:, :, 1:, :] - latent[:, :, :-1, :])
433
+ dx = torch.abs(latent[:, :, :, 1:] - latent[:, :, :, :-1])
434
+
435
+ # Padding para recuperar el tamaño original (B, C, H, W)
436
+ dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')
437
+ dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')
438
+
439
+ grad = torch.sqrt(dx**2 + dy**2).mean(dim=1, keepdim=True)
440
+ # Normalización robusta: No usamos .max() para evitar amplificar ruido en zonas planas
441
+ grad = torch.clamp(grad * 2.0, 0.0, 1.0)
442
+ return grad
443
+
444
+ for i in range(total_steps):
445
+ sigma = sigmas[i]
446
+ sigma_next = sigmas[i + 1]
447
+ dt = sigma_next - sigma
448
+
449
+ denoised = model(x, sigma * s_in, **extra_args)
450
+ d = (x - denoised) / sigma # Dirección del gradiente
451
+
452
+ progress = i / total_steps
453
+
454
+ if progress < 0.4:
455
+ multiplier = 1.05
456
+ elif progress < 0.7:
457
+ multiplier = 1.10 + (progress * 0.10)
458
+ else:
459
+ multiplier = 1.0
460
+
461
+ x_next = x + d * dt * multiplier
462
+
463
+ if progress >= 0.7:
464
+ detail_mask = get_detail_mask(x)
465
+
466
+ refine_strength = 0.05 * (1.0 - progress)
467
+ x_next = x_next + (denoised - x_next) * refine_strength * detail_mask
468
+
469
+ sharpen_strength = 0.03 * detail_mask
470
+ x_next = x_next + (x_next - x) * sharpen_strength
471
+
472
+ x = x_next
473
+
474
+ if callback is not None:
475
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i + 1, "sampling_steps": total_steps})
476
+
477
+ return torch.clamp(x, -5.0, 5.0)
478
+
479
+ # =====================================================
480
+ # AGGA DMD-TURBO LANDING - Optimizado para guías LCM/DMD2 (pocos pasos)
481
+ # =====================================================
482
+
483
+ @torch.no_grad()
484
+ def sample_agga_dmd_turbo(model, x, sigmas, extra_args=None, callback=None, **kwargs):
485
+ extra_args = extra_args or {}
486
+ s_in = x.new_ones([x.shape[0]])
487
+ total_steps = len(sigmas) - 1
488
+ shared.state.sampling_steps = total_steps
489
+
490
+ for i in range(total_steps):
491
+ sigma = sigmas[i]
492
+ sigma_next = sigmas[i + 1]
493
+ dt = sigma_next - sigma
494
+
495
+ denoised = model(x, sigma * s_in, **extra_args)
496
+ d = (x - denoised) / sigma
497
+
498
+ if i < total_steps - 1:
499
+ x = x + d * dt
500
+
501
+ else:
502
+ x = x + (denoised - x) * 0.85
503
+
504
+ blurred_x = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)
505
+ sharpen_map = x - blurred_x
506
+
507
+ x = x + sharpen_map * 0.15
508
+
509
+ if callback is not None:
510
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i + 1, "sampling_steps": total_steps})
511
+
512
+ return torch.clamp(x, -5.0, 5.0)
513
+
514
+ # =====================================================
515
+ # AGGA Herrscher-Native
516
+ # =====================================================
517
+ @torch.no_grad()
518
+ def sample_agga_herrscher_native(model, x, sigmas, extra_args=None, callback=None, **kwargs):
519
+ extra_args = extra_args or {}
520
+ s_in = x.new_ones([x.shape[0]])
521
+ total_steps = len(sigmas) - 1
522
+ shared.state.sampling_steps = total_steps
523
+
524
+ # Reducimos momentum para que sea más ágil en pocos pasos (8 steps)
525
+ momentum_beta = 0.50
526
+ momentum = None
527
+
528
+ for i in range(total_steps):
529
+ sigma = sigmas[i]
530
+ sigma_next = sigmas[i+1]
531
+ dt = sigma_next - sigma
532
+
533
+ denoised = model(x, sigma * s_in, **extra_args)
534
+ d = (x - denoised) / sigma
535
+
536
+ if momentum is None:
537
+ momentum = d
538
+ else:
539
+ momentum = momentum_beta * momentum + (1 - momentum_beta) * d
540
+
541
+ x_next = x + momentum * dt
542
+
543
+ progress = i / total_steps
544
+ if 0.2 < progress < 0.9:
545
+ mag = x_next.std()
546
+ if mag < 1.0:
547
+ scale_factor = (1.0 / (mag + 1e-6)) * 0.05
548
+ x_next = x_next * (1.0 + scale_factor)
549
+
550
+ x_next = x_next - (x_next.mean() * 0.02)
551
+
552
+ x = x_next
553
+
554
+ if callback is not None:
555
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i + 1, "sampling_steps": total_steps})
556
+
557
+ return torch.clamp(x, -5.0, 5.0)
558
+
559
+ # =====================================================
560
+ # AGGA-Detail-Native
561
+ # =====================================================
562
+ @torch.no_grad()
563
+ def sample_agga_detail_native(model, x, sigmas, extra_args=None, callback=None, **kwargs):
564
+ extra_args = extra_args or {}
565
+ s_in = x.new_ones([x.shape[0]])
566
+ total_steps = len(sigmas) - 1
567
+ shared.state.sampling_steps = total_steps
568
+ shared.state.textinfo = "LCM Detail V4: Hires-Refiner Mode"
569
+
570
+ for i in range(total_steps):
571
+ shared.state.sampling_step = i
572
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
573
+ progress = i / total_steps
574
+
575
+ denoised = model(x, sigma * s_in, **extra_args)
576
+
577
+ if i > 0:
578
+
579
+ dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])
580
+ dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])
581
+ dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')
582
+ dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')
583
+ detail_mask = torch.clamp((dx + dy).mean(dim=1, keepdim=True) * 2.5, 0.0, 1.0)
584
+
585
+ if progress > 0.60:
586
+
587
+ sigma_refine = sigma * 0.95
588
+ refine_denoised = model(x, sigma_refine * s_in, **extra_args)
589
+
590
+ denoised = denoised + (refine_denoised - denoised) * (0.4 * detail_mask)
591
+ else:
592
+
593
+ blurred = F.avg_pool2d(denoised, 3, 1, 1)
594
+ denoised = denoised + (denoised - blurred) * (0.12 * detail_mask)
595
+
596
+ if i < total_steps - 1:
597
+ x = denoised + (x - denoised) * (sigma_next / sigma)
598
+ else:
599
+ x = denoised
600
+
601
+ if callback:
602
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
603
+ if shared.state.interrupted: break
604
+
605
+ return torch.clamp(x, -5.0, 5.0)
606
+
607
+ # =====================================================
608
+ # AGGA Hyper-Detail Hybrid
609
+ # =====================================================
610
+ @torch.no_grad()
611
+ def sample_agga_hyper_detail_hybrid(model, x, sigmas, extra_args=None, callback=None, **kwargs):
612
+ extra_args = extra_args or {}
613
+ s_in = x.new_ones([x.shape[0]])
614
+ total_steps = len(sigmas) - 1
615
+ shared.state.sampling_steps = total_steps
616
+
617
+ split_step = int(total_steps * 0.66)
618
+
619
+ for i in range(total_steps):
620
+ shared.state.sampling_step = i
621
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
622
+
623
+ denoised = model(x, sigma * s_in, **extra_args)
624
+
625
+ dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])
626
+ dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])
627
+ dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')
628
+ dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')
629
+ detail_mask = torch.clamp((dx + dy).mean(dim=1, keepdim=True) * 2.5, 0.0, 1.0)
630
+
631
+ if i >= split_step:
632
+ shared.state.textinfo = f"Phase 2: Power Detail (Step {i+1})"
633
+ sigma_refine = sigma * 0.95
634
+ refine_denoised = model(x, sigma_refine * s_in, **extra_args)
635
+ denoised = denoised + (refine_denoised - denoised) * (0.45 * detail_mask)
636
+
637
+ else:
638
+ shared.state.textinfo = f"Phase 1: V2 Structure (Step {i+1})"
639
+ blurred = F.avg_pool2d(denoised, 3, 1, 1)
640
+ denoised = denoised + (denoised - blurred) * (0.12 * detail_mask)
641
+
642
+ if i < total_steps - 1:
643
+ x = denoised + (x - denoised) * (sigma_next / sigma)
644
+
645
+ x_std = x.std()
646
+ if x_std < 1.0:
647
+ x = x * (1.0 + (1.0 - x_std) * 0.05)
648
+ else:
649
+
650
+ x = denoised
651
+
652
+ if callback:
653
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
654
+ if shared.state.interrupted: break
655
+
656
+ return torch.clamp(x, -5.0, 5.0)
657
+
658
+ # =====================================================
659
+ # AGGA Style Repair
660
+ # =====================================================
661
+ @torch.no_grad()
662
+ def sample_agga_style_repair_pro(model, x, sigmas, extra_args=None, callback=None, **kwargs):
663
+ extra_args = extra_args or {}
664
+ s_in = x.new_ones([x.shape[0]])
665
+ total_steps = len(sigmas) - 1
666
+ shared.state.sampling_steps = total_steps
667
+
668
+ BOCETADO_STEPS = int(total_steps * 0.40)
669
+ prev_x = x.clone()
670
+
671
+ for i in range(total_steps):
672
+ shared.state.sampling_step = i
673
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
674
+ progress = i / total_steps
675
+
676
+ denoised = model(x, sigma * s_in, **extra_args)
677
+
678
+ dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])
679
+ dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])
680
+ dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')
681
+ dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')
682
+ style_mask = torch.clamp(torch.sqrt(dx**2 + dy**2).mean(dim=1, keepdim=True) * 2.8, 0.0, 1.0)
683
+
684
+ if i < BOCETADO_STEPS:
685
+ shared.state.textinfo = f"Phase 1: Creative Sketching (Step {i+1})"
686
+
687
+ boost = 1.20 + (i / BOCETADO_STEPS) * 0.25
688
+ d = (x - denoised) / sigma
689
+ x = x + d * (sigma_next - sigma) * boost
690
+
691
+ else:
692
+ shared.state.textinfo = f"Phase 2: Style Repair (Step {i+1})"
693
+
694
+ strength = 0.05 + progress * 0.15
695
+ x = x + (denoised - x) * strength * style_mask
696
+
697
+ if i % 3 == 0 and i < total_steps - 1:
698
+
699
+ sigma_style = sigma * (1.12 + 0.05 * (progress - 0.4))
700
+ denoised_style = model(x, sigma_style * s_in, **extra_args)
701
+
702
+ style_delta = (denoised_style - denoised) * 0.04 * style_mask
703
+ x = x + style_delta
704
+
705
+ x = x + (x - prev_x) * 0.035 * style_mask
706
+
707
+ if i < total_steps - 1 and i >= BOCETADO_STEPS:
708
+
709
+ x = denoised + (x - denoised) * (sigma_next / sigma)
710
+
711
+ x_std = x.std()
712
+ if x_std < 1.08:
713
+ x = x * (1.08 / (x_std + 1e-6))
714
+ elif i == total_steps - 1:
715
+
716
+ x = denoised + (x - denoised) * 0.07
717
+
718
+ prev_x = x.clone()
719
+ if callback:
720
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
721
+ if shared.state.interrupted: break
722
+
723
+ return torch.clamp(x, -5.0, 5.0)
724
+
725
+ # =====================================================
726
+ # AGGA Style Repair Ultra
727
+ # =====================================================
728
+ @torch.no_grad()
729
+ def sample_agga_style_repair_ultra(model, x, sigmas, extra_args=None, callback=None, **kwargs):
730
+ extra_args = extra_args or {}
731
+ s_in = x.new_ones([x.shape[0]])
732
+ total_steps = len(sigmas) - 1
733
+ shared.state.sampling_steps = total_steps
734
+
735
+ BOCETADO_STEPS = int(total_steps * 0.45)
736
+ prev_x = x.clone()
737
+
738
+ for i in range(total_steps):
739
+ shared.state.sampling_step = i
740
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
741
+ dt = sigma_next - sigma
742
+ progress = i / total_steps
743
+
744
+ denoised = model(x, sigma * s_in, **extra_args)
745
+ d = (x - denoised) / sigma
746
+
747
+ dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])
748
+ dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])
749
+ dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')
750
+ dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')
751
+
752
+ style_mask = torch.clamp(torch.sqrt(dx**2 + dy**2).mean(dim=1, keepdim=True) * 2.8, 0.0, 1.0)
753
+
754
+ if i < BOCETADO_STEPS:
755
+ x = x + d * dt
756
+
757
+ else:
758
+
759
+ speed_factor = torch.exp(-torch.abs(dt) * 2.5).item()
760
+ u_boost = 1.18 + progress * 0.12
761
+
762
+ if i % 2 == 0 or speed_factor > 0.6:
763
+
764
+ sigma_style = sigma * (1.15 + 0.05 * (progress - 0.4))
765
+ denoised_style = model(x, sigma_style * s_in, **extra_args)
766
+
767
+ atm_mask = torch.clamp(style_mask + 0.20, 0.0, 1.0)
768
+
769
+ style_delta = (denoised_style - denoised) * 0.05 * atm_mask * (1.0 + speed_factor)
770
+ x = x + style_delta * u_boost
771
+
772
+ x = x + d * dt * u_boost
773
+
774
+ sharpen = 0.038 + (speed_factor * 0.015)
775
+ x = x + (x - prev_x) * sharpen * style_mask
776
+
777
+ if i == total_steps - 1:
778
+ x = denoised + (x - denoised) * 0.08
779
+
780
+ prev_x = x.clone()
781
+ if callback: callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
782
+ if shared.state.interrupted: break
783
+
784
+ return torch.clamp(x, -5.5, 5.5)
785
+
786
+ # =====================================================
787
+ # AGGA STRUCTURAL-DETAIL (Hybrid V5)
788
+ # =====================================================
789
+ @torch.no_grad()
790
+ def sample_agga_structural_detail(model, x, sigmas, extra_args=None, callback=None, **kwargs):
791
+ extra_args = extra_args or {}
792
+ s_in = x.new_ones([x.shape[0]])
793
+ total_steps = len(sigmas) - 1
794
+ shared.state.sampling_steps = total_steps
795
+
796
+ old_d = None
797
+
798
+ split_idx = int(total_steps * 0.45)
799
+
800
+ for i in range(total_steps):
801
+ shared.state.sampling_step = i + 1
802
+ sigma = sigmas[i]
803
+ sigma_next = sigmas[i + 1]
804
+ dt = sigma_next - sigma
805
+
806
+ denoised = model(x, sigma * s_in, **extra_args)
807
+ d = (x - denoised) / sigma
808
+
809
+ if i < split_idx:
810
+
811
+ if old_d is None:
812
+
813
+ x = x + d * dt
814
+ else:
815
+
816
+ x = x + 0.5 * (d + old_d) * dt
817
+
818
+ else:
819
+
820
+ dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])
821
+ dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])
822
+ dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')
823
+ dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')
824
+
825
+ detail_mask = torch.clamp((dx + dy).mean(dim=1, keepdim=True) * 2.2, 0.0, 1.0)
826
+
827
+ progress_phase2 = (i - split_idx) / (total_steps - split_idx)
828
+ boost_amount = 1.0 + (progress_phase2 * 0.15)
829
+
830
+ final_dt = dt * (1.0 + (boost_amount - 1.0) * detail_mask)
831
+
832
+ x = x + d * final_dt
833
+
834
+ if progress_phase2 > 0.6:
835
+ x = x + (x - x.clone()) * 0.04 * detail_mask
836
+
837
+ old_d = d
838
+
839
+ if callback is not None:
840
+ callback({
841
+ "x": x,
842
+ "i": i,
843
+ "sigma": sigma,
844
+ "sampling_step": i + 1,
845
+ "sampling_steps": total_steps
846
+ })
847
+
848
+ return torch.clamp(x, -5.0, 5.0)
849
+
850
+ # =====================================================
851
+ # AGGA STYLE-REPAIR (Prompt-Aware Edition)
852
+ # =====================================================
853
+ @torch.no_grad()
854
+ def sample_agga_style_repair_prompt_aware(model, x, sigmas, extra_args=None, callback=None, **kwargs):
855
+
856
+ if hasattr(model, 'need_last_noise_uncond'):
857
+ model.need_last_noise_uncond = True
858
+
859
+ extra_args = extra_args or {}
860
+ s_in = x.new_ones([x.shape[0]])
861
+ total_steps = len(sigmas) - 1
862
+ shared.state.sampling_steps = total_steps
863
+
864
+ BOCETADO_STEPS = int(total_steps * 0.40)
865
+ prev_x = x.clone()
866
+
867
+ for i in range(total_steps):
868
+ shared.state.sampling_step = i
869
+ sigma = sigmas[i]
870
+ sigma_next = sigmas[i + 1]
871
+ dt = sigma_next - sigma
872
+ progress = i / total_steps
873
+
874
+ denoised = model(x, sigma * s_in, **extra_args)
875
+
876
+ style_force_vector = None
877
+
878
+ last_noise_uncond = getattr(model, 'last_noise_uncond', None)
879
+
880
+ if last_noise_uncond is not None and i > BOCETADO_STEPS:
881
+ # Reconstruimos la imagen "Incondicional" (x0_uncond) desde el ruido
882
+ # x0 = x - sigma * noise
883
+ uncond_denoised = x - sigma * last_noise_uncond
884
+
885
+ style_force_vector = denoised - uncond_denoised
886
+
887
+ dy = torch.abs(denoised[:, :, 1:, :] - denoised[:, :, :-1, :])
888
+ dx = torch.abs(denoised[:, :, :, 1:] - denoised[:, :, :, :-1])
889
+ dy = F.pad(dy, (0, 0, 0, 1), mode='replicate')
890
+ dx = F.pad(dx, (0, 1, 0, 0), mode='replicate')
891
+ style_mask = torch.clamp(torch.sqrt(dx**2 + dy**2).mean(dim=1, keepdim=True) * 2.8, 0.0, 1.0)
892
+
893
+ # --- FASE 1: BOCETADO ---
894
+ if i < BOCETADO_STEPS:
895
+
896
+ boost = 1.20 + (i / BOCETADO_STEPS) * 0.20
897
+ d = (x - denoised) / sigma
898
+ x = x + d * dt * boost
899
+
900
+ # --- FASE 2: RECUPERACIÓN DE ESTILO DIRIGIDA ---
901
+ else:
902
+
903
+ if style_force_vector is not None:
904
+
905
+ prompt_guidance = style_force_vector * style_mask * 0.25
906
+
907
+ x = x + prompt_guidance * torch.abs(dt)
908
+
909
+ x = x + (x - prev_x) * 0.035 * style_mask
910
+
911
+ d = (x - denoised) / sigma
912
+ x = x + d * dt
913
+
914
+ if i >= BOCETADO_STEPS:
915
+ x_std = x.std()
916
+ if x_std > 1.15: # Límite de seguridad
917
+ x = x * (1.15 / x_std)
918
+
919
+ prev_x = x.clone()
920
+
921
+ if callback:
922
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
923
+
924
+ return torch.clamp(x, -5.0, 5.0)
925
+
926
+ # =====================================================
927
+ # AGGA PIXEL-MASTER V10 (Spatial-Only)
928
+ # =====================================================
929
+ @torch.no_grad()
930
+ def sample_agga_pixel_master(model, x, sigmas, extra_args=None, callback=None, **kwargs):
931
+ extra_args = extra_args or {}
932
+ s_in = x.new_ones([x.shape[0]])
933
+ total_steps = len(sigmas) - 1
934
+ shared.state.sampling_steps = total_steps
935
+
936
+ # AJUSTES V10
937
+ # Factor de reducción.
938
+ # 2.0 = Bloques visibles (SNES)
939
+ # 3.0 - 4.0 = Bloques muy grandes (Atari/NES)
940
+ # Si con 2.0 se ve borroso, SUBE a 3.0 o 4.0.
941
+ block_size = 1.88
942
+
943
+ for i in range(total_steps):
944
+ shared.state.sampling_step = i
945
+ sigma = sigmas[i]
946
+ sigma_next = sigmas[i + 1]
947
+ dt = sigma_next - sigma
948
+
949
+ denoised = model(x, sigma * s_in, **extra_args)
950
+
951
+ d = (x - denoised) / sigma
952
+ x = x + d * dt
953
+
954
+ if i == total_steps - 1:
955
+
956
+ latents = denoised
957
+
958
+ h, w = latents.shape[-2:]
959
+ small_h, small_w = int(h / block_size), int(w / block_size)
960
+
961
+ latents_pixelated = F.interpolate(latents, size=(small_h, small_w), mode='area')
962
+
963
+ latents_pixelated = F.interpolate(latents_pixelated, size=(h, w), mode='nearest')
964
+
965
+ x = latents_pixelated
966
+
967
+ if callback:
968
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
969
+
970
+ return x
971
+
972
+
973
+ # =====================================================
974
+ # LORA BRIDGE (PDXL TO VELVETTE_V4/ NoobAI)
975
+ # =====================================================
976
+
977
+ @torch.no_grad()
978
+ def sample_agga_lora_bridge(model, x, sigmas, extra_args=None, callback=None, **kwargs):
979
+ extra_args = extra_args or {}
980
+ s_in = x.new_ones([x.shape[0]])
981
+ total_steps = len(sigmas) - 1
982
+
983
+ # ADN de Pony V6 (Valores reales extraídos)
984
+ PONY_STD_TARGET = 0.016593
985
+ DELTA_MEAN = -0.0104
986
+
987
+ for i in range(total_steps):
988
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
989
+ dt = sigma_next - sigma
990
+ progress = i / total_steps
991
+
992
+ # 1. Predicción y Limpieza Anti-NaNs
993
+ denoised = model(x, sigma * s_in, **extra_args)
994
+ denoised = torch.nan_to_num(denoised, nan=0.0, posinf=4.0, neginf=-4.0)
995
+
996
+ # 2. Monitor de Salud del Tensor
997
+ mag = denoised.std()
998
+
999
+ # --- EL SUELO DE ENERGÍA AGGA ---
1000
+ # Si la energía cae demasiado (gris), forzamos recuperación
1001
+ if mag < 0.90:
1002
+ denoised = denoised * (0.95 / (mag + 1e-6))
1003
+
1004
+ # 3. Inyección de ADN con Factor 1.3 (Blindada)
1005
+ influence = 1.0 - (2.0 * progress - 1.0)**4
1006
+ # El ratio de escala se calcula con precisión de seguridad
1007
+ scale_ratio = torch.clamp(torch.tensor(PONY_STD_TARGET / (mag + 1e-6)), 0.8, 1.25)
1008
+
1009
+ # Aplicamos la fórmula de ADN:
1010
+ # $$denoised = denoised \cdot (1 + (ratio - 1) \cdot influence \cdot 1.3) + (\Delta\mu \cdot influence)$$
1011
+ denoised = denoised * (1.0 + (scale_ratio - 1.0) * influence * 1.3)
1012
+ denoised = denoised + (DELTA_MEAN * influence * 0.7) # Reducido un 30% para evitar el colapso
1013
+
1014
+ # 4. Salto de Consistencia con Suelo de Precisión
1015
+ safe_sigma = max(sigma.item(), 1e-4)
1016
+ d = (x - denoised) / safe_sigma
1017
+ x = x + d * dt
1018
+
1019
+ if callback:
1020
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
1021
+
1022
+ return torch.clamp(x, -6.0, 6.0)
1023
+
1024
+ @torch.no_grad()
1025
+ def sample_agga_lora_bridge_stable(model, x, sigmas, extra_args=None, callback=None, **kwargs):
1026
+
1027
+ extra_args = extra_args or {}
1028
+ s_in = x.new_ones([x.shape[0]])
1029
+ total_steps = len(sigmas) - 1
1030
+
1031
+ # ADN de Pony V6 (Valores reales extraídos)
1032
+ PONY_STD_TARGET = 0.016593
1033
+ DELTA_MEAN = -0.0104
1034
+
1035
+ for i in range(total_steps):
1036
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
1037
+ dt = sigma_next - sigma
1038
+ progress = i / total_steps
1039
+
1040
+ # 1. Predicción y Sanitización Instantánea (FP16 Safe)
1041
+ denoised = model(x, sigma * s_in, **extra_args)
1042
+ denoised = torch.nan_to_num(denoised, nan=0.0, posinf=4.0, neginf=-4.0)
1043
+
1044
+ # 2. Monitor de Salud y Suelo de Energía
1045
+ mag = denoised.std()
1046
+
1047
+ # Si la energía cae por debajo de 0.90 (zona de peligro gris), inyectamos soporte.
1048
+ # Esto es lo que salvó tu imagen en el paso 08.
1049
+ if mag < 0.90:
1050
+ denoised = denoised * (0.95 / (mag + 1e-6))
1051
+
1052
+ # 3. Inyección de ADN Pony
1053
+ # Curva de influencia tipo campana
1054
+ influence = 1.0 - (2.0 * progress - 1.0)**4
1055
+
1056
+ # Cálculo del ratio con límites estrictos (basado en tus logs)
1057
+ scale_ratio = torch.clamp(torch.tensor(PONY_STD_TARGET / (mag + 1e-6)), 0.8, 1.25)
1058
+
1059
+ # Aplicamos el ADN con tu factor agresivo de 1.3, ahora que es seguro
1060
+ denoised = denoised * (1.0 + (scale_ratio - 1.0) * influence * 1.3)
1061
+ denoised = denoised + (DELTA_MEAN * influence * 0.7)
1062
+
1063
+ # 4. Salto de Consistencia Blindado
1064
+ # Evita la división por cero al final que causa la "niebla"
1065
+ safe_sigma = max(sigma.item(), 1e-4)
1066
+ d = (x - denoised) / safe_sigma
1067
+ x = x + d * dt
1068
+
1069
+ if callback:
1070
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
1071
+
1072
+ return torch.clamp(x, -6.0, 6.0)
1073
+
1074
+ @torch.no_grad()
1075
+ def sample_agga_lora_bridge_sharp(model, x, sigmas, extra_args=None, callback=None, **kwargs):
1076
+
1077
+ extra_args = extra_args or {}
1078
+ s_in = x.new_ones([x.shape[0]])
1079
+ total_steps = len(sigmas) - 1
1080
+
1081
+ PONY_STD_TARGET = 0.016593
1082
+ DELTA_MEAN = -0.0104
1083
+
1084
+ for i in range(total_steps):
1085
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
1086
+ dt = sigma_next - sigma
1087
+ progress = i / total_steps
1088
+
1089
+ # 1. Predicción y Sanitización
1090
+ denoised = model(x, sigma * s_in, **extra_args)
1091
+ denoised = torch.nan_to_num(denoised, nan=0.0, posinf=4.0, neginf=-4.0)
1092
+
1093
+ # 2. Monitor de Salud
1094
+ mag = denoised.std()
1095
+
1096
+ # --- INYECTOR DE NITIDEZ INTELIGENTE ---
1097
+ # Condición doble:
1098
+ # a) Solo en fase de textura (30% al 85%)
1099
+ # b) SOLO si el tensor está "✅ ESTABLE" (mag >= 0.90)
1100
+ if 0.3 < progress < 0.85 and mag >= 0.90:
1101
+ # Aislamiento de altas frecuencias (bordes, pestañas, texturas finas)
1102
+ blurred = F.avg_pool2d(denoised, kernel_size=3, stride=1, padding=1)
1103
+ high_freq = denoised - blurred
1104
+ # Inyectamos un 15% extra de nitidez
1105
+ denoised = denoised + (high_freq * 0.15)
1106
+
1107
+ # --- SUELO DE ENERGÍA ---
1108
+ # Si no está estable, aplicamos el rescate normal
1109
+ if mag < 0.90:
1110
+ denoised = denoised * (0.95 / (mag + 1e-6))
1111
+
1112
+ # 3. Inyección de ADN Pony (Igual que la estable)
1113
+ influence = 1.0 - (2.0 * progress - 1.0)**4
1114
+ scale_ratio = torch.clamp(torch.tensor(PONY_STD_TARGET / (mag + 1e-6)), 0.8, 1.25)
1115
+ denoised = denoised * (1.0 + (scale_ratio - 1.0) * influence * 1.3)
1116
+ denoised = denoised + (DELTA_MEAN * influence * 0.7)
1117
+
1118
+ # 4. Salto de Consistencia Blindado
1119
+ safe_sigma = max(sigma.item(), 1e-4)
1120
+ d = (x - denoised) / safe_sigma
1121
+ x = x + d * dt
1122
+
1123
+ if callback:
1124
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
1125
+
1126
+ return torch.clamp(x, -6.0, 6.0)
1127
+
1128
+
1129
+ @torch.no_grad()
1130
+ def sample_agga_lora_bridge_ultra_sharp(model, x, sigmas, extra_args=None, callback=None, **kwargs):
1131
+ extra_args = extra_args or {}
1132
+ s_in = x.new_ones([x.shape[0]])
1133
+ total_steps = len(sigmas) - 1
1134
+
1135
+ # Valores de ADN
1136
+ PONY_STD_TARGET = 0.016593
1137
+ DELTA_MEAN = -0.0104
1138
+ # NUEVO: Factor de "Temperatura" o Vibrancia (1.15 = 15% extra de pop)
1139
+ VIBRANCY_FACTOR = 1.15
1140
+
1141
+ for i in range(total_steps):
1142
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
1143
+ dt = sigma_next - sigma
1144
+ progress = i / total_steps
1145
+
1146
+ # 1. Predicción y Sanitización
1147
+ denoised = model(x, sigma * s_in, **extra_args)
1148
+ denoised = torch.nan_to_num(denoised, nan=0.0, posinf=4.5, neginf=-4.5)
1149
+
1150
+ # 2. Monitor de Salud
1151
+ mag = denoised.std()
1152
+
1153
+ # --- FASE DE INYECCIÓN ACTIVA (30% al 85%) ---
1154
+ if 0.3 < progress < 0.85 and mag >= 0.88:
1155
+ # A) INYECTOR DE NITIDEZ (Bordes)
1156
+ blurred = F.avg_pool2d(denoised, kernel_size=3, stride=1, padding=1)
1157
+ high_freq = denoised - blurred
1158
+ denoised = denoised + (high_freq * 0.18) # Ligeramente más agresivo (18%)
1159
+
1160
+ # B) NUEVO: INYECTOR DE VIBRANCIA (Temperatura/Color)
1161
+ # Calculamos la media actual del tensor
1162
+ current_mean = denoised.mean(dim=(1, 2, 3), keepdim=True)
1163
+ # Centramos el color alrededor de la media
1164
+ centered_color = denoised - current_mean
1165
+ # Estiramos la saturación (boost de vibrancia) sin mover el brillo medio
1166
+ boosted_color = centered_color * VIBRANCY_FACTOR
1167
+ # Restauramos la media
1168
+ denoised = boosted_color + current_mean
1169
+
1170
+ # --- SUELO DE ENERGÍA (Anti-Gris) ---
1171
+ if mag < 0.88:
1172
+ denoised = denoised * (0.95 / (mag + 1e-6))
1173
+
1174
+ # 3. Inyección de ADN Pony (Estructural)
1175
+ influence = 1.0 - (2.0 * progress - 1.0)**4
1176
+ scale_ratio = torch.clamp(torch.tensor(PONY_STD_TARGET / (mag + 1e-6)), 0.8, 1.3)
1177
+
1178
+ # Aplicamos el ADN con tu factor 1.3
1179
+ denoised = denoised * (1.0 + (scale_ratio - 1.0) * influence * 1.3)
1180
+ # Aplicamos el desplazamiento de negros
1181
+ denoised = denoised + (DELTA_MEAN * influence * 0.7)
1182
+
1183
+ # 4. Salto de Consistencia Blindado
1184
+ safe_sigma = max(sigma.item(), 1e-4)
1185
+ d = (x - denoised) / safe_sigma
1186
+ x = x + d * dt
1187
+
1188
+ if callback:
1189
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i, "sampling_steps": total_steps})
1190
+
1191
+ return torch.clamp(x, -6.0, 6.0)
1192
+
1193
+ # =====================================================
1194
+ # AGGA UNIVERSAL BRIDGE
1195
+ # =====================================================
1196
+ DNA_LIBRARY = {
1197
+ "PONY": {"std": 0.016593, "mean": -0.000042},
1198
+ "NOOBAI": {"std": 0.019757, "mean": 0.010395},
1199
+ "ILLUSTRIOUS_V1": {"std": 0.021907, "mean": 0.012189},
1200
+ "ILLUSTRIOUS_V2": {"std": 0.022665, "mean": 0.011841},
1201
+ "VELVETTE": {"std": 0.019734, "mean": 0.010366},
1202
+ "ONEOBSESSION": {"std": 0.019625, "mean": 0.010283},
1203
+ "SDXL": {"std": 0.017260, "mean": 0.000001},
1204
+ "ANIMAGINE": {"std": 0.017165, "mean": 0.000001},
1205
+ }
1206
+
1207
+ @torch.no_grad()
1208
+ def sample_agga_universal_bridge(model, x, sigmas, extra_args=None, callback=None, **kwargs):
1209
+ extra_args = extra_args or {}
1210
+ s_in = x.new_ones([x.shape[0]])
1211
+ total_steps = len(sigmas) - 1
1212
+ shared.state.sampling_steps = total_steps
1213
+
1214
+ source_dna, target_dna = None, None
1215
+ p_scale, p_mean = 1.15, 0.85
1216
+
1217
+ for i in range(total_steps):
1218
+ shared.state.sampling_step = i + 1
1219
+ sigma, sigma_next = sigmas[i], sigmas[i + 1]
1220
+ dt = sigma_next - sigma
1221
+ progress = i / total_steps
1222
+
1223
+ denoised = model(x, sigma * s_in, **extra_args)
1224
+ denoised = torch.nan_to_num(denoised, nan=0.0, posinf=4.0, neginf=-4.0)
1225
+ mag = denoised.std()
1226
+
1227
+ if i == 0:
1228
+ # 1. AUTO-DETECCIÓN DE BASE
1229
+ source_key = min(DNA_LIBRARY, key=lambda k: abs(DNA_LIBRARY[k]["std"] - mag.item()))
1230
+ source_dna = DNA_LIBRARY[source_key]
1231
+ target_dna = source_dna
1232
+
1233
+ # 2. HACK DE DETECCIÓN DE PROMPT (Fix A1111/Reforge)
1234
+ prompt = ""
1235
+ for frame_info in inspect.stack():
1236
+ if 'p' in frame_info.frame.f_locals:
1237
+ p_obj = frame_info.frame.f_locals['p']
1238
+ if hasattr(p_obj, 'prompt'):
1239
+ prompt = str(p_obj.prompt).lower()
1240
+ break
1241
+
1242
+ # 3. MATRIZ DE COMANDOS
1243
+ detected_hacia = "Nativo (Auto)"
1244
+ detected_desde = "Auto-Detectado"
1245
+ for key in DNA_LIBRARY.keys():
1246
+ k_low = key.lower()
1247
+ if f"hacia_{k_low}" in prompt:
1248
+ target_dna = DNA_LIBRARY[key]
1249
+ detected_hacia = key
1250
+ if f"desde_{k_low}" in prompt:
1251
+ source_dna = DNA_LIBRARY[key]
1252
+ source_key = key
1253
+ detected_desde = "Forzado (Manual)"
1254
+
1255
+ # 4. SELECTOR DE POTENCIA
1256
+ modo_desc = "Estándar"
1257
+ if "modo_fuerte" in prompt:
1258
+ p_scale, p_mean = 1.35, 0.75
1259
+ modo_desc = "Fuerte (Contraste AGGA)"
1260
+ elif "modo_safe" in prompt:
1261
+ p_scale, p_mean = 1.0, 1.0
1262
+ modo_desc = "Safe (Sincronización 1:1)"
1263
+ elif "modo_ultra" in prompt:
1264
+ p_scale, p_mean = 1.50, 0.60
1265
+ modo_desc = "Ultra (Fuerza Bruta)"
1266
+ elif "modo_neutral" in prompt:
1267
+ p_scale, p_mean = 0.0, 0.0
1268
+ modo_desc = "Neutral (Solo Post-Proceso)"
1269
+
1270
+ # --- PANEL DE CONTROL AGGA: MOSTRANDO EL PODER ---
1271
+ print(f"\n" + "═"*60)
1272
+ print(f" 🚀 AGGA UNIVERSAL BRIDGE V10 - MOTOR ACTIVO")
1273
+ print(f" " + "─"*58)
1274
+ print(f" 📡 BASE: {source_key} [{detected_desde}]")
1275
+ print(f" 🎯 LORA: {detected_hacia} (Hacia)")
1276
+ print(f" ⚡ MODO: {modo_desc}")
1277
+ print(f" 📈 PARÁMETROS: Scale {p_scale} | Mean Shift {p_mean}")
1278
+
1279
+ # Extraemos solo tus comandos del prompt para mostrarlos
1280
+ comandos = [w for w in prompt.split() if any(x in w for x in ["hacia_", "desde_", "modo_"])]
1281
+ if comandos: print(f" 📝 COMANDOS DETECTADOS: {', '.join(comandos)}")
1282
+
1283
+ print(f" 🛠️ MÉTODO: Traducción Matricial de ADN (Campana de Gauss)")
1284
+ print(f"═"*60 + "\n")
1285
+
1286
+ # 5. INYECTOR DE NITIDEZ (Tus 0.16 clásicos)
1287
+ if 0.35 < progress < 0.85 and mag >= 0.90:
1288
+ blurred = F.avg_pool2d(denoised, kernel_size=3, stride=1, padding=1)
1289
+ denoised = denoised + ((denoised - blurred) * 0.16)
1290
+
1291
+ # 6. TRADUCCIÓN DE ADN MATRICIAL (Campana de Gauss)
1292
+ influence = 1.0 - (2.0 * progress - 1.0)**4
1293
+ scale_ratio = torch.clamp(torch.tensor(target_dna["std"] / (mag + 1e-6)), 0.6, 1.4)
1294
+
1295
+ denoised = denoised * (1.0 + (scale_ratio - 1.0) * influence * p_scale)
1296
+ denoised = denoised + ((target_dna["mean"] - source_dna["mean"]) * influence * p_mean)
1297
+
1298
+ # 7. SUELO DE ENERGÍA Y SALTO
1299
+ if mag < 0.88: denoised = denoised * (0.95 / (mag + 1e-6))
1300
+ x = x + ((x - denoised) / max(sigma.item(), 1e-4)) * dt
1301
+
1302
+ if callback:
1303
+ callback({"x": x, "i": i, "sigma": sigma, "sampling_step": i + 1, "sampling_steps": total_steps})
1304
+
1305
+ return torch.clamp(x, -6.0, 6.0)
1306
+
1307
+ # =====================================================
1308
+ # AGGA AUTO-INTELLIGENT SCHEDULER V2
1309
+ # =====================================================
1310
+
1311
+ def get_sigmas_agga_smart(n, sigma_min, sigma_max, device):
1312
+
1313
+ # 1. ESCÁNER DE PROMPT (Para overrides manuales)
1314
+ prompt_tags = ""
1315
+ try:
1316
+ for frame_info in inspect.stack():
1317
+ if 'p' in frame_info.frame.f_locals:
1318
+ p_obj = frame_info.frame.f_locals['p']
1319
+ if hasattr(p_obj, 'prompt'):
1320
+ prompt_tags = (str(p_obj.prompt) + " " + str(p_obj.all_prompts)).lower()
1321
+ break
1322
+ except:
1323
+ pass
1324
+
1325
+ # 2. SELECTOR MANUAL (Prioridad Absoluta)
1326
+ if "sched_ays" in prompt_tags:
1327
+ print(" AGGA SCHEDULER: Forzado a [AYS Anchor]")
1328
+ return get_sigmas_agga_ays_anchor(n, sigma_min, sigma_max, device)
1329
+
1330
+ if "sched_turbo" in prompt_tags:
1331
+ print(" AGGA SCHEDULER: Forzado a [DMD Turbo]")
1332
+ return get_sigmas_agga_dmd(n, sigma_min, sigma_max, device)
1333
+
1334
+ if "sched_repair" in prompt_tags:
1335
+ print(" AGGA SCHEDULER: Forzado a [Double Anchor]")
1336
+ return get_sigmas_agga_double_anchor(n, sigma_min, sigma_max, device)
1337
+
1338
+ # 3. LÓGICA AUTOMÁTICA POR ZONAS (La magia)
1339
+
1340
+ # ZONA 1: LIGHTNING (1-4 Pasos)
1341
+ # Aquí necesitamos Rho explosivo para que la imagen aparezca de golpe.
1342
+ if n <= 4:
1343
+ # Usamos DMD pero con una curva logarítmica simulada para convergencia instantánea
1344
+ return get_sigmas_agga_dmd(n, sigma_min, sigma_max, device)
1345
+
1346
+ # ZONA 2: TURBO (5-8 Pasos) -> Tu favorito para Flash V2
1347
+ # La curva DMD (Rho 7) es perfecta aquí porque mantiene el ruido alto al principio
1348
+ # y cae en picada al final, ideal para samplers agresivos.
1349
+ elif n <= 8:
1350
+ return get_sigmas_agga_dmd(n, sigma_min, sigma_max, device)
1351
+
1352
+ # ZONA 3: HYBRID SWEET-SPOT (9-19 Pasos) -> La zona de FUSIÓN
1353
+ # Aquí es donde AYS (Align Your Steps) brilla. Es una curva optimizada por NVIDIA
1354
+ # que distribuye los pasos "donde más importan". Ideal para 'fsn_euler_dpm'.
1355
+ elif n < 20:
1356
+ return get_sigmas_agga_ays_anchor(n, sigma_min, sigma_max, device)
1357
+
1358
+ # ZONA 4: HIGH FIDELITY (20-49 Pasos)
1359
+ # Dynamic Rho empieza suave y se vuelve preciso.
1360
+ # Da el mejor acabado de piel y texturas para 'sample_pseudo_hires_flash_v2'.
1361
+ elif n < 50:
1362
+ return get_sigmas_dynamic_rho(n, sigma_min, sigma_max, device)
1363
+
1364
+ # ZONA 5: DEEP REPAIR / WALLPAPER (50+ Pasos)
1365
+ # Si pones tantos pasos, es porque quieres arreglar algo roto o hacer upscaling.
1366
+ # Usamos Double Anchor para fijar la estructura.
1367
+ else:
1368
+ return get_sigmas_agga_double_anchor(n, sigma_min, sigma_max, device)
1369
+
1370
+ # =====================================================
1371
+ # AGGA Schedule
1372
+ # =====================================================
1373
+
1374
+ def get_sigmas_agga_dmd(n, sigma_min, sigma_max, device):
1375
+
1376
+ rho = 7.0
1377
+ ramp = torch.linspace(0, 1, n, device=device)
1378
+ min_inv_rho = sigma_min ** (1 / rho)
1379
+ max_inv_rho = sigma_max ** (1 / rho)
1380
+ sigmas = (max_inv_rho + ramp * (min_inv_rho - max_inv_rho)) ** rho
1381
+
1382
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1383
+
1384
+ def get_sigmas_log_linear(n, sigma_min, sigma_max, device):
1385
+ """Ideal para AGGA Detail: Distribución logarítmica perfecta."""
1386
+ steps = torch.linspace(0, 1, n, device=device)
1387
+ sigmas = torch.exp(torch.log(torch.tensor(sigma_max)) * (1 - steps) + torch.log(torch.tensor(sigma_min)) * steps)
1388
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1389
+
1390
+ def get_sigmas_dynamic_rho(n, sigma_min, sigma_max, device, rho_start=5.0, rho_end=9.0):
1391
+ """Curva de potencia variable para máxima estabilidad."""
1392
+ ramp = torch.linspace(0, 1, n, device=device)
1393
+
1394
+ v_rho = rho_start + (rho_end - rho_start) * ramp
1395
+
1396
+ sigmas = []
1397
+ for i in range(n):
1398
+ r = v_rho[i]
1399
+ m_inv_r = sigma_min ** (1 / r)
1400
+ M_inv_r = sigma_max ** (1 / r)
1401
+ sig = (M_inv_r + ramp[i] * (m_inv_r - M_inv_r)) ** r
1402
+ sigmas.append(sig)
1403
+
1404
+ sigmas = torch.stack(sigmas)
1405
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1406
+
1407
+ def get_sigmas_pseudo_native(n, sigma_min, sigma_max, device):
1408
+ """Tu lógica original de rampas Soft/Sharp ahora como Scheduler universal."""
1409
+ return pseudo_hires_sigmas(n, sigma_min, sigma_max, device)
1410
+
1411
+ def get_sigmas_style_anchor(n, sigma_min, sigma_max, device):
1412
+
1413
+ ramp = torch.linspace(0, 1, n, device=device)
1414
+
1415
+ ramp_anchored = ramp + 0.15 * torch.sin(ramp * 3.1415)
1416
+
1417
+ sigmas = sigma_max * ((sigma_min / sigma_max) ** ramp_anchored)
1418
+
1419
+ sigmas[-2] = sigmas[-2] * 0.9
1420
+
1421
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1422
+
1423
+ def get_sigmas_ultra_anchor(n, sigma_min, sigma_max, device):
1424
+
1425
+ ramp = torch.linspace(0, 1, n, device=device)
1426
+
1427
+ ramp_hybrid = ramp + 0.32 * torch.sin(ramp * torch.pi)
1428
+
1429
+ sigmas = sigma_max * ((sigma_min / sigma_max) ** ramp_hybrid)
1430
+
1431
+ sigmas[-3:] = torch.linspace(sigmas[-3].item(), sigma_min, 3, device=device)
1432
+
1433
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1434
+
1435
+ def get_sigmas_agga_double_anchor(n, sigma_min, sigma_max, device):
1436
+
1437
+ t = torch.linspace(0, 1, n, device=device)
1438
+
1439
+ style_warp = 0.35 * torch.sin(t * torch.pi)
1440
+
1441
+ eye_sniper = 0.15 * torch.exp(-180 * (t - 0.82)**2)
1442
+
1443
+ dmd_tail = 0.10 * (t**4)
1444
+
1445
+ t_warped = t + style_warp + eye_sniper + dmd_tail
1446
+ t_warped = t_warped / t_warped[-1] # Normalización de la línea de tiempo
1447
+
1448
+ sigmas = sigma_max * ((sigma_min / sigma_max) ** (t_warped**1.1))
1449
+
1450
+ s_start = torch.log10(sigmas[-4])
1451
+ s_end = torch.log10(torch.as_tensor(sigma_min, device=device))
1452
+
1453
+ sigmas[-4:] = torch.logspace(s_start, s_end, 4, device=device)
1454
+
1455
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1456
+
1457
+
1458
+ def get_sigmas_agga_pixel_staircase(n, sigma_min, sigma_max, device):
1459
+
1460
+ t = torch.linspace(0, 1, n, device=device)
1461
+ sigmas = torch.exp(torch.log(torch.tensor(sigma_max)) * (1 - t) + torch.log(torch.tensor(sigma_min)) * t)
1462
+
1463
+ for i in range(len(sigmas)):
1464
+ if i % 3 != 0 and i > 0:
1465
+ # Bajada minúscula para evitar dt=0 (que rompe el sampler)
1466
+ sigmas[i] = sigmas[i-1] * 0.98
1467
+
1468
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1469
+
1470
+ def get_sigmas_agga_pixel_staircase_v2(
1471
+ n,
1472
+ sigma_min,
1473
+ sigma_max,
1474
+ device,
1475
+ hold_steps=3,
1476
+ decay=0.985
1477
+ ):
1478
+ t = torch.linspace(0, 1, n, device=device)
1479
+ s_max = torch.as_tensor(sigma_max, device=device)
1480
+ s_min = torch.as_tensor(sigma_min, device=device)
1481
+
1482
+ sigmas = torch.exp(
1483
+ torch.log(s_max) * (1 - t) +
1484
+ torch.log(s_min) * t
1485
+ )
1486
+
1487
+ for i in range(1, len(sigmas)):
1488
+ if i % hold_steps != 0:
1489
+
1490
+ sigmas[i] = sigmas[i - 1] * decay
1491
+
1492
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1493
+
1494
+ def get_sigmas_agga_lora_universal_bridge(n, sigma_min, sigma_max, device):
1495
+ t = torch.linspace(0, 1, n, device=device)
1496
+
1497
+ t_warped = t + 0.28 * torch.sin(t * torch.pi)
1498
+
1499
+ sigmas = sigma_max * ((sigma_min / sigma_max) ** (t_warped**1.15))
1500
+
1501
+ sigmas[-2] = sigmas[-2] * 0.90
1502
+
1503
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
1504
+
1505
+ def get_sigmas_agga_ays_anchor(n, sigma_min, sigma_max, device):
1506
+ ays_base = [14.615, 6.315, 3.771, 2.181, 1.342, 0.862, 0.555, 0.380, 0.234, 0.113, 0.029]
1507
+ t = torch.linspace(0, 1, n, device=device)
1508
+ t_warped = t + 0.15 * torch.sin(t * torch.pi)
1509
+ sigmas_base = torch.tensor(ays_base, device=device).log()
1510
+ indices = t_warped * (len(ays_base) - 1)
1511
+ idx_floor = indices.long().clamp(0, len(ays_base)-2)
1512
+ idx_ceil = (idx_floor + 1).clamp(0, len(ays_base)-1)
1513
+ alpha = indices - idx_floor
1514
+
1515
+ log_sigmas = sigmas_base[idx_floor] * (1 - alpha) + sigmas_base[idx_ceil] * alpha
1516
+ sigmas = torch.exp(log_sigmas)
1517
+
1518
+ return torch.cat([sigmas, sigmas.new_zeros([1])])
sd_samplers_pseudo_hires_loader.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from modules import sd_samplers_common
2
+ from modules.sd_samplers_kdiffusion import (
3
+ KDiffusionSampler,
4
+ samplers_data_k_diffusion,
5
+ )
6
+
7
+ from modules.sd_samplers_pseudo_hires import (
8
+ sample_pseudo_hires_soft,
9
+ sample_pseudo_hires_sharp,
10
+ sample_pseudo_hires_ultra,
11
+ sample_dpmpp_2m_pseudo_hires,
12
+ sample_pseudo_hires_detail,
13
+ sample_agga_dmd_turbo,
14
+ sample_agga_herrscher_native,
15
+ sample_agga_detail_native,
16
+ sample_agga_smart_combo,
17
+ sample_agga_hyper_detail_hybrid,
18
+ sample_agga_structural_detail,
19
+ sample_agga_style_repair_pro,
20
+ sample_agga_style_repair_prompt_aware,
21
+ sample_agga_style_repair_ultra,
22
+ sample_agga_lora_bridge,
23
+ sample_agga_lora_bridge_stable,
24
+ sample_agga_lora_bridge_sharp,
25
+ sample_agga_lora_bridge_ultra_sharp,
26
+ sample_agga_universal_bridge,
27
+ sample_agga_pixel_master,
28
+ )
29
+
30
+ def register():
31
+ existing = [s.name for s in samplers_data_k_diffusion]
32
+ count = 0
33
+
34
+ # =========================================================
35
+ # CONFIGURACIÓN: Samplers!
36
+ # Formato: (Nombre Visible, Función, [Alias1, Alias2...])
37
+ # =========================================================
38
+ agga_samplers_config = [
39
+ ("AGGA Pseudo-HiRes Soft", sample_pseudo_hires_soft, ["AGGA_ph_soft"]),
40
+ ("AGGA Pseudo-HiRes Sharp", sample_pseudo_hires_sharp, ["AGGA_ph_sharp"]),
41
+ ("AGGA Pseudo-HiRes Ultra", sample_pseudo_hires_ultra, ["AGGA_ph_ultra"]),
42
+ ("AGGA Pseudo-HiRes DPM++ 2M", sample_dpmpp_2m_pseudo_hires, ["agga_ph_dpm2m"]),
43
+ ("AGGA Pseudo-HiRes Flash", sample_agga_smart_combo, ["agga_ph_flash_NTV"]),
44
+ ("AGGA Pseudo-HiRes Detail", sample_pseudo_hires_detail, ["agga_ph_detail"]),
45
+ ("AGGA DMD-Turbo Landing", sample_agga_dmd_turbo, ["agga_dmd_turbo"]),
46
+ ("AGGA Herrscher-Native", sample_agga_herrscher_native, ["agga_herrscher_v6"]),
47
+ ("AGGA-Detail-Native (LCM)", sample_agga_detail_native, ["agga_dn"]),
48
+ ("AGGA-Structural-Detail", sample_agga_structural_detail, ["agga_struct_detail"]),
49
+ ("AGGA Hyper-Detail Hybrid", sample_agga_hyper_detail_hybrid, ["agga_hyper_detail_hybrid"]),
50
+ ("AGGA Style-Repair (Test)", sample_agga_style_repair_pro, ["agga_sr"]),
51
+ ("AGGA Style-Repair (Prompt-Aware)", sample_agga_style_repair_prompt_aware, ["agga_sr_prompt"]),
52
+ ("AGGA Style-Repair Ultra", sample_agga_style_repair_ultra, ["agga_sru"]),
53
+ ("AGGA PDXL-Lora Adapted", sample_agga_lora_bridge, ["agga_LA"]),
54
+ ("AGGA PDXL-Lora Adapted Stable", sample_agga_lora_bridge_stable, ["agga_LAS"]),
55
+ ("AGGA PDXL-Lora Adapted Sharp", sample_agga_lora_bridge_sharp, ["agga_LA_Sharp"]),
56
+ ("AGGA PDXL-Lora Adapted Ultra-Sharp", sample_agga_lora_bridge_ultra_sharp, ["agga_LA_US"]),
57
+ ("AGGA Lora universal Bridge", sample_agga_universal_bridge, ["agga_L_UB"]),
58
+ ("AGGA Pixel-Master (Test)", sample_agga_pixel_master, ["agga_pixel"]),
59
+ ]
60
+
61
+ # =========================================================
62
+ # BUCLE DE REGISTRO AUTOMÁTICO
63
+ # =========================================================
64
+ for name, func, aliases in agga_samplers_config:
65
+ if name not in existing:
66
+ # Creamos el objeto Data
67
+ # 'f=func' es vital para capturar el valor actual del bucle en la lambda
68
+ s_data = sd_samplers_common.SamplerData(
69
+ name,
70
+ lambda model, f=func: KDiffusionSampler(f, model),
71
+ aliases=aliases,
72
+ options={}
73
+ )
74
+
75
+ # Inyectamos en la lista oficial de A1111
76
+ samplers_data_k_diffusion.append(s_data)
77
+ count += 1
78
+
79
+ print(f"[AGGA Module] {count} Samplers registered successfully.")
80
+
81
+ register()