Switching audio upscaler to LavaSR

This commit is contained in:
Jonathan Thomas
2026-04-15 18:40:50 -05:00
parent d6536ce152
commit c6ed8d6756
5 changed files with 110 additions and 218 deletions
+11 -10
View File
@@ -28,7 +28,7 @@ This project addresses that gap with chunk-oriented processing designed specific
- `OpenShotGroundingDinoDetect` (text-prompted object detection -> mask + JSON)
- `OpenShotTransNetSceneDetect` (direct TransNetV2 inference -> IN/OUT JSON ranges)
- `OpenShotDeepFilterNetDenoiseAudio` (file-path based audio denoise -> FLAC path)
- `OpenShotAudioSRClarity` (isolated AudioSR runner -> FLAC path)
- `OpenShotLavaSRSpeechClarity` (isolated LavaSR speech runner -> FLAC path)
## Attribution
@@ -44,6 +44,7 @@ Please see upstream projects for full original implementations and credits.
- ComfyUI
- PyTorch (as used by your Comfy install)
- `ffmpeg` and `ffprobe` available on your `PATH`
- `git` available on your `PATH` for LavaSR's first-use isolated install
Install this node pack into `ComfyUI/custom_nodes/OpenShot-ComfyUI` and restart ComfyUI.
@@ -83,7 +84,7 @@ SAM2 is installed separately on purpose. Keeping it out of `requirements.txt` ma
- `OpenShotDownloadAndLoadSAM2Model` downloads supported SAM2 checkpoints into `ComfyUI/models/sam2` on first use.
- `OpenShotGroundingDinoDetect` downloads model weights from Hugging Face on first use and uses the normal HF cache.
- `OpenShotDeepFilterNetDenoiseAudio` downloads the default `DeepFilterNet3` model on first use using DeepFilterNet's cache directory.
- `OpenShotAudioSRClarity` creates an isolated local venv on first use, installs AudioSR there, and then downloads the selected AudioSR checkpoint from Hugging Face on first run.
- `OpenShotLavaSRSpeechClarity` creates an isolated local venv on first use, installs LavaSR there, and then downloads the `YatharthS/LavaSR` model snapshot from Hugging Face on first run.
- `OpenShotTransNetSceneDetect` does not require a separate manual weight download from this node pack.
## Audio denoise node
@@ -98,17 +99,17 @@ SAM2 is installed separately on purpose. Keeping it out of `requirements.txt` ma
The node accepts typical audio formats that `ffmpeg` can decode and always writes a new `.flac` file into ComfyUI's output folder under `openshot_audio/`.
## Audio clarity node
## Speech clarity node
`OpenShotAudioSRClarity` is intended for low-fidelity or bandwidth-limited audio:
`OpenShotLavaSRSpeechClarity` is intended for low-quality speech recordings:
- Input: `source_audio_path` or `audio`, `model_name`, `keep_model_loaded`
- Input: `source_audio_path` or `audio`, `keep_model_loaded`
- Output: a new FLAC file path
- `model_name=speech` is intended for spoken voice
- `model_name=basic` is intended for music and sound effects
- Uses LavaSR v2 speech enhancement
- Intended for speech/dialogue clarity, not general music restoration
AudioSR is intentionally not installed into the main Comfy environment because its package pins older `numpy`, `librosa`, and `transformers` versions. Instead, the node creates and uses an isolated runner environment on first use so the main Comfy environment stays stable.
That means there is no extra install command for AudioSR, but the first `Clarity` run will take longer while the isolated environment and model checkpoint are prepared.
LavaSR is installed into an isolated runner environment on first use so the main Comfy environment stays stable.
That means there is no extra install command for LavaSR, but the first `Clarity -> Speech` run will take longer while the isolated environment and model snapshot are prepared.
## Validation script
@@ -131,7 +132,7 @@ It checks:
- `OpenShotSam2VideoSegmentationChunked` returns only the requested chunk range (bounded memory) instead of collecting whole-video masks.
- For very long videos, pair chunked outputs with batch-safe downstream nodes (VHS meta-batch, staged processing, or on-disk intermediates).
- `torchaudio` is listed explicitly because DeepFilterNet imports it internally and some environments do not pull it in automatically.
- AudioSR uses a separate on-demand runner environment to avoid downgrading shared Comfy dependencies.
- LavaSR uses a separate on-demand runner environment and preserves the original channel count by processing each channel independently before recombining the output.
---
+22 -55
View File
@@ -4,28 +4,28 @@ import time
import venv
AUDIOSR_ENV_VERSION = "6"
LAVASR_ENV_VERSION = "1"
def _log(message):
print("[OpenShot-ComfyUI:AudioSR] {}".format(message), flush=True)
print("[OpenShot-ComfyUI:LavaSR] {}".format(message), flush=True)
def audiosr_env_dir(base_dir):
path = os.path.join(base_dir, ".openshot_envs", "audiosr")
def lavasr_env_dir(base_dir):
path = os.path.join(base_dir, ".openshot_envs", "lavasr")
os.makedirs(os.path.dirname(path), exist_ok=True)
return path
def audiosr_python_path(base_dir):
env_dir = audiosr_env_dir(base_dir)
def lavasr_python_path(base_dir):
env_dir = lavasr_env_dir(base_dir)
if os.name == "nt":
return os.path.join(env_dir, "Scripts", "python.exe")
return os.path.join(env_dir, "bin", "python")
def audiosr_runner_path(base_dir):
return os.path.join(base_dir, "audiosr_runner.py")
def lavasr_runner_path(base_dir):
return os.path.join(base_dir, "lavasr_runner.py")
def run_checked(cmd, error_prefix):
@@ -55,7 +55,7 @@ def run_checked(cmd, error_prefix):
raise RuntimeError("{}: {}".format(error_prefix, err))
def audiosr_env_needs_refresh(marker_path, python_path):
def lavasr_env_needs_refresh(marker_path, python_path):
if not os.path.isfile(marker_path) or not os.path.isfile(python_path):
return True
try:
@@ -63,16 +63,16 @@ def audiosr_env_needs_refresh(marker_path, python_path):
lines = [line.strip() for line in handle.readlines() if line.strip()]
except Exception:
return True
return (not lines) or lines[0] != AUDIOSR_ENV_VERSION
return (not lines) or lines[0] != LAVASR_ENV_VERSION
def ensure_audiosr_environment(base_dir):
env_dir = audiosr_env_dir(base_dir)
python_path = audiosr_python_path(base_dir)
def ensure_lavasr_environment(base_dir):
env_dir = lavasr_env_dir(base_dir)
python_path = lavasr_python_path(base_dir)
marker_path = os.path.join(env_dir, ".ready")
runner_path = audiosr_runner_path(base_dir)
runner_path = lavasr_runner_path(base_dir)
if not audiosr_env_needs_refresh(marker_path, python_path):
if not lavasr_env_needs_refresh(marker_path, python_path):
_log("Using existing isolated environment: {}".format(env_dir))
return python_path
@@ -86,8 +86,8 @@ def ensure_audiosr_environment(base_dir):
builder.create(env_dir)
_log("Bootstrapping pip/setuptools/wheel")
run_checked([python_path, "-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel"], "AudioSR pip bootstrap failed")
_log("Installing AudioSR core package")
run_checked([python_path, "-m", "pip", "install", "--upgrade", "pip", "setuptools", "wheel"], "LavaSR pip bootstrap failed")
_log("Installing LavaSR")
run_checked(
[
python_path,
@@ -95,50 +95,17 @@ def ensure_audiosr_environment(base_dir):
"pip",
"install",
"--upgrade",
"--no-deps",
"audiosr==0.0.7",
],
"AudioSR core package install failed",
)
_log("Installing AudioSR dependency stack")
run_checked(
[
python_path,
"-m",
"pip",
"install",
"--upgrade",
"numpy<=1.23.5",
"librosa==0.9.2",
"transformers==4.30.2",
"soundfile",
"phonemizer",
"torchlibrosa>=0.0.9",
"tqdm",
"progressbar",
"ipdb",
"dlinfo",
"segments",
"csvw",
"language-tags",
"ftfy",
"einops",
"pandas",
"unidecode",
"chardet",
"pyyaml",
"gradio",
"git+https://github.com/ysharma3501/LavaSR.git",
"huggingface-hub",
"scipy",
"timm",
],
"AudioSR dependency install failed",
"LavaSR dependency install failed",
)
with open(marker_path, "w", encoding="utf-8") as handle:
handle.write("{}\n".format(AUDIOSR_ENV_VERSION))
handle.write("{}\n".format(LAVASR_ENV_VERSION))
handle.write("{}\n".format(time.time()))
if not os.path.isfile(runner_path):
raise RuntimeError("AudioSR runner script not found: {}".format(runner_path))
raise RuntimeError("LavaSR runner script not found: {}".format(runner_path))
_log("Isolated environment ready")
return python_path
+40 -103
View File
@@ -2,7 +2,6 @@ import argparse
import json
import os
import subprocess
import sys
import tempfile
import wave
@@ -10,7 +9,7 @@ import numpy as np
def log(message):
print("[OpenShot-ComfyUI:AudioSR] {}".format(message), flush=True)
print("[OpenShot-ComfyUI:LavaSR] {}".format(message), flush=True)
def run_ffmpeg(args, error_prefix):
@@ -77,6 +76,8 @@ def load_pcm16_wav(path):
raise RuntimeError("Expected 16-bit PCM WAV, got sample width {}".format(sample_width))
raw = wav_file.readframes(frame_count)
audio = np.frombuffer(raw, dtype="<i2").astype(np.float32)
if channels <= 0:
raise RuntimeError("Invalid WAV channel count: {}".format(channels))
audio = audio.reshape(-1, channels).T
audio /= 32768.0
return audio, sample_rate
@@ -96,30 +97,7 @@ def save_pcm16_wav(path, audio, sample_rate):
def save_mono_pcm16_wav(path, audio, sample_rate):
audio = np.asarray(audio, dtype=np.float32).reshape(1, -1)
save_pcm16_wav(path, audio, sample_rate)
def patch_torchaudio_load():
import torch
import torchaudio
def _safe_load(path, *args, **kwargs):
audio_np, sample_rate = load_pcm16_wav(path)
waveform = torch.from_numpy(audio_np)
return waveform, sample_rate
torchaudio.load = _safe_load
def patch_strip_silence():
import audiosr.utils as audiosr_utils
def _no_strip(input_path, temp_path, save_path):
del input_path
os.replace(temp_path, save_path)
audiosr_utils.strip_silence = _no_strip
save_pcm16_wav(path, np.asarray(audio, dtype=np.float32).reshape(1, -1), sample_rate)
def is_cuda_oom(ex):
@@ -127,83 +105,53 @@ def is_cuda_oom(ex):
return "outofmemoryerror" in text or "out of memory" in text or "would exceed allowed memory" in text
def run_audiosr(build_model, super_resolution, source_wav, model_name, device_name):
log("Loading AudioSR model '{}' on {}".format(model_name, device_name))
model = build_model(model_name=model_name, device=device_name)
try:
log("Running AudioSR super resolution on {}".format(device_name))
waveform = super_resolution(
model,
source_wav,
seed=42,
guidance_scale=3.5,
ddim_steps=50,
latent_t_per_second=12.8,
)
return waveform
finally:
def safe_input_sr(source_sr):
source_sr = int(source_sr or 16000)
return max(8000, min(48000, source_sr))
def run_lavasr_channels(source_audio_np, source_sr, device_name, tmp_dir):
from LavaSR.model import LavaEnhance2
input_sr = safe_input_sr(source_sr)
log("Loading LavaSR speech model on {}".format(device_name))
lava_model = LavaEnhance2("YatharthS/LavaSR", device_name)
channel_outputs = []
for channel_index in range(int(source_audio_np.shape[0])):
log("Enhancing channel {}/{} on {}".format(channel_index + 1, int(source_audio_np.shape[0]), device_name))
channel_path = os.path.join(tmp_dir, "channel_{}.wav".format(channel_index))
save_mono_pcm16_wav(channel_path, source_audio_np[channel_index], int(source_sr))
channel_audio, _input_sr = lava_model.load_audio(channel_path, input_sr=input_sr)
output_audio = lava_model.enhance(channel_audio, denoise=False, batch=False).cpu().numpy().reshape(-1)
channel_outputs.append(output_audio.astype(np.float32))
max_len = max(int(ch.shape[0]) for ch in channel_outputs)
padded = []
for ch in channel_outputs:
if int(ch.shape[0]) < max_len:
ch = np.pad(ch, (0, max_len - int(ch.shape[0])), mode="edge")
padded.append(ch)
if device_name != "cpu":
try:
model.cpu()
except Exception:
pass
def normalize_audiosr_output(waveform):
out_np = np.asarray(waveform, dtype=np.float32)
if out_np.ndim == 3:
out_np = out_np[0]
if out_np.ndim == 1:
out_np = out_np.reshape(1, -1)
return out_np
def run_audiosr_with_model(model, super_resolution, source_wav, device_name):
log("Running AudioSR super resolution on {}".format(device_name))
return super_resolution(
model,
source_wav,
seed=42,
guidance_scale=3.5,
ddim_steps=50,
latent_t_per_second=12.8,
)
def run_audiosr_channels(build_model, super_resolution, source_audio_np, source_sr, model_name, device_name, tmp_dir):
log("Loading AudioSR model '{}' on {}".format(model_name, device_name))
model = build_model(model_name=model_name, device=device_name)
try:
channel_outputs = []
for channel_index in range(int(source_audio_np.shape[0])):
log("Enhancing channel {}/{} on {}".format(channel_index + 1, int(source_audio_np.shape[0]), device_name))
channel_path = os.path.join(tmp_dir, "channel_{}.wav".format(channel_index))
save_mono_pcm16_wav(channel_path, source_audio_np[channel_index], int(source_sr))
waveform = run_audiosr_with_model(model, super_resolution, channel_path, device_name)
channel_outputs.append(normalize_audiosr_output(waveform)[0])
return np.stack(channel_outputs, axis=0)
finally:
try:
model.cpu()
torch.cuda.empty_cache()
except Exception:
pass
return np.stack(padded, axis=0)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--input", required=True)
parser.add_argument("--output", required=True)
parser.add_argument("--model-name", required=True, choices=["basic", "speech"])
parser.add_argument("--release-model", action="store_true")
args = parser.parse_args()
import torch
input_path = os.path.abspath(args.input)
output_path = os.path.abspath(args.output)
os.makedirs(os.path.dirname(output_path), exist_ok=True)
source_info = probe_audio_info(input_path)
tmp_dir = tempfile.mkdtemp(prefix="openshot_audiosr_")
tmp_dir = tempfile.mkdtemp(prefix="openshot_lavasr_")
try:
source_wav = os.path.join(tmp_dir, "source.wav")
enhanced_wav = os.path.join(tmp_dir, "enhanced.wav")
@@ -211,31 +159,20 @@ def main():
decode_audio_to_wav(input_path, source_wav)
source_audio_np, source_sr = load_pcm16_wav(source_wav)
patch_torchaudio_load()
log("Importing AudioSR")
from audiosr import build_model, super_resolution
patch_strip_silence()
waveform = None
try:
waveform = run_audiosr_channels(build_model, super_resolution, source_audio_np, source_sr, args.model_name, "auto", tmp_dir)
preferred_device = "cuda" if torch.cuda.is_available() else "cpu"
waveform = run_lavasr_channels(source_audio_np, source_sr, preferred_device, tmp_dir)
except Exception as ex:
if not is_cuda_oom(ex):
if preferred_device != "cuda" or not is_cuda_oom(ex):
raise
log("CUDA OOM during AudioSR; retrying on CPU")
try:
if torch.cuda.is_available():
torch.cuda.empty_cache()
except Exception:
pass
waveform = run_audiosr_channels(build_model, super_resolution, source_audio_np, source_sr, args.model_name, "cpu", tmp_dir)
log("CUDA OOM during LavaSR; retrying on CPU")
waveform = run_lavasr_channels(source_audio_np, source_sr, "cpu", tmp_dir)
out_np = normalize_audiosr_output(waveform)
log("Encoding enhanced audio to FLAC")
save_pcm16_wav(enhanced_wav, out_np, 48000)
save_pcm16_wav(enhanced_wav, waveform, 48000)
encode_audio_to_flac(enhanced_wav, output_path, source_info.get("channel_layout"))
log("AudioSR output ready: {}".format(output_path))
log("LavaSR output ready: {}".format(output_path))
return 0
finally:
import shutil
+23 -36
View File
@@ -6,7 +6,6 @@ import shutil
import sys
import time
import tempfile
import venv
import wave
from contextlib import nullcontext
from urllib.parse import urlparse
@@ -18,9 +17,9 @@ import torch.nn.functional as F
from torch.hub import download_url_to_file
from PIL import Image
try:
from .audiosr_bootstrap import audiosr_runner_path, ensure_audiosr_environment, run_checked
from .lavasr_bootstrap import lavasr_runner_path, ensure_lavasr_environment, run_checked
except Exception:
from audiosr_bootstrap import audiosr_runner_path, ensure_audiosr_environment, run_checked
from lavasr_bootstrap import lavasr_runner_path, ensure_lavasr_environment, run_checked
import comfy.model_management as mm
from comfy.utils import ProgressBar, common_upscale
@@ -65,12 +64,6 @@ except Exception as ex: # pragma: no cover - runtime env specific
else:
_deepfilternet_import_error = None
try:
import torchvision
except Exception:
torchvision = None
SAM2_MODEL_DIR = "sam2"
OPENSHOT_NODEPACK_VERSION = "v1.1.2-track-object-keyframes"
GROUNDING_DINO_MODEL_IDS = (
@@ -149,11 +142,9 @@ def _require_deepfilternet():
)
def _require_audiosr_bootstrap():
def _require_lavasr_bootstrap():
if torchaudio is None:
raise RuntimeError("AudioSR bootstrap requires torchaudio in the main Comfy environment")
if torchvision is None:
raise RuntimeError("AudioSR bootstrap requires torchvision in the main Comfy environment")
raise RuntimeError("LavaSR bootstrap requires torchaudio in the main Comfy environment")
def _model_storage_dir():
@@ -1174,13 +1165,13 @@ def _deepfilternet_runner_path():
return os.path.join(os.path.dirname(os.path.abspath(__file__)), "deepfilternet_runner.py")
def _audiosr_runner_path():
return audiosr_runner_path(os.path.dirname(os.path.abspath(__file__)))
def _lavasr_runner_path():
return lavasr_runner_path(os.path.dirname(os.path.abspath(__file__)))
def _ensure_audiosr_environment():
_require_audiosr_bootstrap()
return ensure_audiosr_environment(os.path.dirname(os.path.abspath(__file__)))
def _ensure_lavasr_environment():
_require_lavasr_bootstrap()
return ensure_lavasr_environment(os.path.dirname(os.path.abspath(__file__)))
class OpenShotSceneRangesFromSegments:
@@ -2949,7 +2940,7 @@ class OpenShotDeepFilterNetDenoiseAudio:
return (output_path,)
class OpenShotAudioSRClarity:
class OpenShotLavaSRSpeechClarity:
@classmethod
def IS_CHANGED(cls, **kwargs):
return ""
@@ -2959,7 +2950,6 @@ class OpenShotAudioSRClarity:
return {
"required": {
"source_audio_path": ("STRING", {"default": ""}),
"model_name": (["speech", "basic"], {"default": "speech"}),
"keep_model_loaded": ("BOOLEAN", {"default": True}),
},
"optional": {
@@ -2968,7 +2958,7 @@ class OpenShotAudioSRClarity:
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("clarified_audio_path",)
RETURN_NAMES = ("clarified_speech_audio_path",)
FUNCTION = "enhance"
CATEGORY = "OpenShot/Audio"
@@ -2979,21 +2969,20 @@ class OpenShotAudioSRClarity:
raise ValueError("Audio path not found: {}".format(source_audio_path))
return source_path
def _build_output_path(self, source_path, model_name):
def _build_output_path(self, source_path):
output_dir = os.path.join(_safe_output_directory(), "openshot_audio")
os.makedirs(output_dir, exist_ok=True)
stem = _sanitize_filename_part(os.path.splitext(os.path.basename(source_path))[0], default="audio")
stat = os.stat(source_path)
key = "{}|{}|{}|{}".format(
key = "{}|{}|{}".format(
source_path,
int(stat.st_mtime_ns),
int(stat.st_size),
str(model_name or "basic"),
)
digest = hashlib.sha256(key.encode("utf-8")).hexdigest()[:10]
return os.path.join(output_dir, "{}_clarity_{}_{}.flac".format(stem, str(model_name), digest))
return os.path.join(output_dir, "{}_clarity_speech_{}.flac".format(stem, digest))
def enhance(self, source_audio_path, model_name, keep_model_loaded, audio=None):
def enhance(self, source_audio_path, keep_model_loaded, audio=None):
temp_source_dir = None
if audio is not None:
temp_source_dir = tempfile.mkdtemp(prefix="openshot_audio_input_", dir=folder_paths.get_temp_directory())
@@ -3002,16 +2991,16 @@ class OpenShotAudioSRClarity:
else:
source_path = self._resolve_source_path(source_audio_path)
output_path = self._build_output_path(source_path, model_name)
output_path = self._build_output_path(source_path)
if os.path.isfile(output_path):
if temp_source_dir:
shutil.rmtree(temp_source_dir, ignore_errors=True)
return (output_path,)
runner = _audiosr_runner_path()
runner = _lavasr_runner_path()
if not os.path.isfile(runner):
raise RuntimeError("AudioSR runner script not found: {}".format(runner))
python_path = _ensure_audiosr_environment()
raise RuntimeError("LavaSR runner script not found: {}".format(runner))
python_path = _ensure_lavasr_environment()
cmd = [
python_path,
@@ -3020,20 +3009,18 @@ class OpenShotAudioSRClarity:
source_path,
"--output",
output_path,
"--model-name",
str(model_name or "basic"),
]
if not bool(keep_model_loaded):
cmd.append("--release-model")
try:
run_checked(cmd, "AudioSR enhancement failed")
run_checked(cmd, "LavaSR enhancement failed")
finally:
if temp_source_dir:
shutil.rmtree(temp_source_dir, ignore_errors=True)
if not os.path.isfile(output_path):
raise RuntimeError("AudioSR enhancement did not produce output: {}".format(output_path))
raise RuntimeError("LavaSR enhancement did not produce output: {}".format(output_path))
return (output_path,)
@@ -3193,7 +3180,7 @@ NODE_CLASS_MAPPINGS = {
"OpenShotImageBlurMasked": OpenShotImageBlurMasked,
"OpenShotImageHighlightMasked": OpenShotImageHighlightMasked,
"OpenShotDeepFilterNetDenoiseAudio": OpenShotDeepFilterNetDenoiseAudio,
"OpenShotAudioSRClarity": OpenShotAudioSRClarity,
"OpenShotLavaSRSpeechClarity": OpenShotLavaSRSpeechClarity,
"OpenShotGroundingDinoDetect": OpenShotGroundingDinoDetect,
"OpenShotSceneRangesFromSegments": OpenShotSceneRangesFromSegments,
}
@@ -3207,7 +3194,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"OpenShotImageBlurMasked": "OpenShot Blur Masked (Skip Empty)",
"OpenShotImageHighlightMasked": "OpenShot Highlight Masked",
"OpenShotDeepFilterNetDenoiseAudio": "OpenShot DeepFilterNet Audio Denoise",
"OpenShotAudioSRClarity": "OpenShot AudioSR Clarity",
"OpenShotLavaSRSpeechClarity": "OpenShot LavaSR Speech Clarity",
"OpenShotGroundingDinoDetect": "OpenShot GroundingDINO Detect",
"OpenShotSceneRangesFromSegments": "OpenShot Scene Ranges From Segments",
}
+14 -14
View File
@@ -4,9 +4,9 @@ import shutil
import subprocess
import sys
try:
from .audiosr_bootstrap import audiosr_runner_path, ensure_audiosr_environment
from .lavasr_bootstrap import lavasr_runner_path, ensure_lavasr_environment
except Exception:
from audiosr_bootstrap import audiosr_runner_path, ensure_audiosr_environment
from lavasr_bootstrap import lavasr_runner_path, ensure_lavasr_environment
BASE_REQUIRED_MODULES = [
@@ -36,7 +36,7 @@ EXPECTED_NODES = [
"OpenShotImageBlurMasked",
"OpenShotImageHighlightMasked",
"OpenShotDeepFilterNetDenoiseAudio",
"OpenShotAudioSRClarity",
"OpenShotLavaSRSpeechClarity",
"OpenShotGroundingDinoDetect",
"OpenShotSceneRangesFromSegments",
]
@@ -114,24 +114,24 @@ def check_deepfilternet_runner():
return False
def check_audiosr_runner():
def check_lavasr_runner():
base_dir = os.path.dirname(os.path.abspath(__file__))
runner = audiosr_runner_path(base_dir)
runner = lavasr_runner_path(base_dir)
if not os.path.isfile(runner):
print("[FAIL] audiosr runner missing: {}".format(runner))
print("[FAIL] lavasr runner missing: {}".format(runner))
return False
if not module_available("torch") or not module_available("torchaudio") or not module_available("torchvision"):
print("[OK] audiosr runner present (skipping isolated env probe; main torch/torchaudio/torchvision not available)")
if not module_available("torch") or not module_available("torchaudio"):
print("[OK] lavasr runner present (skipping isolated env probe; main torch/torchaudio not available)")
return True
try:
python_path = ensure_audiosr_environment(base_dir)
python_path = ensure_lavasr_environment(base_dir)
except Exception as ex:
print("[FAIL] audiosr isolated env bootstrap: {}".format(ex))
print("[FAIL] lavasr isolated env bootstrap: {}".format(ex))
return False
code = (
"import warnings; warnings.filterwarnings('ignore');"
"from audiosr import build_model, super_resolution;"
"from LavaSR.model import LavaEnhance2;"
"print('ok')"
)
try:
@@ -142,11 +142,11 @@ def check_audiosr_runner():
stderr=subprocess.PIPE,
text=True,
)
print("[OK] audiosr isolated env import compatibility")
print("[OK] lavasr isolated env import compatibility")
return True
except subprocess.CalledProcessError as ex:
err = "\n".join(part.strip() for part in ((ex.stdout or ""), (ex.stderr or "")) if part.strip())
print("[FAIL] audiosr isolated env import compatibility: {}".format(err or "unknown error"))
print("[FAIL] lavasr isolated env import compatibility: {}".format(err or "unknown error"))
return False
@@ -160,7 +160,7 @@ def main():
ok = check_module(import_name, label) and ok
ok = check_deepfilternet_runner() and ok
ok = check_audiosr_runner() and ok
ok = check_lavasr_runner() and ok
for binary in ("ffmpeg", "ffprobe"):
ok = check_binary(binary) and ok