ذكاء ديستورس الاصطناعي

最近马斯克开源了推特推荐算法,能否在这个插件实现?
以下是某个论坛用户写的油猴脚本实现推特推荐算法,理论上是用于任何discourse论坛:

// ==UserScript==
// @name         *** Algorithm
// @namespace    http://tampermonkey.net/
// @version      0.9
// @description  نظام توصيات ذكي يدمج خوارزمية X وذكاء الاصطناعي DeepSeek، ويقدم توصيات مواضيع مخصصة
// @author       ***
// @match        ****
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @connect      2c2ch1u11-share-api-0.hf.space
// ==/UserScript==

(function() {
    'use strict';

    const API_KEY = '***';
    const API_URL = '***/v1/chat/completions';
    const MODEL = 'deepseek-chat';

    // ========== خوارزمية إعدادات المعلمات (يمكن تعديلها وتحسينها) ==========
    const CONFIG = {
        // خوارزمية X وزن المعلمات
        WEIGHT_LIKES: 0.5,
        WEIGHT_REPLIES: 13.5,
        WEIGHT_VIEWS: 0.015,
        PINNED_BOOST: 2.0,
        TIME_DECAY_FACTOR: 1.5,
        TIME_DECAY_OFFSET: 2,

        // تقييم القيم القصوى المعلمات
        X_SCORE_MAX: 45,
        AI_SCORE_MAX: 55,

        // تقييم عتبة المعلمات
        MAX_SCORE: 100,
        MIN_DISPLAY_SCORE: 20,

        // كاش المعلمات
        PROFILE_CACHE_TTL: 86400000,      // كاش ملف المستخدم: 24 ساعة
        TOPIC_SCORE_CACHE_TTL: 3600000,   // كاش تقييم AI لموضوع واحد: ساعة واحدة

        // API المعلمات
        MAX_TOPICS_PER_BATCH: 30,
        MAX_LIKED_TITLES: 15,       // عدد المواضيع المعجب بها
        MAX_REPLIED_TITLES: 10,     // عدد مواضيع الرد
        MAX_CREATED_TITLES: 5,      // عدد المواضيع المنشأة
        API_RETRY_COUNT: 2,
        API_RETRY_DELAY: 1000,

        // ملف المستخدم تحليل الأبعاد
        PROFILE_CATEGORIES: ['الاهتمامات التقنية', 'تفضيلات المحتوى', 'عادات التفاعل', 'المجال المهني', 'عمق القراءة'],
    };

    let isRecommendMode = false;
    let scoreMap = {};
    let allTopicsData = {};
    let sortTimeout = null;
    let userProfile = "";
    let isLoading = false;
    let isProcessingNewTopics = false;

    // ========== CSS أنماط ==========
    GM_addStyle(`
        .nav-pills > li > a,
        .nav-pills > li.ember-view > a,
        .navigation-container .nav-pills > li > a {
            border-bottom: 3px solid transparent !important;
            transition: all 0.2s ease;
        }

        body.recommend-mode-active .nav-pills > li:not(#nav-item-recommend) > a,
        body.recommend-mode-active .nav-pills > li.ember-view:not(#nav-item-recommend) > a,
        body.recommend-mode-active .navigation-container .nav-pills > li:not(#nav-item-recommend) > a {
            color: var(--primary-medium) !important;
            border-bottom-color: transparent !important;
        }

        .nav-pills li#nav-item-recommend.active > a,
        body.recommend-mode-active .nav-pills li#nav-item-recommend > a {
            color: var(--tertiary) !important;
            border-bottom: 3px solid var(--tertiary) !important;
            font-weight: 600;
        }

        .nav-pills li#nav-item-recommend > a:hover {
            color: var(--tertiary) !important;
            opacity: 0.8;
        }

        .recommend-loading-container {
            width: 100%;
            padding: 60px 20px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            min-height: 300px;
        }

        .recommend-loading-text {
            color: var(--primary-medium);
            font-size: 15px;
            margin-bottom: 24px;
            text-align: center;
        }

        .recommend-spinner {
            width: 36px;
            height: 36px;
            border: 3px solid var(--primary-low);
            border-top: 3px solid var(--primary-medium);
            border-radius: 50%;
            animation: spin 0.8s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .manus-score-badge {
            font-size: 0.75em;
            color: var(--tertiary);
            margin-left: 8px;
            padding: 2px 6px;
            background: var(--tertiary-very-low);
            border-radius: 4px;
            font-weight: 500;
            transition: all 0.3s ease;
        }

        .manus-score-badge.calculating {
            color: var(--primary-medium);
            background: var(--primary-very-low);
            animation: pulse 1.5s ease-in-out infinite;
        }

        @keyframes pulse {
            0%, 100% { opacity: 1; }
            50% { opacity: 0.5; }
        }

        .manus-score-loading {
            font-size: 0.75em;
            color: var(--primary-medium);
            margin-left: 8px;
        }

        .recommend-full-overlay {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: var(--secondary);
            z-index: 100;
            min-height: 500px;
        }

        .recommend-loading-row {
            position: relative;
            z-index: 101;
        }
    `);

    // ========== كاش تقييم AI الموضوعات دالة ==========
    function getTopicScoreCache() {
        return GM_getValue('topic_ai_scores_cache', {});
    }

    function setTopicScoreCache(topicId, aiScore) {
        const cache = getTopicScoreCache();
        cache[topicId] = { score: aiScore, time: Date.now() };
        GM_setValue('topic_ai_scores_cache', cache);
    }

    function getCachedTopicScore(topicId) {
        const cache = getTopicScoreCache();
        const entry = cache[topicId];
        if (entry && (Date.now() - entry.time < CONFIG.TOPIC_SCORE_CACHE_TTL)) {
            return entry.score;
        }
        return null;
    }

    function cleanExpiredCache() {
        const cache = getTopicScoreCache();
        const now = Date.now();
        let cleaned = false;
        for (const [id, entry] of Object.entries(cache)) {
            if (now - entry.time > CONFIG.TOPIC_SCORE_CACHE_TTL) {
                delete cache[id];
                cleaned = true;
            }
        }
        if (cleaned) {
            GM_setValue('topic_ai_scores_cache', cache);
        }
    }

    // ========== حقن تبويب التوصيات ==========
    function injectRecommendTab() {
        if (document.querySelector('#nav-item-recommend')) return;
        const navPills = document.querySelector('.nav-pills');
        if (!navPills) return;

        const recommendTab = document.createElement('li');
        recommendTab.id = 'nav-item-recommend';
        recommendTab.className = 'ember-view nav-item_recommend';
        recommendTab.innerHTML = `<a href="javascript:void(0)">توصيات</a>`;

        const latestTab = navPills.querySelector('.nav-item_latest') ||
                          navPills.querySelector('[data-filter-type="latest"]')?.parentElement ||
                          navPills.firstChild;
        navPills.insertBefore(recommendTab, latestTab);

        recommendTab.addEventListener('click', async (e) => {
            e.preventDefault();
            e.stopPropagation();

            if (isLoading) return;

            isRecommendMode = true;
            document.body.classList.add('recommend-mode-active');

            navPills.querySelectorAll('li').forEach(li => {
                li.classList.remove('active');
                li.querySelector('a')?.classList.remove('active');
            });
            recommendTab.classList.add('active');

            cleanExpiredCache();

            showLoading(true);
            await startRecommendation();
            showLoading(false);

            sortAndDisplayRows();
        });

        navPills.querySelectorAll('li:not(#nav-item-recommend)').forEach(tab => {
            tab.addEventListener('click', () => {
                isRecommendMode = false;
                document.body.classList.remove('recommend-mode-active');
                recommendTab.classList.remove('active');
                document.querySelectorAll('.manus-score-badge').forEach(b => b.remove());
                document.querySelectorAll('.manus-score-loading').forEach(b => b.remove());
            });
        });

        window.addEventListener('popstate', () => {
            if (isRecommendMode) {
                isRecommendMode = false;
                document.body.classList.remove('recommend-mode-active');
                recommendTab.classList.remove('active');
            }
        });
    }

    // ========== تحميل تلميح ==========
    let originalTableContent = null;

    function showLoading(show, text = 'جاري دمج خوارزمية X وتوصيات DeepSeek AI...') {
        isLoading = show;

        const topicListContainer = document.querySelector('.topic-list-container') ||
                                   document.querySelector('.topic-list')?.parentElement ||
                                   document.querySelector('.topic-list');
        const tbody = document.querySelector('.topic-list tbody');

        if (!topicListContainer) return;

        if (show) {
            if (!originalTableContent && tbody) {
                originalTableContent = tbody.innerHTML;
            }

            if (tbody) {
                tbody.innerHTML = `
                    <tr class="recommend-loading-row">
                        <td colspan="100%">
                            <div class="recommend-loading-container">
                                <div class="recommend-loading-text">${text}</div>
                                <div class="recommend-spinner"></div>
                            </div>
                        </td>
                    </tr>
                `;
            }

            topicListContainer.style.position = 'relative';

            let overlay = topicListContainer.querySelector('.recommend-full-overlay');
            if (!overlay) {
                overlay = document.createElement('div');
                overlay.className = 'recommend-full-overlay';
                topicListContainer.appendChild(overlay);
            }
        } else {
            topicListContainer.querySelector('.recommend-full-overlay')?.remove();

            if (originalTableContent && tbody) {
                tbody.innerHTML = originalTableContent;
                originalTableContent = null;
            }
        }
    }

    // ========== دالة مساعدة لاستخراج العناوين ==========
    function extractTitles(data, maxCount) {
        if (!data?.user_actions) return '';

        const titles = [...new Set(
            data.user_actions
                .filter(a => a.title)
                .map(a => a.title)
        )].slice(0, maxCount);

        return titles.length > 0 ? titles.join('\n') : '';
    }

    // ========== تحسين: الحصول على ملف تعريف المستخدم بشكل أكثر تفصيلاً ==========
    async function fetchUserProfile(username) {
        if (!username) {
            console.log('[التوصيات] غير مسجل الدخول، استخدام الملف التعريفي الافتراضي');
            return "افتراضي";
        }

        const cacheKey = `user_profile_v9_${username}`;
        const cached = GM_getValue(cacheKey);
        if (cached && (Date.now() - cached.time < CONFIG.PROFILE_CACHE_TTL)) {
            console.log(`[التوصيات] ملف تعريف المستخدم (ذاكرة التخزين المؤقت):\n${cached.profile}`);
            return cached.profile;
        }

        try {
            // الحصول على بيانات سلوك المستخدم المختلفة
            const [likedData, repliedData, createdData] = await Promise.all([
                fetch(`/user_actions.json?username=${username}&filter=1`).then(r => r.json()).catch(() => null), // الإعجابات
                fetch(`/user_actions.json?username=${username}&filter=5`).then(r => r.json()).catch(() => null), // الردود
                fetch(`/user_actions.json?username=${username}&filter=4`).then(r => r.json()).catch(() => null), // الإنشاء
            ]);

            // استخراج أنواع مختلفة من العناوين
            const likedTitles = extractTitles(likedData, CONFIG.MAX_LIKED_TITLES);
            const repliedTitles = extractTitles(repliedData, CONFIG.MAX_REPLIED_TITLES);
            const createdTitles = extractTitles(createdData, CONFIG.MAX_CREATED_TITLES);

            if (!likedTitles && !repliedTitles && !createdTitles) return "افتراضي";

            // بناء مطالبة تحليل أكثر تفصيلاً
            const prompt = `أنت محلل سلوك مستخدمين محترف. يرجى إنشاء ملف تعريف مستخدم مفصل بناءً على بيانات سلوك المستخدم التالية:

**مواضيع إعجاب المستخدم** (الأكثر تعبيراً عن الاهتمامات):
${likedTitles || 'لا توجد بيانات'}

**المواضيع التي رد عليها المستخدم** (تعكس المشاركة والمجال المهني):
${repliedTitles || 'لا توجد بيانات'}

**المواضيع التي أنشأها المستخدم** (تعكس نقاط الاهتمام النشطة):
${createdTitles || 'لا توجد بيانات'}

يرجى تحليل ملف تعريف المستخدم من الأبعاد التالية، مع تلخيص كل بعد في جملة واحدة:
1. **الاهتمامات التقنية**: ما هي أكواد التقنية، الأدوات أو المنصات التي يهتم بها المستخدم
2. **تفضيلات المحتوى**: هل يفضل الشروحات، النقاشات، الأخبار أو الأسئلة والأجوبة
3. **عادات التفاعل**: هل هو مشارك عميق أم متصفح سطحي
4. **المجال المهني**: المجال التقني أو اتجاه الصناعة الذي يركز عليه بشكل أساسي
5. **عمق القراءة**: هل يفضل المحتوى للمبتدئين، المتقدمين أم الخبراء

تنسيق الإخراج (بدون ترقيم، اطبع 5 أسطر مباشرة):
الاهتمامات التقنية: [نتيجة التحليل]
تفضيلات المحتوى: [نتيجة التحليل]
عادات التفاعل: [نتيجة التحليل]
المجال المهني: [نتيجة التحليل]
عمق القراءة: [نتيجة التحليل]`;

            const profile = await callDeepSeek(prompt, false);

            if (profile && profile.length > 0) {
                GM_setValue(cacheKey, { time: Date.now(), profile: profile });
                console.log(`[التوصيات] ملف تعريف المستخدم:\n${profile}`);
                return profile;
            }
            return "افتراضي";
        } catch (e) {
            console.error('[التوصيات] فشل في الحصول على ملف تعريف المستخدم:', e);
            return "افتراضي";
        }
    }

    // ========== بدء عملية التوصية ==========
    async function startRecommendation() {
        try {
            const currentUser = getCurrentUserInfo();

            if (!userProfile) {
                userProfile = await fetchUserProfile(currentUser?.username);
            }

            const response = await fetch('/latest.json');
            const data = await response.json();
            const topics = data.topic_list.topics;

            topics.forEach(t => {
                allTopicsData[t.id] = t;
            });

            const uncachedTopics = [];
            const xScoresRaw = {};
            const aiScoresMap = {};

            topics.forEach(topic => {
                xScoresRaw[topic.id] = calculateXScore(topic);

                const cachedScore = getCachedTopicScore(topic.id);
                if (cachedScore !== null) {
                    aiScoresMap[topic.id] = cachedScore;
                } else {
                    uncachedTopics.push(topic);
                }
            });

            if (uncachedTopics.length > 0) {
                await batchScoreTopics(uncachedTopics, aiScoresMap);
            }

            calculateFinalScores(topics, xScoresRaw, aiScoresMap);

        } catch (e) {
            console.error('[التوصيات] فشل في عملية التوصية:', e);
        }
    }

    // ========== تقييم المواضيع دفعة واحدة ==========
    async function batchScoreTopics(topics, aiScoresMap) {
        for (let i = 0; i < topics.length; i += CONFIG.MAX_TOPICS_PER_BATCH) {
            const batch = topics.slice(i, i + CONFIG.MAX_TOPICS_PER_BATCH);
            const aiScores = await getAIScoresForBatch(batch);

            batch.forEach(topic => {
                const aiScore = aiScores[topic.id] || 5;
                setTopicScoreCache(topic.id, aiScore);
                aiScoresMap[topic.id] = aiScore;
            });
        }
    }

    // ========== تحسين: تقييم مواضيع أكثر دقة دفعة واحدة ==========
    async function getAIScoresForBatch(topics) {
        const topicList = topics.map((t, idx) =>
            `${idx + 1}. [المعرف: ${t.id}] ${t.title}`
        ).join('\n');

        const prompt = `أنت خبير في توصية المحتوى. يرجى تقييم المواضيع التالية بناءً على ملف تعريف المستخدم.

**ملف تعريف المستخدم**:
${userProfile}

**المواضيع المراد تقييمها**:
${topicList}

**معايير التقييم** (0-10 نقاط):
- **9-10 نقاط**: تطابق عالي مع ملف تعريف المستخدم، من المرجح جداً أن يكون المستخدم مهتماً
- **7-8 نقاط**: تطابق جيد مع ملف تعريف المستخدم، من المرجح أن يكون المستخدم مهتماً
- **5-6 نقاط**: تطابق جزئي مع ملف تعريف المستخدم، قد يكون المستخدم مهتماً
- **3-4 نقاط**: ارتباط ضعيف بملف تعريف المستخدم، من غير المرجح أن يكون المستخدم مهتماً
- **0-2 نقاط**: لا علاقة بملف تعريف المستخدم أو متعارض، المستخدم غير مهتم

**عوامل التقييم**:
1. درجة تطابق محتوى الموضوع مع الاهتمامات التقنية للمستخدم
2. توافق نوع الموضوع مع تفضيلات المحتوى لدى المستخدم
3. ملاءمة عمق الموضوع مع عمق قراءة المستخدم
4. صلة مجال الموضوع بالمجال المهني للمستخدم

يرجى إرجاع تنسيق JSON، حيث يكون المفتاح هو معرّف الموضوع (رقم فقط)، والقيمة هي التقييم (رقم من 0 إلى 10).
مثال: {"123": 8.5, "456": 5.0}

ارجع JSON فقط، بدون نصوص أخرى.`;

        const scores = await callDeepSeek(prompt, true);

        // تنظيف والتحقق من التقييمات
        const cleanedScores = {};
        for (const [id, score] of Object.entries(scores)) {
            const numId = parseInt(id, 10);
            const numScore = parseFloat(score);
            if (!isNaN(numId) && !isNaN(numScore) && numScore >= 0 && numScore <= 10) {
                cleanedScores[numId] = Math.round(numScore * 10) / 10;
            }
        }

        return cleanedScores;
    }

    // ========== تحسين: حساب التقييم النهائي أكثر متانة ==========
    function calculateFinalScores(topics, xScoresRaw, aiScoresMap) {
        const xScores = Object.values(xScoresRaw);
        if (xScores.length === 0) return;

        // استخدام التطبيع الكمي لتجنب تأثير القيم المتطرفة
        const sortedX = [...xScores].sort((a, b) => a - b);
        const p5 = sortedX[Math.floor(sortedX.length * 0.05)];  // الكمية 5%
        const p95 = sortedX[Math.floor(sortedX.length * 0.95)]; // الكمية 95%
        const rangeX = p95 - p5;

        topics.forEach(topic => {
            const id = topic.id;

            let xScoreNormalized;
            if (rangeX === 0) {
                xScoreNormalized = CONFIG.X_SCORE_MAX / 2;
            } else {
                // التقييد ضمن النطاق من p5 إلى p95
                const clampedX = Math.max(p5, Math.min(p95, xScoresRaw[id]));
                xScoreNormalized = ((clampedX - p5) / rangeX) * CONFIG.X_SCORE_MAX;
            }

            const aiScore = aiScoresMap[id] || 5;
            const aiScoreNormalized = (aiScore / 10) * CONFIG.AI_SCORE_MAX;

            // التقييم النهائي: خوارزمية X (45%) + تقييم الذكاء الاصطناعي (55%)
            const finalScore = xScoreNormalized + aiScoreNormalized;
            scoreMap[id] = Math.round(finalScore * 10) / 10;
        });
    }

    // ========== حساب التقييم النهائي للمواضيع الجديدة ==========
    function calculateFinalScoresForNew(topicIds, xScoresRaw, aiScoresMap) {
        const allXScores = Object.values(scoreMap).length > 0
            ? [...Object.values(xScoresRaw), ...Object.keys(allTopicsData).map(id => calculateXScore(allTopicsData[id]))]
            : Object.values(xScoresRaw);

        if (allXScores.length === 0) return;

        const sortedX = [...allXScores].sort((a, b) => a - b);
        const p5 = sortedX[Math.floor(sortedX.length * 0.05)];
        const p95 = sortedX[Math.floor(sortedX.length * 0.95)];
        const rangeX = p95 - p5;

        topicIds.forEach(id => {
            if (xScoresRaw[id] === undefined) return;

            let xScoreNormalized;
            if (rangeX === 0) {
                xScoreNormalized = CONFIG.X_SCORE_MAX / 2;
            } else {
                const clampedX = Math.max(p5, Math.min(p95, xScoresRaw[id]));
                xScoreNormalized = ((clampedX - p5) / rangeX) * CONFIG.X_SCORE_MAX;
            }

            const aiScore = aiScoresMap[id] || 5;
            const aiScoreNormalized = (aiScore / 10) * CONFIG.AI_SCORE_MAX;

            const finalScore = xScoreNormalized + aiScoreNormalized;
            scoreMap[id] = Math.round(finalScore * 10) / 10;
        });
    }

    // ========== معالجة المواضيع المحملة حديثاً (التحميل بالتمرير) ==========
    async function processNewTopics(newRows) {
        if (!isRecommendMode || isProcessingNewTopics) return;
        isProcessingNewTopics = true;

        try {
            const newTopicIds = [];
            newRows.forEach(row => {
                const id = row.getAttribute('data-topic-id');
                if (id && !scoreMap[id]) {
                    newTopicIds.push(id);
                }
            });

            if (newTopicIds.length === 0) {
                isProcessingNewTopics = false;
                return;
            }

            newTopicIds.forEach(id => {
                const row = document.querySelector(`tr[data-topic-id="${id}"]`);
                if (row) {
                    addCalculatingBadge(row);
                }
            });

            const uncachedTopics = [];
            const xScoresRaw = {};
            const aiScoresMap = {};

            for (const id of newTopicIds) {
                const topicData = allTopicsData[id] || await fetchTopicData(id);
                if (!topicData) continue;

                allTopicsData[id] = topicData;
                xScoresRaw[id] = calculateXScore(topicData);

                const cachedScore = getCachedTopicScore(id);
                if (cachedScore !== null) {
                    aiScoresMap[id] = cachedScore;
                } else {
                    uncachedTopics.push(topicData);
                }
            }

            if (uncachedTopics.length > 0) {
                await batchScoreTopics(uncachedTopics, aiScoresMap);
            }

            calculateFinalScoresForNew(newTopicIds, xScoresRaw, aiScoresMap);

            updateRowBadges();

        } catch (e) {
            console.error('[التوصيات] فشل في معالجة المواضيع الجديدة:', e);
        }

        isProcessingNewTopics = false;
    }

    // ========== الحصول على بيانات موضوع واحد ==========
    async function fetchTopicData(topicId) {
        try {
            const row = document.querySelector(`tr[data-topic-id="${topicId}"]`);
            if (row) {
                const title = row.querySelector('.title')?.textContent?.trim() || '';
                const replies = parseInt(row.querySelector('.posts')?.textContent) || 0;
                const views = parseInt(row.querySelector('.views')?.textContent?.replace(/[k,]/gi, '')) || 0;
                const likes = parseInt(row.querySelector('.likes')?.textContent) || 0;

                return {
                    id: topicId,
                    title: title,
                    posts_count: replies,
                    views: views,
                    like_count: likes,
                    created_at: new Date().toISOString(),
                    pinned: row.classList.contains('pinned')
                };
            }
            return null;
        } catch (e) {
            return null;
        }
    }

    // ========== الترتيب والعرض ==========
    function sortAndDisplayRows() {
        if (!isRecommendMode) return;
        const tbody = document.querySelector('.topic-list tbody');
        if (!tbody) return;

        const rows = Array.from(tbody.querySelectorAll('tr.topic-list-item'));

        rows.sort((a, b) => {
            const idA = a.getAttribute('data-topic-id');
            const idB = b.getAttribute('data-topic-id');
            const scoreA = scoreMap[idA] || 0;
            const scoreB = scoreMap[idB] || 0;
            return scoreB - scoreA;
        });

        let hiddenCount = 0;
        rows.forEach(row => {
            const id = row.getAttribute('data-topic-id');
            const score = scoreMap[id];

            if (score === undefined) {
                row.style.display = '';
                addCalculatingBadge(row);
            } else if (score < CONFIG.MIN_DISPLAY_SCORE) {
                row.style.display = 'none';
                hiddenCount++;
            } else {
                row.style.display = '';
                addScoreBadge(row);
            }
            tbody.appendChild(row);
        });
    }

    // ========== تحديث شارات جميع الصفوف ==========
    function updateRowBadges() {
        if (!isRecommendMode) return;
        const rows = document.querySelectorAll('tr.topic-list-item');
        rows.forEach(row => {
            const id = row.getAttribute('data-topic-id');
            const score = scoreMap[id];

            if (score === undefined) {
                addCalculatingBadge(row);
            } else if (score < CONFIG.MIN_DISPLAY_SCORE) {
                row.style.display = 'none';
            } else {
                row.style.display = '';
                addScoreBadge(row);
            }
        });
    }

    // ========== إضافة شارة التقييم ==========
    function addScoreBadge(row) {
        const id = row.getAttribute('data-topic-id');
        const score = scoreMap[id];

        row.querySelector('.manus-score-loading')?.remove();

        if (score !== undefined) {
            let badge = row.querySelector('.manus-score-badge');
            if (!badge) {
                badge = document.createElement('span');
                badge.className = 'manus-score-badge';
                const titleContainer = row.querySelector('.link-top-line') ||
                                      row.querySelector('.title')?.parentElement ||
                                      row.querySelector('.main-link') ||
                                      row.querySelector('td:first-child');
                if (titleContainer) {
                    titleContainer.appendChild(badge);
                }
            }
            if (badge) {
                badge.textContent = `🔥 ${score.toFixed(1)}`;
                badge.classList.remove('calculating');
            }
        }
    }

    // ========== إضافة شارة "جارٍ الحساب" ==========
    function addCalculatingBadge(row) {
        const id = row.getAttribute('data-topic-id');

        if (scoreMap[id] !== undefined) return;

        let badge = row.querySelector('.manus-score-badge');
        if (!badge) {
            badge = document.createElement('span');
            badge.className = 'manus-score-badge calculating';
            const titleContainer = row.querySelector('.link-top-line') ||
                                  row.querySelector('.title')?.parentElement ||
                                  row.querySelector('.main-link') ||
                                  row.querySelector('td:first-child');
            if (titleContainer) {
                titleContainer.appendChild(badge);
            }
        }
        if (badge) {
            badge.textContent = '⏳ جارٍ الحساب...';
            badge.classList.add('calculating');
        }
    }

    // ========== تحسين: تحسين منطق تنظيف JSON ==========
    function cleanJsonResponse(content) {
        if (!content) return content;

        let cleaned = content.trim();

        // إزالة علامات كتلة الكود Markdown
        cleaned = cleaned.replace(/^```(?:json)?\s*/i, '').replace(/```\s*$/i, '');

        // إزالة النصوص التوضيحية المحتملة
        const jsonMatch = cleaned.match(/\{[\s\S]*\}/);
        if (jsonMatch) {
            cleaned = jsonMatch[0];
        }

        return cleaned.trim();
    }

    // ========== استدعاء API ==========
    async function callDeepSeek(prompt, isJson = true, retryCount = 0) {
        return new Promise((resolve) => {
            GM_xmlhttpRequest({
                method: "POST",
                url: API_URL,
                headers: {
                    "Content-Type": "application/json",
                    "Authorization": `Bearer ${API_KEY}`
                },
                data: JSON.stringify({
                    model: MODEL,
                    messages: [{ role: "user", content: prompt }],
                    temperature: 0.3,
                    max_tokens: 1000
                }),
                timeout: 30000,
                onload: (res) => {
                    try {
                        if (res.status >= 200 && res.status < 300) {
                            let content = JSON.parse(res.responseText).choices[0].message.content;

                            if (isJson) {
                                content = cleanJsonResponse(content);
                                resolve(JSON.parse(content));
                            } else {
                                resolve(content);
                            }
                        } else {
                            throw new Error(`HTTP ${res.status}`);
                        }
                    } catch(e) {
                        console.error('[التوصيات] فشل في تحليل استجابة API:', e);
                        if (retryCount < CONFIG.API_RETRY_COUNT) {
                            setTimeout(() => {
                                callDeepSeek(prompt, isJson, retryCount + 1).then(resolve);
                            }, CONFIG.API_RETRY_DELAY);
                        } else {
                            resolve(isJson ? {} : "");
                        }
                    }
                },
                onerror: (err) => {
                    console.error('[التوصيات] فشل في استدعاء API:', err);
                    if (retryCount < CONFIG.API_RETRY_COUNT) {
                        setTimeout(() => {
                            callDeepSeek(prompt, isJson, retryCount + 1).then(resolve);
                        }, CONFIG.API_RETRY_DELAY);
                    } else {
                        resolve(isJson ? {} : "");
                    }
                },
                ontimeout: () => {
                    console.error('[التوصيات] انتهاء مهلة استدعاء API');
                    if (retryCount < CONFIG.API_RETRY_COUNT) {
                        setTimeout(() => {
                            callDeepSeek(prompt, isJson, retryCount + 1).then(resolve);
                        }, CONFIG.API_RETRY_DELAY);
                    } else {
                        resolve(isJson ? {} : "");
                    }
                }
            });
        });
    }

    // ========== تحسين: تقييم خوارزمية X أكثر ذكاءً ==========
    function calculateXScore(topic) {
        const now = new Date();
        const created = new Date(topic.created_at);
        const hoursOld = Math.max(0, (now - created) / (1000 * 60 * 60));

        // تقييم التفاعل الأساسي
        const likeScore = (topic.like_count || 0) * CONFIG.WEIGHT_LIKES;
        const replyScore = (topic.posts_count || 0) * CONFIG.WEIGHT_REPLIES;
        const viewScore = (topic.views || 0) * CONFIG.WEIGHT_VIEWS;

        // حساب مكافأة معدل التفاعل (المحتوى ذو معدل التفاعل العالي يكون بجودة أعلى)
        const views = topic.views || 1;
        const engagementRate = ((topic.like_count || 0) + (topic.posts_count || 0)) / views;
        const engagementBoost = 1 + Math.min(engagementRate * 10, 2); // مكافأة تصل إلى ضعف

        let score = (likeScore + replyScore + viewScore) * engagementBoost;

        // مكافأة التثبيت
        if (topic.pinned) {
            score *= CONFIG.PINNED_BOOST;
        }

        // التوهين الزمني (الطزاجة)
        const timeFactor = Math.pow(hoursOld + CONFIG.TIME_DECAY_OFFSET, CONFIG.TIME_DECAY_FACTOR);

        return score / timeFactor;
    }

    // ========== الحصول على معلومات المستخدم الحالي ==========
    function getCurrentUserInfo() {
        try {
            // الطريقة 1: حاوية Discourse
            const container = window.Discourse?.__container__;
            if (container) {
                const currentUser = container.lookup('service:current-user');
                if (currentUser?.username) {
                    return {
                        username: currentUser.username,
                        id: currentUser.id,
                        name: currentUser.name,
                        trust_level: currentUser.trust_level
                    };
                }
            }

            // الطريقة 2: User.current()
            if (window.User?.current?.()?.username) {
                const user = window.User.current();
                return { username: user.username, id: user.id };
            }

            // الطريقة 3: #current-user
            const userLink = document.querySelector('#current-user a[data-user-card]');
            if (userLink) {
                return { username: userLink.getAttribute('data-user-card') };
            }

            // الطريقة 4: الرأس
            const headerUser = document.querySelector('.header-dropdown-toggle.current-user button');
            if (headerUser) {
                const img = headerUser.querySelector('img');
                if (img?.alt) {
                    return { username: img.alt };
                }
            }

            // الطريقة 5: d-header
            const anyUserCard = document.querySelector('.d-header [data-user-card]');
            if (anyUserCard) {
                return { username: anyUserCard.getAttribute('data-user-card') };
            }

            // الطريقة 6: بيانات التحميل المسبق
            const preloadData = document.querySelector('#data-preloaded');
            if (preloadData) {
                try {
                    const data = JSON.parse(preloadData.dataset.preloaded || '{}');
                    const currentUser = JSON.parse(data.currentUser || '{}');
                    if (currentUser.username) {
                        return { username: currentUser.username };
                    }
                } catch (e) {}
            }

            return null;
        } catch (e) {
            return null;
        }
    }

    // ========== مراقبة تغييرات DOM ==========
    const listObserver = new MutationObserver((mutations) => {
        if (!isRecommendMode || isLoading) return;

        const newRows = [];
        mutations.forEach(m => {
            m.addedNodes.forEach(node => {
                if (node.nodeType === 1) {
                    if (node.classList?.contains('topic-list-item')) {
                        newRows.push(node);
                    } else if (node.querySelectorAll) {
                        node.querySelectorAll('.topic-list-item').forEach(row => newRows.push(row));
                    }
                }
            });
        });

        if (newRows.length > 0) {
            newRows.forEach(row => {
                const id = row.getAttribute('data-topic-id');
                if (id && scoreMap[id] === undefined) {
                    addCalculatingBadge(row);
                } else if (scoreMap[id] !== undefined) {
                    if (scoreMap[id] >= CONFIG.MIN_DISPLAY_SCORE) {
                        addScoreBadge(row);
                    } else {
                        row.style.display = 'none';
                    }
                }
            });

            clearTimeout(sortTimeout);
            sortTimeout = setTimeout(() => processNewTopics(newRows), 500);
        }
    });

    const navObserver = new MutationObserver(() => {
        injectRecommendTab();
        const tbody = document.querySelector('.topic-list tbody');
        if (tbody && !tbody.dataset.observing) {
            tbody.dataset.observing = 'true';
            listObserver.observe(tbody, { childList: true });
        }
    });

    // ========== بدء البرنامج النصي ==========
    navObserver.observe(document.body, { childList: true, subtree: true });
    injectRecommendTab();

    console.log('[نظام التوصيات] تم التحميل - دمج خوارزمية X مع DeepSeek AI');

})();

فيما يلي التأثير على منتدى Discourse:


إعجاب واحد (1)