System Overview
Hệ thống AI Orchestrator cung cấp API để xử lý các tác vụ AI nặng (FaceSwap, Video Gen, Upscale, Editing) thông qua cơ chế Async Queue.
Hỗ trợ:
Faceswap (Single/Multi)
Faceswap Video
AHV Image/Video
GG Image
CX Image
Upscale & Beauty
Remove Obj
Scan Obj
Voice TTS
Voice STT
Music Gen
Recommended Workflow
- 1. Client gửi
POST /v1/jobskèmwebhook_url. - 2. Server trả về
job_idvà trạng tháiqueued. - 3. Client tiếp tục làm việc khác.
- 4. Khi hoàn thành, Server gọi
POST webhook_urltrả kết quả.
Authentication
X-API-Key: your_secret_key
1. Async Jobs API
Endpoint: POST /v1/jobs. Hỗ trợ retry, queue management và webhook notification.
Create FaceSwap Job (Image)
Mode 1: Single Face
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "faceswap",
"webhook_url": "https://your-site.com/webhook",
"payload": {
"source_url": "https://example.com/face.jpg",
"target_url": "https://example.com/body.jpg",
"upscale": 1,
"max_side": 1280
}
}'
Mode 2: Multi-Face
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "faceswap_multi",
"webhook_url": "https://your-site.com/webhook",
"payload": {
"source_urls": [
"https://ex.com/face1.jpg",
"https://ex.com/face2.jpg"
],
"target_url": "https://example.com/group.jpg",
"swap_faces_index": [0, 1],
"target_faces_index": [2, 0],
"sharpen": 0.5
}
}'
| Param | Type | Desc |
|---|---|---|
target_url | string | Required. Ảnh đích. |
source_url | string | Ảnh chứa mặt gốc (1 mặt). |
source_urls | array | Mảng ảnh chứa mặt (Nhiều mặt). |
swap_faces_index | array | Index mặt trong nguồn cần lấy. |
target_faces_index | array | Index mặt trong đích cần thay. |
max_side | int | Resize cạnh lớn nhất (Def: 1080). |
upscale | 0/1 | Bật Upscale sau khi swap (Def: 1). |
sharpen | float | Độ sắc nét (e.g. 0.12). |
max_faces | int | Giới hạn số mặt xử lý (Def: 0 - All). |
/v1/jobs
task: nsfw_check
Kiểm tra ảnh có chứa nội dung 18+/NSFW hay không. Trả về điểm NSFW score và nhãn safe/nsfw.
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "nsfw_check",
"webhook_url": "https://your-site.com/webhook",
"payload": {
"image_url": "https://example.com/photo.jpg",
"strict": "medium"
}
}'
| Param | Type | Desc |
|---|---|---|
image_url | string * | URL ảnh cần kiểm tra (bắt buộc). |
strict | string | Mức độ lọc: low (0.75), medium (0.55), high (0.35). Def: low. |
threshold | float | Ngưỡng tùy chỉnh 0.0-1.0. Nếu set sẽ ghi đè strict. |
Response result:
{
"nsfw_score": 0.0001,
"is_nsfw": false,
"threshold": 0.75,
"strict": "low",
"label": "safe",
"elapsed": 0.098
}
| Strict Level | Threshold | Mô tả |
|---|---|---|
low | 0.75 | Mặc định, chỉ block rõ ràng |
medium | 0.55 | Lọc vừa phải |
high | 0.35 | Lọc gắt, nhạy cảm cao |
/v1/nsfw-check
Upload file trực tiếp
Endpoint hỗ trợ upload file ảnh trực tiếp (multipart/form-data) hoặc gửi URL. Tự động upload → tạo job → trả job_id.
Upload file:
curl -X POST "{{API_BASE}}/v1/nsfw-check" \
-H "X-API-Key: {{API_KEY}}" \
-F "file=@/path/to/image.jpg" \
-F "strict=medium"
Gửi URL:
curl -X POST "{{API_BASE}}/v1/nsfw-check" \
-H "X-API-Key: {{API_KEY}}" \
-F "image_url=https://example.com/photo.jpg" \
-F "strict=low"
| Param | Type | Desc |
|---|---|---|
file | file | Upload ảnh trực tiếp (JPG/PNG/WEBP/GIF, max 10MB). Ưu tiên nếu có. |
image_url | string | URL ảnh (dùng nếu không upload file). |
strict | string | Mức độ lọc: low, medium, high. Def: low. |
threshold | float | Ngưỡng tùy chỉnh 0.0-1.0. |
webhook_url | string | URL nhận kết quả qua webhook. |
Response:
{
"ok": true,
"job_id": "abc123...",
"status": "queued",
"image_url": "https://...uploaded-file.jpg",
"predict_time": 5
}
💡 Sau đó dùng GET /v1/jobs/{job_id} để lấy kết quả, hoặc nhận qua webhook.
2. Webhook & Job Status
Webhook Payload: succeeded
{
"event": "job.finished",
"event_id": "f03675fc03334822be22b98ee9215c1d",
"ts": "2026-02-04T18:04:19.463754+00:00",
"job_id": "d1142818265748d9914053dafc20dd98",
"task": "upscale",
"status": "succeeded",
"progress": 100,
"ok": true,
"created_at": "2026-02-04T18:04:13.773524+00:00",
"created_at_ms": 1770228253773,
"queued_at": "2026-02-04T18:04:13.773524+00:00",
"queued_at_ms": 1770228253773,
"started_at": "2026-02-04T18:04:14.264808+00:00",
"started_at_ms": 1770228254264,
"finished_at": "2026-02-04T18:04:19.462901+00:00",
"finished_at_ms": 1770228259462,
"duration": 5.198093,
"predict_time": 3,
"eta_utc": "2026-02-04T18:04:16.773638+00:00",
"result": {
"ok": true,
"status": "succeeded",
"url": "http://15.235.200.66:2022/files/3c3da5ddac6a4c5081d46d829d168cb3.jpg",
"filename": "3c3da5ddac6a4c5081d46d829d168cb3.jpg",
"meta": {
"width": 507,
"height": 678,
"backend": "UPVN1-1"
}
},
"error": null,
"predictTime": 3
}
Job Lifecycle Status
Click vào badge để xem mẫu Webhook JSON tương ứng.
| queued | Đang chờ trong hàng đợi. |
| running | Backend đang xử lý. |
| succeeded | Hoàn thành, có result.url. |
| failed | Lỗi kỹ thuật hoặc timeout. |
| rejected | Từ chối (NSFW blocked). |
3. API Reference
Management Endpoints
GET /stats |
Lấy danh sách các jobs gần nhất. |
GET /v1/jobs/{id} |
Polling trạng thái Job (nếu không dùng Webhook). |
DELETE /tasks/{id} |
Xóa job khỏi hệ thống. |
GET /diag/backends |
Xem trạng thái tải (slots/concurrency) của các node GPU. |
Direct Blocking Endpoints
Gọi trực tiếp, giữ kết nối cho đến khi xong. Payload giống hệt payload của Async Job.
POST /faceswap | Xử lý FaceSwap Ảnh |
POST /faceswap/video | Xử lý FaceSwap Video |
POST /upscale | Upscale & Restore |
POST /ahv/image | Gen Ảnh (Text2Img, Img2Img) |
POST /ahv/video | Video Gen (MiniMax H3 — có tiếng) |
POST /gg/image | GG Image Gen (Imagen 4) |
POST /cx/image | CX Image Gen (GPT-5.4 Image) |
POST /remove-object | Xóa vật thể (Mask/Prompt) |
POST /scan-objects | Detect vật thể (JSON) |
POST /remove-background | Tách nền |
4. Voice AI — TTS & STT
Giọng nói tiếng Việt qua cùng một API job của hệ thống (POST /v1/jobs) — có hàng đợi, retry, webhook và quản lý backend trên Orchestrator, giống mọi tác vụ khác. Chỉ cần đổi task.
task: tts
task: stt
26 ngôn ngữ
Tùy chỉnh giọng
Nhân bản giọng
Text → Speech task: "tts"
Cơ bản
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "tts",
"webhook_url": "https://your-site.com/webhook",
"payload": {
"text": "Xin chào anh, đây là giọng đọc thử.",
"language": "vi"
}
}'
Nâng cao — tùy chỉnh giọng + nhân bản
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "tts",
"webhook_url": "https://your-site.com/webhook",
"payload": {
"text": "Chào mừng quý khách.",
"language": "vi",
"instruct": "female, young adult, high pitch",
"speed": 1.1,
"ref_audio_url": "https://example.com/mau_giong.wav",
"ref_text": "Nội dung chính xác của file mẫu."
}
}'
Kết quả (qua webhook / GET /v1/jobs/{id})
{
"job_id": "2d71af26-...",
"task": "tts",
"status": "succeeded",
"result": {
"url": "http://.../files/tts_xxxx.wav",
"duration": 3.63,
"gen_time": 1.3,
"mode": "tts",
"meta": { "backend": "tts-183" }
}
}
| payload.* | Type | Desc |
|---|---|---|
text | string | Required. Văn bản cần đọc. |
language | string | Mã ngôn ngữ hoặc auto. |
instruct | string | Mô tả giọng bằng thẻ tiếng Anh, ngăn cách bởi dấu phẩy. |
speed | float | Tốc độ đọc 0.5–2.0 (mặc định 1.0). |
duration | float | (Optional) Ép độ dài audio (giây). |
ref_audio_url | string | (Optional) Link audio mẫu để nhân bản giọng. |
ref_text | string | Kèm ref_audio_url: transcript của mẫu. |
num_step, guidance_scale | int/float | (Optional) Tinh chỉnh chất lượng diffusion. |
Thẻ instruct
| Nhóm | Giá trị |
|---|---|
| Giới tính | female, male |
| Độ tuổi | child, teenager, young adult, middle-aged, elderly |
| Cao độ | very low pitch … very high pitch |
| Phong cách | whisper |
VD "female, young adult, high pitch". Ngôn ngữ: vi, en, zh, ja, ko, th, id, ms, fr, de, es, it, pt, ru, ar, hi, km, lo, my, nl, tr, pl, uk, fa, ta + auto.
Speech → Text task: "stt"
Request
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "stt",
"webhook_url": "https://your-site.com/webhook",
"payload": {
"audio_url": "https://example.com/ghi_am.wav",
"language": "vi"
}
}'
Kết quả
{
"task": "stt",
"status": "succeeded",
"result": {
"text": "Xin chào anh, đây là giọng đọc thử.",
"lang": "vi",
"gen_time": 0.26,
"mode": "stt",
"meta": { "backend": "stt-183" }
}
}
| payload.* | Type | Desc |
|---|---|---|
audio_url | string | Required. Link file audio (wav/mp3/m4a...). |
language | string | (Optional) Ép ngôn ngữ. Bỏ trống = tự nhận diện. |
POST /v1/jobs nhận job_id, kết quả trả qua webhook_url hoặc GET /v1/jobs/{job_id}. Backend giọng nói được quản lý trên Orchestrator (bật/tắt/định tuyến), không gọi thẳng GPU server.
5. Music Generation — ACE-Step v1.5
Tạo nhạc có lời từ mô tả, qua cùng một API job (POST /v1/jobs, task: "music_gen"). Hai chế độ: AI tự viết lời hoặc tự đưa lời.
task: music_gen
AI tự viết lời
Chọn giọng nam/nữ
30–240 giây
Hoà tấu
Chế độ 1 — AI tự viết lời lyrics: "[auto:vi]"
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "music_gen",
"webhook_url": "https://your-site.com/webhook",
"payload": {
"prompt": "female vocals, nhạc pop ballad Việt Nam, có piano, về tình bạn tuổi học trò",
"lyrics": "[auto:vi]",
"duration": 90,
"format": "mp3"
}
}'
Hệ thống gọi LLM viết lời bám sát mô tả (giữ tên riêng, câu chuyện) rồi mới dựng nhạc.
Chế độ 2 — Tự đưa lời (hát đúng từng chữ)
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "music_gen",
"payload": {
"prompt": "male vocals, acoustic ballad, guitar mộc, ấm áp",
"lyrics": "[Verse]\nNắng sớm lên rồi, anh gọi em dậy\nTiếng cười giòn tan theo gió bay xa\n\n[Chorus]\nDẫu mai lớn khôn ta vẫn là gia đình\nNắm chặt tay nhau đi hết con đường",
"duration": 80,
"seed": 42
}
}'
Chế độ 3 — Sáng tác từ ẢNH image_url 🆕
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "music_gen",
"payload": {
"image_url": "https://example.com/anh-ky-niem.jpg",
"language": "vi",
"duration": 90,
"prompt": "giọng nữ, nhẹ nhàng"
}
}'
AI nhìn ảnh (chủ thể, bối cảnh, ánh sáng, tâm trạng) rồi tự quyết phong cách nhạc + viết lời hợp cảnh.
prompt lúc này là gợi ý thêm (không bắt buộc). Kết quả trả thêm meta.scene (mô tả ảnh) và lyrics (lời đã hát).
Hoà tấu (không lời)
"lyrics": "[instrumental]"
Kết quả (qua webhook / GET /v1/jobs/{id})
{
"job_id": "7796e62b-...",
"task": "music_gen",
"status": "succeeded",
"result": {
"url": "http://.../files/7724747c.mp3",
"duration": 90,
"mode": "music_gen",
"meta": { "backend": "music-239" }
}
}
| payload.* | Type | Desc |
|---|---|---|
prompt | string | Bắt buộc nếu không có image_url. Mô tả phong cách/nội dung, tối đa 1000 ký tự. |
image_url | string | 🆕 Link ảnh — AI đọc ảnh rồi sáng tác bài hát hợp bối cảnh & tâm trạng. Có ảnh thì prompt/lyrics thành gợi ý. |
language | string | Ngôn ngữ lời khi dùng image_url (mặc định vi). |
lyrics | string | Lời bài hát, hoặc [auto:xx] để AI viết, hoặc [instrumental]. Tối đa 4000 ký tự. Bỏ trống = hoà tấu. |
duration | int | Độ dài giây, 30–240 (mặc định 75). Ngoài khoảng sẽ bị kẹp về biên. |
format | string | mp3 (mặc định) hoặc wav. |
seed | int | (Optional) Cố định seed để tái tạo bài giống nhau. |
Mã [auto:xx] — ngôn ngữ lời (18 ngôn ngữ)
| Mức | Mã |
|---|---|
| Mạnh nhất | en Anh · zh Trung |
| Tốt | ja Nhật · ko Hàn · es Tây Ban Nha · ru Nga · de Đức · fr Pháp · pt Bồ Đào Nha · it Ý |
| Có hỗ trợ | pl Ba Lan · tr Thổ Nhĩ Kỳ · cs Séc · nl Hà Lan · ar Ả Rập · hu Hungary · hi Hindi |
| Ngoài vùng huấn luyện | vi Việt — vẫn hát được, nhưng model chưa được huấn luyện với nhạc Việt nên chất lượng thấp hơn các nhóm trên |
[auto] không kèm mã = mặc định vi ·
[instrumental] = không lời (hoà tấu) ·
Mã lạ ngoài bảng cũng rơi về vi.
| |
language của
music_cover dùng chung bảng mã này.
Chọn giọng hát
prompt bằng thẻ tiếng Anh đặt ở đầu:
female vocals, ... hoặc male vocals, ....
Ghi "giọng nữ" bằng tiếng Việt không đảm bảo — model chỉ hiểu thẻ tiếng Anh.
Cấu trúc lời (chế độ 2)
[Intro], [Verse], [Pre-Chorus], [Chorus], [Bridge], [Outro]. Mỗi câu hát một dòng.
GET /v1/jobs/{job_id}.
6. Music Cover — Phối nhạc từ audio có sẵn
Gửi một file âm thanh + mô tả phong cách → hệ thống phối lại thành bài mới. Hai kịch bản dùng chung
task: "music_cover", khác nhau ở mode:
mode: vocal — bạn tự hát → phối nhạc
mode: remix — đổi phong cách, giữ lời
Tự giữ lời bằng STT
A. Tự hát → phối nhạc mode: "vocal"
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "music_cover",
"webhook_url": "https://your-site.com/webhook",
"payload": {
"audio_url": "https://example.com/toi-tu-hat.m4a",
"prompt": "warm acoustic ballad, gentle guitar, soft piano, emotional",
"mode": "vocal",
"language": "vi"
}
}'
B. Phối lại bài cũ, giữ nguyên lời mode: "remix"
curl -X POST "{{API_BASE}}/v1/jobs" \
-H "X-API-Key: {{API_KEY}}" \
-H "Content-Type: application/json" \
-d '{
"task": "music_cover",
"payload": {
"audio_url": "https://example.com/bai-goc.mp3",
"prompt": "upbeat EDM dance remix, energetic synths, festival vibe",
"mode": "remix",
"keep_lyrics": true,
"language": "vi"
}
}'
Kết quả
{
"task": "music_cover",
"status": "succeeded",
"result": {
"url": "http://.../files/51b843ab.mp3",
"duration": 30,
"src_duration": 30.0,
"lyrics": "Nắng sớm lên rồi, em bước qua sân nhà...",
"mode": "music_cover",
"meta": { "backend": "cover-239", "mode": "remix", "lyrics_from": "stt" }
}
}
| payload.* | Type | Desc |
|---|---|---|
audio_url | string | Required. Link audio nguồn (mp3/wav/m4a/flac/ogg). |
prompt | string | Required. Phong cách nhạc muốn ra (nên viết tiếng Anh cho chuẩn: thể loại, nhạc cụ, tempo, mood). |
mode | string | vocal: GIỮ NGUYÊN giọng bạn thu, hệ sinh nhạc nền theo prompt rồi hoà âm (có ducking — nhạc nhường khi có giọng). remix (mặc định): tách giọng hát khỏi bản gốc (AI separation), sinh nhạc nền phong cách mới khớp BPM & tông của bài gốc, rồi hoà âm lại → giữ nguyên 100% giọng hát và lời, chỉ thay nhạc. Lời trả về được nhận dạng trên track giọng đã tách nên chính xác hơn nhiều. |
keep_lyrics | bool | Mặc định true: nếu không gửi lyrics, hệ thống tự nghe audio nguồn (STT) để giữ nguyên lời. |
lyrics | string | (Optional) Lời tự nhập, ưu tiên hơn STT. Tối đa 4000 ký tự. |
language | string | Ngôn ngữ lời (mặc định vi). |
duration | int | Giây. Bỏ trống/0 = theo độ dài audio nguồn (kẹp 20–240s). |
keep | float | 0–1: mức bám bản gốc. Càng cao càng ít nhạc cụ (chỉ giữ giọng); càng thấp thì hệ dựng nhạc càng nhiều. Mặc định 0.25 (vocal) / 0.35 (remix). Muốn nhiều nhạc: 0.15–0.25. |
strength | float | 0–1: mức áp phong cách mới (nhỏ = đổi mạnh). Mặc định 0.15 (vocal) / 0.2 (remix). |
seed | int | (Optional) Cố định để tái tạo. |
keep (0.15–0.25);
muốn giữ giai điệu gốc → tăng keep (0.5–0.7).
7. Chat LLM — API chuẩn OpenAI
Endpoint chat tương thích hoàn toàn với OpenAI. Đang dùng thư viện openai (Python/Node)
hay bất kỳ công cụ nào nói chuẩn OpenAI, bạn chỉ cần đổi base_url — không sửa một dòng code nào khác.
Khoá của nhà cung cấp nằm ở phía máy chủ, không bao giờ lộ ra trình duyệt.
Model mặc định là ahv-qwen38 — model của nhà, chạy trên GPU riêng, biết
suy luận và gọi công cụ. Không truyền model thì hệ thống tự dùng nó.
Nếu máy chủ Qwen chưa sẵn sàng, hệ thống tự lui về nhà cung cấp bên ngoài để câu hỏi
của bạn không bị lỗi — bạn không phải xử lý gì thêm.
POST /v1/chat/completions
GET /v1/models
Streaming SSE
Gọi công cụ
Chế độ suy luận
Đọc ảnh
Nhớ ngữ cảnh nhiều lượt
Ngữ cảnh 256K · đầu ra 64K
1012 model
Đổi base_url là chạy POST /v1/chat/completions
Python — thư viện openai
from openai import OpenAI
# api_key chưa bắt buộc, chỉ để cho hợp SDK
cl = OpenAI(
base_url="http://15.235.200.66:2022/v1",
api_key="anhyeuem",
)
# bỏ model đi cũng được, mặc định đã là ahv-qwen38
r = cl.chat.completions.create(
model="ahv-qwen38",
messages=[
{"role": "user", "content": "Viết 3 câu quảng cáo"}
],
)
print(r.choices[0].message.content)
Streaming — chữ hiện dần
s = cl.chat.completions.create(
model="ahv-qwen38",
messages=[
{"role": "user", "content": "Kể một câu chuyện"}
],
stream=True,
)
for chunk in s:
manh = chunk.choices[0].delta.content
if manh:
print(manh, end="", flush=True)
Gọi thẳng bằng curl
curl -s http://15.235.200.66:2022/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "ahv-qwen38",
"messages": [
{"role": "system", "content": "Bạn là trợ lý của AHV, trả lời bằng tiếng Việt."},
{"role": "user", "content": "Giới thiệu hệ thống AHV trong 2 câu"}
],
"temperature": 0.6,
"max_tokens": 500
}'
Tham số
| Trường | Kiểu | Mặc định | Mô tả |
|---|---|---|---|
model | string | ahv-qwen38 |
Tên model. Bỏ trống thì dùng ahv-qwen38 (model của nhà).
Lấy danh sách đầy đủ ở GET /v1/models. |
messages | array | — bắt buộc | Mảng {role, content}. role nhận system / user / assistant.
Gửi cả lịch sử để model nhớ ngữ cảnh. |
stream | bool | false |
true để nhận SSE từng mảnh (choices[0].delta.content), kết thúc bằng data: [DONE]. |
temperature | float | 0.6 |
Càng cao càng sáng tạo, càng thấp càng bám sát. Sinh code nên đặt 0.1–0.3. |
max_tokens | int | 65536 |
Số token tối đa cho câu trả lời. Cửa sổ ngữ cảnh 262.144 token (256K)
— đủ cho các CLI coding nạp cả kho mã. Bỏ trống thì hệ thống tự lấy 65536,
và tự co lại nếu câu hỏi quá dài để không tràn ngữ cảnh.
Lưu ý: câu trả lời cực dài mất nhiều thời gian (tốc độ ~18 token/giây,
65.536 token ≈ 58 phút) — nên dùng stream: true để nhận dần. |
tools | array | — | Khai báo công cụ để model gọi — xem phần Gọi công cụ. |
reasoning_effort | string | low |
Mức suy luận: minimal / low / medium / high,
hoặc none để tắt hẳn — xem phần
Chế độ suy luận. |
reasoning | object | — | {effort, enabled, exclude} — cách viết của OpenRouter, cũng nhận. |
thinking | object | — | {type, budget_tokens} — cách viết của Anthropic, cũng nhận. |
Giới hạn & lỗi
| Mã | Ý nghĩa | Xử lý |
|---|---|---|
400 | Thiếu messages hoặc body không phải JSON | Kiểm lại body. |
429 | Quá 120 lượt/phút trên một IP | Chờ một chút rồi gọi lại. |
502 | Cả model của nhà lẫn nhà cung cấp dự phòng đều không trả nội dung (thường do đang giới hạn tần suất) | Hiếm gặp, vì hệ thống đã tự lui về dự phòng. Thử lại sau ít phút hoặc đổi model khác. |
503 | Dịch vụ LLM đang tắt trong cấu hình | Bật lại ở trang Admin. |
Lỗi trả về đúng khuôn OpenAI — {"error": {"message": "...", "type": "..."}} —
nên SDK bắt được như với API gốc. Mỗi lượt tối đa 400 tin nhắn; hội thoại dài hơn thì phần cũ nhất bị lược bớt
nhưng mọi tin system luôn được giữ nguyên. Nội dung
không bao giờ bị cắt âm thầm: vượt cửa sổ ngữ cảnh thì trả lỗi
400 context_length_exceeded kèm số token ước tính.
Danh sách model GET /v1/models
curl -s http://15.235.200.66:2022/v1/models
{
"object": "list",
"data": [
{"id": "ahv-qwen38", "object": "model", "created": 1787330074, "owned_by": "ahv"},
{"id": "AHV-Holding-TroLy", "object": "model", "created": 1787330074, "owned_by": "ahv"},
{"id": "Grok-SuperHeavy", "object": "model", "created": 1787330074, "owned_by": "ahv"}
]
}
Chế độ suy luận — reasoning_effort
ahv-qwen38 là model biết suy nghĩ trước khi trả lời. Mặc định hệ thống đặt
mức low — chúng tôi đã đo trên bộ bài code khó và low cho kết
quả đúng ngang mức cao nhất nhưng nhanh hơn khoảng 32%. Bạn chỉnh bằng
reasoning_effort ở cấp cao nhất của body, đúng như cách gọi OpenAI:
curl -X POST http://15.235.200.66:2022/v1/chat/completions \
-H 'Content-Type: application/json' -d '{
"messages": [{"role": "user", "content": "1 + 1 bằng mấy?"}],
"reasoning_effort": "low"
}'
| Giá trị | Model làm gì | Dùng khi nào |
|---|---|---|
low / minimal mặc định |
Nghĩ ngắn gọn rồi trả lời ngay | Hầu hết mọi việc, kể cả code — đo được 10/10 bài |
medium | Nghĩ vừa phải | Câu hỏi thường ngày |
high |
Nghĩ kỹ, tự kiểm giả định, cân nhắc phương án khác | Bài thật sự hóc búa — chậm hơn ~50%, không cho thêm điểm ở bài thường |
none | Tắt hẳn phần suy nghĩ, trả lời thẳng | Chat nhanh, dịch, viết lại câu |
Viết theo chuẩn nào cũng chạy
Mỗi hãng đặt tên tham số một kiểu, nên các CLI và SDK cũng gửi mỗi bên một kiểu. Máy chủ nhận cả bốn, bạn không phải sửa công cụ đang dùng:
"reasoning_effort": "high" // OpenAI
"reasoning": {"effort": "high", "exclude": false} // OpenRouter
"thinking": {"type": "enabled", "budget_tokens": 8000} // Anthropic
"chat_template_kwargs": {"reasoning_effort": "xhigh"} // vLLM
Đặt "reasoning": {"exclude": true} nếu muốn model vẫn nghĩ nhưng
không trả phần nghĩ về cho bạn (tiết kiệm băng thông khi bạn không hiển thị nó).
Gửi giá trị lạ thì máy chủ trả 400 kèm danh sách giá trị hợp lệ, chứ không im lặng bỏ qua.
Đọc phần suy nghĩ ở đâu
content trả về luôn sạch — không bao giờ lẫn khối
<think>. Phần suy nghĩ nằm riêng, và trả cùng lúc ở cả hai tên
(reasoning theo OpenRouter, reasoning_content theo DeepSeek)
để công cụ nào cũng đọc được:
{
"choices": [{
"message": {
"role": "assistant",
"content": "2",
"reasoning": "Người dùng hỏi 1+1...",
"reasoning_content": "Người dùng hỏi 1+1..."
}
}]
}
Khi stream: true, phần nghĩ về trước theo từng mảnh ở
delta.reasoning và delta.reasoning_content, xong mới tới
delta.content — nên bạn hiện được khối “đang suy nghĩ” theo thời gian thực.
max_tokens: phần suy nghĩ cũng tính vào max_tokens.
Đặt quá thấp (dưới ~800) thì model có thể dùng hết token vào việc nghĩ và trả
content rỗng — phần nghĩ vẫn nằm trong reasoning.
Mặc định 65536 đã đủ rộng cho hầu hết nhu cầu; muốn ngắn và nhanh thì hạ
reasoning_effort xuống low / none.
Gọi công cụ — tools / tool_calls
Hỗ trợ function calling chuẩn OpenAI. Bạn khai báo tools như với OpenAI,
model trả về tool_calls đã được cấu trúc hoá sẵn (kèm id và
arguments dạng chuỗi JSON) — không phải XML thô, không cần bạn tự bóc tách.
Khi model quyết định gọi công cụ, finish_reason là tool_calls.
Chế độ streaming cũng hỗ trợ: tên hàm về trước, arguments nhả dần theo từng mảnh.
curl -X POST http://15.235.200.66:2022/v1/chat/completions \
-H 'Content-Type: application/json' -d '{
"messages": [{"role": "user", "content": "Tra cứu thời tiết Hà Nội giúp tôi."}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Lấy thời tiết một thành phố",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}]
}'
Model trả về:
{
"choices": [{
"finish_reason": "tool_calls",
"message": {
"role": "assistant",
"content": "",
"tool_calls": [{
"id": "chatcmpl-tool-9ef9a5d721211647",
"type": "function",
"function": {"name": "get_weather", "arguments": "{\"city\": \"Ha Noi\"}"}
}]
}
}]
}
Sau khi chạy hàm, gửi kết quả trở lại bằng message role: "tool" kèm
tool_call_id đúng bằng id ở trên, model sẽ dùng nó để viết câu trả lời cuối:
"messages": [
{"role": "user", "content": "Tra cứu thời tiết Hà Nội giúp tôi."},
{"role": "assistant", "tool_calls": [ ...như trên... ]},
{"role": "tool", "tool_call_id": "chatcmpl-tool-9ef9a5d721211647",
"content": "{\"temp_c\": 31, \"desc\": \"nắng\"}"}
]
openai. Vì đúng chuẩn nên
client.chat.completions.create(..., tools=[...]) chạy y hệt như khi trỏ vào OpenAI,
kể cả tool_choice và parallel_tool_calls.
8. Giọng nói — API chuẩn OpenAI
Hai endpoint cho trò chuyện bằng giọng nói, dùng thẳng TTS/STT chạy trên GPU nhà.
Gọi trực tiếp (không qua hàng đợi /v1/jobs) vì hội thoại là thời gian thực.
POST /v1/audio/transcriptions
POST /v1/audio/speech
Nghe: ~0,4s
Đọc: ~0,9s
Tiếng Việt có dấu
Nghe → chữ POST /v1/audio/transcriptions
Nhận một trong hai cách: gửi link âm thanh, hoặc tải thẳng file lên (multipart). Đo thật: gửi link 0,79s, gửi file 1,77s (đã gồm thời gian lưu file).
Cách 1 — gửi link
curl -s http://15.235.200.66:2022/v1/audio/transcriptions \
-H 'Content-Type: application/json' \
-d '{"audio_url": "https://.../ghi_am.wav"}'
Cách 2 — tải file lên
curl -s http://15.235.200.66:2022/v1/audio/transcriptions \
-F "file=@ghi_am.webm"
{
"text": "Xin chào anh Hiếu, đây là giọng đọc thử.",
"language": "vi",
"duration": 0.38
}
Định dạng nhận được: webm, wav, mp3, m4a,
ogg, opus, flac. Tối đa 25MB.
Chữ → tiếng POST /v1/audio/speech
curl -s http://15.235.200.66:2022/v1/audio/speech \
-H 'Content-Type: application/json' \
-d '{
"input": "Xin chào, tôi là trợ lý AHV. Bạn cần giúp gì ạ?",
"language": "vi"
}'
{
"url": "http://178.63.96.183:2037/files/tts_714812a2.wav",
"duration": 3.3,
"xu_ly": 1.24
}
Trả về link file thay vì luồng nhị phân, để trình duyệt phát ngay bằng thẻ
<audio> mà không phải chờ tải hết.
Tham số
| Endpoint | Trường | Kiểu | Mặc định | Mô tả |
|---|---|---|---|---|
transcriptions |
audio_url | string | — | Link file âm thanh. Bắt buộc nếu không gửi file. |
file | multipart | — | File âm thanh tải thẳng lên. Bắt buộc nếu không gửi audio_url. | |
speech |
input | string | — bắt buộc | Văn bản cần đọc. Tối đa 1500 ký tự mỗi lượt. |
language | string | vi |
Mã ngôn ngữ. | |
voice | string | (mặc định) | female hoặc male. |
Mã lỗi
| Mã | Ý nghĩa | Xử lý |
|---|---|---|
400 | Thiếu trường bắt buộc, định dạng âm thanh không hỗ trợ, hoặc file quá 25MB | Kiểm lại body. |
422 | Nghe được file nhưng không ra chữ nào (tiếng quá nhỏ hoặc chỉ có tạp âm) | Nhắc người dùng nói to và rõ hơn. |
429 | Quá 120 lượt/phút trên một IP | Chờ một chút rồi gọi lại. |
502 | Dịch vụ TTS/STT lỗi hoặc không trả kết quả | Thử lại sau ít phút. |
Lỗi trả về đúng khuôn OpenAI — {"error": {"message": "...", "type": "..."}}.
. ! ? ngay trong lúc nhận luồng chữ,
rồi gọi /v1/audio/speech cho từng câu và phát nối tiếp. Trang demo
Chat AI làm đúng như vậy —
người dùng nghe thấy tiếng sau khoảng 3–5 giây thay vì phải đợi hết câu trả lời.