Greasy Fork

Greasy Fork is available in English.

青书学堂考试显示助手

青书学堂答案显示助手 只用于考试

目前为 2025-04-26 提交的版本,查看 最新版本

// ==UserScript==
// @name         青书学堂考试显示助手
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  青书学堂答案显示助手 只用于考试
// @license MIT
// @author       ruby
// @match        https://degree.qingshuxuetang.com/zzqd/Student/ExercisePaper*
// @grant        GM_xmlhttpRequest
// @connect      degree.qingshuxuetang.com
// @connect      www.baidu.com
// @connect      cn.bing.com
// @connect      *
// ==/UserScript==

(function() {
    'use strict';

    // 添加显示答案按钮
    function addAnswerButton() {
        const button = document.createElement('button');
        button.textContent = '显示答案';
        button.style.position = 'fixed';
        button.style.top = '10px';
        button.style.right = '10px';
        button.style.zIndex = '9999';
        button.style.padding = '10px';
        button.style.backgroundColor = '#4CAF50';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.borderRadius = '5px';
        button.style.cursor = 'pointer';

        button.addEventListener('click', showAnswers);
        document.body.appendChild(button);
    }

    // 获取URL参数
    function getUrlParams() {
        const url = new URL(window.location.href);
        return {
            courseId: url.searchParams.get('courseId'),
            quizId: url.searchParams.get('quizId'),
            teachPlanId: url.searchParams.get('teachPlanId'),
            periodId: url.searchParams.get('periodId')
        };
    }

    // 搜索配置
    const SEARCH_CONFIG = {
        // 一些常见的ChatGPT镜像网站API,建议自行替换为可用的地址
        FREE_AI_APIS: [
            'https://free-api.cveoy.top/v3/chat/completions',
            'https://api.chatanywhere.cn/v1/chat/completions'
        ],
        // 搜索引擎
        SEARCH_URLS: {
            BAIDU: 'https://www.baidu.com/s?wd=',
            BING: 'https://cn.bing.com/search?q='
        },
        // 请求头
        HEADERS: {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
    };

    // 获取题目答案
    async function getAnswers() {
        const params = getUrlParams();
        const timestamp = Date.now();
        const questionBankUrl = `https://degree.qingshuxuetang.com/zzqd/Student/QuestionBank`;

        try {
            // 获取题库数据
            const bankResponse = await fetch(questionBankUrl, {
                credentials: 'include',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                }
            });
            const bankData = await bankResponse.json();
            const matchedAnswers = [];

            // 获取当前考试题目
            const questions = document.querySelectorAll('.question-content');

            for (const question of questions) {
                const questionId = question.id;
                let answer = null;

                // 获取题目中的图片链接
                const imgElement = question.querySelector('img');
                const questionText = question.textContent.trim();

                // 先尝试通过图片链接匹配
                if (imgElement) {
                    const imgUrl = imgElement.src;
                    const matchedQuestion = bankData.find(q => q.imageUrl === imgUrl);
                    if (matchedQuestion) {
                        answer = matchedQuestion.solution;
                    }
                }

                // 如果没有找到匹配的图片,尝试文本匹配
                if (!answer) {
                    const matchedQuestion = bankData.find(q =>
                        similarity(questionText, q.questionText) > 0.9
                    );
                    if (matchedQuestion) {
                        answer = matchedQuestion.solution;
                    }
                }

                // 如果仍然没有答案,使用AI搜索
                if (!answer) {
                    answer = await searchWithAI(questionText);
                }

                matchedAnswers.push({
                    questionId: questionId,
                    solution: answer || '未找到答案'
                });
            }

            return { data: { paperDetail: { questions: matchedAnswers } } };
        } catch (error) {
            console.error('获取答案失败:', error);
            return null;
        }
    }

    // 搜索答案主函数
    async function searchWithAI(questionText) {
        const results = [];

        // 并行执行多个搜索
        const searchPromises = [
            searchBaidu(questionText),
            searchBing(questionText),
            searchFreeAI(questionText)
        ];

        try {
            const searchResults = await Promise.all(searchPromises);
            results.push(...searchResults.filter(Boolean));

            // 验证和处理答案
            return processSearchResults(results, questionText);
        } catch (error) {
            console.error('搜索过程出错:', error);
            return null;
        }
    }

    // 百度搜索
    async function searchBaidu(question) {
        try {
            const encodedQuestion = encodeURIComponent(question);
            const url = SEARCH_CONFIG.SEARCH_URLS.BAIDU + encodedQuestion;

            // 使用GM_xmlhttpRequest进行跨域请求
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: url,
                    headers: SEARCH_CONFIG.HEADERS,
                    onload: function(response) {
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.responseText, 'text/html');

                        // 提取搜索结果
                        const searchResults = doc.querySelectorAll('.c-container');
                        let combinedText = '';

                        searchResults.forEach((result, index) => {
                            if (index < 3) { // 只取前3个结果
                                combinedText += result.textContent + ' ';
                            }
                        });

                        resolve(combinedText.trim());
                    },
                    onerror: reject
                });
            });
        } catch (error) {
            console.error('百度搜索失败:', error);
            return null;
        }
    }

    // 必应搜索
    async function searchBing(question) {
        try {
            const encodedQuestion = encodeURIComponent(question);
            const url = SEARCH_CONFIG.SEARCH_URLS.BING + encodedQuestion;

            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    method: 'GET',
                    url: url,
                    headers: SEARCH_CONFIG.HEADERS,
                    onload: function(response) {
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(response.responseText, 'text/html');

                        // 提取搜索结果
                        const searchResults = doc.querySelectorAll('.b_algo');
                        let combinedText = '';

                        searchResults.forEach((result, index) => {
                            if (index < 3) {
                                combinedText += result.textContent + ' ';
                            }
                        });

                        resolve(combinedText.trim());
                    },
                    onerror: reject
                });
            });
        } catch (error) {
            console.error('必应搜索失败:', error);
            return null;
        }
    }

    // 使用免费AI API
    async function searchFreeAI(question) {
        for (const apiUrl of SEARCH_CONFIG.FREE_AI_APIS) {
            try {
                const response = await fetch(apiUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        messages: [{
                            role: 'user',
                            content: `请简洁回答这个问题:${question}`
                        }],
                        model: 'gpt-3.5-turbo',
                        temperature: 0.3
                    })
                });

                if (!response.ok) continue;

                const data = await response.json();
                if (data.choices && data.choices[0]) {
                    return data.choices[0].message.content.trim();
                }
            } catch (error) {
                console.error(`AI API ${apiUrl} 调用失败:`, error);
                continue;
            }
        }
        return null;
    }

    // 处理搜索结果
    function processSearchResults(results, questionText) {
        if (!results.length) return null;

        // 清理和标准化结果
        const cleanResults = results.map(result => {
            if (!result) return null;
            // 清理HTML标签和特殊字符
            return result.replace(/<[^>]*>/g, '')
                        .replace(/\s+/g, ' ')
                        .trim();
        }).filter(Boolean);

        if (!cleanResults.length) return null;

        // 提取最相关的答案
        const relevantAnswers = cleanResults.map(result => {
            // 分析结果相关性
            const relevanceScore = calculateRelevance(result, questionText);
            return { text: result, score: relevanceScore };
        });

        // 按相关性排序
        relevantAnswers.sort((a, b) => b.score - a.score);

        // 如果有多个高相关性答案,进行交叉验证
        if (relevantAnswers.length >= 2 &&
            relevantAnswers[0].score > 0.6 &&
            relevantAnswers[1].score > 0.6) {
            // 比较前两个答案的相似度
            const similarity = calculateSimilarity(relevantAnswers[0].text, relevantAnswers[1].text);
            if (similarity > 0.7) {
                return relevantAnswers[0].text;
            }
            return `[待确认] ${relevantAnswers[0].text}`;
        }

        // 返回最相关的答案
        return relevantAnswers[0].score > 0.6 ?
               relevantAnswers[0].text :
               `[待确认] ${relevantAnswers[0].text}`;
    }

    // 计算文本相关性
    function calculateRelevance(text, question) {
        const questionWords = question.toLowerCase().split(/\s+/);
        const textWords = text.toLowerCase().split(/\s+/);

        let matchCount = 0;
        questionWords.forEach(word => {
            if (textWords.includes(word)) matchCount++;
        });

        return matchCount / questionWords.length;
    }

    // 计算文本相似度
    function calculateSimilarity(text1, text2) {
        const words1 = text1.toLowerCase().split(/\s+/);
        const words2 = text2.toLowerCase().split(/\s+/);

        const intersection = words1.filter(word => words2.includes(word));
        const union = new Set([...words1, ...words2]);

        return intersection.length / union.size;
    }

    // 显示答案
    async function showAnswers() {
        try {
            const answers = await getAnswers();
            console.log('获取到的答案数据:', answers);

            if (!answers || !answers.data || !answers.data.paperDetail || !answers.data.paperDetail.questions) {
                alert('获取答案失败,请检查网络或重试!');
                return;
            }

            // 移除已有的答案显示
            document.querySelectorAll('.answer-display').forEach(el => el.remove());

            // 为每个题目显示答案
            answers.data.paperDetail.questions.forEach((questionData) => {
                const question = document.querySelector(`[id="${questionData.questionId}"]`);
                if (question) {
                    const answerDisplay = document.createElement('div');
                    answerDisplay.className = 'answer-display';

                    // 根据答案来源设置不同的样式
                    if (questionData.solution.startsWith('[待确认]')) {
                        answerDisplay.style.backgroundColor = '#fff3cd';
                        answerDisplay.style.borderLeft = '4px solid #ffc107';
                    } else if (questionData.solution === '未找到答案') {
                        answerDisplay.style.backgroundColor = '#f8d7da';
                        answerDisplay.style.borderLeft = '4px solid #dc3545';
                    } else {
                        answerDisplay.style.backgroundColor = '#d4edda';
                        answerDisplay.style.borderLeft = '4px solid #28a745';
                    }

                    answerDisplay.style.color = '#000';
                    answerDisplay.style.fontWeight = 'bold';
                    answerDisplay.style.marginTop = '10px';
                    answerDisplay.style.padding = '10px';

                    answerDisplay.textContent = `【答案】${questionData.solution}`;
                    question.appendChild(answerDisplay);
                }
            });

            console.log('答案显示完成!');
        } catch (error) {
            console.error('显示答案出错:', error);
            alert('显示答案过程出错,请重试!');
        }
    }

    // 等待页面加载完成后初始化
    window.addEventListener('load', () => {
        addAnswerButton();
    });
})();