perf: reduce prompt relay and audio ui overhead
This commit is contained in:
@@ -1,7 +1,15 @@
|
|||||||
import folder_paths
|
import folder_paths
|
||||||
import os
|
import numpy as np
|
||||||
import torch
|
import os
|
||||||
import av
|
import torch
|
||||||
|
import av
|
||||||
|
|
||||||
|
DEFAULT_SAMPLE_RATE = 44100
|
||||||
|
DEFAULT_SILENCE_SECONDS = 1
|
||||||
|
|
||||||
|
|
||||||
|
def build_silence(sample_rate: int = DEFAULT_SAMPLE_RATE, seconds: int = DEFAULT_SILENCE_SECONDS, channels: int = 2) -> torch.Tensor:
|
||||||
|
return torch.zeros((channels, int(sample_rate * seconds)), dtype=torch.float32)
|
||||||
|
|
||||||
def f32_pcm(wav: torch.Tensor) -> torch.Tensor:
|
def f32_pcm(wav: torch.Tensor) -> torch.Tensor:
|
||||||
"""Convert audio to float 32 bits PCM format."""
|
"""Convert audio to float 32 bits PCM format."""
|
||||||
@@ -13,30 +21,29 @@ def f32_pcm(wav: torch.Tensor) -> torch.Tensor:
|
|||||||
return wav.float() / (2 ** 31)
|
return wav.float() / (2 ** 31)
|
||||||
raise ValueError(f"Unsupported wav dtype: {wav.dtype}")
|
raise ValueError(f"Unsupported wav dtype: {wav.dtype}")
|
||||||
|
|
||||||
def load_audio_file(filepath: str) -> tuple[torch.Tensor, int]:
|
def load_audio_file(filepath: str) -> tuple[torch.Tensor, int]:
|
||||||
"""Uses the latest ComfyUI av-based decoding for maximum compatibility."""
|
"""Uses the latest ComfyUI av-based decoding for maximum compatibility."""
|
||||||
with av.open(filepath) as af:
|
with av.open(filepath) as af:
|
||||||
if not af.streams.audio:
|
if not af.streams.audio:
|
||||||
raise ValueError("No audio stream found in the file.")
|
raise ValueError("No audio stream found in the file.")
|
||||||
|
|
||||||
stream = af.streams.audio[0]
|
stream = af.streams.audio[0]
|
||||||
sr = stream.codec_context.sample_rate
|
sr = stream.codec_context.sample_rate
|
||||||
n_channels = stream.channels
|
n_channels = stream.channels
|
||||||
|
|
||||||
frames = []
|
frame_arrays = []
|
||||||
for frame in af.decode(streams=stream.index):
|
for frame in af.decode(streams=stream.index):
|
||||||
buf = torch.from_numpy(frame.to_ndarray())
|
array = frame.to_ndarray()
|
||||||
if buf.shape[0] != n_channels:
|
if array.shape[0] != n_channels:
|
||||||
buf = buf.view(-1, n_channels).t()
|
array = array.reshape(-1, n_channels).T
|
||||||
|
frame_arrays.append(array)
|
||||||
frames.append(buf)
|
|
||||||
|
if not frame_arrays:
|
||||||
if not frames:
|
raise ValueError("No audio frames decoded.")
|
||||||
raise ValueError("No audio frames decoded.")
|
|
||||||
|
wav = torch.from_numpy(np.concatenate(frame_arrays, axis=1))
|
||||||
wav = torch.cat(frames, dim=1)
|
wav = f32_pcm(wav)
|
||||||
wav = f32_pcm(wav)
|
return wav, sr
|
||||||
return wav, sr
|
|
||||||
|
|
||||||
|
|
||||||
class LoadAudioUI:
|
class LoadAudioUI:
|
||||||
@@ -95,21 +102,20 @@ class LoadAudioUI:
|
|||||||
|
|
||||||
# --- FALLBACK LOGIC ---
|
# --- FALLBACK LOGIC ---
|
||||||
# If the file is 'none' or doesn't exist on disk, provide 1 second of silence
|
# If the file is 'none' or doesn't exist on disk, provide 1 second of silence
|
||||||
if audio == "none" or not audio_path or not os.path.exists(audio_path):
|
if audio == "none" or not audio_path or not os.path.exists(audio_path):
|
||||||
missing_info = audio if audio != "none" else "None selected"
|
missing_info = audio if audio != "none" else "None selected"
|
||||||
print(f"!!! [LoadAudioUI] Warning: Audio file '{missing_info}' not found. Outputting 1 second of silence.")
|
print(f"!!! [LoadAudioUI] Warning: Audio file '{missing_info}' not found. Outputting 1 second of silence.")
|
||||||
|
|
||||||
sample_rate = 44100
|
sample_rate = DEFAULT_SAMPLE_RATE
|
||||||
# 1 second of silence (stereo) -> shape [channels, time]
|
waveform = build_silence(sample_rate)
|
||||||
waveform = torch.zeros((2, 44100))
|
else:
|
||||||
else:
|
try:
|
||||||
try:
|
waveform, sample_rate = load_audio_file(audio_path)
|
||||||
waveform, sample_rate = load_audio_file(audio_path)
|
except Exception as e:
|
||||||
except Exception as e:
|
# If decoding fails for any reason, fallback to silence rather than crashing the workflow
|
||||||
# If decoding fails for any reason, fallback to silence rather than crashing the workflow
|
print(f"!!! [LoadAudioUI] Error decoding {audio}: {e}. Falling back to silence.")
|
||||||
print(f"!!! [LoadAudioUI] Error decoding {audio}: {e}. Falling back to silence.")
|
sample_rate = DEFAULT_SAMPLE_RATE
|
||||||
sample_rate = 44100
|
waveform = build_silence(sample_rate)
|
||||||
waveform = torch.zeros((2, 44100))
|
|
||||||
|
|
||||||
# Convert seconds to frames
|
# Convert seconds to frames
|
||||||
start_frame = int(start_time * sample_rate)
|
start_frame = int(start_time * sample_rate)
|
||||||
@@ -138,4 +144,4 @@ class LoadAudioUI:
|
|||||||
# Calculate the final trimmed duration in seconds as a float
|
# Calculate the final trimmed duration in seconds as a float
|
||||||
final_duration = float(trimmed_waveform.shape[1] / sample_rate)
|
final_duration = float(trimmed_waveform.shape[1] / sample_rate)
|
||||||
|
|
||||||
return (audio_output, final_duration)
|
return (audio_output, final_duration)
|
||||||
|
|||||||
31
patches.py
31
patches.py
@@ -1,9 +1,12 @@
|
|||||||
import logging
|
import logging
|
||||||
import types
|
import os
|
||||||
|
import types
|
||||||
import comfy.ldm.modules.attention
|
|
||||||
|
import comfy.ldm.modules.attention
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
_DEBUG_PROMPT_RELAY = os.environ.get("PROMPT_RELAY_DEBUG", "").strip().lower() in {"1", "true", "yes", "on"}
|
||||||
|
_DEBUG_LOG_PATH = os.path.join(os.path.dirname(__file__), "debug_prompt_relay.log")
|
||||||
|
|
||||||
|
|
||||||
def _masked_attention(q, k, v, heads, mask, transformer_options={}, **kwargs):
|
def _masked_attention(q, k, v, heads, mask, transformer_options={}, **kwargs):
|
||||||
@@ -72,14 +75,14 @@ def _make_masked_override(prev_override):
|
|||||||
return override
|
return override
|
||||||
|
|
||||||
|
|
||||||
def debug_log(msg):
|
def debug_log(msg):
|
||||||
try:
|
if not _DEBUG_PROMPT_RELAY:
|
||||||
import os
|
return
|
||||||
log_path = os.path.join(os.path.dirname(__file__), "debug_prompt_relay.log")
|
try:
|
||||||
with open(log_path, "a", encoding="utf-8") as f:
|
with open(_DEBUG_LOG_PATH, "a", encoding="utf-8") as f:
|
||||||
f.write(msg + "\n")
|
f.write(msg + "\n")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _make_ltx_mask_wrapper(underlying, mask_fn, attr):
|
def _make_ltx_mask_wrapper(underlying, mask_fn, attr):
|
||||||
|
|||||||
Reference in New Issue
Block a user