Quick Start
  1. Đăng ký tài khoản miễn phí → nhận credits khởi đầu
  2. Vào API Keys → tạo key mới
  3. Gửi request với header Authorization: Bearer YOUR_API_KEY
  4. Đọc docs phía dưới để biết endpoints + parameters
Hướng dẫn sử dụng API

🔐 Authentication

Mọi API request cần gửi API key qua HTTP header:

Authorization: Bearer sk-ov-YOUR_API_KEY
  1. Đăng ký tài khoản tại /register
  2. Vào /api-keys → click "Tạo Key mới"
  3. Copy key (format sk-ov-xxxxxxxx...) và gửi trong header mọi request

⚠️ Key không hợp lệ hoặc bị disable → HTTP 401 Unauthorized. Có thể quản lý (Active / Disabled / Delete) nhiều keys cùng lúc trong tab API Keys.

⏱️ Rate Limits

Loại giới hạnGiá trịMô tả
Requests/phút (per user)10Số request tối đa 1 phút/user
Concurrent jobs (API, per user)2Số job xử lý đồng thời/user
Concurrent jobs (server total)5Tổng concurrent jobs toàn server

Khi vượt giới hạn → HTTP 429 Too Many Requests. Client nên:

📌 Rate limits có thể được admin điều chỉnh per-user. Xem limits hiện tại của bạn trong /dashboard.

Endpoints

MethodEndpointMô tả
GET/api/v1/healthKiểm tra trạng thái server
GET/api/v1/optionsLấy danh sách tùy chọn voice
POST/api/v1/tts/designTạo voice từ mô tả
POST/api/v1/tts/cloneClone voice từ audio mẫu
POST/api/v1/tts/autoTự động tạo voice
GET/api/v1/voicesLấy danh sách giọng đã lưu
POST/api/v1/tts/savedTạo voice từ giọng đã lưu (voice_id)
POST/api/v1/tts/dialogueHội thoại đa giọng (Multi-Voice Dialogue)
POST/api/v1/sttChuyển giọng nói thành text (STT v1, Whisper HuggingFace)
POST/api/v2/stt⚡ STT v2 (FasterWhisper - nhanh hơn 4-5x, có VAD)
POST/api/v1/srt-to-voiceSRT → Voice (timing-synced TTS)
POST/api/v1/audio-separateTách vocals khỏi nhạc nền (Demucs)
GET/api/v1/job/{job_id}Kiểm tra trạng thái job (async mode) — dùng chung cho v1 + v2
POST/api/v1/job/{job_id}/cancelHủy job đang queued/picked + refund credits

1. Text-to-Speech (TTS)

POST /api/v1/tts/design — Tạo voice từ mô tả
ParamTypeBắt buộcMô tả
textstringNội dung cần đọc
languagestringNgôn ngữ: vietnamese, english, chinese, japanese, korean, french...
genderstringmale / female
agestringchild, young adult, middle-aged, elderly
pitchstringlow pitch, moderate pitch, high pitch
stylestringnormal, cheerful, sad, angry, whisper...
instructstringMô tả trực tiếp (thay thế gender/age/pitch/style)
speedfloatTốc độ đọc (default: 1.0)
num_stepintSố bước diffusion (default: 32, cao hơn = chất lượng hơn)
guidance_scalefloatGuidance scale (default: 2.0)
denoiseboolKhử nhiễu (default: true)
async_modeboolChế độ async: trả về job_id thay vì chờ audio (default: false)

📥 Response: audio/wav file | Nếu async_mode=true: JSON {job_id, status, credits_used}

POST /api/v1/tts/clone — Clone voice từ audio mẫu
ParamTypeBắt buộcMô tả
textstringNội dung cần đọc
ref_audiofileFile audio mẫu để clone giọng (wav, mp3, flac...)
languagestringNgôn ngữ: vietnamese, english, chinese...
speedfloatTốc độ đọc (default: 1.0)
num_stepintSố bước diffusion (default: 32)
denoiseboolKhử nhiễu (default: true)
async_modeboolChế độ async: trả về job_id thay vì chờ audio (default: false)

📥 Response: audio/wav file | Nếu async_mode=true: JSON {job_id, status, credits_used}

POST /api/v1/tts/auto — Tự động tạo voice
ParamTypeBắt buộcMô tả
textstringNội dung cần đọc
languagestringNgôn ngữ (default: auto)
speedfloatTốc độ đọc (default: 1.0)
num_stepintSố bước diffusion (default: 32)
denoiseboolKhử nhiễu (default: true)
async_modeboolChế độ async: trả về job_id thay vì chờ audio (default: false)

📥 Response: audio/wav file | Nếu async_mode=true: JSON {job_id, status, credits_used}

POST /api/v1/tts/saved — Tạo voice từ giọng đã lưu
ParamTypeBắt buộcMô tả
textstringNội dung cần đọc
voice_idintID giọng đã lưu (lấy từ GET /api/v1/voices)
languagestringNgôn ngữ (default: auto)
speedfloatTốc độ đọc (default: 1.0)
num_stepintSố bước diffusion (default: 32)
denoiseboolKhử nhiễu (default: true)
async_modeboolChế độ async: trả về job_id thay vì chờ audio (default: false)

📥 Response: audio/wav file | Nếu async_mode=true: JSON {job_id, status, credits_used}

POST /api/v1/tts/dialogue — Hội thoại đa giọng

Tạo audio hội thoại với nhiều nhân vật, mỗi nhân vật dùng 1 giọng đã lưu. Tính phí theo tổng ký tự lời thoại (không tính #TênNhânVật).

ParamTypeBắt buộcMô tả
textstringKịch bản hội thoại. Format: #TênNhânVật trên 1 dòng, lời thoại bên dưới
char_voice_mapstring (JSON)JSON mapping nhân vật → voice_id. VD: {"MC": 1, "Guest": 2}
languagestringNgôn ngữ (default: auto)
speedfloatTốc độ đọc (default: 1.0)
num_stepintSố bước diffusion (default: 32)
denoiseboolKhử nhiễu (default: true)
async_modeboolChế độ async (default: false)
// text format:
#MC
Xin chào các bạn, hôm nay chúng ta sẽ nói về AI.
#Guest
Cảm ơn MC, tôi rất vui được ở đây.
#MC
Vậy anh có thể giới thiệu về mình không?

// char_voice_map:
{"MC": 1, "Guest": 2}

📥 Response: audio/wav file | Nếu async_mode=true: JSON {job_id, status, credits_used}

GET /api/v1/voices — Lấy danh sách giọng đã lưu

Không cần tham số.

// Response
[
  {"id": 1, "name": "Giọng MC", "type": "design", "instruct": "male, young adult", ...},
  {"id": 2, "name": "Clone Boss", "type": "clone", ...}
]

💡 Giới hạn lưu voice: mỗi tài khoản có hạn mức voice lưu (mặc định 3). Việc lưu giọng mới phải thực hiện qua giao diện web (POST /voices/save, cookie-auth). Khi đã đầy, request lưu trả về HTTP 409. Liên hệ admin để nâng hạn mức.

1.1. Async Job Flow (Khuyến nghị cho văn bản dài)

Thêm async_mode=true vào bất kỳ TTS endpoint nào. Server trả về job_id ngay lập tức, bạn poll trạng thái để lấy audio khi xong.

# Step 1: Submit job
curl -X POST "https://your-domain/api/v1/tts/design" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "text=Nội dung dài cần xử lý..." \
  -F "async_mode=true"

# Response:
# {"job_id": "abc123def456", "status": "queued", "credits_used": 2.5}

# Step 2: Poll status (mỗi 3-5 giây)
curl "https://your-domain/api/v1/job/abc123def456" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Response (đang xử lý):
# {"job_id": "abc123def456", "status": "processing"}

# Response (hoàn thành):
# {"job_id": "abc123def456", "status": "completed", "audio_url": "/audio/tts_xxx.wav"}

# Step 3: Download audio
curl -O "https://your-domain/audio/tts_xxx.wav" \
  -H "Authorization: Bearer YOUR_API_KEY"

💡 Lưu ý: Nếu job thất bại, credits sẽ được hoàn lại tự động. Status: queued → processing → completed/failed.

2. Speech-to-Text (STT) — Audio & Video

POST /api/v1/stt — Chuyển audio/video thành text + SRT

Upload file audio HOẶC video để chuyển thành text. Video được auto-extract audio qua ffmpeg. Hỗ trợ 70+ ngôn ngữ. Output dạng JSON / SRT / VTT / TXT.

ParamTypeBắt buộcMô tả
audio_filefileFile audio (wav, mp3, flac, m4a, ogg...) hoặc video (mp4, mov, mkv, webm, avi, flv, wmv, m4v...). Tự động phát hiện qua extension.
languagestringNgôn ngữ audio (default: auto detect). Ví dụ: vietnamese, english, japanese, korean...
output_formatstringjson (default) — JSON full data · srt — tải file .srt · vtt — tải file .vtt · txt — tải file .txt
async_modeboolChế độ async: trả về job_id thay vì chờ kết quả (default: false). Lưu ý: audio > 2 phút tự động chuyển sang async mode.
⚡ Auto-async cho audio dài: File audio/video > 2 phút (120s) sẽ tự động chuyển sang async mode dù không gửi async_mode=true. Response trả job_id thay vì kết quả trực tiếp. Client cần poll GET /api/v1/job/{job_id} để lấy kết quả.
File ≤ 2 phút vẫn hoạt động sync như bình thường (backward compatible).

📥 Response (Sync — file ≤ 2 phút): JSON | SRT | VTT | TXT tuỳ output_format.

// Response — Sync mode (audio ≤ 2 phút)
{
  "text": "Nội dung được nhận diện từ audio...",
  "language": "vietnamese",
  "duration_secs": 45.2,
  "credits_used": 135.00,
  "media_type": "audio",
  "srt_url": "/audio/stt_abc.srt"
}

📥 Response (Async — file > 2 phút hoặc async_mode=true):

// Step 1: Submit — trả job_id ngay lập tức
{
  "job_id": "abc123def456",
  "status": "queued",
  "credits_used": 752.50,
  "media_type": "video",
  "duration_secs": 1200.0,
  "async": true
}

// Step 2: Poll GET /api/v1/job/abc123def456
{
  "status": "completed",
  "job_type": "stt",
  "text": "Nội dung...",
  "language": "vietnamese",
  "duration_secs": 1200.0,
  "srt_url": "/audio/stt_abc.srt"
}
Tính phí:
• Audio: 3000 credits / phút
• Video: 3600 credits / phút (bao gồm chi phí extract audio)
Giới hạn:
• Audio: max 50MB, 2000s
• Video: max 100MB, 1800s

⚡ 2b. Speech-to-Text v2 (FasterWhisper) — Nhanh hơn 4-5x

⚡ Khác biệt với v1:
• Engine: FasterWhisper (CTranslate2 backend) thay vì HuggingFace pipeline
• Tốc độ: 4-5x nhanh hơn (audio 20 phút: v1 ~8 phút → v2 ~2 phút)
• VAD filter: cắt silence tự động → giảm hallucination, tăng tốc thêm
LUÔN async (kể cả file ngắn < 2 phút): trả job_id ngay, poll GET /api/v1/job/{id} đến khi status=completed để lấy text + srt_url
Không có sync mode như v1 — luôn trả JSON với job_id, không bao giờ trả file trực tiếp
• Hoàn toàn độc lập với /api/v1/stt — không ảnh hưởng tool đang dùng v1
🚨 Bool params — BẮT BUỘC ĐÚNG FORMAT:
Khi gửi vad_filter hay word_timestamps trong form-data:
• ✅ ĐÚNG: true, false, 1, 0, yes, no
• ❌ SAI: True (Pythonic), giá trị viết hoa khác — server sẽ ignore và dùng default từ Admin
• Tốt nhất: dùng 1/0 để chắc chắn cross-platform
POST /api/v2/stt — Chuyển audio/video thành text + SRT (FasterWhisper)
ParamTypeBắt buộcMô tả
audio_filefileFile audio (wav, mp3, flac, m4a, ogg) hoặc video (mp4, mov, mkv, webm, avi, flv...). Auto-detect.
languagestringNgôn ngữ (default: auto). Ví dụ: vietnamese, english, chinese, japanese...
output_formatstringjson (default) — full data trong job poll · srt/vtt/txt
beam_sizeintBeam search size (1=greedy fastest, 5=balance default, 10=quality). Override Admin default
vad_filterboolBật VAD lọc silence. Default: lấy từ Admin (mặc định true). Format chấp nhận: true/false, 1/0, yes/no
temperaturefloatSampling temp (0.0=deterministic, 0.4=variety). Default: lấy từ Admin (mặc định 0.0)
initial_promptstringPrompt giúp Whisper nhận diện thuật ngữ riêng. Default: lấy từ Admin (mặc định trống). VD: "Đây là podcast về AI, có nhắc tên Lương, Hùng"
word_timestampsboolWord-level timestamps (cần cho SRT chuẩn). Default: lấy từ Admin (mặc định true). Format giống vad_filter

📥 Response (luôn async):

// Step 1: Submit
{
  "job_id": "abc123def456",
  "status": "queued",
  "media_type": "audio",
  "engine": "faster-whisper"
}

// Step 2: Poll GET /api/v1/job/abc123def456 → khi completed:
{
  "status": "completed",
  "job_type": "stt_v2",
  "text": "Nội dung được nhận diện...",
  "language": "vi",
  "duration_secs": 1200.0,
  "srt_file": "stt_xxx.srt",
  "srt_url": "/audio/stt_xxx.srt",
  "engine": "faster-whisper"
}
Tính phí (giống nhau cho audio + video):
• Web: 1500 credits/phút
• API: 2500 credits/phút
Lưu ý: Video v2 KHÔNG tính phụ phí extract (khác với v1). Tính theo độ dài audio sau khi extract.
Giới hạn: dùng chung với v1 (audio max 50MB/2000s, video max 100MB/1800s)
Engine settings (Admin → STT v2): model size, compute type, beam size, VAD threshold, temperature, lazy unload
Cancel job đang chạy (apply cho cả v1 + v2)

Job ở trạng thái queued hoặc picked có thể hủy. Job đang processing không hủy được. Credits tự động refund nếu đã trừ.

curl -X POST "https://your-domain/api/v1/job/abc123/cancel" \
  -H "Authorization: Bearer YOUR_API_KEY"
# → {"success":true,"message":"Job cancelled and credits refunded"}
⚠️ Best Practices khi build tool API client (QUAN TRỌNG)

3 lỗi phổ biến cần tránh:

1. ❌ Hardcode file size limit cho TẤT CẢ file

Server có 2 limit khác nhau: audio = 50MB, video = 100MB (mặc định, admin chỉnh được). Tool client nên detect video/audio theo extension và dùng limit phù hợp, hoặc bỏ luôn check client-side để server tự reject.

// ❌ SAI:
const long MAX_BYTES = 50 * 1024 * 1024;  // chỉ phù hợp audio

// ✅ ĐÚNG:
bool isVideo = IsVideoFile(filename);  // check by extension
long maxBytes = isVideo ? 500*1024*1024 : 50*1024*1024;
if (file.Length > maxBytes) throw new Exception("File too large");

// ✅ HOẶC: Bỏ check client, để server reject (KISS, không lệch khi admin đổi setting)

2. ❌ Throw exception khi text rỗng

Audio im lặng / nhạc nền không lời / file lỗi → text có thể rỗng. KHÔNG nên throw cứng nhắc, hãy tolerant: chỉ báo lỗi khi cả text lẫn srt_url đều rỗng.

// ❌ SAI:
if (string.IsNullOrWhiteSpace(result.Text)) throw new Exception("Text rỗng!");

// ✅ ĐÚNG:
if (string.IsNullOrWhiteSpace(result.Text) && string.IsNullOrEmpty(result.SrtUrl))
    throw new Exception("Audio không có nội dung nhận diện được");
// → Cho phép có SRT mà text rỗng (hoặc ngược lại) — vẫn show user

3. ❌ Không retry khi SRT download fail

Endpoint /audio/{filename} KHÔNG yêu cầu Bearer auth (nhưng gửi cũng không sao). Network glitch có thể fail 1 request. Nên retry 1-2 lần với delay 2s. KHÔNG fallback về chunks vì v2 response không có field này (chỉ có srt_file + srt_url).

// ✅ Retry 2 lần:
for (int retry = 0; retry < 2; retry++) {
    try { srtBytes = await DownloadAsync(srtUrl); break; }
    catch (Exception ex) {
        Logger.Warn($"SRT download fail (retry {retry+1}/2): {ex.Message}");
        if (retry == 1) throw;
        await Task.Delay(2000);
    }
}
💡 Khuyến nghị thêm cho client production
Curl examples — STT v2
# ────── STT v2 cơ bản ──────
curl -X POST "https://your-domain/api/v2/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "language=vietnamese"
# → {"job_id":"abc","status":"queued","engine":"faster-whisper"}

# ────── Poll kết quả ──────
curl "https://your-domain/api/v1/job/abc" \
  -H "Authorization: Bearer YOUR_API_KEY"
# → {"status":"completed","text":"...","srt_url":"/audio/stt_xxx.srt"}

# ────── STT v2 với custom params (override Admin defaults) ──────
# Lưu ý: bool dùng 1/0 để chắc chắn (true/false cũng OK)
curl -X POST "https://your-domain/api/v2/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "language=vietnamese" \
  -F "beam_size=10" \
  -F "vad_filter=1" \
  -F "temperature=0.0" \
  -F "word_timestamps=1" \
  -F "initial_prompt=Đây là podcast về AI, công nghệ, có tên Lương, Hùng, Minh"

# ────── STT v2 với video ──────
curl -X POST "https://your-domain/api/v2/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "language=auto"

# ────── Workflow đầy đủ (bash polling) ──────
JOB=$(curl -s -X POST "https://your-domain/api/v2/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" | jq -r .job_id)
echo "Job: $JOB"
while true; do
  STATUS=$(curl -s "https://your-domain/api/v1/job/$JOB" -H "Authorization: Bearer YOUR_API_KEY")
  S=$(echo "$STATUS" | jq -r .status)
  if [ "$S" = "completed" ] || [ "$S" = "failed" ]; then
    echo "$STATUS" | jq .
    break
  fi
  echo "Status: $S, polling..."
  sleep 3
done
Python example — Production-ready (apply best practices)
import os, time, requests
from pathlib import Path

BASE = "https://your-domain"
API_KEY = "YOUR_API_KEY"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# Best Practice: detect video by extension
VIDEO_EXTS = {".mp4", ".mov", ".mkv", ".webm", ".avi", ".flv", ".wmv", ".m4v"}
def is_video(filename):
    return Path(filename).suffix.lower() in VIDEO_EXTS

def stt_v2(audio_path, language="vietnamese", **engine_overrides):
    """STT v2 với best practices đầy đủ."""
    fname = os.path.basename(audio_path)
    file_size = os.path.getsize(audio_path)

    # Best Practice 1: detect video → dùng limit phù hợp
    max_mb = 500 if is_video(fname) else 50
    if file_size > max_mb * 1024 * 1024:
        raise ValueError(f"File quá lớn: {file_size/1024/1024:.1f}MB > {max_mb}MB")

    # Submit (timeout 30 phút cho file lớn)
    with open(audio_path, "rb") as f:
        data = {"language": language}
        data.update({k: str(v) for k, v in engine_overrides.items() if v is not None})
        resp = requests.post(f"{BASE}/api/v2/stt",
            headers=HEADERS, files={"audio_file": f}, data=data,
            timeout=1800)  # 30 phút
    resp.raise_for_status()
    job = resp.json()
    job_id = job["job_id"]
    print(f"Job: {job_id}")

    # Poll với retry network error (job có thể chạy lâu)
    while True:
        try:
            r = requests.get(f"{BASE}/api/v1/job/{job_id}",
                            headers=HEADERS, timeout=30)
            r.raise_for_status()
            st = r.json()
        except requests.RequestException as e:
            print(f"Network glitch, retry in 5s: {e}")
            time.sleep(5)
            continue

        if st["status"] == "completed":
            text = st.get("text", "")
            srt_url = st.get("srt_url", "")
            # Best Practice 2: tolerant với text rỗng (chỉ throw khi BOTH rỗng)
            if not text and not srt_url:
                raise RuntimeError("Audio không có nội dung nhận diện được")
            # Download SRT với retry
            srt_content = None
            if srt_url:
                for attempt in range(2):
                    try:
                        srt_resp = requests.get(BASE + srt_url, timeout=60)
                        srt_resp.raise_for_status()
                        srt_content = srt_resp.text
                        break
                    except Exception as e:
                        if attempt == 1:
                            print(f"SRT download fail (đã thử 2 lần): {e}")
                        else:
                            time.sleep(2)
            return {"text": text, "srt": srt_content,
                    "duration_secs": st.get("duration_secs"),
                    "language": st.get("language"),
                    "credits_used": st.get("credits_used"),
                    "credits_remaining": st.get("credits_remaining")}

        if st["status"] in ("failed", "cancelled"):
            raise RuntimeError(f"Job {st['status']}: {st.get('error', 'unknown')}")

        print(f"Status: {st['status']}, polling...")
        time.sleep(3)


# Usage
result = stt_v2("podcast.mp3", language="vietnamese",
                beam_size=5, vad_filter=1,
                initial_prompt="Đây là podcast về AI")
print("Text:", result["text"][:200])
print("Credits used:", result["credits_used"])
if result["srt"]:
    Path("output.srt").write_text(result["srt"], encoding="utf-8")
    print("SRT saved to output.srt")

3. SRT → Voice (Timing-synced TTS)

POST /api/v1/srt-to-voice — Tạo voice từ file SRT khớp timing

Upload file .srt + chọn voice đã lưu → hệ thống tạo audio MP3 với giọng TTS khớp với timing từng đoạn sub. Luôn chạy async mode — trả về job_id, poll /api/v1/job/{id} để lấy audio_url khi xong.

ParamTypeBắt buộcMô tả
srt_filefileFile SRT (encoding UTF-8 khuyến nghị). Format chuẩn WebVTT/SRT với timestamps HH:MM:SS,mmm
voice_idintID giọng đã lưu (từ GET /api/v1/voices)
languagestringNgôn ngữ TTS target (default: auto). Ví dụ: vietnamese, english, japanese...

📥 Response (async): JSON {job_id, cue_count, total_duration, credits_used}. Poll GET /api/v1/job/{job_id} đến khi status=completed → response có audio_url.

// Initial response
{
  "job_id": "abc123def456",
  "status": "queued",
  "credits_used": 15.60,
  "cue_count": 42,
  "total_duration": 180.5
}

// Poll /api/v1/job/abc123def456 when completed:
{
  "job_id": "abc123def456",
  "status": "completed",
  "audio_url": "/audio/srt2voice_xxx.mp3",
  "progress_pct": 100
}
Tính phí: 1440.0 credits / 1000 ký tự (= giá TTS API × markup 120%, admin configurable)
Giới hạn:
• Max SRT file: 500KB
• Max cues/job: 500
• Formats: SRT chuẩn (.srt UTF-8)
Timing behavior: Hybrid mode (default) — không cắt chữ cuối câu. Audio có thể dài hơn SRT gốc ±5% để bảo toàn ý nghĩa.

💡 Use case: video dubbing (transcribe video → dịch SRT sang ngôn ngữ khác → gen voice mới khớp timing), voiceover từ kịch bản, audiobook từ subtitle...

4. Audio Source Separation (Demucs)

POST /api/v1/audio-separate — Tách giọng nói khỏi nhạc nền

Upload file audio HOẶC video → tách thành 2 stems: vocals (giọng nói) và instrumental (nhạc nền). Sử dụng Demucs htdemucs (Meta Research). Luôn chạy async mode — trả về job_id, poll /api/v1/job/{id} để lấy URL khi xong.

ParamTypeBắt buộcMô tả
audio_filefileFile audio (mp3, wav, flac, m4a...) hoặc video (mp4, mov, mkv...). Tự động extract audio nếu là video.
modestringall (default) — tách cả vocals + instrumental · vocals — chỉ giọng nói · instrumental — chỉ nhạc nền

📥 Response (async): JSON {job_id, mode, duration_secs, credits_used}. Poll job → completed → response có vocals_url + instrumental_url.

// Initial response
{
  "job_id": "abc123def456",
  "status": "queued",
  "mode": "all",
  "duration_secs": 180.5,
  "credits_used": 13500.0
}

// Poll /api/v1/job/abc123def456 when completed:
{
  "job_id": "abc123def456",
  "status": "completed",
  "vocals_url": "/audio/sep_xxx_vocals.mp3",
  "instrumental_url": "/audio/sep_xxx_instrumental.mp3"
}
Tính phí: 4500 credits / phút audio
Giới hạn:
• Max file: 100MB
• Max duration: 1200s (20 phút)
• Output: MP3 192kbps stereo

💡 Use case: tách vocals cho karaoke, isolate giọng nói để STT chính xác hơn, remix nhạc, podcast cleanup, voice cloning từ video có nhạc nền.
⚠️ Lưu ý: Demucs train trên music data (giọng hát + nhạc cụ). Quality TỐT NHẤT khi audio có cả giọng + nhạc rõ ràng. Cho speech + ambient noise (không phải music), kết quả có thể kém.

Mã lỗi

HTTP CodeMô tả
200Thành công
400Lỗi request (thiếu param, file quá lớn, audio quá dài, text quá dài...)
401API key không hợp lệ hoặc thiếu header Authorization
402Không đủ credits
429Quá nhiều request đồng thời (vượt giới hạn concurrent)
500Lỗi server nội bộ

Ví dụ (curl)

# ────── TTS: Voice Design ──────
curl -X POST "https://your-domain/api/v1/tts/design" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "text=Xin chào, đây là giọng nói AI" \
  -F "language=vietnamese" \
  -F "gender=female" \
  -F "age=young adult" \
  -F "pitch=moderate pitch" \
  --output voice.wav

# ────── TTS: Voice Clone ──────
curl -X POST "https://your-domain/api/v1/tts/clone" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "text=Nội dung cần đọc" \
  -F "language=vietnamese" \
  -F "[email protected]" \
  --output cloned.wav

# ────── TTS: Auto ──────
curl -X POST "https://your-domain/api/v1/tts/auto" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "text=Hello world, this is AI voice" \
  -F "language=english" \
  --output auto.wav

# ────── TTS: Saved Voice ──────
curl -X POST "https://your-domain/api/v1/tts/saved" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "text=Xin chào, đây là giọng đã lưu" \
  -F "voice_id=1" \
  -F "language=vietnamese" \
  --output saved_voice.wav

# ────── TTS: Multi-Voice Dialogue ──────
curl -X POST "https://your-domain/api/v1/tts/dialogue" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F 'text=#MC
Xin chào các bạn!
#Guest
Cảm ơn MC, tôi rất vui.' \
  -F 'char_voice_map={"MC": 1, "Guest": 2}' \
  -F "language=vietnamese" \
  --output dialogue.wav

# ────── List Saved Voices ──────
curl "https://your-domain/api/v1/voices" \
  -H "Authorization: Bearer YOUR_API_KEY"

# ────── STT: Audio ngắn (≤2 phút) → sync JSON ──────
curl -X POST "https://your-domain/api/v1/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "language=vietnamese"
# → trả kết quả ngay: {"text":"...","duration_secs":45.2,...}

# ────── STT: Audio dài (>2 phút) → auto-async ──────
curl -X POST "https://your-domain/api/v1/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "audio_file=@podcast_20min.mp3"
# → trả job_id: {"job_id":"abc123","status":"queued","async":true}
# → poll: curl .../api/v1/job/abc123 -H "Authorization: ..."

# ────── STT: Force async (bất kể duration) ──────
curl -X POST "https://your-domain/api/v1/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "async_mode=true"

# ────── STT: Video → SRT (sync, file ngắn) ──────
curl -X POST "https://your-domain/api/v1/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "language=vietnamese" \
  -F "output_format=srt" \
  -o transcription.srt

# ────── STT: Video → VTT (for web players) ──────
curl -X POST "https://your-domain/api/v1/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "output_format=vtt" \
  -o subtitles.vtt

# ────── STT: Video → TXT only (plain transcript) ──────
curl -X POST "https://your-domain/api/v1/stt" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "output_format=txt" \
  -o transcript.txt

# ────── SRT → Voice: timing-synced TTS ──────
# Step 1: Submit SRT + voice → get job_id
curl -X POST "https://your-domain/api/v1/srt-to-voice" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "voice_id=1" \
  -F "language=vietnamese"

# Response: {"job_id":"abc123...","status":"queued","cue_count":42,"credits_used":15.6}

# Step 2: Poll until completed
curl "https://your-domain/api/v1/job/abc123def456" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Response (completed): {"status":"completed","audio_url":"/audio/srt2voice_xxx.mp3","progress_pct":100}

# Step 3: Download final MP3
curl -O "https://your-domain/audio/srt2voice_xxx.mp3" \
  -H "Authorization: Bearer YOUR_API_KEY"

# ────── Audio Separate: tách vocals + instrumental ──────
# Step 1: Submit audio/video → get job_id
curl -X POST "https://your-domain/api/v1/audio-separate" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "mode=all"

# Response: {"job_id":"abc123...","status":"queued","mode":"all","credits_used":13500.0}

# Step 2: Poll until completed
curl "https://your-domain/api/v1/job/abc123def456" \
  -H "Authorization: Bearer YOUR_API_KEY"

# Response: {"status":"completed","vocals_url":"/audio/sep_xxx_vocals.mp3","instrumental_url":"/audio/sep_xxx_instrumental.mp3"}

# Step 3: Download both stems
curl -O "https://your-domain/audio/sep_xxx_vocals.mp3" -H "Authorization: Bearer YOUR_API_KEY"
curl -O "https://your-domain/audio/sep_xxx_instrumental.mp3" -H "Authorization: Bearer YOUR_API_KEY"

# ────── Audio Separate: chỉ tách vocals (mode=vocals) ──────
curl -X POST "https://your-domain/api/v1/audio-separate" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "[email protected]" \
  -F "mode=vocals"

Ví dụ (Python)

import requests

API_KEY = "YOUR_API_KEY"
BASE    = "https://your-domain"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# ── TTS: Design ──
r = requests.post(f"{BASE}/api/v1/tts/design", headers=HEADERS, data={
    "text": "Xin chào, đây là giọng nói AI",
    "language": "vietnamese", "gender": "female",
    "age": "young adult", "pitch": "moderate pitch",
})
with open("voice.wav", "wb") as f: f.write(r.content)

# ── TTS: Clone ──
r = requests.post(f"{BASE}/api/v1/tts/clone", headers=HEADERS,
    data={"text": "Nội dung cần đọc", "language": "vietnamese"},
    files={"ref_audio": open("sample.wav", "rb")},
)
with open("cloned.wav", "wb") as f: f.write(r.content)

# ── TTS: Multi-Voice Dialogue ──
script = """#MC
Xin chào các bạn, hôm nay chúng ta sẽ nói về AI.
#Guest
Cảm ơn MC, tôi rất vui được ở đây."""
import json
r = requests.post(f"{BASE}/api/v1/tts/dialogue", headers=HEADERS, data={
    "text": script,
    "char_voice_map": json.dumps({"MC": 1, "Guest": 2}),
    "language": "vietnamese",
})
with open("dialogue.wav", "wb") as f: f.write(r.content)

# ── STT: Audio → JSON ──
r = requests.post(f"{BASE}/api/v1/stt", headers=HEADERS,
    files={"audio_file": open("recording.wav", "rb")},
    data={"language": "vietnamese"},
)
result = r.json()
print(result["text"])            # "Nội dung được nhận diện..."
print(result["duration_secs"])   # 45.2
print(result["credits_used"])    # 1.51
print(result["media_type"])      # "audio"

# ── STT: Video → SRT download ──
r = requests.post(f"{BASE}/api/v1/stt", headers=HEADERS,
    files={"audio_file": open("video.mp4", "rb")},
    data={"language": "vietnamese", "output_format": "srt"},
)
with open("subtitles.srt", "wb") as f: f.write(r.content)
print("Credits used:", r.headers.get("X-Credits-Used"))
print("Duration:", r.headers.get("X-Duration-Secs"), "s")
print("Media type:", r.headers.get("X-Media-Type"))  # "video"

# ── SRT → Voice: timing-synced TTS (async workflow) ──
import time

# Step 1: Submit SRT + voice
r = requests.post(f"{BASE}/api/v1/srt-to-voice", headers=HEADERS,
    files={"srt_file": open("subtitles.srt", "rb")},
    data={"voice_id": 1, "language": "vietnamese"},
)
job = r.json()
job_id = job["job_id"]
print(f"Job created: {job_id}, {job['cue_count']} cues, {job['credits_used']} credits")

# Step 2: Poll until completed
while True:
    r = requests.get(f"{BASE}/api/v1/job/{job_id}", headers=HEADERS)
    j = r.json()
    print(f"  Status: {j['status']}, progress: {j.get('progress_pct', 0)}%")
    if j["status"] in ("completed", "failed", "cancelled"):
        break
    time.sleep(3)

# Step 3: Download MP3
if j["status"] == "completed":
    r = requests.get(f"{BASE}{j['audio_url']}", headers=HEADERS)
    with open("output.mp3", "wb") as f: f.write(r.content)
    print(f"Saved output.mp3 ({len(r.content)} bytes)")

# ── Audio Separate: tách vocals + instrumental ──
r = requests.post(f"{BASE}/api/v1/audio-separate", headers=HEADERS,
    files={"audio_file": open("song.mp3", "rb")},
    data={"mode": "all"},
)
job = r.json()
print(f"Separate job: {job['job_id']}, {job['credits_used']} credits, {job['duration_secs']}s")

# Poll until completed
while True:
    r = requests.get(f"{BASE}/api/v1/job/{job['job_id']}", headers=HEADERS)
    j = r.json()
    print(f"  Status: {j['status']}")
    if j["status"] in ("completed", "failed", "cancelled"):
        break
    time.sleep(5)

# Download both stems
if j["status"] == "completed":
    if j.get("vocals_url"):
        r = requests.get(f"{BASE}{j['vocals_url']}", headers=HEADERS)
        with open("vocals.mp3", "wb") as f: f.write(r.content)
        print("Saved vocals.mp3")
    if j.get("instrumental_url"):
        r = requests.get(f"{BASE}{j['instrumental_url']}", headers=HEADERS)
        with open("instrumental.mp3", "wb") as f: f.write(r.content)
        print("Saved instrumental.mp3")

🚀 Sẵn sàng tích hợp?

Đăng ký miễn phí để nhận API key và bắt đầu gọi API ngay.

Tạo tài khoản miễn phí

Đã có tài khoản? Đăng nhập