Hướng dẫn sử dụng WhisperX với Python: Nhận diện giọng nói, tách từ và phân biệt người nói

Artificial Intelligence tutorial - IT technology blog
Artificial Intelligence tutorial - IT technology blog

Bài toán nhận diện giọng nói trong thực tế: Khi chỉ nghe thôi là chưa đủ

Team CSKH vừa gửi cho bạn một file ghi âm cuộc gọi 45 phút qua tổng đài Asterisk hoặc Zoom. Yêu cầu đặt ra: trích xuất toàn bộ nội dung để chấm điểm chất lượng tư vấn. Nếu chỉ ném file vào Whisper thông thường, bạn sẽ nhận về một khối văn bản dài nghìn chữ không đầu không đuôi. Ai là nhân viên? Khách phàn nàn ở phút thứ mấy? Đoạn nào hai bên chốt deal?

Để dựng phụ đề chạy chữ karaoke trên CapCut hay lập biên bản họp tự động chia theo từng đầu việc, hệ thống STT phải giải quyết cùng lúc 3 bài toán: Nói nội dung gì?, Nói vào chính xác giây thứ mấy? (word-level timestamps), và Ai nói? (speaker diarization).

So sánh các giải pháp Speech-to-Text hiện nay

Dưới đây là trải nghiệm thực tế sau khi mình benchmark qua nhiều giải pháp để xử lý hàng trăm giờ audio hội thoại:

  • OpenAI Whisper thuần: Độ chính xác tiếng Việt rất ấn tượng. Dẫu vậy, timestamp chỉ dừng ở cấp độ câu (segment-level). File audio dài trên 30 phút rất dễ bị lệch mốc vài giây, đôi khi dính lỗi lặp từ vô tận (hallucination). Hạn chế lớn nhất: Whisper không có tính năng phân biệt người nói.
  • Cloud Speech APIs (Google Cloud Speech-to-Text, AWS Transcribe): Tính năng đầy đủ, độ ổn định cao. Nhưng chi phí là rào cản lớn. Với mức phí trung bình khoảng $0.024/phút (tương đương $1.44/giờ), một contact center xử lý 500 giờ ghi âm mỗi tháng sẽ tiêu tốn hơn $700. Thêm vào đó, việc đẩy audio nội bộ chứa thông tin thẻ hay số CMND/CCCD lên cloud tiềm ẩn nhiều rủi ro tuân thủ bảo mật.
  • WhisperX: Dự án mã nguồn mở kết hợp 3 công cụ: lõi faster-whisper (sử dụng CTranslate2 tối ưu inference), mô hình forced alignment (căn chỉnh âm vị) và pipeline pyannote.audio. WhisperX khắc phục triệt để lỗi trôi timestamp, phân tách speaker rõ ràng và chạy offline hoàn toàn trên hạ tầng riêng.

Ưu và nhược điểm của từng phương án

1. Whisper gốc (Vanilla Whisper)

  • Ưu điểm: Cài đặt siêu nhanh chỉ với một lệnh pip install openai-whisper. Thư viện chính chủ, xử lý ngữ cảnh tiếng Việt mượt mà.
  • Nhược điểm: Ngốn nhiều VRAM (cần 10-12GB VRAM cho model large-v3). Tốc độ inference chậm khi xử lý file dài. Không hỗ trợ diarization và không thể cắt ghép video chuẩn xác theo từng từ đơn lẻ.

2. Dịch vụ Cloud API trả phí

  • Ưu điểm: Không lo hạ tầng phần cứng. Chỉ việc gọi REST API là có kết quả.
  • Nhược điểm: Hóa đơn tăng phi mã khi scale quy mô lớn. Dữ liệu rời khỏi mạng nội bộ doanh nghiệp.

3. WhisperX

  • Ưu điểm: Nhanh gấp 2–4 lần Whisper gốc nhờ CTranslate2 và thuật toán VAD (Voice Activity Detection) cắt bỏ khoảng lặng. Timestamp chuẩn đến từng từ nhờ forced alignment. Tích hợp sẵn Pyannote 3.1 cho độ chính xác phân vai rất cao.
  • Nhược điểm: Đòi hỏi GPU NVIDIA có tối thiểu 6GB–8GB VRAM (khuyên dùng RTX 3060 12GB hoặc T4/A10 trên cloud). Khâu cài đặt cần khai báo token truy cập từ Hugging Face.

Tại sao WhisperX là lựa chọn tối ưu cho hệ thống tự vận hành?

Nếu bạn đang xây dựng công cụ tạo tự động phụ đề video ngắn, bot ghi biên bản Google Meet hay hệ thống QA kiểm toán chất lượng cuộc gọi, WhisperX là điểm cân bằng lý tưởng. Chi phí phần cứng cố định. Dữ liệu bảo mật tuyệt đối. Đặc biệt, dữ liệu trả về có cấu trúc JSON chi tiết, rất thuận tiện để ném thẳng vào các mô hình LLM phân tích tiếp.

Hướng dẫn triển khai WhisperX từng bước bằng Python

Bước 1: Chuẩn bị môi trường và thư viện

WhisperX yêu cầu Python 3.10 hoặc 3.11 cùng tiện ích ffmpeg để bóc tách stream âm thanh.

# Cài đặt ffmpeg trên Ubuntu/Debian
sudo apt update && sudo apt install -y ffmpeg

# Khởi tạo virtual environment
python3 -m venv venv && source venv/bin/activate

# Cài đặt PyTorch tương thích CUDA 12.1
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

# Cài đặt WhisperX
pip install git+https://github.com/m-bain/whisperx.git

Bước 2: Lấy Hugging Face Access Token

Pipeline phân tách người nói sử dụng pre-trained weights của pyannote.audio. Bạn cần dùng tài khoản Hugging Face để bấm đồng ý điều khoản sử dụng tại hai repo sau:

  • pyannote/speaker-diarization-3.1
  • pyannote/segmentation-3.0

Tiếp theo, truy cập mục Settings > Access Tokens trên Hugging Face, tạo một token mới quyền Read và lưu lại để gán vào mã Python.

Bước 3: Viết script xử lý âm thanh toàn diện

Script dưới đây vận hành trọn vẹn chuỗi pipeline 3 giai đoạn: Nhận diện giọng nói → Căn chỉnh mốc thời gian từng từ → Gán nhãn người nói.

import whisperx
import gc
import torch

device = "cuda" if torch.cuda.is_available() else "cpu"
audio_file = "cuoc_hop_demo.wav"
batch_size = 8  # Hạ xuống 4 hoặc 2 nếu VRAM dưới 8GB
compute_type = "float16" if device == "cuda" else "int8"
HF_TOKEN = "hf_your_personal_access_token_here"

# 1. Nhận diện giọng nói bằng faster-whisper
print("--- [1/3] Đang transcribe nội dung audio ---")
model = whisperx.load_model("large-v3", device, compute_type=compute_type, language="vi")
audio = whisperx.load_audio(audio_file)
result = model.transcribe(audio, batch_size=batch_size)

# Giải phóng VRAM GPU trước khi nạp model tiếp theo
del model
gc.collect()
torch.cuda.empty_cache()

# 2. Căn chỉnh thời gian chính xác tới từng từ (Forced Alignment)
print("--- [2/3] Đang căn chỉnh mốc thời gian từng từ ---")
model_a, metadata = whisperx.load_align_model(language_code=result["language"], device=device)
result = whisperx.align(result["segments"], model_a, metadata, audio, device, return_char_alignments=False)

del model_a
gc.collect()
torch.cuda.empty_cache()

# 3. Phân biệt người nói (Speaker Diarization)
print("--- [3/3] Đang gán nhãn speaker với Pyannote ---")
diarize_model = whisperx.DiarizationPipeline(use_auth_token=HF_TOKEN, device=device)
diarize_segments = diarize_model(audio_file)

# Gộp thông tin người nói vào mốc thời gian từng từ
final_result = whisperx.assign_word_speakers(diarize_segments, result)

# Hiển thị kết quả ra màn hình console
for segment in final_result["segments"]:
    speaker = segment.get("speaker", "UNKNOWN")
    start = segment["start"]
    end = segment["end"]
    text = segment["text"].strip()
    print(f"[{start:.2f}s -> {end:.2f}s] {speaker}: {text}")
    
    # In chi tiết timestamp từng từ để kiểm tra độ lệch
    words_detail = [f"{w['word']} ({w.get('start', 0):.2f}-{w.get('end', 0):.2f})" for w in segment.get("words", [])]
    print("   Chi tiết từ:", ", ".join(words_detail))

Bước 4: Khai thác dữ liệu đầu ra

Đầu ra của WhisperX là một mảng JSON chi tiết đến từng mili-giây cùng định danh người nói (như SPEAKER_00, SPEAKER_01). Với dữ liệu này, bạn có thể triển khai ngay 3 use-case thực tế:

  1. Tạo phụ đề động: Xuất file .srt hoặc .ass để render chữ chạy karaoke trên Premiere Pro, tự tin phụ đề khớp từng khung hình 100%.
  2. Tìm kiếm âm thanh (Audio Search): Cho phép người dùng gõ từ khóa và bấm nghe đúng giây phát âm trong kho lưu trữ hàng nghìn cuộc gọi.
  3. Tóm tắt cuộc họp bằng LLM: Nạp transcript có phân vai rõ ràng vào GPT-4o hoặc Claude 3.5 Sonnet để bóc tách action item của từng cá nhân mà không sợ nhầm lẫn người nói.
Share: