📖 API Documentation
REST API dành cho developer — tích hợp TTS Tiếng Việt và STT audio/video vào ứng dụng của bạn.
- Đăng ký tài khoản miễn phí → nhận credits khởi đầu
- Vào API Keys → tạo key mới
- Gửi request với header
Authorization: Bearer YOUR_API_KEY - Đọc docs phía dưới để biết endpoints + parameters
🔐 Authentication
Mọi API request cần gửi API key qua HTTP header:
Authorization: Bearer sk-ov-YOUR_API_KEY
- Đăng ký tài khoản tại /register
- Vào /api-keys → click "Tạo Key mới"
- 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ạn | Giá trị | Mô tả |
|---|---|---|
| Requests/phút (per user) | 10 | Số request tối đa 1 phút/user |
| Concurrent jobs (API, per user) | 2 | Số job xử lý đồng thời/user |
| Concurrent jobs (server total) | 5 | Tổng concurrent jobs toàn server |
Khi vượt giới hạn → HTTP 429 Too Many Requests. Client nên:
- Wait & retry: chờ 5-10s rồi thử lại
- Exponential backoff: retry với delay 2s, 4s, 8s, 16s... nếu vẫn 429
- Dùng async_mode=true cho TTS/STT job dài — tránh blocking + tối ưu throughput
- Liên hệ admin để tăng quota nếu cầ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
| Method | Endpoint | Mô tả |
|---|---|---|
| GET | /api/v1/health | Kiểm tra trạng thái server |
| GET | /api/v1/options | Lấy danh sách tùy chọn voice |
| POST | /api/v1/tts/design | Tạo voice từ mô tả |
| POST | /api/v1/tts/clone | Clone voice từ audio mẫu |
| POST | /api/v1/tts/auto | Tự động tạo voice |
| GET | /api/v1/voices | Lấy danh sách giọng đã lưu |
| POST | /api/v1/tts/saved | Tạo voice từ giọng đã lưu (voice_id) |
| POST | /api/v1/tts/dialogue | Hội thoại đa giọng (Multi-Voice Dialogue) |
| POST | /api/v1/stt | Chuyể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-voice | SRT → Voice (timing-synced TTS) |
| POST | /api/v1/audio-separate | Tá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}/cancel | Hủy job đang queued/picked + refund credits |
1. Text-to-Speech (TTS)
POST /api/v1/tts/design — Tạo voice từ mô tả
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
text | string | ✅ | Nội dung cần đọc |
language | string | ❌ | Ngôn ngữ: vietnamese, english, chinese, japanese, korean, french... |
gender | string | ❌ | male / female |
age | string | ❌ | child, young adult, middle-aged, elderly |
pitch | string | ❌ | low pitch, moderate pitch, high pitch |
style | string | ❌ | normal, cheerful, sad, angry, whisper... |
instruct | string | ❌ | Mô tả trực tiếp (thay thế gender/age/pitch/style) |
speed | float | ❌ | Tốc độ đọc (default: 1.0) |
num_step | int | ❌ | Số bước diffusion (default: 32, cao hơn = chất lượng hơn) |
guidance_scale | float | ❌ | Guidance scale (default: 2.0) |
denoise | bool | ❌ | Khử nhiễu (default: true) |
async_mode | bool | ❌ | Chế độ 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
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
text | string | ✅ | Nội dung cần đọc |
ref_audio | file | ✅ | File audio mẫu để clone giọng (wav, mp3, flac...) |
language | string | ❌ | Ngôn ngữ: vietnamese, english, chinese... |
speed | float | ❌ | Tốc độ đọc (default: 1.0) |
num_step | int | ❌ | Số bước diffusion (default: 32) |
denoise | bool | ❌ | Khử nhiễu (default: true) |
async_mode | bool | ❌ | Chế độ 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
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
text | string | ✅ | Nội dung cần đọc |
language | string | ❌ | Ngôn ngữ (default: auto) |
speed | float | ❌ | Tốc độ đọc (default: 1.0) |
num_step | int | ❌ | Số bước diffusion (default: 32) |
denoise | bool | ❌ | Khử nhiễu (default: true) |
async_mode | bool | ❌ | Chế độ 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
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
text | string | ✅ | Nội dung cần đọc |
voice_id | int | ✅ | ID giọng đã lưu (lấy từ GET /api/v1/voices) |
language | string | ❌ | Ngôn ngữ (default: auto) |
speed | float | ❌ | Tốc độ đọc (default: 1.0) |
num_step | int | ❌ | Số bước diffusion (default: 32) |
denoise | bool | ❌ | Khử nhiễu (default: true) |
async_mode | bool | ❌ | Chế độ 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).
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
text | string | ✅ | Kị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_map | string (JSON) | ✅ | JSON mapping nhân vật → voice_id. VD: {"MC": 1, "Guest": 2} |
language | string | ❌ | Ngôn ngữ (default: auto) |
speed | float | ❌ | Tốc độ đọc (default: 1.0) |
num_step | int | ❌ | Số bước diffusion (default: 32) |
denoise | bool | ❌ | Khử nhiễu (default: true) |
async_mode | bool | ❌ | Chế độ 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.
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
audio_file | file | ✅ | File 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. |
language | string | ❌ | Ngôn ngữ audio (default: auto detect). Ví dụ: vietnamese, english, japanese, korean... |
output_format | string | ❌ | json (default) — JSON full data · srt — tải file .srt · vtt — tải file .vtt · txt — tải file .txt |
async_mode | bool | ❌ | Chế độ 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. |
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"
}
• 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
• 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
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)
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
audio_file | file | ✅ | File audio (wav, mp3, flac, m4a, ogg) hoặc video (mp4, mov, mkv, webm, avi, flv...). Auto-detect. |
language | string | ❌ | Ngôn ngữ (default: auto). Ví dụ: vietnamese, english, chinese, japanese... |
output_format | string | ❌ | json (default) — full data trong job poll · srt/vtt/txt |
beam_size | int | ❌ | Beam search size (1=greedy fastest, 5=balance default, 10=quality). Override Admin default |
vad_filter | bool | ❌ | Bậ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 |
temperature | float | ❌ | Sampling temp (0.0=deterministic, 0.4=variety). Default: lấy từ Admin (mặc định 0.0) |
initial_prompt | string | ❌ | Prompt 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_timestamps | bool | ❌ | Word-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"
}
• 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
- HTTP timeout dài: set
30 phútthay vì default (~100s) — đủ cho file audio/video dài upload + transcribe. - Polling interval: 3 giây ổn định cho hầu hết case. Có thể dùng exponential backoff (2s → 4s → 8s) nếu muốn tiết kiệm request.
- Cancel khi tool exit: trap signal đóng tool → POST
/api/v1/job/{id}/cancelđể refund credits, tránh job orphan trên server (server tự cleanup sau 5 phút nhưng tốn credits). - Retry khi network error: poll endpoint thì retry vô hạn (job có thể chạy 5-30 phút), nhưng submit endpoint thì retry tối đa 3 lần với backoff.
- Cache job_id local: nếu tool restart giữa chừng, có thể resume polling thay vì gửi lại file (tiết kiệm credits).
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.
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
srt_file | file | ✅ | File SRT (encoding UTF-8 khuyến nghị). Format chuẩn WebVTT/SRT với timestamps HH:MM:SS,mmm |
voice_id | int | ✅ | ID giọng đã lưu (từ GET /api/v1/voices) |
language | string | ❌ | Ngô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
}
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.
| Param | Type | Bắt buộc | Mô tả |
|---|---|---|---|
audio_file | file | ✅ | File audio (mp3, wav, flac, m4a...) hoặc video (mp4, mov, mkv...). Tự động extract audio nếu là video. |
mode | string | ❌ | all (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"
}
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 Code | Mô tả |
|---|---|
200 | Thành công |
400 | Lỗi request (thiếu param, file quá lớn, audio quá dài, text quá dài...) |
401 | API key không hợp lệ hoặc thiếu header Authorization |
402 | Không đủ credits |
429 | Quá nhiều request đồng thời (vượt giới hạn concurrent) |
500 | Lỗ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