Từ kinh nghiệm triển khai hệ thống TTS (Text-to-Speech) cho dự án podcast tự động của mình, tôi nhận ra rằng chi phí API có thể trở thành gánh nặng lớn khi quy mô tăng lên. Trong bài viết này, tôi sẽ chia sẻ cách tôi triển khai Edge TTS - giải pháp tổng hợp giọng nói miễn phí với chất lượng cao, hoàn toàn chạy local.

Bảng so sánh chi phí AI và TTS 2026

Trước khi đi vào chi tiết kỹ thuật, hãy cùng xem bức tranh tổng quan về chi phí AI và TTS năm 2026:

Với 10 triệu token/tháng, chi phí sẽ là:

Để tối ưu chi phí, bạn có thể sử dụng nền tảng HolySheep AI với tỷ giá ¥1=$1 (tiết kiệm 85%+), hỗ trợ WeChat/Alipay, độ trễ dưới 50ms cùng tín dụng miễn phí khi đăng ký.

Edge TTS là gì và tại sao nên dùng?

Edge TTS là thư viện Python mã nguồn mở, sử dụng API tổng hợp giọng nói của Microsoft Edge để tạo âm thanh tự nhiên. Điểm mạnh của nó:

Cài đặt Edge TTS

pip install edge-tts

Hoặc sử dụng conda

conda install -c conda-forge edge-tts

Yêu cầu hệ thống: Python 3.8+, ffmpeg (để chuyển đổi định dạng âm thanh).

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

Cài đặt ffmpeg trên macOS

brew install ffmpeg

Cài đặt ffmpeg trên Windows (sử dụng winget)

winget install ffmpeg

Sử dụng cơ bản với Edge TTS

import edge_tts
import asyncio

async def synthesize_speech():
    """Tổng hợp giọng nói cơ bản"""
    
    # Khởi tạo communicate với text và giọng đọc
    communicate = edge_tts.Communicate(
        text="Xin chào! Đây là bài hướng dẫn Edge TTS của HolySheep AI.",
        voice="vi-VN-NamMinhNeural"  # Giọng tiếng Việt Nam
    )
    
    # Lưu thành file MP3
    await communicate.save("output.mp3")
    print("Đã tạo file output.mp3 thành công!")

Chạy async function

asyncio.run(synthesize_speech())

Danh sách giọng đọc tiếng Việt

import edge_tts

async def list_vietnamese_voices():
    """Liệt kê tất cả giọng tiếng Việt có sẵn"""
    
    voices = await edge_tts.list_voices()
    
    # Lọc giọng tiếng Việt
    vi_voices = [v for v in voices if v["Locale"].startswith("vi")]
    
    print("=" * 60)
    print("DANH SÁCH GIỌNG TIẾNG VIỆT")
    print("=" * 60)
    
    for voice in vi_voices:
        print(f"Tên: {voice['Name']}")
        print(f"  Locale: {voice['Locale']}")
        print(f"  Giới tính: {voice['Gender']}")
        print(f"  ShortName: {voice['ShortName']}")
        print("-" * 40)

Chạy

asyncio.run(list_vietnamese_voices())

Kết quả điển hình:

Tùy chỉnh tham số nâng cao

import edge_tts
import asyncio

async def advanced_synthesis():
    """Tổng hợp với các tham số nâng cao"""
    
    # Các tham số điều chỉnh:
    # - Rate: Tốc độ đọc (-50% đến +100%)
    # - Volume: Âm lượng (-50% đến +50%)  
    # - Pitch: Cao độ (Hz)
    
    communicate = edge_tts.Communicate(
        text="Chào mừng bạn đến với hướng dẫn Edge TTS. "
             "Tôi sẽ hướng dẫn bạn cách tùy chỉnh giọng nói.",
        voice="vi-VN-HoaiMyNeural",
        rate="+10%",      # Nhanh hơn 10%
        volume="+5%",     # To hơn 5%
        pitch="+10Hz"     # Cao hơn 10Hz
    )
    
    # Xuất văn bản SSML để kiểm tra
    # substitute = await communicate.get_ssml()
    # print(substitute)
    
    await communicate.save("advanced_output.mp3")
    print("Đã tạo file với tốc độ và âm lượng tùy chỉnh!")

asyncio.run(advanced_synthesis())

Tích hợp với HolySheep AI cho pipeline hoàn chỉnh

Trong thực tế, tôi thường kết hợp Edge TTS với HolySheep AI để tạo pipeline hoàn chỉnh: dùng LLM để tạo nội dung, rồi dùng Edge TTS để chuyển thành giọng nói. Dưới đây là ví dụ:

import edge_tts
import openai
import asyncio
import re

Cấu hình HolySheep AI - KHÔNG dùng api.openai.com

openai.api_base = "https://api.holysheep.ai/v1" openai.api_key = "YOUR_HOLYSHEEP_API_KEY" # Thay bằng key của bạn async def generate_and_speak(topic: str, voice: str = "vi-VN-NamMinhNeural"): """ Pipeline hoàn chỉnh: Tạo nội dung bằng LLM -> Tổng hợp giọng nói Chi phí: DeepSeek V3.2 chỉ $0.42/MTok """ # Bước 1: Gọi LLM để tạo nội dung response = openai.ChatCompletion.create( model="deepseek-chat", # Hoặc gpt-4.1, claude-3-5-sonnet, gemini-2.0-flash messages=[ { "role": "system", "content": "Bạn là người viết bài podcast ngắn gọn, súc tích." }, { "role": "user", "content": f"Viết một đoạn podcast 200 từ về chủ đề: {topic}" } ], max_tokens=500, temperature=0.7 ) content = response.choices[0].message.content print(f"Nội dung tạo được: {len(content)} ký tự") # Bước 2: Làm sạch text cho TTS # Loại bỏ các ký tự đặc biệt không phù hợp clean_text = re.sub(r'[📌•→●★]', '-', content) clean_text = re.sub(r'\n{3,}', '\n\n', clean_text) # Bước 3: Tổng hợp giọng nói với Edge TTS communicate = edge_tts.Communicate( text=clean_text, voice=voice, rate="+5%", volume="+0%" ) output_file = f"podcast_{topic[:20].replace(' ', '_')}.mp3" await communicate.save(output_file) print(f"✅ Đã tạo podcast: {output_file}") # Báo cáo chi phí input_tokens = response.usage.prompt_tokens output_tokens = response.usage.completion_tokens total_tokens = response.usage.total_tokens cost_per_million = 0.42 # DeepSeek V3.2 cost = (total_tokens / 1_000_000) * cost_per_million print(f"💰 Chi phí LLM: ${cost:.4f} ({total_tokens} tokens)") print(f"📊 Chi phí TTS: Miễn phí (Edge TTS local)")

Chạy demo

asyncio.run(generate_and_speak("Công nghệ AI 2026"))

Xử lý text dài với chunking

Khi xử lý văn bản dài (podcast, audiobook), bạn cần chia nhỏ text để tránh timeout:

import edge_tts
import asyncio
import re

class EdgeTTSLongForm:
    """Xử lý văn bản dài bằng chunking thông minh"""
    
    def __init__(self, voice: str = "vi-VN-NamMinhNeural"):
        self.voice = voice
        self.CHUNK_SIZE = 3000  # Ký tự mỗi chunk
        self.CHUNK_OVERLAP = 200  # Độ chồng lấn
        
    async def synthesize_long_text(self, text: str, output_file: str):
        """Tổng hợp văn bản dài thành file MP3"""
        
        # Chia văn bản thành các đoạn
        chunks = self._split_into_chunks(text)
        
        print(f"Tổng cộng {len(chunks)} đoạn cần xử lý...")
        
        # Tạo list các task
        tasks = []
        for i, chunk in enumerate(chunks):
            print(f"  Đang xử lý đoạn {i+1}/{len(chunks)}...")
            
            communicate = edge_tts.Communicate(
                text=chunk.strip(),
                voice=self.voice,
                rate="+5%"
            )
            
            temp_file = f"temp_chunk_{i:03d}.mp3"
            tasks.append(communicate.save(temp_file))
        
        # Chạy song song (giới hạn 5 task cùng lúc)
        for i in range(0, len(tasks), 5):
            batch = tasks[i:i+5]
            await asyncio.gather(*batch)
        
        # Ghép các file MP3
        await self._merge_audio_files(len(chunks), output_file)
        
        # Dọn file tạm
        for i in range(len(chunks)):
            temp_file = f"temp_chunk_{i:03d}.mp3"
            try:
                import os
                os.remove(temp_file)
            except:
                pass
        
        print(f"✅ Hoàn thành: {output_file}")
    
    def _split_into_chunks(self, text: str) -> list:
        """Chia văn bản thành các đoạn có ý nghĩa"""
        
        # Tách theo câu
        sentences = re.split(r'(?<=[.!?])\s+', text)
        
        chunks = []
        current_chunk = ""
        
        for sentence in sentences:
            if len(current_chunk) + len(sentence) < self.CHUNK_SIZE:
                current_chunk += sentence + " "
            else:
                if current_chunk:
                    chunks.append(current_chunk.strip())
                # Overlap
                words = current_chunk.split()[-20:]
                current_chunk = " ".join(words) + " " + sentence + " "
        
        if current_chunk.strip():
            chunks.append(current_chunk.strip())
        
        return chunks
    
    async def _merge_audio_files(self, num_chunks: int, output_file: str):
        """Ghép các file MP3 thành một"""
        # Sử dụng pydub hoặc ffmpeg để merge
        from pydub import AudioSegment
        
        combined = AudioSegment.empty()
        
        for i in range(num_chunks):
            temp_file = f"temp_chunk_{i:03d}.mp3"
            audio = AudioSegment.from_mp3(temp_file)
            combined += audio
        
        combined.export(output_file, format="mp3")


Sử dụng

async def demo_long_form(): tts = EdgeTTSLongForm(voice="vi-VN-HoaiMyNeural") long_text = """ Đây là một văn bản dài mô phỏng nội dung podcast. Với Edge TTS, bạn có thể tổng hợp hàng nghìn ký tự mà không tốn chi phí. Kết hợp với HolySheep AI để tạo nội dung tự động. """ # Lặp lại để tạo văn bản dài long_text = long_text * 50 await tts.synthesize_long_text(long_text, "long_podcast.mp3") asyncio.run(demo_long_form())

Triển khai Docker cho production

Để sử dụng Edge TTS trong môi trường production, tôi khuyên dùng Docker:

# Dockerfile
FROM python:3.11-slim

WORKDIR /app

Cài đặt ffmpeg

RUN apt-get update && apt-get install -y \ ffmpeg \ && rm -rf /var/lib/apt/lists/*

Cài đặt thư viện Python

RUN pip install --no-cache-dir \ edge-tts \ fastapi \ uvicorn \ pydub

Copy code

COPY app.py .

Expose port

EXPOSE 8000

Chạy server

CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
# app.py - FastAPI server cho Edge TTS
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import edge_tts
import asyncio
import uuid
import os

app = FastAPI(title="Edge TTS API", version="1.0.0")

class TTSRequest(BaseModel):
    text: str
    voice: str = "vi-VN-NamMinhNeural"
    rate: str = "+0%"
    volume: str = "+0%"
    format: str = "mp3"  # mp3, wav, ogg

class TTSResponse(BaseModel):
    success: bool
    audio_url: str = None
    duration_seconds: float = None
    error: str = None

@app.post("/tts", response_model=TTSResponse)
async def text_to_speech(request: TTSRequest):
    try:
        # Validate voice
        voices = await edge_tts.list_voices()
        valid_voice = any(v["ShortName"] == request.voice for v in voices)
        
        if not valid_voice:
            return TTSResponse(
                success=False,
                error=f"Voice '{request.voice}' không hợp lệ"
            )
        
        # Tạo file tạm
        filename = f"{uuid.uuid4()}.mp3"
        
        # Tổng hợp
        communicate = edge_tts.Communicate(
            text=request.text,
            voice=request.voice,
            rate=request.rate,
            volume=request.volume
        )
        
        await communicate.save(filename)
        
        # Lấy thông tin duration
        from pydub import AudioSegment
        audio = AudioSegment.from_mp3(filename)
        duration = len(audio) / 1000  # Convert ms to seconds
        
        # Cleanup
        os.remove(filename)
        
        return TTSResponse(
            success=True,
            audio_url=f"/audio/{filename}",
            duration_seconds=duration
        )
        
    except Exception as e:
        return TTSResponse(
            success=False,
            error=str(e)
        )

@app.get("/voices")
async def list_voices():