Upload voxcpm2_vps.py
Browse files- voxcpm2_vps.py +79 -20
voxcpm2_vps.py
CHANGED
|
@@ -6,13 +6,14 @@ Optimized for: Hostinger KVM 4 (4 vCPU, 8GB RAM) or similar VPS
|
|
| 6 |
⚠️ MEMORY WARNING: VoxCPM2 (2B params) needs ~8-9GB RAM in float32 on CPU.
|
| 7 |
An 8GB VPS will need swap space. This script auto-checks and warns.
|
| 8 |
|
| 9 |
-
If OOM persists,
|
| 10 |
|
| 11 |
Features:
|
| 12 |
- Auto memory check with swap creation guide
|
| 13 |
- Auto float32 conversion for CPU (fixes bfloat16 crash)
|
| 14 |
-
- Graceful fallback to VoxCPM-0.5B if RAM is insufficient
|
| 15 |
- All capabilities: TTS, Voice Design, Voice Cloning, Multilingual, Streaming
|
|
|
|
|
|
|
| 16 |
"""
|
| 17 |
|
| 18 |
import os
|
|
@@ -20,7 +21,6 @@ import sys
|
|
| 20 |
import time
|
| 21 |
import argparse
|
| 22 |
import warnings
|
| 23 |
-
import subprocess
|
| 24 |
|
| 25 |
warnings.filterwarnings("ignore")
|
| 26 |
|
|
@@ -61,21 +61,6 @@ def check_memory():
|
|
| 61 |
return True
|
| 62 |
|
| 63 |
|
| 64 |
-
def create_swap_guide():
|
| 65 |
-
"""Print swap creation commands."""
|
| 66 |
-
print("""
|
| 67 |
-
╔══════════════════════════════════════════════════════════════════╗
|
| 68 |
-
║ HOW TO ADD SWAP ON YOUR VPS (run these via SSH) ║
|
| 69 |
-
╠══════════════════════════════════════════════════════════════════╣
|
| 70 |
-
║ sudo fallocate -l 8G /swapfile ║
|
| 71 |
-
║ sudo chmod 600 /swapfile ║
|
| 72 |
-
║ sudo mkswap /swapfile ║
|
| 73 |
-
║ sudo swapon /swapfile ║
|
| 74 |
-
║ echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab ║
|
| 75 |
-
╚══════════════════════════════════════════════════════════════════╝
|
| 76 |
-
""")
|
| 77 |
-
|
| 78 |
-
|
| 79 |
def load_model(model_id="openbmb/VoxCPM2"):
|
| 80 |
"""Load VoxCPM model optimized for VPS CPU."""
|
| 81 |
from voxcpm import VoxCPM
|
|
@@ -177,10 +162,55 @@ def generate_multilingual(model, texts_dict, timesteps=10):
|
|
| 177 |
return results
|
| 178 |
|
| 179 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
def run_all_demos(model_id="openbmb/VoxCPM2"):
|
| 181 |
mem_ok = check_memory()
|
| 182 |
if not mem_ok:
|
| 183 |
-
create_swap_guide()
|
| 184 |
response = input("\nContinue anyway? (y/n): ").strip().lower()
|
| 185 |
if response != 'y':
|
| 186 |
print("[INFO] Exiting. Add swap or use --model openbmb/VoxCPM-0.5B")
|
|
@@ -192,10 +222,14 @@ def run_all_demos(model_id="openbmb/VoxCPM2"):
|
|
| 192 |
print("RUNNING ALL CAPABILITY DEMOS")
|
| 193 |
print("=" * 60)
|
| 194 |
|
|
|
|
| 195 |
generate_basic_tts(model, "Hello! This is VoxCPM2 running on a VPS.", "demo_01_basic.wav", 10)
|
|
|
|
|
|
|
| 196 |
generate_voice_design(model, "A warm professional female narrator",
|
| 197 |
"Welcome to today's presentation.", "demo_02_design.wav", 12)
|
| 198 |
|
|
|
|
| 199 |
texts = {
|
| 200 |
"english": "The quick brown fox jumps over the lazy dog.",
|
| 201 |
"chinese": "你好,这是VoxCPM2语音合成模型。",
|
|
@@ -203,11 +237,23 @@ def run_all_demos(model_id="openbmb/VoxCPM2"):
|
|
| 203 |
}
|
| 204 |
generate_multilingual(model, texts, 10)
|
| 205 |
|
|
|
|
| 206 |
if os.path.exists("my_voice.wav"):
|
| 207 |
generate_voice_clone(model, "This is my cloned voice.", "my_voice.wav", "demo_05_clone.wav", 15)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
else:
|
| 209 |
print("\n[SKIP] Place 'my_voice.wav' to test voice cloning")
|
| 210 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 211 |
print("\n" + "=" * 60)
|
| 212 |
print("ALL DEMOS COMPLETE!")
|
| 213 |
print("=" * 60)
|
|
@@ -233,12 +279,18 @@ Examples:
|
|
| 233 |
|
| 234 |
# Voice clone
|
| 235 |
python voxcpm2_vps.py --mode clone --text "Hi" --reference my_voice.wav
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 236 |
"""
|
| 237 |
)
|
| 238 |
parser.add_argument("--model", type=str, default="openbmb/VoxCPM2",
|
| 239 |
help="Model ID: openbmb/VoxCPM2 (2B) or openbmb/VoxCPM-0.5B (smaller)")
|
| 240 |
parser.add_argument("--demo", action="store_true", help="Run all capability demos")
|
| 241 |
-
parser.add_argument("--mode", choices=["basic", "design", "clone", "multilingual"],
|
| 242 |
default="basic", help="Generation mode")
|
| 243 |
parser.add_argument("--text", type=str, default="Hello from VoxCPM2 on VPS!", help="Text to synthesize")
|
| 244 |
parser.add_argument("--description", type=str, default="A warm professional voice", help="Voice design description")
|
|
@@ -274,6 +326,13 @@ Examples:
|
|
| 274 |
"spanish": "¡Hola! Esta es síntesis de voz.",
|
| 275 |
}
|
| 276 |
generate_multilingual(model, texts, args.timesteps)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
|
| 278 |
print(f"\n[OK] Done! Output: {args.output}")
|
| 279 |
|
|
|
|
| 6 |
⚠️ MEMORY WARNING: VoxCPM2 (2B params) needs ~8-9GB RAM in float32 on CPU.
|
| 7 |
An 8GB VPS will need swap space. This script auto-checks and warns.
|
| 8 |
|
| 9 |
+
If OOM persists, use VoxCPM-0.5B (much smaller).
|
| 10 |
|
| 11 |
Features:
|
| 12 |
- Auto memory check with swap creation guide
|
| 13 |
- Auto float32 conversion for CPU (fixes bfloat16 crash)
|
|
|
|
| 14 |
- All capabilities: TTS, Voice Design, Voice Cloning, Multilingual, Streaming
|
| 15 |
+
- NEW: Multilingual Voice Cloning (clone voice + speak any language)
|
| 16 |
+
- NEW: Multilingual Voice Design (design voice + speak any language)
|
| 17 |
"""
|
| 18 |
|
| 19 |
import os
|
|
|
|
| 21 |
import time
|
| 22 |
import argparse
|
| 23 |
import warnings
|
|
|
|
| 24 |
|
| 25 |
warnings.filterwarnings("ignore")
|
| 26 |
|
|
|
|
| 61 |
return True
|
| 62 |
|
| 63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
def load_model(model_id="openbmb/VoxCPM2"):
|
| 65 |
"""Load VoxCPM model optimized for VPS CPU."""
|
| 66 |
from voxcpm import VoxCPM
|
|
|
|
| 162 |
return results
|
| 163 |
|
| 164 |
|
| 165 |
+
# NEW: Multilingual Voice Cloning — clone a voice and speak ANY language!
|
| 166 |
+
def generate_multilingual_clone(model, text, reference_wav, output_path="output_multi_clone.wav", timesteps=15):
|
| 167 |
+
"""Clone a voice and speak in ANY language!"""
|
| 168 |
+
import soundfile as sf
|
| 169 |
+
if not os.path.exists(reference_wav):
|
| 170 |
+
print(f"[ERROR] Reference not found: {reference_wav}")
|
| 171 |
+
return None
|
| 172 |
+
|
| 173 |
+
print(f"\n[MODE] Multilingual Voice Cloning")
|
| 174 |
+
print(f"[TEXT] {text[:80]}...")
|
| 175 |
+
print(f"[REF] {reference_wav}")
|
| 176 |
+
print("[INFO] The cloned voice will speak in whatever language you typed!")
|
| 177 |
+
|
| 178 |
+
start = time.time()
|
| 179 |
+
wav = model.generate(text=text, reference_wav_path=reference_wav, cfg_value=2.0,
|
| 180 |
+
inference_timesteps=timesteps, max_len=4096)
|
| 181 |
+
elapsed = time.time() - start
|
| 182 |
+
|
| 183 |
+
sf.write(output_path, wav, model.tts_model.sample_rate)
|
| 184 |
+
duration = len(wav) / model.tts_model.sample_rate
|
| 185 |
+
print(f"[OK] Saved: {output_path} ({duration:.1f}s audio, {elapsed:.1f}s generation)")
|
| 186 |
+
print("[INFO] ✅ The cloned voice is speaking the language of your text!")
|
| 187 |
+
return output_path
|
| 188 |
+
|
| 189 |
+
|
| 190 |
+
# NEW: Multilingual Voice Design — design a voice and speak ANY language!
|
| 191 |
+
def generate_multilingual_design(model, description, text, output_path="output_multi_design.wav", timesteps=12):
|
| 192 |
+
"""Design a voice and speak in ANY language!"""
|
| 193 |
+
import soundfile as sf
|
| 194 |
+
full_text = f"({description}) {text}"
|
| 195 |
+
print(f"\n[MODE] Multilingual Voice Design")
|
| 196 |
+
print(f"[DESC] {description}")
|
| 197 |
+
print(f"[TEXT] {text[:80]}...")
|
| 198 |
+
print("[INFO] The designed voice will speak in whatever language you typed!")
|
| 199 |
+
|
| 200 |
+
start = time.time()
|
| 201 |
+
wav = model.generate(text=full_text, cfg_value=2.0, inference_timesteps=timesteps, max_len=4096)
|
| 202 |
+
elapsed = time.time() - start
|
| 203 |
+
|
| 204 |
+
sf.write(output_path, wav, model.tts_model.sample_rate)
|
| 205 |
+
duration = len(wav) / model.tts_model.sample_rate
|
| 206 |
+
print(f"[OK] Saved: {output_path} ({duration:.1f}s audio, {elapsed:.1f}s generation)")
|
| 207 |
+
print("[INFO] ✅ The designed voice is speaking the language of your text!")
|
| 208 |
+
return output_path
|
| 209 |
+
|
| 210 |
+
|
| 211 |
def run_all_demos(model_id="openbmb/VoxCPM2"):
|
| 212 |
mem_ok = check_memory()
|
| 213 |
if not mem_ok:
|
|
|
|
| 214 |
response = input("\nContinue anyway? (y/n): ").strip().lower()
|
| 215 |
if response != 'y':
|
| 216 |
print("[INFO] Exiting. Add swap or use --model openbmb/VoxCPM-0.5B")
|
|
|
|
| 222 |
print("RUNNING ALL CAPABILITY DEMOS")
|
| 223 |
print("=" * 60)
|
| 224 |
|
| 225 |
+
# 1. Basic TTS
|
| 226 |
generate_basic_tts(model, "Hello! This is VoxCPM2 running on a VPS.", "demo_01_basic.wav", 10)
|
| 227 |
+
|
| 228 |
+
# 2. Voice Design
|
| 229 |
generate_voice_design(model, "A warm professional female narrator",
|
| 230 |
"Welcome to today's presentation.", "demo_02_design.wav", 12)
|
| 231 |
|
| 232 |
+
# 3. Multilingual
|
| 233 |
texts = {
|
| 234 |
"english": "The quick brown fox jumps over the lazy dog.",
|
| 235 |
"chinese": "你好,这是VoxCPM2语音合成模型。",
|
|
|
|
| 237 |
}
|
| 238 |
generate_multilingual(model, texts, 10)
|
| 239 |
|
| 240 |
+
# 4. Voice Clone (if reference exists)
|
| 241 |
if os.path.exists("my_voice.wav"):
|
| 242 |
generate_voice_clone(model, "This is my cloned voice.", "my_voice.wav", "demo_05_clone.wav", 15)
|
| 243 |
+
|
| 244 |
+
# 5. NEW: Multilingual Clone — clone voice, speak Chinese!
|
| 245 |
+
generate_multilingual_clone(model,
|
| 246 |
+
"你好!这是我克隆的声音在说中文。非常自然和流畅!",
|
| 247 |
+
"my_voice.wav", "demo_06_multi_clone.wav", 15)
|
| 248 |
else:
|
| 249 |
print("\n[SKIP] Place 'my_voice.wav' to test voice cloning")
|
| 250 |
|
| 251 |
+
# 6. NEW: Multilingual Design — design voice, speak Chinese!
|
| 252 |
+
generate_multilingual_design(model,
|
| 253 |
+
"A warm elderly British woman, soft and caring",
|
| 254 |
+
"你好!这是一个温暖的英国老太太的声音在说中文。",
|
| 255 |
+
"demo_07_multi_design.wav", 12)
|
| 256 |
+
|
| 257 |
print("\n" + "=" * 60)
|
| 258 |
print("ALL DEMOS COMPLETE!")
|
| 259 |
print("=" * 60)
|
|
|
|
| 279 |
|
| 280 |
# Voice clone
|
| 281 |
python voxcpm2_vps.py --mode clone --text "Hi" --reference my_voice.wav
|
| 282 |
+
|
| 283 |
+
# Multilingual clone (NEW!) — clone voice + speak any language
|
| 284 |
+
python voxcpm2_vps.py --mode multi-clone --text "你好!" --reference my_voice.wav
|
| 285 |
+
|
| 286 |
+
# Multilingual design (NEW!) — design voice + speak any language
|
| 287 |
+
python voxcpm2_vps.py --mode multi-design --description "warm elderly woman" --text "¡Hola!"
|
| 288 |
"""
|
| 289 |
)
|
| 290 |
parser.add_argument("--model", type=str, default="openbmb/VoxCPM2",
|
| 291 |
help="Model ID: openbmb/VoxCPM2 (2B) or openbmb/VoxCPM-0.5B (smaller)")
|
| 292 |
parser.add_argument("--demo", action="store_true", help="Run all capability demos")
|
| 293 |
+
parser.add_argument("--mode", choices=["basic", "design", "clone", "multilingual", "multi-clone", "multi-design"],
|
| 294 |
default="basic", help="Generation mode")
|
| 295 |
parser.add_argument("--text", type=str, default="Hello from VoxCPM2 on VPS!", help="Text to synthesize")
|
| 296 |
parser.add_argument("--description", type=str, default="A warm professional voice", help="Voice design description")
|
|
|
|
| 326 |
"spanish": "¡Hola! Esta es síntesis de voz.",
|
| 327 |
}
|
| 328 |
generate_multilingual(model, texts, args.timesteps)
|
| 329 |
+
elif args.mode == "multi-clone":
|
| 330 |
+
if not args.reference:
|
| 331 |
+
print("[ERROR] --reference required for multi-clone mode")
|
| 332 |
+
sys.exit(1)
|
| 333 |
+
generate_multilingual_clone(model, args.text, args.reference, args.output, args.timesteps)
|
| 334 |
+
elif args.mode == "multi-design":
|
| 335 |
+
generate_multilingual_design(model, args.description, args.text, args.output, args.timesteps)
|
| 336 |
|
| 337 |
print(f"\n[OK] Done! Output: {args.output}")
|
| 338 |
|