File size: 20,410 Bytes
33acd27 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 |
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"colab_type": "text",
"id": "view-in-github"
},
"source": [
"<a href=\"https://colab.research.google.com/github/thinhlpg/vixtts-demo/blob/dev/viXTTS_Demo.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Yv6wKD48of3x"
},
"source": [
"# 🔥🔥🔥**viXTTS Demo**🗣️🗣️🗣️\n",
"\n",
"- https://github.com/thinhlpg/vixtts-demo/\n",
"- https://github.com/thinhlpg/viVoice\n",
"\n",
"Demo này giúp bạn chạy viXTTS miễn phí trên Google Colab!\n",
"Xem thông tin mô hình tại [đây](https://huggingface.co/capleaf/viXTTS)\n",
"\n",
"Bạn có thể dùng demo này với mục đích:\n",
"- ✅Mục đích cá nhân, học tập, nghiên cứu, thử nghiệm\n",
"\n",
"Bạn **KHÔNG** được dùng demo này với mục đích:\n",
"- ❌Mục đích trái đạo đức, vi phạm pháp luật Việt Nam\n",
"- ❌Tạo ra nội dung gây thù ghét, kỳ thị, bạo lực hoặc nội dung vi phạm bản quyền\n",
"- ❌Giả mạo danh tính hoặc gây hiểu nhầm rằng nội dung được tạo ra bởi một cá nhân hoặc tổ chức khác"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "kIEFgM3gnEZm"
},
"outputs": [],
"source": [
"# @title 1. ⚙️ **Cài đặt**\n",
"# @markdown 👈Nhấn nút này để cài đặt (~5 phút)\n",
"# Change timezone to Vietnam\n",
"!rm /etc/localtime\n",
"!ln -s /usr/share/zoneinfo/Asia/Ho_Chi_Minh /etc/localtime\n",
"!date\n",
"\n",
"print(\" > Cài đặt thư viện...\")\n",
"!rm -rf TTS/\n",
"!git clone --branch add-vietnamese-xtts -q https://github.com/thinhlpg/TTS.git\n",
"!pip install --use-deprecated=legacy-resolver -q -e TTS\n",
"!pip install deepspeed -q\n",
"!pip install -q vinorm==2.0.7\n",
"!pip install -q cutlet\n",
"!pip install -q unidic==1.1.0\n",
"!pip install -q underthesea\n",
"!pip install -q gradio==4.35\n",
"!pip install deepfilternet==0.5.6 -q\n",
"\n",
"import os\n",
"from huggingface_hub import snapshot_download\n",
"\n",
"\n",
"os.system(\"python -m unidic download\")\n",
"print(\" > Tải mô hình...\")\n",
"snapshot_download(repo_id=\"thinhlpg/viXTTS\",\n",
" repo_type=\"model\",\n",
" local_dir=\"model\")\n",
"\n",
"from IPython.display import clear_output\n",
"clear_output()\n",
"print(\" > ✅ Cài đặt hoàn tất, bạn hãy chạy tiếp các bước tiếp theo nhé!\")\n",
"quit()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "oGSVcv3xuWWi"
},
"outputs": [],
"source": [
"# The inference code is adopted from https://github.com/coqui-ai/TTS/blob/dev/TTS/demos/xtts_ft_demo/xtts_demo.py\n",
"# @title 2. 🤗 **Sử dụng**\n",
"# @markdown 👈 Nhấn để chạy.\n",
"# @markdown Nếu gặp lỗi thì cũng nhấn nút này nhé!\n",
"\n",
"# @markdown Lần đầu chạy sẽ hơi lâu, bạn chờ tí nhé!\n",
"\n",
"# @markdown Kết quả sẽ được lưu vào `/content/output`\n",
"\n",
"# @markdown Chọn ngôn ngữ:\n",
"language = \"Tiếng Việt\" # @param [\"Tiếng Việt\", \"Tiếng Anh\",\"Tiếng Tây Ban Nha\", \"Tiếng Pháp\",\"Tiếng Đức\",\"Tiếng Ý\", \"Tiếng Bồ Đào Nha\", \"Tiếng Ba Lan\", \"Tiếng Thổ Nhĩ Kỳ\", \"Tiếng Nga\", \"Tiếng Hà Lan\", \"Tiếng Séc\", \"Tiếng Ả Rập\", \"Tiếng Trung (giản thể)\", \"Tiếng Nhật\", \"Tiếng Hungary\", \"Tiếng Hàn\", \"Tiếng Hindi\"]\n",
"# @markdown Văn bản để đọc. Độ dài tối thiểu mỗi câu nên từ 10 từ để đặt kết quả tốt nhất.\n",
"input_text =\"Xin chào, tôi là một công cụ có khả năng chuyển đổi văn bản thành giọng nói tự nhiên, được phát triển bởi nhóm Nón lá. Tôi có thể hổ trợ người khiếm thị, đọc sách nói, làm trợ lý ảo, review phim, làm waifu để an ủi bạn, và phục vụ nhiều mục đích khác.\" # @param {type:\"string\"}\n",
"# @markdown Chọn giọng mẫu:\n",
"reference_audio = \"model/vi_sample.wav\" # @param [ \"model/user_sample.wav\", \"model/vi_sample.wav\", \"model/samples/nam-calm.wav\", \"model/samples/nam-cham.wav\", \"model/samples/nam-nhanh.wav\", \"model/samples/nam-truyen-cam.wav\", \"model/samples/nu-calm.wav\", \"model/samples/nu-cham.wav\", \"model/samples/nu-luu-loat.wav\", \"model/samples/nu-nhan-nha.wav\", \"model/samples/nu-nhe-nhang.wav\"]\n",
"# @markdown Tự động chuẩn hóa chữ (VD: 20/11 -> hai mươi tháng mười một)\n",
"normalize_text = True # @param {type:\"boolean\"}\n",
"# @markdown In chi tiết xử lý\n",
"verbose = True # @param {type:\"boolean\"}\n",
"# @markdown Lưu từng câu thành file riêng lẻ.\n",
"output_chunks = True # @param {type:\"boolean\"}\n",
"\n",
"from IPython.display import clear_output\n",
"def cry_and_quit():\n",
" clear_output()\n",
" print(\"> Lỗi rồi huhu 😭😭, bạn hãy nhấn chạy lại phần này nhé!\")\n",
" quit()\n",
"\n",
"import os\n",
"import string\n",
"import unicodedata\n",
"from datetime import datetime\n",
"from pprint import pprint\n",
"\n",
"import torch\n",
"import torchaudio\n",
"from tqdm import tqdm\n",
"from underthesea import sent_tokenize\n",
"from unidecode import unidecode\n",
"\n",
"try:\n",
" from vinorm import TTSnorm\n",
" from TTS.tts.configs.xtts_config import XttsConfig\n",
" from TTS.tts.models.xtts import Xtts\n",
"except:\n",
" cry_and_quit()\n",
"\n",
"# Load model\n",
"def clear_gpu_cache():\n",
" if torch.cuda.is_available():\n",
" torch.cuda.empty_cache()\n",
"\n",
"\n",
"def load_model(xtts_checkpoint, xtts_config, xtts_vocab):\n",
" clear_gpu_cache()\n",
" if not xtts_checkpoint or not xtts_config or not xtts_vocab:\n",
" return \"You need to run the previous steps or manually set the `XTTS checkpoint path`, `XTTS config path`, and `XTTS vocab path` fields !!\"\n",
" config = XttsConfig()\n",
" config.load_json(xtts_config)\n",
" XTTS_MODEL = Xtts.init_from_config(config)\n",
" print(\"Loading XTTS model! \")\n",
" XTTS_MODEL.load_checkpoint(config,\n",
" checkpoint_path=xtts_checkpoint,\n",
" vocab_path=xtts_vocab,\n",
" use_deepspeed=True)\n",
" if torch.cuda.is_available():\n",
" XTTS_MODEL.cuda()\n",
"\n",
" print(\"Model Loaded!\")\n",
" return XTTS_MODEL\n",
"\n",
"\n",
"def get_file_name(text, max_char=50):\n",
" filename = text[:max_char]\n",
" filename = filename.lower()\n",
" filename = filename.replace(\" \", \"_\")\n",
" filename = filename.translate(str.maketrans(\"\", \"\", string.punctuation.replace(\"_\", \"\")))\n",
" filename = unidecode(filename)\n",
" current_datetime = datetime.now().strftime(\"%m%d%H%M%S\")\n",
" filename = f\"{current_datetime}_{filename}\"\n",
" return filename\n",
"\n",
"\n",
"def calculate_keep_len(text, lang):\n",
" if lang in [\"ja\", \"zh-cn\"]:\n",
" return -1\n",
"\n",
" word_count = len(text.split())\n",
" num_punct = (\n",
" text.count(\".\")\n",
" + text.count(\"!\")\n",
" + text.count(\"?\")\n",
" + text.count(\",\")\n",
" )\n",
"\n",
" if word_count < 5:\n",
" return 15000 * word_count + 2000 * num_punct\n",
" elif word_count < 10:\n",
" return 13000 * word_count + 2000 * num_punct\n",
" return -1\n",
"\n",
"\n",
"def normalize_vietnamese_text(text):\n",
" text = (\n",
" TTSnorm(text, unknown=False, lower=False, rule=True)\n",
" .replace(\"..\", \".\")\n",
" .replace(\"!.\", \"!\")\n",
" .replace(\"?.\", \"?\")\n",
" .replace(\" .\", \".\")\n",
" .replace(\" ,\", \",\")\n",
" .replace('\"', \"\")\n",
" .replace(\"'\", \"\")\n",
" .replace(\"AI\", \"Ây Ai\")\n",
" .replace(\"A.I\", \"Ây Ai\")\n",
" )\n",
" return text\n",
"\n",
"\n",
"def run_tts(XTTS_MODEL, lang, tts_text, speaker_audio_file,\n",
" normalize_text= True,\n",
" verbose=False,\n",
" output_chunks=False):\n",
" \"\"\"\n",
" Run text-to-speech (TTS) synthesis using the provided XTTS_MODEL.\n",
"\n",
" Args:\n",
" XTTS_MODEL: A pre-trained TTS model.\n",
" lang (str): The language of the input text.\n",
" tts_text (str): The text to be synthesized into speech.\n",
" speaker_audio_file (str): Path to the audio file of the speaker to condition the synthesis on.\n",
" normalize_text (bool, optional): Whether to normalize the input text. Defaults to True.\n",
" verbose (bool, optional): Whether to print verbose information. Defaults to False.\n",
" output_chunks (bool, optional): Whether to save synthesized speech chunks separately. Defaults to False.\n",
"\n",
" Returns:\n",
" str: Path to the synthesized audio file.\n",
" \"\"\"\n",
"\n",
" if XTTS_MODEL is None or not speaker_audio_file:\n",
" return \"You need to run the previous step to load the model !!\", None, None\n",
"\n",
" output_dir = \"./output\"\n",
" os.makedirs(output_dir, exist_ok=True)\n",
"\n",
" gpt_cond_latent, speaker_embedding = XTTS_MODEL.get_conditioning_latents(\n",
" audio_path=speaker_audio_file,\n",
" gpt_cond_len=XTTS_MODEL.config.gpt_cond_len,\n",
" max_ref_length=XTTS_MODEL.config.max_ref_len,\n",
" sound_norm_refs=XTTS_MODEL.config.sound_norm_refs,\n",
" )\n",
"\n",
" if normalize_text and lang == \"vi\":\n",
" # Bug on google colab\n",
" try:\n",
" tts_text = normalize_vietnamese_text(tts_text)\n",
" except:\n",
" cry_and_quit()\n",
"\n",
" if lang in [\"ja\", \"zh-cn\"]:\n",
" tts_texts = tts_text.split(\"。\")\n",
" else:\n",
" tts_texts = sent_tokenize(tts_text)\n",
"\n",
" if verbose:\n",
" print(\"Text for TTS:\")\n",
" pprint(tts_texts)\n",
"\n",
" wav_chunks = []\n",
" for text in tqdm(tts_texts):\n",
" if text.strip() == \"\":\n",
" continue\n",
"\n",
" wav_chunk = XTTS_MODEL.inference(\n",
" text=text,\n",
" language=lang,\n",
" gpt_cond_latent=gpt_cond_latent,\n",
" speaker_embedding=speaker_embedding,\n",
" temperature=0.3,\n",
" length_penalty=1.0,\n",
" repetition_penalty=10.0,\n",
" top_k=30,\n",
" top_p=0.85,\n",
" )\n",
"\n",
" # Quick hack for short sentences\n",
" keep_len = calculate_keep_len(text, lang)\n",
" wav_chunk[\"wav\"] = torch.tensor(wav_chunk[\"wav\"][:keep_len])\n",
"\n",
" if output_chunks:\n",
" out_path = os.path.join(output_dir, f\"{get_file_name(text)}.wav\")\n",
" torchaudio.save(out_path, wav_chunk[\"wav\"].unsqueeze(0), 24000)\n",
" if verbose:\n",
" print(f\"Saved chunk to {out_path}\")\n",
"\n",
" wav_chunks.append(wav_chunk[\"wav\"])\n",
"\n",
" out_wav = torch.cat(wav_chunks, dim=0).unsqueeze(0)\n",
" out_path = os.path.join(output_dir, f\"{get_file_name(tts_text)}.wav\")\n",
" torchaudio.save(out_path, out_wav, 24000)\n",
"\n",
" if verbose:\n",
" print(f\"Saved final file to {out_path}\")\n",
"\n",
" return out_path\n",
"\n",
"\n",
"language_code_map = {\n",
" \"Tiếng Việt\": \"vi\",\n",
" \"Tiếng Anh\": \"en\",\n",
" \"Tiếng Tây Ban Nha\": \"es\",\n",
" \"Tiếng Pháp\": \"fr\",\n",
" \"Tiếng Đức\": \"de\",\n",
" \"Tiếng Ý\": \"it\",\n",
" \"Tiếng Bồ Đào Nha\": \"pt\",\n",
" \"Tiếng Ba Lan\": \"pl\",\n",
" \"Tiếng Thổ Nhĩ Kỳ\": \"tr\",\n",
" \"Tiếng Nga\": \"ru\",\n",
" \"Tiếng Hà Lan\": \"nl\",\n",
" \"Tiếng Séc\": \"cs\",\n",
" \"Tiếng Ả Rập\": \"ar\",\n",
" \"Tiếng Trung (giản thể)\": \"zh-cn\",\n",
" \"Tiếng Nhật\": \"ja\",\n",
" \"Tiếng Hungary\": \"hu\",\n",
" \"Tiếng Hàn\": \"ko\",\n",
" \"Tiếng Hindi\": \"hi\"\n",
"}\n",
"\n",
"print(\"> Đang nạp mô hình...\")\n",
"try:\n",
" if not vixtts_model:\n",
" vixtts_model = load_model(xtts_checkpoint=\"model/model.pth\",\n",
" xtts_config=\"model/config.json\",\n",
" xtts_vocab=\"model/vocab.json\")\n",
"except:\n",
" vixtts_model = load_model(xtts_checkpoint=\"model/model.pth\",\n",
" xtts_config=\"model/config.json\",\n",
" xtts_vocab=\"model/vocab.json\")\n",
"clear_output()\n",
"print(\"> Đã nạp mô hình\")\n",
"\n",
"if not os.path.exists(reference_audio):\n",
" print(\"⚠️⚠️⚠️Bạn chưa tải file âm thanh lên. Hãy chọn giọng khác, hoặc tải file của bạn lên ở bên dưới.⚠️⚠️⚠️\")\n",
" audio_file=\"/content/model/vi_sample.wav\"\n",
"else:\n",
" audio_file = run_tts(vixtts_model,\n",
" lang=language_code_map[language],\n",
" tts_text=input_text,\n",
" speaker_audio_file=reference_audio,\n",
" normalize_text=normalize_text,\n",
" verbose=verbose,\n",
" output_chunks=output_chunks,)\n",
"\n",
"from IPython.display import Audio\n",
"Audio(audio_file)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "C7Bm9c2iTmpQ"
},
"outputs": [],
"source": [
"# @title 🎤 **Tải file âm thanh của bạn lên**\n",
"# @markdown Để đạt chất lượng tốt nhất, hãy tham khảo file '/content/model/vi_sample.wav'\n",
"# @\n",
"import os\n",
"import locale\n",
"from google.colab import files\n",
"\n",
"denoise = True # @param {type:\"boolean\"}\n",
"\n",
"# Upload the audio file\n",
"uploaded = files.upload()\n",
"for filename in uploaded.keys():\n",
" # Convert the audio file to WAV format using ffmpeg\n",
" uploaded_dir = os.path.dirname(filename)\n",
" if denoise:\n",
" !deepFilter \"{filename}\"\n",
" !ffmpeg -i \"{filename.replace('.wav', '_DeepFilterNet3.wav')}\" -ac 1 -ar 22050 -vn /content/model/user_sample.wav -y -hide_banner -loglevel error\n",
" os.remove(filename.replace('.wav', '_DeepFilterNet3.wav'))\n",
" else:\n",
" !ffmpeg -i \"{filename}\" -ac 1 -ar 22050 -vn /content/model/user_sample.wav -y -hide_banner -loglevel error\n",
" os.remove(filename)\n",
" break\n",
"\n",
"from IPython.display import Audio, clear_output\n",
"clear_output()\n",
"print(\"> Đã tải file âm thanh lên\")\n",
"Audio(\"/content/model/user_sample.wav\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "6sC6v6pNQVt5"
},
"outputs": [],
"source": [
"# @title ⏬ **Lưu kết quả vào Drive**\n",
"# @markdown Chạy phần này để lưu kết quả vào Google Drive của bạn\n",
"# @markdown `/content/drive/MyDrive/vixtts-output`\n",
"\n",
"from google.colab import drive\n",
"drive.mount('/content/drive')\n",
"\n",
"# Save the output folder in \"vixtts-output\" in Google Drive, without overwriting existing files\n",
"!cp -n -r /content/output/* /content/drive/MyDrive/vixtts-output\n",
"print(\"> Đã lưu kết quả vào Google Drive\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "7-X619YbX0n-"
},
"outputs": [],
"source": [
"# @title ⚠️ **Dọn kết quả**\n",
"# @markdown Chạy phần này để xóa toàn bộ file trong `/content/output`\n",
"import shutil\n",
"shutil.rmtree('/content/output')\n",
"print(\"Đã xóa toàn bộ file trong /content/output\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"cellView": "form",
"id": "cvzEJ8c_PkRb"
},
"outputs": [],
"source": [
"# @title 📴 **Tắt Demo**\n",
"# @markdown Khi chạy xong thì bạn hãy tắt demo để tiết kiệm GPU nhé!\n",
"from google.colab import runtime\n",
"runtime.unassign()"
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"authorship_tag": "ABX9TyN7+AM4TCVxzIzD/jayBMlv",
"gpuType": "T4",
"include_colab_link": true,
"machine_shape": "hm",
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
|