زوّد 10,000 صفحة شهريًا بصور حقيقية — بـ 500 طلب API فقط

ابحث مرة واحدة لكل عنقود موضوعي بدل مرة لكل صورة، فتتحول 40,000 استدعاء API إلى 500. نمط التجميع والإسناد، والعامل الذي ينجو من حدود المعدّل، وقسم صريح عمّا لا تستطيع الصور إصلاحه.

مشاركة
مكتب مزدحم يعمل فيه زملاء جنبًا إلى جنب على حواسيب فوق مكاتب طويلة مشتركة.
الصورة عبر Unsplash

هناك صيغة من مشكلة تصوير المحتوى لا يحلّها أي قدر من الذوق الرفيع: أنت لا تختار صورة، بل تملأ 40,000 خانة صورة شهريًا عبر 800 عنقود موضوعي، و9 لغات، و14 موقع عميل، وكل واحدة منها يجب أن تكون مرخّصة ومُسندة ومضبوطة الأبعاد ومختلفة عن التي بجانبها. عند هذا الحجم يتوقف السؤال عن أن يكون «أي صورة؟» ويصبح «ما هي البنية؟»

هذا المقال هو الإجابة عبر الـ API: نمط الطلب الذي يقلّص عدد الاستدعاءات بمرتبتين عشريتين، والعامل الذي ينجو من حدود المعدّل، وإزالة التكرار التي تمنع موقعًا من 10,000 صفحة من أن يبدو جدارًا من نفس الصورة — وقسم صريح عمّا لا تستطيع الصور فعله لك.

عنق الزجاجة الحقيقي عند 10,000 مقال

الفرق التي تنشر بكثافة — منظومات السيو البرمجي، وصفحات فئات الأسواق الإلكترونية، والمجمّعات، وشبكات التسويق بالعمولة، والوكالات التي تدير محتوى محفظة من العملاء، وخطوط التوطين التي تحوّل مقالًا واحدًا إلى 20 — كلها تصطدم بالجدران الثلاثة نفسها، وبالترتيب نفسه:

  1. عدد الاستدعاءات. بحث واحد لكل خانة صورة يعني 40,000 استدعاء API لأجل 10,000 مقال بأربع صور لكل منها. كل مزوّد يسعّرك ويقيّدك ويراجعك بناءً على هذا الرقم.
  2. التكرار. عند الصفحة الثلاثين تقريبًا، تبدأ الصورة نفسها بالظهور مجددًا. وعند الصفحة الثلاثة آلاف، يصبح لموقعك بصمة بصرية: مولَّد بالجملة.
  3. التنسيق. مئة مقال في عنقود واحد يجب أن تبدو كسلسلة، لا كمئة لوحة بينتريست غير مترابطة — والنسخة اللغوية التالية من المقال نفسه يجب أن تعيد استخدام الصورة نفسها، لا أن تبحث مجددًا بلغة أخرى.

لاحظ ما هو غير موجود في تلك القائمة: العثور على صورة جيدة. محرّك دلالي يعيد صفحة من المرشّحين القابلين للاستخدام في نحو 130 مللي ثانية. الاسترجاع حُلّ؛ التوزيع لم يُحلّ. كل ما يلي يتعلق بالتوزيع.

لماذا الصور الحقيقية، عند هذا الحجم تحديدًا

الحجة لصالح التصوير مقابل التوليد تصبح أقوى كلما ارتفع الحجم، لأسباب تشغيلية في معظمها أكثر منها جمالية.

عند 40,000 صورة/شهر توليدها البحث عنها
الوقت لكل صورة ثوانٍ إلى دقائق، إضافة إلى المحاولات المرفوضة طلب واحد (~130 مللي ثانية) يغطي عنقودًا كاملًا
محرّك التكلفة لكل صورة، إلى الأبد لكل طلب — وطلب واحد يخدم ~25 مقالًا
البيانات الوصفية التي تحصل عليها لا شيء. تكتب النص البديل والأبعاد بنفسك الأبعاد، اللون السائد، blur hash، مسودة تعليق، سطر الإسناد
المصدر الموثّق موسومة آليًا كاصطناعية بموجب قانون الذكاء الاصطناعي الأوروبي منذ 2 أغسطس 20261 مصوّر باسمه، وتاريخ، ورابط مصدر يستطيع القارئ فتحه
نمط الفشل تفاصيل معقولة لكنها خاطئة، وأسلوب موحّد لا شيء طابق الوصف — تحصل على صفر نتائج، وهو أمر يمكنك معالجته

صف البيانات الوصفية هو الذي يحسم خطوط الإنتاج. كل نتيجة بحث تحمل أصلًا width وheight وblur_hash وcolor_hex وalt_description وسلسلة attribution.html جاهزة — وهي تحديدًا الحمولة التي يحتاجها محرّك القوالب لإخراج <img> بلا انزياح تخطيط، مع عنصر نائب وسطر إسناد. الصور المولّدة تعطيك ملفًا وتترك لك اختراع الحقول الستة الأخرى.

أين يبقى التوليد متفوقًا عند التوسّع. التصوير على مستوى الفئات في التصنيفات المجردة («ترحيل السحابة»، «صناديق المؤشرات»)، والرسوم التوضيحية، والأسلوب البصري الذي تريده مكرّرًا عبر منظومة كاملة لأسباب تتعلق بالعلامة. التقسيم الذي يستقر عليه معظم الناشرين الكبار: الصور الفوتوغرافية لكل ما يوجد في العالم، والفن المولّد لكل ما لا يوجد إلا في حجّة. عرضنا الحجة الكاملة لهذا التقسيم في كيف تُصوّر كل مقال تنشره.

طلب واحد، مئة صورة

هذا هو التغيير الوحيد الذي يعيد تشكيل الحساب. نقطة نهاية البحث تقبل per_page حتى 100، وترقيم المؤشّر يتيح لك مواصلة السير عبر مجموعة النتائج المرتّبة نفسها. لذا فوحدة العمل ليست صورة، بل مخزون.

طلب واحد ← مخزون لعنقود كامل
curl -sG "https://api.pexafy.com/api/v1/search/photos" \
  -H "X-Api-Key: $PEXAFY_API_KEY" \
  --data-urlencode "q=a woman signing paperwork with an insurance agent at a kitchen table in her home" \
  --data-urlencode "per_page=100" \
  --data-urlencode "orientation=landscape" \
  --data-urlencode "score_threshold=0.5" \
  --data-urlencode "fields=photo_id,urls,width,height,blur_hash,alt_description,attribution"

# → { "success": true, "data": [ …حتى 100 صورة… ],
#     "pagination": { "per_page": 100, "has_more": true, "next_cursor": "eyJyc…" },
#     "meta": { "took_ms": 122.33, "request_id": "7ff1fb9b-…" } }

ثلاثة معاملات هناك تؤدي عملًا صامتًا عند التوسّع:

  • fields — مجموعة حقول مقتضبة. اطلب الحقول السبعة التي يعرضها قالبك ويتوقف الرد عن شحن الوصف الطويل لكل صورة. عبر 40,000 صورة، هذا هو الفرق بين بناء ينساب وآخر يستخدم ذاكرة التبديل.
  • score_threshold — ذيل صفحة من 100 نتيجة هو، بحكم التعريف، أقل صلة من رأسها. وضع حدّ أدنى يعني أن عنقودًا ضعيفًا يعيد 34 صورة بدل 100 صورة متوسطة، ويستطيع خط إنتاجك التفاعل مع ذلك بدل نشره.
  • next_cursor — حين يحتاج عنقود فعليًا إلى 300 صورة، رقّم المجموعة المرتّبة نفسها بدل إطلاق ثلاثة استعلامات مختلفة متداخلة.

وإليك الحساب، لموقع ينشر 10,000 صفحة شهريًا بأربع صور لكل منها:

الاستراتيجية الطلبات / الشهر مرور واحد عند حد معدّل الخطة المجانية20 طلب/دقيقة هل تدخل ضمن الحصة الشهرية المجانية؟
بحث واحد لكل خانة صورة 40,000 33 hours لا — خطة مدفوعة
بحث واحد لكل مقال 10,000 8 hours لا — خطة مدفوعة
بحث واحد لكل عنقود من ~20 مقالًاالنمط المطروح في هذا المقال 500 25 minutes نعم

نفس الـ 40,000 صورة منشورة في الصفوف الثلاثة. الشيء الوحيد الذي تغيّر هو موضع الحلقة.

التجميع والتوزيع: النمط القابل للتوسّع

البنية كلها مرحلتان تعملان بترددين مختلفين، مع جدول بينهما:

شكل المعمارية
                     ┌────────── تعمل أسبوعيًا، ~500 طلب ──────────┐
  topic clusters ──▶ POOL   بحث مرة لكل عنقود، per_page=100
                     │       └─▶ خزّن 100 صف صورة لكل عنقود
                     └──────────────────┬───────────────────────────────┘
                                        ▼
                              image_pool table
                        (cluster, photo_id, urls, blur_hash,
                         alt, credit, used_by_page, used_at)
                                        │
                     ┌──────────────────┴──── تعمل عند كل نشر، 0 طلب ───┐
  article ─────────▶ ASSIGN  اختر أفضل صف غير مستخدم لهذا
                     │        العنقود، علّمه مستخدمًا، واعرضه
                     └────────────────────────────────────────────────────────┘

ما يمنحك إياه هذا، مرتّبًا بحسب أهميته عند الحجم الكبير:

  1. النشر لا يتوقف أبدًا بانتظار API. التوزيع قراءة من قاعدة بيانات. خطّاف الحفظ في نظام إدارة المحتوى، والبناء الثابت، والاستيراد الجماعي في الثالثة فجرًا، كلها تعمل بسرعة محلية، دون اتصال، وبلا أي حد معدّل في المسار.
  2. إزالة التكرار مجانية ودقيقة. used_by_page IS NULL هي الميزة كاملة. لا تستطيع صفحتان سحب الصورة نفسها، لأن التوزيع معاملة، لا استدلال ترتيب.
  3. إعادة التشغيل رخيصة وغير تراكمية الأثر. جدّد مخزون عنقود حين ينخفض أو حين تريد تصويرًا أحدث (after_date، أو sort_by=newest) — طلب واحد، ولا يتحرك شيء منشور سلفًا.
  4. اللغات تأتي مجانًا. الترجمات العشرون لمقال هي صفحة واحدة في نموذجك بعشرين عرضًا؛ تتشارك الـ photo_id الموزّع ولا تبحث مرتين أبدًا. وحين تريد فعلًا مظهرًا مصوّرًا محليًا، شغّل استعلام المخزون لذلك العنقود باللغة الهدف — المحرك يقبل جملة بأكثر من 100 لغة.

العامل، في الشيفرة

ستون سطرًا تقريبًا. مالئ المخزون هو الجزء الوحيد الذي يتخاطب مع الشبكة، لذا هو الجزء الوحيد الذي يحتاج إلى حذر — تزامن محدود، احترام لـ 429، ونتائج تُكتب في معاملة واحدة.

pool.py — املأ مخزونًا واحدًا لكل عنقود، بأدب
import asyncio, os, time, httpx

SEARCH = "https://api.pexafy.com/api/v1/search/photos"
KEY    = os.environ["PEXAFY_API_KEY"]
FIELDS = "photo_id,urls,width,height,blur_hash,alt_description,attribution"

# Free = 20 طلب/دقيقة. ابقَ أقل بواحد. المنظّم عام: نوم لكل مهمة
# داخل بوابة التزامن يجعل N عاملًا يطلقون N× المعدّل.
PER_MIN = 19
gate    = asyncio.Semaphore(4)         # اتصالات جارية
_lock   = asyncio.Lock()
_slot   = 0.0                          # اللحظة الحرة التالية على الخط المشترك

async def pace():
    """Hand out one request slot every 60/PER_MIN seconds, fleet-wide."""
    global _slot
    async with _lock:
        now  = time.monotonic()
        _slot = max(now, _slot) + 60 / PER_MIN
        wait  = _slot - now
    if wait > 0:
        await asyncio.sleep(wait)

class QuotaExhausted(Exception): ...   # شهري: الإعادة لا تنفع

async def fill_pool(client, cluster) -> list[dict]:
    """One request → up to 100 credited photos for one topic cluster."""
    for attempt in range(4):
        await pace()
        async with gate:
            r = await client.get(
                SEARCH,
                headers={"X-Api-Key": KEY},
                params={
                    "q": cluster["camera_brief"],   # مشهد، لا كلمة مفتاحية
                    "per_page": 100,
                    "orientation": "landscape",
                    "score_threshold": 0.5,
                    "fields": FIELDS,
                },
                timeout=15,
            )
        if r.status_code == 429:
            retry_after = r.headers.get("Retry-After")
            if retry_after is None:            # بلا Retry-After ⇐ حصة شهرية،
                raise QuotaExhausted(cluster["id"])   # أوقف التشغيل كله
            await asyncio.sleep(int(retry_after))   # لكل دقيقة: تنقضي
            continue
        r.raise_for_status()
        return r.json()["data"]
    return []                                  # سجّلها؛ المخزون يحتفظ بصفوفه القديمة

async def refill(clusters):
    async with httpx.AsyncClient(http2=True) as client:
        pools = await asyncio.gather(*(fill_pool(client, c) for c in clusters))
    for cluster, photos in zip(clusters, pools):
        db.upsert_pool(cluster["id"], photos)     # ON CONFLICT DO NOTHING على photo_id

تفصيلان هناك هما الفرق بين عامل يعمل بلا إشراف وآخر يوقظك ليلًا. المنظّم عام، لا لكل مهمة: وضع النوم داخل بوابة التزامن هو الخطأ الكلاسيكي — أربعة عمّال يتوقف كل منهم 3 ثوانٍ بعد طلبه الخاص ينتجون أربعة طلبات كل 3 ثوانٍ، أي نحو 75 في الدقيقة، والخطة المجانية تبدأ بإعادة 429 فورًا. كما أن الـ 429 ليسا من النوع نفسه: تلك الخاصة بالدقيقة تحمل Retry-After وتنقضي بنفسها، أما تلك الخاصة بالحصة الشهرية فلا تحملها ولن تحملها — وإعادة المحاولة معها حلقة أمام جدار.

أما التوزيع، الجزء الذي يعمل عند كل نشر، فلا يلمس الشبكة أبدًا:

assign.py — حتمي، معامَلاتي، بلا تكرار في أي مكان
# التفرّد يفرضه المخطط، لا حذر الاستعلام.
# قد تكون الصورة في عدة مخزونات عناقيد؛ لكنها تُنشر مرة واحدة فقط.
# CREATE UNIQUE INDEX one_use_per_photo ON image_pool (photo_id)
#        WHERE used_by_page IS NOT NULL;

def assign_hero(page_id: str, cluster_id: str) -> dict | None:
    for _ in range(5):                # خسارة السباق تعني أخذ الصورة التالية
        try:
            return db.query_one("""
                UPDATE image_pool p SET used_by_page = %s, used_at = NOW()
                WHERE p.id = (
                    SELECT c.id FROM image_pool c
                    WHERE c.cluster_id = %s AND c.used_by_page IS NULL
                      AND NOT EXISTS (              -- مستخدمة في أي عنقود آخر؟
                          SELECT 1 FROM image_pool u
                          WHERE u.photo_id = c.photo_id
                            AND u.used_by_page IS NOT NULL
                      )
                    ORDER BY c.rank ASC
                    LIMIT 1 FOR UPDATE SKIP LOCKED  -- آمن مع عمّال متوازين
                )
                RETURNING photo_id, urls, width, height, blur_hash, alt, credit
            """, [page_id, cluster_id])
        except UniqueViolation:      # عنقودان طلباها في المللي ثانية ذاتها
            continue
    return None                     # المخزون نفد ← وسّع الوصف، وأعد الملء

# العرض: كل سمة تأتي من الصف — لا انزياح تخطيط، ولا تخمين.
# <img src="{urls[regular]}" width="{width}" height="{height}"
#      alt="{alt}" loading="lazy" style="background:{blur_placeholder}">
# <figcaption>{credit}</figcaption>

نمطا فشل، وآليتان، وكلتاهما ضرورية. FOR UPDATE SKIP LOCKED يعالج التزامن داخل العنقود: ولّد الصفحات بالتوازي — وستفعل عند هذا الحجم — وسيمتد عاملان إلى الصورة الأعلى ترتيبًا نفسها في المللي ثانية ذاتها.

أما الفهرس الفريد الجزئي فيعالج ما ينساه الجميع: الصورة نفسها تظهر بشكل مشروع في مخزونات عدة عناقيد، لأن العناقيد المتجاورة («تأمين المنزل للمستأجرين»، «…للمالكين») تعيد نتائج متداخلة. فحص used_by_page IS NULL على مستوى العنقود أعمى عن ذلك — كل عنقود يظن الصورة متاحة. الـ NOT EXISTS يبقي الاستعلام صادقًا، والفهرس يجعل الخطأ مستحيلًا تحت التزامن: خاسر السباق يحصل على انتهاك، يعيد المحاولة، ويأخذ الصورة التالية. من دونه، «لا تتشارك صفحتان صورة رئيسية» ادّعاء لا ضمان.

حين ينفد مخزون في منتصف البناء، فإن أفضل بديل سلوكًا هو التوسيع لا التكرار: احذف الجملة الأخيرة من وصف المشهد، وأعد تشغيل استعلام المخزون مرة واحدة، وعندها فقط أعد استخدام أقدم صورة موزّعة — مع قاعدة صارمة بألا تنزل على صفحة في العنقود نفسه.

عنقود واحد، مخزون واحد: استعلام حقيقي

خذ منظومة مقارنات: تأمين المنزل، عشرون صفحة — «تأمين المنزل للمستأجرين»، «…للمالكين»، «ما تغطّيه الوثيقة فعليًا»، اثنتا عشرة صفحة مدن، وثلاثة أدلة مطالبات. وصف مشهد واحد للعنقود، وطلب واحد، وهذا هو رأس المخزون، مُعادًا في 122 مللي ثانية:

GET /search/photos — “a woman signing paperwork with an insurance agent at a kitchen table in her home” · 122 ms
رأس المخزون: ستة مشاهد مختلفة من مجموعة نتائج مرتّبة واحدة — توقيع، استمارة عن قرب، وثيقة تُشرح، أوراق على مكتب، زوجان مع وكيل، ومقارنة على فنجان قهوة. هذه ستّ من العشرين صفحة مغطّاة سلفًا؛ وطلب التجميع يطلب per_page=100 ويحتفظ بالباقي. شغّل هذا البحث بالضبط →

الأوصاف أهم من الشيفرة. قاعدتان تصمدان أمام منظومة عناقيد حقيقية: اكتب الوصف لأجل العنقود، لا لأجل الصفحة (عناوين الصفحات شبه متطابقة في المجموعات البرمجية، فالأوصاف لكل صفحة تعيد صورًا شبه متطابقة)، وصف مشهدًا يمكن لكاميرا أن تلتقطه بدل الموضوع — home insurance يعيد لقطات قريبة للمستندات ولا شيء غيرها. نشرنا الموجّه القابل للنسخ الذي ينتج هذه الأوصاف في مقال تصوير كل منشور.

الحفاظ على تماسك بصري في سلسلة من 200 صفحة

الفشل المعاكس للتكرار هو التفكك: عشرون صفحة في عنقود واحد، لكل منها صورة صحيحة تقنيًا، في عشرين سجلًا بصريًا مختلفًا. الحل نقطة نهاية واحدة — GET /photos/{id}/similar — تُشغَّل مرة على الصورة التي اعتمدتها للصفحة الأساسية:

GET /photos/019e143f…/similar — المزيد مثل الصورة الرئيسية المعتمدة · 48 ms
الإضاءة نفسها، والغرفة نفسها، والملابس نفسها، ولحظات مختلفة — لأن التشابه البصري يجد بقية جلسة المصوّر، لا الموضوع نفسه فحسب. وزّع هذه عبر عنقود وستُقرأ السلسلة كأنها مصوّرة بتكليف لا مجمّعة.

رافعتان إضافيتان تستحقان الربط في استعلام المخزون حين يكون اتساق العلامة مطلبًا: color_hex مع color_tolerance يُبقي منظومة كاملة داخل لوحة ألوان، وphotographer يثبّت عنقودًا على أعمال مصوّر واحد. وكلاهما معاملا استعلام عاديان — لا تقييد بحسب الخطة على مرشّحات البحث.

حدود المعدّل والحصص والتكلفة الفعلية

اختر الخطة بناءً على الاندفاع، لا على الحجم. بمجرد أن تجمّع، تتوقف الحصة الشهرية عن كونها القيد لدى الجميع تقريبًا؛ ما يحدد خطتك هو السرعة التي يجب أن ينتهي بها التحديث الكامل.

الخطة الطلبات / الشهر= العناقيد القابلة للتحديث حد المعدّل مفاتيح API تحديث 1,000 عنقودزمن فعلي، مرور واحد
Free — $0 5,000 20 / دقيقة 1 50 min
Starter — $5 25,000 30 / دقيقة 3 34 min
Pro — $19 100,000 60 / دقيقة 5 17 min
Team — $99الوكالات: مفتاح لكل عميل 500,000 200 / دقيقة 25 5 min
Business — $249 1,000,000 300 / دقيقة unlimited 4 min
Enterprise — $599 2,000,000 500 / دقيقة unlimited 2 min

اقرأ العمود الأول بوصفه عناقيد: طلب تجميع واحد يملأ عنقودًا واحدًا، فالحصة الشهرية هي عدد العناقيد التي يمكنك تحديثها، والعمود الأخير هو المدة التي يستغرقها مرور كامل على منظومة من 1,000 عنقود عند حد معدّل تلك الخطة. وكلاهما قيم حيّة من كتالوج التسعير — وصفحة التسعير تذكر حدود المعدّل نفسها لكل ساعة بدل كل دقيقة.

إذًا فمنظومة تنشر 10,000 صفحة شهريًا وفق نمط التجميع تنفق ~500 طلب ولا تدفع شيئًا. ما يدفع الفرق إلى أعلى الجدول نادرًا ما يكون الحجم — بل أحد ثلاثة أمور: إعادة تصوير كاملة لمنظومة قائمة في ليلة واحدة، أو عزل المفاتيح لكل عميل (وكالة تريد مفتاحًا لكل عميل ليكون الاستخدام منسوبًا دون ألاعيب الأسرار المشتركة)، أو نافذة بناء تُقاس بالدقائق لا بالساعات.

تفصيلان تشغيليان يوفّران ليلة من التصحيح. كل رد يحمل X-RateLimit-Limit وX-RateLimit-Remaining، فيستطيع العامل ضبط إيقاعه بنفسه بدل التخمين. و429 الذي يمثل حدًا فعليًا لكل دقيقة يحمل Retry-After، في حين أن حجب الحصة الشهرية لا يحمله عمدًا — إعادة المحاولة لن تحلّ ذلك، والعامل الذي يميّز بينهما يتوقف عن قرع نقطة نهاية لم يبقَ لديها ما تعطيه.

حين يتولى الوكيل النشر

إن كان محتواك ينتجه وكيل — وعند هذه الأحجام يتزايد ذلك — فطبقة التجميع لا تختفي، بل تنتقل. أعطِ الوكيل أدوات البحث فيملأ المخزون بينما لا يزال وصف العنقود حاضرًا في سياقه، مستخدمًا خادم Model Context Protocol على mcp.pexafy.com/mcp: ثلاث أدوات، search_photos (جملة)، وsearch_photos_by_image (صورة مرجعية، مع جملة اختياريًا) وget_similar_photos (أداة تماسك السلسلة المذكورة أعلاه).

اربطه بوكيل بلا واجهة — موصّل واحد، مفتاح واحد
# Claude Code / منفّذ CI
claude mcp add --transport http pexafy https://mcp.pexafy.com/mcp \
  --header "Authorization: Bearer $PEXAFY_API_KEY"

# أو أودِع .mcp.json ليرثه كل عامل في الأسطول
{
  "mcpServers": {
    "pexafy": {
      "type": "http",
      "url": "https://mcp.pexafy.com/mcp",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}

التعليمة التي تنجح عند التوسّع هي تعليمة دفعية، لا تعليمة لكل مقال — وهي تنطبق واحدة بواحدة على المرحلتين أعلاه:

تحديث عنقود، يقوده الوكيل
You  إليك 12 عنقودًا موضوعيًا من تقويم المحتوى. لكل واحد،
     اكتب وصف مشهد واحدًا، واسحب 100 صورة أفقية، واكتب
     المخزون إلى Postgres. أشِر إلى أي عنقود يعيد أقل من 40
     نتيجة فوق 0.5 — تلك الأوصاف تحتاج إعادة كتابة.

Agent  → search_photos(q="a woman signing paperwork with an insurance
           agent at a kitchen table in her home", orientation="landscape")
      ← 100 صورة · 122 مللي ثانية · 87 فوق العتبة
      … 11 عنقودًا آخر …

      ✓ كُتب 11 مخزونًا (1,043 صورة، جميعها مُسندة)
      ⚠ "index fund rebalancing" ← 12 نتيجة. الوصف مجرّد؛
        الاقتراح: "a person at a kitchen table checking figures on a
        laptop with a notebook and coffee beside them"

ذلك السطر الأخير هو سبب وضع الوكيل في هذه الحلقة بدل سكربت: نمط الفشل في التصوير البرمجي هو وصف سيئ، والوصف السيئ هو تحديدًا ما يستطيع نموذج لغوي ملاحظته وإعادة كتابته. تبقى السكربتات مسؤولة عن التوزيع، حيث تهم الحتمية ولا يهم الإبداع.

ما لا تستطيع الصور إصلاحه

قسم صريح، لأن الفشل الذي يصفه مكلف. التصوير الحقيقي المُسند يحسّن الصفحة. لكنه لا يحوّل المحتوى الضحل إلى محتوى جيد، ولا يغيّر أي خط إنتاج صور طريقة تعامل محركات البحث مع الصفحات المنتجة بالجملة التي وُجدت للتصدّر لا للإفادة. سياسات جوجل ضد السبام تسمّي هذا مباشرة: إساءة استخدام المحتوى واسع النطاق تشمل توليد صفحات كثيرة ذات قيمة ضئيلة سواء استُخدمت الأتمتة أم لا، والصور في تلك الصفحات لا علاقة لها بهذا الحكم.2

لذا فالتأطير المفيد ضيّق وصحيح: التصوير إشارة جودة تتحكم بها على صفحات تستحق أصلًا أن توجد. وحيث يؤتي ثماره بوضوح:

  • مصدر يستطيع القارئ التحقق منه. سطر إسناد باسم مصوّر ورابط مصدر هو ادّعاء قابل للتحقق — عكس صورة بلا إسناد على صفحة بمؤلف بلا إسناد.
  • إمكانية الوصول ومؤشرات Core Web Vitals. width/height من الرد يقضيان على انزياح التخطيط، وblur_hash يعطي عنصرًا نائبًا حقيقيًا، و alt_description مسودة لنص بديل يستطيع قالبك تحسينها بدل اختراعها. اضربها في 40,000 خانة وستحصل على قصة جودة الصور كاملة في الموقع.
  • ألا تبدو منتَجًا بالجملة. إزالة التكرار وتماسك السلسلة هما ما يمنع منظومة من امتلاك بصمة بصرية. تلك كلفة إدراكية حقيقية بعواقب حقيقية، وهي بالكامل تحت سيطرتك.

ويبقى الترخيص هو الحاكم للصورة. الإسناد غير مطلوب بموجب شروط Pexafy API — فكل نتيجة تُشحن مع attribution.html وattribution.plain جاهزين للعرض — لكن الترخيص المرفق من المكتبة الأصلية ينطبق على استخدامك لتلك الصورة، وعند 40,000 صورة شهريًا يكون عرض الإسناد تلقائيًا أرخص من التدقيق لاحقًا.

من أين تبدأ يوم الاثنين

  1. جمّع قائمة أعمالك في عناقيد من 15–30 صفحة يمكن أن تتشارك منطقيًا جلسة تصوير واحدة. هذه هي الخطوة اليدوية الوحيدة فعلًا، وهي جدول بيانات لا مشروع.
  2. اكتب وصف مشهد واحدًا لكل عنقود — مشهد، من 12 إلى 25 كلمة. ولّدها بنموذج، ثم اقرأها؛ الأوصاف التي تسمّي موضوعًا بدل مشهد تظهر من نظرة واحدة.
  3. املأ مخزونًا واحدًا بطلب per_page=100 واحد وتفحّص رأسه. إن لم تكن العشر الأولى قابلة للاستخدام، فالوصف خاطئ — لا المحرّك.
  4. أضف عمود used_by_page قبل أن تنشر أي شيء. إنه خمس دقائق الآن، أو ترحيل عبر 3,000 صفحة حيّة لاحقًا.
  5. شغّل كل ذلك على الخطة المجانية حتى تدفعك نافذة بناء إلى الأعلى. وعند 500 طلب شهريًا، سيستغرق ذلك وقتًا.

المراجع & الحواشي

1 قانون الذكاء الاصطناعي الأوروبي، المادة 50 — التزامات الشفافية السارية من 2 أغسطس 2026: على مزوّدي الأنظمة التي تولّد صورًا أو صوتًا أو فيديو أو نصًا اصطناعيًا وسم المخرجات بصيغة مقروءة آليًا وجعلها قابلة للكشف كمولّدة اصطناعيًا. وهو يلزم مزوّدي ومشغّلي الذكاء الاصطناعي؛ وليس قاعدة بشأن الصور التي يجوز لموقع نشرها.

2 سياسات جوجل للبحث ضد السبام — إساءة استخدام المحتوى واسع النطاق: توليد صفحات كثيرة أساسًا للتلاعب بالترتيب مع تقديم قيمة ضئيلة للمستخدمين، سواء أُنشئت بالأتمتة أو بجهد بشري أو بمزيج منهما. جودة الصور ليست عاملًا في ذلك التقييم، وهو تحديدًا سبب فصل هذا المقال بين الأمرين.

الأسئلة الشائعة

كيف أحصل على صور لآلاف صفحات السيو البرمجي؟
ابحث مرة واحدة لكل عنقود موضوعي، لا مرة لكل صفحة. طلب واحد GET /api/v1/search/photos مع per_page=100 يُرجع حتى 100 صورة منسوبة لأصحابها لعنقود واحد؛ تخزّنها في جدول مجمّع وتُسند صورة لكل صفحة عند النشر. منظومة من 10,000 صفحة شهريًا بأربع صور لكل صفحة تحتاج نحو 500 طلب بدل 40,000، وهو ما يندرج ضمن الخطة المجانية (5,000 طلب/شهر).
ما أفضل واجهة برمجية للصور المخزنة لإنتاج المحتوى بكميات كبيرة؟
المعايير المهمة فوق بضعة آلاف صورة شهريًا هي: كم صورة يمكن أن يُرجعها الطلب الواحد، وهل تعود عدة مكتبات في مخطط موحّد واحد، وحد المعدّل في الدقيقة، وهل تُشترط مراجعة للتطبيق قبل الوصول الإنتاجي. تُرجع Pexafy حتى 100 صورة لكل طلب عبر 9 مكتبات مجانية في مخطط واحد، وتمنح مفتاحًا فعّالًا فورًا، وتتيح 20 طلبًا/دقيقة في الخطة المجانية وحتى 300/دقيقة في خطة Business. نقارن كل واجهة مجانية وفق هذه المعايير في مقال مخصص.
كيف أمنع ظهور الصورة نفسها على عدة صفحات؟
خزّن photo_id لكل صورة تنشرها واحجز الصور من المجمّع ضمن معاملة — في SQL، عبر UPDATE … WHERE used_by_page IS NULL … FOR UPDATE SKIP LOCKED. عندئذٍ تصبح إزالة التكرار دقيقة لا احتمالية، ولا يمكن لعمّال البناء المتوازين التسابق على الصورة الأعلى ترتيبًا نفسها. إنه عمود واحد، وإضافته لاحقًا عبر آلاف الصفحات الحية أغلى بكثير من إضافته في اليوم الأول.
كم صورة يمكن أن يُرجعها طلب API واحد؟
حتى 100، عبر per_page=100، ويتيح لك الترقيم بالمؤشّر مواصلة التنقل داخل مجموعة النتائج المرتّبة نفسها لبناء مجمّعات أعمق. اجمعه مع score_threshold ليُرجع العنقود الضعيف 40 نتيجة قوية بدل 100 نتيجة فضفاضة، ومع fields لإرجاع السمات التي يعرضها قالبك فقط، ما يبقي الاستجابات صغيرة عند الحجم الكبير.
هل تساعد الصور الحقيقية الصفحات المنتَجة على نطاق واسع في تحسين ترتيبها؟
لا — ومن المهم الدقة هنا. تعرّف سياسات جوجل لمكافحة السبام إساءة استخدام المحتوى واسع النطاق بأنها إنتاج صفحات كثيرة أساسًا للتلاعب بالترتيب مع قيمة ضئيلة للمستخدمين، سواء استُخدمت الأتمتة أم لا؛ والصور في تلك الصفحات لا تغيّر هذا التقييم. التصوير الحقيقي المنسوب لأصحابه إشارة جودة على صفحات تستحق الوجود أصلًا: فهو يحمل مصدرًا قابلًا للتحقق، ويوفّر العرض والارتفاع وblur hash والنص البديل التي تحمي مؤشرات Core Web Vitals وإتاحة الوصول، ويمنع المنظومة من أن تبدو منتَجة بالجملة.
هل يمكن لوكيل ذكاء اصطناعي ملء مجمّع الصور تلقائيًا؟
نعم، عبر خادم MCP (Model Context Protocol) المستضاف لدى Pexafy على mcp.pexafy.com/mcp، الذي يتيح search_photos وsearch_photos_by_image وphoto_similar. أعطِ الوكيل قائمة بالعناقيد فيكتب موجزًا تصويريًا لكل واحد، ويسحب المجمّعات، ويعلّم الموجزات التي أعادت عددًا قليلًا جدًا من النتائج القوية — وهو نمط الفشل الفعلي في التصوير البرمجي. أما الإسناد فيبقى داخل سكربتاتك، حيث تفوق الحتمية أهميةَ الإبداع.

توقّف عن البحث عن الكلمات المفتاحية. صِف ما تقصده.

ابحث في 9M+ صورة مجانية الاستخدام بالمعنى — بأي لغة، في أقل من 100 مللي ثانية.