Rememberizer Docs
تسجيل الدخولاشتراكاتصل بنا
دليل
دليل
  • لماذا Rememberizer؟
  • خلفية
    • ما هي تضمينات المتجهات وقواعد بيانات المتجهات؟
    • مسرد
    • المصطلحات القياسية
  • الاستخدام الشخصي
    • البدء
      • ابحث في معرفتك
      • الوصول إلى فلتر الذكريات
      • المعرفة العامة
      • إدارة معرفتك المدمجة
  • التكاملات
    • تطبيق Rememberizer
    • تكامل Rememberizer مع Slack
    • تكامل Rememberizer مع Google Drive
    • تكامل Rememberizer مع Dropbox
    • تكامل Rememberizer مع Gmail
    • تكامل Rememberizer مع الذاكرة
    • خوادم Rememberizer MCP
    • إدارة التطبيقات الخارجية
  • موارد المطورين
    • نظرة عامة على المطور
  • خيارات التكامل
    • تسجيل واستخدام مفاتيح API
    • تسجيل تطبيقات Rememberizer
    • تفويض تطبيقات Rememberizer
    • إنشاء GPT لـ Rememberizer
    • تكامل LangChain
    • متاجر المتجهات
    • تحدث إلى Slack تطبيق الويب النموذجي
  • تكامل المؤسسات
    • أنماط تكامل المؤسسات
  • مرجع واجهة برمجة التطبيقات
    • الصفحة الرئيسية لوثائق واجهة برمجة التطبيقات
    • المصادقة
  • واجهات برمجة التطبيقات الأساسية
    • البحث عن المستندات حسب التشابه الدلالي
    • استرجاع المستندات
    • استرجاع محتويات المستندات
    • استرجاع محتوى Slack
    • تذكر المحتوى إلى Rememberizer
  • الحساب والتكوين
    • استرجاع تفاصيل حساب المستخدم الحالي
    • قائمة تكاملات مصادر البيانات المتاحة
    • المذكرات
    • الحصول على جميع المعرفة العامة المضافة
  • واجهات برمجة تطبيقات تخزين المتجهات
    • وثائق تخزين المتجهات
    • الحصول على معلومات تخزين المتجهات
    • الحصول على قائمة بالوثائق في تخزين المتجهات
    • الحصول على معلومات الوثيقة
    • إضافة وثيقة نصية جديدة إلى تخزين المتجهات
    • رفع الملفات إلى تخزين المتجهات
    • تحديث محتوى الملف في تخزين المتجهات
    • إزالة وثيقة في تخزين المتجهات
    • البحث عن وثائق تخزين المتجهات حسب التشابه الدلالي
  • موارد إضافية
    • الإشعارات
      • شروط الاستخدام
      • سياسة الخصوصية
      • B2B
        • حول وكيل Reddit
  • الإصدارات
    • صفحة ملاحظات الإصدار
  • إصدارات 2025
    • 25 أبريل 2025
    • 18 أبريل 2025
    • 11 أبريل 2025
    • 4 أبريل 2025
    • 28 مارس 2025
    • 21 مارس 2025
    • 14 مارس 2025
    • 17 يناير 2025
  • إصدارات 2024
    • 27 ديسمبر 2024
    • 20 ديسمبر 2024
    • 13 ديسمبر 2024
    • 6 ديسمبر 2024
  • 29 نوفمبر 2024
  • 22 نوفمبر 2024
  • 15 نوفمبر 2024
  • 8 نوفمبر 2024
  • 1 نوفمبر 2024
  • 25 أكتوبر 2024
  • 18 أكتوبر 2024
  • 11 أكتوبر 2024
  • 4 أكتوبر 2024
  • 27 سبتمبر 2024
  • 20 سبتمبر 2024
  • 13 سبتمبر 2024
  • 16 أغسطس 2024
  • 9 أغسطس 2024
  • 2 أغسطس 2024
  • 26 يوليو 2024
  • 12 يوليو 2024
  • 28 يونيو 2024
  • 14 يونيو 2024
  • 31 مايو 2024
  • 17 مايو 2024
  • 10 مايو 2024
  • 26 أبريل 2024
  • 19 أبريل 2024
  • 12 أبريل 2024
  • 5 أبريل 2024
  • 25 مارس 2024
  • 18 مارس 2024
  • 11 مارس 2024
  • 4 مارس 2024
  • 26 فبراير 2024
  • 19 فبراير 2024
  • 12 فبراير 2024
  • 5 فبراير 2024
  • 29 يناير 2024
  • 22 يناير 2024
  • 15 يناير 2024
  • وثائق LLM
    • وثائق Rememberizer LLM جاهزة
Powered by GitBook
On this page
  • مخازن المتجهات
  • المقدمة
  • نظرة عامة تقنية
  • البدء
  • إدارة مفاتيح API
  • استخدام واجهة برمجة تطبيقات تخزين المتجهات
  • رفع مستند إلى مخزن المتجهات
  • رفع محتوى النص إلى مخزن المتجهات
  • البحث في مخزن المتجهات
  • مثال على الاستخدام
  • رفع_المستند("path/to/document.pdf")
  • upload_text("هذا نص عينة ليتم تحويله إلى متجهات", "sample-document.txt")
  • search_vector_store("كيف تعمل تشابه المتجهات؟")
  • مثال على الاستخدام
  • البحث عن الوثائق
  • عرض النتيجة الأعلى
  • اعتبارات الأداء
  • الاستخدام المتقدم
  • الانتقال من قواعد بيانات المتجهات الأخرى
  1. خيارات التكامل

متاجر المتجهات

ستساعدك هذه الدليل على فهم كيفية استخدام متجر متجهات Rememberizer كمطور.

Previousتكامل LangChainNextتحدث إلى Slack تطبيق الويب النموذجي

Last updated 26 days ago

مخازن المتجهات

تبسط مخازن المتجهات في Rememberizer عملية التعامل مع بيانات المتجهات، مما يتيح لك التركيز على إدخال النص والاستفادة من قوة المتجهات لمجموعة متنوعة من التطبيقات مثل البحث وتحليل البيانات.

المقدمة

يوفر متجر المتجهات Rememberizer واجهة سهلة الاستخدام للتعامل مع بيانات المتجهات مع إخفاء تعقيد تضمينات المتجهات. مدعومًا بـ PostgreSQL مع امتداد pgvector، يتيح لك متجر المتجهات Rememberizer العمل مباشرة مع النص. تتولى الخدمة تقسيم النص وتضمينه وتخزين بيانات النص، مما يسهل عليك التركيز على منطق التطبيق الأساسي الخاص بك.

لفهم أعمق للمفاهيم النظرية وراء تضمينات المتجهات وقواعد بيانات المتجهات، راجع .

نظرة عامة تقنية

كيف تعمل مخازن المتجهات

تحول مخازن المتجهات في Rememberizer النص إلى تمثيلات متجهية عالية الأبعاد (تضمينات) تلتقط المعنى الدلالي. وهذا يمكّن من:

  1. البحث الدلالي: العثور على الوثائق بناءً على المعنى بدلاً من الكلمات الرئيسية فقط

  2. مطابقة التشابه: تحديد المحتوى المرتبط مفهوميًا

  3. استرجاع فعال: تحديد المعلومات ذات الصلة بسرعة من مجموعات البيانات الكبيرة

المكونات الرئيسية

  • معالجة الوثائق: يتم تقسيم النص إلى قطع بحجم مثالي مع حدود متداخلة للحفاظ على السياق

  • تحويل إلى متجهات: يتم تحويل القطع إلى تمثيلات باستخدام نماذج متطورة

  • الفهرسة: تنظم الخوارزميات المتخصصة المتجهات للبحث الفعال عن التشابه

  • معالجة الاستعلامات: يتم تحويل استعلامات البحث إلى متجهات ومقارنتها مع التمثيلات المخزنة

العمارة

تقوم Rememberizer بتنفيذ مخازن المتجهات باستخدام:

  • PostgreSQL مع امتداد pgvector: لتخزين المتجهات والبحث عنها بكفاءة

  • تنظيم قائم على المجموعات: كل مخزن متجه له مجموعته المعزولة الخاصة

  • وصول مدفوع بواجهة برمجة التطبيقات: نقاط نهاية RESTful بسيطة لجميع العمليات

البدء

إنشاء متجر المتجهات

  1. انتقل إلى قسم متاجر المتجهات في لوحة التحكم الخاصة بك

  2. انقر على "إنشاء متجر متجهات جديد":

    • ستظهر لك نموذج يطلب منك إدخال التفاصيل.

  3. املأ التفاصيل:

    • الاسم: قدم اسمًا فريدًا لمتجر المتجهات الخاص بك.

    • الوصف: اكتب وصفًا موجزًا لمتجر المتجهات.

    • نموذج التضمين: اختر النموذج الذي يحول النص إلى متجهات.

    • خوارزمية الفهرسة: اختر كيفية تنظيم المتجهات للبحث.

    • مقياس البحث: حدد كيفية حساب التشابه بين المتجهات.

    • أبعاد المتجه: حجم تضمينات المتجه (عادةً 768-1536).

  4. قدم النموذج:

    • انقر على زر "إنشاء". ستتلقى إشعار نجاح، وسيظهر المتجر الجديد في قائمة متاجر المتجهات الخاصة بك.

خيارات التكوين

نماذج التضمين

النموذج
الأبعاد
الوصف
الأفضل لـ

openai/text-embedding-3-large

1536

نموذج تضمين عالي الدقة من OpenAI

التطبيقات الإنتاجية التي تتطلب أقصى دقة

openai/text-embedding-3-small

1536

نموذج تضمين أصغر وأسرع من OpenAI

التطبيقات التي تتطلب معدل نقل أعلى

خوارزميات الفهرسة

الخوارزمية
الوصف
المساومات

IVFFLAT (افتراضي)

ملف مقلوب مع ضغط مسطح

توازن جيد بين السرعة والدقة؛ يعمل بشكل جيد لمعظم مجموعات البيانات

HNSW

عالم صغير قابل للتنقل هرمي

دقة أفضل لمجموعات البيانات الكبيرة؛ متطلبات ذاكرة أعلى

مقاييس البحث

المقياس
الوصف
الأفضل لـ

كوساين (افتراضي)

يقيس الزاوية بين المتجهات

المطابقة العامة للسمات

المنتج الداخلي (ip)

حاصل الضرب النقطي بين المتجهات

عندما تكون قيمة المتجه مهمة

L2 (إقليدي)

المسافة المستقيمة بين المتجهات

عندما تكون العلاقات المكانية مهمة

إدارة مخازن المتجهات

  1. عرض وتحرير مخازن المتجهات:

    • الوصول إلى لوحة الإدارة لعرض أو تحرير أو حذف مخازن المتجهات.

  2. عرض المستندات:

    • تصفح المستندات الفردية والبيانات الوصفية المرتبطة بها ضمن مخزن متجهات محدد.

  3. الإحصائيات:

    • عرض إحصائيات مفصلة مثل عدد المتجهات المخزنة، أداء الاستعلام، ومقاييس التشغيل.

إدارة مفاتيح API

تُستخدم مفاتيح API للمصادقة وتفويض الوصول إلى نقاط نهاية واجهة برمجة التطبيقات لمخزن المتجهات Rememberizer. إن الإدارة السليمة لمفاتيح API أمر ضروري للحفاظ على أمان وسلامة مخازن المتجهات الخاصة بك.

إنشاء مفاتيح API

  1. انتقل إلى صفحة تفاصيل متجر المتجهات الخاص بك

  2. انتقل إلى قسم إدارة مفاتيح API:

    • يمكن العثور عليه ضمن علامة التبويب "الإعدادات"

  3. انقر على "إضافة مفتاح API":

    • ستظهر لك نموذج يطلب منك إدخال التفاصيل.

  4. املأ التفاصيل:

    • الاسم: قدم اسمًا لمفتاح API لمساعدتك في تحديد حالة استخدامه.

  5. قدم النموذج:

    • انقر على زر "إنشاء". سيتم إنشاء مفتاح API الجديد وعرضه. تأكد من نسخه وتخزينه بأمان. يتم استخدام هذا المفتاح للمصادقة على الطلبات إلى متجر المتجهات المحدد.

إلغاء مفاتيح API

إذا لم تعد بحاجة إلى مفتاح API، يمكنك حذفه لمنع أي استخدام غير مناسب محتمل.

لأسباب أمنية، قد ترغب في تغيير مفاتيح API الخاصة بك بشكل دوري. يتضمن ذلك إنشاء مفتاح جديد وإلغاء المفتاح القديم.

استخدام واجهة برمجة تطبيقات تخزين المتجهات

بعد إنشاء تخزين المتجهات وتوليد مفتاح API، يمكنك التفاعل معه باستخدام واجهة برمجة التطبيقات REST.

أمثلة على الكود

import requests
import json

API_KEY = "your_api_key_here"
VECTOR_STORE_ID = "vs_abc123"  # استبدل بمعرف مخزن المتجهات الخاص بك
BASE_URL = "https://api.rememberizer.ai/api/v1"

رفع مستند إلى مخزن المتجهات

def upload_document(file_path, document_name=None): if document_name is None: document_name = file_path.split("/")[-1]

with open(file_path, "rb") as f:
    files = {"file": (document_name, f)}
    headers = {"x-api-key": API_KEY}
    
    response = requests.post(
        f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents",
        headers=headers,
        files=files
    )
    
    if response.status_code == 201:
        print(f"تم رفع المستند '{document_name}' بنجاح!")
        return response.json()
    else:
        print(f"خطأ في رفع المستند: {response.text}")
        return None

رفع محتوى النص إلى مخزن المتجهات

def upload_text(content, document_name): headers = { "x-api-key": API_KEY, "Content-Type": "application/json" }

data = {
    "name": document_name,
    "content": content
}

response = requests.post(
    f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
    headers=headers,
    json=data
)

if response.status_code == 201:
    print(f"تم رفع مستند النص '{document_name}' بنجاح!")
    return response.json()
else:
    print(f"خطأ في رفع النص: {response.text}")
    return None

البحث في مخزن المتجهات

def search_vector_store(query, num_results=5, prev_chunks=1, next_chunks=1): headers = {"x-api-key": API_KEY}

params = {
    "q": query,
    "n": num_results,
    "prev_chunks": prev_chunks,
    "next_chunks": next_chunks
}

response = requests.get(
    f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/search",
    headers=headers,
    params=params
)

if response.status_code == 200:
    results = response.json()
    print(f"تم العثور على {len(results['matched_chunks'])} تطابقات لـ '{query}'")
    
    # طباعة النتيجة الأعلى
    if results['matched_chunks']:
        top_match = results['matched_chunks'][0]
        print(f"أفضل تطابق (المسافة: {top_match['distance']}):")
        print(f"المستند: {top_match['document']['name']}")
        print(f"المحتوى: {top_match['matched_content']}")
    
    return results
else:
    print(f"خطأ في البحث: {response.text}")
    return None

مثال على الاستخدام

رفع_المستند("path/to/document.pdf")

upload_text("هذا نص عينة ليتم تحويله إلى متجهات", "sample-document.txt")

search_vector_store("كيف تعمل تشابه المتجهات؟")


</div>

<div data-gb-custom-block data-tag="tab" data-title='JavaScript'>

```javascript
// عميل واجهة برمجة تطبيقات متجر المتجهات
class VectorStoreClient {
  constructor(apiKey, vectorStoreId) {
    this.apiKey = apiKey;
    this.vectorStoreId = vectorStoreId;
    this.baseUrl = 'https://api.rememberizer.ai/api/v1';
  }

  // الحصول على معلومات متجر المتجهات
  async getVectorStoreInfo() {
    const response = await fetch(`${this.baseUrl}/vector-stores/${this.vectorStoreId}`, {
      method: 'GET',
      headers: {
        'x-api-key': this.apiKey
      }
    });
    
    if (!response.ok) {
      throw new Error(`فشل في الحصول على معلومات متجر المتجهات: ${response.statusText}`);
    }
    
    return response.json();
  }

  // تحميل مستند نصي
  async uploadTextDocument(name, content) {
    const response = await fetch(`${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents/text`, {
      method: 'POST',
      headers: {
        'x-api-key': this.apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        name,
        content
      })
    });
    
    if (!response.ok) {
      throw new Error(`فشل في تحميل المستند النصي: ${response.statusText}`);
    }
    
    return response.json();
  }

  // تحميل ملف
  async uploadFile(file, onProgress) {
    const formData = new FormData();
    formData.append('file', file);
    
    const xhr = new XMLHttpRequest();
    
    return new Promise((resolve, reject) => {
      xhr.open('POST', `${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents`);
      xhr.setRequestHeader('x-api-key', this.apiKey);
      
      xhr.upload.onprogress = (event) => {
        if (event.lengthComputable && onProgress) {
          const percentComplete = (event.loaded / event.total) * 100;
          onProgress(percentComplete);
        }
      };
      
      xhr.onload = () => {
        if (xhr.status === 201) {
          resolve(JSON.parse(xhr.responseText));
        } else {
          reject(new Error(`فشل في تحميل الملف: ${xhr.statusText}`));
        }
      };
      
      xhr.onerror = () => {
        reject(new Error('خطأ في الشبكة أثناء تحميل الملف'));
      };
      
      xhr.send(formData);
    });
  }

  // البحث عن مستندات في متجر المتجهات
  async searchDocuments(query, options = {}) {
    const params = new URLSearchParams({
      q: query,
      n: options.numResults || 10,
      prev_chunks: options.prevChunks || 1,
      next_chunks: options.nextChunks || 1
    });
    
    if (options.threshold) {
      params.append('t', options.threshold);
    }
    
    const response = await fetch(
      `${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents/search?${params}`,
      {
        method: 'GET',
        headers: {
          'x-api-key': this.apiKey
        }
      }
    );
    
    if (!response.ok) {
      throw new Error(`فشل البحث: ${response.statusText}`);
    }
    
    return response.json();
  }

  // قائمة بجميع المستندات في متجر المتجهات
  async listDocuments() {
    const response = await fetch(
      `${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents`,
      {
        method: 'GET',
        headers: {
          'x-api-key': this.apiKey
        }
      }
    );
    
    if (!response.ok) {
      throw new Error(`فشل في قائمة المستندات: ${response.statusText}`);
    }
    
    return response.json();
  }

  // حذف مستند
  async deleteDocument(documentId) {
    const response = await fetch(
      `${this.baseUrl}/vector-stores/${this.vectorStoreId}/documents/${documentId}`,
      {
        method: 'DELETE',
        headers: {
          'x-api-key': this.apiKey
        }
      }
    );
    
    if (!response.ok) {
      throw new Error(`فشل في حذف المستند: ${response.statusText}`);
    }
    
    return true;
  }
}

// مثال على الاستخدام
/*
const client = new VectorStoreClient('your_api_key', 'vs_abc123');

// البحث عن المستندات
client.searchDocuments('كيف تعمل عملية البحث الدلالي؟')
  .then(results => {
    console.log(`تم العثور على ${results.matched_chunks.length} تطابقات`);
    results.matched_chunks.forEach(match => {
      console.log(`المستند: ${match.document.name}`);
      console.log(`الدرجة: ${match.distance}`);
      console.log(`المحتوى: ${match.matched_content}`);
      console.log('---');
    });
  })
  .catch(error => console.error(error));
*/
require 'net/http'
require 'uri'
require 'json'

class VectorStoreClient
  def initialize(api_key, vector_store_id)
    @api_key = api_key
    @vector_store_id = vector_store_id
    @base_url = 'https://api.rememberizer.ai/api/v1'
  end

  # الحصول على تفاصيل متجر المتجهات
  def get_vector_store_info
    uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}")
    request = Net::HTTP::Get.new(uri)
    request['x-api-key'] = @api_key
    
    response = send_request(uri, request)
    JSON.parse(response.body)
  end

  # تحميل محتوى نصي
  def upload_text(name, content)
    uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents/text")
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request['x-api-key'] = @api_key
    
    request.body = {
      name: name,
      content: content
    }.to_json
    
    response = send_request(uri, request)
    JSON.parse(response.body)
  end

  # البحث عن المستندات
  def search(query, num_results: 5, prev_chunks: 1, next_chunks: 1, threshold: nil)
    uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents/search")
    params = {
      q: query,
      n: num_results,
      prev_chunks: prev_chunks,
      next_chunks: next_chunks
    }
    
    params[:t] = threshold if threshold
    
    uri.query = URI.encode_www_form(params)
    request = Net::HTTP::Get.new(uri)
    request['x-api-key'] = @api_key
    
    response = send_request(uri, request)
    JSON.parse(response.body)
  end

  # قائمة المستندات
  def list_documents
    uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents")
    request = Net::HTTP::Get.new(uri)
    request['x-api-key'] = @api_key
    
    response = send_request(uri, request)
    JSON.parse(response.body)
  end

  # تحميل ملف (نموذج متعدد الأجزاء)
  def upload_file(file_path)
    uri = URI("#{@base_url}/vector-stores/#{@vector_store_id}/documents")
    
    file_name = File.basename(file_path)
    file_content = File.binread(file_path)
    
    boundary = "RememberizerBoundary#{rand(1000000)}"
    
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
    request['x-api-key'] = @api_key
    
    post_body = []
    post_body << "--#{boundary}\r\n"
    post_body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{file_name}\"\r\n"
    post_body << "Content-Type: application/octet-stream\r\n\r\n"
    post_body << file_content
    post_body << "\r\n--#{boundary}--\r\n"
    
    request.body = post_body.join
    
    response = send_request(uri, request)
    JSON.parse(response.body)
  end

  private

  def send_request(uri, request)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = (uri.scheme == 'https')
    
    response = http.request(request)
    
    unless response.is_a?(Net::HTTPSuccess)
      raise "فشل طلب واجهة برمجة التطبيقات: #{response.code} #{response.message}\n#{response.body}"
    end
    
    response
  end
end

مثال على الاستخدام

=begin client = VectorStoreClient.new('your_api_key', 'vs_abc123')

البحث عن الوثائق

results = client.search('ما هي أفضل الممارسات لأمان البيانات؟') puts "تم العثور على #{results['matched_chunks'].length} نتيجة"

عرض النتيجة الأعلى

if results['matched_chunks'].any? top_match = results['matched_chunks'].first puts "النتيجة الأعلى (المسافة: #{top_match['distance']}):" puts "المستند: #{top_match['document']['name']}" puts "المحتوى: #{top_match['matched_content']}" end =end


</div>

<div data-gb-custom-block data-tag="tab" data-title='cURL'>

```bash
# قم بتعيين مفتاح API ومعرف متجر المتجهات
API_KEY="your_api_key_here"
VECTOR_STORE_ID="vs_abc123"
BASE_URL="https://api.rememberizer.ai/api/v1"

# احصل على معلومات مخزن المتجهات
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}" \
  -H "x-api-key: ${API_KEY}"

# رفع مستند نصي
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/text" \
  -H "x-api-key: ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "example-document.txt",
    "content": "هذا مستند عينة سيتم تحويله إلى متجه وتخزينه في قاعدة بيانات المتجهات للبحث الدلالي."
  }'

# رفع ملف
curl -X POST "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
  -H "x-api-key: ${API_KEY}" \
  -F "file=@/path/to/your/document.pdf"

# البحث عن المستندات
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/search?q=semantic%20search&n=5&prev_chunks=1&next_chunks=1" \
  -H "x-api-key: ${API_KEY}"

# قائمة بجميع الوثائق
curl -X GET "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents" \
  -H "x-api-key: ${API_KEY}"

# حذف مستند
curl -X DELETE "${BASE_URL}/vector-stores/${VECTOR_STORE_ID}/documents/123" \
  -H "x-api-key: ${API_KEY}"

اعتبارات الأداء

قريباً: مخطط هندسة تخزين المتجهات

سيوضح هذا المخطط الهندسي الفني:

  • هندسة قاعدة بيانات PostgreSQL + pgvector

  • هياكل خوارزميات الفهرسة (IVFFLAT مقابل HNSW)

  • كيف تعمل مقاييس البحث في فضاء المتجهات (مقارنة بصرية)

  • عملية تقسيم الوثائق مع تصور التداخل

  • اعتبارات الأداء مصورة عبر مقاييس مختلفة

تحسين لأحجام البيانات المختلفة

حجم البيانات
التكوين الموصى به
ملاحظات

صغير (<10k مستندات)

IVFFLAT، تشابه كوساين

التكوين البسيط يوفر أداءً جيدًا

متوسط (10k-100k مستندات)

IVFFLAT، تأكد من إعادة الفهرسة بانتظام

توازن بين سرعة البحث وصيانة الفهرس

كبير (>100k مستندات)

HNSW، اعتبر زيادة أبعاد المتجهات

استخدام ذاكرة أعلى ولكن يحافظ على الأداء عند النطاق

استراتيجيات تقسيم المحتوى

تؤثر عملية تقسيم المحتوى بشكل كبير على جودة البحث:

  • حجم القطعة: يستخدم Rememberizer حجم قطعة افتراضي يبلغ 1024 بايت مع تداخل 200 بايت

  • قطع أصغر (512-1024 بايت): تطابقات أكثر دقة، أفضل للأسئلة المحددة

  • قطع أكبر (1500-2048 بايت): مزيد من السياق في كل تطابق، أفضل للمواضيع الأوسع

  • التداخل: يضمن عدم فقدان السياق عند حدود القطع

تحسين الاستعلام

  • نوافذ السياق: استخدم prev_chunks و next_chunks لاسترجاع المحتوى المحيط

  • عدد النتائج: ابدأ بـ 3-5 نتائج (n parameter) واضبط بناءً على احتياجات الدقة

  • العتبة: اضبط t parameter لتصفية النتائج حسب درجة التشابه

الاستخدام المتقدم

إعادة الفهرسة

يقوم Rememberizer تلقائيًا بتحفيز إعادة الفهرسة عندما تتجاوز أعداد المتجهات الحدود المحددة مسبقًا، ولكن يُفضل النظر في إعادة الفهرسة يدويًا بعد:

  • رفع عدد كبير من الوثائق

  • تغيير نموذج التضمين

  • تعديل خوارزمية الفهرسة

تحسين الاستعلام

للحصول على نتائج بحث أفضل:

  1. كن محددًا في استعلامات البحث

  2. قم بتضمين السياق عند الإمكان

  3. استخدم اللغة الطبيعية بدلاً من الكلمات الرئيسية

  4. قم بضبط المعلمات بناءً على جودة النتائج

الانتقال من قواعد بيانات المتجهات الأخرى

إذا كنت تستخدم حاليًا حلول قواعد بيانات المتجهات الأخرى وترغب في الانتقال إلى Rememberizer Vector Store، ستساعدك الأدلة التالية في نقل بياناتك بكفاءة.

نظرة عامة على الهجرة

تشمل هجرة بيانات المتجهات:

  1. تصدير البيانات من قاعدة بيانات المتجهات المصدر الخاصة بك

  2. تحويل البيانات إلى تنسيق متوافق مع Rememberizer

  3. استيراد البيانات إلى متجر المتجهات الخاص بك في Rememberizer

  4. التحقق من نجاح الهجرة

فوائد الانتقال إلى Rememberizer

  • أساس PostgreSQL: مبني على تكنولوجيا قاعدة بيانات ناضجة مع نسخ احتياطي واستعادة مدمجة

  • نظام بيئي متكامل: اتصال سلس مع مكونات Rememberizer الأخرى

  • إدارة مبسطة: واجهة موحدة لعمليات المتجهات

  • أمان متقدم: أمان على مستوى الصفوف وضوابط وصول دقيقة

  • بنية قابلة للتوسع: تحسين الأداء مع نمو بياناتك

الانتقال من Pinecone

import os
import pinecone
import requests
import json
import time

# إعداد عميل Pinecone
pinecone.init(api_key="PINECONE_API_KEY", environment="PINECONE_ENV")
source_index = pinecone.Index("your-pinecone-index")

# إعداد عميل متجر متجهات Rememberizer
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123"  # معرف متجر متجهات Rememberizer الخاص بك
BASE_URL = "https://api.rememberizer.ai/api/v1"

# 1. إعداد حجم الدفعة للهجرة (قم بتعديلها بناءً على حجم بياناتك)
BATCH_SIZE = 100

# 2. وظيفة للحصول على المتجهات من Pinecone
def fetch_vectors_from_pinecone(index_name, batch_size, cursor=None):
    # استخدم عملية القائمة إذا كانت متاحة في إصدار Pinecone الخاص بك
    try:
        result = source_index.list(limit=batch_size, cursor=cursor)
        vectors = result.get("vectors", {})
        next_cursor = result.get("cursor")
        return vectors, next_cursor
    except AttributeError:
        # للإصدارات القديمة من Pinecone التي لا تحتوي على عملية القائمة
        # هذه طريقة مبسطة؛ التنفيذ الفعلي يعتمد على نمط الوصول إلى بياناتك
        query_response = source_index.query(
            vector=[0] * source_index.describe_index_stats()["dimension"],
            top_k=batch_size,
            include_metadata=True,
            include_values=True
        )
        return {item.id: {"id": item.id, "values": item.values, "metadata": item.metadata} 
                for item in query_response.matches}, None

# 3. وظيفة لتحميل المتجهات إلى Rememberizer
def upload_to_rememberizer(vectors):
    headers = {
        "x-api-key": REMEMBERIZER_API_KEY,
        "Content-Type": "application/json"
    }
    
    for vector_id, vector_data in vectors.items():
        # تحويل بيانات متجه Pinecone إلى تنسيق Rememberizer
        document_name = vector_data.get("metadata", {}).get("filename", f"pinecone_doc_{vector_id}")
        content = vector_data.get("metadata", {}).get("text", "")
        
        if not content:
            print(f"تخطي {vector_id} - لم يتم العثور على محتوى نصي في البيانات الوصفية")
            continue
            
        data = {
            "name": document_name,
            "content": content,
            # اختياري: تضمين بيانات وصفية إضافية
            "metadata": vector_data.get("metadata", {})
        }
        
        response = requests.post(
            f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
            headers=headers,
            json=data
        )
        
        if response.status_code == 201:
            print(f"تم تحميل المستند '{document_name}' بنجاح!")
        else:
            print(f"خطأ في تحميل المستند {document_name}: {response.text}")
        
        # إضافة تأخير صغير لمنع تحديد المعدل
        time.sleep(0.1)

# 4. دالة الهجرة الرئيسية
def migrate_pinecone_to_rememberizer():
    cursor = None
    total_migrated = 0
    
    print("بدء الهجرة من Pinecone إلى Rememberizer...")
    
    while True:
        vectors, cursor = fetch_vectors_from_pinecone("your-pinecone-index", BATCH_SIZE, cursor)
        
        if not vectors:
            break
            
        print(f"تم جلب {len(vectors)} متجهات من Pinecone")
        upload_to_rememberizer(vectors)
        
        total_migrated += len(vectors)
        print(f"التقدم: {total_migrated} متجهات تم هجرتها")
        
        if not cursor:
            break
    
    print(f"اكتملت الهجرة! {total_migrated} إجمالي المتجهات التي تم هجرتها إلى Rememberizer")

# تشغيل الهجرة
# migrate_pinecone_to_rememberizer()
const { PineconeClient } = require('@pinecone-database/pinecone');
const axios = require('axios');

// إعدادات Pinecone
const pineconeApiKey = 'PINECONE_API_KEY';
const pineconeEnvironment = 'PINECONE_ENVIRONMENT';
const pineconeIndexName = 'YOUR_PINECONE_INDEX';

// إعدادات Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// إعدادات حجم الدفعة
const BATCH_SIZE = 100;

// تهيئة عميل Pinecone
async function initPinecone() {
  const pinecone = new PineconeClient();
  await pinecone.init({
    apiKey: pineconeApiKey,
    environment: pineconeEnvironment,
  });
  return pinecone;
}

// جلب المتجهات من Pinecone
async function fetchVectorsFromPinecone(pinecone, batchSize, paginationToken = null) {
  const index = pinecone.Index(pineconeIndexName);
  
  try {
    // للإصدارات الأحدث من Pinecone
    const listResponse = await index.list({
      limit: batchSize,
      paginationToken: paginationToken
    });
    
    return {
      vectors: listResponse.vectors || {},
      nextToken: listResponse.paginationToken
    };
  } catch (error) {
    // بديل للإصدارات الأقدم من Pinecone
    // هذا مبسط؛ التنفيذ الفعلي يعتمد على نمط الوصول إلى بياناتك
    const stats = await index.describeIndexStats();
    const dimension = stats.dimension;
    
    const queryResponse = await index.query({
      vector: Array(dimension).fill(0),
      topK: batchSize,
      includeMetadata: true,
      includeValues: true
    });
    
    const vectors = {};
    queryResponse.matches.forEach(match => {
      vectors[match.id] = {
        id: match.id,
        values: match.values,
        metadata: match.metadata
      };
    });
    
    return { vectors, nextToken: null };
  }
}

// رفع المتجهات إلى Rememberizer
async function uploadToRememberizer(vectors) {
  const headers = {
    'x-api-key': rememberizerApiKey,
    'Content-Type': 'application/json'
  };
  
  const results = [];
  
  for (const [vectorId, vectorData] of Object.entries(vectors)) {
    const documentName = vectorData.metadata?.filename || `pinecone_doc_${vectorId}`;
    const content = vectorData.metadata?.text || '';
    
    if (!content) {
      console.log(`تخطي ${vectorId} - لم يتم العثور على محتوى نصي في البيانات الوصفية`);
      continue;
    }
    
    const data = {
      name: documentName,
      content: content,
      // اختياري: تضمين بيانات وصفية إضافية
      metadata: vectorData.metadata || {}
    };
    
    try {
      const response = await axios.post(
        `${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
        data,
        { headers }
      );
      
      if (response.status === 201) {
        console.log(`تم رفع الوثيقة '${documentName}' بنجاح!`);
        results.push({ id: vectorId, success: true });
      } else {
        console.error(`خطأ في رفع الوثيقة ${documentName}: ${response.statusText}`);
        results.push({ id: vectorId, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`خطأ في رفع الوثيقة ${documentName}: ${error.message}`);
      results.push({ id: vectorId, success: false, error: error.message });
    }
    
    // إضافة تأخير صغير لمنع تحديد المعدل
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// دالة الهجرة الرئيسية
async function migratePineconeToRememberizer() {
  try {
    console.log('بدء الهجرة من Pinecone إلى Rememberizer...');
    
    const pinecone = await initPinecone();
    let nextToken = null;
    let totalMigrated = 0;
    
    do {
      const { vectors, nextToken: token } = await fetchVectorsFromPinecone(
        pinecone, 
        BATCH_SIZE, 
        nextToken
      );
      
      nextToken = token;
      
      if (Object.keys(vectors).length === 0) {
        break;
      }
      
      console.log(`تم جلب ${Object.keys(vectors).length} متجهات من Pinecone`);
      
      const results = await uploadToRememberizer(vectors);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`التقدم: ${totalMigrated} متجهات تم نقلها بنجاح`);
      
    } while (nextToken);
    
    console.log(`اكتملت الهجرة! ${totalMigrated} إجمالي المتجهات تم نقلها إلى Rememberizer`);
    
  } catch (error) {
    console.error('فشلت الهجرة:', error);
  }
}

// تشغيل الهجرة
// migratePineconeToRememberizer();

الانتقال من Qdrant

import requests
import json
import time
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest

# إعداد عميل Qdrant
QDRANT_URL = "http://localhost:6333"  # أو عنوان URL الخاص بسحابة Qdrant
QDRANT_API_KEY = "your_qdrant_api_key"  # إذا كنت تستخدم سحابة Qdrant
QDRANT_COLLECTION_NAME = "your_collection"

qdrant_client = QdrantClient(
    url=QDRANT_URL,
    api_key=QDRANT_API_KEY  # فقط لسحابة Qdrant
)

# إعداد عميل متجر متجهات Rememberizer
REMEMBERIZER_API_KEY = "your_rememberizer_api_key"
VECTOR_STORE_ID = "vs_abc123"  # معرف متجر متجهات Rememberizer الخاص بك
BASE_URL = "https://api.rememberizer.ai/api/v1"

# حجم الدفعة للمعالجة
BATCH_SIZE = 100

# دالة لجلب النقاط من Qdrant
def fetch_points_from_qdrant(collection_name, batch_size, offset=0):
    try:
        # الحصول على معلومات المجموعة لتحديد أبعاد المتجه
        collection_info = qdrant_client.get_collection(collection_name=collection_name)
        
        # التمرير عبر النقاط
        scroll_result = qdrant_client.scroll(
            collection_name=collection_name,
            limit=batch_size,
            offset=offset,
            with_payload=True,
            with_vectors=True
        )
        
        points = scroll_result[0]  # زوج من (النقاط، next_offset)
        next_offset = scroll_result[1]
        
        return points, next_offset
    except Exception as e:
        print(f"خطأ في جلب النقاط من Qdrant: {e}")
        return [], None

# دالة لتحميل المتجهات إلى Rememberizer
def upload_to_rememberizer(points):
    headers = {
        "x-api-key": REMEMBERIZER_API_KEY,
        "Content-Type": "application/json"
    }
    
    results = []
    
    for point in points:
        # استخراج البيانات من نقطة Qdrant
        point_id = point.id
        metadata = point.payload
        text_content = metadata.get("text", "")
        document_name = metadata.get("filename", f"qdrant_doc_{point_id}")
        
        if not text_content:
            print(f"تخطي {point_id} - لم يتم العثور على محتوى نصي في الحمولة")
            continue
            
        data = {
            "name": document_name,
            "content": text_content,
            # اختياري: تضمين بيانات التعريف الإضافية
            "metadata": metadata
        }
        
        try:
            response = requests.post(
                f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
                headers=headers,
                json=data
            )
            
            if response.status_code == 201:
                print(f"تم تحميل الوثيقة '{document_name}' بنجاح!")
                results.append({"id": point_id, "success": True})
            else:
                print(f"خطأ في تحميل الوثيقة {document_name}: {response.text}")
                results.append({"id": point_id, "success": False, "error": response.text})
        except Exception as e:
            print(f"استثناء في تحميل الوثيقة {document_name}: {str(e)}")
            results.append({"id": point_id, "success": False, "error": str(e)})
        
        # إضافة تأخير صغير لمنع تحديد المعدل
        time.sleep(0.1)
    
    return results

# دالة الهجرة الرئيسية
def migrate_qdrant_to_rememberizer():
    offset = None
    total_migrated = 0
    
    print("بدء الهجرة من Qdrant إلى Rememberizer...")
    
    while True:
        points, next_offset = fetch_points_from_qdrant(
            QDRANT_COLLECTION_NAME, 
            BATCH_SIZE,
            offset
        )
        
        if not points:
            break
            
        print(f"تم جلب {len(points)} نقطة من Qdrant")
        
        results = upload_to_rememberizer(points)
        success_count = sum(1 for r in results if r.get("success", False))
        
        total_migrated += success_count
        print(f"التقدم: {total_migrated} نقطة تم هجرتها بنجاح")
        
        if next_offset is None:
            break
            
        offset = next_offset
    
    print(f"اكتملت الهجرة! {total_migrated} نقطة إجمالية تم هجرتها إلى Rememberizer")

# تشغيل الهجرة
# migrate_qdrant_to_rememberizer()
const { QdrantClient } = require('@qdrant/js-client-rest');
const axios = require('axios');

// إعدادات Qdrant
const qdrantUrl = 'http://localhost:6333'; // أو عنوان URL الخاص بسحابة Qdrant
const qdrantApiKey = 'your_qdrant_api_key'; // إذا كنت تستخدم سحابة Qdrant
const qdrantCollectionName = 'your_collection';

// إعدادات Rememberizer
const rememberizerApiKey = 'YOUR_REMEMBERIZER_API_KEY';
const vectorStoreId = 'vs_abc123';
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// إعدادات حجم الدفعة
const BATCH_SIZE = 100;

// تهيئة عميل Qdrant
const qdrantClient = new QdrantClient({ 
  url: qdrantUrl,
  apiKey: qdrantApiKey // فقط لسحابة Qdrant
});

// جلب النقاط من Qdrant
async function fetchPointsFromQdrant(collectionName, batchSize, offset = 0) {
  try {
    // الحصول على معلومات المجموعة
    const collectionInfo = await qdrantClient.getCollection(collectionName);
    
    // التمرير عبر النقاط
    const scrollResult = await qdrantClient.scroll(collectionName, {
      limit: batchSize,
      offset: offset,
      with_payload: true,
      with_vectors: true
    });
    
    return {
      points: scrollResult.points,
      nextOffset: scrollResult.next_page_offset
    };
  } catch (error) {
    console.error(`خطأ في جلب النقاط من Qdrant: ${error.message}`);
    return { points: [], nextOffset: null };
  }
}

// رفع المتجهات إلى Rememberizer
async function uploadToRememberizer(points) {
  const headers = {
    'x-api-key': rememberizerApiKey,
    'Content-Type': 'application/json'
  };
  
  const results = [];
  
  for (const point of points) {
    // استخراج البيانات من نقطة Qdrant
    const pointId = point.id;
    const metadata = point.payload || {};
    const textContent = metadata.text || '';
    const documentName = metadata.filename || `qdrant_doc_${pointId}`;
    
    if (!textContent) {
      console.log(`تخطي ${pointId} - لم يتم العثور على محتوى نصي في الحمولة`);
      continue;
    }
    
    const data = {
      name: documentName,
      content: textContent,
      // اختياري: تضمين بيانات وصفية إضافية
      metadata: metadata
    };
    
    try {
      const response = await axios.post(
        `${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
        data,
        { headers }
      );
      
      if (response.status === 201) {
        console.log(`تم رفع الوثيقة '${documentName}' بنجاح!`);
        results.push({ id: pointId, success: true });
      } else {
        console.error(`خطأ في رفع الوثيقة ${documentName}: ${response.statusText}`);
        results.push({ id: pointId, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`خطأ في رفع الوثيقة ${documentName}: ${error.message}`);
      results.push({ id: pointId, success: false, error: error.message });
    }
    
    // إضافة تأخير صغير لتجنب تحديد المعدل
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// الدالة الرئيسية للهجرة
async function migrateQdrantToRememberizer() {
  try {
    console.log('بدء الهجرة من Qdrant إلى Rememberizer...');
    
    let offset = null;
    let totalMigrated = 0;
    
    do {
      const { points, nextOffset } = await fetchPointsFromQdrant(
        qdrantCollectionName, 
        BATCH_SIZE, 
        offset
      );
      
      offset = nextOffset;
      
      if (points.length === 0) {
        break;
      }
      
      console.log(`تم جلب ${points.length} نقطة من Qdrant`);
      
      const results = await uploadToRememberizer(points);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`التقدم: ${totalMigrated} نقطة تم هجرها بنجاح`);
      
    } while (offset !== null);
    
    console.log(`اكتملت الهجرة! ${totalMigrated} إجمالي النقاط التي تم هجرها إلى Rememberizer`);
    
  } catch (error) {
    console.error('فشلت الهجرة:', error);
  }
}

// تشغيل الهجرة
// migrateQdrantToRememberizer();

الانتقال من Supabase pgvector

إذا كنت تستخدم Supabase مع pgvector بالفعل، فإن الانتقال إلى Rememberizer هو أمر سهل بشكل خاص حيث أن كلاهما يستخدم PostgreSQL مع امتداد pgvector.

import psycopg2
import requests
import json
import time
import os
from dotenv import load_dotenv

# تحميل متغيرات البيئة
load_dotenv()

# إعدادات PostgreSQL لـ Supabase
SUPABASE_DB_HOST = os.getenv("SUPABASE_DB_HOST")
SUPABASE_DB_PORT = os.getenv("SUPABASE_DB_PORT", "5432")
SUPABASE_DB_NAME = os.getenv("SUPABASE_DB_NAME")
SUPABASE_DB_USER = os.getenv("SUPABASE_DB_USER")
SUPABASE_DB_PASSWORD = os.getenv("SUPABASE_DB_PASSWORD")
SUPABASE_VECTOR_TABLE = os.getenv("SUPABASE_VECTOR_TABLE", "documents")

# إعداد Rememberizer
REMEMBERIZER_API_KEY = os.getenv("REMEMBERIZER_API_KEY")
VECTOR_STORE_ID = os.getenv("VECTOR_STORE_ID")  # على سبيل المثال، "vs_abc123"
BASE_URL = "https://api.rememberizer.ai/api/v1"

# حجم الدفعة للمعالجة
BATCH_SIZE = 100

# الاتصال بـ Supabase PostgreSQL
def connect_to_supabase():
    try:
        conn = psycopg2.connect(
            host=SUPABASE_DB_HOST,
            port=SUPABASE_DB_PORT,
            dbname=SUPABASE_DB_NAME,
            user=SUPABASE_DB_USER,
            password=SUPABASE_DB_PASSWORD
        )
        return conn
    except Exception as e:
        print(f"خطأ في الاتصال بـ Supabase PostgreSQL: {e}")
        return None

# جلب الوثائق من Supabase pgvector
def fetch_documents_from_supabase(conn, batch_size, offset=0):
    try:
        cursor = conn.cursor()
        
        # قم بتعديل هذا الاستعلام بناءً على هيكل جدولك
        query = f"""
        SELECT id, content, metadata, embedding
        FROM {SUPABASE_VECTOR_TABLE}
        ORDER BY id
        LIMIT %s OFFSET %s
        """
        
        cursor.execute(query, (batch_size, offset))
        documents = cursor.fetchall()
        cursor.close()
        
        return documents
    except Exception as e:
        print(f"خطأ في جلب الوثائق من Supabase: {e}")
        return []

# رفع المستندات إلى Rememberizer
def upload_to_rememberizer(documents):
    headers = {
        "x-api-key": REMEMBERIZER_API_KEY,
        "Content-Type": "application/json"
    }
    
    results = []
    
    for doc in documents:
        doc_id, content, metadata, embedding = doc
        
        # تحليل البيانات الوصفية إذا كانت مخزنة كسلسلة JSON
        if isinstance(metadata, str):
            try:
                metadata = json.loads(metadata)
            except:
                metadata = {}
        elif metadata is None:
            metadata = {}
        
        document_name = metadata.get("filename", f"supabase_doc_{doc_id}")
        
        if not content:
            print(f"تخطي {doc_id} - لم يتم العثور على محتوى")
            continue
            
        data = {
            "name": document_name,
            "content": content,
            "metadata": metadata
        }
        
        try:
            response = requests.post(
                f"{BASE_URL}/vector-stores/{VECTOR_STORE_ID}/documents/text",
                headers=headers,
                json=data
            )
            
            if response.status_code == 201:
                print(f"تم رفع المستند '{document_name}' بنجاح!")
                results.append({"id": doc_id, "success": True})
            else:
                print(f"خطأ في رفع المستند {document_name}: {response.text}")
                results.append({"id": doc_id, "success": False, "error": response.text})
        except Exception as e:
            print(f"استثناء في رفع المستند {document_name}: {str(e)}")
            results.append({"id": doc_id, "success": False, "error": str(e)})
        
        # إضافة تأخير صغير لمنع تحديد المعدل
        time.sleep(0.1)
    
    return results

# دالة الهجرة الرئيسية
def migrate_supabase_to_rememberizer():
    conn = connect_to_supabase()
    if not conn:
        print("فشل الاتصال بـ Supabase. يتم إلغاء الهجرة.")
        return
    
    offset = 0
    total_migrated = 0
    
    print("بدء الهجرة من Supabase pgvector إلى Rememberizer...")
    
    try:
        while True:
            documents = fetch_documents_from_supabase(conn, BATCH_SIZE, offset)
            
            if not documents:
                break
                
            print(f"تم جلب {len(documents)} مستندات من Supabase")
            
            results = upload_to_rememberizer(documents)
            success_count = sum(1 for r in results if r.get("success", False))
            
            total_migrated += success_count
            print(f"التقدم: {total_migrated} مستندات تم هجرتها بنجاح")
            
            offset += BATCH_SIZE
            
    finally:
        conn.close()
    
    print(f"اكتملت الهجرة! {total_migrated} إجمالي المستندات التي تم هجرتها إلى Rememberizer")

# تشغيل الهجرة
# migrate_supabase_to_rememberizer()
const { Pool } = require('pg');
const axios = require('axios');
require('dotenv').config();

// إعدادات PostgreSQL لـ Supabase
const supabasePool = new Pool({
  host: process.env.SUPABASE_DB_HOST,
  port: process.env.SUPABASE_DB_PORT || 5432,
  database: process.env.SUPABASE_DB_NAME,
  user: process.env.SUPABASE_DB_USER,
  password: process.env.SUPABASE_DB_PASSWORD,
  ssl: {
    rejectUnauthorized: false
  }
});

const supabaseVectorTable = process.env.SUPABASE_VECTOR_TABLE || 'documents';

// إعدادات Rememberizer
const rememberizerApiKey = process.env.REMEMBERIZER_API_KEY;
const vectorStoreId = process.env.VECTOR_STORE_ID; // على سبيل المثال، "vs_abc123"
const baseUrl = 'https://api.rememberizer.ai/api/v1';

// إعداد حجم الدفعة
const BATCH_SIZE = 100;

// جلب الوثائق من Supabase pgvector
async function fetchDocumentsFromSupabase(batchSize, offset = 0) {
  try {
    // ضبط هذا الاستعلام بناءً على هيكل جدولك
    const query = `
      SELECT id, content, metadata, embedding
      FROM ${supabaseVectorTable}
      ORDER BY id
      LIMIT $1 OFFSET $2
    `;
    
    const result = await supabasePool.query(query, [batchSize, offset]);
    return result.rows;
  } catch (error) {
    console.error(`خطأ في جلب الوثائق من Supabase: ${error.message}`);
    return [];
  }
}

// رفع الوثائق إلى Rememberizer
async function uploadToRememberizer(documents) {
  const headers = {
    'x-api-key': rememberizerApiKey,
    'Content-Type': 'application/json'
  };
  
  const results = [];
  
  for (const doc of documents) {
    // تحليل البيانات الوصفية إذا كانت مخزنة كسلسلة JSON
    let metadata = doc.metadata;
    if (typeof metadata === 'string') {
      try {
        metadata = JSON.parse(metadata);
      } catch (e) {
        metadata = {};
      }
    } else if (metadata === null) {
      metadata = {};
    }
    
    const documentName = metadata.filename || `supabase_doc_${doc.id}`;
    
    if (!doc.content) {
      console.log(`تخطي ${doc.id} - لم يتم العثور على محتوى`);
      continue;
    }
    
    const data = {
      name: documentName,
      content: doc.content,
      metadata: metadata
    };
    
    try {
      const response = await axios.post(
        `${baseUrl}/vector-stores/${vectorStoreId}/documents/text`,
        data,
        { headers }
      );
      
      if (response.status === 201) {
        console.log(`تم رفع الوثيقة '${documentName}' بنجاح!`);
        results.push({ id: doc.id, success: true });
      } else {
        console.error(`خطأ في رفع الوثيقة ${documentName}: ${response.statusText}`);
        results.push({ id: doc.id, success: false, error: response.statusText });
      }
    } catch (error) {
      console.error(`خطأ في رفع الوثيقة ${documentName}: ${error.message}`);
      results.push({ id: doc.id, success: false, error: error.message });
    }
    
    // إضافة تأخير صغير لمنع تحديد المعدل
    await new Promise(resolve => setTimeout(resolve, 100));
  }
  
  return results;
}

// دالة الهجرة الرئيسية
async function migrateSupabaseToRememberizer() {
  try {
    console.log('بدء الهجرة من Supabase pgvector إلى Rememberizer...');
    
    let offset = 0;
    let totalMigrated = 0;
    
    while (true) {
      const documents = await fetchDocumentsFromSupabase(BATCH_SIZE, offset);
      
      if (documents.length === 0) {
        break;
      }
      
      console.log(`تم جلب ${documents.length} وثيقة من Supabase`);
      
      const results = await uploadToRememberizer(documents);
      const successCount = results.filter(r => r.success).length;
      
      totalMigrated += successCount;
      console.log(`التقدم: ${totalMigrated} وثيقة تم نقلها بنجاح`);
      
      offset += BATCH_SIZE;
    }
    
    console.log(`اكتملت الهجرة! تم نقل ${totalMigrated} وثيقة إجمالاً إلى Rememberizer`);
    
  } catch (error) {
    console.error('فشلت الهجرة:', error);
  } finally {
    await supabasePool.end();
  }
}

// تشغيل الهجرة
// migrateSupabaseToRememberizer();

أفضل الممارسات للهجرة

اتبع هذه التوصيات لهجرة ناجحة:

  1. التخطيط مسبقًا:

    • تقدير حجم البيانات والوقت المطلوب للهجرة

    • جدولة الهجرة خلال فترات انخفاض الحركة

    • زيادة مساحة القرص قبل بدء الهجرات الكبيرة

  2. اختبار أولاً:

    • إنشاء متجر متجهات اختبار في Rememberizer

    • نقل مجموعة صغيرة من البيانات (100-1000 متجه)

    • التحقق من وظيفة البحث باستخدام استعلامات رئيسية

  3. تحقق من البيانات:

    • مقارنة عدد الوثائق قبل وبعد الهجرة

    • تشغيل استعلامات مرجعية لضمان نتائج مماثلة

    • التحقق من أن البيانات الوصفية محفوظة بشكل صحيح

  4. تحسين الأداء:

    • استخدام العمليات الدفعة من أجل الكفاءة

    • النظر في التواجد الجغرافي لقواعد البيانات المصدر والهدف

    • مراقبة حدود معدل واجهة برمجة التطبيقات وضبط أحجام الدفعات وفقًا لذلك

  5. خطوات ما بعد الهجرة:

    • التحقق من إنشاء الفهرس في Rememberizer

    • تحديث تكوينات التطبيق للإشارة إلى متجر المتجهات الجديد

    • الاحتفاظ بقاعدة البيانات المصدر كنسخة احتياطية حتى يتم التحقق من الهجرة

للحصول على مرجع واجهة برمجة التطبيقات المفصل ووثائق نقاط النهاية، قم بزيارة صفحة وثائق تخزين المتجهات.


تأكد من التعامل مع مفاتيح واجهة برمجة التطبيقات بشكل آمن واتباع أفضل الممارسات لإدارة مفاتيح واجهة برمجة التطبيقات.

ما هي تضمينات المتجهات وقواعد بيانات المتجهات؟
إنشاء متجر متجهات جديد
عرض تفاصيل مخزن متجهات
إنشاء مفتاح API جديد
إنشاء متجر متجهات جديد
عرض تفاصيل مخزن متجهات
إنشاء مفتاح API جديد