API បកប្រែឯកសារដោយ AI តាមបែបបង់ប្រាក់ជាមុនសម្រាប់អ្នកអភិវឌ្ឍន៍ — ផ្ទុកឡើង PDF តាមដានការងារ រួចទាញយក PDF ដែលបកប្រែរួចគ្មានរូបសញ្ញាទឹក។
API បកប្រែឯកសាររបស់ InKhmer បកប្រែឯកសារ PDF រវាងខ្មែរ និងអង់គ្លេស (និងគូភាសាផ្សេងទៀតដែលគាំទ្រ) ដោយម៉ាស៊ីនដដែលដែលដំណើរការឧបករណ៍បកប្រែលើគេហទំព័រ inkhmer.com។ វាជាប្រព័ន្ធបង់ប្រាក់ជាមុន៖ ការងារនីមួយៗកាត់ក្រេឌីតពីកាបូប InKhmer របស់អ្នកនៅពេលបង្កើតការងារ ហើយក្រេឌីតដែលមិនបានប្រើត្រូវបានសងវិញដោយស្វ័យប្រវត្តិ ប្រសិនបើការងារបរាជ័យ ឬត្រូវបានបោះបង់មុនពេលបញ្ចប់។
Base URL: https://api.inkhmer.com/v1/public/document-translator
បង្កើតការងារដោយ multipart POST មួយ តាមដានរហូតស្ថានភាពឈានដល់ done រួចទាញយក PDF។ ជំនួស sk_test_… ដោយកូនសោរបស់អ្នក និង contract.pdf ដោយឯកសាររបស់អ្នក។
# Create a job
curl -X POST https://api.inkhmer.com/v1/public/document-translator/jobs \
-H "Authorization: Bearer $INKHMER_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-F "file=@contract.pdf" \
-F "source=auto" \
-F "target=km"
# → 202 { "jobId": "019a…", "pagesTotal": 72, "tier": "t4",
# "priceCredits": 999, "walletAfter": 1301,
# "pollUrl": "/v1/public/document-translator/jobs/019a…" }
# Poll until done / error / cancelled (~every 2 s)
JOB_ID=019a… # from the 202 response
while :; do
STATE=$(curl -s https://api.inkhmer.com/v1/public/document-translator/jobs/$JOB_ID \
-H "Authorization: Bearer $INKHMER_KEY" | jq -r .state)
echo "$STATE"
[ "$STATE" = done ] && break
[ "$STATE" = error ] && exit 1
[ "$STATE" = cancelled ] && exit 1
sleep 2
done
# Download the watermark-free PDF
curl -o translation.pdf https://api.inkhmer.com/v1/public/document-translator/jobs/$JOB_ID/pdf \
-H "Authorization: Bearer $INKHMER_KEY"// Requires Node 18+ (global fetch / FormData / Blob).
import { randomUUID } from 'node:crypto';
import fs from 'node:fs';
const BASE = 'https://api.inkhmer.com/v1/public/document-translator';
const ORIGIN = 'https://api.inkhmer.com';
const KEY = process.env.INKHMER_KEY; // sk_test_… / sk_live_…
const headers = { Authorization: `Bearer ${KEY}` };
// 1. Create the job (multipart upload)
const form = new FormData();
form.append('file', new Blob([fs.readFileSync('contract.pdf')]), 'contract.pdf');
form.append('source', 'auto');
form.append('target', 'km');
const created = await fetch(`${BASE}/jobs`, {
method: 'POST',
headers: { ...headers, 'Idempotency-Key': randomUUID() },
body: form,
}).then((r) => r.json());
// 2. Poll the job (~every 2 s) until a terminal state.
// created.pollUrl is the relative /v1/… path from the 202 response.
while (true) {
const job = await fetch(`${ORIGIN}${created.pollUrl}`, { headers })
.then((r) => r.json());
if (job.state === 'done') break;
if (job.state === 'error' || job.state === 'cancelled')
throw new Error(`job ${job.state}: ${job.error}`);
await new Promise((r) => setTimeout(r, 2000));
}
// 3. Download the watermark-free PDF
const pdf = await fetch(`${BASE}/jobs/${created.jobId}/pdf`, { headers });
fs.writeFileSync('translation.pdf', Buffer.from(await pdf.arrayBuffer()));import os, time, uuid
import requests
BASE = 'https://api.inkhmer.com/v1/public/document-translator'
KEY = os.environ['INKHMER_KEY'] # sk_test_… / sk_live_…
HEADERS = {'Authorization': f'Bearer {KEY}'}
# 1. Create the job (multipart upload)
with open('contract.pdf', 'rb') as f:
created = requests.post(
f'{BASE}/jobs',
headers={**HEADERS, 'Idempotency-Key': str(uuid.uuid4())},
files={'file': ('contract.pdf', f, 'application/pdf')},
data={'source': 'auto', 'target': 'km'},
).json()
# 2. Poll the job (~every 2 s) until a terminal state
while True:
job = requests.get(
f"{BASE}/jobs/{created['jobId']}", headers=HEADERS
).json()
if job['state'] == 'done':
break
if job['state'] in ('error', 'cancelled'):
raise RuntimeError(f"job {job['state']}: {job['error']}")
time.sleep(2)
# 3. Download the watermark-free PDF
pdf = requests.get(
f"{BASE}/jobs/{created['jobId']}/pdf", headers=HEADERS
)
with open('translation.pdf', 'wb') as f:
f.write(pdf.content)ការងារដែលមានទំហំលើស ~20 MiB គួរប្រើលំហូរ direct-to-storage ជំនួស៖ POST /jobs/intent ដើម្បីយក URL ផ្ទុកឡើង presigned បញ្ជូន bytes ដោយ PUT រួច POST /jobs/{jobId}/finalize។ មើលផ្នែកឯកសារយោងសម្រាប់លំហូរទាំងពីរ។
ការងារត្រូវបូកជាក្រេឌីតកាបូបតាមក្រុមទំព័រ — ក្រុមតម្លៃដដែលនឹងឧបករណ៍លើ inkhmer.com។ ១ ក្រេឌីត = $០.០១ USD។ តម្លៃត្រូវបានបញ្ជាក់នៅពេលបង្កើតការងារ ហើយកាត់មុនពេលបកប្រែចាប់ផ្តើម; ក្រេឌីតដែលមិនបានប្រើពីការងារបរាជ័យ ឬបោះបង់ ត្រូវបានសងវិញដោយស្វ័យប្រវត្តិ។
| Pages | Credits | USD | KHR |
|---|---|---|---|
| 1–5 | 99 | $0.99 | 20,000 ៛ |
| 6–20 | 199 | $1.99 | 40,000 ៛ |
| 21–50 | 499 | $4.99 | 100,000 ៛ |
| 51–100 | 999 | $9.99 | 200,000 ៛ |
| 101–200 | 1,999 | $19.99 | 400,000 ៛ |
| 201–500 | 3,999 | $39.99 | 800,000 ៛ |
| 501–1,000 | 7,999 | $79.99 | 1,600,000 ៛ |
| 1,001+ | — | — | — |
លើសពី ១,០០០ ទំព័រក្នុងមួយឯកសារ? ទាក់ទងមកយើងសម្រាប់សម្រង់តម្លៃផ្ទាល់ខ្លួន។
សំណើរនីមួយៗដឹកកូនសោ TosKey API ក្នុង header Authorization: Bearer។ ចេញកូនសោនៅ TosKey Console ផ្នែក InKhmer (S5) — កូនសោថ្មីជ្រើស scopes translator ទាំងបីដោយស្វ័យប្រវត្តិ។
Authorization: Bearer sk_live_…
# scopes: translator:translate | translator:read | translator:canceltranslator:translate — បង្កើតការងារ បង្កើត upload intent និង finalize ការផ្ទុកឡើង។translator:read — តាមដានស្ថានភាពការងារ និងទាញយក PDF។translator:cancel — បោះបង់ការងារកំពុងដំណើរការ និងសងក្រេឌីតទំព័រដែលមិនទាន់បកប្រែ។translator:* — wildcard គ្របដណ្តប់ទាំងបី; ត្រូវបានជ្រើសជាលំនាំដើមលើកូនសោថ្មី។TosKey gateway អនុវត្តដែនកំណត់ក្នុងមួយកូនសោមុនពេលសំណើរឈានដល់ API។ ចម្លើយនីមួយៗមាន X-RateLimit-Limit / -Remaining / -Reset ហើយនៅពេល 429 មាន Retry-After ប្រាប់ចំនួនវិនាទីត្រូវរង់ចាំ។
| Endpoint | Scope | Per minute | Per hour | Per day |
|---|---|---|---|---|
| POST /v1/public/document-translator/jobs | translator:translate | 10 | 100 | 1000 |
| POST /v1/public/document-translator/jobs/intent | translator:translate | 10 | 100 | 1000 |
| GET /v1/public/document-translator/jobs/{jobId} | translator:read | 60 | — | — |
| POST /v1/public/document-translator/jobs/{jobId}/finalize | translator:translate | 10 | 100 | 1000 |
| GET /v1/public/document-translator/jobs/{jobId}/pdf | translator:read | 10 | — | — |
| GET /v1/public/document-translator/jobs/{jobId}/pdf-url | translator:read | 10 | — | — |
| POST /v1/public/document-translator/jobs/{jobId}/cancel | translator:cancel | 10 | — | — |
50 req/min — កូនសោទាំងអស់របស់អត្តសញ្ញាណតែមួយចែករំលែកដែនកំណត់ burst កម្រិតគណនី ៥០ សំណើ/នាទី — សំណើទី ៥១ ក្នុងមួយនាទីត្រូវបដិសេធនៅ gateway។
pro-translator-rate pro-translator-rate លើកដែនកំណត់សរសេរទៅ ១០០/នាទី · ១,០០០/ម៉ោង · ១០,០០០/ថ្ងៃ ក្នុងមួយកូនសោ។ វាត្រូវបានកំណត់ដោយប្រតិបត្តិករក្នុង TosKey Console — ទាក់ទងមកយើងដើម្បីស្នើសុំ; វាមិនមែន self-serve ទេ។
អាន X-RateLimit-Remaining ដើម្បីបន្ថយល្បឿនមុនពេលឈប់ ហើយគោរព Retry-After លើចម្លើយ 429។ X-RateLimit-LimitX-RateLimit-RemainingX-RateLimit-ResetRetry-After
ប្រតិបត្តិការនីមួយៗខាងក្រោមត្រូវបានបង្ហាញពីឯកសារ OpenAPI ផ្ទាល់ — request/response body, parameter និងឧទាហរណ៍កំហុសពិតប្រាកដដែល API ត្រឡប់មក។
idempotency-key — ប្រតិបត្តិការផ្លាស់ប្តូរទទួល header Idempotency-Key។ ការហៅឡើងវិញដោយកូនសោដដែលក្នុងរយៈពេល ២៤ ម៉ោង ត្រឡប់ចម្លើយដើមដោយមិនកាត់ក្រេឌីតពីរដង។
v1 គ្មាន webhooks ទេ — សូមហៅ GET /jobs/{jobId} រៀងរាល់ ~២ វិនាទី រហូតស្ថានភាពជា done, error ឬ cancelled។ webhook job.done ស្ថិតក្នុងផែនទីផ្លូវ។
ពេលវេលារបស់ pipeline ឡើងចុះតាមចំនួនទំព័រ និងថាតើឯកសារត្រូវការ OCR ឬអត់។ PDF ឌីជីថលស្អាតជាមធ្យមចំណាយពីរបីវិនាទីក្នុងមួយទំព័រ; ទំព័រស្កេនយូរជាងនេះ ព្រោះទំព័រនីមួយៗឆ្លងកាត់ OCR មុនបកប្រែ។ ឯកសារឌីជីថល ៥០ ទំព័រជាធម្មតាបញ្ចប់ក្នុងរយៈពេលពីរបីនាទី។ តាមដានការងាររៀងរាល់ពីរវិនាទី — ស្ថានភាពផ្លាស់ uploading → detecting → translating → rendering → done ហើយ pagesDone ប្រាប់វឌ្ឍនភាពពិត។ ឯកសារវែង (៥០០+ ទំព័រ) អាចចំណាយដល់ដប់ប្រាំនាទី ឬច្រើនជាង; សូមបន្ថយប្រេកង់ហៅនៅពេលឆ្លងផុតនាទីដំបូង។
មិនទាន់បានក្នុង v1 ទេ។ API ទទួលតែ bytes ឯកសារប៉ុណ្ណោះ — មេរៀន multipart POST /jobs ឬលំហូរ intent/finalize ទៅ storage ដោយផ្ទាល់សម្រាប់ឯកសារធំ។ ការទាញឯកសារពី URL ដែលអ្នកប្រើផ្តល់ ជាធាតុផែនទីផ្លូវដែលយើងកំពុងតាមដាន ព្រោះវាលើកសំណួរ SSRF និងប្រភពដែលយើងចង់ដោះស្រាយឱ្យត្រឹមត្រូវជាមុន។ ឥឡូវនេះ សូមទាញឯកសារពីខាងអ្នក រួច POST bytes មកយើង។
PDF ប៉ុណ្ណោះក្នុង v1 — ដែនកំណត់ដដែលនឹងឧបករណ៍គេហទំព័រ។ ទាំង PDF ឌីជីថល និង PDF ស្កេន ដំណើរការបាន; ទំព័រស្កេនត្រូវបានរកឃើញដោយស្វ័យប្រវត្តិ រួចបញ្ជូនឆ្លងកាត់ OCR។ Word (.docx) និងការផ្ទុករូបភាព ស្ថិតក្នុងផែនទីផ្លូវ។ ប្រសិនបើប្រភពរបស់អ្នកជារូបភាព សូមវេចខ្ចប់ជា PDF ពីខាងអ្នកជាមុន — រូបភាពមួយក្នុងមួយទំព័រ នៅ DPI សមរម្យ ផ្តល់លទ្ធផល OCR ល្អបំផុត។
ចំនួនទំព័រដែលរកឃើញនៅពេលបង្កើតការងារ — ចំនួនទំព័រ PDF មិនមែនចំនួនទំព័រដែលមានអត្ថបទទេ។ តម្លៃត្រូវបានបញ្ជាក់ពីតារាងក្រុមមុនការកាត់ ដូច្នេះ POST /jobs តែងតែប្រាប់ pagesTotal, tier, priceCredits និងសមតុល្យ walletAfter របស់អ្នកជាមុន។ ប្រសិនបើម៉ាស៊ីនរកឃើញទំព័រលើសដែនកំណត់ ១,០០០ ការងារត្រូវបដិសេធដោយ payload_too_large មុនការកាត់ណាមួយ។
ក្រេឌីតត្រូវបានសងវិញដោយស្វ័យប្រវត្តិ។ ការបរាជ័យ internal_error ឬ upstream_unavailable សងការកាត់ពេញលេញ; ការបោះបង់ការងារកំពុងដំណើរការ សងទំព័រដែលមិនទាន់បកប្រែ (សមាមាត្រទល់នឹង pagesDone)។ ការសងចូលកាបូបដដែល — គ្មានត្រូវការ ticket គាំទ្រទេ។ អ្នកអាចផ្ទៀងផ្ទាត់ការសងលើការងារខ្លួនឯង៖ POST /jobs/{jobId}/cancel រាយការណ៍ refundedCredits ហើយទំព័រវិក្កយបត្ររបស់អ្នកបង្ហាញការកត់ត្រា ledger។
បាទ — PDF ស្កេនត្រូវបានរកឃើញក្នុងដំណាក់កាល detecting ហើយទំព័រនីមួយៗឆ្លងកាត់ OCR មុនបកប្រែ។ អ្នកមិនចាំបាច់សម្គាល់ថាឯកសារជាស្កេនទេ។ គុណភាព OCR អាស្រ័យលើគុណភាពស្កេន៖ ស្កេន 300 DPI ច្បាស់បកប្រែល្អ ខណៈរូបថតទូរស័ព្ទពិលទំព័រ contrast ទាប អាចផ្តល់អត្ថបទប្រភពខូច។ ប្រសិនបើ pagesDone នៅស្ងៀម ឬ error រាយការណ៍ការបរាជ័យ OCR សូមស្កេនម្តងទៀតនៅកម្រិតខ្ពស់ជាង រួចដាក់ស្នើឡើងវិញ។
v1 ទទួលតែ PDF — គ្មាន endpoint រូបភាពទេ។ ប្រសិនបើអ្នកមានរូបភាពឯករាជ្យ (ស្កេន JPG/PNG ឬរូបថតទូរស័ព្ទ) សូមវេចខ្ចប់ជា PDF ជាមុន៖ វេទិកាភាគច្រើនអាច print-to-PDF ឬប្រើបណ្ណាល័យតូចមួយ (img2pdf ក្នុង Python, pdf-lib ក្នុង Node)។ ដាក់រូបភាពនីមួយៗនៅទំព័រផ្ទាល់ខ្លួន តាមលំដាប់អាន រួច pipeline OCR ដោះស្រាយវាដូចឯកសារស្កេនផ្សេងៗ។
ឯកសារត្រូវបានរក្សាទុករយៈពេលអប្បបរមាដែលត្រូវការដើម្បីបម្រើលទ្ធផល។ ឯកសារដើមដែលបានផ្ទុកឡើង ត្រូវបានលុបក្រោយ ២៤ ម៉ោង; PDF ដែលបកប្រែអាចទាញយកបាន ៧ ថ្ងៃ រួចត្រូវបានលុប។ អត្ថបទឯកសារមិនដែលត្រូវបានសរសេរទៅក្នុង logs កម្មវិធីទេ — មានតែ metadata ការងារ (ចំនួនទំព័រ ស្ថានភាព កូដកំហុស) ត្រូវបានកត់ត្រា។ សូមទាញយកលទ្ធផលក្នុងរយៈពេល ៧ ថ្ងៃ; បន្ទាប់ពីនោះ មានតែការងារថ្មីទើបបង្កើតវាឡើងវិញបាន។
gateway ឆ្លើយតប 429 ជាមួយ Retry-After (វិនាទីត្រូវរង់ចាំ) ហើយ header X-RateLimit-* លើចម្លើយនីមួយៗបង្ហាញថវិកាដែលនៅសល់។ ធុងពីរអនុវត្ត៖ ដែនកំណត់ក្នុងមួយកូនសោក្នុងមួយ endpoint និង burst គណនី ៥០ សំណើ/នាទី ចែករំលែកដោយកូនសោទាំងអស់របស់អ្នក។ បន្ថយល្បឿនតាម Retry-After រួច retry — សំណើមិនដែលឈានដល់ API ទេ ដូច្នេះគ្មានអ្វីត្រូវកាត់។ សម្រាប់បរិមាណខ្ពស់ជាប់លាប់ សូមសួរអំពីកម្រិត pro-translator-rate ដែលប្រតិបត្តិករកំណត់។
កូនសោមួយក្នុងមួយកម្មវិធី ឬបរិយាកាស គឺជាលំនាំងដែលគួរប្រើ — កូនសោ live និងកូនសោ test យ៉ាងតិច។ ដែនកំណត់ក្នុងមួយកូនសោមានន័យថាកម្មវិធីដាច់ដោយឡែកមិនធ្វើឱ្យគ្នាអត់ឃ្លាន ហើយការលុបកូនសោដែលលេចធ្លាយ មិនបំបែក integration ផ្សេងទៀតរបស់អ្នក។ កូនសោទាំងអស់បូករួមក្រោមអត្តសញ្ញាណរបស់អ្នកសម្រាប់ burst គណនី ៥០/នាទី និងសម្រាប់វិក្កយបត្រ — ក្រេឌីតមកពីកាបូបតែមួយ ទោះកូនសោណាបានចំណាយក៏ដោយ។
ការប្រើប្រាស់ API មានន័យថាអ្នកទទួលយកលក្ខខណ្ឌ API របស់ InKhmer — ការប្រើប្រាស់ដែលទទួលយកបាន ការរក្សាទុក និងការអនុវត្តដែនកំណត់អត្រា។ អានលក្ខខណ្ឌ API