diff --git a/pyproject.toml b/pyproject.toml index 62c56be..e5cbce2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,11 +30,11 @@ dependencies = [ "pinyin-tone-converter", "genanki", "argostranslate", - "chatterbox-tts", "torch", "torchaudio", "torchcodec", "python-dotenv", + "qwen-tts", ] diff --git a/src/anki_hsk_creator/__init__.py b/src/anki_hsk_creator/__init__.py index 3210c4b..b4a629e 100644 --- a/src/anki_hsk_creator/__init__.py +++ b/src/anki_hsk_creator/__init__.py @@ -18,3 +18,6 @@ HF_TOKEN = os.environ.get("HF_TOKEN") default_path = Path.home() / "anki-hsk-creator-data" DATA_FOLDER = Path(os.environ.get("DATA_FOLDER", default_path)) DATA_FOLDER.mkdir(exist_ok=True, parents=True) +default_gwen = Path.home() / "Gwen" +GWEN_FOLDER = Path(os.environ.get("GWEN_FOLDER", default_gwen)) +GWEN_FOLDER.mkdir(exist_ok=True, parents=True) diff --git a/src/anki_hsk_creator/constants.py b/src/anki_hsk_creator/constants.py index fb5755d..b274cbb 100644 --- a/src/anki_hsk_creator/constants.py +++ b/src/anki_hsk_creator/constants.py @@ -4,7 +4,7 @@ import importlib.resources # Local -from . import DATA_FOLDER +from . import DATA_FOLDER, GWEN_FOLDER # Resources CCCEDICT_PATH = importlib.resources.files("anki_hsk_creator").joinpath("cedict_ts.u8") @@ -16,16 +16,13 @@ OUTPUT = DATA_FOLDER / "output" OUTPUT.mkdir(exist_ok=True, parents=True) RESOURCES = DATA_FOLDER / "resources" RESOURCES.mkdir(exist_ok=True, parents=True) +GWEN_TTS = GWEN_FOLDER / "Qwen3-TTS-12Hz-1.7B-CustomVoice" # File Types PHRASES_TYPE = ".phrases" DICT_TYPE = ".dictionary" DICTATION_TYPE = ".dictation" -# time dalays -WORD = 0.1 -COMMA = 0.5 -POINT = 1.0 class LANGUAGES: """Available laguages for translation""" @@ -37,7 +34,6 @@ class LANGUAGES: RU = "ru" TR = "tr" TH = "th" - AvailableLanguages = (EN, ES, FR, RU, TR, TH) LanguageNames = { EN: "English", diff --git a/src/anki_hsk_creator/proccessor.py b/src/anki_hsk_creator/proccessor.py index e381127..23d9889 100644 --- a/src/anki_hsk_creator/proccessor.py +++ b/src/anki_hsk_creator/proccessor.py @@ -8,7 +8,7 @@ import argostranslate.translate import torchaudio # Local -from .constants import LANGUAGES, WORD, COMMA +from .constants import LANGUAGES from .utility import CCCEDICT, TTS, DictionaryResult, ProcessFile, TranslationResult # Constants @@ -31,10 +31,8 @@ def dictation_process( audio_line = audio_line.replace(",", ",。。。]") audio_path = process_file.resources / f"N{n:03n}.wav" if not audio_path.exists(): - audio = TTS.MODEL.generate( - f"{audio_line}。", language_id=LANGUAGES.CN, **TTS.DEFAULTS - ) - torchaudio.save(audio_path, audio, TTS.MODEL.sr) + wavs, sr = TTS.generate(f"{audio_line}。") + torchaudio.save(audio_path, wavs[0], sr) translated = argostranslate.translate.translate( line, LANGUAGES.CN, process_file.language_id ) @@ -56,10 +54,8 @@ def translator_process( audio_line = audio_line.replace(",", ",。。。]") audio_path = process_file.resources / f"N{n:03n}.wav" if not audio_path.exists(): - audio = TTS.MODEL.generate( - f"{audio_line}。", language_id=LANGUAGES.CN, **TTS.DEFAULTS - ) - torchaudio.save(audio_path, audio, TTS.MODEL.sr) + wavs, sr = TTS.generate(f"{audio_line}。") + torchaudio.save(audio_path, wavs[0], sr) translated = argostranslate.translate.translate( line, LANGUAGES.CN, process_file.language_id ) @@ -121,10 +117,8 @@ def dictionary_process(process_file: ProcessFile) -> list[DictionaryResult]: for line in reader: audio_path = process_file.resources / f"{line['pinyin']}.wav" if not audio_path.exists(): - audio = TTS.MODEL.generate( - f"{line['simplified']}。", language_id=LANGUAGES.CN, **TTS.DEFAULTS - ) - torchaudio.save(audio_path, audio, TTS.MODEL.sr) + wavs, sr = TTS.generate(f"{line['simplified']}。") + torchaudio.save(audio_path, wavs[0], sr) print(line) result = DictionaryResult( **line, audio_path=audio_path, language_id=process_file.language_id diff --git a/src/anki_hsk_creator/utility.py b/src/anki_hsk_creator/utility.py index 535dec6..ff063dd 100644 --- a/src/anki_hsk_creator/utility.py +++ b/src/anki_hsk_creator/utility.py @@ -12,10 +12,10 @@ import argostranslate.package import argostranslate.translate import torch from cedict_utils.cedict import CedictEntry, CedictParser -from chatterbox.mtl_tts import ChatterboxMultilingualTTS +from qwen_tts import Qwen3TTSModel # Local -from .constants import CCCEDICT_PATH, INPUT, LANGUAGES, OUTPUT, RESOURCES +from .constants import CCCEDICT_PATH, GWEN_TTS, INPUT, LANGUAGES, OUTPUT, RESOURCES # Static Clases @@ -50,10 +50,12 @@ class TRANS: if out_package.to_code == to_code: if in_package.to_code == out_package.from_code: print( - f"Check in_package {in_package.from_code} {in_package.to_code}" + f"Check in_package {in_package.from_code}" + f"{in_package.to_code}" ) print( - f"Check out_package {out_package.from_code} {out_package.to_code}" + f"Check out_package {out_package.from_code}" + f"{out_package.to_code}" ) packages_to_install.append(in_package) packages_to_install.append(out_package) @@ -137,7 +139,11 @@ class TTS: MODEL = None DEVICE = None - DEFAULTS = {"cfg_weight": 0.2, "exaggeration": 0.8} + DEFAULTS = { + "language": "Chinese", + "speaker": "Uncle_Fu", + "instruct": "语速缓慢而审慎,每个音节的语调都拿捏得恰到好处,宛如教授在指导新生。", + } @staticmethod def create_tts(): @@ -151,10 +157,18 @@ class TTS: else: TTS.DEVICE = "cpu" if TTS.MODEL is None: - TTS.MODEL = ChatterboxMultilingualTTS.from_pretrained( - device=TTS.DEVICE, t3_model="v3" + TTS.MODEL = Qwen3TTSModel.from_pretrained( + GWEN_TTS, + device_map=TTS.DEVICE, + dtype=torch.bfloat16, + # attn_implementation="flash_attention_2", ) + @staticmethod + def generate(text: str): + """Generates a Waw using the defaulst values""" + return TTS.MODEL.generate_custom_voice(text=text, **TTS.DEFAULTS) + # Clases