Αναφορά API

Αυτό το έγγραφο ταιριάζει με τη συμπεριφορά της εφαρμογής Express στο api/app.js και τους χειριστές διαδρομών κάτω από το api/routes/.

Όρια και συμπεριφορά

ΣτοιχείοΤιμή
Μέγεθος σώματος JSONΈως 2 MB (express.json({ limit: '2mb' }))
Στόχοι ανά αίτημα1–36 κωδικοί γλωσσών
Αντικείμενα παρτίδας1–100 αντικείμενα ανά αίτημα παρτίδας
Μοντέλαstandard (προεπιλογή) ή advanced (μόνο επί πληρωμή; δείτε παρακάτω)

Μηνιαίο όριο διακριτικών (δωρεάν επίπεδο): Πριν από την κλήση του μοντέλου, το API εκτιμά τα διακριτικά περίπου ως ceil(content_length / 4) × (number_of_targets + 1) και, μόνο για το επίπεδο free, απορρίπτει το αίτημα με 429 / token_limit_reached αν η εκτίμηση υπερβαίνει το υπόλοιπο μηνιαίο όριο (FREE_TIER_MONTHLY_TOKENS, προεπιλογή 100000). Τα επί πληρωμή επίπεδα δεν μπλοκάρονται από αυτόν τον προέλεγχο στο enforceTokenCap; η χρήση καταγράφεται κανονικά.

Όρια ρυθμού: Όταν έχει ρυθμιστεί το Upstash Redis (UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN, και το URL δεν περιέχει το placeholder your-instance), εφαρμόζονται όρια ανά λεπτό ανά επίπεδο: δωρεάν 5, starter 30, growth 60, scale 120, enterprise απεριόριστο. Σε όριο, η απόκριση είναι 429 με error: "rate_limit_reached". Αν το Redis δεν έχει ρυθμιστεί, ο περιορισμός ρυθμού παραλείπεται (βλέπε rateLimit.js).

Επιτυχείς απαντήσεις με περιορισμό ρυθμού μπορεί να περιλαμβάνουν X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.


GET /health

Χωρίς αυθεντικοποίηση.

Απάντηση 200

{
  "status": "ok",
  "timestamp": "2025-03-23T12:00:00.000Z"
}

GET /languages

Χωρίς αυθεντικοποίηση.

Επιστρέφει τη κανονική λίστα υποστηριζόμενων γλωσσών (κωδικός, εμφανιζόμενο όνομα, σημαία RTL). Υπάρχουν 36 εγγραφές· οι κωδικοί είναι οι μόνοι αποδεκτοί τιμές στο targets στα endpoints μετάφρασης.

Απάντηση 200

{
  "languages": [
    { "code": "en", "name": "English", "rtl": false },
    { "code": "ar", "name": "Arabic", "rtl": true }
  ]
}

Πηγή: api/utils/languages.js.


POST /translate

Απαιτεί Authorization: Bearer <api_key>.

Μεταφράζει ένα μόνο string content σε κάθε γλώσσα που αναφέρεται στο targets. Το μοντέλο επιστρέφει ένα μόνο αντικείμενο JSON των οποίων τα κλειδιά είναι ακριβώς οι ζητούμενοι κωδικοί γλωσσών και οι τιμές είναι οι μεταφρασμένες συμβολοσειρές (βλέπε formatPrompts.js).

Σώμα αιτήματος

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
contentstringΝαιΜη κενή συμβολοσειρά προς μετάφραση.
targetsstring[]ΝαιΜη κενός πίνακας έγκυρων κωδικών γλωσσών (μέγ. 36).
formatstringΌχιΈνα από plain, markdown, json, html. Αν παραληφθεί, το format ανιχνεύεται αυτόματα από το content.
sourcestringΌχιΥπόδειξη γλώσσας πηγής για το μοντέλο· προαιρετικό.
modelstringΌχιstandard (προεπιλογή) ή advanced. Το advanced απαιτεί επί πληρωμή επίπεδο (403 στο δωρεάν).

Απάντηση 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 και το detection_confidence εμφανίζονται μόνο όταν το format παραλήφθηκε και εκτελέστηκε αυτόματη ανίχνευση.

Παράδειγμα (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"]
  }'

Παράδειγμα (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

Απαιτεί Authorization: Bearer <api_key>.

Επεξεργάζεται κάθε στοιχείο διαδοχικά (μία κλήση μοντέλου ανά στοιχείο). Αν κάποιο στοιχείο αποτύχει, το API επιστρέφει 500 και δεν επιστρέφει μερικά αποτελέσματα για το αίτημα.

Σώμα αιτήματος

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
itemsarrayΝαιΚάθε στοιχείο: id (string), content (string), προαιρετικό format.
targetsstring[]ΝαιΊδιες κανόνες με /translate.
sourcestringΌχιΠροαιρετική υπόδειξη γλώσσας πηγής.
modelstringΌχιstandard ή advanced (ίδιοι κανόνες με /translate).

Απάντηση 200

{
  "results": [
    { "id": "welcome", "translations": { "fr": "...", "de": "..." } },
    { "id": "goodbye", "translations": { "fr": "...", "de": "..." } }
  ],
  "usage": {
    "total_tokens": 900,
    "input_tokens": 400,
    "output_tokens": 500,
    "model": "standard"
  }
}

Παράδειγμα

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

Απαιτεί Authorization: Bearer <api_key>.

Τοποθετεί σε ουρά μια εργασία μετάφρασης και επιστρέφει αμέσως με job_id. Η μετάφραση εκτελείται στο παρασκήνιο — χωρίς κίνδυνο χρονικού ορίου HTTP ανεξαρτήτως μεγέθους περιεχομένου. Κάντε polling στο GET /jobs/:id για το αποτέλεσμα.

Χρησιμοποιήστε αυτό το endpoint αντί για POST /translate όταν μεταφράζετε μεγάλα έγγραφα (μεγάλο Markdown, πολλές γλώσσες στόχοι) όπου η διάρκεια του αιτήματος μπορεί να υπερβεί το χρονικό όριο του HTTP client ή proxy.

Σώμα αιτήματος

ΠεδίοΤύποςΥποχρεωτικόΠεριγραφή
contentstringΝαιΜη κενή συμβολοσειρά προς μετάφραση.
targetsstring[]ΝαιΜη κενός πίνακας έγκυρων κωδικών γλωσσών (μέγ. 36).
formatstringΌχιΈνα από plain, markdown, json, html. Ανιχνεύεται αυτόματα αν παραληφθεί.
sourcestringΌχιΥπόδειξη γλώσσας πηγής· προαιρετικό.
modelstringΌχιstandard (προεπιλογή) ή advanced.

Απάντηση 202

{
  "job_id": "a1b2c3d4-...",
  "status": "pending",
  "created_at": "2025-03-23T12:00:00.000Z"
}

GET /jobs/:id

Απαιτεί Authorization: Bearer <api_key>.

Κάνει polling στην κατάσταση μιας εργασίας που υποβλήθηκε μέσω POST /jobs. Κάντε polling κάθε 5–10 δευτερόλεπτα. Οι εργασίες ανήκουν στον χρήστη που τις υπέβαλε — άλλοι χρήστες λαμβάνουν 404.

Απάντηση (pending / processing)

{
  "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 είναι pending (αναμονή για worker) ή processing (worker το έχει αναλάβει). Το queue_position (βάση 1) δείχνει πόσες εργασίες σε κατάσταση pending ή processing δημιουργήθηκαν αυστηρά πριν από αυτήν — χρησιμοποιήστε το για UI προόδου. Παραλείπεται αν η ερώτηση μέτρησης αποτύχει.

Απάντηση (completed)

{
  "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"
  }
}

Απάντηση (failed)

{
  "job_id": "a1b2c3d4-...",
  "status": "failed",
  "error": "Model returned invalid JSON"
}

Παράδειγμα (JavaScript)

const API = 'https://api.usepolylingo.com/v1'
const headers = {
  'Authorization': `Bearer ${process.env.POLYLINGO_API_KEY}`,
  'Content-Type': 'application/json',
}

// 1. Υποβολή
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) }
  // Προαιρετικό: εμφάνιση προόδου (queue_position είναι βάση 1, παραλείπεται αν δεν είναι σε ουρά)
  if (job.queue_position != null) console.log(`Queue position: ${job.queue_position}`)
}

GET /usage

Απαιτεί Authorization: Bearer <api_key> (τυπική αναζήτηση κλειδιού — όχι η εσωτερική διαδρομή παράκαμψης).

Επιστρέφει χρήση διακριτικών για τον τρέχοντα ημερολογιακό μήνα για τον αυθεντικοποιημένο χρήστη.

Απάντηση 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 και tokens_remaining είναι null για enterprise (απεριόριστο όριο στην αναφορά).


Μορφές περιεχομένου

Υποστηριζόμενες τιμές format: plain, markdown, json, html.

ΜορφήΔιατηρείταιΜεταφράζεται
plainΔιακοπές γραμμής / παράγραφοιΌλο το ορατό κείμενο
markdownΣύνταξη, σύνδεσμοι (URL αμετάβλητο), fenced code (αυστηρά)Κείμενο και κείμενο συνδέσμων
jsonΚλειδιά, δομή, μη-συμβολοσειρές τύποιΜόνο τιμές συμβολοσειρών
htmlΕτικέτες και χαρακτηριστικάΚείμενο και κατάλληλα χαρακτηριστικά (βλέπε prompts)

RTL και κατεύθυνση στην εφαρμογή σας

Για έξοδο plain και markdown, το API επιστρέφει μόνο το μεταφρασμένο κείμενο — δεν προσθέτει dir="rtl" ή περιτυλιγμένα στοιχεία. Ορίστε την κατεύθυνση κειμένου στο UI σας (CSS direction, το dir χαρακτηριστικό γονικού στοιχείου ή το i18n layout του framework σας) όταν εμφανίζετε Αραβικά, Εβραϊκά ή Περσικά.

Για μορφή html, το μεταφρασμένο markup μπορεί να περιλαμβάνει dir="rtl" όπου είναι κατάλληλο για RTL στόχους· δείτε formatPrompts.js και τα HTML tests στο scripts/test-translation.js.


Απαντήσεις σφαλμάτων

Τα σφάλματα είναι JSON όπου είναι δυνατόν:

{
  "error": "invalid_request",
  "message": "Ανθρώπινα αναγνώσιμη λεπτομέρεια"
}
HTTPerrorΠότε
400invalid_requestΕλλείποντα/μη έγκυρα πεδία σώματος (π.χ. κενό content, κακά targets)
400invalid_formatΤο format δεν είναι στο υποστηριζόμενο σύνολο
400invalid_languageΆγνωστος κωδικός στο targets
401invalid_api_keyΕλλείπον/λανθασμένο Authorization, άγνωστο κλειδί, ανακληθέν κλειδί
403advanced_not_availablemodel: "advanced" στο δωρεάν επίπεδο
429token_limit_reachedΤο μηνιαίο όριο δωρεάν επιπέδου θα ξεπεραστεί (προέλεγχος)
429rate_limit_reachedΌριο RPM ανά λεπτό (όταν το Redis είναι ενεργοποιημένο)
500translation_errorΣφάλμα μοντέλου/δικτύου; ασφαλές για επανάληψη
404not_foundGET /jobs/:id — η εργασία δεν υπάρχει ή ανήκει σε άλλον χρήστη
500server_errorPOST /jobs — αποτυχία τοποθέτησης σε ουρά; ασφαλές για επανάληψη

Το GET /usage μπορεί να επιστρέψει 500 με γενικό μήνυμα αν αποτύχει το ερώτημα Supabase.


Υποκείμενα μοντέλα (πληροφοριακά)

Το API εκθέτει μόνο standard και advanced. Τα πραγματικά IDs μοντέλων OpenAI ρυθμίζονται στο api/utils/modelRouter.js και δεν επιστρέφονται στις απαντήσεις API.

Αναφορά API | PolyLingo | PolyLingo