mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 13:40:27 +02:00
refactor(webui): use shared get_split_pattern instead of hardcoded \\n+
All three Web UI consumers now call domain.split_pattern.get_split_pattern() which selects the correct split pattern based on language and subtitle mode. Before: WebUI always split on \\n+ regardless of language (CJK missed punctuation-based splitting that PyQt already had). After: Both UIs share identical language-aware splitting logic. 1038 tests pass.
This commit is contained in:
@@ -111,6 +111,7 @@ from abogen.domain.output_paths import (
|
|||||||
resolve_project_layout as _resolve_project_layout,
|
resolve_project_layout as _resolve_project_layout,
|
||||||
)
|
)
|
||||||
from abogen.domain.device import select_device as _select_device
|
from abogen.domain.device import select_device as _select_device
|
||||||
|
from abogen.domain.split_pattern import get_split_pattern
|
||||||
from abogen.domain.audio_helpers import (
|
from abogen.domain.audio_helpers import (
|
||||||
build_ffmpeg_command as _build_ffmpeg_command,
|
build_ffmpeg_command as _build_ffmpeg_command,
|
||||||
to_float32 as _to_float32,
|
to_float32 as _to_float32,
|
||||||
@@ -127,7 +128,7 @@ from .service import Job, JobStatus
|
|||||||
|
|
||||||
_export_svc = ExportService()
|
_export_svc = ExportService()
|
||||||
|
|
||||||
SPLIT_PATTERN = r"\n+"
|
SPLIT_PATTERN = r"\n+" # Kept for backward compatibility; prefer get_split_pattern()
|
||||||
SAMPLE_RATE = 24000
|
SAMPLE_RATE = 24000
|
||||||
|
|
||||||
|
|
||||||
@@ -172,6 +173,12 @@ def run_conversion_job(job: Job) -> None:
|
|||||||
"LLM-based apostrophe normalization is selected, but the LLM configuration is incomplete."
|
"LLM-based apostrophe normalization is selected, but the LLM configuration is incomplete."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Compute language-aware split pattern once for the entire job
|
||||||
|
job_split_pattern = get_split_pattern(
|
||||||
|
str(job.language or "a"),
|
||||||
|
str(job.subtitle_mode or "Disabled"),
|
||||||
|
)
|
||||||
|
|
||||||
sink_stack = ExitStack()
|
sink_stack = ExitStack()
|
||||||
subtitle_writer = None
|
subtitle_writer = None
|
||||||
chapter_paths: list[Path] = []
|
chapter_paths: list[Path] = []
|
||||||
@@ -438,12 +445,14 @@ def run_conversion_job(job: Job) -> None:
|
|||||||
voice_choice: Any,
|
voice_choice: Any,
|
||||||
chapter_sink: Optional[AudioSink],
|
chapter_sink: Optional[AudioSink],
|
||||||
preview_prefix: Optional[str] = None,
|
preview_prefix: Optional[str] = None,
|
||||||
split_pattern: Optional[str] = SPLIT_PATTERN,
|
split_pattern: Optional[str] = None,
|
||||||
tts_provider: Optional[str] = None,
|
tts_provider: Optional[str] = None,
|
||||||
speed_override: Optional[float] = None,
|
speed_override: Optional[float] = None,
|
||||||
supertonic_steps_override: Optional[int] = None,
|
supertonic_steps_override: Optional[int] = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
nonlocal processed_chars, current_time
|
nonlocal processed_chars, current_time
|
||||||
|
if split_pattern is None:
|
||||||
|
split_pattern = job_split_pattern
|
||||||
source_text = str(text or "")
|
source_text = str(text or "")
|
||||||
try:
|
try:
|
||||||
normalized = prepare_text_for_tts(
|
normalized = prepare_text_for_tts(
|
||||||
@@ -625,7 +634,6 @@ def run_conversion_job(job: Job) -> None:
|
|||||||
voice_choice=voice_choice,
|
voice_choice=voice_choice,
|
||||||
chapter_sink=chapter_sink,
|
chapter_sink=chapter_sink,
|
||||||
preview_prefix=f"Chapter {idx} title",
|
preview_prefix=f"Chapter {idx} title",
|
||||||
split_pattern=SPLIT_PATTERN,
|
|
||||||
tts_provider=chapter_provider,
|
tts_provider=chapter_provider,
|
||||||
speed_override=chapter_speed,
|
speed_override=chapter_speed,
|
||||||
supertonic_steps_override=chapter_steps,
|
supertonic_steps_override=chapter_steps,
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ from abogen.kokoro_text_normalization import normalize_for_pipeline
|
|||||||
from abogen.normalization_settings import build_apostrophe_config
|
from abogen.normalization_settings import build_apostrophe_config
|
||||||
from abogen.text_extractor import extract_from_path
|
from abogen.text_extractor import extract_from_path
|
||||||
from abogen.voice_cache import ensure_voice_assets
|
from abogen.voice_cache import ensure_voice_assets
|
||||||
from abogen.webui.conversion_runner import SAMPLE_RATE, SPLIT_PATTERN, _select_device, _to_float32, _resolve_voice, _spec_to_voice_ids
|
from abogen.webui.conversion_runner import SAMPLE_RATE, _select_device, _to_float32, _resolve_voice, _spec_to_voice_ids
|
||||||
|
from abogen.domain.split_pattern import get_split_pattern
|
||||||
from abogen.tts_plugin.utils import create_pipeline
|
from abogen.tts_plugin.utils import create_pipeline
|
||||||
|
|
||||||
|
|
||||||
@@ -200,7 +201,7 @@ def run_debug_tts_wavs(
|
|||||||
normalized,
|
normalized,
|
||||||
voice=voice_choice,
|
voice=voice_choice,
|
||||||
speed=speed,
|
speed=speed,
|
||||||
split_pattern=SPLIT_PATTERN,
|
split_pattern=get_split_pattern(language, "Disabled"),
|
||||||
):
|
):
|
||||||
audio = _to_float32(getattr(segment, "audio", None))
|
audio = _to_float32(getattr(segment, "audio", None))
|
||||||
if audio.size:
|
if audio.size:
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ from flask import current_app, send_file
|
|||||||
from flask.typing import ResponseReturnValue
|
from flask.typing import ResponseReturnValue
|
||||||
|
|
||||||
from abogen.domain.device import select_device as _select_device
|
from abogen.domain.device import select_device as _select_device
|
||||||
|
from abogen.domain.split_pattern import get_split_pattern
|
||||||
|
|
||||||
|
|
||||||
SPLIT_PATTERN = r"\n+"
|
|
||||||
SAMPLE_RATE = 24000
|
SAMPLE_RATE = 24000
|
||||||
|
|
||||||
_preview_pipelines: Dict[Tuple[str, str], Any] = {}
|
_preview_pipelines: Dict[Tuple[str, str], Any] = {}
|
||||||
@@ -123,6 +123,8 @@ def generate_preview_audio(
|
|||||||
current_app.logger.exception("Preview normalization failed; using raw text")
|
current_app.logger.exception("Preview normalization failed; using raw text")
|
||||||
normalized_text = source_text
|
normalized_text = source_text
|
||||||
|
|
||||||
|
preview_split = get_split_pattern(str(language or "a"), "Disabled")
|
||||||
|
|
||||||
if provider == "supertonic":
|
if provider == "supertonic":
|
||||||
from abogen.tts_plugin.utils import create_pipeline
|
from abogen.tts_plugin.utils import create_pipeline
|
||||||
|
|
||||||
@@ -131,7 +133,7 @@ def generate_preview_audio(
|
|||||||
normalized_text,
|
normalized_text,
|
||||||
voice=voice_spec,
|
voice=voice_spec,
|
||||||
speed=speed,
|
speed=speed,
|
||||||
split_pattern=SPLIT_PATTERN,
|
split_pattern=preview_split,
|
||||||
total_steps=supertonic_total_steps,
|
total_steps=supertonic_total_steps,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@@ -149,7 +151,7 @@ def generate_preview_audio(
|
|||||||
normalized_text,
|
normalized_text,
|
||||||
voice=voice_choice,
|
voice=voice_choice,
|
||||||
speed=speed,
|
speed=speed,
|
||||||
split_pattern=SPLIT_PATTERN,
|
split_pattern=preview_split,
|
||||||
)
|
)
|
||||||
|
|
||||||
audio_chunks: List[np.ndarray] = []
|
audio_chunks: List[np.ndarray] = []
|
||||||
|
|||||||
Reference in New Issue
Block a user