Tham khảo API
Tài liệu này khớp với hành vi của ứng dụng Express trong api/app.js và các bộ xử lý tuyến đường dưới api/routes/.
Giới hạn và hành vi
| Mục | Giá trị |
|---|---|
| Kích thước thân JSON | Tối đa 2 MB (express.json({ limit: '2mb' })) |
| Mục tiêu mỗi yêu cầu | 1–36 mã ngôn ngữ |
| Mục lô | 1–100 mục mỗi yêu cầu lô |
| Mô hình | standard (mặc định) hoặc advanced (chỉ các cấp trả phí; xem bên dưới) |
Hạn mức token hàng tháng (cấp miễn phí): Trước khi gọi mô hình, API ước tính token xấp xỉ ceil(content_length / 4) × (number_of_targets + 1) và, chỉ với cấp free, từ chối yêu cầu với mã 429 / token_limit_reached nếu ước tính vượt quá hạn mức hàng tháng còn lại (FREE_TIER_MONTHLY_TOKENS, mặc định 100000). Các cấp trả phí không bị chặn bởi kiểm tra trước này trong enforceTokenCap; việc sử dụng vẫn được ghi lại.
Giới hạn tốc độ: Khi cấu hình Upstash Redis (UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN, và URL không chứa chỗ giữ chỗ your-instance), giới hạn theo phút áp dụng theo cấp: miễn phí 5, khởi đầu 30, phát triển 60, mở rộng 120, doanh nghiệp không giới hạn. Khi vượt giới hạn, phản hồi là 429 với error: "rate_limit_reached". Nếu Redis không được cấu hình, giới hạn tốc độ bị bỏ qua (xem rateLimit.js).
Phản hồi giới hạn tốc độ thành công có thể bao gồm X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
GET /health
Không cần xác thực.
Phản hồi 200
{
"status": "ok",
"timestamp": "2025-03-23T12:00:00.000Z"
}
GET /languages
Không cần xác thực.
Trả về danh sách chuẩn các ngôn ngữ được hỗ trợ (mã, tên hiển thị, cờ RTL). Có 36 mục; mã là giá trị duy nhất được chấp nhận trong targets tại các điểm cuối dịch.
Phản hồi 200
{
"languages": [
{ "code": "en", "name": "English", "rtl": false },
{ "code": "ar", "name": "Arabic", "rtl": true }
]
}
Nguồn: api/utils/languages.js.
POST /translate
Yêu cầu Authorization: Bearer <api_key>.
Dịch một chuỗi content duy nhất sang mọi ngôn ngữ được liệt kê trong targets. Mô hình trả về một đối tượng JSON duy nhất với các khóa chính xác là các mã ngôn ngữ yêu cầu và giá trị là các chuỗi đã dịch (xem formatPrompts.js).
Thân yêu cầu
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
content | string | Có | Chuỗi không rỗng để dịch. |
targets | string[] | Có | Mảng không rỗng các mã ngôn ngữ hợp lệ (tối đa 36). |
format | string | Không | Một trong plain, markdown, json, html. Nếu bỏ qua, định dạng được tự động phát hiện từ content. |
source | string | Không | Gợi ý ngôn ngữ nguồn cho mô hình; tùy chọn. |
model | string | Không | standard (mặc định) hoặc advanced. advanced yêu cầu cấp trả phí (403 với cấp miễn phí). |
Phản hồi 200
{
"translations": {
"es": "...",
"fr": "..."
},
"usage": {
"input_tokens": 120,
"output_tokens": 340,
"total_tokens": 460,
"model": "standard",
"detected_format": "markdown",
"detection_confidence": 0.95
}
}
detected_format và detection_confidence chỉ xuất hiện khi format bị bỏ qua và tự động phát hiện được thực hiện.
Ví dụ (cURL)
curl -sS -X POST "https://api.usepolylingo.com/v1/translate" \
-H "Authorization: Bearer $POLYLINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "{\"title\":\"Hello\"}",
"format": "json",
"targets": ["fr", "de"]
}'
Ví dụ (Python 3)
pip install requests
import os, requests
url = "https://api.usepolylingo.com/v1/translate"
headers = {
"Authorization": f"Bearer {os.environ['POLYLINGO_API_KEY']}",
"Content-Type": "application/json",
}
r = requests.post(url, json={
"content": "<p>Hello <strong>world</strong></p>",
"format": "html",
"targets": ["es"],
}, timeout=120)
r.raise_for_status()
print(r.json()["translations"]["es"])
POST /translate/batch
Yêu cầu Authorization: Bearer <api_key>.
Xử lý từng mục tuần tự (mỗi mục gọi mô hình một lần). Nếu bất kỳ mục nào thất bại, API trả về 500 và không trả kết quả một phần cho yêu cầu đó.
Thân yêu cầu
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
items | mảng | Có | Mỗi phần tử: id (chuỗi), content (chuỗi), tùy chọn format. |
targets | string[] | Có | Quy tắc giống /translate. |
source | string | Không | Gợi ý ngôn ngữ nguồn tùy chọn. |
model | string | Không | standard hoặc advanced (quy tắc giống /translate). |
Phản hồi 200
{
"results": [
{ "id": "welcome", "translations": { "fr": "...", "de": "..." } },
{ "id": "goodbye", "translations": { "fr": "...", "de": "..." } }
],
"usage": {
"total_tokens": 900,
"input_tokens": 400,
"output_tokens": 500,
"model": "standard"
}
}
Ví dụ
curl -sS -X POST "https://api.usepolylingo.com/v1/translate/batch" \
-H "Authorization: Bearer $POLYLINGO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"items": [
{ "id": "a", "content": "Hello", "format": "plain" },
{ "id": "b", "content": "## Title", "format": "markdown" }
],
"targets": ["es", "it"]
}'
POST /jobs
Yêu cầu Authorization: Bearer <api_key>.
Đưa một công việc dịch vào hàng đợi và trả về ngay với job_id. Việc dịch chạy nền — không có rủi ro hết thời gian HTTP bất kể kích thước nội dung. Kiểm tra GET /jobs/:id để lấy kết quả.
Sử dụng điểm cuối này thay cho POST /translate khi dịch tài liệu lớn (Markdown dài, nhiều ngôn ngữ mục tiêu) mà thời gian yêu cầu có thể vượt quá thời gian chờ của client hoặc proxy HTTP của bạn.
Thân yêu cầu
| Trường | Loại | Bắt buộc | Mô tả |
|---|---|---|---|
content | string | Có | Chuỗi không rỗng để dịch. |
targets | string[] | Có | Mảng không rỗng các mã ngôn ngữ hợp lệ (tối đa 36). |
format | string | Không | Một trong plain, markdown, json, html. Tự động phát hiện nếu bỏ qua. |
source | string | Không | Gợi ý ngôn ngữ nguồn; tùy chọn. |
model | string | Không | standard (mặc định) hoặc advanced. |
Phản hồi 202
{
"job_id": "a1b2c3d4-...",
"status": "pending",
"created_at": "2025-03-23T12:00:00.000Z"
}
GET /jobs/:id
Yêu cầu Authorization: Bearer <api_key>.
Kiểm tra trạng thái công việc gửi qua POST /jobs. Kiểm tra mỗi 5–10 giây. Công việc thuộc về người dùng gửi — người dùng khác nhận 404.
Phản hồi (đang chờ / xử lý)
{
"job_id": "a1b2c3d4-...",
"status": "pending",
"created_at": "2025-03-23T12:00:00.000Z",
"updated_at": "2025-03-23T12:00:00.000Z",
"completed_at": null,
"queue_position": 3
}
status là pending (đang chờ công nhân) hoặc processing (công nhân đã nhận). queue_position (bắt đầu từ 1) là số công việc đang chờ hoặc xử lý được tạo trước công việc này — dùng cho giao diện tiến trình. Bỏ qua nếu truy vấn đếm thất bại.
Phản hồi (hoàn thành)
{
"job_id": "a1b2c3d4-...",
"status": "completed",
"created_at": "2025-03-23T12:00:00.000Z",
"updated_at": "2025-03-23T12:00:02.000Z",
"completed_at": "2025-03-23T12:00:02.000Z",
"translations": {
"es": "...",
"fr": "..."
},
"usage": {
"input_tokens": 120,
"output_tokens": 340,
"total_tokens": 460,
"model": "standard"
}
}
Phản hồi (thất bại)
{
"job_id": "a1b2c3d4-...",
"status": "failed",
"error": "Model returned invalid JSON"
}
Ví dụ (JavaScript)
const API = 'https://api.usepolylingo.com/v1'
const headers = {
'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
'Content-Type': 'application/json',
}
// 1. Gửi
const submit = await fetch(`${API}/jobs`, {
method: 'POST',
headers,
body: JSON.stringify({ content: longMarkdown, format: 'markdown', targets: ['de', 'fr'] }),
})
const { job_id } = await submit.json()
// 2. Kiểm tra
while (true) {
await new Promise(r => setTimeout(r, 10_000))
const poll = await fetch(`${API}/jobs/${job_id}`, { headers })
const job = await poll.json()
if (job.status === 'completed') { console.log(job.translations); break }
if (job.status === 'failed') { throw new Error(job.error) }
// Tùy chọn: hiển thị tiến trình (queue_position bắt đầu từ 1, bỏ qua khi không trong hàng)
if (job.queue_position != null) console.log(`Vị trí hàng đợi: ${job.queue_position}`)
}
GET /usage
Yêu cầu Authorization: Bearer <api_key> (tra cứu khóa tiêu chuẩn — không phải đường dẫn bỏ qua nội bộ).
Trả về việc sử dụng token cho tháng lịch hiện tại của người dùng đã xác thực.
Phản hồi 200
{
"period_start": "2025-03-01T00:00:00.000Z",
"period_end": "2025-03-31T23:59:59.000Z",
"tokens_used": 12000,
"tokens_included": 100000,
"tokens_remaining": 88000,
"overage_tokens": 0,
"tier": "free"
}
tokens_included và tokens_remaining là null cho enterprise (hạn mức không giới hạn trong báo cáo).
Định dạng nội dung
Các giá trị format được hỗ trợ: plain, markdown, json, html.
| Định dạng | Giữ nguyên | Dịch |
|---|---|---|
plain | Ngắt dòng / đoạn văn | Tất cả văn bản hiển thị |
markdown | Cú pháp, liên kết (URL không đổi), khối mã (nguyên văn) | Văn bản và văn bản liên kết |
json | Khóa, cấu trúc, kiểu không phải chuỗi | Chỉ giá trị chuỗi |
html | Thẻ và thuộc tính | Nút văn bản và thuộc tính thích hợp (xem lời nhắc) |
RTL và hướng trong ứng dụng của bạn
Với đầu ra plain và markdown, API chỉ trả về văn bản đã dịch — không thêm dir="rtl" hoặc phần tử bao bọc. Đặt hướng văn bản trong UI của bạn (CSS direction, thuộc tính dir của phần tử cha hoặc bố cục i18n của framework) khi hiển thị tiếng Ả Rập, Do Thái hoặc Ba Tư.
Với định dạng html, đánh dấu đã dịch có thể bao gồm dir="rtl" khi thích hợp cho các mục tiêu RTL; xem formatPrompts.js và các bài kiểm tra HTML trong scripts/test-translation.js.
Phản hồi lỗi
Lỗi ở dạng JSON khi có thể:
{
"error": "invalid_request",
"message": "Chi tiết dễ hiểu cho người dùng"
}
| HTTP | error | Khi nào |
|---|---|---|
| 400 | invalid_request | Thiếu/trường thân không hợp lệ (ví dụ: content rỗng, targets sai) |
| 400 | invalid_format | format không thuộc tập hợp được hỗ trợ |
| 400 | invalid_language | Mã không xác định trong targets |
| 401 | invalid_api_key | Thiếu/hỏng Authorization, khóa không biết, khóa bị thu hồi |
| 403 | advanced_not_available | model: "advanced" trên cấp miễn phí |
| 429 | token_limit_reached | Vượt hạn mức token hàng tháng cấp miễn phí (kiểm tra trước) |
| 429 | rate_limit_reached | Giới hạn RPM theo phút (khi Redis bật) |
| 500 | translation_error | Lỗi mô hình/mạng; có thể thử lại |
| 404 | not_found | GET /jobs/:id — công việc không tồn tại hoặc thuộc người dùng khác |
| 500 | server_error | POST /jobs — không thể xếp hàng; có thể thử lại |
GET /usage có thể trả về 500 với thông báo chung nếu truy vấn Supabase thất bại.
Mô hình nền tảng (thông tin)
API chỉ cung cấp standard và advanced. ID mô hình OpenAI thực tế được cấu hình trong api/utils/modelRouter.js và không được trả về trong phản hồi API.