好友
阅读权限10
听众
最后登录1970-1-1
|
本帖最后由 backaxe 于 2025-6-8 16:08 编辑
安装步骤- 创建一个新文件夹,将所有文件保存到该文件夹中
- 打开Chrome浏览器,访问 chrome://extensions/
- 开启"开发者模式"
- 点击"加载已解压的扩展程序",选择你的插件文件夹
- 插件安装完成后,点击插件图标进行设置
使用方法- 配置API:点击插件图标,填入API地址和密钥
- 选择文本:在任何网页上用鼠标选中题目文本
- 分析题目:按快捷键开始分析
- 查看结果:分析结果会显示在题目下方,包含答案和解析
特色功能- 🎯 智能识别:自动识别并格式化答案和解析部分
- 🔄 实时反馈:显示加载状态和错误提示
- 🎨 美观界面:现代化的UI设计,支持响应式布局
- ⌨️ 快捷操作:支持Esc键关闭结果窗口
- 🛡️ 错误处理:完善的错误提示和异常处理
插件已经配置了专业的提示词,会要求AI助手提供准确的答案和详细解析。你只需要根据你使用的AI服务商(如OpenAI、Claude、国内厂商等)调整API地址和认证方式即可使用。PS:插件完全通过claude.ai生成
[JavaScript] 纯文本查看 复制代码 // content.js
console.log('Content script loaded on:', window.location.href);
let isAnalyzing = false;
let currentShortcut = 'F2'; // 默认快捷键
// 初始化时获取快捷键设置
chrome.storage.sync.get(['shortcut'], function(result) {
currentShortcut = result.shortcut || 'F2';
console.log('Current shortcut set to:', currentShortcut);
});
// 监听存储变化,更新快捷键设置
chrome.storage.onChanged.addListener(function(changes, namespace) {
if (changes.shortcut) {
currentShortcut = changes.shortcut.newValue;
console.log('Shortcut updated to:', currentShortcut);
}
});
// 监听来自background script的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('Message received in content script:', request);
if (request.action === 'analyzeSelectedText') {
analyzeSelectedText();
sendResponse({ received: true });
}
return true;
});
// 键盘事件监听
document.addEventListener('keydown', function(event) {
console.log('Key pressed:', event.key, 'Current shortcut:', currentShortcut);
// 检查是否是设置的功能键
if (event.key === currentShortcut) {
event.preventDefault();
console.log('Shortcut key matched, analyzing text');
analyzeSelectedText();
return;
}
// 备用快捷键:Ctrl+Shift+A 或 Cmd+Shift+A
if ((event.ctrlKey || event.metaKey) && event.shiftKey && event.key === 'A') {
event.preventDefault();
console.log('Legacy shortcut detected');
analyzeSelectedText();
return;
}
// 额外的备用快捷键:Alt+Q
if (event.altKey && event.key === 'q') {
event.preventDefault();
console.log('Alt+Q shortcut detected');
analyzeSelectedText();
return;
}
}, true); // 使用捕获阶段确保优先处理
// 分析选中的文本
async function analyzeSelectedText() {
console.log('analyzeSelectedText called, isAnalyzing:', isAnalyzing);
if (isAnalyzing) {
showNotification('正在分析中,请稍候...', 'warning');
return;
}
const selectedText = window.getSelection().toString().trim();
console.log('Selected text length:', selectedText.length);
console.log('Selected text preview:', selectedText.substring(0, 100));
if (!selectedText) {
showNotification('请先用鼠标选中要分析的题目文本', 'error');
return;
}
if (selectedText.length < 3) {
showNotification('选中的文本太短,请选择完整的题目', 'warning');
return;
}
isAnalyzing = true;
// 显示加载状态
const loadingElement = showLoadingIndicator();
try {
console.log('Sending message to background script');
// 发送消息给background script进行AI分析
chrome.runtime.sendMessage({
action: 'analyzeText',
text: selectedText
}, (response) => {
console.log('Response from background:', response);
isAnalyzing = false;
// 移除加载指示器
if (loadingElement && loadingElement.parentNode) {
loadingElement.remove();
}
if (chrome.runtime.lastError) {
console.error('Runtime error:', chrome.runtime.lastError);
showNotification('插件连接错误:' + chrome.runtime.lastError.message, 'error');
return;
}
if (response && response.success) {
displayAnalysisResult(selectedText, response.result);
} else {
const errorMsg = response?.error || '分析失败,请检查网络连接和API设置';
showNotification(errorMsg, 'error');
}
});
} catch (error) {
console.error('Error in analyzeSelectedText:', error);
isAnalyzing = false;
if (loadingElement && loadingElement.parentNode) {
loadingElement.remove();
}
showNotification('发生错误:' + error.message, 'error');
}
}
// 显示加载指示器
function showLoadingIndicator() {
const selection = window.getSelection();
if (selection.rangeCount === 0) {
// 如果没有选中文本,在右上角显示加载提示
const loading = document.createElement('div');
loading.className = 'ai-assistant-loading';
loading.innerHTML = `
<div class="loading-content">
<div class="loading-spinner"></div>
<span>AI正在分析中...</span>
</div>
`;
loading.style.position = 'fixed';
loading.style.top = '20px';
loading.style.right = '20px';
loading.style.zIndex = '10000';
document.body.appendChild(loading);
return loading;
}
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect();
const loading = document.createElement('div');
loading.className = 'ai-assistant-loading';
loading.innerHTML = `
<div class="loading-content">
<div class="loading-spinner"></div>
<span>AI正在分析中...</span>
</div>
`;
loading.style.position = 'fixed';
loading.style.left = rect.left + 'px';
loading.style.top = (rect.bottom + window.scrollY + 10) + 'px';
loading.style.zIndex = '10000';
document.body.appendChild(loading);
return loading;
}
// 显示分析结果
function displayAnalysisResult(originalText, analysisResult) {
const selection = window.getSelection();
let rect = { left: 100, bottom: 100 }; // 默认位置
if (selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
rect = range.getBoundingClientRect();
}
// 创建结果容器
const resultContainer = document.createElement('div');
resultContainer.className = 'ai-assistant-result';
resultContainer.innerHTML = `
<div class="result-header">
<h4>🤖 AI答题助手</h4>
<button class="close-btn">×</button>
</div>
<div class="result-content">
<div class="original-question">
<h5>📝 题目:</h5>
<p>${originalText}</p>
</div>
<div class="analysis-result">
<h5>💡 分析结果:</h5>
<div class="analysis-text">${formatAnalysisResult(analysisResult)}</div>
</div>
</div>
<div class="result-footer">
<small>按Esc键、点击×或按 ${currentShortcut} 键关闭</small>
</div>
`;
// 设置位置
resultContainer.style.position = 'fixed';
resultContainer.style.left = Math.min(rect.left, window.innerWidth - 500) + 'px';
resultContainer.style.top = (rect.bottom + window.scrollY + 10) + 'px';
resultContainer.style.zIndex = '10001';
document.body.appendChild(resultContainer);
// 添加键盘事件监听
const closeHandler = (e) => {
if (e.key === 'Escape' || e.key === currentShortcut) {
resultContainer.remove();
document.removeEventListener('keydown', closeHandler);
}
};
document.addEventListener('keydown', closeHandler);
// 显示成功通知
showNotification(`分析完成!使用了快捷键: ${currentShortcut}`, 'success');
}
// 格式化分析结果
function formatAnalysisResult(result) {
// 简单的格式化,将换行转换为<br>,并识别答案和解析部分
let formatted = result.replace(/\n/g, '<br>');
// 尝试识别答案和解析部分
formatted = formatted.replace(/答案[::]/g, '<strong style="color: #e74c3c;">答案:</strong>');
formatted = formatted.replace(/解析[::]/g, '<strong style="color: #3498db;">解析:</strong>');
return formatted;
}
// 显示通知
function showNotification(message, type = 'info') {
console.log('Showing notification:', message, type);
const notification = document.createElement('div');
notification.className = `ai-assistant-notification ${type}`;
notification.textContent = message;
notification.style.position = 'fixed';
notification.style.top = '20px';
notification.style.right = '20px';
notification.style.zIndex = '10002';
document.body.appendChild(notification);
// 3秒后自动移除
setTimeout(() => {
if (document.body.contains(notification)) {
notification.remove();
}
}, 3000);
}
// 页面加载完成后显示初始化信息
//window.addEventListener('load', function() {
// console.log('Page loaded, AI Assistant ready');
// setTimeout(() => {
// showNotification(`AI答题助手已就绪!快捷键: ${currentShortcut}`, 'info');
// }, 1000);
//});
// 显示加载指示器
function showLoadingIndicator() {
const selection = window.getSelection();
if (selection.rangeCount === 0) return null;
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect();
const loading = document.createElement('div');
loading.className = 'ai-assistant-loading';
loading.innerHTML = `
<div class="loading-content">
<div class="loading-spinner"></div>
<span>AI正在分析中...</span>
</div>
`;
loading.style.position = 'fixed';
loading.style.left = rect.left + 'px';
loading.style.top = (rect.bottom + window.scrollY + 10) + 'px';
loading.style.zIndex = '10000';
document.body.appendChild(loading);
return loading;
}
// 显示分析结果
function displayAnalysisResult(originalText, analysisResult) {
const selection = window.getSelection();
if (selection.rangeCount === 0) return;
const range = selection.getRangeAt(0);
const rect = range.getBoundingClientRect();
// 创建结果容器
const resultContainer = document.createElement('div');
resultContainer.className = 'ai-assistant-result';
resultContainer.innerHTML = `
<div class="result-header">
<h4>🤖 AI答题助手</h4>
<button class="close-btn">×</button>
</div>
<div class="result-content">
<div class="original-question">
<h5>📝 题目:</h5>
<p>${originalText}</p>
</div>
<div class="analysis-result">
<h5>💡 分析结果:</h5>
<div class="analysis-text">${formatAnalysisResult(analysisResult)}</div>
</div>
</div>
<div class="result-footer">
<small>按Esc键或点击×关闭</small>
</div>
`;
// 设置位置
resultContainer.style.position = 'fixed';
resultContainer.style.left = Math.min(rect.left, window.innerWidth - 500) + 'px';
resultContainer.style.top = (rect.bottom + window.scrollY + 10) + 'px';
resultContainer.style.zIndex = '10001';
document.body.appendChild(resultContainer);
// 添加键盘事件监听
const closeHandler = (e) => {
if (e.key === 'Escape') {
resultContainer.remove();
document.removeEventListener('keydown', closeHandler);
}
};
document.addEventListener('keydown', closeHandler);
// 5秒后自动显示提示
setTimeout(() => {
if (document.body.contains(resultContainer)) {
showNotification('分析结果已显示,按Esc键可关闭', 'info');
}
}, 5000);
}
// 格式化分析结果
function formatAnalysisResult(result) {
// 简单的格式化,将换行转换为<br>,并识别答案和解析部分
let formatted = result.replace(/\n/g, '<br>');
// 尝试识别答案和解析部分
formatted = formatted.replace(/答案[::]/g, '<strong style="color: #e74c3c;">答案:</strong>');
formatted = formatted.replace(/解析[::]/g, '<strong style="color: #3498db;">解析:</strong>');
return formatted;
}
// 显示通知
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `ai-assistant-notification ${type}`;
notification.textContent = message;
notification.style.position = 'fixed';
notification.style.top = '20px';
notification.style.right = '20px';
notification.style.zIndex = '10002';
document.body.appendChild(notification);
// 3秒后自动移除
setTimeout(() => {
if (document.body.contains(notification)) {
notification.remove();
}
}, 3000);
}
[JavaScript] 纯文本查看 复制代码 // background.js
console.log('Background script loaded');
// 监听来自content script的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
console.log('Message received in background:', request);
if (request.action === 'analyzeText') {
analyzeTextWithAI(request.text)
.then(result => {
console.log('Analysis result obtained');
sendResponse({ success: true, result: result });
})
.catch(error => {
console.error('Analysis error:', error);
sendResponse({ success: false, error: error.message });
});
return true; // 保持消息通道开放用于异步响应
}
// 处理测试连接消息
if (request.action === 'testConnection') {
testAPIConnection(request.settings)
.then(result => {
sendResponse({ success: true, result: result });
})
.catch(error => {
sendResponse({ success: false, error: error.message });
});
return true;
}
});
// 插件安装时设置默认值
chrome.runtime.onInstalled.addListener(() => {
console.log('Extension installed, setting up defaults');
chrome.storage.sync.get(['shortcut', 'modelName'], function(result) {
const updates = {};
if (!result.shortcut) {
updates.shortcut = 'F2';
}
if (!result.modelName) {
updates.modelName = 'gpt-3.5-turbo';
}
if (Object.keys(updates).length > 0) {
chrome.storage.sync.set(updates);
console.log('Default settings applied:', updates);
}
});
});
// 测试API连接
async function testAPIConnection(settings) {
const { apiUrl, apiKey, modelName, customModel } = settings;
let actualModelName = modelName || 'gpt-3.5-turbo';
if (modelName === 'custom' && customModel) {
actualModelName = customModel;
}
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`
},
body: JSON.stringify({
model: actualModelName,
messages: [
{
role: 'user',
content: '测试连接'
}
],
max_tokens: 10
})
});
if (!response.ok) {
throw new Error(`${response.status} ${response.statusText}`);
}
return actualModelName;
}
// 使用AI分析文本
async function analyzeTextWithAI(text) {
// 获取存储的设置
const settings = await chrome.storage.sync.get(['apiUrl', 'apiKey', 'modelName', 'customModel']);
console.log('Settings retrieved:', {
hasApiUrl: !!settings.apiUrl,
hasApiKey: !!settings.apiKey,
modelName: settings.modelName
});
if (!settings.apiUrl || !settings.apiKey) {
throw new Error('请先在插件设置中配置API地址和密钥。点击插件图标进行设置。');
}
// 确定使用的模型名称
let modelName = settings.modelName || 'gpt-3.5-turbo';
if (modelName === 'custom' && settings.customModel) {
modelName = settings.customModel;
} else if (modelName === 'custom') {
throw new Error('请设置自定义模型名称');
}
const prompt = `你是一个专业的答题助手。请针对用户提供的题目,给出准确的答案和详细的解析。回答格式应该包含两部分:答案和解析。
题目内容:
${text}`;
console.log('Making API request to:', settings.apiUrl, 'with model:', modelName);
try {
const response = await fetch(settings.apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${settings.apiKey}`
},
body: JSON.stringify({
model: modelName,
messages: [
{
role: 'user',
content: prompt
}
],
max_tokens: 1000,
temperature: 0.7
})
});
console.log('API response status:', response.status);
if (!response.ok) {
const errorText = await response.text();
console.error('API error response:', errorText);
throw new Error(`API请求失败: ${response.status} ${response.statusText}`);
}
const data = await response.json();
console.log('API response data keys:', Object.keys(data));
if (data.choices && data.choices.length > 0) {
return data.choices[0].message.content;
} else {
console.error('Unexpected API response format:', data);
throw new Error('API返回数据格式异常,请检查API配置');
}
} catch (error) {
console.error('AI分析错误:', error);
if (error.name === 'TypeError' && error.message.includes('fetch')) {
throw new Error('网络连接失败,请检查网络和API地址');
}
throw error;
}
} |
免费评分
-
查看全部评分
|