واجهة API

المصادقة بمفتاح API في الترويسة Authorization: Bearer sfh_…. الأخطاء بصيغة موحدة { error: { code, message } }. المواصفة الكاملة في docs/openapi.yaml داخل المستودع.

الطريقةالمسارالوصف
POST/api/v1/librariesإنشاء مكتبة
GET/api/v1/librariesقائمة المكتبات المتاحة
POST/api/v1/documents/uploadرفع مستند (multipart) مع بياناته الوصفية وحقوقه
GET/api/v1/documents/:idتفاصيل المستند: الصفحات والكتل والجودة والإصدارات
GET/api/v1/documents/:id/statusحالة المعالجة (خطوة، تقدم، خطأ)
POST/api/v1/documents/:id/reprocessإعادة المعالجة
POST/api/v1/documents/:id/transitionاعتماد / نشر / سحب
POST/api/v1/searchبحث هجين مع فلاتر
POST/api/v1/answerإجابة بمصادر (SSE عند stream=true)
POST/api/v1/evalsإنشاء مجموعة تقييم
POST/api/v1/evals/:id/runتشغيل على عدة مودلات
GET/api/v1/evals/:id/resultsنتائج التشغيل
POST/api/v1/feedbackتقييم إجابة: صحيحة / جزئية / خاطئة
GET/api/v1/modelsالمودلات والمزودون المتاحون

مثال: إجابة بمصادر

curl -X POST $APP_URL/api/v1/answer \
  -H "Authorization: Bearer sfh_..." \
  -H "Content-Type: application/json" \
  -d '{"query":"ما مدة الإجازة السنوية؟","libraryIds":["<uuid>"],"limit":8}'

SDK (TypeScript)

import { SafahClient } from "@safah/sdk";
const safah = new SafahClient({ baseUrl: "http://localhost:3000", apiKey: "sfh_..." });
const hits = await safah.search({ query: "ساعات العمل", libraryIds: [libraryId] });
const answer = await safah.answer({ query: "كم ساعات العمل اليومية؟", libraryIds: [libraryId] });
for await (const ev of safah.answerStream({ query: "…", libraryIds: [libraryId] })) { /* delta | sources | done */ }