# الملفات

> ارفع الصور والمستندات إلى Fileverity: multipart للملفات حتى 4 ميغابايت، ورفع بعنوان موقّع مسبقًا للملفات حتى 50 ميغابايت. كائن الملف والحدود والاحتفاظ.

المصدر: https://fileverity.com/ar/docs/files

تُفحص الصور والمستندات على خطوتين. أولًا ترفع الملف عبر `POST /files` فتتلقى معرّف ملف. ثم تنشئ [تحليلًا](https://fileverity.com/ar/docs/analyses.md) يشير إلى ذلك المعرّف. لا يحتاج النص إلى ملف؛ استخدم [كشف النصوص](https://fileverity.com/ar/docs/text-detections.md).

## الملفات المدعومة

|  | الصور (fvimg-2) | المستندات (fvdoc-3) |
| --- | --- | --- |
| الصيغ | `jpeg`, `png`, `webp` | `pdf`, `docx`, `doc`, `rtf`, `odt`, `pptx`, `txt` |
| الحجم الأقصى | 10 ميغابايت | 50 ميغابايت |
| حدود أخرى | 40 ميغابكسل | 100 صفحة |

## طريقتان للرفع

| الطريقة | الطلب | الحجم | حالة الملف في الاستجابة |
| --- | --- | --- | --- |
| Multipart | `multipart/form-data` مع الحقل `file` | حتى 4 ميغابايت | `uploaded` |
| عنوان URL موقّع مسبقًا | JSON يتضمن `filename` و`content_type` و`bytes`، ثم `PUT` للبايتات | حتى 50 ميغابايت | `pending` إلى أن تصل البايتات |

حجم الصور محدود بالحجم المذكور أعلاه أيًّا كانت طريقة الرفع.

## الرفع بطريقة Multipart

أرسل الملفات حتى 4 ميغابايت بصيغة `multipart/form-data` في الحقل `file`. وتُحدَّد الصيغة من محتوى الملف، لا من اسمه ولا من نوعه المعلَن.

**الرفع بطريقة Multipart: cURL**

```bash
curl https://api.fileverity.com/v1/files \
  -H "Authorization: Bearer $FILEVERITY_API_KEY" \
  -F file=@claim-photo.jpg
```

**الرفع بطريقة Multipart: JavaScript**

```javascript
import { readFile } from "node:fs/promises";

const form = new FormData();
form.append("file", new Blob([await readFile("claim-photo.jpg")]), "claim-photo.jpg");
const response = await fetch("https://api.fileverity.com/v1/files", {
  method: "POST",
  headers: { Authorization: "Bearer " + process.env.FILEVERITY_API_KEY },
  body: form,
});
const file = await response.json();
```

**الرفع بطريقة Multipart: Python**

```python
import os
import requests

response = requests.post(
    "https://api.fileverity.com/v1/files",
    headers={"Authorization": "Bearer " + os.environ["FILEVERITY_API_KEY"]},
    files={"file": open("claim-photo.jpg", "rb")},
)
file = response.json()
```

**201 Created**

```json
{
  "id": "file_8Hk2pQ4vN9sL1xR7cW3mY6zB",
  "object": "file",
  "filename": "claim-photo.jpg",
  "bytes": 2481920,
  "content_type": "image/jpeg",
  "status": "uploaded",
  "livemode": true,
  "created": 1793700000,
  "expires_at": 1793786400
}
```

## الرفع بعنوان موقّع مسبقًا

للملفات الأكبر من 4 ميغابايت وحتى 50 ميغابايت، اطلب عنوان رفع، ثم أرسل البايتات مباشرة إلى التخزين.

1. `POST /files` بمحتوى طلب بصيغة JSON: `filename` (اختياري) و`content_type` والحجم الدقيق في `bytes`. تحمل الاستجابة `status: pending` وكائن `upload`.
2. أرسل بايتات الملف بطلب `PUT` إلى `upload.url` مع الترويسات الواردة في `upload.headers`، قبل `upload.expires_at`. لا حاجة إلى ترويسة `Authorization` في هذا الطلب.
3. اختياريًا، كرّر الاستعلام عبر `GET /files/{id}` إلى أن تصبح قيمة `status` هي `uploaded`.
4. أنشئ التحليل بمعرّف الملف.

**الرفع بعنوان موقّع مسبقًا: cURL**

```bash
FILE=$(curl -s https://api.fileverity.com/v1/files \
  -H "Authorization: Bearer $FILEVERITY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename": "contract.pdf", "content_type": "application/pdf", "bytes": 18874368}')

UPLOAD_URL=$(echo "$FILE" | jq -r .upload.url)
FILE_ID=$(echo "$FILE" | jq -r .id)

curl -X PUT "$UPLOAD_URL" \
  -H "content-type: application/pdf" \
  --data-binary @contract.pdf
```

**الرفع بعنوان موقّع مسبقًا: JavaScript**

```javascript
import { readFile } from "node:fs/promises";

const bytes = await readFile("contract.pdf");
const response = await fetch("https://api.fileverity.com/v1/files", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.FILEVERITY_API_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ filename: "contract.pdf", content_type: "application/pdf", bytes: bytes.length }),
});
const file = await response.json();

await fetch(file.upload.url, { method: "PUT", headers: file.upload.headers, body: bytes });
```

**الرفع بعنوان موقّع مسبقًا: Python**

```python
import os
import requests

data = open("contract.pdf", "rb").read()
response = requests.post(
    "https://api.fileverity.com/v1/files",
    headers={"Authorization": "Bearer " + os.environ["FILEVERITY_API_KEY"]},
    json={"filename": "contract.pdf", "content_type": "application/pdf", "bytes": len(data)},
)
file = response.json()

requests.put(file["upload"]["url"], headers=file["upload"]["headers"], data=data)
```

**201 Created**

```json
{
  "id": "file_Pw3mY6zB8Hk2pQ4vN9sL1xR7",
  "object": "file",
  "filename": "contract.pdf",
  "bytes": 18874368,
  "content_type": "application/pdf",
  "status": "pending",
  "livemode": true,
  "created": 1793700000,
  "expires_at": 1793786400,
  "upload": {
    "url": "https://example.private.blob.vercel-storage.com/f/0d6f1c2e-7b1a-4c53-9a0e-5e8a41b3c7d2?signature=...",
    "method": "PUT",
    "headers": {
      "content-type": "application/pdf"
    },
    "expires_at": 1793703600
  }
}
```

عنوان URL المعروض مختصر. استخدم العنوان الوارد في استجابتك كما هو. أرسل ترويسة `content-type` تمامًا كما أُعيدت في `upload.headers`.

### أنواع المحتوى المقبولة

| الفئة | أنواع المحتوى |
| --- | --- |
| الصور | `image/jpeg`, `image/png`, `image/webp` |
| المستندات | `application/pdf`, `application/vnd.openxmlformats-officedocument.wordprocessingml.document`, `application/msword`, `application/rtf`, `application/vnd.oasis.opendocument.text`, `application/vnd.openxmlformats-officedocument.presentationml.presentation`, `text/plain` |

## كائن الملف

| الحقل | النوع | الوصف |
| --- | --- | --- |
| `id` | string | معرّف الملف، ويبدأ بالبادئة `file_`. |
| `object` | string | دائمًا `file`. |
| `filename` | string أو null | اسم الملف بعد تنظيفه. |
| `bytes` | integer أو null | الحجم بالبايت. |
| `content_type` | string | نوع المحتوى المكتشف أو المعلَن. |
| `status` | string | `pending` إلى أن تصل البايتات المرفوعة، ثم `uploaded`. |
| `livemode` | boolean | `false` للملفات المنشأة بمفتاح اختبار. تُفصل الملفات بحسب الوضع. |
| `created` | integer | طابع زمني بصيغة Unix. |
| `expires_at` | integer | طابع زمني بصيغة Unix يُحذف الملف بعده. |
| `upload` | object | في استجابة طلب الرفع بصيغة JSON فقط: `url` و`method` (`PUT`) و`headers` و`expires_at`. |

## الاحتفاظ

- يُحتفظ بالملف 24 ساعة على الأكثر (انظر `expires_at`) ثم يُحذف.
- يُحذف الملف بمجرد أن يبدأ تحليل منه. يُستخدم كل ملف مرفوع في تحليل واحد؛ ارفعه مرة أخرى لفحصه مجددًا.
- يزيل `DELETE /files/{id}` الملف وبايتاته المخزنة في وقت أبكر.
- يمكن أن تضم مساحة العمل حتى 50 ملفًا لم تنته صلاحيتها و200 ميغابايت لكل وضع في آن واحد. وبعد ذلك تفشل عمليات الرفع برمز الخطأ `pending_files_limit` (رمز الحالة 429 في HTTP، دون `retry-after`) إلى أن تُستخدم الملفات أو تُحذف أو تنتهي صلاحيتها.
- يعيد معرّف ملف غير معروف أو منتهي الصلاحية أو مستخدم سابقًا الخطأ `file_not_found` عند إنشاء تحليل، والخطأ `not_found` عند جلبه أو حذفه. ويُعاد `file_not_found` أيضًا إذا لم ينتهِ الرفع إلى `upload.url` بعد، فانتظر حتى يُظهر `GET /files/{id}` القيمة `uploaded`.

## الأخطاء

| الرمز | الحالة | السبب |
| --- | --- | --- |
| `missing_parameter` | 400 | لا يوجد حقل `file` في محتوى الطلب بصيغة multipart. |
| `unsupported_media_type` | 415 | محتوى الطلب ليس بصيغة `multipart/form-data` ولا بصيغة JSON. |
| `unsupported_file` | 415 | الصيغة غير مدعومة. |
| `invalid_file` | 422 | الملف فارغ أو تالف أو لا يمكن قراءته. |
| `file_too_large` | 413 | ملف multipart أكبر من 4 ميغابايت، أو `bytes` أكبر من 50 ميغابايت. |
| `invalid_parameter` | 400 | حقل JSON مفقود أو نوعه خاطئ أو غير معروف. |
| `invalid_json` | 400 | محتوى الطلب بصيغة JSON ليس كائنًا. |
| `pending_files_limit` | 429 | عدد كبير جدًا من عمليات الرفع غير المنتهية الصلاحية في مساحة العمل. لا تُرسل معه ترويسة `retry-after`. |
| `idempotency_mismatch`, `idempotency_in_progress` | 409 | استُخدم `Idempotency-Key` مع طلب مختلف، أو لا يزال طلبه الأول قيد التنفيذ. |

> **ملاحظة.** تتحقق مفاتيح الاختبار من صحة عمليات الرفع لكنها لا تخزّن البايتات. ويعيد طلب الرفع بصيغة JSON بمفتاح اختبار كائن رفع تجريبيًا (قيمة `upload.test` هي `true` والملف في حالة `uploaded` أصلًا): فلا شيء يُرسل بطلب PUT.

