Unified aedocw backends
This commit is contained in:
+84
-38
@@ -8,16 +8,23 @@
|
||||
This module provides a generic TTS backend that can be used to convert text to speech using various TTS engines. It defines a `GenericTTSBackend` class that can be initialized with a specific backend command, language, and voice. The class provides methods to normalize paths, determine input and output flags based on the type of input/output (file or directory), build the command for the TTS engine, and run the command.
|
||||
|
||||
Classes:
|
||||
|
||||
GenericTTSBackend:
|
||||
|
||||
Parameters:
|
||||
backend_cmd (str): Command or executable for the backend.
|
||||
language (Optional[str]): Language code for TTS output.
|
||||
voice (Optional[str]): Voice name for TTS output.
|
||||
|
||||
Methods:
|
||||
_normalize_path(value: PathLike) -> Path: Normalize a string or Path to Path.
|
||||
_input_flag(input_path: Path) -> str: Return backend flag for input file or directory.
|
||||
_output_flag(output_path: Path) -> str: Return backend flag for output file or directory.
|
||||
|
||||
gen_input_flag(input_path: Path) -> str: Return backend flag for input file or directory.
|
||||
|
||||
gen_output_flag(output_path: Path) -> str: Return backend flag for output file or directory.
|
||||
|
||||
_build_command(input_source: PathLike, output_dest: PathLike) -> list[str]: Build command list for subprocess.
|
||||
|
||||
run(input_source: PathLike, output_dest: PathLike) -> subprocess.CompletedProcess: Execute backend command.
|
||||
|
||||
"""
|
||||
@@ -28,52 +35,91 @@ from typing import Optional, Union
|
||||
|
||||
PathLike = Union[str, Path]
|
||||
|
||||
from .vendor_utils import build_run_command
|
||||
|
||||
|
||||
class GenericTTSBackend:
|
||||
def __init__(
|
||||
self,
|
||||
backend_cmd: str,
|
||||
language: Optional[str] = None,
|
||||
voice: Optional[str] = None,
|
||||
):
|
||||
self.backend_cmd = backend_cmd
|
||||
self.language = language
|
||||
self.voice = voice
|
||||
"""Generic TTS backend for handling text-to-speech conversion.
|
||||
|
||||
Parameters:
|
||||
backend_cmd (str): Command or executable for the backend.
|
||||
language (Optional[str]): Language code for TTS output.
|
||||
voice (Optional[str]): Voice name for TTS output.
|
||||
"""
|
||||
|
||||
FLAGS = {}
|
||||
INTERMEDIATE_TXT = False
|
||||
DEFAULT_SPEAKER = None
|
||||
DEFAULT_SAMPLE = None
|
||||
SUPPORTED_AUDIO_FORMATS = {
|
||||
# subclasses may override this
|
||||
".m4b": "m4b",
|
||||
".wav": "wav",
|
||||
".flac": "flac",
|
||||
".mp3": "mp3",
|
||||
".ogg": "ogg",
|
||||
}
|
||||
|
||||
_INPUT_FLAG_MAP = lambda x: [
|
||||
"--input-dir", x] if x else ["--input-file", x]
|
||||
|
||||
_OUTPUT_FLAG_MAP = lambda x: [
|
||||
"--output-dir", x] if x else ["--output-file", x]
|
||||
|
||||
def __init__(self,**kwargs):
|
||||
for k,v in kwargs.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
|
||||
def _normalize_path(self, value: PathLike) -> Path:
|
||||
if isinstance(value, Path):
|
||||
return value
|
||||
return Path(value)
|
||||
return value.resolve()
|
||||
else:
|
||||
return Path(value).resolve()
|
||||
|
||||
def _input_flag(self, input_path: Path) -> str:
|
||||
return "--input-dir" if input_path.is_dir() else "--input-file"
|
||||
|
||||
def _output_flag(self, output_path: Path) -> str:
|
||||
return "--output-dir" if output_path.is_dir() else "--output-file"
|
||||
def gen_input_flag(self, input_path: Path) -> str:
|
||||
return self._INPUT_FLAG_MAP(self._normalize_path(input_path).is_dir())
|
||||
|
||||
def _build_command(
|
||||
self, input_source: PathLike, output_dest: PathLike
|
||||
) -> list[str]:
|
||||
input_path = self._normalize_path(input_source)
|
||||
output_path = self._normalize_path(output_dest)
|
||||
|
||||
command = [
|
||||
self.backend_cmd,
|
||||
self._input_flag(input_path),
|
||||
str(input_path),
|
||||
self._output_flag(output_path),
|
||||
str(output_path),
|
||||
]
|
||||
def gen_output_flag(self, output_path: Path) -> str:
|
||||
return self._OUTPUT_FLAG_MAP(self._normalize_path(output_path).is_dir())
|
||||
|
||||
if self.language:
|
||||
command.extend(["--language", self.language])
|
||||
if self.voice:
|
||||
command.extend(["--voice", self.voice])
|
||||
|
||||
def _build_command(self, input_source: PathLike, output_dest: PathLike) -> list[str]:
|
||||
command = [self.backend_cmd]
|
||||
command.extend(self.gen_input_flag(input_source))
|
||||
command.extend(self.gen_output_flag(output_dest))
|
||||
for flag_name, var_name in self.FLAGS.items():
|
||||
if getattr(self, flag_name, None) is not None:
|
||||
command.extend([
|
||||
f"--{flag_name.replace('_', '-')}",
|
||||
getattr(self, var_name)])
|
||||
return command
|
||||
|
||||
def run(self,
|
||||
input_source: PathLike,
|
||||
output_dest: PathLike,
|
||||
**kwargs
|
||||
) -> subprocess.CompletedProcess:
|
||||
|
||||
|
||||
|
||||
def run(
|
||||
self, input_source: PathLike, output_dest: PathLike
|
||||
) -> subprocess.CompletedProcess:
|
||||
command = self._build_command(input_source, output_dest)
|
||||
return subprocess.run(command, check=True)
|
||||
completed = subprocess.run(
|
||||
self._build_command(input_source, output_dest),
|
||||
cwd=str(self._normalize_path(input_source).parent),
|
||||
check=True)
|
||||
|
||||
if self.INTERMEDIATE_TXT:
|
||||
txt_file = self._normalize_path(input_source).with_suffix(".txt")
|
||||
if txt_file.exists():
|
||||
completed = subprocess.run(
|
||||
self._build_command(txt_file, output_dest),
|
||||
cwd=str(self._normalize_path(input_source).parent),
|
||||
check=True
|
||||
)
|
||||
|
||||
|
||||
return completed
|
||||
|
||||
|
||||
Reference in New Issue
Block a user