AI解题脚本安装
一、环境要求
电脑、Edge浏览器
二、安装浏览器插件
- 安装“篡改猴(原tampermonkey)”,安装链接(从Edge插件商店下载):直达链接
点击
获取,再点击添加扩展

三、设置浏览器
- 在搜索框输入
edge://extensions/并回车打开扩展设置页面
- 打开浏览器
开发者模式,
- 点击插件
详细信息
勾选
允许用户脚本
四、安装AI解题脚本
- 点击右上角拼图状“扩展”图形

- 点击“篡改猴”插件

点击
添加新脚本
将默认的代码全部删除,并且粘贴我写的代码,最后按ctrl+S保存就大功告成了
五、学习通网页版地址
点击链接直达:链接
六、其他
我的代码(点击右上角copy按钮可直接复制):
// ==UserScript== // @name 学习通考试 · DeepSeek AI 解题助手 // @namespace cx-deepseek-helper // @version 1.6.0 // @description 提取学习通考试题目,调用 DeepSeek API 进行 AI 解析,结果浮窗展示 // @match *://*.chaoxing.com/* // @match *://*.xuexitong.com/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @connect api.deepseek.com // @run-at document-end // ==/UserScript== (function () { 'use strict'; const CONFIG = { apiKey: GM_getValue('ds_api_key', ''), model: 'deepseek-v4-pro', maxTokens: 4096, systemPrompt: `你是一个专业的考试解题助手。 用户会给你提供题目类型、题干和选项(如有)。 请按以下格式回答: 【答案】直接给出答案(单选给选项字母,多选给多个字母,判断题给"正确"或"错误",填空/简答直接给答案文字) 【解析】用2-4句话解释理由,要简洁准确。`, }; GM_addStyle(` #cx-ds-panel { position: fixed; top: 60px; right: 20px; z-index: 2147483647; width: 460px; max-height: 88vh; background: #fff; border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,.18); font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; font-size: 13px; overflow: hidden; display: flex; flex-direction: column; pointer-events: auto !important; } .ds-header { background: linear-gradient(135deg,#1a73e8,#0d47a1); color:#fff; padding:10px 14px; display:flex; align-items:center; justify-content:space-between; cursor:move; user-select:none; flex-shrink:0; } .ds-header .title { font-weight:600; font-size:14px; } .ds-header .ds-btns { display:flex; gap:5px; flex-wrap:wrap; } .ds-header button { background:rgba(255,255,255,.2); border:none; color:#fff; border-radius:6px; padding:4px 10px; cursor:pointer; font-size:11px; pointer-events: auto !important; } .ds-header button:hover { background:rgba(255,255,255,.38); } .ds-settings { padding:8px 12px; background:#f5f7fa; border-bottom:1px solid #e8eaed; flex-shrink:0; } .ds-settings input { width:100%; box-sizing:border-box; padding:6px 8px; border:1px solid #ccc; border-radius:6px; font-size:12px; margin-top:3px; } .ds-settings label { font-size:12px; color:#555; } #cx-ds-progress-wrap { height:3px; background:#e8eaed; flex-shrink:0; } #cx-ds-progress-bar { height:100%; width:0%; background:linear-gradient(90deg,#1a73e8,#34a853); transition:width .4s ease; } #cx-ds-body { overflow-y:auto; padding:12px; flex:1; } .ds-q-card { border:1px solid #dce3f0; border-radius:10px; margin-bottom:16px; overflow:hidden; box-shadow:0 2px 8px rgba(26,115,232,.06); } .ds-q-head { background:linear-gradient(90deg,#e8f0fe,#f0f4ff); padding:8px 12px; display:flex; align-items:center; justify-content:space-between; border-bottom:1px solid #dce3f0; } .ds-q-num { font-weight:700; color:#1a73e8; font-size:13px; } .ds-q-type { font-size:11px; font-weight:700; background:#1a73e8; color:#fff; border-radius:4px; padding:2px 8px; } .ds-q-title-block { padding:10px 14px; border-bottom:1px dashed #e0e7f5; background:#fff; } .ds-block-label { font-size:10px; font-weight:700; color:#888; letter-spacing:.5px; margin-bottom:5px; display:flex; align-items:center; gap:4px; } .ds-q-title-text { color:#111; font-size:13px; line-height:1.8; white-space:pre-wrap; word-break:break-word; background:#f7f9ff; border:1px solid #dce3f0; border-radius:6px; padding:8px 10px; max-height:200px; overflow-y:auto; } .ds-q-options-block { padding:8px 14px 10px; background:#f8faff; border-bottom:1px dashed #e0e7f5; } .ds-q-option-row { display:flex; gap:6px; align-items:baseline; padding:3px 6px; border-radius:5px; font-size:12px; line-height:1.7; color:#333; margin-bottom:1px; } .ds-q-option-row:hover { background:#e8f0fe; } .ds-q-option-letter { font-weight:700; color:#1a73e8; min-width:18px; flex-shrink:0; } .ds-q-option-text { word-break:break-word; white-space:pre-wrap; } .ds-no-option { font-size:11px; color:#aaa; padding:4px 14px 8px; font-style:italic; } .ds-status-bar { display:flex; align-items:center; gap:8px; padding:8px 12px; font-size:12px; background:#fafafa; border-top:1px solid #eee; } .ds-status-bar.waiting { color:#999; } .ds-status-bar.loading { color:#1a73e8; background:rgba(232,240,254,.4); } .ds-status-bar.done { color:#00897b; background:rgba(246,255,248,.6); } .ds-status-bar.error { color:#d32f2f; background:rgba(255,240,240,.6); } .ds-q-answer-wrap { padding:10px 14px; background:#fff; } .ds-answer-box { background:#f6fff8; border:1px solid #b2dfdb; border-radius:7px; padding:8px 10px; margin-bottom:8px; } .ds-analysis-box { background:#f0f4ff; border:1px solid #c5cae9; border-radius:7px; padding:8px 10px; } .ds-answer-label-tag { display:inline-block; font-size:11px; font-weight:700; border-radius:4px; padding:1px 7px; margin-bottom:5px; } .ds-answer-label-tag.answer { background:#00897b; color:#fff; } .ds-answer-label-tag.analysis { background:#3949ab; color:#fff; } .ds-answer-content { color:#1a1a1a; line-height:1.7; font-size:13px; } .ds-spinner { width:14px; height:14px; border:2px solid #ccc; border-top-color:#1a73e8; border-radius:50%; animation:ds-spin .7s linear infinite; flex-shrink:0; } @keyframes ds-spin { to{transform:rotate(360deg);} } #cx-ds-panel.minimized .ds-settings, #cx-ds-panel.minimized #cx-ds-body, #cx-ds-panel.minimized #cx-ds-progress-wrap { display:none; } .ds-count-badge { background:#ff5722; color:#fff; border-radius:10px; padding:1px 7px; font-size:11px; margin-left:6px; } /* 复制成功提示 toast */ #cx-ds-toast { position:fixed; bottom:32px; left:50%; transform:translateX(-50%) translateY(20px); background:#323232; color:#fff; border-radius:8px; padding:8px 20px; font-size:13px; z-index:2147483648; opacity:0; transition:opacity .3s, transform .3s; pointer-events:none; } #cx-ds-toast.show { opacity:1; transform:translateX(-50%) translateY(0); } `); // ── 工具函数 ────────────────────────────────────── function escHtml(s) { return String(s) .replace(/&/g,'&').replace(/</g,'<') .replace(/>/g,'>').replace(/"/g,'"'); } function showToast(msg) { let t = document.getElementById('cx-ds-toast'); if (!t) { t = document.createElement('div'); t.id = 'cx-ds-toast'; document.documentElement.appendChild(t); } t.textContent = msg; t.classList.add('show'); clearTimeout(t._timer); t._timer = setTimeout(() => t.classList.remove('show'), 2000); } function cleanText(node) { if (!node) return ''; const clone = node.cloneNode(true); clone.querySelectorAll('.colorShallow, input, script, style').forEach(el => el.remove()); clone.querySelectorAll('br').forEach(el => el.replaceWith('\n')); return (clone.textContent || '').replace(/[ \t]{2,}/g,' ').replace(/\n{3,}/g,'\n\n').trim(); } const TYPE_NAME = { '0':'单选题','1':'多选题','2':'填空题','3':'判断题', '4':'简答题','5':'名词解释','6':'论述题','7':'计算题', '13':'排序题','15':'阅读理解','20':'共用选项题','999':'未知类型' }; const TYPE_MAP = new Map([ ['单选题','0'],['A1型题','0'],['A1A2型题','0'],['A2','0'],['A1','0'], ['多选题','1'],['X型题','1'], ['填空题','2'],['判断题','3'],['简答题','4'], ['名词解释','5'],['论述题','6'],['计算题','7'],['排序题','13'], ['阅读理解','15'], ['B型题','20'],['B1型题','20'],['B1','20'],['共用选项题','20'], ]); function resolveTypeCode(raw) { if (!raw) return '999'; const s = raw.replace(/[\[\]【】()()\s]/g,'').trim(); if (TYPE_MAP.has(s)) return TYPE_MAP.get(s); for (const [k,v] of TYPE_MAP) { if (s.includes(k)||k.includes(s)) return v; } if (/^\d+$/.test(s)) return s; return '999'; } // ── 题目提取 ────────────────────────────────────── function extractQuestions(doc) { if (!doc) return []; const questions = []; let containers = [...doc.querySelectorAll('.questionLi')]; let mode = 'ks'; if (!containers.length) { containers = [...doc.querySelectorAll('.noSplitBx')]; mode = 'ks'; } if (!containers.length) { containers = [...doc.querySelectorAll('.TiMu')]; mode = 'zj'; } containers.forEach((el, idx) => { let title = '', rawType = '', options = []; try { if (mode === 'zj') { title = cleanText(el.querySelector('.fontLabel')); rawType = cleanText(el.querySelector('.newZy_TItle')); el.querySelectorAll('[class*="before-after"]').forEach(o => { const t = cleanText(o.querySelector('.fl.after') || o); if (t) options.push(t); }); } else { const shallow = el.querySelector('.colorShallow'); if (shallow) rawType = shallow.textContent.replace(/[()()\[\]【】]/g,'').trim(); if (!rawType) rawType = el.getAttribute('typename') || ''; if (!rawType) { const ti = el.querySelector('input[id^="typeName"]'); if (ti) rawType = ti.value; } const typeValInput = el.querySelector('input[name^="type"]'); const numericType = typeValInput ? typeValInput.value : ''; const typeCode = resolveTypeCode(rawType) !== '999' ? resolveTypeCode(rawType) : (numericType || '999'); const h3 = el.querySelector('h3.mark_name') || el.querySelector('h3'); if (h3) title = cleanText(h3); title = title.replace(/^\d+\.\s*/,'').replace(/^【.*?】\s*/,'').replace(/\s*(\d+\.\d+分)$/,'').trim(); const numCode = parseInt(typeCode); if (numCode === 20) { const sharedOpts = []; el.querySelectorAll('.stem_answer .clearfix').forEach(row => { const text = row.querySelector('.p_wid805, .fr') ? (row.querySelector('.p_wid805, .fr').textContent||'').trim() : ''; if (text) sharedOpts.push(text); }); el.querySelectorAll('.B-answer-ct').forEach((sub, si) => { const subTitle = sub.querySelector('.B-tit') ? sub.querySelector('.B-tit').textContent.trim() : ('子题'+(si+1)); questions.push({ index: questions.length + 1, type: '20', typeName: '共用选项题', title: title ? (title + '\n' + subTitle) : subTitle, options: [...sharedOpts], rawType, }); }); return; } else if (numCode === 15) { el.querySelectorAll('.reading_answer').forEach((sub, si) => { const titEl = sub.querySelector('.reader_answer_tit'); const subTit = titEl ? titEl.textContent.replace(/\(.*?\)/g,'').trim() : ('子题'+(si+1)); const typeEl = sub.querySelector('.read_type'); const subType = typeEl ? typeEl.textContent.replace(/[()()]/g,'').trim() : '简答题'; const subCode = resolveTypeCode(subType); questions.push({ index: questions.length + 1, type: subCode, typeName: TYPE_NAME[subCode] || subType, title: subTit, options: [], rawType: subType, }); }); return; } else { el.querySelectorAll('.answerBg').forEach(opt => { const ap = opt.querySelector('.answer_p'); const t = (ap ? ap.textContent : opt.textContent).trim(); if (t) options.push(t); }); } if (!title) return; questions.push({ index: questions.length + 1, type: typeCode, typeName: TYPE_NAME[typeCode] || '未知类型', title, options, rawType, }); return; } // 章节测试通用 push if (!title) return; const typeCode = resolveTypeCode(rawType); questions.push({ index: questions.length + 1, type: typeCode, typeName: TYPE_NAME[typeCode] || '未知类型', title, options, rawType, }); } catch(e) { /* 静默忽略单题错误 */ } }); questions.forEach((q,i) => q.index = i + 1); return questions; } function getAllQuestions() { let qs = extractQuestions(document); if (qs.length) return qs; for (const f of document.querySelectorAll('iframe')) { try { const fd = f.contentDocument || f.contentWindow?.document; if (!fd) continue; const r = extractQuestions(fd); if (r.length) return r; } catch(e) {} } return []; } // ── 题目卡片渲染 ─────────────────────────────────── function renderCards(panel, questions, mode) { const body = panel.querySelector('#cx-ds-body'); body.innerHTML = ''; questions.forEach(q => { const card = document.createElement('div'); card.className = 'ds-q-card'; card.id = 'ds-card-' + q.index; let optBlock = ''; if (q.options.length) { const rows = q.options.map((o,i) => '<div class="ds-q-option-row">' + '<span class="ds-q-option-letter">' + String.fromCharCode(65+i) + '.</span>' + '<span class="ds-q-option-text">' + escHtml(o) + '</span>' + '</div>' ).join(''); optBlock = '<div class="ds-q-options-block"><div class="ds-block-label">📋 选项(共'+q.options.length+'项)</div>'+rows+'</div>'; } else { optBlock = '<div class="ds-no-option">(无选项 — ' + q.typeName + ')</div>'; } const statusHtml = mode === 'solving' ? '<div class="ds-status-bar waiting" id="ds-status-'+q.index+'">⏳ 等待 AI 解析…</div>' : '<div class="ds-status-bar done">✅ 已提取</div>'; const answerBlock = mode === 'solving' ? '<div class="ds-q-answer-wrap" id="ds-answer-'+q.index+'"></div>' : ''; card.innerHTML = '<div class="ds-q-head">' + '<span class="ds-q-num">第 ' + q.index + ' 题</span>' + '<span class="ds-q-type">' + q.typeName + '</span>' + '</div>' + '<div class="ds-q-title-block">' + '<div class="ds-block-label">📌 题干</div>' + '<div class="ds-q-title-text">' + escHtml(q.title) + '</div>' + '</div>' + optBlock + statusHtml + answerBlock; body.appendChild(card); }); } // ── 复制题目为纯文本 ────────────────────────────── function copyQuestionsText(questions) { const lines = questions.map(q => { let s = '第' + q.index + '题【' + q.typeName + '】\n' + q.title; if (q.options.length) { s += '\n' + q.options.map((o,i) => String.fromCharCode(65+i) + '. ' + o).join('\n'); } return s; }); const text = lines.join('\n\n'); try { navigator.clipboard.writeText(text).then( () => showToast('✅ 已复制 ' + questions.length + ' 道题目到剪贴板'), () => fallbackCopy(text) ); } catch(e) { fallbackCopy(text); } } function fallbackCopy(text) { const ta = document.createElement('textarea'); ta.value = text; ta.style.cssText = 'position:fixed;opacity:0;top:0;left:0;'; document.body.appendChild(ta); ta.select(); try { document.execCommand('copy'); showToast('✅ 已复制题目到剪贴板'); } catch(e) { showToast('❌ 复制失败,请手动复制'); } document.body.removeChild(ta); } // ── DeepSeek API(非流式)──────────────────────── function buildPrompt(q) { let t = '题目类型:' + q.typeName + '\n题干:' + q.title; if (q.options.length) t += '\n选项:\n' + q.options.map((o,i) => ' ' + String.fromCharCode(65+i) + '. ' + o).join('\n'); return t; } function callDeepSeek(prompt, onDone, onError) { if (!CONFIG.apiKey) { onError('未配置 API Key,请在面板顶部填写'); return; } GM_xmlhttpRequest({ method: 'POST', url: 'https://api.deepseek.com/chat/completions', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + CONFIG.apiKey, 'Accept': 'application/json', }, data: JSON.stringify({ model: CONFIG.model, max_tokens: CONFIG.maxTokens, stream: false, messages: [ { role: 'system', content: CONFIG.systemPrompt }, { role: 'user', content: prompt }, ], }), timeout: 60000, onload(res) { try { if (res.status !== 200) { onError('HTTP ' + res.status + ':' + res.responseText.slice(0,200)); return; } const json = JSON.parse(res.responseText); const text = json.choices?.[0]?.message?.content || ''; if (!text) { onError('API 返回内容为空'); return; } onDone(text); } catch(e) { onError('解析响应失败:' + e.message); } }, onerror(e) { onError('网络错误:' + (e.statusText || JSON.stringify(e))); }, ontimeout() { onError('请求超时(60s),请检查网络或 API Key 余额'); }, }); } function formatBoxes(text) { if (!text) return '<div style="color:#aaa;padding:8px">(无内容)</div>'; const am = text.match(/【答案】([\s\S]*?)(?=【解析】|$)/); const sm = text.match(/【解析】([\s\S]*?)$/); if (!am && !sm) { return '<div style="white-space:pre-wrap;padding:8px;font-size:13px;line-height:1.7">' + escHtml(text) + '</div>'; } let h = ''; if (am) h += '<div class="ds-answer-box"><span class="ds-answer-label-tag answer">📌 答案</span>' + '<div class="ds-answer-content">' + escHtml(am[1].trim()).replace(/\n/g,'<br>') + '</div></div>'; if (sm) h += '<div class="ds-analysis-box"><span class="ds-answer-label-tag analysis">💡 解析</span>' + '<div class="ds-answer-content">' + escHtml(sm[1].trim()).replace(/\n/g,'<br>') + '</div></div>'; return h; } // ── 解题流程 ────────────────────────────────────── function startSolving(panel, questions) { const bar = panel.querySelector('#cx-ds-progress-bar'); const count = panel.querySelector('#cx-ds-count'); count.textContent = questions.length; count.style.display = 'inline-block'; renderCards(panel, questions, 'solving'); (async () => { for (let i = 0; i < questions.length; i++) { const q = questions[i]; const status = document.getElementById('ds-status-' + q.index); const wrap = document.getElementById('ds-answer-' + q.index); if (!wrap) continue; if (status) { status.className = 'ds-status-bar loading'; status.innerHTML = '<div class="ds-spinner"></div> AI 正在思考第 ' + q.index + ' 题…'; } document.getElementById('ds-card-' + q.index) ?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); wrap.innerHTML = '<div style="display:flex;align-items:center;gap:8px;padding:10px 12px;color:#1a73e8;font-size:12px;">' + '<div class="ds-spinner"></div>正在请求 DeepSeek API…</div>'; await new Promise(resolve => { callDeepSeek( buildPrompt(q), (final) => { wrap.innerHTML = '<div class="ds-block-label" style="padding:6px 0 4px">🤖 AI 解答</div>' + formatBoxes(final); if (status) { status.className = 'ds-status-bar done'; status.textContent = '✅ 解析完成'; } bar.style.width = ((i + 1) / questions.length * 100) + '%'; resolve(); }, (err) => { wrap.innerHTML = '<div class="ds-status-bar error" style="padding:10px 12px">❌ ' + escHtml(err) + '</div>'; if (status) { status.className = 'ds-status-bar error'; status.textContent = '❌ 失败'; } bar.style.width = ((i + 1) / questions.length * 100) + '%'; resolve(); } ); }); await new Promise(r => setTimeout(r, 500)); } bar.style.width = '100%'; showToast('✅ 全部 ' + questions.length + ' 题解析完成'); })(); } // ── 面板创建 ────────────────────────────────────── function createPanel() { if (document.getElementById('cx-ds-panel')) return; const panel = document.createElement('div'); panel.id = 'cx-ds-panel'; panel.innerHTML = '<div class="ds-header" id="cx-ds-drag">' + '<span class="title">🤖解析(QingYi♥)' + '<span id="cx-ds-count" class="ds-count-badge" style="display:none">0</span>' + '</span>' + '<div class="ds-btns">' + '<button id="cx-ds-copy" type="button">📄 复制题目</button>' + '<button id="cx-ds-start" type="button">🚀 开始解析</button>' + '<button id="cx-ds-clear" type="button">🗑 清空</button>' + '<button id="cx-ds-min" type="button">—</button>' + '</div></div>' + '<div class="ds-settings">' + '<label>DeepSeek API Key</label>' + '<input id="cx-ds-apikey" type="password" placeholder="sk-..." value="' + escHtml(CONFIG.apiKey) + '" autocomplete="off"/>' + '</div>' + '<div id="cx-ds-progress-wrap"><div id="cx-ds-progress-bar"></div></div>' + '<div id="cx-ds-body">' + '<div style="color:#999;text-align:center;padding:24px 0;font-size:12px;">' + '点「📄 复制题目」可将所有题目复制到剪贴板<br>点「🚀 开始解析」自动提取题目并调用 AI 解析' + '</div></div>'; document.documentElement.appendChild(panel); panel.querySelector('#cx-ds-apikey').addEventListener('input', e => { CONFIG.apiKey = e.target.value.trim(); GM_setValue('ds_api_key', CONFIG.apiKey); }); let minimized = false; panel.querySelector('#cx-ds-min').addEventListener('click', () => { minimized = !minimized; panel.classList.toggle('minimized', minimized); panel.querySelector('#cx-ds-min').textContent = minimized ? '□' : '—'; }); panel.querySelector('#cx-ds-clear').addEventListener('click', () => { panel._qs = null; panel.querySelector('#cx-ds-body').innerHTML = '<div style="color:#999;text-align:center;padding:24px 0;font-size:12px;">已清空</div>'; panel.querySelector('#cx-ds-count').style.display = 'none'; panel.querySelector('#cx-ds-progress-bar').style.width = '0%'; }); // ★ 复制题目 panel.querySelector('#cx-ds-copy').addEventListener('click', () => { const qs = panel._qs && panel._qs.length ? panel._qs : getAllQuestions(); if (!qs.length) { showToast('❌ 未检测到题目'); return; } panel._qs = qs; copyQuestionsText(qs); }); // ★ 开始解析(自动提取 + 解析) panel.querySelector('#cx-ds-start').addEventListener('click', () => { if (!CONFIG.apiKey) { alert('请先填写 DeepSeek API Key!'); return; } const qs = getAllQuestions(); if (!qs.length) { alert('未检测到题目,请确认已进入考试/作业/章节测试页面。'); return; } panel._qs = qs; startSolving(panel, qs); }); makeDraggable(panel, panel.querySelector('#cx-ds-drag')); } function makeDraggable(el, handle) { let sx, sy, il, it; handle.addEventListener('mousedown', e => { if (e.target.tagName === 'BUTTON' || e.target.tagName === 'INPUT') return; sx = e.clientX; sy = e.clientY; const r = el.getBoundingClientRect(); il = r.left; it = r.top; el.style.right = 'auto'; el.style.left = il + 'px'; el.style.top = it + 'px'; const mv = ev => { el.style.left=(il+ev.clientX-sx)+'px'; el.style.top=(it+ev.clientY-sy)+'px'; }; const up = () => { document.removeEventListener('mousemove',mv); document.removeEventListener('mouseup',up); }; document.addEventListener('mousemove', mv); document.addEventListener('mouseup', up); e.preventDefault(); }); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', createPanel); } else { createPanel(); } })();