mirror of
https://github.com/denizsafak/abogen.git
synced 2026-09-20 11:40:57 +02:00
- EngineConfig.language: Language (was lang_code: str = 'a') - Engine owns _KOKORO_LANG_MAP, engine_language(), supported_languages() - Engine provides language_for_voice_id() for voice catalog - Plugins/kokoro/__init__.py calls engine_language() internally - create_pipeline(plugin_id, language=Language) — no kokoro codes - pipeline_factory.py clean of kokoro-specific code - Domain functions raise TypeError if non-enum passed - WebUI api.py: _parse_language() helper at API boundary - Voice catalog returns ISO codes (lang.value) - Constants: LANGUAGE_DESCRIPTIONS keyed by Language enum - All tests updated for Language enum - 1414 tests pass
77 lines
2.4 KiB
Python
77 lines
2.4 KiB
Python
"""Chunk processing utilities.
|
|
|
|
Functions for grouping chunks, recording override usage, and selecting
|
|
text for TTS synthesis.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections import defaultdict
|
|
from typing import Any, Dict, Iterable, Mapping
|
|
|
|
from abogen.domain.enums import Language
|
|
from abogen.pronunciation_store import increment_usage
|
|
|
|
|
|
def safe_int(value: Any, default: int = 0) -> int:
|
|
try:
|
|
return int(value)
|
|
except (TypeError, ValueError):
|
|
return default
|
|
|
|
|
|
def group_chunks_by_chapter(chunks: Iterable[Dict[str, Any]]) -> Dict[int, List[Dict[str, Any]]]:
|
|
grouped: Dict[int, List[Dict[str, Any]]] = defaultdict(list)
|
|
for entry in chunks or []:
|
|
if not isinstance(entry, dict):
|
|
continue
|
|
try:
|
|
chapter_index = int(entry.get("chapter_index", 0))
|
|
except (TypeError, ValueError):
|
|
chapter_index = 0
|
|
grouped[chapter_index].append(dict(entry))
|
|
|
|
for chapter_index, items in grouped.items():
|
|
items.sort(key=lambda payload: safe_int(payload.get("chunk_index")))
|
|
|
|
return grouped
|
|
|
|
|
|
def record_override_usage(
|
|
job: Any,
|
|
usage_counter: Mapping[str, int],
|
|
token_map: Mapping[str, str],
|
|
) -> None:
|
|
if not usage_counter:
|
|
return
|
|
|
|
language = getattr(job, "language", Language.EN_US) or Language.EN_US
|
|
for normalized, amount in usage_counter.items():
|
|
if amount <= 0:
|
|
continue
|
|
token_value = token_map.get(normalized, normalized)
|
|
try:
|
|
increment_usage(language=language, token=token_value, amount=int(amount))
|
|
except Exception: # pragma: no cover - defensive logging
|
|
job.add_log(f"Failed to record usage for override {token_value}", level="warning")
|
|
|
|
|
|
def chunk_text_for_tts(entry: Mapping[str, Any]) -> str:
|
|
"""Choose the best source text for synthesis.
|
|
|
|
We must prefer the raw chunk text (``text`` / ``original_text``) so
|
|
manual/pronunciation overrides can match against the original tokens
|
|
(e.g. censored words like ``Unfu*k``). ``normalized_text`` may have
|
|
already been run through ``normalize_for_pipeline``, which can remove
|
|
punctuation and prevent overrides from triggering.
|
|
"""
|
|
|
|
if not isinstance(entry, Mapping):
|
|
return ""
|
|
return str(
|
|
entry.get("text")
|
|
or entry.get("original_text")
|
|
or entry.get("normalized_text")
|
|
or ""
|
|
).strip()
|