توليد أوراق البيانات: إنشاء ملفات PDF عند الطلب وعن طريق الدُفعات

تشرح هذه المقالة كيفية إنشاء أوراق بيانات المنتجات كملفات PDF، سواء عند الطلب (عندما يطلبها المستخدمون) أو عن طريق الدُفعات (الإنشاء المُسبق للمنتجات الشائعة).

المشكلة: إنشاء أوراق بيانات المنتجات

كل منتج يحتاج إلى ورقة بيانات PDF احترافية تحتوي على:

  • اسم المنتج والصور

  • المواصفات الفنية مجمعة حسب الفئة

  • هوية الشركة التجارية ومعلومات الاتصال

  • تخطيط مُحسّن (صفحة واحدة، أعمدة متوازنة)

إنشاء ملفات PDF عند كل طلب بطيء (~2 ثانية لكل PDF). الإنشاء المُسبق لجميع 65,000 SKU يهدر مساحة التخزين والوقت.

الحل: النهج الهجين

نستخدم طريقتين للإنشاء:

عند الطلب: إنشاء PDF عندما يطلبه المستخدم (لأول مرة)

عن طريق الدُفعات: الإنشاء المُسبق لملفات PDF للمنتجات الشائعة (ليلياً)

الإنشاء عند الطلب

هيكل URL

/ds/<sku>.pdf
/ds/<sku>

كلا الرابطين يولدان نفس ملف PDF.

تدفق الطلب

@web.route("/ds/<sku>.pdf")
def datasheet(sku: str):
    # التحقق من صحة SKU
# ... (تفاصيل التنفيذ محذوفة)

عملية الإنشاء

الخطوة 1: الحصول على بيانات المنتج

# اسم المنتج
name = expand_sku(sku)

# ... (تفاصيل التنفيذ محذوفة)

الخطوة 2: موازنة الأعمدة

يتم توزيع الميزات عبر 3 أعمدة لموازنة عدد الأسطر:

# حساب الأسطر لكل مجموعة ميزات
all_groups = []
for heading, f_items in features.items():
# ... (تفاصيل التنفيذ محذوفة)

الخطوة 3: حساب ارتفاعات الصور

# ارتفاع الصورة الرئيسية (نسبي إلى نسبة العرض إلى الارتفاع)
with Image.open(main_image_path) as img:
    main_width, main_height = img.size
# ... (تفاصيل التنفيذ محذوفة)

الخطوة 4: حساب المسافة الفاصلة

دفع التذييل إلى أسفل الصفحة:

available_height = 25.0  # سم
content_height = total_image_height + text_height_cm
spacer_height = max(0, available_height - content_height)

الخطوة 5: عرض HTML

html = render_template(
    "datasheet.html",
    sku=sku,
# ... (تفاصيل التنفيذ محذوفة)

الخطوة 6: إنشاء PDF

options = {
    "page-size": "A4",
    "enable-local-file-access": None,
    "load-error-handling": "ignore",
    "load-media-error-handling": "ignore",
    "no-stop-slow-scripts": None
}

pdf_data = pdfkit.from_string(html, options=options)

الخطوة 7: الاحتفاظ بالصفحة الأولى فقط

reader = PdfReader(BytesIO(pdf_data))
if len(reader.pages) > 1:
    writer = PdfWriter()
    writer.add_page(reader.pages[0])
    output = BytesIO()
    writer.write(output)
    pdf_data = output.getvalue()

الأداء

وقت الإنشاء: ~2 ثانية لكل PDF

التخزين المؤقت: لا يوجد تخزين مؤقت (دائماً حديث)

الفائدة: دائماً محدث بأحدث بيانات المنتج

الإنشاء عن طريق الدُفعات

الغرض

الإنشاء المُسبق لملفات PDF للمنتجات الشائعة لتقليل الحمل عند الطلب.

موقع النص البرمجي

scripts/utils/generate_datasheets.py

تتبع التغييرات

نتتبع التغييرات في أقسام productdb.json ذات الصلة بكل SKU:

def get_sku_productdb_hash(sku: str) -> str:
    """الحصول على تجزئة أقسام productdb ذات الصلة بهذا SKU."""
    with open(PRODUCTDB_PATH, "r") as f:
# ... (تفاصيل التنفيذ محذوفة)

تحديد الأولويات

نحدد أولوية SKUs حسب تكرار الطلب:

def load_popular_skus() -> List[str]:
    """تحميل SKUs الشائعة من سجلات الوصول."""
    try:
# ... (تفاصيل التنفيذ محذوفة)

استراتيجية الإنشاء

def batch_generate():
    # تحميل ذاكرة التخزين المؤقت للتجزئة
    hash_cache = load_hash_cache()
# ... (تفاصيل التنفيذ محذوفة)

الجدولة

يعمل الإنشاء عن طريق الدُفعات ليلاً عبر cron:

0 2 * * * cd /home/ubuntu/manage && python scripts/utils/generate_datasheets.py

التخزين

المحلي: /home/ubuntu/web-static/ds/<sku>.pdf

S3: s3://thinvent-web-static/ds/<sku>.pdf

شبكة توصيل المحتوى (CDN): يتم تقديمه عبر CloudFront

هيكل القالب

يستخدم قالب ورقة البيانات تخطيطاً مكوناً من 3 أعمدة:

<div class="container">
  <!-- الرأس مع الشعار واسم المنتج -->
  <div class="header">
    <img src="logo.png">
    <h1>{{ name }}</h1>
  </div>

  <!-- الصورة الرئيسية -->
  <img src="{{ images[0][1] }}" style="width: 9.5cm">

  <!-- الصور المصغرة (حتى 4) -->
  <div class="thumbnails">
    {% for name, url in images[1:5] %}
      <img src="{{ url }}" style="width: 4.5cm">
    {% endfor %}
  </div>

  <!-- الميزات في 3 أعمدة -->
  <div class="features">
    <div class="column">
      {% for heading, items in features1 %}
        <h3>{{ heading }}</h3>
        {% for name, value in items.items() %}
          <div><strong>{{ name }}:</strong> {{ value }}</div>
        {% endfor %}
      {% endfor %}
    </div>

    <div class="column">
      <!-- features2 -->
    </div>

    <div class="column">
      <!-- features3 -->
    </div>
  </div>

  <!-- المسافة الفاصلة لدفع التذييل للأسفل -->
  <div style="height: {{ spacer_height }}cm"></div>

  <!-- التذييل مع معلومات الاتصال -->
  <div class="footer">
    <p>www.thinvent.in | sales@thinvent.in | +91-124-4343177</p>
  </div>
</div>

التكوين

تتحكم الثوابت في التخطيط:

DATASHEET_COLUMN_COUNT = 3
DATASHEET_HEADING_LINE_WEIGHT = 2  # الأسطر لكل عنوان
DATASHEET_FEATURE_NAME_MAX_LEN = 30  # الأحرف قبل الالتفاف
DATASHEET_FEATURE_VALUE_CHARS_PER_LINE = 40  # أحرف لكل سطر
PDF_PAGE_SIZE = "A4"

نقاط التكامل

صفحات المنتجات

رابط إلى ورقة البيانات:

<a href="/ds/{{ sku }}.pdf" target="_blank">تنزيل ورقة البيانات</a>

Google Shopping

أوراق البيانات مرتبطة في خلاصة المنتجات:

<g:product_detail>
  <g:section_name>ورقة البيانات</g:section_name>
  <g:attribute_name>PDF</g:attribute_name>
  <g:attribute_value>https://www.thinvent.in/ds/{{ sku }}.pdf</g:attribute_value>
</g:product_detail>

حملات البريد الإلكتروني

أوراق البيانات مرفقة ببريد إلكتروني للعروض.

معالجة الأخطاء

SKU غير صالح

if not check_sku(sku):
    abort(422, description="المنتج غير موجود.")

فشل الإنشاء

try:
    pdf_data = generate_datasheet_pdf(sku)
    if pdf_data is None:
        abort(500, description="فشل إنشاء PDF.")
except Exception as e:
    logger.error(f"فشل إنشاء PDF لـ {sku}: {e}")
    abort(500, description="فشل إنشاء PDF.")

الصور المفقودة

try:
    with Image.open(image_path) as img:
        width, height = img.size
except Exception:
    # استخدام الأبعاد الافتراضية
    width, height = 800, 600

المراجع

المكتبات

  • pdfkit - تحويل HTML إلى PDF

  • pypdf - معالجة PDF

  • Pillow - معالجة الصور

مقالات ذات صلة

الملخص

يستخدم إنشاء أوراق البيانات نهجاً هجيناً:

عند الطلب:

  • ✅ الإنشاء عندما يطلب المستخدم

  • ✅ دائماً محدث

  • ✅ لا هدر في التخزين

  • ✅ ~2 ثانية لكل PDF

عن طريق الدُفعات:

  • ✅ الإنشاء المُسبق للمنتجات الشائعة

  • ✅ تتبع تغييرات productdb

  • ✅ تحديد الأولوية حسب تكرار الطلب

  • ✅ مهمة cron ليلية

العملية:

  • ✅ الحصول على بيانات المنتج (الاسم، الصور، الميزات، الوصف)

  • ✅ موازنة الميزات عبر 3 أعمدة

  • ✅ حساب ارتفاعات الصور

  • ✅ عرض قالب HTML

  • ✅ إنشاء PDF باستخدام pdfkit

  • ✅ الاحتفاظ بالصفحة الأولى فقط

التخزين:

  • ✅ محلي: /home/ubuntu/web-static/ds/

  • ✅ S3: s3://thinvent-web-static/ds/

  • ✅ شبكة توصيل المحتوى (CDN): توزيع CloudFront

يوازن هذا النهج الهجين بين الحداثة (عند الطلب) والأداء (الإنشاء المُسبق عن طريق الدُفعات).


← العودة إلى فهرس التوثيق