Referencje API
Ten dokument odpowiada zachowaniu aplikacji Express w api/app.js oraz obsługiwaczom tras w katalogu api/routes/.
Limity i zachowanie
| Element | Wartość |
|---|---|
| Rozmiar ciała JSON | Do 2 MB (express.json({ limit: '2mb' })) |
| Cele na żądanie | 1–36 kodów języków |
| Elementy partii | 1–100 elementów na żądanie partii |
| Modele | standard (domyślny) lub advanced (tylko płatne poziomy; patrz poniżej) |
Miesięczny limit tokenów (poziom darmowy): Przed wywołaniem modelu API szacuje tokeny mniej więcej jako ceil(content_length / 4) × (number_of_targets + 1) i tylko dla poziomu free odrzuca żądanie z kodem 429 / token_limit_reached, jeśli szacowana wartość przekroczyłaby pozostały miesięczny limit (FREE_TIER_MONTHLY_TOKENS, domyślnie 100000). Poziomy płatne nie są blokowane przez tę wstępną kontrolę w enforceTokenCap; użycie jest nadal rejestrowane.
Limity szybkości: Gdy Upstash Redis jest skonfigurowany (UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN, a URL nie zawiera zastępczego tekstu your-instance), obowiązują limity na minutę według poziomu: darmowy 5, startowy 30, wzrost 60, skala 120, enterprise bez limitu. Po przekroczeniu limitu odpowiedź to 429 z error: "rate_limit_reached". Jeśli Redis nie jest skonfigurowany, limitowanie szybkości jest pomijane (patrz rateLimit.js).
Udane odpowiedzi z limitowaniem szybkości mogą zawierać nagłówki X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
GET /health
Brak uwierzytelniania.
Odpowiedź 200
{
"status": "ok",
"timestamp": "2025-03-23T12:00:00.000Z"
}
GET /languages
Brak uwierzytelniania.
Zwraca kanoniczną listę obsługiwanych języków (kod, nazwa wyświetlana, flaga RTL). Jest 36 wpisów; kody są jedynymi wartościami akceptowanymi w targets na punktach końcowych tłumaczenia.
Odpowiedź 200
{
"languages": [
{ "code": "en", "name": "English", "rtl": false },
{ "code": "ar", "name": "Arabic", "rtl": true }
]
}
Źródło: api/utils/languages.js.
POST /translate
Wymaga Authorization: Bearer <api_key>.
Tłumaczy pojedynczy ciąg content na każdy język wymieniony w targets. Model zwraca pojedynczy obiekt JSON, którego klucze są dokładnie żądanymi kodami języków, a wartości to przetłumaczone ciągi (patrz formatPrompts.js).
Treść żądania
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
content | string | Tak | Niepusty ciąg do przetłumaczenia |
targets | string[] | Tak | Niepusta tablica prawidłowych kodów języków (maks. 36) |
format | string | Nie | Jeden z plain, markdown, json, html. Jeśli pominięty, format jest automatycznie wykrywany na podstawie content. |
source | string | Nie | Wskazówka dotycząca języka źródłowego dla modelu; opcjonalne |
model | string | Nie | standard (domyślny) lub advanced. advanced wymaga płatnego poziomu (403 dla darmowego). |
Odpowiedź 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 i detection_confidence pojawiają się tylko wtedy, gdy format został pominięty i uruchomiono automatyczne wykrywanie.
Przykład (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"]
}'
Przykład (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
Wymaga Authorization: Bearer <api_key>.
Przetwarza każdy element sekwencyjnie (jedno wywołanie modelu na element). Jeśli którykolwiek element się nie powiedzie, API zwraca 500 i nie zwraca częściowych wyników dla tego żądania.
Treść żądania
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
items | array | Tak | Każdy element: id (string), content (string), opcjonalnie format. |
targets | string[] | Tak | Te same zasady co w /translate. |
source | string | Nie | Opcjonalna wskazówka języka źródłowego. |
model | string | Nie | standard lub advanced (te same zasady co w /translate). |
Odpowiedź 200
{
"results": [
{ "id": "welcome", "translations": { "fr": "...", "de": "..." } },
{ "id": "goodbye", "translations": { "fr": "...", "de": "..." } }
],
"usage": {
"total_tokens": 900,
"input_tokens": 400,
"output_tokens": 500,
"model": "standard"
}
}
Przykład
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
Wymaga Authorization: Bearer <api_key>.
Umieszcza zadanie tłumaczenia w kolejce i zwraca natychmiast job_id. Tłumaczenie odbywa się w tle — brak ryzyka przekroczenia limitu czasu HTTP niezależnie od rozmiaru zawartości. Polluj GET /jobs/:id po wynik.
Użyj tego punktu końcowego zamiast POST /translate podczas tłumaczenia dużych dokumentów (długi Markdown, wiele języków docelowych), gdzie czas trwania żądania może przekroczyć limit czasu klienta HTTP lub proxy.
Treść żądania
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
content | string | Tak | Niepusty ciąg do przetłumaczenia |
targets | string[] | Tak | Niepusta tablica prawidłowych kodów języków (maks. 36) |
format | string | Nie | Jeden z plain, markdown, json, html. Automatycznie wykrywany, jeśli pominięty. |
source | string | Nie | Wskazówka języka źródłowego; opcjonalne. |
model | string | Nie | standard (domyślny) lub advanced. |
Odpowiedź 202
{
"job_id": "a1b2c3d4-...",
"status": "pending",
"created_at": "2025-03-23T12:00:00.000Z"
}
GET /jobs/:id
Wymaga Authorization: Bearer <api_key>.
Polluje status zadania przesłanego przez POST /jobs. Polluj co 5–10 sekund. Zadania należą do użytkownika, który je przesłał — inni użytkownicy otrzymują 404.
Odpowiedź (oczekujące / przetwarzanie)
{
"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 to pending (oczekuje na pracownika) lub processing (pracownik przejął zadanie). queue_position (indeksowany od 1) to liczba oczekujących lub przetwarzanych zadań utworzonych ściśle przed tym — użyj tego do UI postępu. Pomijane, gdy zapytanie o liczbę się nie powiedzie.
Odpowiedź (ukończone)
{
"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"
}
}
Odpowiedź (niepowodzenie)
{
"job_id": "a1b2c3d4-...",
"status": "failed",
"error": "Model returned invalid JSON"
}
Przykład (JavaScript)
const API = 'https://api.usepolylingo.com/v1'
const headers = {
'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
'Content-Type': 'application/json',
}
// 1. Prześlij
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. Poll
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) }
// Opcjonalnie: pokaż postęp (queue_position jest indeksowane od 1, pomijane gdy nie w kolejce)
if (job.queue_position != null) console.log(`Queue position: ${job.queue_position}`)
}
GET /usage
Wymaga Authorization: Bearer <api_key> (standardowe wyszukiwanie klucza — nie wewnętrzna ścieżka omijająca).
Zwraca użycie tokenów za bieżący miesiąc kalendarzowy dla uwierzytelnionego użytkownika.
Odpowiedź 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 i tokens_remaining są null dla enterprise (nieograniczony przydział w raportowaniu).
Formaty treści
Obsługiwane wartości format: plain, markdown, json, html.
| Format | Zachowane | Przetłumaczone |
|---|---|---|
plain | Złamania linii / akapity | Cały widoczny tekst |
markdown | Składnia, linki (URL bez zmian), fenced code (dosłownie) | Proza i tekst linków |
json | Klucze, struktura, typy niebędące stringami | Tylko wartości stringowe |
html | Tag-i i atrybuty | Węzły tekstowe i odpowiednie atrybuty (patrz podpowiedzi) |
RTL i kierunek w Twojej aplikacji
Dla wyjścia plain i markdown API zwraca tylko przetłumaczony tekst — nie dodaje dir="rtl" ani elementów opakowujących. Ustaw kierunek tekstu w UI (CSS direction, atrybut dir elementu nadrzędnego lub układ i18n Twojego frameworka) podczas wyświetlania języka arabskiego, hebrajskiego lub perskiego.
Dla formatu html przetłumaczony markup może zawierać dir="rtl" tam, gdzie jest to odpowiednie dla celów RTL; zobacz formatPrompts.js oraz testy HTML w scripts/test-translation.js.
Odpowiedzi błędów
Błędy są w formacie JSON, jeśli to możliwe:
{
"error": "invalid_request",
"message": "Szczegóły czytelne dla człowieka"
}
| HTTP | error | Kiedy |
|---|---|---|
| 400 | invalid_request | Brakujące/nieprawidłowe pola w ciele (np. puste content, złe targets) |
| 400 | invalid_format | format nie jest w obsługiwanym zestawie |
| 400 | invalid_language | Nieznany kod w targets |
| 401 | invalid_api_key | Brakujący/błędny Authorization, nieznany klucz, cofnięty klucz |
| 403 | advanced_not_available | model: "advanced" na darmowym poziomie |
| 429 | token_limit_reached | Miesięczny limit darmowego poziomu zostałby przekroczony (wstępna kontrola) |
| 429 | rate_limit_reached | Limit RPM na minutę (gdy Redis jest włączony) |
| 500 | translation_error | Błąd modelu/sieci; bezpieczne do ponownego wywołania |
| 404 | not_found | GET /jobs/:id — zadanie nie istnieje lub należy do innego użytkownika |
| 500 | server_error | POST /jobs — nie udało się dodać do kolejki; bezpieczne do ponownego wywołania |
GET /usage może zwrócić 500 z ogólnym komunikatem, jeśli zapytanie Supabase się nie powiedzie.
Podstawowe modele (informacyjnie)
API udostępnia tylko standard i advanced. Faktyczne identyfikatory modeli OpenAI są skonfigurowane w api/utils/modelRouter.js i nie są zwracane w odpowiedziach API.