Αναφορά 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).
Σώμα αιτήματος
| Πεδίο | Τύπος | Υποχρεωτικό | Περιγραφή |
|---|---|---|---|
content | string | Ναι | Μη κενή συμβολοσειρά προς μετάφραση. |
targets | string[] | Ναι | Μη κενός πίνακας έγκυρων κωδικών γλωσσών (μέγ. 36). |
format | string | Όχι | Ένα από plain, markdown, json, html. Αν παραληφθεί, το format ανιχνεύεται αυτόματα από το content. |
source | string | Όχι | Υπόδειξη γλώσσας πηγής για το μοντέλο· προαιρετικό. |
model | string | Όχι | 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 και δεν επιστρέφει μερικά αποτελέσματα για το αίτημα.
Σώμα αιτήματος
| Πεδίο | Τύπος | Υποχρεωτικό | Περιγραφή |
|---|---|---|---|
items | array | Ναι | Κάθε στοιχείο: id (string), content (string), προαιρετικό format. |
targets | string[] | Ναι | Ίδιες κανόνες με /translate. |
source | string | Όχι | Προαιρετική υπόδειξη γλώσσας πηγής. |
model | string | Όχι | 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.
Σώμα αιτήματος
| Πεδίο | Τύπος | Υποχρεωτικό | Περιγραφή |
|---|---|---|---|
content | string | Ναι | Μη κενή συμβολοσειρά προς μετάφραση. |
targets | string[] | Ναι | Μη κενός πίνακας έγκυρων κωδικών γλωσσών (μέγ. 36). |
format | string | Όχι | Ένα από plain, markdown, json, html. Ανιχνεύεται αυτόματα αν παραληφθεί. |
source | string | Όχι | Υπόδειξη γλώσσας πηγής· προαιρετικό. |
model | string | Όχι | 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": "Ανθρώπινα αναγνώσιμη λεπτομέρεια"
}
| HTTP | error | Πότε |
|---|---|---|
| 400 | invalid_request | Ελλείποντα/μη έγκυρα πεδία σώματος (π.χ. κενό content, κακά targets) |
| 400 | invalid_format | Το format δεν είναι στο υποστηριζόμενο σύνολο |
| 400 | invalid_language | Άγνωστος κωδικός στο targets |
| 401 | invalid_api_key | Ελλείπον/λανθασμένο Authorization, άγνωστο κλειδί, ανακληθέν κλειδί |
| 403 | advanced_not_available | model: "advanced" στο δωρεάν επίπεδο |
| 429 | token_limit_reached | Το μηνιαίο όριο δωρεάν επιπέδου θα ξεπεραστεί (προέλεγχος) |
| 429 | rate_limit_reached | Όριο RPM ανά λεπτό (όταν το Redis είναι ενεργοποιημένο) |
| 500 | translation_error | Σφάλμα μοντέλου/δικτύου; ασφαλές για επανάληψη |
| 404 | not_found | GET /jobs/:id — η εργασία δεν υπάρχει ή ανήκει σε άλλον χρήστη |
| 500 | server_error | POST /jobs — αποτυχία τοποθέτησης σε ουρά; ασφαλές για επανάληψη |
Το GET /usage μπορεί να επιστρέψει 500 με γενικό μήνυμα αν αποτύχει το ερώτημα Supabase.
Υποκείμενα μοντέλα (πληροφοριακά)
Το API εκθέτει μόνο standard και advanced. Τα πραγματικά IDs μοντέλων OpenAI ρυθμίζονται στο api/utils/modelRouter.js και δεν επιστρέφονται στις απαντήσεις API.