mirror of
https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI.git
synced 2026-08-29 10:09:32 +02:00
180 lines
6.2 KiB
Python
180 lines
6.2 KiB
Python
import math
|
|
from time import time
|
|
|
|
from tqdm.auto import tqdm
|
|
|
|
|
|
def _format_progress_time(value):
|
|
"""Format progress seconds as mm:ss or hh:mm:ss."""
|
|
seconds = max(0, int(round(value or 0)))
|
|
hours, remainder = divmod(seconds, 3600)
|
|
minutes, seconds = divmod(remainder, 60)
|
|
if hours:
|
|
return f"{hours:d}:{minutes:02d}:{seconds:02d}"
|
|
return f"{minutes:d}:{seconds:02d}"
|
|
|
|
|
|
def _is_time_progress_message(message):
|
|
"""Return whether a progress message represents audio seconds."""
|
|
return "audio" in str(message).lower()
|
|
|
|
|
|
def _format_progress_rtf(bar):
|
|
"""Return real-time factor text for a tqdm audio progress bar."""
|
|
done = float(bar.n or 0)
|
|
if done <= 0:
|
|
return "--"
|
|
elapsed = max(0.0, time() - getattr(bar, "start_t", time()))
|
|
return f"{elapsed / done:.2f}"
|
|
|
|
|
|
def _update_time_progress_bar(bar):
|
|
"""Update a tqdm bar with formatted elapsed/total audio time."""
|
|
if bar is None:
|
|
return
|
|
rtf = _format_progress_rtf(bar)
|
|
bar._pymss_audio_progress = f"{_format_progress_time(bar.n)}/{_format_progress_time(bar.total)}, RTF={rtf}"
|
|
bar.refresh()
|
|
|
|
|
|
class _TimeProgressTqdm(tqdm):
|
|
"""tqdm subclass with a custom audio progress field."""
|
|
|
|
@property
|
|
def format_dict(self):
|
|
data = super().format_dict
|
|
data["audio_progress"] = getattr(self, "_pymss_audio_progress", "")
|
|
return data
|
|
|
|
|
|
class _ProgressContext:
|
|
"""Small progress adapter used by demixing helpers."""
|
|
|
|
def __init__(
|
|
self,
|
|
pbar=False,
|
|
total=1,
|
|
callback=None,
|
|
done=0,
|
|
message="Processing audio",
|
|
sample_rate=None,
|
|
):
|
|
"""Initialize the progress adapter.
|
|
|
|
Args:
|
|
pbar (Any, optional): Whether to show a tqdm progress bar.
|
|
Defaults to False.
|
|
total (Any, optional): Total progress units. Defaults to 1.
|
|
callback (Any, optional): Optional callback receiving
|
|
``(done, total, message)``. Defaults to None.
|
|
done (Any, optional): Initial completed units. Defaults to 0.
|
|
message (str, optional): Progress message. Defaults to
|
|
``"Processing audio"``.
|
|
sample_rate (int | None, optional): Sample rate used to expose
|
|
progress in seconds. When omitted, progress values are used as
|
|
already provided.
|
|
"""
|
|
self.enabled = bool(pbar or callback)
|
|
self.bar = None
|
|
self.callback = callback
|
|
self.done = done
|
|
self.total = total
|
|
self.message = message
|
|
self.sample_rate = int(sample_rate or 0)
|
|
if not self.enabled:
|
|
return
|
|
self.total = int(self.total or 1)
|
|
self.done = min(max(0, int(self.done or 0)), self.total)
|
|
if pbar:
|
|
bar_kwargs = {"total": self._display_total(), "desc": message, "leave": False}
|
|
if self.sample_rate > 0:
|
|
bar_kwargs.update({"unit": "", "bar_format": "{l_bar}{bar}| {audio_progress}"})
|
|
self.bar = _TimeProgressTqdm(**bar_kwargs)
|
|
else:
|
|
self.bar = tqdm(**bar_kwargs)
|
|
if self.sample_rate > 0:
|
|
_update_time_progress_bar(self.bar)
|
|
if self.bar is not None and self.done:
|
|
self.bar.update(self._display_value(self.done))
|
|
if self.sample_rate > 0:
|
|
_update_time_progress_bar(self.bar)
|
|
self.emit()
|
|
|
|
def _display_value(self, value):
|
|
"""Return progress value exposed to callbacks and progress bars."""
|
|
if self.sample_rate <= 0:
|
|
return int(value)
|
|
if int(value) >= self.total:
|
|
return self._display_total()
|
|
return min(self._display_total(), int(int(value) // self.sample_rate))
|
|
|
|
def _display_total(self):
|
|
"""Return total seconds for the current progress unit."""
|
|
if self.sample_rate <= 0:
|
|
return self.total
|
|
return max(1, int(math.ceil(self.total / self.sample_rate)))
|
|
|
|
def emit(self, done=None):
|
|
"""Emit a progress update."""
|
|
if not self.enabled:
|
|
return
|
|
if done is not None:
|
|
next_done = min(max(0, int(done)), self.total)
|
|
if self.bar is not None:
|
|
self.bar.update(self._display_value(next_done) - self._display_value(self.done))
|
|
if self.sample_rate > 0:
|
|
_update_time_progress_bar(self.bar)
|
|
self.done = next_done
|
|
if self.callback is None:
|
|
return
|
|
self.callback(self._display_value(self.done), self._display_total(), self.message)
|
|
|
|
def update(self, amount):
|
|
"""Advance progress by ``amount`` internal units."""
|
|
if not self.enabled:
|
|
return
|
|
amount = int(amount)
|
|
self.emit(self.done + amount)
|
|
|
|
def close(self):
|
|
"""Close the progress bar when present."""
|
|
if not self.enabled:
|
|
return
|
|
if self.bar:
|
|
self.bar.close()
|
|
|
|
|
|
class _CliInferenceProgress:
|
|
"""CLI callback adapter for inference progress updates."""
|
|
|
|
def __init__(self):
|
|
self._bar = None
|
|
self._message = None
|
|
self._total = None
|
|
|
|
def __call__(self, done, total, message):
|
|
total = max(1, int(total or 1))
|
|
done = max(0, min(int(done), total))
|
|
if self._bar is None or self._message != message or self._total != total or done < self._bar.n:
|
|
self.close()
|
|
self._message = message
|
|
self._total = total
|
|
bar_kwargs = {"total": total, "desc": message, "leave": False, "mininterval": 0, "miniters": 1}
|
|
if _is_time_progress_message(message):
|
|
bar_kwargs.update({"unit": "", "bar_format": "{l_bar}{bar}| {audio_progress}"})
|
|
self._bar = _TimeProgressTqdm(**bar_kwargs)
|
|
else:
|
|
self._bar = tqdm(**bar_kwargs)
|
|
if _is_time_progress_message(message):
|
|
_update_time_progress_bar(self._bar)
|
|
if done != self._bar.n:
|
|
self._bar.update(done - self._bar.n)
|
|
if _is_time_progress_message(message):
|
|
_update_time_progress_bar(self._bar)
|
|
|
|
def close(self):
|
|
"""Close the active CLI progress bar."""
|
|
if self._bar is not None:
|
|
self._bar.close()
|
|
self._bar = None
|