تشغيل عمليات الاستخراج
نظرة عامة
تقبل نقطة نهاية الاستخراج مستنداً (مشفر بـ base64)، وتمرره عبر قالب حددته، وتُرجع بيانات منظمة تطابق متغيرات القالب. استدعاء API واحد يتولى خط الأنابيب بالكامل -- الرفع ومعالجة الذكاء الاصطناعي والمخرجات المنظمة.
جميع طلبات الاستخراج تمر عبر POST /v1/extractions/run.
تحضير مستندك
قبل إرسال مستند إلى API، تحتاج إلى تشفير محتوى الملف بـ base64.
القيود:
- الحد الأقصى لحجم جسم الطلب: 15 ميجابايت
- أنواع MIME المدعومة:
application/pdf(PDF)application/vnd.openxmlformats-officedocument.wordprocessingml.document(DOCX)
# Base64-encode a PDF file
base64 -i invoice.pdf -o invoice_b64.txt
# Or inline (macOS / Linux)
PDF_BASE64=$(base64 -w 0 invoice.pdf)import { readFileSync } from "fs";
const pdfBuffer = readFileSync("invoice.pdf");
const pdfBase64 = pdfBuffer.toString("base64");import base64
with open("invoice.pdf", "rb") as f:
pdf_base64 = base64.b64encode(f.read()).decode("utf-8")WARNING
يزيد تشفير Base64 حجم الملف بنحو 33%. ملف PDF بحجم 10 ميجابايت يصبح حوالي 13.3 ميجابايت بعد التشفير، لذا حافظ على ملفاتك المصدرية أقل من ~11 ميجابايت للبقاء ضمن حد الطلب البالغ 15 ميجابايت.
إجراء الطلب
أرسل طلب POST إلى /v1/extractions/run مع جسم JSON التالي:
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
templateId | string | نعم | معرّف القالب للاستخراج |
fileName | string | نعم | اسم الملف الأصلي (مثال: "invoice.pdf") |
pdfBase64 | string | نعم | محتوى الملف المشفر بـ Base64 |
mimeType | string | نعم | نوع MIME للملف |
runId | string | لا | معرّف اختياري لتجميع عدة عمليات استخراج في دفعة |
curl -X POST https://api.docmap.io/v1/extractions/run \
-H "Authorization: Bearer dm_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"templateId": "tmpl_abc123",
"fileName": "invoice.pdf",
"pdfBase64": "JVBERi0xLjQKJeLj...",
"mimeType": "application/pdf"
}'const response = await fetch("https://api.docmap.io/v1/extractions/run", {
method: "POST",
headers: {
Authorization: "Bearer dm_live_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_abc123",
fileName: "invoice.pdf",
pdfBase64: pdfBase64,
mimeType: "application/pdf",
}),
});
const { data } = await response.json();
console.log(data.extractedData);import requests
response = requests.post(
"https://api.docmap.io/v1/extractions/run",
headers={
"Authorization": "Bearer dm_live_your_api_key",
"Content-Type": "application/json",
},
json={
"templateId": "tmpl_abc123",
"fileName": "invoice.pdf",
"pdfBase64": pdf_base64,
"mimeType": "application/pdf",
},
)
data = response.json()["data"]
print(data["extractedData"])فهم الاستجابة
يُرجع الاستخراج الناجح استجابة مغلفة في كائن data:
{
"data": {
"id": "ext_abc123def456",
"userId": "user_789",
"templateId": "tmpl_abc123",
"templateName": "Invoice Parser",
"fileName": "invoice.pdf",
"status": "completed",
"extractedData": {
"vendor_name": "Acme Corp",
"invoice_number": "INV-2024-001",
"total_amount": 1250.00,
"line_items": [
{ "description": "Widget A", "quantity": 10, "unit_price": 125.00 }
]
},
"error": null,
"variables": [
{ "name": "vendor_name", "type": "string", "description": "Company name of the vendor" },
{ "name": "invoice_number", "type": "string", "description": "Invoice reference number" },
{ "name": "total_amount", "type": "number", "description": "Total invoice amount" },
{ "name": "line_items", "type": "array", "description": "List of line items" }
],
"source": "api",
"runId": null,
"processingTimeMs": 3420,
"createdAt": "2025-07-15T10:30:00.000Z"
}
}| الحقل | الوصف |
|---|---|
id | معرّف الاستخراج الفريد (مسبوق بـ ext_) |
status | "processing" أثناء التشغيل (الوضع غير المتزامن)، "completed" إذا تم استخراج البيانات بنجاح، "failed" إذا واجهت المعالجة خطأ |
extractedData | كائن مفاتيحه تطابق أسماء متغيرات القالب. null إذا فشل الاستخراج |
error | سلسلة رسالة الخطأ إذا فشل الاستخراج. null عند النجاح |
processingTimeMs | الوقت الذي استغرقه الذكاء الاصطناعي لمعالجة المستند، بالمللي ثانية |
source | "api" عند التشغيل عبر مفتاح API، "dashboard" عند التشغيل من واجهة الويب |
variables | تعريفات متغيرات القالب التي استُخدمت لهذا الاستخراج |
runId | معرّف الدفعة الذي قدمته، أو null إذا لم يُحدد |
templateName | اسم القالب المستخدم القابل للقراءة البشرية |
createdAt | طابع زمني ISO 8601 لوقت إنشاء الاستخراج |
TIP
تحقق دائماً من حقل status قبل الوصول إلى extractedData. إذا كان status هو "failed"، فإن حقل error يحتوي على وصف لما حدث خطأ.
عمليات الاستخراج الدفعية
لمعالجة عدة ملفات كدفعة منطقية، مرّر نفس runId لكل طلب استخراج. هذا لا يغير كيفية معالجة المستندات -- يُستخرج كل ملف بشكل مستقل -- لكنه يتيح لك الاستعلام عن جميع النتائج من دفعة معاً.
const runId = "batch-invoices-2025-07";
const files = ["invoice-001.pdf", "invoice-002.pdf", "invoice-003.pdf"];
// Process each file with the same runId
const results = await Promise.all(
files.map(async (fileName) => {
const pdfBase64 = readFileSync(fileName).toString("base64");
const response = await fetch("https://api.docmap.io/v1/extractions/run", {
method: "POST",
headers: {
Authorization: "Bearer dm_live_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_abc123",
fileName,
pdfBase64,
mimeType: "application/pdf",
runId,
}),
});
return response.json();
})
);ثم استرجع جميع عمليات الاستخراج من الدفعة:
curl "https://api.docmap.io/v1/extractions?runId=batch-invoices-2025-07" \
-H "Authorization: Bearer dm_live_your_api_key"const response = await fetch(
"https://api.docmap.io/v1/extractions?runId=batch-invoices-2025-07",
{
headers: { Authorization: "Bearer dm_live_your_api_key" },
}
);
const { data } = await response.json();
console.log(`Batch contains ${data.length} extractions`);response = requests.get(
"https://api.docmap.io/v1/extractions",
params={"runId": "batch-invoices-2025-07"},
headers={"Authorization": "Bearer dm_live_your_api_key"},
)
data = response.json()["data"]
print(f"Batch contains {len(data)} extractions")TIP
تدعم نقطة نهاية القائمة أيضاً التصفية حسب templateId ومعامل limit (1--100، الافتراضي 50). يمكنك دمج المرشحات: ?runId=batch-001&templateId=tmpl_abc123&limit=100.
سير العمل غير المتزامن
بشكل افتراضي، طلبات الاستخراج متزامنة -- تنتظر واجهة API حتى تنتهي المعالجة. لعمليات الاستخراج الطويلة أو عندما تريد تجنب انتهاء مهلة HTTP، استخدم الوضع غير المتزامن بإضافة ?async=true إلى عنوان URL. تُرجع واجهة API فوراً بحالة "processing"، وتستعلم عن نقطة نهاية منفصلة حتى تكون النتيجة جاهزة.
نمط الإرسال + الاستعلام
import { readFileSync } from "fs";
const API_BASE = "https://api.docmap.io";
const API_KEY = process.env.DOCMAP_API_KEY!;
// 1. Submit the extraction asynchronously
const submitResponse = await fetch(`${API_BASE}/v1/extractions/run?async=true`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_abc123",
fileName: "invoice.pdf",
pdfBase64: readFileSync("invoice.pdf").toString("base64"),
mimeType: "application/pdf",
}),
});
const { data: submitted } = await submitResponse.json();
console.log(`Extraction ${submitted.id} submitted, status: ${submitted.status}`);
// 2. Poll until complete
async function poll(extractionId: string): Promise<any> {
for (let i = 0; i < 30; i++) {
const res = await fetch(`${API_BASE}/v1/extractions/${extractionId}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
const { data } = await res.json();
if (data.status !== "processing") return data;
await new Promise((r) => setTimeout(r, 2000));
}
throw new Error("Extraction timed out");
}
const result = await poll(submitted.id);
console.log(`Final status: ${result.status}`);
console.log("Extracted data:", result.extractedData);import base64
import time
import requests
API_BASE = "https://api.docmap.io"
API_KEY = "dm_live_your_api_key"
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
# 1. Submit the extraction asynchronously
with open("invoice.pdf", "rb") as f:
pdf_base64 = base64.b64encode(f.read()).decode("utf-8")
submit_response = requests.post(
f"{API_BASE}/v1/extractions/run?async=true",
headers=headers,
json={
"templateId": "tmpl_abc123",
"fileName": "invoice.pdf",
"pdfBase64": pdf_base64,
"mimeType": "application/pdf",
},
)
submitted = submit_response.json()["data"]
print(f"Extraction {submitted['id']} submitted, status: {submitted['status']}")
# 2. Poll until complete
def poll(extraction_id: str):
for _ in range(30):
res = requests.get(
f"{API_BASE}/v1/extractions/{extraction_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
)
data = res.json()["data"]
if data["status"] != "processing":
return data
time.sleep(2)
raise TimeoutError("Extraction timed out")
result = poll(submitted["id"])
print(f"Final status: {result['status']}")
print("Extracted data:", result["extractedData"])متى تستخدم الوضع غير المتزامن
استخدم الوضع غير المتزامن عند معالجة مستندات كبيرة، أو عندما يكون لعميل HTTP الخاص بك مهلات قصيرة، أو عندما تريد إرسال عدة عمليات استخراج وجمع النتائج لاحقاً. لمعظم عمليات استخراج المستند الواحد، الوضع المتزامن أبسط.
مثال سير عمل كامل
إليك مثالاً كاملاً من البداية إلى النهاية بلغة TypeScript يقرأ ملف PDF من القرص ويشغّل استخراجاً ويتعامل مع النجاح والفشل:
import { readFileSync } from "fs";
const API_BASE = "https://api.docmap.io";
const API_KEY = process.env.DOCMAP_API_KEY!;
async function extractInvoice(filePath: string) {
// 1. Read and encode the PDF
const pdfBuffer = readFileSync(filePath);
const pdfBase64 = pdfBuffer.toString("base64");
const fileName = filePath.split("/").pop()!;
console.log(`Processing ${fileName} (${(pdfBuffer.length / 1024).toFixed(0)} KB)...`);
// 2. Run the extraction
const response = await fetch(`${API_BASE}/v1/extractions/run`, {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
templateId: "tmpl_invoice_parser",
fileName,
pdfBase64,
mimeType: "application/pdf",
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API error ${response.status}: ${error.error.message}`);
}
const { data } = await response.json();
// 3. Check the extraction result
if (data.status === "failed") {
console.error(`Extraction failed: ${data.error}`);
return null;
}
console.log(`Extraction completed in ${data.processingTimeMs}ms`);
console.log("Extracted data:", JSON.stringify(data.extractedData, null, 2));
return data.extractedData;
}
// Run it
extractInvoice("./invoices/invoice-001.pdf")
.then((result) => {
if (result) {
console.log(`Vendor: ${result.vendor_name}`);
console.log(`Total: $${result.total_amount}`);
}
})
.catch(console.error);