55 lines
No EOL
1.8 KiB
Python
55 lines
No EOL
1.8 KiB
Python
# tts_utils.py
|
|
import re
|
|
from bs4 import BeautifulSoup
|
|
|
|
|
|
def get_configured_tts_rate(settings: dict) -> str:
|
|
"""Converts a numerical speed multiplier (e.g., 0.75, 1.0, 1.25) from app settings
|
|
into Edge TTS percentage format string (e.g., '-25%', '+0%', '+25%').
|
|
"""
|
|
# Check the actual database key 'tts_playback_speed' with fallbacks
|
|
raw_val = (
|
|
settings.get("tts_playback_speed")
|
|
or settings.get("tts_speed_multiplier")
|
|
or 1.0
|
|
)
|
|
|
|
try:
|
|
raw_rate = float(raw_val)
|
|
except (TypeError, ValueError):
|
|
raw_rate = 1.0
|
|
|
|
# Calculate percentage shift relative to baseline 1.0
|
|
pct = int(round((raw_rate - 1.0) * 100))
|
|
if pct >= 0:
|
|
return f"+{pct}%"
|
|
return f"{pct}%"
|
|
|
|
|
|
def parse_text_for_edgetts(html_content: str) -> str:
|
|
"""Strips content between <meta sound-off> and <meta sound-on> tags,
|
|
handling optional whitespace inside the tag brackets (e.g., <meta sound-off >).
|
|
Converts remaining HTML tags to clean spoken text.
|
|
"""
|
|
if not html_content:
|
|
return ""
|
|
|
|
# Flexible regex to slice out everything from <meta sound-off ...> through <meta sound-on ...>
|
|
pattern = re.compile(
|
|
r"<meta\s+sound-off\s*\/?>.*?<meta\s+sound-on\s*\/?>",
|
|
re.DOTALL | re.IGNORECASE,
|
|
)
|
|
cleaned_html = re.sub(pattern, "", html_content)
|
|
|
|
# Handle unclosed <meta sound-off> (mute rest of string from that point)
|
|
if re.search(r"<meta\s+sound-off\s*\/?>", cleaned_html, re.IGNORECASE):
|
|
cleaned_html = re.split(
|
|
r"<meta\s+sound-off\s*\/?>", cleaned_html, flags=re.IGNORECASE
|
|
)[0]
|
|
|
|
# Convert remaining HTML into plain text for speech
|
|
soup = BeautifulSoup(cleaned_html, "html.parser")
|
|
text = soup.get_text(separator=" ")
|
|
|
|
# Normalize extra whitespace
|
|
return re.sub(r"\s+", " ", text).strip() |