// ==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 * // @downloadURL none // ==/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(); }); })();