انقطاع بث SSE في محرر الذكاء الاصطناعي — حلول حصص Gemini وانتهاء المهلة
يستخدم مساعد الكتابة بالذكاء الاصطناعي بروتوكول Server-Sent Events لبث المحتوى من Gemini. إن انقطع البث في منتصف الجملة، فالسبب في الغالب هو استنفاد حصة الطلبات في الدقيقة لدى Gemini، أو انتهاء مهلة طلب Railway، أو إلغاء اتصال fetch من جانب المتصفح.
يبث مساعد الكتابة بالذكاء الاصطناعي في VeloCMS الردود من Google Gemini عبر Server-Sent Events. إن انقطع البث في منتصف الجملة وأظهر المحرر استجابة منقوصة، فثمة ثلاثة أسباب محتملة: استنفاد حصة الطلبات في الدقيقة لدى Gemini، أو الوصول إلى مهلة الطلب البالغة 60 ثانية في Railway، أو انقطاع اتصال EventSource في المتصفح بسبب توقف الشبكة.
السبب الأول — حصة Gemini في الدقيقة
تبلغ حصة Google Gemini 2.0 Flash الافتراضية 15 طلباً في الدقيقة (RPM) و1,000,000 رمز في الدقيقة (TPM) على الطبقة المجانية. في خطة VeloCMS SaaS المشتركة حيث تكون GEMINI_API_KEY هي مفتاح المنصة، تُقاسَم هذه الحصة بين جميع طلبات مساعدة الذكاء الاصطناعي. إن كنت تكتب مقالاً طويلاً وتُجري استمرارات ذكاء اصطناعي متعاقبة بسرعة، فقد تبلغ حد RPM. يتجلى العرض في انقطاع البث بعد 2-3 ثوانٍ دون رسالة خطأ في المحرر.
إن كنت على خطة Pro أو Business وقد أعددت مفتاح Gemini API الخاص بك BYOK في الإعدادات ثم الذكاء الاصطناعي، فحصتك منفصلة عن مستخدمي VeloCMS الآخرين. أنشئ مفتاح BYOK للحصول على حصة مخصصة — دليل الإعداد متاح في 'كيفية إعداد مفتاح BYOK AI'.
السبب الثاني — مهلة Railway البالغة 60 ثانية
يُطبّق وكيل HTTP في Railway مهلة طلب مدتها 60 ثانية. مسار بث SSE لـ Gemini هو اتصال HTTP طويل الأمد — لاستجابة من 2,000 رمز بمعدل إصدار الرموز لدى Gemini، قد يستمر البث من 30 إلى 90 ثانية. الطلبات التي تتجاوز 60 ثانية تصطدم بمهلة وكيل Railway التي تُغلق الاتصال دون حدث SSE نهائي نظيف. الحل هو keepalive أثناء البث: يُرسل معالج مسار VeloCMS تعليقاً SSE كل 15 ثانية بينما ينتظر رموز Gemini، مما يُعيد ضبط عداد مهلة Railway.
// In /api/ai/generate/route.ts -- keepalive pattern:
const keepalive = setInterval(() => {
controller.enqueue(
new TextEncoder().encode(": keep-alive\n\n")
);
}, 15_000);
try {
for await (const chunk of geminiStream) {
controller.enqueue(
encoder.encode(`data: ${JSON.stringify({ text: chunk })}\n\n`)
);
}
} finally {
clearInterval(keepalive);
controller.close();
}السبب الثالث — إلغاء fetch من جانب المتصفح
تُلغي المتصفحات الحديثة طلبات fetch واتصالات EventSource حين ينتقل المستخدم بعيداً عن الصفحة، أو حين تصبح تبويبة المتصفح خاملة لفترة ممتدة على الأجهزة المحمولة، أو حين يعترض Service Worker الطلب. يتعامل محرر VeloCMS مع ذلك باستراتيجية إعادة اتصال — حين يُطلق EventSource حدث خطأ، ينتظر المحرر ثانيتين ثم يُعيد الاتصال مضيفاً النص الجزئي الذي وصل بالفعل. إن فشلت إعادة الاتصال بعد 3 محاولات، أظهر المحرر تنبيهاً بالخطأ مع زر «إعادة المحاولة».
التشخيص باستخدام أدوات مطور المتصفح
افتح Chrome DevTools ثم Network وصفّها بـ EventStream. انقر على طلب /api/ai/generate وافتح تبويبة EventStream. سترى كل حدث SSE كصف منفصل. إن انتهى البث بصورة نظيفة، كان آخر صف حدث done. إن انقطع البث دون حدث done، فالاتصال أُغلق من الخارج — تحقق من عمود التوقيت لترى إن توقف عند 60 ثانية بالضبط (مهلة Railway) أم عند نقطة عشوائية (مشكلة حصة أو شبكة).