# كشف النصوص

> صنّف النص العادي بوصفه مكتوبًا بالذكاء الاصطناعي أو مختلطًا أو كتبه إنسان باستخدام POST /text/detections. حقول الطلب والاستجابة، وإزاحات المقاطع، والحدود، والفوترة.

المصدر: https://fileverity.com/ar/docs/text-detections

يُجري `POST /text/detections` فحص نص واحد. يصنّف النص العادي بنموذج `fvdoc-3-text` ويعيد الفقرات المكتوبة بالذكاء الاصطناعي. وهو متزامن: النتيجة في الاستجابة نفسها.

تقرأ الأمثلة النص من ملف، لذا احفظ أي فقرة من 100 كلمة أو أكثر باسم `essay.txt` أولًا. ويتضمن [البدء السريع](https://fileverity.com/ar/docs/quickstart.md#text) أمرًا يكتب نصًا تجريبيًا.

**الطلب: cURL**

```bash
curl https://api.fileverity.com/v1/text/detections \
  -H "Authorization: Bearer $FILEVERITY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6b9d1c1e-3b0f-4c0a-9a53-2d1c9d6b7e11" \
  -d "$(jq -Rs '{text: ., language: "en"}' essay.txt)"
```

**الطلب: JavaScript**

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

const response = await fetch("https://api.fileverity.com/v1/text/detections", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.FILEVERITY_API_KEY,
    "Content-Type": "application/json",
    "Idempotency-Key": randomUUID(),
  },
  body: JSON.stringify({ text: await readFile("essay.txt", "utf8"), language: "en" }),
});
const detection = await response.json();
```

**الطلب: Python**

```python
import os
import uuid
import requests

response = requests.post(
    "https://api.fileverity.com/v1/text/detections",
    headers={
        "Authorization": "Bearer " + os.environ["FILEVERITY_API_KEY"],
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={"text": open("essay.txt", encoding="utf-8").read(), "language": "en"},
)
detection = response.json()
```

## محتوى الطلب

| الحقل | النوع | مطلوب | الوصف |
| --- | --- | --- | --- |
| `text` | string | نعم | نص عادي لا يقل عن 100 كلمة ولا يزيد على 100,000 حرف. |
| `model` | string | لا | الافتراضي `fvdoc-3-text`. يقبل معرّف النموذج أو معرّف نسخته المؤرَّخة `fvdoc-3-text-2026-11-03`. |
| `language` | string أو null | لا | رمز ISO 639-1: `en` و`fr` و`de` و`es` و`zh`. يُكتشف تلقائيًا عند عدم تحديده. |

تُرفض الحقول غير المعروفة برمز الخطأ `invalid_parameter`. وعند التحقق من الحد الأدنى البالغ 100 كلمة، يُحتسب كل حرفين صينيين تقريبًا ككلمة واحدة.

## الاستجابة

**200 OK**

```json
{
  "id": "tdet_8Hk2pQ4vN9sL1xR7cW3mY6zB",
  "object": "text.detection",
  "created": 1793664000,
  "model": "fvdoc-3-text-2026-11-03",
  "livemode": true,
  "language": "en",
  "verdict": "mixed",
  "score": 0.97,
  "ai_fraction": 0.41,
  "segments": [
    {
      "start": 212,
      "end": 433,
      "score": 0.97
    },
    {
      "start": 579,
      "end": 790,
      "score": 0.93
    }
  ],
  "usage": {
    "characters": 1412,
    "free_characters": 0,
    "billed_units": 2
  }
}
```

| الحقل | النوع | الوصف |
| --- | --- | --- |
| `id` | string | معرّف الكشف، ويبدأ بالبادئة `tdet_`. |
| `object` | string | دائمًا `text.detection`. |
| `created` | integer | طابع زمني بصيغة Unix. |
| `model` | string | النسخة المؤرَّخة التي أنتجت النتيجة. |
| `livemode` | boolean | `false` لمفاتيح الاختبار. |
| `language` | string | اللغة المستخدمة: التي أرسلتها، أو التي اكتُشفت. |
| `verdict` | string | `ai`: يبدو النص مكتوبًا بالذكاء الاصطناعي من أوله إلى آخره. `mixed`: فقرات مكتوبة بالذكاء الاصطناعي داخل نص كتبه إنسان. `human`: لم يُعثر على أي فقرة مكتوبة بالذكاء الاصطناعي. |
| `score` | number | من 0 إلى 1. درجة النموذج لأكثر الفقرات شبهًا بالنص المكتوب بالذكاء الاصطناعي. |
| `ai_fraction` | number | من 0 إلى 1. نسبة النص المُقيَّم الواقعة داخل المقاطع المكتوبة بالذكاء الاصطناعي. |
| `segments` | array | الفقرات المكتوبة بالذكاء الاصطناعي. لكل منها `start` و`end` (موضع النهاية غير مشمول) و`score`. |
| `usage` | object | `characters` الأحرف التي جرى تقييمها، و`free_characters` الأحرف التي غطّاها رصيد البدء المجاني، و`billed_units` الوحدات المحتسبة فعليًا بعد الأحرف المجانية. |

> **ملاحظة.** يعيد كشف النص تقديرًا إحصائيًا وليس دليلًا على هوية كاتب النص. وحدود المقاطع تقريبية. استخدمه مُدخلًا واحدًا في مراجعة بشرية، ولا تعتمد عليه وحده في اتخاذ قرارات تمس شخصًا.

## إزاحات المقاطع

`start` و`end` إزاحتان في النص الذي أرسلته، تُحسبان بنقاط ترميز Unicode، لا بالبايتات ولا بوحدات UTF-16. وحدود المقاطع تقريبية وقد تشمل جملًا مجاورة. تُفهرَس سلاسل JavaScript بوحدات UTF-16، لذا قسّم النص إلى نقاط ترميز أولًا:

**اقتطاع مقطع: JavaScript**

```javascript
const points = Array.from(text);
for (const { start, end } of detection.segments) {
  console.log(points.slice(start, end).join(""));
}
```

**اقتطاع مقطع: Python**

```python
for segment in detection["segments"]:
    print(text[segment["start"]:segment["end"]])
```

تُفهرَس سلاسل Python أصلًا بنقاط الترميز.

## الفوترة

- يُحتسب النص بسعر ⁦US$ 0.14⁩ لكل 1,000 حرف، وتُعدّ الأحرف بنقاط ترميز Unicode. ويُقرَّب كل طلب إلى الأعلى إلى وحدات كاملة، بحد أدنى وحدة واحدة.
- تُستخدم أحرف النص المجانية من رصيد البدء المجاني أولًا، وتظهر في `usage.free_characters`. و`usage.billed_units` هو عدد الوحدات المحتسبة بعدها، فتكون التكلفة `billed_units` مضروبًا في ⁦US$ 0.14⁩. مثال: 1,412 حرفًا دون أحرف مجانية متبقية يُحتسب عليها وحدتان، أي ⁦US$ 0.28⁩.
- لا تُحتسب رسوم على الطلبات المرفوضة قبل التقييم: المعلمات غير الصالحة، والنص القصير جدًا أو الطويل جدًا، واللغات غير المدعومة وما شابه. وإذا فشل الفحص داخل الخدمة (`service_unavailable`) فيُحرَّر المبلغ المحجوز ولا يُحتسب عليك.
- عند عدم كفاية الرصيد يُعاد الخطأ `insufficient_balance` (402).

## ما الذي يُخزَّن

يُقيَّم النص ثم يُحذف. ولا يُخزَّن أبدًا، لذلك لا يمكن استرجاعه لاحقًا.

تحتفظ Fileverity بالنتيجة دون النص (الحكم والدرجات وإزاحات الفقرات والاستخدام) مدة 7 أيام، حتى تعرضها لوحة التحكم ويمكن احتساب الاستخدام وتدقيقه. ويحصل الطلب المُعاد الذي يحمل `Idempotency-Key` نفسه على النتيجة المحفوظة خلال 24 ساعة. عمليات كشف النصوص متزامنة: فلا تظهر في `GET /analyses` ولا تُرسل أحداث Webhook. ولا تسجّل مفاتيح الاختبار شيئًا. راجع [الاحتفاظ بالبيانات والأمان](https://fileverity.com/ar/docs/security.md).

## الأخطاء

| الرمز | الحالة | السبب |
| --- | --- | --- |
| `text_too_short` | 400 | أقل من 100 كلمة. |
| `text_too_long` | 413 | أكثر من 100,000 حرف. قسّم النص إلى عدة طلبات. |
| `unsupported_language` | 400 | اللغة غير مدعومة، أو تعذّر اكتشافها. |
| `unsupported_media_type` | 415 | لم يُرسل محتوى الطلب بصيغة `application/json`. |
| `invalid_json` | 400 | محتوى الطلب ليس كائن JSON. |
| `missing_parameter` | 400 | الحقل `text` مفقود. |
| `invalid_parameter` | 400 | نوع أحد الحقول خاطئ، أو أُرسل حقل غير معروف، أو `Idempotency-Key` غير صالح. |
| `model_not_found` | 404 | قيمة `model` غير معروفة. |
| `insufficient_balance` | 402 | الرصيد لا يغطي الطلب. |
| `spend_limit_reached` | 402 | بلغ المفتاح حد إنفاقه الشهري. |
| `idempotency_mismatch`, `idempotency_in_progress` | 409 | استُخدم `Idempotency-Key` مع محتوى طلب مختلف، أو لا يزال طلبه الأول قيد التنفيذ. |
| `service_unavailable`, `analysis_failed` | 503, 502 | خدمة الكشف غير متاحة مؤقتًا أو مشغولة. لا تُحتسب رسوم؛ أعد المحاولة. يحمل `service_unavailable` ترويسة `retry-after`. |

> **ملاحظة.** أرسل `Idempotency-Key` حتى لا تؤدي إعادة المحاولة بعد انتهاء المهلة إلى احتساب الرسم مرتين. راجع [Idempotency](https://fileverity.com/ar/docs/idempotency.md).

