diff --git a/README.md b/README.md index e919d5d..b77a31c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@
@@ -174,9 +174,12 @@ will install the correct versions of all dependencies into your `.venv` director uv sync --all-extras ``` -If the download is slow, please try a *local mirror*, for example China: +If the download is slow, please try a *local mirror*, for example any of these +local mirrors in China (choose one mirror from the list below): ```bash +uv sync --all-extras --default-index "https://mirrors.aliyun.com/pypi/simple" + uv sync --all-extras --default-index "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" ``` @@ -186,7 +189,8 @@ uv sync --all-extras --default-index "https://mirrors.tuna.tsinghua.edu.cn/pypi/ > - `--all-extras`: Automatically adds *every* extra feature listed below. You can > remove this flag if you want to customize your installation choices. > - `--extra webui`: Adds WebUI support (recommended). -> - `--extra deepspeed`: Adds DeepSpeed support (faster inference). +> - `--extra deepspeed`: Adds DeepSpeed support (may speed up inference on some +> systems). > [!IMPORTANT] > **Important (Windows):** The DeepSpeed library may be difficult to install for @@ -259,6 +263,12 @@ uv run webui.py -h Have fun! +> [!IMPORTANT] +> **DeepSpeed** *may* speed up inference on some systems, but it could also +> make it slower. The performance impact is highly dependent on your specific +> hardware, drivers and operating system. Please try with and without it, +> to discover what works best on your personal system. + #### 📝 Using IndexTTS2 in Python @@ -311,6 +321,10 @@ tts.infer(spk_audio_prompt='examples/voice_07.wav', text=text, output_path="gen. during inference; the default is `False`, and setting it to `True` enables randomness: +> [!NOTE] +> Enabling random sampling will reduce the voice cloning fidelity of the speech +> synthesis. + ```python from indextts.infer_v2 import IndexTTS2 tts = IndexTTS2(cfg_path="checkpoints/config.yaml", model_dir="checkpoints", use_fp16=False, use_cuda_kernel=False, use_deepspeed=False) @@ -321,6 +335,8 @@ tts.infer(spk_audio_prompt='examples/voice_10.wav', text=text, output_path="gen. 5. Alternatively, you can enable `use_emo_text` to guide the emotions based on your provided `text` script. Your text script will then automatically be converted into emotion vectors. + It's recommended to use `emo_alpha` around 0.6 (or lower) when using the text + emotion modes, for more natural sounding speech. You can introduce randomness with `use_random` (default: `False`; `True` enables randomness): @@ -328,7 +344,7 @@ tts.infer(spk_audio_prompt='examples/voice_10.wav', text=text, output_path="gen. from indextts.infer_v2 import IndexTTS2 tts = IndexTTS2(cfg_path="checkpoints/config.yaml", model_dir="checkpoints", use_fp16=False, use_cuda_kernel=False, use_deepspeed=False) text = "快躲起来!是他要来了!他要来抓我们了!" -tts.infer(spk_audio_prompt='examples/voice_12.wav', text=text, output_path="gen.wav", use_emo_text=True, use_random=False, verbose=True) +tts.infer(spk_audio_prompt='examples/voice_12.wav', text=text, output_path="gen.wav", emo_alpha=0.6, use_emo_text=True, use_random=False, verbose=True) ``` 6. It's also possible to directly provide a specific text emotion description @@ -341,7 +357,7 @@ from indextts.infer_v2 import IndexTTS2 tts = IndexTTS2(cfg_path="checkpoints/config.yaml", model_dir="checkpoints", use_fp16=False, use_cuda_kernel=False, use_deepspeed=False) text = "快躲起来!是他要来了!他要来抓我们了!" emo_text = "你吓死我了!你是鬼吗?" -tts.infer(spk_audio_prompt='examples/voice_12.wav', text=text, output_path="gen.wav", use_emo_text=True, emo_text=emo_text, use_random=False, verbose=True) +tts.infer(spk_audio_prompt='examples/voice_12.wav', text=text, output_path="gen.wav", emo_alpha=0.6, use_emo_text=True, emo_text=emo_text, use_random=False, verbose=True) ``` diff --git a/doc/README_zh.md b/docs/README_zh.md similarity index 98% rename from doc/README_zh.md rename to docs/README_zh.md index 01941c8..2fba98d 100644 --- a/doc/README_zh.md +++ b/docs/README_zh.md @@ -153,6 +153,8 @@ uv sync --all-extras 如中国大陆地区用户下载缓慢,可选用国内镜像: ```bash +uv sync --all-extras --default-index "https://mirrors.aliyun.com/pypi/simple" + uv sync --all-extras --default-index "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" ``` @@ -259,9 +261,9 @@ tts.infer(spk_audio_prompt='examples/voice_07.wav', text=text, output_path="gen. ``` 4. 可直接指定8维情感向量 `[高兴, 愤怒, 悲伤, 害怕, 厌恶, 忧郁, 惊讶, 平静]`,可用`use_random`开启随机情感采样(默认False): + > [!NOTE] > 开启随机采样会降低音色的还原度。 -> ```python from indextts.infer_v2 import IndexTTS2 @@ -276,7 +278,7 @@ tts.infer(spk_audio_prompt='examples/voice_10.wav', text=text, output_path="gen. from indextts.infer_v2 import IndexTTS2 tts = IndexTTS2(cfg_path="checkpoints/config.yaml", model_dir="checkpoints", use_fp16=False, use_cuda_kernel=False, use_deepspeed=False) text = "快躲起来!是他要来了!他要来抓我们了!" -tts.infer(spk_audio_prompt='examples/voice_12.wav', text=text, output_path="gen.wav", use_emo_text=True, use_random=False, verbose=True) +tts.infer(spk_audio_prompt='examples/voice_12.wav', text=text, output_path="gen.wav", emo_alpha=0.6, use_emo_text=True, use_random=False, verbose=True) ``` 6. 可直接指定情感文本描述(`emo_text`),实现文本与情感分离控制: @@ -286,7 +288,7 @@ from indextts.infer_v2 import IndexTTS2 tts = IndexTTS2(cfg_path="checkpoints/config.yaml", model_dir="checkpoints", use_fp16=False, use_cuda_kernel=False, use_deepspeed=False) text = "快躲起来!是他要来了!他要来抓我们了!" emo_text = "你吓死我了!你是鬼吗?" -tts.infer(spk_audio_prompt='examples/voice_12.wav', text=text, output_path="gen.wav", use_emo_text=True, emo_text=emo_text, use_random=False, verbose=True) +tts.infer(spk_audio_prompt='examples/voice_12.wav', text=text, output_path="gen.wav", emo_alpha=0.6, use_emo_text=True, emo_text=emo_text, use_random=False, verbose=True) ``` ### 旧版IndexTTS1使用指南 diff --git a/indextts/cli.py b/indextts/cli.py index 5349901..39cd047 100644 --- a/indextts/cli.py +++ b/indextts/cli.py @@ -47,10 +47,10 @@ def main(): if args.device is None: if torch.cuda.is_available(): args.device = "cuda:0" - elif torch.mps.is_available(): - args.device = "mps" - elif torch.xpu.is_available(): + elif hasattr(torch, "xpu") and torch.xpu.is_available(): args.device = "xpu" + elif hasattr(torch, "mps") and torch.mps.is_available(): + args.device = "mps" else: args.device = "cpu" args.fp16 = False # Disable FP16 on CPU diff --git a/indextts/infer.py b/indextts/infer.py index c776b74..f137f25 100644 --- a/indextts/infer.py +++ b/indextts/infer.py @@ -291,9 +291,9 @@ class IndexTTS: - 越大,bucket数量越少,batch越多,推理速度越*快*,占用内存更多,可能影响质量 - 越小,bucket数量越多,batch越少,推理速度越*慢*,占用内存和质量更接近于非快速推理 """ - print(">> start fast inference...") + print(">> starting fast inference...") - self._set_gr_progress(0, "start fast inference...") + self._set_gr_progress(0, "starting fast inference...") if verbose: print(f"origin text:{text}") start_time = time.perf_counter() @@ -385,7 +385,7 @@ class IndexTTS: processed_num += batch_num # gpt speech self._set_gr_progress(0.2 + 0.3 * processed_num / all_batch_num, - f"gpt inference speech... {processed_num}/{all_batch_num}") + f"gpt speech inference {processed_num}/{all_batch_num}...") m_start_time = time.perf_counter() with torch.no_grad(): with torch.amp.autocast(batch_text_tokens.device.type, enabled=self.dtype is not None, @@ -407,7 +407,7 @@ class IndexTTS: gpt_gen_time += time.perf_counter() - m_start_time # gpt latent - self._set_gr_progress(0.5, "gpt inference latents...") + self._set_gr_progress(0.5, "gpt latents inference...") all_idxs = [] all_latents = [] has_warned = False @@ -456,7 +456,7 @@ class IndexTTS: latent_length = len(all_latents) # bigvgan chunk decode - self._set_gr_progress(0.7, "bigvgan decode...") + self._set_gr_progress(0.7, "bigvgan decoding...") tqdm_progress = tqdm(total=latent_length, desc="bigvgan") for items in chunk_latents: tqdm_progress.update(len(items)) @@ -478,7 +478,7 @@ class IndexTTS: self.torch_empty_cache() # wav audio output - self._set_gr_progress(0.9, "save audio...") + self._set_gr_progress(0.9, "saving audio...") wav = torch.cat(wavs, dim=1) wav_length = wav.shape[-1] / sampling_rate print(f">> Reference audio length: {cond_mel_frame * 256 / sampling_rate:.2f} seconds") @@ -509,8 +509,8 @@ class IndexTTS: # 原始推理模式 def infer(self, audio_prompt, text, output_path, verbose=False, max_text_tokens_per_segment=120, **generation_kwargs): - print(">> start inference...") - self._set_gr_progress(0, "start inference...") + print(">> starting inference...") + self._set_gr_progress(0, "starting inference...") if verbose: print(f"origin text:{text}") start_time = time.perf_counter() @@ -578,7 +578,7 @@ class IndexTTS: # print(text_len) progress += 1 self._set_gr_progress(0.2 + 0.4 * (progress - 1) / len(segments), - f"gpt inference latent... {progress}/{len(segments)}") + f"gpt latents inference {progress}/{len(segments)}...") m_start_time = time.perf_counter() with torch.no_grad(): with torch.amp.autocast(text_tokens.device.type, enabled=self.dtype is not None, dtype=self.dtype): @@ -620,7 +620,7 @@ class IndexTTS: print(f"fix codes shape: {codes.shape}, codes type: {codes.dtype}") print(f"code len: {code_lens}") self._set_gr_progress(0.2 + 0.4 * progress / len(segments), - f"gpt inference speech... {progress}/{len(segments)}") + f"gpt speech inference {progress}/{len(segments)}...") m_start_time = time.perf_counter() # latent, text_lens_out, code_lens_out = \ with torch.amp.autocast(text_tokens.device.type, enabled=self.dtype is not None, dtype=self.dtype): @@ -644,7 +644,7 @@ class IndexTTS: # wavs.append(wav[:, :-512]) wavs.append(wav.cpu()) # to cpu before saving end_time = time.perf_counter() - self._set_gr_progress(0.9, "save audio...") + self._set_gr_progress(0.9, "saving audio...") wav = torch.cat(wavs, dim=1) wav_length = wav.shape[-1] / sampling_rate print(f">> Reference audio length: {cond_mel_frame * 256 / sampling_rate:.2f} seconds") diff --git a/indextts/infer_v2.py b/indextts/infer_v2.py index 7161a58..71c36e1 100644 --- a/indextts/infer_v2.py +++ b/indextts/infer_v2.py @@ -298,37 +298,45 @@ class IndexTTS2: emo_vector=None, use_emo_text=False, emo_text=None, use_random=False, interval_silence=200, verbose=False, max_text_tokens_per_segment=120, **generation_kwargs): - print(">> start inference...") - self._set_gr_progress(0, "start inference...") + print(">> starting inference...") + self._set_gr_progress(0, "starting inference...") if verbose: - print(f"origin text:{text}, spk_audio_prompt:{spk_audio_prompt}," - f" emo_audio_prompt:{emo_audio_prompt}, emo_alpha:{emo_alpha}, " + print(f"origin text:{text}, spk_audio_prompt:{spk_audio_prompt}, " + f"emo_audio_prompt:{emo_audio_prompt}, emo_alpha:{emo_alpha}, " f"emo_vector:{emo_vector}, use_emo_text:{use_emo_text}, " f"emo_text:{emo_text}") start_time = time.perf_counter() - if use_emo_text: + if use_emo_text or emo_vector is not None: + # we're using a text or emotion vector guidance; so we must remove + # "emotion reference voice", to ensure we use correct emotion mixing! emo_audio_prompt = None - emo_alpha = 1.0 - # assert emo_audio_prompt is None - # assert emo_alpha == 1.0 + + if use_emo_text: + # automatically generate emotion vectors from text prompt if emo_text is None: - emo_text = text + emo_text = text # use main text prompt emo_dict = self.qwen_emo.inference(emo_text) - print(emo_dict) + print(f"detected emotion vectors from text: {emo_dict}") # convert ordered dict to list of vectors; the order is VERY important! emo_vector = list(emo_dict.values()) if emo_vector is not None: - emo_audio_prompt = None - emo_alpha = 1.0 - # assert emo_audio_prompt is None - # assert emo_alpha == 1.0 + # we have emotion vectors; they can't be blended via alpha mixing + # in the main inference process later, so we must pre-calculate + # their new strengths here based on the alpha instead! + emo_vector_scale = max(0.0, min(1.0, emo_alpha)) + if emo_vector_scale != 1.0: + # scale each vector and truncate to 4 decimals (for nicer printing) + emo_vector = [int(x * emo_vector_scale * 10000) / 10000 for x in emo_vector] + print(f"scaled emotion vectors to {emo_vector_scale}x: {emo_vector}") if emo_audio_prompt is None: + # we are not using any external "emotion reference voice"; use + # speaker's voice as the main emotion reference audio. emo_audio_prompt = spk_audio_prompt + # must always use alpha=1.0 when we don't have an external reference voice emo_alpha = 1.0 - # assert emo_alpha == 1.0 # 如果参考音频改变了,才需要重新生成, 提升速度 if self.cache_spk_cond is None or self.cache_spk_audio_prompt != spk_audio_prompt: @@ -400,9 +408,10 @@ class IndexTTS2: self._set_gr_progress(0.1, "text processing...") text_tokens_list = self.tokenizer.tokenize(text) segments = self.tokenizer.split_segments(text_tokens_list, max_text_tokens_per_segment) + segments_count = len(segments) if verbose: print("text_tokens_list:", text_tokens_list) - print("segments count:", len(segments)) + print("segments count:", segments_count) print("max_text_tokens_per_segment:", max_text_tokens_per_segment) print(*segments, sep="\n") do_sample = generation_kwargs.pop("do_sample", True) @@ -421,9 +430,11 @@ class IndexTTS2: gpt_forward_time = 0 s2mel_time = 0 bigvgan_time = 0 - progress = 0 has_warned = False - for sent in segments: + for seg_idx, sent in enumerate(segments): + self._set_gr_progress(0.2 + 0.7 * seg_idx / segments_count, + f"speech synthesis {seg_idx + 1}/{segments_count}...") + text_tokens = self.tokenizer.convert_tokens_to_ids(sent) text_tokens = torch.tensor(text_tokens, dtype=torch.int32, device=self.device).unsqueeze(0) if verbose: @@ -553,7 +564,8 @@ class IndexTTS2: # wavs.append(wav[:, :-512]) wavs.append(wav.cpu()) # to cpu before saving end_time = time.perf_counter() - self._set_gr_progress(0.9, "save audio...") + + self._set_gr_progress(0.9, "saving audio...") wavs = self.insert_interval_silence(wavs, sampling_rate=sampling_rate, interval_silence=interval_silence) wav = torch.cat(wavs, dim=1) wav_length = wav.shape[-1] / sampling_rate diff --git a/pyproject.toml b/pyproject.toml index 73207cb..75cf2f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,7 +65,7 @@ dependencies = [ [project.optional-dependencies] # To install the WebUI support, use `uv sync --extra webui` (or `--all-extras`). webui = [ - "gradio>=5.44.1", + "gradio==5.44.1", ] # To install the DeepSpeed support, use `uv sync --extra deepspeed` (or `--all-extras`). deepspeed = [ diff --git a/tools/gpu_check.py b/tools/gpu_check.py index f6ea8f9..2fe2730 100644 --- a/tools/gpu_check.py +++ b/tools/gpu_check.py @@ -1,47 +1,85 @@ import torch -def show_cuda_gpu_list() -> None: +def show_device_list(backend: str) -> int: """ - Displays a list of all detected GPUs that support the CUDA Torch APIs. + Displays a list of all detected devices for a given PyTorch backend. + + Args: + backend: The name of the device backend module (e.g., "cuda", "xpu"). + + Returns: + The number of devices found if the backend is usable, otherwise 0. """ - num_gpus = torch.cuda.device_count() - print(f"Number of GPUs found: {num_gpus}") + backend_upper = backend.upper() - for i in range(num_gpus): - gpu_name = torch.cuda.get_device_name(i) - print(f'GPU {i}: "{gpu_name}"') + try: + # Get the backend module from PyTorch, e.g., `torch.cuda`. + # NOTE: Backends always exist even if the user has no devices. + backend_module = getattr(torch, backend) + + # Determine which vendor brand name to display. + brand_name = backend_upper + if backend == "cuda": + # NOTE: This also checks for PyTorch's official AMD ROCm support, + # since that's implemented inside the PyTorch CUDA APIs. + # SEE: https://docs.pytorch.org/docs/stable/cuda.html + brand_name = "NVIDIA CUDA / AMD ROCm" + elif backend == "xpu": + brand_name = "Intel XPU" + elif backend == "mps": + brand_name = "Apple MPS" + + if not backend_module.is_available(): + print(f"PyTorch: No devices found for {brand_name} backend.") + return 0 + + print(f"PyTorch: {brand_name} is available!") + + # Show all available hardware acceleration devices. + device_count = backend_module.device_count() + print(f" * Number of {backend_upper} devices found: {device_count}") + + # NOTE: Apple Silicon devices don't have `get_device_name()` at the + # moment, so we'll skip those since we can't get their device names. + # SEE: https://docs.pytorch.org/docs/stable/mps.html + if backend != "mps": + for i in range(device_count): + device_name = backend_module.get_device_name(i) + print(f' * Device {i}: "{device_name}"') + + return device_count + + except AttributeError: + print( + f'Error: The PyTorch backend "{backend}" does not exist, or is missing the necessary APIs (is_available, device_count, get_device_name).' + ) + except Exception as e: + print(f"Error: {e}") + + return 0 -def check_torch_gpus() -> None: +def check_torch_devices() -> None: """ - Checks for the availability of various PyTorch GPU acceleration platforms - and prints information about the discovered GPUs. + Checks for the availability of various PyTorch hardware acceleration + platforms and prints information about the discovered devices. """ - # Check for AMD ROCm/HIP first, since it modifies the CUDA APIs. - # NOTE: The unofficial ROCm/HIP backend exposes the AMD features through - # the CUDA Torch API calls. - if hasattr(torch.backends, "hip") and torch.backends.hip.is_available(): - print("PyTorch: AMD ROCm/HIP is available!") - show_cuda_gpu_list() + print("Scanning for PyTorch hardware acceleration devices...\n") - # Check for NVIDIA CUDA. - elif torch.cuda.is_available(): - print("PyTorch: NVIDIA CUDA is available!") - show_cuda_gpu_list() + device_count = 0 - # Check for Apple Metal Performance Shaders (MPS). - elif torch.backends.mps.is_available(): - print("PyTorch: Apple MPS is available!") - # PyTorch with MPS doesn't have a direct equivalent of `device_count()` - # or `get_device_name()` for now, so we just confirm its presence. - print("Using Apple Silicon GPU.") + device_count += show_device_list("cuda") # NVIDIA CUDA / AMD ROCm. + device_count += show_device_list("xpu") # Intel XPU. + device_count += show_device_list("mps") # Apple Metal Performance Shaders (MPS). + if device_count > 0: + print("\nHardware acceleration detected. Your system is ready!") else: - print("PyTorch: No GPU acceleration detected. Running in CPU mode.") + print("\nNo hardware acceleration detected. Running in CPU mode.") if __name__ == "__main__": - check_torch_gpus() + check_torch_devices() diff --git a/uv.lock b/uv.lock index 880b5da..f88e9b1 100644 --- a/uv.lock +++ b/uv.lock @@ -1213,7 +1213,7 @@ requires-dist = [ { name = "einops", specifier = ">=0.8.1" }, { name = "ffmpeg-python", specifier = "==0.2.0" }, { name = "g2p-en", specifier = "==2.1.0" }, - { name = "gradio", marker = "extra == 'webui'", specifier = ">=5.44.1" }, + { name = "gradio", marker = "extra == 'webui'", specifier = "==5.44.1" }, { name = "jieba", specifier = "==0.42.1" }, { name = "json5", specifier = "==0.10.0" }, { name = "keras", specifier = "==2.9.0" }, @@ -2910,28 +2910,28 @@ wheels = [ [[package]] name = "ruff" -version = "0.12.12" +version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a8/f0/e0965dd709b8cabe6356811c0ee8c096806bb57d20b5019eb4e48a117410/ruff-0.12.12.tar.gz", hash = "sha256:b86cd3415dbe31b3b46a71c598f4c4b2f550346d1ccf6326b347cc0c8fd063d6", size = 5359915, upload-time = "2025-09-04T16:50:18.273Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/1a/1f4b722862840295bcaba8c9e5261572347509548faaa99b2d57ee7bfe6a/ruff-0.13.0.tar.gz", hash = "sha256:5b4b1ee7eb35afae128ab94459b13b2baaed282b1fb0f472a73c82c996c8ae60", size = 5372863, upload-time = "2025-09-10T16:25:37.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/09/79/8d3d687224d88367b51c7974cec1040c4b015772bfbeffac95face14c04a/ruff-0.12.12-py3-none-linux_armv6l.whl", hash = "sha256:de1c4b916d98ab289818e55ce481e2cacfaad7710b01d1f990c497edf217dafc", size = 12116602, upload-time = "2025-09-04T16:49:18.892Z" }, - { url = "https://files.pythonhosted.org/packages/c3/c3/6e599657fe192462f94861a09aae935b869aea8a1da07f47d6eae471397c/ruff-0.12.12-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7acd6045e87fac75a0b0cdedacf9ab3e1ad9d929d149785903cff9bb69ad9727", size = 12868393, upload-time = "2025-09-04T16:49:23.043Z" }, - { url = "https://files.pythonhosted.org/packages/e8/d2/9e3e40d399abc95336b1843f52fc0daaceb672d0e3c9290a28ff1a96f79d/ruff-0.12.12-py3-none-macosx_11_0_arm64.whl", hash = "sha256:abf4073688d7d6da16611f2f126be86523a8ec4343d15d276c614bda8ec44edb", size = 12036967, upload-time = "2025-09-04T16:49:26.04Z" }, - { url = "https://files.pythonhosted.org/packages/e9/03/6816b2ed08836be272e87107d905f0908be5b4a40c14bfc91043e76631b8/ruff-0.12.12-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:968e77094b1d7a576992ac078557d1439df678a34c6fe02fd979f973af167577", size = 12276038, upload-time = "2025-09-04T16:49:29.056Z" }, - { url = "https://files.pythonhosted.org/packages/9f/d5/707b92a61310edf358a389477eabd8af68f375c0ef858194be97ca5b6069/ruff-0.12.12-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42a67d16e5b1ffc6d21c5f67851e0e769517fb57a8ebad1d0781b30888aa704e", size = 11901110, upload-time = "2025-09-04T16:49:32.07Z" }, - { url = "https://files.pythonhosted.org/packages/9d/3d/f8b1038f4b9822e26ec3d5b49cf2bc313e3c1564cceb4c1a42820bf74853/ruff-0.12.12-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b216ec0a0674e4b1214dcc998a5088e54eaf39417327b19ffefba1c4a1e4971e", size = 13668352, upload-time = "2025-09-04T16:49:35.148Z" }, - { url = "https://files.pythonhosted.org/packages/98/0e/91421368ae6c4f3765dd41a150f760c5f725516028a6be30e58255e3c668/ruff-0.12.12-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:59f909c0fdd8f1dcdbfed0b9569b8bf428cf144bec87d9de298dcd4723f5bee8", size = 14638365, upload-time = "2025-09-04T16:49:38.892Z" }, - { url = "https://files.pythonhosted.org/packages/74/5d/88f3f06a142f58ecc8ecb0c2fe0b82343e2a2b04dcd098809f717cf74b6c/ruff-0.12.12-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ac93d87047e765336f0c18eacad51dad0c1c33c9df7484c40f98e1d773876f5", size = 14060812, upload-time = "2025-09-04T16:49:42.732Z" }, - { url = "https://files.pythonhosted.org/packages/13/fc/8962e7ddd2e81863d5c92400820f650b86f97ff919c59836fbc4c1a6d84c/ruff-0.12.12-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:01543c137fd3650d322922e8b14cc133b8ea734617c4891c5a9fccf4bfc9aa92", size = 13050208, upload-time = "2025-09-04T16:49:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/53/06/8deb52d48a9a624fd37390555d9589e719eac568c020b27e96eed671f25f/ruff-0.12.12-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2afc2fa864197634e549d87fb1e7b6feb01df0a80fd510d6489e1ce8c0b1cc45", size = 13311444, upload-time = "2025-09-04T16:49:49.931Z" }, - { url = "https://files.pythonhosted.org/packages/2a/81/de5a29af7eb8f341f8140867ffb93f82e4fde7256dadee79016ac87c2716/ruff-0.12.12-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0c0945246f5ad776cb8925e36af2438e66188d2b57d9cf2eed2c382c58b371e5", size = 13279474, upload-time = "2025-09-04T16:49:53.465Z" }, - { url = "https://files.pythonhosted.org/packages/7f/14/d9577fdeaf791737ada1b4f5c6b59c21c3326f3f683229096cccd7674e0c/ruff-0.12.12-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a0fbafe8c58e37aae28b84a80ba1817f2ea552e9450156018a478bf1fa80f4e4", size = 12070204, upload-time = "2025-09-04T16:49:56.882Z" }, - { url = "https://files.pythonhosted.org/packages/77/04/a910078284b47fad54506dc0af13839c418ff704e341c176f64e1127e461/ruff-0.12.12-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b9c456fb2fc8e1282affa932c9e40f5ec31ec9cbb66751a316bd131273b57c23", size = 11880347, upload-time = "2025-09-04T16:49:59.729Z" }, - { url = "https://files.pythonhosted.org/packages/df/58/30185fcb0e89f05e7ea82e5817b47798f7fa7179863f9d9ba6fd4fe1b098/ruff-0.12.12-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5f12856123b0ad0147d90b3961f5c90e7427f9acd4b40050705499c98983f489", size = 12891844, upload-time = "2025-09-04T16:50:02.591Z" }, - { url = "https://files.pythonhosted.org/packages/21/9c/28a8dacce4855e6703dcb8cdf6c1705d0b23dd01d60150786cd55aa93b16/ruff-0.12.12-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:26a1b5a2bf7dd2c47e3b46d077cd9c0fc3b93e6c6cc9ed750bd312ae9dc302ee", size = 13360687, upload-time = "2025-09-04T16:50:05.8Z" }, - { url = "https://files.pythonhosted.org/packages/c8/fa/05b6428a008e60f79546c943e54068316f32ec8ab5c4f73e4563934fbdc7/ruff-0.12.12-py3-none-win32.whl", hash = "sha256:173be2bfc142af07a01e3a759aba6f7791aa47acf3604f610b1c36db888df7b1", size = 12052870, upload-time = "2025-09-04T16:50:09.121Z" }, - { url = "https://files.pythonhosted.org/packages/85/60/d1e335417804df452589271818749d061b22772b87efda88354cf35cdb7a/ruff-0.12.12-py3-none-win_amd64.whl", hash = "sha256:e99620bf01884e5f38611934c09dd194eb665b0109104acae3ba6102b600fd0d", size = 13178016, upload-time = "2025-09-04T16:50:12.559Z" }, - { url = "https://files.pythonhosted.org/packages/28/7e/61c42657f6e4614a4258f1c3b0c5b93adc4d1f8575f5229d1906b483099b/ruff-0.12.12-py3-none-win_arm64.whl", hash = "sha256:2a8199cab4ce4d72d158319b63370abf60991495fb733db96cd923a34c52d093", size = 12256762, upload-time = "2025-09-04T16:50:15.737Z" }, + { url = "https://files.pythonhosted.org/packages/ac/fe/6f87b419dbe166fd30a991390221f14c5b68946f389ea07913e1719741e0/ruff-0.13.0-py3-none-linux_armv6l.whl", hash = "sha256:137f3d65d58ee828ae136a12d1dc33d992773d8f7644bc6b82714570f31b2004", size = 12187826, upload-time = "2025-09-10T16:24:39.5Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/c92296b1fc36d2499e12b74a3fdb230f77af7bdf048fad7b0a62e94ed56a/ruff-0.13.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:21ae48151b66e71fd111b7d79f9ad358814ed58c339631450c66a4be33cc28b9", size = 12933428, upload-time = "2025-09-10T16:24:43.866Z" }, + { url = "https://files.pythonhosted.org/packages/44/cf/40bc7221a949470307d9c35b4ef5810c294e6cfa3caafb57d882731a9f42/ruff-0.13.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:64de45f4ca5441209e41742d527944635a05a6e7c05798904f39c85bafa819e3", size = 12095543, upload-time = "2025-09-10T16:24:46.638Z" }, + { url = "https://files.pythonhosted.org/packages/f1/03/8b5ff2a211efb68c63a1d03d157e924997ada87d01bebffbd13a0f3fcdeb/ruff-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2c653ae9b9d46e0ef62fc6fbf5b979bda20a0b1d2b22f8f7eb0cde9f4963b8", size = 12312489, upload-time = "2025-09-10T16:24:49.556Z" }, + { url = "https://files.pythonhosted.org/packages/37/fc/2336ef6d5e9c8d8ea8305c5f91e767d795cd4fc171a6d97ef38a5302dadc/ruff-0.13.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cec632534332062bc9eb5884a267b689085a1afea9801bf94e3ba7498a2d207", size = 11991631, upload-time = "2025-09-10T16:24:53.439Z" }, + { url = "https://files.pythonhosted.org/packages/39/7f/f6d574d100fca83d32637d7f5541bea2f5e473c40020bbc7fc4a4d5b7294/ruff-0.13.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd628101d9f7d122e120ac7c17e0a0f468b19bc925501dbe03c1cb7f5415b24", size = 13720602, upload-time = "2025-09-10T16:24:56.392Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c8/a8a5b81d8729b5d1f663348d11e2a9d65a7a9bd3c399763b1a51c72be1ce/ruff-0.13.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afe37db8e1466acb173bb2a39ca92df00570e0fd7c94c72d87b51b21bb63efea", size = 14697751, upload-time = "2025-09-10T16:24:59.89Z" }, + { url = "https://files.pythonhosted.org/packages/57/f5/183ec292272ce7ec5e882aea74937f7288e88ecb500198b832c24debc6d3/ruff-0.13.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f96a8d90bb258d7d3358b372905fe7333aaacf6c39e2408b9f8ba181f4b6ef2", size = 14095317, upload-time = "2025-09-10T16:25:03.025Z" }, + { url = "https://files.pythonhosted.org/packages/9f/8d/7f9771c971724701af7926c14dab31754e7b303d127b0d3f01116faef456/ruff-0.13.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b5e3d883e4f924c5298e3f2ee0f3085819c14f68d1e5b6715597681433f153", size = 13144418, upload-time = "2025-09-10T16:25:06.272Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a6/7985ad1778e60922d4bef546688cd8a25822c58873e9ff30189cfe5dc4ab/ruff-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03447f3d18479df3d24917a92d768a89f873a7181a064858ea90a804a7538991", size = 13370843, upload-time = "2025-09-10T16:25:09.965Z" }, + { url = "https://files.pythonhosted.org/packages/64/1c/bafdd5a7a05a50cc51d9f5711da704942d8dd62df3d8c70c311e98ce9f8a/ruff-0.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fbc6b1934eb1c0033da427c805e27d164bb713f8e273a024a7e86176d7f462cf", size = 13321891, upload-time = "2025-09-10T16:25:12.969Z" }, + { url = "https://files.pythonhosted.org/packages/bc/3e/7817f989cb9725ef7e8d2cee74186bf90555279e119de50c750c4b7a72fe/ruff-0.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8ab6a3e03665d39d4a25ee199d207a488724f022db0e1fe4002968abdb8001b", size = 12119119, upload-time = "2025-09-10T16:25:16.621Z" }, + { url = "https://files.pythonhosted.org/packages/58/07/9df080742e8d1080e60c426dce6e96a8faf9a371e2ce22eef662e3839c95/ruff-0.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2a5c62f8ccc6dd2fe259917482de7275cecc86141ee10432727c4816235bc41", size = 11961594, upload-time = "2025-09-10T16:25:19.49Z" }, + { url = "https://files.pythonhosted.org/packages/6a/f4/ae1185349197d26a2316840cb4d6c3fba61d4ac36ed728bf0228b222d71f/ruff-0.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b7b85ca27aeeb1ab421bc787009831cffe6048faae08ad80867edab9f2760945", size = 12933377, upload-time = "2025-09-10T16:25:22.371Z" }, + { url = "https://files.pythonhosted.org/packages/b6/39/e776c10a3b349fc8209a905bfb327831d7516f6058339a613a8d2aaecacd/ruff-0.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:79ea0c44a3032af768cabfd9616e44c24303af49d633b43e3a5096e009ebe823", size = 13418555, upload-time = "2025-09-10T16:25:25.681Z" }, + { url = "https://files.pythonhosted.org/packages/46/09/dca8df3d48e8b3f4202bf20b1658898e74b6442ac835bfe2c1816d926697/ruff-0.13.0-py3-none-win32.whl", hash = "sha256:4e473e8f0e6a04e4113f2e1de12a5039579892329ecc49958424e5568ef4f768", size = 12141613, upload-time = "2025-09-10T16:25:28.664Z" }, + { url = "https://files.pythonhosted.org/packages/61/21/0647eb71ed99b888ad50e44d8ec65d7148babc0e242d531a499a0bbcda5f/ruff-0.13.0-py3-none-win_amd64.whl", hash = "sha256:48e5c25c7a3713eea9ce755995767f4dcd1b0b9599b638b12946e892123d1efb", size = 13258250, upload-time = "2025-09-10T16:25:31.773Z" }, + { url = "https://files.pythonhosted.org/packages/e1/a3/03216a6a86c706df54422612981fb0f9041dbb452c3401501d4a22b942c9/ruff-0.13.0-py3-none-win_arm64.whl", hash = "sha256:ab80525317b1e1d38614addec8ac954f1b3e662de9d59114ecbf771d00cf613e", size = 12312357, upload-time = "2025-09-10T16:25:35.595Z" }, ] [[package]] diff --git a/webui.py b/webui.py index 6ba60a7..cf81a2b 100644 --- a/webui.py +++ b/webui.py @@ -25,7 +25,7 @@ parser.add_argument("--port", type=int, default=7860, help="Port to run the web parser.add_argument("--host", type=str, default="0.0.0.0", help="Host to run the web UI on") parser.add_argument("--model_dir", type=str, default="./checkpoints", help="Model checkpoints directory") parser.add_argument("--fp16", action="store_true", default=False, help="Use FP16 for inference if available") -parser.add_argument("--use_deepspeed", action="store_true", default=False, help="Use DeepSpeed to accelerate if available") +parser.add_argument("--deepspeed", action="store_true", default=False, help="Use DeepSpeed to accelerate if available") parser.add_argument("--cuda_kernel", action="store_true", default=False, help="Use CUDA kernel for inference if available") parser.add_argument("--gui_seg_tokens", type=int, default=120, help="GUI: Max tokens per generation segment") cmd_args = parser.parse_args() @@ -55,7 +55,7 @@ MODE = 'local' tts = IndexTTS2(model_dir=cmd_args.model_dir, cfg_path=os.path.join(cmd_args.model_dir, "config.yaml"), use_fp16=cmd_args.fp16, - use_deepspeed=cmd_args.use_deepspeed, + use_deepspeed=cmd_args.deepspeed, use_cuda_kernel=cmd_args.cuda_kernel, ) # 支持的语言列表 @@ -126,25 +126,26 @@ def gen_single(emo_control_method,prompt, text, } if type(emo_control_method) is not int: emo_control_method = emo_control_method.value - if emo_control_method == 0: - emo_ref_path = None + if emo_control_method == 0: # emotion from speaker + emo_ref_path = None # remove external reference audio emo_weight = 1.0 - if emo_control_method == 1: - emo_weight = emo_weight - if emo_control_method == 2: + if emo_control_method == 1: # emotion from reference audio + # emo_weight = emo_weight + pass + if emo_control_method == 2: # emotion from custom vectors vec = [vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8] - vec_sum = sum([vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8]) - if vec_sum > 1.5: + if sum(vec) > 1.5: gr.Warning(i18n("情感向量之和不能超过1.5,请调整后重试。")) return else: + # don't use the emotion vector inputs for the other modes vec = None if emo_text == "": # erase empty emotion descriptions; `infer()` will then automatically use the main prompt emo_text = None - print(f"Emo control mode:{emo_control_method},vec:{vec}") + print(f"Emo control mode:{emo_control_method},weight:{emo_weight},vec:{vec}") output = tts.infer(spk_audio_prompt=prompt, text=text, output_path=output_path, emo_audio_prompt=emo_ref_path, emo_alpha=emo_weight, @@ -167,6 +168,7 @@ with gr.Blocks(title="IndexTTS Demo") as demo: