feat: Add pending ID handling and pronunciation/manual overrides to audio preview generation

This commit is contained in:
JB
2025-12-20 17:40:05 -08:00
parent 5dd53354a1
commit 0fe8ee0ad4
4 changed files with 111 additions and 4 deletions
+17
View File
@@ -215,6 +215,7 @@ def api_voice_profiles_preview() -> ResponseReturnValue:
@api_bp.post("/speaker-preview")
def api_speaker_preview() -> ResponseReturnValue:
payload = request.get_json(force=True, silent=True) or {}
pending_id = str(payload.get("pending_id") or "").strip()
text = payload.get("text", "Hello world")
voice = payload.get("voice", "af_heart")
language = payload.get("language", "a")
@@ -243,6 +244,19 @@ def api_speaker_preview() -> ResponseReturnValue:
if not resolved_provider:
resolved_provider = "supertonic" if str(base_spec or "").strip() in {"M1","M2","M3","M4","M5","F1","F2","F3","F4","F5"} else "kokoro"
pronunciation_overrides = None
manual_overrides = None
speakers = None
if pending_id:
try:
pending = get_service().get_pending_job(pending_id)
except Exception:
pending = None
if pending is not None:
manual_overrides = getattr(pending, "manual_overrides", None)
pronunciation_overrides = getattr(pending, "pronunciation_overrides", None)
speakers = getattr(pending, "speakers", None)
try:
return synthesize_preview(
@@ -254,6 +268,9 @@ def api_speaker_preview() -> ResponseReturnValue:
,
tts_provider=resolved_provider,
supertonic_total_steps=supertonic_total_steps or int(settings.get("supertonic_total_steps") or 5),
pronunciation_overrides=pronunciation_overrides,
manual_overrides=manual_overrides,
speakers=speakers,
)
except Exception as e:
return jsonify({"error": str(e)}), 500
+36 -4
View File
@@ -1,6 +1,6 @@
import io
import threading
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Dict, Iterable, List, Mapping, Optional, Tuple
import numpy as np
import soundfile as sf
from flask import current_app, send_file
@@ -61,21 +61,47 @@ def generate_preview_audio(
tts_provider: str = "kokoro",
supertonic_total_steps: int = 5,
max_seconds: float = 8.0,
pronunciation_overrides: Optional[Iterable[Mapping[str, Any]]] = None,
manual_overrides: Optional[Iterable[Mapping[str, Any]]] = None,
speakers: Optional[Mapping[str, Any]] = None,
) -> bytes:
if not text.strip():
raise ValueError("Preview text is required")
provider = (tts_provider or "kokoro").strip().lower()
normalized_text = text
# Apply pronunciation/manual overrides first so tokens like `Unfu*k` still match
# before any downstream normalization potentially strips punctuation.
source_text = text
if pronunciation_overrides or manual_overrides or speakers:
try:
from abogen.web import conversion_runner as runner
class _PreviewJob:
def __init__(self):
self.language = language
self.voice = voice_spec
self.speakers = speakers
self.manual_overrides = list(manual_overrides or [])
self.pronunciation_overrides = list(pronunciation_overrides or [])
job = _PreviewJob()
merged = runner._merge_pronunciation_overrides(job)
rules = runner._compile_pronunciation_rules(merged)
source_text = runner._apply_pronunciation_rules(source_text, rules)
except Exception:
current_app.logger.exception("Preview override application failed; using raw text")
source_text = text
normalized_text = source_text
if provider != "supertonic":
try:
from abogen.kokoro_text_normalization import normalize_for_pipeline
normalized_text = normalize_for_pipeline(text)
normalized_text = normalize_for_pipeline(source_text)
except Exception:
current_app.logger.exception("Preview normalization failed; using raw text")
normalized_text = text
normalized_text = source_text
if provider == "supertonic":
from abogen.tts_supertonic import SupertonicPipeline
@@ -152,6 +178,9 @@ def synthesize_preview(
tts_provider: str = "kokoro",
supertonic_total_steps: int = 5,
max_seconds: float = 8.0,
pronunciation_overrides: Optional[Iterable[Mapping[str, Any]]] = None,
manual_overrides: Optional[Iterable[Mapping[str, Any]]] = None,
speakers: Optional[Mapping[str, Any]] = None,
) -> ResponseReturnValue:
try:
audio_bytes = generate_preview_audio(
@@ -163,6 +192,9 @@ def synthesize_preview(
tts_provider=tts_provider,
supertonic_total_steps=supertonic_total_steps,
max_seconds=max_seconds,
pronunciation_overrides=pronunciation_overrides,
manual_overrides=manual_overrides,
speakers=speakers,
)
except Exception as e:
raise e
+9
View File
@@ -77,6 +77,15 @@ const playPreview = async (button) => {
max_seconds: 8,
};
const pendingId =
button.dataset.pendingId ||
button.closest("[data-pending-id]")?.dataset.pendingId ||
document.querySelector('[data-role="prepare-form"]')?.dataset.pendingId ||
"";
if (pendingId) {
payload.pending_id = pendingId;
}
stopCurrentPlayback();
activeButton = button;
setLoadingState(button, true);