Клонирование голоса и озвучка текста бесплатно с Qwen3-TTS (Windows, RTX 3060)
Этот гайд показывает, как озвучить русский текст из файла TXT вашим голосом локально на ПК. Мы используем Qwen3-TTS и режим voice cloning: вы даете короткий референсный фрагмент своего голоса (ref.wav) и текст, который в нем произнесен (ref_text_ru.txt), а затем модель озвучивает article_ru.txt в похожем тембре.
Ориентировано на конфигурацию:
- Windows 11
- NVIDIA RTX 3060 Ti, 8 GB VRAM
- 32 GB RAM
- Python 3.12
- venv
- PyTorch CUDA 12.4
Важно про железо
На 8 GB VRAM начинайте с модели 0.6B. Модель 1.7B можно пробовать позже, но это уже режим экспериментов: выше риск нехватки VRAM и ниже предсказуемость.
Почему в гайде FP32, а не FP16
На Windows вы можете столкнуться с падением CUDA вида device-side assert triggered при FP16. Поэтому в инструкции сразу используем dtype=torch.float32. Это медленнее, но стабильнее.
Подготовьте папку проекта - шаг 1
Рекомендуемая структура:
\voice\
├── .venv\
├── tts_ru_clone.py
├── article_ru.txt
├── ref.wav
└── ref_text_ru.txt
Файлы:
- article_ru.txt: текст статьи в UTF-8
- ref.wav: ваш голос, референс
- ref_text_ru.txt: точная расшифровка того, что сказано в ref.wav
Требования к ref.wav
- WAV, mono, 16 kHz
- Минимум 3 секунды, но лучше 15-30 секунд чистой речи
- Без музыки, без эха, без шумодава, без пережатия мессенджерами
- ref_text_ru.txt должен совпадать со словами в ref.wav. Если не совпадает, качество клона ухудшается
Установите SoX и добавьте в PATH - шаг 2
Qwen3-TTS пайплайн для аудио на Windows часто ожидает наличие sox.exe. Без него вы получите ошибку SoX could not be found.
2.1 Скачать и установить
SoX можно скачать со страницы проекта на SourceForge (https://sourceforge.net/projects/sox/) и установить как обычную программу.
2.2 Добавить SoX в PATH
У вас SoX может лежать здесь:
C:\Program Files (x86)\sox-14-4-2\sox.exe
Добавляем в PATH именно папку:
C:\Program Files (x86)\sox-14-4-2
Шаги:
- Нажмите Win и введите: Изменение переменных среды (environment variables)
- Откройте: Изменение переменных среды для вашей учетной записи (Edit environment variables for your account)
- В блоке Переменные пользователя (User variables) найдите Path и нажмите Изменить (Edit)

- Нажмите Создать (New)
- Вставьте: C:\Program Files (x86)\sox-14-4-2 или ваш путь

- Нажмите ОК во всех окнах (OK)
- Закройте все окна PowerShell и откройте новый PowerShell
2.3 Проверка в PowerShell
where.exe sox
sox --version
Если команда sox --version выводит версию, все готово.
Создайте venv и установите зависимости - шаг 3
Откройте PowerShell в папке проекта. Создайте виртуальное окружение и активируйте его:
python -m venv .venv
.\.venv\Scripts\activate
Обновите pip:
python -m pip install -U pip
Установите PyTorch под CUDA 12.4:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
Установите qwen-tts и утилиты:
pip install -U qwen-tts soundfile numpy "huggingface_hub[hf_xet]" hf_xet
Проверьте, что PyTorch видит GPU:
python -c "import torch; print(torch.__version__); print(torch.cuda.is_available()); print(torch.version.cuda); print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else None)"
Клон голоса + озвучка TXT + склейка WAV - шаг 4
Создайте файл tts_ru_clone.py в папке проекта:
import os
import re
import time
import subprocess
from pathlib import Path
import numpy as np
import soundfile as sf
import torch
from qwen_tts import Qwen3TTSModel
SOX_DIR = r"C:\Program Files (x86)\sox-14-4-2" # папка с sox.exe
ARTICLE_PATH = Path("article_ru.txt")
REF_AUDIO_PATH = Path("ref.wav")
REF_TEXT_PATH = Path("ref_text_ru.txt")
OUT_PATH = Path("out_ru.wav")
MODEL_ID = "Qwen/Qwen3-TTS-12Hz-0.6B-Base"
MAX_CHARS = 600
SILENCE_MS = 120
HF_DOWNLOAD_TIMEOUT = "600"
HF_ETAG_TIMEOUT = "120"
HF_DISABLE_XET = "" # если будут таймауты на xethub, поставьте "1"
def _ensure_env():
os.environ["PATH"] = SOX_DIR + ";" + os.environ.get("PATH", "")
os.environ.setdefault("HF_HUB_DOWNLOAD_TIMEOUT", HF_DOWNLOAD_TIMEOUT)
os.environ.setdefault("HF_HUB_ETAG_TIMEOUT", HF_ETAG_TIMEOUT)
os.environ.setdefault("HF_HUB_DISABLE_SYMLINKS_WARNING", "1")
if HF_DISABLE_XET.strip():
os.environ["HF_HUB_DISABLE_XET"] = HF_DISABLE_XET.strip()
def _check_sox():
out = subprocess.check_output(["sox", "--version"], text=True).strip()
print(f"[env] {out}")
def split_text_ru(text: str, max_chars: int) -> list[str]:
text = re.sub(r"\s+", " ", text).strip()
if not text:
return []
parts = re.split(r"(?<=[\.\!\?…])\s+", text)
chunks, buf = [], ""
for p in parts:
p = p.strip()
if not p:
continue
if not buf:
buf = p
continue
if len(buf) + 1 + len(p) <= max_chars:
buf = buf + " " + p
else:
chunks.append(buf)
buf = p
if buf:
chunks.append(buf)
return chunks
def concat_wavs(wavs: list[np.ndarray], sr: int, silence_ms: int) -> np.ndarray:
silence = np.zeros(int(sr * (silence_ms / 1000.0)), dtype=np.float32)
out = []
for w in wavs:
out.append(np.asarray(w, dtype=np.float32).reshape(-1))
out.append(silence)
return np.concatenate(out, axis=0) if out else np.zeros((0,), dtype=np.float32)
def main():
_ensure_env()
_check_sox()
# На Windows FP16 иногда падает с CUDA assert, поэтому фиксируем FP32.
torch.backends.cuda.matmul.allow_tf32 = True
torch.set_float32_matmul_precision("high")
print("1) reading inputs...")
text = ARTICLE_PATH.read_text(encoding="utf-8")
chunks = split_text_ru(text, MAX_CHARS)
if not chunks:
raise SystemExit("Пустой article_ru.txt")
ref_text = REF_TEXT_PATH.read_text(encoding="utf-8").strip()
if not ref_text:
raise SystemExit("Пустой ref_text_ru.txt")
print(f" chunks: {len(chunks)} (MAX_CHARS={MAX_CHARS})")
print("2) loading model (first run can be slow)...")
t0 = time.time()
model = Qwen3TTSModel.from_pretrained(
MODEL_ID,
device_map="cuda:0",
dtype=torch.float32,
)
print(f"3) model loaded in {time.time() - t0:.1f}s")
print("4) building voice clone prompt...")
t1 = time.time()
voice_prompt = model.create_voice_clone_prompt(
ref_audio=str(REF_AUDIO_PATH),
ref_text=ref_text,
x_vector_only_mode=False,
)
print(f"5) voice prompt ready in {time.time() - t1:.1f}s")
print(f"6) generating audio for {len(chunks)} chunks...")
all_wavs = []
sr_final = None
for i, chunk in enumerate(chunks, 1):
tg0 = time.time()
wavs, sr = model.generate_voice_clone(
text=chunk,
language="Russian",
voice_clone_prompt=voice_prompt,
)
wav = wavs[0]
all_wavs.append(wav)
sr_final = sr
print(f" [{i}/{len(chunks)}] ok: {len(wav)/sr:.2f}s, gen_time={time.time() - tg0:.1f}s")
print("7) saving wav...")
audio = concat_wavs(all_wavs, sr_final, SILENCE_MS)
sf.write(str(OUT_PATH), audio, sr_final)
print(f"Done. Saved: {OUT_PATH.resolve()}")
if __name__ == "__main__":
main()
Запуск клонирования голоса и озвучки текста - шаг 5
Убедитесь, что venv активирован. Запустите скрипт:
python tts_ru_clone.py
Результат: out_ru.wav в той же папке.
Первый запуск может быть долгим. При первом запуске модель скачивается и загружается. Это нормально. Следующие запуски обычно заметно быстрее.
Частые проблемы и решения
SoX could not be found
Симптом: скрипт ругается, что SoX не найден.
Проверка:
where.exe sox
sox --version
Решение:
- Добавьте папку SoX в PATH как в шаге 2.
- Если запускаете из IDE, PATH может отличаться. В скрипте SOX_DIR принудительно добавляет путь для процесса Python, убедитесь, что SOX_DIR указывает на: C:\Program Files (x86)\sox-14-4-2
ReadTimeout при скачивании модели с Hugging Face
Симптом: таймауты на xethub или cas-bridge.
Решение 1: увеличить таймауты в PowerShell перед запуском
$env:HF_HUB_DOWNLOAD_TIMEOUT="600"
$env:HF_HUB_ETAG_TIMEOUT="120"
python tts_ru_clone.py
Решение 2: отключить Xet, если сеть нестабильна
$env:HF_HUB_DISABLE_XET="1"
python tts_ru_clone.py
Warning про symlinks на Windows
Симптом: предупреждение, что кэш Hugging Face не может использовать symlinks.
Это не ломает работу, но кэш может занимать больше места.
Решения:
- Игнорировать
- Включить Developer Mode в Windows
- Или убрать предупреждение:
$env:HF_HUB_DISABLE_SYMLINKS_WARNING="1"
python tts_ru_clone.py
CUDA error: device-side assert triggered
Симптом: падение на генерации, часто после установки pad_token_id.
Решение:
- Используйте FP32 на Windows. В этом гайде уже стоит dtype=torch.float32.
CUDA out of memory
Симптом: нехватка видеопамяти.
Решения:
- Уменьшите MAX_CHARS до 300-400
- Закройте приложения, которые держат VRAM
- Оставайтесь на 0.6B
Как попробовать 1.7B на 8 GB VRAM
Сначала добейтесь стабильной работы 0.6B.
Если хотите тест 1.7B:
- Поменяйте MODEL_ID на 1.7B Base
- Поставьте MAX_CHARS 300
- Запустите и следите за nvidia-smi Если получите OOM или станет слишком медленно, возвращайтесь на 0.6B.
Примечание про нормализацию громкости
Если нужно выровнять громкость, это обычно делают постобработкой (например ffmpeg loudnorm или sox gain). В этом туториале я намеренно не добавляю нормализацию в код, чтобы оставить минимально надежный путь.
Авторизуйтесь, чтобы оставить комментарий.
Нет комментариев.