Voice Cloning Automation Script — วิธีสร้างระบบ
Voice Cloning คืออะไร
Voice Cloning เป็นเทคโนโลยี AI ที่ใช้ Deep Learning สร้างเสียงเลียนแบบเสียงของคนจริง โดยวิเคราะห์ลักษณะเฉพาะของเสียง (Speaker Embedding) เช่น โทนเสียง จังหวะการพูด น้ำเสียง ความถี่ แล้วสร้างเสียงใหม่จากข้อความที่กำหนด (Text-to-Speech) ให้ฟังเหมือนคนต้นแบบ
ปัจจุบัน Voice Cloning ใช้กันแพร่หลายใน Audiobook Production, Video Dubbing, Virtual Assistant, Content Creation, Accessibility สำหรับผู้พิการทางเสียง และ Personalized TTS เทคโนโลยีพัฒนาเร็วมากจนสามารถ Clone เสียงได้จากตัวอย่างเพียง 3-10 วินาที
ติดตั้งและเตรียมสภาพแวดล้อม
# === ติดตั้ง Voice Cloning Environment ===
# สร้าง Virtual Environment
python -m venv voice-clone-env
source voice-clone-env/bin/activate # Linux/Mac
# voice-clone-env\Scripts\activate # Windows
# ติดตั้ง Coqui TTS (XTTS v2)
pip install TTS torch torchaudio
# ติดตั้ง Dependencies เพิ่มเติม
pip install soundfile librosa scipy numpy pydub
pip install fastapi uvicorn python-multipart # สำหรับ API
# ตรวจสอบ GPU
python -c "import torch; print(f'CUDA: {torch.cuda.is_available()}')"
python -c "import torch; print(f'GPU: {torch.cuda.get_device_name(0)}')"
# ดาวน์โหลด Model
python -c "from TTS.api import TTS; tts = TTS('tts_models/multilingual/multi-dataset/xtts_v2')"
# Model จะถูกดาวน์โหลดอัตโนมัติ (~1.8GB)
# โครงสร้าง Project
voice-cloner/
├── main.py # Main Script
├── api.py # FastAPI Server
├── preprocess.py # Audio Preprocessing
├── clone.py # Voice Cloning Engine
├── batch_process.py # Batch Processing
├── samples/ # Voice Samples
│ └── speaker.wav
├── output/ # Generated Audio
├── config.yaml # Configuration
└── requirements.txt
Voice Cloning Script
# clone.py — Voice Cloning Engine
import os
import torch
import numpy as np
import soundfile as sf
from TTS.api import TTS
from pydub import AudioSegment
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class VoiceCloner:
"""Voice Cloning Engine ด้วย XTTS v2"""
def __init__(self, model_name="tts_models/multilingual/multi-dataset/xtts_v2",
device=None):
self.device = device or ("cuda" if torch.cuda.is_available() else "cpu")
logger.info(f"Loading model on {self.device}...")
self.tts = TTS(model_name).to(self.device)
logger.info("Model loaded successfully")
def preprocess_audio(self, audio_path, output_path=None,
target_sr=22050, max_duration=30):
"""เตรียมไฟล์เสียงสำหรับ Voice Cloning"""
audio = AudioSegment.from_file(audio_path)
# Convert to mono
if audio.channels > 1:
audio = audio.set_channels(1)
# Set sample rate
audio = audio.set_frame_rate(target_sr)
# Normalize volume
target_dbfs = -20
change_in_dbfs = target_dbfs - audio.dBFS
audio = audio.apply_gain(change_in_dbfs)
# Trim silence
from pydub.silence import detect_leading_silence
start_trim = detect_leading_silence(audio, silence_threshold=-40)
end_trim = detect_leading_silence(audio.reverse(), silence_threshold=-40)
audio = audio[start_trim:len(audio) - end_trim]
# Limit duration
if len(audio) > max_duration * 1000:
audio = audio[:max_duration * 1000]
out_path = output_path or audio_path.replace(".wav", "_processed.wav")
audio.export(out_path, format="wav")
logger.info(f"Preprocessed: {out_path} ({len(audio)/1000:.1f}s)")
return out_path
def clone_voice(self, text, speaker_wav, output_path,
language="th", speed=1.0):
"""Clone เสียงและสร้าง Audio จากข้อความ"""
logger.info(f"Generating speech: '{text[:50]}...'")
self.tts.tts_to_file(
text=text,
speaker_wav=speaker_wav,
language=language,
file_path=output_path,
speed=speed,
)
# ตรวจสอบไฟล์ Output
if os.path.exists(output_path):
audio = AudioSegment.from_file(output_path)
duration = len(audio) / 1000
logger.info(f"Generated: {output_path} ({duration:.1f}s)")
return {"path": output_path, "duration": duration}
else:
raise FileNotFoundError(f"Failed to generate: {output_path}")
def batch_clone(self, texts, speaker_wav, output_dir,
language="th", prefix="output"):
"""Clone เสียงหลายข้อความพร้อมกัน"""
os.makedirs(output_dir, exist_ok=True)
results = []
for i, text in enumerate(texts):
output_path = os.path.join(output_dir, f"{prefix}_{i:04d}.wav")
try:
result = self.clone_voice(text, speaker_wav, output_path,
language=language)
results.append(result)
except Exception as e:
logger.error(f"Error on text {i}: {e}")
results.append({"path": None, "error": str(e)})
success = sum(1 for r in results if r.get("path"))
logger.info(f"Batch complete: {success}/{len(texts)} succeeded")
return results
def concatenate_audio(self, audio_files, output_path, gap_ms=500):
"""รวมไฟล์เสียงหลายไฟล์เข้าด้วยกัน"""
combined = AudioSegment.empty()
gap = AudioSegment.silent(duration=gap_ms)
for f in audio_files:
if f and os.path.exists(f):
audio = AudioSegment.from_file(f)
combined += audio + gap
combined.export(output_path, format="wav")
logger.info(f"Concatenated {len(audio_files)} files -> {output_path}")
return output_path
# ตัวอย่างการใช้งาน
if __name__ == "__main__":
cloner = VoiceCloner()
# Preprocess Speaker Sample
processed = cloner.preprocess_audio("samples/speaker.wav")
# Clone เสียงเดียว
result = cloner.clone_voice(
text="สวัสดีครับ นี่คือเสียงที่สร้างจาก AI Voice Cloning",
speaker_wav=processed,
output_path="output/test_output.wav",
language="th",
)
print(f"Generated: {result}")
# Batch Clone
texts = [
"ยินดีต้อนรับสู่ระบบ Voice Cloning อัตโนมัติ",
"ระบบนี้ใช้เทคโนโลยี XTTS v2 ในการสร้างเสียง",
"สามารถ Clone เสียงได้จากตัวอย่างเพียงไม่กี่วินาที",
]
results = cloner.batch_clone(texts, processed, "output/batch/")
API Server สำหรับ Voice Cloning
# api.py — FastAPI Server สำหรับ Voice Cloning
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import FileResponse
import tempfile
import os
import uuid
from clone import VoiceCloner
app = FastAPI(title="Voice Cloning API")
cloner = VoiceCloner()
@app.post("/clone")
async def clone_voice(
text: str = Form(...),
language: str = Form(default="th"),
speaker: UploadFile = File(...),
):
"""Clone เสียงจากไฟล์ตัวอย่างและข้อความ"""
# Save uploaded file
tmp_speaker = os.path.join(tempfile.gettempdir(), f"speaker_{uuid.uuid4()}.wav")
with open(tmp_speaker, "wb") as f:
content = await speaker.read()
f.write(content)
# Preprocess
processed = cloner.preprocess_audio(tmp_speaker)
# Generate
output_path = os.path.join(tempfile.gettempdir(), f"output_{uuid.uuid4()}.wav")
result = cloner.clone_voice(text, processed, output_path, language=language)
# Cleanup
os.remove(tmp_speaker)
if os.path.exists(processed):
os.remove(processed)
return FileResponse(
output_path,
media_type="audio/wav",
filename="cloned_voice.wav",
)
@app.post("/batch")
async def batch_clone(
texts: str = Form(...), # JSON array of texts
language: str = Form(default="th"),
speaker: UploadFile = File(...),
):
"""Batch Clone หลายข้อความ"""
import json
text_list = json.loads(texts)
tmp_speaker = os.path.join(tempfile.gettempdir(), f"speaker_{uuid.uuid4()}.wav")
with open(tmp_speaker, "wb") as f:
f.write(await speaker.read())
processed = cloner.preprocess_audio(tmp_speaker)
output_dir = os.path.join(tempfile.gettempdir(), f"batch_{uuid.uuid4()}")
results = cloner.batch_clone(text_list, processed, output_dir, language)
# Concatenate all outputs
audio_files = [r["path"] for r in results if r.get("path")]
final_output = os.path.join(tempfile.gettempdir(), f"final_{uuid.uuid4()}.wav")
cloner.concatenate_audio(audio_files, final_output)
return FileResponse(final_output, media_type="audio/wav")
@app.get("/health")
async def health():
return {"status": "ok", "device": cloner.device}
# รัน: uvicorn api:app --host 0.0.0.0 --port 8000
# ทดสอบ:
# curl -X POST http://localhost:8000/clone \
# -F "text=สวัสดีครับ" \
# -F "language=th" \
# -F "speaker=@samples/speaker.wav" \
# -o output.wav
Automation Pipeline
# batch_process.py — Automation Pipeline สำหรับ Voice Cloning
import os
import csv
import yaml
import time
import logging
from clone import VoiceCloner
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
)
logger = logging.getLogger(__name__)
def process_csv(csv_path, speaker_wav, output_dir, language="th"):
"""
อ่านข้อความจาก CSV แล้ว Clone เสียงอัตโนมัติ
CSV Format: id, text, filename
"""
cloner = VoiceCloner()
os.makedirs(output_dir, exist_ok=True)
# Preprocess speaker
processed = cloner.preprocess_audio(speaker_wav)
results = []
with open(csv_path, "r", encoding="utf-8") as f:
reader = csv.DictReader(f)
rows = list(reader)
logger.info(f"Processing {len(rows)} items...")
start_time = time.time()
for i, row in enumerate(rows):
text = row["text"]
filename = row.get("filename", f"output_{i:04d}.wav")
output_path = os.path.join(output_dir, filename)
try:
result = cloner.clone_voice(text, processed, output_path,
language=language)
results.append({"id": row.get("id", i), "status": "ok",
**result})
logger.info(f"[{i+1}/{len(rows)}] OK: {filename}")
except Exception as e:
results.append({"id": row.get("id", i), "status": "error",
"error": str(e)})
logger.error(f"[{i+1}/{len(rows)}] FAIL: {filename} - {e}")
elapsed = time.time() - start_time
success = sum(1 for r in results if r["status"] == "ok")
logger.info(f"Done: {success}/{len(rows)} in {elapsed:.1f}s")
# Save report
report_path = os.path.join(output_dir, "report.csv")
with open(report_path, "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=["id", "status", "path",
"duration", "error"])
writer.writeheader()
writer.writerows(results)
return results
if __name__ == "__main__":
process_csv(
csv_path="texts.csv",
speaker_wav="samples/speaker.wav",
output_dir="output/batch/",
language="th",
)
Best Practices และข้อควรระวัง
- คุณภาพเสียงตัวอย่าง: ใช้เสียงที่สะอาด ไม่มี Background Noise, เสียงดนตรี หรือเสียงรบกวน บันทึกในห้องเงียบ ใช้ไมค์คุณภาพดี
- ความยาวเสียง: สำหรับ XTTS v2 ใช้ตัวอย่าง 6-30 วินาที ยาวเกินไปอาจไม่ดีกว่า คัดเลือกส่วนที่ชัดเจนที่สุด
- จริยธรรม: ใช้เฉพาะเสียงตัวเองหรือได้รับอนุญาต ห้ามใช้สร้าง Deepfake หลอกลวง ระบุว่าเป็นเสียง AI เสมอ
- GPU Memory: XTTS v2 ใช้ VRAM ~4GB สำหรับ Inference ถ้าไม่มี GPU ใช้ CPU ได้แต่ช้ากว่า 5-10 เท่า
- Batch Processing: สำหรับงานจำนวนมาก ใช้ Batch Processing กับ Queue System เพื่อจัดการ Resources
- Watermarking: เพิ่ม Audio Watermark ในเสียงที่สร้าง เพื่อระบุว่าเป็นเสียง AI-generated
Voice Cloning คืออะไร
Voice Cloning ใช้ AI สร้างเสียงเลียนแบบเสียงคนจริง วิเคราะห์ลักษณะเฉพาะของเสียงแล้วสร้างเสียงใหม่จากข้อความ ใช้ใน Text-to-Speech, Audiobook, Dubbing, Virtual Assistant เทคโนโลยีใหม่ Clone ได้จากตัวอย่างเพียง 3-10 วินาที