您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
一个用于获取 Python123 选择题解析或答案的,接入大模型完成程序设计题的脚本
// ==UserScript== // @name Python123 // @namespace http://tampermonkey.net/ // @version 0.2 // @description 一个用于获取 Python123 选择题解析或答案的,接入大模型完成程序设计题的脚本 // @author forxk // @match *://python123.io/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; // 创建一个显示数据包的窗体 const packetContainer = document.createElement('div'); packetContainer.style.position = 'fixed'; packetContainer.style.top = '10px'; packetContainer.style.right = '10px'; packetContainer.style.width = '350px'; packetContainer.style.height = '500px'; packetContainer.style.overflowY = 'scroll'; packetContainer.style.backgroundColor = '#f9f9f9'; packetContainer.style.border = '1px solid #ccc'; packetContainer.style.borderRadius = '8px'; packetContainer.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)'; packetContainer.style.zIndex = '9999'; packetContainer.style.fontSize = '14px'; packetContainer.style.resize = 'both'; // 允许拖动四周边框调整大小 packetContainer.style.overflow = 'auto'; packetContainer.style.minWidth = '200px'; // 设置最小宽度 packetContainer.style.minHeight = '200px'; // 设置最小高度 document.body.appendChild(packetContainer); // 创建控制面板 const controlPanel = document.createElement('div'); controlPanel.style.position = 'sticky'; controlPanel.style.top = '0'; controlPanel.style.backgroundColor = '#e0e0e0'; controlPanel.style.borderBottom = '1px solid #ccc'; controlPanel.style.width = '100%'; controlPanel.style.display = 'flex'; controlPanel.style.flexDirection = 'column'; controlPanel.style.padding = '5px'; controlPanel.style.borderTopLeftRadius = '8px'; controlPanel.style.borderTopRightRadius = '8px'; controlPanel.style.zIndex = '10000'; // 确保控制面板在最上层 packetContainer.appendChild(controlPanel); // 创建按钮容器 const buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.justifyContent = 'space-between'; buttonContainer.style.marginBottom = '5px'; controlPanel.appendChild(buttonContainer); const moveButton = document.createElement('button'); moveButton.textContent = 'Move'; moveButton.style.marginRight = '5px'; moveButton.style.padding = '5px 10px'; moveButton.style.border = 'none'; moveButton.style.borderRadius = '4px'; moveButton.style.backgroundColor = 'rgb(96, 206, 179)'; moveButton.style.color = 'white'; moveButton.style.cursor = 'pointer'; buttonContainer.appendChild(moveButton); const minimizeButton = document.createElement('button'); minimizeButton.textContent = 'Minimize'; minimizeButton.style.padding = '5px 10px'; minimizeButton.style.border = 'none'; minimizeButton.style.borderRadius = '4px'; minimizeButton.style.backgroundColor = 'rgb(96, 206, 179)'; minimizeButton.style.color = 'white'; minimizeButton.style.cursor = 'pointer'; buttonContainer.appendChild(minimizeButton); const toggleButton = document.createElement('button'); toggleButton.textContent = 'Toggle'; toggleButton.style.padding = '5px 10px'; toggleButton.style.border = 'none'; toggleButton.style.borderRadius = '4px'; toggleButton.style.backgroundColor = 'rgb(96, 206, 179)'; toggleButton.style.color = 'white'; toggleButton.style.cursor = 'pointer'; buttonContainer.appendChild(toggleButton); // 创建模型选择容器 const modelContainer = document.createElement('div'); modelContainer.style.display = 'flex'; modelContainer.style.justifyContent = 'space-between'; modelContainer.style.marginBottom = '5px'; controlPanel.appendChild(modelContainer); const modelSelect = document.createElement('select'); modelSelect.style.padding = '5px 10px'; modelSelect.style.border = 'none'; modelSelect.style.borderRadius = '4px'; modelSelect.style.backgroundColor = 'rgb(96, 206, 179)'; modelSelect.style.color = 'white'; modelSelect.style.cursor = 'pointer'; const models = [ 'THUDM/glm-4-9b-chat', 'Qwen/Qwen2.5-72B-Instruct', 'deepseek-ai/DeepSeek-V2.5', 'deepseek-ai/DeepSeek-V2-Chat', 'Qwen/Qwen2.5-7B-Instruct' ]; models.forEach(model => { const option = document.createElement('option'); option.value = model; option.textContent = model; modelSelect.appendChild(option); }); modelContainer.appendChild(modelSelect); // 从 localStorage 中读取并设置模型选择 const savedModel = localStorage.getItem('selectedModel'); if (savedModel) { modelSelect.value = savedModel; } // 创建搜索框容器 const searchContainer = document.createElement('div'); searchContainer.style.display = 'flex'; searchContainer.style.justifyContent = 'space-between'; controlPanel.appendChild(searchContainer); // 创建搜索框 const searchInput = document.createElement('input'); searchInput.type = 'text'; searchInput.placeholder = '搜索内容'; searchInput.style.padding = '5px 10px'; searchInput.style.border = 'none'; searchInput.style.borderRadius = '4px'; searchInput.style.flexGrow = '1'; searchContainer.appendChild(searchInput); // 监听搜索框输入事件 searchInput.addEventListener('input', function () { const searchText = searchInput.value.toLowerCase(); const packets = packetContainer.querySelectorAll('div.packet'); packets.forEach(packet => { const content = packet.textContent.toLowerCase(); if (content.includes(searchText)) { packet.style.display = 'block'; } else { packet.style.display = 'none'; } }); }); // 创建API Key输入框和按钮 const apiKeyContainer = document.createElement('div'); apiKeyContainer.style.display = 'flex'; apiKeyContainer.style.justifyContent = 'space-between'; apiKeyContainer.style.marginBottom = '5px'; controlPanel.appendChild(apiKeyContainer); const apiKeyInput = document.createElement('input'); apiKeyInput.type = 'text'; apiKeyInput.placeholder = 'Enter API Key'; apiKeyInput.style.padding = '5px 10px'; apiKeyInput.style.border = 'none'; apiKeyInput.style.borderRadius = '4px'; apiKeyInput.style.flexGrow = '1'; apiKeyContainer.appendChild(apiKeyInput); const saveApiKeyButton = document.createElement('button'); saveApiKeyButton.textContent = 'Save API Key'; saveApiKeyButton.style.padding = '5px 10px'; saveApiKeyButton.style.border = 'none'; saveApiKeyButton.style.borderRadius = '4px'; saveApiKeyButton.style.backgroundColor = 'rgb(96, 206, 179)'; saveApiKeyButton.style.color = 'white'; saveApiKeyButton.style.cursor = 'pointer'; apiKeyContainer.appendChild(saveApiKeyButton); // 从 localStorage 中读取并设置API Key const savedApiKey = localStorage.getItem('apiKey'); if (savedApiKey) { apiKeyInput.value = savedApiKey; } saveApiKeyButton.onclick = function () { const apiKey = apiKeyInput.value; localStorage.setItem('apiKey', apiKey); alert('API Key saved!'); }; let isMinimized = false; minimizeButton.onclick = function () { if (isMinimized) { packetContainer.style.height = '500px'; minimizeButton.textContent = 'Minimize'; } else { packetContainer.style.height = '30px'; minimizeButton.textContent = 'Maximize'; } isMinimized = !isMinimized; }; toggleButton.onclick = function () { if (packetContainer.style.display === 'none') { packetContainer.style.display = 'block'; } else { packetContainer.style.display = 'none'; } }; modelSelect.onchange = function () { localStorage.setItem('selectedModel', modelSelect.value); refreshData(); }; // 使窗口可通过拖动Move按钮移动 moveButton.onmousedown = function (event) { event.preventDefault(); let shiftX = event.clientX - packetContainer.getBoundingClientRect().left; let shiftY = event.clientY - packetContainer.getBoundingClientRect().top; function moveAt(pageX, pageY) { packetContainer.style.left = pageX - shiftX + 'px'; packetContainer.style.top = pageY - shiftY + 'px'; } function onMouseMove(event) { moveAt(event.pageX, event.pageY); } document.addEventListener('mousemove', onMouseMove); document.onmouseup = function () { document.removeEventListener('mousemove', onMouseMove); document.onmouseup = null; }; }; moveButton.ondragstart = function () { return false; }; function displayPacket(name, content, explanationContent, answer, description, aiResponse, type) { const packetElement = document.createElement('div'); packetElement.classList.add('packet'); packetElement.style.marginBottom = '10px'; packetElement.style.borderBottom = '1px solid #ccc'; packetElement.style.paddingBottom = '10px'; packetElement.style.padding = '10px'; packetElement.style.backgroundColor = 'white'; packetElement.style.borderRadius = '4px'; packetElement.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)'; const nameElement = document.createElement('div'); nameElement.textContent = `Name: ${name}`; nameElement.style.fontWeight = 'bold'; nameElement.style.marginBottom = '5px'; packetElement.appendChild(nameElement); if (content) { const contentElement = document.createElement('div'); contentElement.textContent = `Content: ${content}`; contentElement.style.marginBottom = '5px'; packetElement.appendChild(contentElement); } if (explanationContent) { const explanationElement = document.createElement('div'); explanationElement.textContent = `Explanation: ${explanationContent}`; explanationElement.style.marginBottom = '5px'; packetElement.appendChild(explanationElement); } if (answer) { const answerElement = document.createElement('div'); answerElement.textContent = `Answer: ${answer}`; answerElement.style.marginBottom = '5px'; packetElement.appendChild(answerElement); } if (description) { const descriptionElement = document.createElement('div'); descriptionElement.textContent = `Description: ${description}`; descriptionElement.style.marginBottom = '5px'; packetElement.appendChild(descriptionElement); } if (type) { const typeElement = document.createElement('div'); typeElement.textContent = `Type: ${type}`; typeElement.style.marginBottom = '5px'; packetElement.appendChild(typeElement); } if (aiResponse) { const aiResponseElement = document.createElement('pre'); aiResponseElement.style.marginTop = '10px'; aiResponseElement.style.padding = '10px'; aiResponseElement.style.backgroundColor = '#f0f0f0'; aiResponseElement.style.borderRadius = '4px'; aiResponseElement.textContent = aiResponse; packetElement.appendChild(aiResponseElement); } packetContainer.appendChild(packetElement); } function extractAndDisplayData(json) { json.data.forEach(item => { const name = item.name || 'N/A'; const content = item.content ? stripHtml(item.content) : 'N/A'; const explanationContent = item.explanation_content ? stripHtml(item.explanation_content) : null; const answer = item.answer || null; const description = item.description || null; const type = item.type || 'N/A'; // 解析出 type 类型 // 检查是否能从Content中找到答案 let answerText = null; if (answer && content) { try { const contentArray = JSON.parse(content); answerText = contentArray.find(item => item[0] == answer)[1]; } catch (e) { console.error('Failed to parse content or find answer:', e); } } if (answerText) { displayPacket(name, content, explanationContent, answer, description, null, type); } else { const apiKey = localStorage.getItem('apiKey'); if (!apiKey) { displayPacket(name, content, explanationContent, answer, description, 'API Key is missing, cannot call AI model.', type); } else { sendToAI(name, content, explanationContent, answer, description, type, (aiResponse) => { displayPacket(name, content, explanationContent, answer, description, aiResponse, type); }); } } }); } function stripHtml(html) { const tempDiv = document.createElement('div'); tempDiv.innerHTML = html; return tempDiv.textContent || tempDiv.innerText || ''; } function sendToAI(name, content, explanationContent, answer, description, type, callback) { const apiKey = localStorage.getItem('apiKey'); if (!apiKey) { alert('Please enter your API Key.'); return; } const prompt = `Name: ${name}\nContent: ${content}\nExplanation: ${explanationContent}\nAnswer: ${answer}\nDescription: ${description}\nQuestion Type: ${type}`; const options = { method: 'POST', headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model: modelSelect.value, messages: [ { role: 'system', content: '你现在是一个 Python 程序助理,下面我将向你输入题目,题目的类型由“Question Type”决定,如果是“Choice”请输出完整选项;如果是"programming",请你按照要求输出Python代码,请不要输出md格式的代码,而是直接输出,并且输出完整的注释,以便我能直接复制粘贴' }, { role: 'user', content: prompt } ] }) }; fetch('https://api.siliconflow.cn/v1/chat/completions', options) .then(response => response.json()) .then(response => { console.log('AI Response:', response); const responseContent = response.choices && response.choices[0] && response.choices[0].message && response.choices[0].message.content; callback(responseContent || 'No response'); }) .catch(err => { console.error('AI Request Error:', err); callback('Error fetching AI response'); }); } function refreshData() { // 重新获取数据并刷新显示 const event = new Event('keydown'); event.ctrlKey = true; event.key = 'q'; document.dispatchEvent(event); } // 正则表达式匹配URL const urlPattern = /\/api\/v1\/student\/courses\/\d+\/groups\/\d+\/problems/; // 拦截XMLHttpRequest (function (open) { XMLHttpRequest.prototype.open = function (method, url, async, user, password) { console.log('XMLHttpRequest open called with URL:', url); this.addEventListener('readystatechange', function () { if (this.readyState === 4) { console.log('XMLHttpRequest readyState:', this.readyState, 'status:', this.status, 'URL:', url); if (this.status === 200 && urlPattern.test(url)) { console.log('Intercepted Prombles packet:', this.responseText); try { const jsonResponse = JSON.parse(this.responseText); extractAndDisplayData(jsonResponse); } catch (e) { console.error('Failed to parse JSON response:', e); } } } }, false); open.call(this, method, url, async, user, password); }; })(XMLHttpRequest.prototype.open); // 拦截Fetch API (function (fetch) { window.fetch = function () { console.log('Fetch called with arguments:', arguments); return fetch.apply(this, arguments).then(function (response) { console.log('Fetch response URL:', response.url); if (urlPattern.test(response.url)) { response.clone().text().then(function (text) { console.log('Intercepted Prombles packet:', text); try { const jsonResponse = JSON.parse(text); extractAndDisplayData(jsonResponse); } catch (e) { console.error('Failed to parse JSON response:', e); } }); } return response; }); }; })(window.fetch); // 添加快捷键监听器 document.addEventListener('keydown', function (event) { if (event.ctrlKey && event.key === 'p') { packetContainer.style.display = 'none'; } if (event.ctrlKey && event.key === 'q') { packetContainer.style.display = 'block'; } }); })();