Chuyển tới nội dung chính

Cắm thẳng vào app tương thích OpenAI

Rất nhiều phần mềm đã nói được POST /v1/audio/speech và cho phép bạn trỏ nó tới một base URL riêng. VieNeu có sẵn endpoint đó, nên những app này dùng được giọng tiếng Việt mà không cần plugin, không cần adapter.

Trang này là bảng khai báo: với mỗi client, điền giá trị nào vào ô nào.

Phần VieNeu trong mọi mục dưới đây là chính xác. Phần client được viết theo kiểu "giá trị này thuộc về loại ô nào", vì nhãn của các ô cài đặt thay đổi theo phiên bản — hãy đối chiếu tên trường với đúng bản bạn đang chạy.

Ba giá trị cần có​

Client nào cũng cần đúng ba thứ giống nhau.

Giá trịĐiền gì
Base URLhttps://api.vieneu.io/api/v1 (xem cái bẫy bên dưới)
API keykey VieNeu của bạn — bắt đầu bằng vn_sk_ (thật) hoặc vn_test_ (test)
Modeltts-1, tts-1-hd, gpt-4o-mini-tts, vieneu hoặc vieneu-v4 → v4, engine duy nhất kể từ khi v3 ngừng ngày 2026-09-24. Mọi tên khác đều được nhận rồi bỏ qua — trừ một tên vieneu-… không trỏ tới engine đang chạy, cái đó là 400. vieneu-v3 giờ là một trong số đó.

Ngoại lệ duy nhất ở dòng cuối lại chính là chỗ người dùng VieNeu dễ vấp nhất. vieneu-v5 hay vieneu-turbo không rơi về engine mặc định theo kiểu whatever-tts; nó trả về 400 invalid_request_error kèm param: "model", liệt kê những tên engine thực sự tồn tại. Tiền tố đó được đọc như một lựa chọn engine tường minh, mà âm thầm đọc nó bằng engine khác thì bạn bị tính phí theo mức bạn chưa từng chọn. Nếu bạn gửi cả engine lẫn model, engine thắng.

vieneu-v3 mới là trường hợp bạn dễ gặp thật nhất. Nó là lựa chọn hợp lệ cho tới khi v3 rút khỏi Cloud API ngày 2026-09-24, và giờ trả về 400 kèm Model 'vieneu-v3' is retired. Engine "v3" was retired on 2026-09-24. Use engine "v4" and a voice from GET /v1/voices?engine=v4 — the two catalogues share no ids. Hãy đổi model sang vieneu-v4 (hoặc tts-1) và kiểm lại giọng trong cùng một lượt — một slug vieneu-… lưu từ danh mục v3 cũ sẽ 400 ở param: "voice" ngay sau đó.

Trường thứ tư, voice, không bắt buộc nhưng thường thì bạn vẫn muốn có: bỏ trống thì server dùng giọng đang bật đầu tiên trên engine được chọn. Thứ bạn không làm được là dùng lại tên của OpenAI — alloy / nova v.v. không được ánh xạ và trả về 400. Lấy id thật từ GET /api/v1/audio/voices (bên dưới).

Cái bẫy base URL​

Path là /api/v1/audio/speech. Cái /api/v1 trông như bị lặp đó là thật — server đặt một prefix api toàn cục và gắn API công khai ở v1. Nên giá trị bạn gõ vào phụ thuộc vào phần client tự nối thêm:

Nếu ô đó có nghĩa là…Điền
"base URL của OpenAI — tôi tự nối /audio/speech"https://api.vieneu.io/api/v1
"host — tôi tự nối /v1/audio/speech"https://api.vieneu.io/api
"URL endpoint đầy đủ"https://api.vieneu.io/api/v1/audio/speech

Phần lớn client hiểu theo dòng đầu. Chọn sai thì luôn là 404, và luôn là JSON — nhưng theo cấu trúc lỗi nền tảng của VieNeu, chứ không phải cái phong bì OpenAI mà endpoint này vẫn dùng ở mọi chỗ khác:

{ "statusCode": 404, "message": "Cannot POST /api/v1/v1/audio/speech", "error": "Not Found" }

Đọc được hai điều từ đó:

  • Thông báo Cannot POST … và việc vắng mặt lớp bọc {"error":{"message","type","param","code"}} mà mọi lỗi thật của /v1/audio/speech đều mang, có nghĩa là hình dạng URL sai chứ không phải key sai. Đừng đi lục API key vì lỗi này.
  • Path nằm trong thông báo chính là URL client của bạn thực sự dựng ra. So nó với /api/v1/audio/speech, chỗ lệch sẽ cho biết bạn cần dòng nào ở bảng trên — ví dụ ở đây bị lặp /v1, nên client đó cần https://api.vieneu.io/api.

Không có /v1/models​

VieNeu chỉ phục vụ TTS. Không có route /v1/models, cũng không có /v1/chat/completions. Hai hệ quả:

  • Nút "Test connection" / "Verify" nào dò /models sẽ báo thất bại, dù việc tổng hợp giọng vẫn chạy. Cứ kệ nó và gửi một request thật.
  • Ô chọn model lấy dữ liệu từ /models sẽ trống rỗng. Hãy gõ tay tên model.

Trong Open WebUI, SillyTavern và LobeChat, base URL này chỉ thuộc về phần cài đặt provider audio/TTS — đừng bao giờ đặt vào ô endpoint OpenAI/LLM chung, đặt vào đó là hỏng model chat.

Chứng minh nó chạy trước đã​

Trước khi đụng vào bất kỳ client nào, hãy xác nhận base URL và key bằng curl. Gửi $VIENEU_API_KEY — key vn_sk_… hoặc vn_test_… của chính bạn — và không gửi voice, để ngoài hai giá trị đó ra không còn gì có thể hỏng:

curl https://api.vieneu.io/api/v1/audio/speech \
-H "Authorization: Bearer $VIENEU_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "tts-1", "input": "Xin chào, đây là VieNeu." }' \
--output speech.mp3

Bỏ voice đi thì server tự chọn giọng đang bật đầu tiên trên engine được chọn, và đó là thứ giữ cho bước này trung thực: một voice id bạn chưa kiểm chứng sẽ 400 ở param: "voice" và bạn hết đường phân biệt giọng sai với key sai hay base URL sai. Chọn một giọng thật ở bước sau, khi bước này đã qua.

Nếu lệnh đó cho ra audio nghe được thì mọi thứ sau đây chỉ là chuyện cấu hình client.

Lấy voice id​

# Which engine will my requests land on? No API key needed.
curl https://api.vieneu.io/api/v1/engines

# Voice ids for that engine. API key IS required here.
curl "https://api.vieneu.io/api/v1/audio/voices?engine=v4" \
-H "Authorization: Bearer $VIENEU_API_KEY"

GET /api/v1/engines trả về mỗi engine đang bật một mục, kèm key, isDefault, billingMultiplier và features. Hãy dùng cái có isDefault: true — từ khi v3 ngừng ngày 2026-09-24 thì đó là mục duy nhất, v4.

Voice id lưu trước 2026-09-24 có thể đã chết

audio/voices giờ chỉ liệt kê v4, có lọc hay không cũng vậy, và ?engine=v3 là 400. Nhưng id của danh mục V3 đã ngừng là slug vieneu-…, id của V4 là tên hiển thị (Ngọc Lan), và hai bên gần như không chung không gian id nào — nên một giọng mà client lưu từ danh sách chưa lọc trước ngày ngừng sẽ 400 ở param: "voice" bây giờ. Hãy nạp lại ô chọn giọng từ lời gọi ở trên, và cứ truyền ?engine=v4: không tốn gì mà request lại tường minh.

Việc khớp giọng không phân biệt hoa thường, nhưng có phân biệt dấu, và id của V4 có dấu cách. Client nào slugify hoặc bỏ dấu trước khi gửi sẽ 400 ở mọi request.

Giờ chạy lại phép thử nhanh với một id lấy từ danh sách đó, chép đúng y như lúc nhận về:

curl https://api.vieneu.io/api/v1/audio/speech \
-H "Authorization: Bearer $VIENEU_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "tts-1", "input": "Xin chào, đây là VieNeu.", "voice": "PASTE_AN_ID_HERE" }' \
--output speech.mp3

Nếu lệnh curl đầu chạy được mà lệnh này 400 ở param: "voice" thì id là thứ duy nhất đã thay đổi — hãy kiểm bộ lọc engine và dấu tiếng Việt trước đã.

Giọng nhân bản không dùng được ở đây

Id clone_… bị /v1/audio/speech từ chối, kèm thông báo nêu tên hai route nhận chúng: POST /v1/tts và POST /v1/tts/stream. Không client tương thích OpenAI nào chạm tới được giọng nhân bản.

Open WebUI​

Phần cài đặt Audio/TTS, engine OpenAI:

TrườngGiá trị
TTS engine / providertuỳ chọn tương thích OpenAI
API base URLhttps://api.vieneu.io/api/v1
API keyvn_sk_…
Modeltts-1
Voicemột id thật từ audio/voices, ví dụ Ngọc Lan

Ghi chú:

  • Đặt cái này vào phần cài đặt audio, không phải phần model/connection.
  • Ô voice phải nhận được chữ nhập tự do. Nếu bản bạn chạy chỉ đưa ra sáu cái tên của OpenAI thì cả sáu đều 400 — hãy kiểm trên bản của bạn.
  • Response format: cứ để mặc định. Open WebUI phát mp3, cũng đúng là mặc định của VieNeu.

SillyTavern​

Extension TTS, provider tương thích OpenAI:

TrườngGiá trị
Providertuỳ chọn OpenAI TTS
API / base URLhttps://api.vieneu.io/api/v1
API keyvn_sk_…
Modeltts-1
Voice (theo từng nhân vật)một id thật từ audio/voices

Ghi chú:

  • SillyTavern gán giọng cho từng nhân vật. Mọi nhân vật đều phải mang id VieNeu — một nhân vật còn để alloy sẽ hỏng trong khi số còn lại chạy, nhìn vào cứ tưởng tích hợp lúc được lúc không.
  • Nếu extension chỉ cho một ô chọn giọng cố định thay vì ô nhập chữ thì nó không gọi được giọng VieNeu. Hãy kiểm trên bản của bạn.
  • Nếu SillyTavern của bạn gọi TTS từ trình duyệt chứ không từ server của chính nó, xem Client chạy phía trình duyệt.

LobeChat​

Phần cài đặt TTS / audio, provider OpenAI:

TrườngGiá trị
OpenAI TTS base URL / proxy URLhttps://api.vieneu.io/api/v1
API keyvn_sk_…
Modeltts-1
Voicemột id thật từ audio/voices

Ghi chú:

  • LobeChat giữ hai phần cài đặt riêng cho provider chat và provider TTS. URL này chỉ đặt vào phần TTS.
  • LobeChat thường được triển khai theo kiểu trình duyệt gọi thẳng tới provider TTS — hãy xem Client chạy phía trình duyệt trước khi gỡ bất cứ thứ gì khác.

LiteLLM​

Thêm VieNeu như một model trong config.yaml:

model_list:
- model_name: vieneu-tts
litellm_params:
model: openai/tts-1
api_base: https://api.vieneu.io/api/v1
api_key: os.environ/VIENEU_API_KEY

Rồi khi proxy đang chạy, gọi nó y hệt như gọi OpenAI:

curl http://localhost:4000/v1/audio/speech \
-H "Authorization: Bearer $LITELLM_MASTER_KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "vieneu-tts", "input": "Xin chào", "voice": "Ngọc Lan" }' \
--output speech.mp3

Ghi chú:

  • LITELLM_MASTER_KEY không phải key VieNeu của bạn. Đó là credential proxy của riêng LiteLLM, là bất cứ thứ gì bạn đặt lúc khởi động proxy — cổng (:4000 ở trên) cũng là của LiteLLM. Key vn_sk_… của bạn chỉ xuất hiện trong config.yaml, lấy qua os.environ/VIENEU_API_KEY; chính proxy mới là bên gắn nó vào lời gọi lên upstream.
  • Tiền tố openai/ trong model bảo LiteLLM chuyển tiếp request theo hình dạng của OpenAI, đúng thứ VieNeu trả lời được. Cái tên đứng sau nó (tts-1) mới là thứ đi tới VieNeu.
  • Các giá trị VieNeu ở trên là chính xác; những key LiteLLM bao quanh chúng là hình dạng model_list chuẩn của nó — hãy đối chiếu với phiên bản LiteLLM bạn dùng.
  • Đừng bật bất kỳ tính năng làm giàu request nào có thêm field vào body. VieNeu từ chối field lạ bằng 400 chứ không bỏ qua chúng — xem 400.

LiveKit Agents​

Plugin OpenAI nhận một base URL và một key:

from livekit.plugins import openai

tts = openai.TTS(
model="vieneu-v4",
voice="Ngọc Lan",
base_url="https://api.vieneu.io/api/v1",
api_key="vn_sk_...",
)

Ghi chú:

  • Hãy ghim vieneu-v4, hoặc bỏ trống model. Cả hai đều rơi vào v4, engine duy nhất kể từ khi v3 ngừng ngày 2026-09-24. vieneu-v3 — thứ mà endpoint này từng nhận kèm streaming, trả 200 rồi để v3 nhả hết chunk ra một lượt ở cuối mà không có lỗi nào báo cho bạn biết — giờ là 400 kèm param: "model" nói rằng engine đã ngừng.
  • GET /v1/engines trả về hệ số tính phí đang chạy; xem Engine.
  • Muốn streaming, VieNeu cần cả hai: response_format: "pcm" và stream_format. response_format mặc định là mp3, nên chỉ đặt mỗi stream_format là 400. Plugin có gửi cái nào trong hai cái đó không, và có cho bạn thêm vào không, chính là thứ cần kiểm trên bản bạn chạy. Thiếu chúng thì lời gọi vẫn chạy — chỉ là nó trả về một file mp3 hoàn chỉnh thay vì một luồng.
  • pcm không có header và mặc định 24000 Hz trên route này (tần số gốc của engine là 48000). Hãy đọc tần số thật từ header phản hồi X-Sample-Rate rồi cấu hình pipeline cho khớp, không thì audio phát sai cao độ.

Pipecat​

import os
from pipecat.services.openai.tts import OpenAITTSService

tts = OpenAITTSService(
api_key=os.environ["VIENEU_API_KEY"],
base_url="https://api.vieneu.io/api/v1",
model="vieneu-v4",
voice="Ngọc Lan",
)

Ghi chú:

  • Đường dẫn import cho service OpenAI TTS của Pipecat đã đổi chỗ qua các bản phát hành — hãy kiểm bản của bạn. Thứ quan trọng là các tham số constructor và những giá trị ở trên.
  • Ba quy tắc streaming giống hệt LiveKit vẫn áp dụng: ghim vieneu-v4, gửi response_format: "pcm" và stream_format, và lấy tần số từ X-Sample-Rate thay vì mặc định coi là 48 kHz.
  • Nếu phiên bản của bạn hard-code một response_format mà VieNeu không nhận (aac, flac) thì request 400 kèm tên field đó. Các giá trị được nhận là wav, mp3, opus, pcm và ulaw.

Client chạy phía trình duyệt​

Trên production, chính sách CORS của VieNeu chỉ cho phép các origin của chính VieNeu. Client nào gọi /v1/audio/speech từ trang web chứ không từ server của chính nó sẽ chết ngay ở bước preflight, không có body phản hồi nào giải thích.

Một bản triển khai LobeChat hay SillyTavern cụ thể có gọi TTS ở phía server hay không là chuyện tuỳ từng bản — hãy kiểm trên bản của bạn. Nếu nó chạy phía trình duyệt, hãy dựng một proxy của riêng bạn đứng trước (LiteLLM hợp cho việc này) rồi trỏ client vào đó.

JavaScript trong trình duyệt đọc được X-Request-Id, X-Sample-Rate, X-Output-Format, các header X-RateLimit-* và Retry-After; mọi thứ còn lại bị trình duyệt che. (X-Stream-Format cũng được mở qua CORS, nhưng đừng viết code đọc nó ở đây — chỉ route gốc POST /v1/tts/stream mới gửi nó. Trên route này phần đóng khung đã được bóc sẵn cho bạn rồi, nên header đó luôn vắng mặt.)

Gỡ rối theo triệu chứng​

Không có audio​

Đi lần lượt xuống danh sách — mỗi mục một nguyên nhân khác nhau.

  • Tệp lưu về chứa JSON. Trên đường stream thô, một lượt sinh không ra được gì sẽ trả 502 kèm body lỗi ở đúng chỗ lẽ ra là audio. Client nào ghi thẳng body phản hồi vào tệp .pcm sẽ có JSON nằm trong đó. Hãy xem những byte đầu tiên của tệp.
  • Tệp bị tải về thay vì phát. Phản hồi đồng bộ mang Content-Disposition: attachment. Client nào fetch phần body thì không bị ảnh hưởng; client nào điều hướng thẳng tới URL sẽ nhận một lượt tải về.
  • Audio phát sai cao độ hoặc sai tốc độ. pcm và ulaw không có header — chuỗi byte không mang theo sample rate. Ở đây pcm là 24000 Hz trừ khi bạn yêu cầu khác; ulaw luôn là 8000. Hãy đọc X-Sample-Rate thay vì đoán.
  • Trình phát từ chối một tệp .mp3. Nếu bạn bỏ trống response_format mà worker đang phục vụ bạn không mã hoá được mp3, VieNeu lùi về byte WAV thay vì báo lỗi. Hãy đọc X-Output-Format để biết bạn thực sự nhận được gì. (Nếu bạn đã yêu cầu mp3 tường minh thì thay vào đó bạn sẽ nhận 503 kèm tên định dạng — một lựa chọn tường minh không bao giờ bị âm thầm thay thế.)

400 invalid_request_error​

Với hầu hết các trường hợp này, field param trong body lỗi nêu đích danh thủ phạm — trừ đúng một ngoại lệ, và đó là nguyên nhân đầu tiên trong danh sách dưới đây. Các nguyên nhân thường gặp:

  • Một field lạ trong body. VieNeu từ chối những field nó không khai báo chứ không bỏ qua chúng. Bộ field được nhận đúng bằng: model, input, voice, response_format, sample_rate, speed, instructions, stream_format, emotion, aiRefine, engine. Lưu ý là không có boolean stream — client nào gửi stream: true (như với chat completions) sẽ nhận 400. user, language hay bất kỳ phần mở rộng riêng nào của client cũng vậy. Đây là lý do phổ biến nhất khiến một client chạy tốt với OpenAI lại hỏng với VieNeu: hãy soi đúng cái body mà nó thực sự gửi đi.

    Với trường hợp này, hãy đọc message chứ không phải param. Lỗi bị chặn ở bộ validator của request chứ không ở handler, nên param trả về đúng chuỗi "property" chứ không bao giờ là tên field vi phạm. Tên nằm trong message: property stream should not exist. Mỗi request chỉ báo field vi phạm đầu tiên, nên nếu client của bạn thêm mấy field một lúc thì cứ sửa rồi thử lại cho tới khi qua.

  • Một tên model vieneu-… không nhận ra. param: "model". Các tên model lạ khác thì bị bỏ qua; riêng tiền tố này thì không.

  • Một tên giọng của OpenAI. alloy, echo, fable, onyx, nova, shimmer không được ánh xạ. param: "voice".

  • Một voice id nhân bản. clone_… chỉ chạy trên POST /v1/tts và POST /v1/tts/stream.

  • stream_format đi với một định dạng không stream được. Chỉ pcm và ulaw stream được, mà response_format lại mặc định là mp3 — nên chỉ đặt mỗi stream_format thì luôn luôn 400.

  • aac hoặc flac. Định dạng có thật của OpenAI nhưng VieNeu không mã hoá được; thông báo nói thẳng ra điều đó.

  • Một sample_rate mâu thuẫn với định dạng. opus luôn là 48000 và ulaw luôn là 8000; một tần số xung đột sẽ bị từ chối chứ không bị ghi đè. Các tần số hợp lệ là 8000, 16000, 22050, 24000, 44100, 48000.

  • speed nằm ngoài 0.25–4.0. Nằm trong dải đó thì nó bị kẹp về 0.5–2.0 và không bao giờ báo lỗi; nằm ngoài thì bộ kiểm tra từ chối.

  • Key test vượt quá 100 từ. Key vn_test_ chặn mỗi request ở 100 từ tách bằng khoảng trắng. Thông báo nêu đúng số từ thực tế của bạn.

401 authentication_error​

  • Invalid API key format. — key phải bắt đầu đúng bằng vn_sk_ hoặc vn_test_. Chỗ này được kiểm trước mọi thao tác tra cứu, nên những key giữ chỗ mà vài client kèm sẵn hoặc bắt phải điền (sk-..., none, ollama) đều chết ở đây. Nếu client không chịu lưu khi ô key để trống thì nó cần một key VieNeu thật.
  • API key required. dù bạn đã điền — một bearer token có chứa dấu chấm sẽ bị coi là JWT và bị bỏ qua với tư cách API key. Key VieNeu thật là hex và không bao giờ có dấu chấm, nên lỗi này nghĩa là có thứ gì đó đã bọc hoặc thay mất key của bạn.
  • Invalid or revoked API key. — một key đã thu hồi thì không phân biệt được với một key lạ.

Key đặt ở Authorization: Bearer <key> hoặc X-API-Key: <key>; cả hai đều được. Nếu client của bạn gửi cả hai với giá trị khác nhau thì X-API-Key âm thầm thắng.

403 — thường là "hết token"​

Ở đây hết token là 403, không phải 402. Không chỗ nào trong API công khai phát ra 402, nên một client chỉ canh mã đó sẽ chẳng bao giờ biết mình đã hết tiền. Hãy canh 403. Có ba thông báo, đều mang type insufficient_quota:

  • Insufficient tokens. You have <n> tokens remaining but this request costs <m> tokens. — đây là lúc một grant hết theo cách bình thường, và là lỗi đầu tiên bạn gặp khi hạn mức dùng thử cạn.
  • Your API token package has expired. Please renew your Developer plan. — chuyện thời hạn, không phải chuyện tiêu thụ. Mua thêm token không chữa được; gia hạn mới chữa được.
  • API token grant is not active. Check your Developer plan status.

Hai lỗi 403 khác thì không liên quan tới token, và field type là thứ phân biệt chúng:

  • Your plan does not include engine "v4". Upgrade your Developer plan to use it. — mang type invalid_request_error, param: "engine". Chỉ phát sinh khi bạn ghim engine tường minh mà gói không bao gồm nó; với v4 là engine duy nhất từ 2026-09-24 thì hiếm khi bạn gặp — bỏ model/engine đi thì engine mặc định chạy được.
  • This feature is not available yet. — mang type authentication_error, đến từ một cổng tính năng chứ không phải từ khâu tính phí.

Vậy nên đừng rẽ nhánh chỉ theo type để nhận ra "hết token", mà cũng đừng rẽ nhánh chỉ theo 403. Hai thứ đi cùng nhau thì không còn nhập nhằng.

Trần theo ngày hoặc theo tuần là 429, không phải 403 — xem bên dưới.

429 rate_limit_exceeded​

Đọc header để phân biệt nguồn gốc:

Header có mặtNguồnĐếm vào
Retry-After + X-RateLimit-*bộ throttle của VieNeu trên các route tổng hợp giọng — 300 request/phút theo mặc địnhAPI key của bạn
không có cái nào, body không phải JSONproxy ở biên — 3000 request/phútIP nguồn của bạn, dùng chung với mọi người đứng sau nó
JSON, message có chứa Resets at <ISO>trần ngày hoặc trần tuần của token grantgrant của bạn

Cả ba trường hợp đều phải giãn nhịp. Trường hợp giữa đáng để biết: nếu client của bạn đi ra qua một đường egress dùng chung hoặc có NAT, bạn có thể chạm phải một giới hạn mà chỉnh bao nhiêu ở phía mình cũng không chữa được.

Đừng hard-code số 300. Đó là một cài đặt theo bản triển khai (PUBLIC_API_SYNTHESIS_RPM), không phải hằng số, và các trang khác nêu con số khác vì chúng được viết dựa trên những bản triển khai khác. Phần bền vững là cột đầu của dòng đó: hãy đọc hạn mức đang chạy của bạn từ X-RateLimit-Limit và X-RateLimit-Remaining trên bất kỳ phản hồi thành công nào.

Dòng thứ ba là dòng người ta hay nhầm thành dòng đầu. Trần ngày hoặc trần tuần của grant là một lỗi 429 mà message kết thúc bằng Resets at <ISO timestamp> — chậm lại cỡ nào cũng không gỡ được nó trước thời điểm đó. Còn hết sạch token thì là 403, không bao giờ là 402.

503 — lỗi ở đội máy, không phải ở request của bạn​

Không có gì trong request của bạn cần sửa; cứ thử lại sau chốc lát. Bốn nguyên nhân:

  • Không có worker nào cho engine bạn đã ghim. No V4 TTS worker is available right now. Please try again shortly. (đường streaming thì nói …available for streaming right now.) Chỉ phát sinh với engine không phải mặc định: một request đi theo engine mặc định sẽ lùi về worker đã cấu hình chứ không trả 503, nên bỏ model/engine là cách chữa cháy hợp lệ ở đây.
  • Không có giọng nào đang bật trên engine đó, khi bạn bỏ trống voice. No voice is currently available on engine "v4". Pass an explicit voiceId from GET /v1/voices. Lỗi này về dưới dạng 503 nhưng mang type invalid_request_error kèm param: "voice" — một vấn đề của danh mục giọng lại đeo cái nhãn của lỗi request. Nó phát sinh trước khâu tính phí, nên bạn chưa bị trừ gì.
  • Một định dạng bạn yêu cầu tường minh mà worker không mã hoá được. Nếu bạn bỏ trống response_format thì thay vào đó bạn đã nhận được byte WAV; một lựa chọn tường minh không bao giờ bị âm thầm thay thế. Xem Không có audio.
  • Một sample_rate worker không tạo ra được, trên đường streaming. Thông báo nêu cả thứ bạn yêu cầu lẫn thứ worker đưa ra được.

Mọi trường hợp trong số này mà đã đi tới khâu tính phí đều được hoàn tự động — bạn không bị tính tiền cho audio bạn không nhận được.

Luồng dừng giữa chừng câu​

  • Với SSE, hãy đợi sự kiện kết thúc. Không có dấu hiệu data: [DONE] nào cả. Luôn luôn có đúng một speech.audio.done (audio trọn vẹn, mang theo usage) hoặc speech.audio.error (thì không trọn vẹn) đi tới. Nếu chẳng cái nào tới thì luồng đã bị cắt cụt — hãy bỏ đoạn audio đi; request được hoàn tự động.
  • Trên đường stream thô thì không có tín hiệu như vậy. Một luồng bị cắt cụt không tài nào phân biệt được với một luồng vốn dĩ ngắn. Nếu bạn cần bằng chứng về sự trọn vẹn, hãy dùng stream_format: "sse" hoặc route gốc POST /v1/tts/stream.
  • Nó "treo", rồi đổ ra tất cả một lượt. Trước đây đó là vieneu-v3 đi kèm stream_format: endpoint này nhận, trả 200, rồi v3 nhả hết chunk ra một lượt ở cuối. Từ khi v3 ngừng ngày 2026-09-24, request đó là 400, nên nếu bạn vẫn thấy kiểu này thì việc đệm đang xảy ra ở một proxy hay client của chính bạn, không phải ở engine. Hãy ghim vieneu-v4 và kiểm xem có gì nằm giữa bạn và API.
  • Một lời gọi không streaming bị timeout với text dài. Trên endpoint này input không có trần độ dài — request chỉ đơn giản là chặn đó suốt trọn thời gian tổng hợp, rồi cái timeout HTTP của chính client bỏ cuộc trước. Trần thực sự là body request 2 MB và read timeout 600 giây ở proxy. Với text dài, hãy dùng đường bất đồng bộ POST /api/v1/tts + GET /api/v1/tts/{jobId} thay cho nó.

Mọi phản hồi đều mang X-Request-Id. Hãy dẫn nó ra khi gửi yêu cầu hỗ trợ.

Xem thêm​

  • Tổng quan tích hợp — chọn đường nào nếu công cụ của bạn không có trong trang này.
  • Endpoint TTS tương thích OpenAI — hợp đồng đầy đủ theo từng field cho /v1/audio/speech: mọi field được nhận, quy tắc về định dạng và sample rate, cùng danh sách lỗi trọn vẹn.
  • Streaming — so sánh hai endpoint streaming, và ngữ nghĩa của sự kiện kết thúc đã tóm ở trên.
  • Hạn mức và request id — các header, và vì sao hạn mức đếm theo từng key.
  • API reference — sinh từ chính đặc tả OpenAPI của server.