refactor: consolidate voice formula building into voice_formulas.py

- voice_formulas.py: add pairs_to_formula() as canonical implementation
- webui/routes/utils/voice.py: formula_from_profile() and pairs_to_formula()
  now delegate to voice_formulas.pairs_to_formula()
- pyqt/gui.py: get_voice_formula() now uses voice_formulas.pairs_to_formula()
  instead of inline string formatting
- Eliminates 3 duplicate implementations of voice*weight formula building
- +9 tests
- 1178 tests pass
This commit is contained in:
Artem Akymenko
2026-07-19 10:02:14 +00:00
parent fe62b6b44c
commit a99cf58c79
4 changed files with 80 additions and 28 deletions
+28 -1
View File
@@ -1,5 +1,5 @@
import re
from typing import List, Tuple
from typing import Iterable, List, Optional, Tuple
from abogen.tts_plugin.utils import get_voices
@@ -72,6 +72,33 @@ def parse_voice_formula(pipeline, formula):
return weighted_sum
def pairs_to_formula(pairs: Iterable[Tuple[str, float]]) -> Optional[str]:
"""Build a voice formula string from (voice_name, weight) pairs.
Normalizes weights to sum to 1.0 and formats as "voice1*0.5+voice2*0.5".
Args:
pairs: Iterable of (voice_name, weight) tuples. Zero-weight entries
are filtered out.
Returns:
Formula string, or None if no valid entries.
"""
voices = [(voice, float(weight)) for voice, weight in pairs if weight is not None and float(weight) > 0]
if not voices:
return None
total = sum(weight for _, weight in voices)
if total <= 0:
return None
def _format_value(value: float) -> str:
normalized = value / total if total else 0.0
return (f"{normalized:.4f}").rstrip("0").rstrip(".") or "0"
parts = [f"{voice}*{_format_value(weight)}" for voice, weight in voices]
return "+".join(parts)
def calculate_sum_from_formula(formula):
weights = re.findall(r"\* *([\d.]+)", formula)
total_sum = sum(float(weight) for weight in weights)