{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# ๐๏ธ VoxCPM2 - Interactive TTS Web App (Gradio UI)\n", "**Launch your own voice cloning & synthesis web app in Google Colab!**\n", "\n", "[Model: openbmb/VoxCPM2](https://huggingface.co/openbmb/VoxCPM2) | [Paper](https://arxiv.org/abs/2509.24650) | [Docs](https://voxcpm.readthedocs.io/)\n", "\n", "### ๐ MAIN FEATURE: Interactive Gradio Web UI\n", "Run a beautiful web interface with tabs for:\n", "- ๐ **Basic TTS** โ Type text, get 48kHz studio-quality speech\n", "- ๐จ **Voice Design** โ Describe any voice with natural language\n", "- ๐ค **Voice Clone** โ Upload a 3-10s voice sample, clone it!\n", "- ๐ **Multilingual** โ Type in any language โ auto-detects & speaks it\n", "- ๐๐ค **Multilingual + Clone** โ Clone a voice & speak ANY language\n", "- ๐๐จ **Multilingual + Design** โ Design a voice & speak ANY language\n", "\n", "**You'll get a public URL** to share or use from your phone!\n", "\n", "---\n", "\n", "### โ๏ธ Quick Setup (2 steps then launch UI)\n", "1. Run **Step 1** โ Install packages\n", "2. Run **Step 2** โ Load model\n", "3. Run **Step 3 (MAIN)** โ Launch Gradio UI ๐ฏ\n", "\n", "*Optional: Scroll down for individual mode demos if you want to experiment with code.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ๐ฆ Step 1: Install Dependencies (Run First)\n", "*Note: First run downloads ~4.6GB model weights. Takes ~3-5 minutes.*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install -q voxcpm soundfile gradio\n", "\n", "import torch\n", "print(f\"PyTorch: {torch.__version__}\")\n", "print(f\"CUDA available: {torch.cuda.is_available()}\")\n", "if torch.cuda.is_available():\n", " print(f\"GPU: {torch.cuda.get_device_name(0)}\")\n", " print(f\"VRAM: {torch.cuda.get_device_properties(0).total_memory / 1024**3:.1f} GB\")\n", "else:\n", " print(\"\\nโ ๏ธ WARNING: No GPU detected! VoxCPM2 needs a GPU runtime.\")\n", " print(\"โก๏ธ Run: Runtime -> Change runtime type -> T4 GPU -> Save -> Restart session\")\n", " print(\"Then re-run all cells from the top.\")\n", " raise SystemExit(\"Please switch to GPU runtime and restart.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## ๐ Step 2: Load Model (Run Second)\n", "**โ ๏ธ Must use GPU runtime.** (Runtime โ Change runtime type โ T4 GPU)\n", "\n", "*Torch compilation (`optimize=True`) is disabled on T4 because bfloat16 is not natively supported.*\n", "*This saves ~50-100 seconds of failed compilation during warmup.*\n", "\n", "*If CPU is detected, model auto-converts to float32 (slower but works).*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from voxcpm import VoxCPM\n", "import time\n", "\n", "print(\"\\n\" + \"=\"*60)\n", "print(\"LOADING VoxCPM2...\")\n", "print(\"=\"*60 + \"\\n\")\n", "\n", "import torch\n", "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", "print(f\"Detected device: {device}\")\n", "\n", "start = time.time()\n", "\n", "# โก SPEED TIP: T4 GPU does NOT support bfloat16 torch.compile natively.\n", "# Setting optimize=False saves ~50-100 seconds of failed compilation during warmup.\n", "model = VoxCPM.from_pretrained(\n", " \"openbmb/VoxCPM2\",\n", " load_denoiser=False, # Disable to save VRAM (~500MB)\n", " optimize=False, # torch.compile fails on T4 bfloat16, skip it\n", ")\n", "\n", "elapsed = time.time() - start\n", "print(f\"\\nโ Model loaded in {elapsed:.1f}s\")\n", "print(f\"๐ข Output sample rate: {model.tts_model.sample_rate} Hz\")\n", "print(f\"๐ฅ๏ธ Device: {device}\")\n", "\n", "# CPU fallback: bfloat16 crashes on CPU, convert to float32\n", "if not torch.cuda.is_available():\n", " print(\"\\nโ ๏ธ CPU detected! Converting model from bfloat16 to float32...\")\n", " model.tts_model = model.tts_model.to(torch.float32)\n", " print(\"โ Model converted to float32 (slower but works on CPU)\")\n", "else:\n", " print(f\"๐ฎ GPU VRAM used: {torch.cuda.memory_allocated() / 1024**3:.1f} GB\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "## ๐ฏ Step 3 (MAIN): Launch Interactive Gradio Web UI\n", "**This is the primary way to use VoxCPM2.** Run this cell and you'll get a public URL!\n", "\n", "### What's inside the UI:\n", "| Tab | What it does |\n", "|-----|-------------|\n", "| ๐ **Basic TTS** | Type any text โ get 48kHz speech |\n", "| ๐จ **Voice Design** | Describe a voice (e.g. \"warm female narrator\") โ get custom voice |\n", "| ๐ค **Voice Clone** | Upload 3-10s audio โ clone that voice |\n", "| ๐ **Multilingual** | Type in any language โ auto-detects & speaks it |\n", "| ๐๐ค **Multilingual + Clone** | Clone a voice AND speak in ANY language |\n", "| ๐๐จ **Multilingual + Design** | Design a voice AND speak in ANY language |\n", "| โน๏ธ **About** | Tips, capabilities, speed/quality guide |\n", "\n", "**Controls in every tab:**\n", "- **Timesteps slider** (4-30): Lower = faster, Higher = better quality\n", "- **CFG Scale slider** (1.0-3.0): Lower = more natural, Higher = tighter control\n", "\n", "*The UI will generate a public `gradio.live` URL you can open anywhere โ even your phone!*" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import gradio as gr\n", "import soundfile as sf\n", "import numpy as np\n", "\n", "print(\"\\n\" + \"=\"*60)\n", "print(\"๐ LAUNCHING VoxCPM2 INTERACTIVE WEB UI\")\n", "print(\"=\"*60)\n", "print(\"\\nTabs: ๐ Basic | ๐จ Design | ๐ค Clone | ๐ Multilingual | ๐๐ค Multi+Clone | ๐๐จ Multi+Design\")\n", "print(\"Controls: Timesteps (4-30) | CFG Scale (1.0-3.0)\")\n", "print(\"\\nโณ Starting Gradio server...\\n\")\n", "\n", "def tts_basic(text, timesteps, cfg):\n", " \"\"\"Basic text-to-speech generation.\"\"\"\n", " if not text or not text.strip():\n", " return None, \"Please enter some text.\"\n", " wav = model.generate(\n", " text=text.strip(),\n", " cfg_value=float(cfg),\n", " inference_timesteps=int(timesteps),\n", " )\n", " output = \"/content/gradio_basic.wav\"\n", " sf.write(output, wav, model.tts_model.sample_rate)\n", " return output, f\"โ Generated! Duration: {len(wav)/model.tts_model.sample_rate:.1f}s\"\n", "\n", "def tts_design(text, description, timesteps, cfg):\n", " \"\"\"Voice design via natural language description.\"\"\"\n", " if not text or not text.strip():\n", " return None, \"Please enter some text.\"\n", " full_text = f\"({description.strip()}) {text.strip()}\"\n", " wav = model.generate(\n", " text=full_text,\n", " cfg_value=float(cfg),\n", " inference_timesteps=int(timesteps),\n", " )\n", " output = \"/content/gradio_design.wav\"\n", " sf.write(output, wav, model.tts_model.sample_rate)\n", " return output, f\"โ Generated with voice design! Duration: {len(wav)/model.tts_model.sample_rate:.1f}s\"\n", "\n", "def tts_clone(text, audio_file, timesteps, cfg):\n", " \"\"\"Zero-shot voice cloning from reference audio.\"\"\"\n", " if not text or not text.strip():\n", " return None, \"Please enter some text.\"\n", " if audio_file is None:\n", " return None, \"โ ๏ธ Please upload a reference audio file (3-10s WAV or MP3).\"\n", " wav = model.generate(\n", " text=text.strip(),\n", " reference_wav_path=audio_file,\n", " cfg_value=float(cfg),\n", " inference_timesteps=int(timesteps),\n", " )\n", " output = \"/content/gradio_clone.wav\"\n", " sf.write(output, wav, model.tts_model.sample_rate)\n", " return output, f\"โ Voice cloned! Duration: {len(wav)/model.tts_model.sample_rate:.1f}s\"\n", "\n", "def tts_multilingual(text, timesteps, cfg):\n", " \"\"\"Multilingual TTS โ just type in any supported language.\"\"\"\n", " if not text or not text.strip():\n", " return None, \"Please enter some text.\"\n", " wav = model.generate(\n", " text=text.strip(),\n", " cfg_value=float(cfg),\n", " inference_timesteps=int(timesteps),\n", " )\n", " output = \"/content/gradio_multilingual.wav\"\n", " sf.write(output, wav, model.tts_model.sample_rate)\n", " return output, f\"โ Multilingual audio generated! Duration: {len(wav)/model.tts_model.sample_rate:.1f}s\"\n", "\n", "def tts_multilingual_clone(text, audio_file, timesteps, cfg):\n", " \"\"\"Clone a voice and speak in ANY language!\"\"\"\n", " if not text or not text.strip():\n", " return None, \"Please enter some text.\"\n", " if audio_file is None:\n", " return None, \"โ ๏ธ Please upload a reference audio file (3-10s). The cloned voice will speak your text in any language you type!\"\n", " wav = model.generate(\n", " text=text.strip(),\n", " reference_wav_path=audio_file,\n", " cfg_value=float(cfg),\n", " inference_timesteps=int(timesteps),\n", " )\n", " output = \"/content/gradio_multilingual_clone.wav\"\n", " sf.write(output, wav, model.tts_model.sample_rate)\n", " lang_note = \"๐ The cloned voice now speaks your text in whatever language you typed!\"\n", " return output, f\"โ Multilingual voice cloned! Duration: {len(wav)/model.tts_model.sample_rate:.1f}s | {lang_note}\"\n", "\n", "def tts_multilingual_design(text, description, timesteps, cfg):\n", " \"\"\"Design a voice and speak in ANY language!\"\"\"\n", " if not text or not text.strip():\n", " return None, \"Please enter some text.\"\n", " full_text = f\"({description.strip()}) {text.strip()}\"\n", " wav = model.generate(\n", " text=full_text,\n", " cfg_value=float(cfg),\n", " inference_timesteps=int(timesteps),\n", " )\n", " output = \"/content/gradio_multilingual_design.wav\"\n", " sf.write(output, wav, model.tts_model.sample_rate)\n", " lang_note = \"๐ The designed voice speaks your text in whatever language you typed!\"\n", " return output, f\"โ Multilingual voice designed! Duration: {len(wav)/model.tts_model.sample_rate:.1f}s | {lang_note}\"\n", "\n", "# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n", "# BUILD THE GRADIO INTERFACE\n", "# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n", "with gr.Blocks() as demo:\n", "\n", " gr.Markdown(\"\"\"\n", "