{/* آخر تحديث: 2026-04-24 | بُني واستورد وحُفظ مباشرة على nerdleveltech.app.n8n.cloud | gpt-5-mini + أرصدة مجانية */}
12 عقدة، 3 مصادر بيانات متوازية، خطوة تلخيص AI واحدة، حمولة Slack Block Kit واحدة — وُصلت وحُفظت على n8n cloud. استورد، بدّل رابط Slack webhook العام (الخطوة 6)، وجدول. لقطات التنفيذ أدناه تعرض البيانات تتدفق عبر مُلخص AI.
⚠️ قبل التفعيل: عقدة Post to Slack Webhook تأتي برابط placeholder (
https://hooks.slack.com/services/REPLACE/WITH/YOUR_WEBHOOK). أول تشغيل مجدول سيفشل بـ 404 إذا لم تستبدله. انظر الخطوة 6 لإجراء الاستبدال الدقيق.
ما الذي ستبنيه
سير n8n مُشغّل بجدول يومي:
- يعمل كل صباح الساعة 8 (UTC افتراضياً، قابل للضبط)
- يجلب أهم 5 عناصر بالتوازي من ثلاثة مصادر: صفحة Hacker News الأولى، أفضل مقالات Dev.to، مستودعات GitHub المُنشأة في آخر 48 ساعة مرتبة بالنجوم
- يُطبّع كل شكل إلى كائن مشترك
{ source, title, url, score, summary_seed } - يستخدم Summarization Chain من LangChain لكتابة ملخص جملة واحدة لكل عنصر
- يبني رسالة Slack Block Kit بأقسام مُجمّعة وروابط قابلة للنقر وفواصل
- يُرسل POST إلى Slack Incoming Webhook — بدون OAuth
تخطَّ البناء — استورد السير
المتطلبات المسبقة
| المتطلب | التفاصيل |
|---|---|
| حساب n8n | تجربة مجانية 14 يوماً |
| أرصدة OpenAI | 100 مجانية تغطي شهور من التشغيلات اليومية |
| مساحة عمل Slack | تحتاج صلاحيات admin لتثبيت Incoming Webhook |
| الوقت | حوالي 20 دقيقة |
الخطوة 1 — استيراد السير
أنشئ سير جديد، ألصق JSON على اللوحة الفارغة. يُحمل n8n 12 عقدة. يبدو هكذا:
Schedule ──┬─→ HN Fetch ─→ Normalize HN
├─→ Dev.to ─→ Normalize Dev.to ──┐
└─→ GitHub ─→ Normalize GitHub ──┼─→ Merge → Summarize Each → Combine → Format Slack → POST
──┘
انقر نقراً مزدوجاً على OpenAI Chat Model، وتحقق من بيانات n8n المجانية و gpt-5-mini بدرجة حرارة 0.3 (منخفضة — نريد مخرجات جملة واحدة متسقة).
الخطوة 2 — فهم المصادر الثلاثة
| المصدر | نقطة النهاية | المصادقة | يُعيد |
|---|---|---|---|
| Hacker News | hn.algolia.com/api/v1/search?tags=front_page&hitsPerPage=5 | بدون | hits[] مع title و url و points |
| Dev.to | dev.to/api/articles?top=1&per_page=5 | بدون | مصفوفة عادية مع title و url و positive_reactions_count |
| GitHub | api.github.com/search/repositories?q=created:>{date}&sort=stars&order=desc&per_page=5 | بدون (محدود) | items[] مع full_name و html_url و stargazers_count و description |
رابط GitHub يستخدم تعبير n8n: {{ $now.minus({days: 2}).toFormat('yyyy-MM-dd') }} — يبني سلسلة تاريخ لـ"قبل يومين" في وقت التشغيل لتحصل دائماً على أحدث المستودعات.
الخطوة 3 — تطبيع كل مصدر
ثلاث عقد Code تحول كل مصدر إلى نفس شكل الكائن. مثلاً Normalize HN:
const hits = $input.first().json.hits || [];
return hits.map(h => ({
json: {
source: 'Hacker News',
title: h.title,
url: h.url || `https://news.ycombinator.com/item?id=${h.objectID}`,
score: h.points || 0,
summary_seed: (h.story_text || '').slice(0, 400)
}
}));
summary_seed يُعطي AI سياقاً للعناصر التي تفتقد لجسم URL (Show HN أو Ask HN). URL الاحتياطي (news.ycombinator.com/item?id=...) يضمن أن عناصر Ask HN لا تزال قابلة للنقر.
Normalize Dev.to يقرأ description إلى summary_seed. Normalize GitHub يقرأ description السطر الواحد للمستودع.
بعد هذه الخطوة، كل العناصر الـ 15 (5 × 3) لها بنية متطابقة — لا عقدة لاحقة تحتاج لمعرفة من أي مصدر جاءت.
الخطوة 4 — الدمج والتلخيص
عقدة Merge
مضبوطة على mode: append. تأخذ 3 تدفقات مدخلة (عقد Normalize الثلاث) وتُخرج قائمة مُجمعة واحدة من 15 عنصراً بترتيب المصدر.
Summarization Chain
السلسلة تشتغل مرة لكل عنصر. المطالبة مُدمجة في combineMapPrompt للعقدة:
⚠️ اختلاف نحوي مهم: مطالبة Summarization Chain تستخدم متغير قالب LangChain
{text}وليس تعبيرات n8n{{ $json.x }}. السلسلة الافتراضية تُغذي محتوى كل عنصر مدخل تلقائياً كـ{text}في المطالبة. إذا احتجت الوصول لحقول أخرى ($json.titleو$json.url)، أنظف حل هو استبدال Summarization Chain بـ Basic LLM Chain (chainLlm) — تلك العقدة تُبدل تعبيرات n8n مثل ما يفعل دليل 1. واجهنا هذا في اختبارنا الحقيقي: مع{{ $json.title }}حرفياً في مطالبة Summarization Chain، أعاد النموذج placeholders بأسلوب القوالب الخاصة به بدلاً من ملخص حقيقي. استخدم Basic LLM Chain إلا إذا احتجت تحديداً map-reduce على مستندات طويلة جداً.
Source: {{ $json.source }}
Title: {{ $json.title }}
URL: {{ $json.url }}
Score/engagement: {{ $json.score }}
Context: "{{ $json.summary_seed }}"
Write ONE crisp sentence (≤ 25 words) that tells a busy developer what this
is and why it matters TODAY. Lead with the concrete thing, not with "This
story is about...". If it is a GitHub repo, mention the language or primary
domain. No hedging.
كل عنصر يحصل على استدعاء API واحد إلى gpt-5-mini. التكلفة اليومية الإجمالية: ~0.005$ (أقل بكثير من 100 رصيد مجاني).
أعلاه: عقدة Summarize Each مفتوحة بعد تنفيذ حقيقي — اللوحة اليسرى المُدخل المدموج من المصادر الثلاثة، اللوحة اليمنى ملخصات الجملة الواحدة التي أنتجتها gpt-5-mini.
Combine Items
عقدة Code تُجمِّع العناصر المُلخصة حسب المصدر:
const bySource = {};
items.forEach(it => {
const src = it.json.source || 'Other';
bySource[src] = bySource[src] || [];
bySource[src].push({
summary: (it.json.output || it.json.response?.text || it.json.text || '').trim(),
url: it.json.url,
title: it.json.title,
score: it.json.score
});
});
الاحتياطي الثلاثي it.json.output || it.json.response?.text || it.json.text يتعامل مع أشكال مخرجات التلخيص لثلاث إصدارات n8n. احتفظ به — التكلفة مقارنة حرف واحد، والفائدة توافق مستقبلي.
الخطوة 5 — تنسيق Slack Block Kit
انقر نقراً مزدوجاً على Format Slack Blocks. عقدة Code تبني حمولة Block Kit الرسمية من Slack — JSON منظم يعرض كبطاقات غنية، ليس نصاً عادياً.
const blocks = [
{ type: 'header', text: { type: 'plain_text', text: `🧠 Daily Tech Digest — ${date}` } },
{ type: 'context', elements: [{ type: 'mrkdwn', text: `Merged from ${Object.keys(bySource).length} sources` }] },
{ type: 'divider' }
];
Object.entries(bySource).forEach(([src, items]) => {
blocks.push({ type: 'section', text: { type: 'mrkdwn', text: `*${src}*` } });
items.forEach(i => {
const scoreStr = i.score ? ` _(${i.score})_` : '';
blocks.push({ type: 'section', text: { type: 'mrkdwn', text: `• <${i.url}|${i.title}>${scoreStr}\n${i.summary}` } });
});
blocks.push({ type: 'divider' });
});
النتيجة: رأس قسم بالخط العريض لكل مصدر، كل عنصر على سطر خاص به بعنوان قابل للنقر وملخص AI أسفله. النقاط تُعرض بالخط المائل _(312)_.
لماذا Block Kit مقابل النص العادي؟ رسائل النص العادي تقطع العناوين عند الروابط الطويلة ولا تُعرض قابلة للنقر. صيغة
<url|text>في Block Kit تُعطيك تسميات روابط قابلة للنقر وتجميع وفواصل وتذييلات سياق.
الخطوة 6 — توصيل Slack Webhook
6أ. إنشاء webhook في Slack
- افتح Slack في متصفح ← اضغط اسم مساحة العمل أعلى اليسار ← Settings & administration ← Manage apps
- ابحث "Incoming Webhooks" ← Add to Slack
- اختر القناة التي تريد نشر الملخص عليها (مثلاً
#ai-digest) - اضغط Add Incoming WebHooks integration — Slack يُعطيك رابطاً مثل
https://hooks.slack.com/services/T01.../B02.../abc123 - انسخ الرابط
6ب. اللصق في السير
انقر نقراً مزدوجاً على Post to Slack Webhook في n8n. استبدل placeholder الـ URL:
https://hooks.slack.com/services/REPLACE/WITH/YOUR_WEBHOOK
…برابط webhook الحقيقي. احفظ السير.
6ج. اختبره
اضغط Execute workflow على اللوحة. السير يشتغل عبر العقد الـ 12 وينشر على قناة Slack. إذا كان كل شيء صحيحاً، تحصل على رسالة غنية تبدو كنشرة مُنسقة — المصادر مفصولة، الروابط قابلة للنقر، ملخصات AI تحت كل عنصر.
إذا لم تصل رسالة Slack:
- افتح سجل التنفيذ ← اضغط عقدة Post to Slack Webhook ← افحص رمز استجابة HTTP.
200= نجاح.400= JSON تالف (عادة حقلtextاحتياطي مفقود). - تحقق من القناة التي تم تثبيت webhook عليها — لا يمكنك إعادة توجيه webhook بدون تثبيت واحد جديد.
التوسعات: البريد و Teams و Discord والتخصيص
البريد الإلكتروني بدلاً من Slack
استبدل Post to Slack Webhook بعقدة Gmail (تحتاج OAuth لحساب Google). اعمل خريطة:
- To ← بريدك الإلكتروني
- Subject ←
🧠 Daily Tech Digest — {{ $json.text }} - Body (HTML) ← حوّل blocks من Slack إلى HTML بعقدة Code صغيرة قبل هذه الخطوة
Microsoft Teams
Teams يقبل Adaptive Cards بدلاً من Block Kit. أنشئ عقدة Code جديدة تُترجم كائن bySource إلى JSON بتنسيق Adaptive Card (المخطط هنا). أرسل POST إلى رابط webhook الوارد لقناة Teams.
Discord
Discord يقبل webhooks لكن بشكل مختلف — مصفوفة embeds مع title و description و url و fields. سهل الترجمة من bySource.
التخصيص بتفضيلات المستخدم
أضف عقدة Read From Database قبل الجلب. استعلم عن جدول { user_id, topics[], min_score, slack_webhook } ووزع لكل مستخدم. كل مستخدم يحصل على ملخص مُصفى لمواضيعه مع webhook شخصي.
ضبط المصادر لكل يوم
أضف عقدة Switch بعد Schedule توجه إلى مجموعات fetch مختلفة حسب يوم الأسبوع. الإثنين = Hacker News + Dev.to؛ الجمعة = GitHub Trending + Product Hunt. يُبقي الملخص طازجاً.
ما التالي
ادمج هذا مع يوتيوب إلى تدوينة AI لتحويل مستودع GitHub لليوم إلى مقال شرح كامل، أو مع إثراء العملاء المحتملين بالـAI لتحديد الشركات المُوظِّفة من منشورات Dev.to وتوليد outreach.