Guest User

advanced.py

a guest
Mar 29th, 2026
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.50 KB | Source Code | 0 0
  1. """Advanced node variants with full parameter control and hi-res pipeline.
  2.  
  3. Stage 1+2 run at reduced spatial resolution for speed,
  4. latent upscale, then Stage 3 at full resolution.
  5. """
  6.  
  7. from __future__ import annotations
  8.  
  9. import logging
  10. from pathlib import Path
  11. from typing import Any
  12.  
  13. import comfy.model_management
  14. import comfy.samplers
  15. import comfy.utils
  16. import torch
  17.  
  18. from triple_ksampler.base import TripleKSamplerBase
  19. from triple_ksampler.shared import alignment as core_alignment
  20. from triple_ksampler.shared import config as core_config
  21. from triple_ksampler.shared import models as core_models
  22. from triple_ksampler.shared import notifications as core_notifications
  23.  
  24. _CONFIG = core_config.load_config(config_dir=Path(__file__).resolve().parent.parent.parent)
  25. _BASE_QUALITY_THRESHOLD = core_config.get_base_quality_threshold(_CONFIG)
  26. _LOG_LEVEL = core_config.get_log_level(_CONFIG)
  27.  
  28. logger = logging.getLogger("triple_ksampler.ksampler.advanced")
  29. bare_logger = logging.getLogger("triple_ksampler.separator")
  30.  
  31. STAGE3_SEED_OFFSET = 1
  32. UPSCALE_METHODS = ["nearest-exact", "bilinear", "area", "bislerp"]
  33.  
  34. # WanVideo VAE spatial compression factor (pixels / latent)
  35. VAE_SPATIAL_FACTOR = 8
  36.  
  37.  
  38. def _downscale_latent(
  39. latent: dict[str, torch.Tensor], scale_factor: float
  40. ) -> dict[str, torch.Tensor]:
  41. """Downscale video latent [B, C, T, H, W] spatially by scale_factor."""
  42. samples = latent["samples"]
  43.  
  44. if scale_factor <= 1.0:
  45. return {"samples": samples.clone()}
  46.  
  47. b, c, t, h, w = samples.shape
  48. new_h = max(1, round(h / scale_factor))
  49. new_w = max(1, round(w / scale_factor))
  50.  
  51. reshaped = samples.permute(0, 2, 1, 3, 4).reshape(b * t, c, h, w)
  52. scaled = torch.nn.functional.interpolate(
  53. reshaped, size=(new_h, new_w), mode="bilinear", align_corners=False
  54. )
  55. result = scaled.reshape(b, t, c, new_h, new_w).permute(0, 2, 1, 3, 4)
  56.  
  57. return {"samples": result}
  58.  
  59.  
  60. def _upscale_latent(
  61. latent: dict[str, torch.Tensor],
  62. target_h: int,
  63. target_w: int,
  64. method: str = "bislerp",
  65. ) -> dict[str, torch.Tensor]:
  66. """Upscale video latent [B, C, T, H, W] to target spatial dimensions."""
  67. samples = latent["samples"]
  68. b, c, t, h, w = samples.shape
  69.  
  70. if h == target_h and w == target_w:
  71. return {"samples": samples.clone()}
  72.  
  73. reshaped = samples.permute(0, 2, 1, 3, 4).reshape(b * t, c, h, w)
  74. scaled = comfy.utils.common_upscale(reshaped, target_w, target_h, method, "disabled")
  75. result = scaled.reshape(b, t, c, target_h, target_w).permute(0, 2, 1, 3, 4)
  76.  
  77. return {"samples": result}
  78.  
  79.  
  80. class TripleKSamplerAdvancedAlt(TripleKSamplerBase):
  81. """Advanced triple-stage sampler with hi-res pipeline. Static UI."""
  82.  
  83. @classmethod
  84. def INPUT_TYPES(cls) -> dict[str, dict[str, Any]]:
  85. base_inputs = cls._get_base_input_types()
  86.  
  87. return {
  88. "required": {
  89. "base_high": base_inputs["base_high"],
  90. "lightning_high": base_inputs["lightning_high"],
  91. "lightning_low": base_inputs["lightning_low"],
  92. "positive": base_inputs["positive"],
  93. "negative": base_inputs["negative"],
  94. "latent_image": base_inputs["latent_image"],
  95. "seed": base_inputs["seed"],
  96. "sigma_shift": base_inputs["sigma_shift"],
  97. "base_quality_threshold": (
  98. "INT",
  99. {
  100. "default": core_config.DEFAULT_BASE_QUALITY_THRESHOLD,
  101. "min": 1,
  102. "max": 100,
  103. "step": 1,
  104. "tooltip": (
  105. "Minimum total steps for base_steps auto-calculation "
  106. f"(config default: {_BASE_QUALITY_THRESHOLD}). "
  107. "Only applies when base_steps=-1."
  108. ),
  109. },
  110. ),
  111. "base_steps": (
  112. "INT",
  113. {
  114. "default": -1,
  115. "min": -1,
  116. "max": 100,
  117. "tooltip": (
  118. "Stage 1 steps for base high-noise model. "
  119. "Use -1 for auto-calculation."
  120. ),
  121. },
  122. ),
  123. "base_cfg": base_inputs["base_cfg"],
  124. "base_sampler": (
  125. comfy.samplers.KSampler.SAMPLERS,
  126. {"tooltip": "Sampler for Stage 1 (base model)."},
  127. ),
  128. "base_scheduler": (
  129. comfy.samplers.KSampler.SCHEDULERS,
  130. {"tooltip": "Scheduler for Stage 1 (base model)."},
  131. ),
  132. "lightning_start": (
  133. "INT",
  134. {
  135. "default": 1,
  136. "min": 0,
  137. "max": 99,
  138. "tooltip": (
  139. "Starting step within lightning schedule. "
  140. "Set to 0 to skip Stage 1."
  141. ),
  142. },
  143. ),
  144. "lightning_steps": base_inputs["lightning_steps"],
  145. "lightning_cfg": (
  146. "FLOAT",
  147. {
  148. "default": 1.0,
  149. "min": 0.0,
  150. "max": 100.0,
  151. "step": 0.1,
  152. "tooltip": "CFG scale for Stage 2 and Stage 3.",
  153. },
  154. ),
  155. "lightning_sampler": (
  156. comfy.samplers.KSampler.SAMPLERS,
  157. {"tooltip": "Sampler for Stage 2 and Stage 3."},
  158. ),
  159. "lightning_scheduler": (
  160. comfy.samplers.KSampler.SCHEDULERS,
  161. {"tooltip": "Scheduler for Stage 2 and Stage 3."},
  162. ),
  163. "switch_strategy": (
  164. [
  165. "50% of steps",
  166. "Manual switch step",
  167. "T2V boundary",
  168. "I2V boundary",
  169. "Manual boundary",
  170. "T2V boundary (refined)",
  171. "I2V boundary (refined)",
  172. "Manual boundary (refined)",
  173. ],
  174. {
  175. "default": "50% of steps",
  176. "tooltip": (
  177. "Strategy for switching between models. "
  178. "Refined variants auto-tune sigma_shift."
  179. ),
  180. },
  181. ),
  182. "switch_step": (
  183. "INT",
  184. {
  185. "default": -1,
  186. "min": -1,
  187. "max": 99,
  188. "tooltip": (
  189. "Manual switch step. Only for 'Manual switch step' strategy. "
  190. "-1 = auto at 50%."
  191. ),
  192. },
  193. ),
  194. "switch_boundary": (
  195. "FLOAT",
  196. {
  197. "default": 0.875,
  198. "min": 0.0,
  199. "max": 1.0,
  200. "step": 0.001,
  201. "tooltip": "Sigma boundary. Only for 'Manual boundary' strategy.",
  202. },
  203. ),
  204. "hr_scale_factor": (
  205. "FLOAT",
  206. {
  207. "default": 2.0,
  208. "min": 1.0,
  209. "max": 8.0,
  210. "step": 0.25,
  211. "tooltip": (
  212. "Spatial downscale factor for Stage 1+2. "
  213. "2.0 = half pixel resolution. 1.0 = disabled."
  214. ),
  215. },
  216. ),
  217. "hr_upscale_method": (
  218. UPSCALE_METHODS,
  219. {
  220. "default": "bislerp",
  221. "tooltip": "Latent upscale method between Stage 2 and Stage 3.",
  222. },
  223. ),
  224. "dry_run": (
  225. "BOOLEAN",
  226. {
  227. "default": False,
  228. "tooltip": "Test stage calculations without sampling.",
  229. },
  230. ),
  231. },
  232. }
  233.  
  234. RETURN_TYPES = ("LATENT",)
  235. RETURN_NAMES = ("samples",)
  236. FUNCTION = "sample"
  237. CATEGORY = "TripleKSampler"
  238. DESCRIPTION = (
  239. "Advanced triple-stage cascade sampler with hi-res pipeline. "
  240. "Stage 1+2 at reduced resolution, upscale, Stage 3 at full resolution."
  241. )
  242.  
  243. def sample(
  244. self,
  245. base_high: Any,
  246. lightning_high: Any,
  247. lightning_low: Any,
  248. positive: Any,
  249. negative: Any,
  250. latent_image: dict[str, torch.Tensor],
  251. seed: int,
  252. sigma_shift: float,
  253. base_quality_threshold: int,
  254. base_steps: int,
  255. base_cfg: float,
  256. base_sampler: str,
  257. base_scheduler: str,
  258. lightning_start: int,
  259. lightning_steps: int,
  260. lightning_cfg: float,
  261. lightning_sampler: str,
  262. lightning_scheduler: str,
  263. switch_strategy: str,
  264. switch_step: int = -1,
  265. switch_boundary: float = 0.875,
  266. hr_scale_factor: float = 2.0,
  267. hr_upscale_method: str = "bislerp",
  268. dry_run: bool = False,
  269. ) -> tuple[dict[str, torch.Tensor], ...]:
  270. """Execute 4-phase pipeline with hi-res upscale."""
  271.  
  272. if str(_LOG_LEVEL).upper() == "DEBUG":
  273. bare_logger.info("")
  274. logger.debug("=== TripleKSampler Advanced - Input Parameters ===")
  275. logger.debug("seed=%d, sigma_shift=%.3f", seed, sigma_shift)
  276. logger.debug(
  277. "base: threshold=%d, steps=%d, cfg=%.1f, sampler=%s, scheduler=%s",
  278. base_quality_threshold, base_steps, base_cfg, base_sampler, base_scheduler,
  279. )
  280. logger.debug(
  281. "lightning: start=%d, steps=%d, cfg=%.1f, sampler=%s, scheduler=%s",
  282. lightning_start, lightning_steps, lightning_cfg,
  283. lightning_sampler, lightning_scheduler,
  284. )
  285. logger.debug(
  286. "strategy=%s, switch_step=%d, switch_boundary=%.3f",
  287. switch_strategy, switch_step, switch_boundary,
  288. )
  289. logger.debug(
  290. "hr: scale=%.2f, method=%s, dry_run=%s",
  291. hr_scale_factor, hr_upscale_method, dry_run,
  292. )
  293.  
  294. base_calculation_info = ""
  295. model_switching_info = ""
  296. hr_enabled = hr_scale_factor > 1.0
  297.  
  298. # === Validation ===
  299. self._validate_basic_parameters(
  300. lightning_steps, lightning_start, switch_strategy, switch_step
  301. )
  302.  
  303. bare_logger.info("")
  304.  
  305. # === Calculate base_steps alignment ===
  306. optimal_total_base_steps = None
  307. if base_steps == -1:
  308. base_steps, optimal_total_base_steps, method = self._calculate_perfect_alignment(
  309. base_quality_threshold, lightning_start, lightning_steps
  310. )
  311. if lightning_start > 0:
  312. if method in ("mathematical_search", "simple_math"):
  313. base_calculation_info = (
  314. f"Auto-calculated base_steps = {base_steps}, "
  315. f"total_base_steps = {optimal_total_base_steps} "
  316. f"({method.replace('_', ' ')})"
  317. )
  318. else:
  319. base_calculation_info = (
  320. f"Auto-calculated base_steps = {base_steps} "
  321. f"(fallback - no perfect alignment found)"
  322. )
  323. logger.info(base_calculation_info)
  324. else:
  325. optimal_total_base_steps = core_alignment.calculate_manual_base_steps_alignment(
  326. base_steps, lightning_start, lightning_steps
  327. )
  328. base_calculation_info = (
  329. f"Auto-calculated total_base_steps = {optimal_total_base_steps} "
  330. f"for manual base_steps = {base_steps}"
  331. )
  332. logger.info(base_calculation_info)
  333.  
  334. if lightning_start > 0 and base_steps > 0 and optimal_total_base_steps > 0:
  335. stage1_end_pct = base_steps / optimal_total_base_steps
  336. stage2_start_pct = lightning_start / lightning_steps
  337. if stage1_end_pct > stage2_start_pct:
  338. overlap_pct = (stage1_end_pct - stage2_start_pct) * 100.0
  339. logger.warning(
  340. "Stage 1 and 2 overlap (%.1f%%)!", overlap_pct,
  341. )
  342. core_notifications.send_overlap_warning(overlap_pct)
  343.  
  344. total_base_steps = optimal_total_base_steps or base_steps
  345.  
  346. # === Post-calculation validation ===
  347. self._validate_resolved_parameters(lightning_start, base_steps)
  348. self._validate_special_modes(
  349. lightning_start, lightning_steps, base_steps, switch_strategy, switch_step
  350. )
  351.  
  352. # === Patch models ===
  353. patched_base_high, patched_lightning_high, patched_lightning_low = (
  354. self._patch_models_for_sampling(base_high, lightning_high, lightning_low, sigma_shift)
  355. )
  356.  
  357. # === Calculate switch point ===
  358. switch_step_final, _, model_switching_info = self._calculate_switch_step_and_strategy(
  359. switch_strategy, switch_step, switch_boundary,
  360. lightning_steps, patched_lightning_high, lightning_scheduler,
  361. )
  362.  
  363. # === Sigma shift refinement ===
  364. sigma_shift_final = sigma_shift
  365.  
  366. if self._is_refined_strategy(switch_strategy):
  367. try:
  368. target_boundary = self._get_target_boundary_from_strategy(
  369. switch_strategy, switch_boundary
  370. )
  371. refined_shift, refine_msg = core_models.calculate_perfect_shift_for_step(
  372. model=lightning_high,
  373. scheduler=lightning_scheduler,
  374. total_steps=lightning_steps,
  375. target_step=switch_step_final,
  376. target_sigma=target_boundary,
  377. initial_shift=sigma_shift,
  378. is_wanvideo=False,
  379. )
  380. logger.info(
  381. "Refined sigma_shift: %.2f → %.2f at step %d",
  382. sigma_shift, refined_shift, switch_step_final,
  383. )
  384. sigma_shift_final = refined_shift
  385. model_switching_info += (
  386. f" [Refined shift: {sigma_shift:.2f}→{refined_shift:.2f}]"
  387. )
  388. except Exception as e:
  389. logger.warning("Shift refinement failed: %s. Using %.2f", e, sigma_shift)
  390.  
  391. if sigma_shift_final != sigma_shift:
  392. patched_base_high, patched_lightning_high, patched_lightning_low = (
  393. self._patch_models_for_sampling(
  394. base_high, lightning_high, lightning_low, sigma_shift_final
  395. )
  396. )
  397.  
  398. logger.info(model_switching_info)
  399.  
  400. # === Resolve spatial dimensions ===
  401. orig_samples = latent_image["samples"] # [B, C, T, H, W]
  402. orig_h, orig_w = orig_samples.shape[3], orig_samples.shape[4]
  403. orig_px_h = orig_h * VAE_SPATIAL_FACTOR
  404. orig_px_w = orig_w * VAE_SPATIAL_FACTOR
  405.  
  406. if hr_enabled:
  407. lr_h = max(1, round(orig_h / hr_scale_factor))
  408. lr_w = max(1, round(orig_w / hr_scale_factor))
  409. lr_px_h = lr_h * VAE_SPATIAL_FACTOR
  410. lr_px_w = lr_w * VAE_SPATIAL_FACTOR
  411. logger.info(
  412. "Hi-res pipeline: Stage 1+2 at %dx%d px (latent %dx%d) "
  413. "→ upscale (%s) → Stage 3 at %dx%d px (latent %dx%d)",
  414. lr_px_w, lr_px_h, lr_w, lr_h,
  415. hr_upscale_method,
  416. orig_px_w, orig_px_h, orig_w, orig_h,
  417. )
  418. else:
  419. lr_h, lr_w = orig_h, orig_w
  420. lr_px_h, lr_px_w = orig_px_h, orig_px_w
  421. logger.info("Hi-res pipeline: disabled (scale_factor=1.0)")
  422.  
  423. # === Execution flags ===
  424. skip_stage1 = lightning_start == 0
  425. skip_stage2 = lightning_start == switch_step_final
  426.  
  427. if not skip_stage1 and lightning_start > switch_step_final:
  428. raise ValueError("lightning_start cannot be greater than switch_step.")
  429.  
  430. # === Prepare low-res latent ===
  431. if hr_enabled:
  432. lr_latent = _downscale_latent(latent_image, hr_scale_factor)
  433. else:
  434. lr_latent = latent_image
  435.  
  436. # ================================================================
  437. # STAGE 1: Base high-noise model (low resolution)
  438. # ================================================================
  439. if skip_stage1:
  440. bare_logger.info("")
  441. logger.info("Stage 1: Skipped (Lightning-only mode)")
  442. stage1_info = "Skipped (Lightning-only mode)"
  443. stage1_output = lr_latent
  444. else:
  445. lr_tag = f" [{lr_px_w}×{lr_px_h} px]" if hr_enabled else ""
  446. stage1_info = (
  447. self._format_stage_range(0, base_steps, total_base_steps) + lr_tag
  448. )
  449. stage1_result = self._run_sampling_stage(
  450. model=patched_base_high,
  451. positive=positive,
  452. negative=negative,
  453. latent=lr_latent,
  454. seed=seed,
  455. steps=total_base_steps,
  456. cfg=base_cfg,
  457. sampler_name=base_sampler,
  458. scheduler=base_scheduler,
  459. start_at_step=0,
  460. end_at_step=base_steps,
  461. add_noise=True,
  462. return_with_leftover_noise=True,
  463. dry_run=dry_run,
  464. stage_name="Stage 1",
  465. stage_info=stage1_info,
  466. )
  467. stage1_output = stage1_result[0]
  468.  
  469. # ================================================================
  470. # STAGE 2: Lightning high-noise model (low resolution)
  471. # When hr_enabled: return clean signal (no leftover noise)
  472. # so we upscale clean data, Stage 3 adds fresh noise.
  473. # ================================================================
  474. if skip_stage2:
  475. bare_logger.info("")
  476. logger.info("Stage 2: Skipped (lightning_start == switch point)")
  477. stage2_info = "Skipped (lightning_start == switch point)"
  478. stage2_output = stage1_output
  479. else:
  480. lr_tag = f" [{lr_px_w}×{lr_px_h} px]" if hr_enabled else ""
  481. stage2_info = (
  482. self._format_stage_range(
  483. lightning_start, switch_step_final, lightning_steps
  484. ) + lr_tag
  485. )
  486. stage2_result = self._run_sampling_stage(
  487. model=patched_lightning_high,
  488. positive=positive,
  489. negative=negative,
  490. latent=stage1_output,
  491. seed=seed,
  492. steps=lightning_steps,
  493. cfg=lightning_cfg,
  494. sampler_name=lightning_sampler,
  495. scheduler=lightning_scheduler,
  496. start_at_step=lightning_start,
  497. end_at_step=switch_step_final,
  498. add_noise=skip_stage1,
  499. return_with_leftover_noise=not hr_enabled,
  500. dry_run=dry_run,
  501. stage_name="Stage 2",
  502. stage_info=stage2_info,
  503. )
  504. stage2_output = stage2_result[0]
  505.  
  506. # ================================================================
  507. # LATENT UPSCALE
  508. # ================================================================
  509. if hr_enabled:
  510. bare_logger.info("")
  511. if dry_run:
  512. logger.info(
  513. "Latent Upscale: %dx%d px → %dx%d px (%s) [DRY RUN]",
  514. lr_px_w, lr_px_h, orig_px_w, orig_px_h, hr_upscale_method,
  515. )
  516. stage3_input = stage2_output
  517. else:
  518. stage3_input = _upscale_latent(
  519. stage2_output, orig_h, orig_w, hr_upscale_method
  520. )
  521. logger.info(
  522. "Latent Upscale: %dx%d px → %dx%d px (%s)",
  523. lr_px_w, lr_px_h, orig_px_w, orig_px_h, hr_upscale_method,
  524. )
  525. else:
  526. stage3_input = stage2_output
  527.  
  528. upscale_info = ""
  529. if hr_enabled:
  530. upscale_info = (
  531. f"Latent Upscale: {lr_px_w}×{lr_px_h} px → "
  532. f"{orig_px_w}×{orig_px_h} px ({hr_upscale_method})"
  533. )
  534.  
  535. # ================================================================
  536. # STAGE 3: Lightning low-noise model (full resolution)
  537. # When hr_enabled: add_noise=True because Stage 2 returned
  538. # fully denoised signal. Stage 3 injects fresh noise at the
  539. # correct sigma level for full resolution.
  540. # ================================================================
  541. stage3_start = max(lightning_start, switch_step_final)
  542.  
  543. if hr_enabled:
  544. stage3_add_noise = True
  545. else:
  546. stage3_add_noise = skip_stage1 and skip_stage2
  547.  
  548. hr_tag = f" [{orig_px_w}×{orig_px_h} px]" if hr_enabled else ""
  549. stage3_info = (
  550. self._format_stage_range(stage3_start, lightning_steps, lightning_steps)
  551. + hr_tag
  552. )
  553.  
  554. stage3_result = self._run_sampling_stage(
  555. model=patched_lightning_low,
  556. positive=positive,
  557. negative=negative,
  558. latent=stage3_input,
  559. seed=seed + STAGE3_SEED_OFFSET,
  560. steps=lightning_steps,
  561. cfg=lightning_cfg,
  562. sampler_name=lightning_sampler,
  563. scheduler=lightning_scheduler,
  564. start_at_step=stage3_start,
  565. end_at_step=lightning_steps,
  566. add_noise=stage3_add_noise,
  567. return_with_leftover_noise=False,
  568. dry_run=dry_run,
  569. stage_name="Stage 3",
  570. stage_info=stage3_info,
  571. )
  572.  
  573. bare_logger.info("")
  574.  
  575. # === Dry run notification ===
  576. if dry_run:
  577. summary_lines = []
  578.  
  579. has_base_calc = not skip_stage1 and base_calculation_info
  580. if has_base_calc or model_switching_info:
  581. summary_lines.append("Calculations:")
  582. if has_base_calc:
  583. formatted = self._format_base_calculation_compact(base_calculation_info)
  584. summary_lines.append(f"• {formatted}")
  585. if model_switching_info:
  586. formatted = self._format_switch_info_compact(model_switching_info)
  587. summary_lines.append(f"• {formatted}")
  588. summary_lines.append("")
  589.  
  590. summary_lines.append("Stage Configuration:")
  591. summary_lines.append(f"• Stage 1: {stage1_info}")
  592. summary_lines.append(f"• Stage 2: {stage2_info}")
  593. if upscale_info:
  594. summary_lines.append(f"• {upscale_info}")
  595. summary_lines.append(f"• Stage 3: {stage3_info}")
  596.  
  597. if hr_enabled:
  598. summary_lines.append("")
  599. summary_lines.append(
  600. "Note: Stage 3 uses add_noise=True (fresh noise at full resolution)"
  601. )
  602.  
  603. detail_text = "\n".join(summary_lines)
  604. core_notifications.send_dry_run_notification(detail_text)
  605.  
  606. logger.info("[DRY RUN] Complete - interrupting workflow")
  607. bare_logger.info("")
  608. raise comfy.model_management.InterruptProcessingException()
  609.  
  610. return stage3_result
  611.  
  612.  
  613. class TripleKSamplerAdvanced(TripleKSamplerAdvancedAlt):
  614. """Advanced triple-stage sampler with dynamic UI."""
  615.  
  616. @classmethod
  617. def INPUT_TYPES(cls) -> dict[str, dict[str, Any]]:
  618. base_inputs = cls._get_base_input_types()
  619.  
  620. return {
  621. "required": {
  622. "base_high": base_inputs["base_high"],
  623. "lightning_high": base_inputs["lightning_high"],
  624. "lightning_low": base_inputs["lightning_low"],
  625. "positive": base_inputs["positive"],
  626. "negative": base_inputs["negative"],
  627. "latent_image": base_inputs["latent_image"],
  628. "seed": base_inputs["seed"],
  629. "sigma_shift": base_inputs["sigma_shift"],
  630. "base_quality_threshold": (
  631. "INT",
  632. {
  633. "default": core_config.DEFAULT_BASE_QUALITY_THRESHOLD,
  634. "min": 1,
  635. "max": 100,
  636. "step": 1,
  637. "tooltip": (
  638. "Minimum total steps for base_steps auto-calculation "
  639. f"(config default: {_BASE_QUALITY_THRESHOLD}). "
  640. "Only applies when base_steps=-1."
  641. ),
  642. },
  643. ),
  644. "base_steps": (
  645. "INT",
  646. {
  647. "default": -1,
  648. "min": -1,
  649. "max": 100,
  650. "tooltip": "Stage 1 steps. -1 = auto.",
  651. },
  652. ),
  653. "base_cfg": base_inputs["base_cfg"],
  654. "base_sampler": (
  655. comfy.samplers.KSampler.SAMPLERS,
  656. {"tooltip": "Sampler for Stage 1."},
  657. ),
  658. "base_scheduler": (
  659. comfy.samplers.KSampler.SCHEDULERS,
  660. {"tooltip": "Scheduler for Stage 1."},
  661. ),
  662. "lightning_start": (
  663. "INT",
  664. {
  665. "default": 1,
  666. "min": 0,
  667. "max": 99,
  668. "tooltip": "Starting step in lightning schedule. 0 = skip Stage 1.",
  669. },
  670. ),
  671. "lightning_steps": base_inputs["lightning_steps"],
  672. "lightning_cfg": (
  673. "FLOAT",
  674. {
  675. "default": 1.0,
  676. "min": 0.0,
  677. "max": 100.0,
  678. "step": 0.1,
  679. "tooltip": "CFG for Stage 2 and Stage 3.",
  680. },
  681. ),
  682. "lightning_sampler": (
  683. comfy.samplers.KSampler.SAMPLERS,
  684. {"tooltip": "Sampler for Stage 2 and Stage 3."},
  685. ),
  686. "lightning_scheduler": (
  687. comfy.samplers.KSampler.SCHEDULERS,
  688. {"tooltip": "Scheduler for Stage 2 and Stage 3."},
  689. ),
  690. "switch_strategy": (
  691. [
  692. "50% of steps",
  693. "Manual switch step",
  694. "T2V boundary",
  695. "I2V boundary",
  696. "Manual boundary",
  697. "T2V boundary (refined)",
  698. "I2V boundary (refined)",
  699. "Manual boundary (refined)",
  700. ],
  701. {"default": "50% of steps", "tooltip": "Model switching strategy."},
  702. ),
  703. "hr_scale_factor": (
  704. "FLOAT",
  705. {
  706. "default": 2.0,
  707. "min": 1.0,
  708. "max": 8.0,
  709. "step": 0.25,
  710. "tooltip": "Spatial downscale for Stage 1+2. 1.0 = disabled.",
  711. },
  712. ),
  713. "hr_upscale_method": (
  714. UPSCALE_METHODS,
  715. {
  716. "default": "bislerp",
  717. "tooltip": "Latent upscale method between Stage 2 and Stage 3.",
  718. },
  719. ),
  720. },
  721. "optional": {
  722. "switch_step": (
  723. "INT",
  724. {
  725. "default": -1,
  726. "min": -1,
  727. "max": 99,
  728. "tooltip": "Manual switch step. -1 = 50%.",
  729. },
  730. ),
  731. "switch_boundary": (
  732. "FLOAT",
  733. {
  734. "default": 0.875,
  735. "min": 0.0,
  736. "max": 1.0,
  737. "step": 0.001,
  738. "tooltip": "Sigma boundary for 'Manual boundary'.",
  739. },
  740. ),
  741. "dry_run": (
  742. "BOOLEAN",
  743. {
  744. "default": False,
  745. "tooltip": "Test calculations without sampling.",
  746. },
  747. ),
  748. },
  749. }
  750.  
  751. DESCRIPTION = (
  752. "Advanced triple-stage cascade sampler with hi-res pipeline and dynamic UI."
  753. )
  754.  
  755. # sample() inherited from TripleKSamplerAdvancedAlt
Advertisement
Add Comment
Please, Sign In to add comment