AI网页内容总结

使用AI总结网页内容的油猴脚本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

作者
bizhanrensheng
今日安裝
1
安裝總數
14
評價
0 0 0
版本
1.0
建立日期
2024-11-05
更新日期
2024-11-05
尺寸
28.2 KB
授權條款
MIT
腳本執行於
所有網站

// ==UserScript==
// @name AI网页内容总结
// @namespace http://tampermonkey.net/
// @version 1.0
// @description 使用AI总结网页内容的油猴脚本
// @author bizhanrensheng
// @match *://*/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @require https://cdnjs.cloudflare.com/ajax/libs/markdown-it/13.0.1/markdown-it.min.js
// @license MIT
// @homepageURL https://xr.imyaigc.com
// ==/UserScript==

(function() {
'use strict';

// 默认配置
// Replace DEFAULT_CONFIG with the new API settings
const DEFAULT_CONFIG = {
API_URL: 'https://api.x.ai/v1/chat/completions',
API_KEY: 'xai-bizhan(这里用你注册获得的API)',
MAX_TOKENS: 10000,
SHORTCUT: 'Alt+S',
PROMPT: 'Please summarize the following webpage content in Markdown format, covering main points, key information, and details. Make it thorough, accurate, and organized.',
MODEL: 'grok-beta'
};

// Then, update the `summarizeContent` function to match the API format you need
async function summarizeContent(content) {
return new Promise(async (resolve, reject) => {
const contentContainer = document.querySelector('.ai-summary-content');
contentContainer.innerHTML = '

Generating summary

';

let summary = '';
const md = createMarkdownRenderer();

// Set a timeout to handle potential request delays
const timeout = setTimeout(() => {
reject(new Error('Request timed out. Please check API URL, API Key, and network connection.'));
}, 20000);

try {
const response = await fetch(CONFIG.API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CONFIG.API_KEY}`
},
body: JSON.stringify({
model: CONFIG.MODEL,
messages: [
{ role: 'system', content: CONFIG.PROMPT },
{ role: 'user', content: content }
],
max_tokens: CONFIG.MAX_TOKENS,
temperature: 0,
stream: false
})
});

// Check if the response is OK
if (!response.ok) {
clearTimeout(timeout);
throw new Error(`API request failed (${response.status}): Please check API URL and Key`);
}

const result = await response.json();
clearTimeout(timeout);

if (result && result.choices && result.choices[0] && result.choices[0].message) {
summary = result.choices[0].message.content;
contentContainer.innerHTML = md.render(summary);
resolve(summary);
} else {
throw new Error("Unexpected API response format.");
}

} catch (error) {
clearTimeout(timeout);
reject(error);
}
});
}


// 获取配置
let CONFIG = {};
function loadConfig() {
CONFIG = {
API_URL: GM_getValue('API_URL', DEFAULT_CONFIG.API_URL),
API_KEY: GM_getValue('API_KEY', DEFAULT_CONFIG.API_KEY),
MAX_TOKENS: GM_getValue('MAX_TOKENS', DEFAULT_CONFIG.MAX_TOKENS),
SHORTCUT: GM_getValue('SHORTCUT', DEFAULT_CONFIG.SHORTCUT),
PROMPT: GM_getValue('PROMPT', DEFAULT_CONFIG.PROMPT),
MODEL: GM_getValue('MODEL', DEFAULT_CONFIG.MODEL)
};
return CONFIG;
}

// 保存配置
function saveConfig(newConfig) {
Object.keys(newConfig).forEach(key => {
GM_setValue(key, newConfig[key]);
});
CONFIG = { ...CONFIG, ...newConfig };
}

// 添加样式
GM_addStyle(` #ai-summary-root .ai-summary-container{position:fixed;bottom:20px;right:20px;display:flex;align-items:center;z-index:99998;user-select:none;align-items:stretch;box-shadow:0 2px 5px rgba(0,0,0,.2);height:30px}#ai-summary-root .ai-settings-panel,#ai-summary-root .ai-summary-modal{position:fixed;transform:translate(-50%,-50%);box-shadow:0 4px 20px rgba(0,0,0,.15)}#ai-summary-root .ai-summary-container .ai-drag-handle{width:15px;height:100%;background-color:rgba(75,85,99,.8);border-radius:5px 0 0 5px;cursor:move;margin-right:1px;display:flex;align-items:center;justify-content:center}#ai-summary-root .ai-summary-container .ai-drag-handle::before{content:"⋮";color:#f3f4f6;font-size:16px;transform:rotate(90deg)}#ai-summary-root .ai-summary-container .ai-summary-btn{padding:5px 15px;background-color:rgba(75,85,99,.8);color:#f3f4f6;border:none;border-radius:0 4px 4px 0;cursor:pointer;font-size:12px;transition:.3s;height:100%;line-height:1;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}#ai-summary-root .ai-summary-container .ai-summary-btn:hover{background-color:rgba(75,85,99,.9)}#ai-summary-root .ai-summary-modal{display:none;top:50%;left:50%;width:80%;max-width:800px;max-height:80vh;background:#f8f9fa;border-radius:8px;z-index:99999;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}#ai-summary-root .ai-summary-modal *{box-sizing:border-box}#ai-summary-root .ai-summary-overlay{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.5);z-index:99998}#ai-summary-root .ai-summary-modal .ai-summary-header{padding:15px 20px;background:#f1f3f5;border-bottom:1px solid #dee2e6;display:flex;justify-content:space-between;align-items:center}#ai-summary-root .ai-summary-modal .ai-summary-header h3{color:#495057;margin:0;padding:0;font-size:16px;font-weight:600;line-height:1.4;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-summary-close{background:0 0;border:none;font-size:20px;cursor:pointer;color:#6c757d;padding:0 5px;line-height:1;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-summary-close:hover{color:#495057}#ai-summary-root .ai-summary-modal .ai-summary-content{padding:20px;overflow-y:auto;max-height:calc(80vh - 130px);line-height:1.6;color:#374151;font-size:15px;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-summary-content h1{font-size:1.8em;margin:1.5em 0 .8em;padding-bottom:.3em;border-bottom:2px solid #e5e7eb;font-weight:600;line-height:1.3;color:#1f2937}#ai-summary-root .ai-summary-modal .ai-summary-content h2{font-size:1.5em;margin:1.3em 0 .7em;padding-bottom:.2em;border-bottom:1px solid #e5e7eb;font-weight:600;line-height:1.3;color:#1f2937}#ai-summary-root .ai-summary-modal .ai-summary-content h3{font-size:1.3em;margin:1.2em 0 .6em;font-weight:600;line-height:1.3;color:#1f2937}#ai-summary-root .ai-summary-modal .ai-summary-content p{margin:1em 0;line-height:1.8;color:inherit}#ai-summary-root .ai-summary-modal .ai-summary-content ol,#ai-summary-root .ai-summary-modal .ai-summary-content ul{margin:1em 0;padding-left:2em;line-height:1.6}#ai-summary-root .ai-summary-modal .ai-summary-content li{margin:.5em 0;line-height:inherit;color:inherit}#ai-summary-root .ai-summary-modal .ai-summary-content blockquote{margin:1em 0;padding:.5em 1em;border-left:4px solid #60a5fa;background:#f3f4f6;color:#4b5563;font-style:normal}#ai-summary-root .ai-summary-modal .ai-summary-content code{background:#f3f4f6;padding:.2em .4em;border-radius:3px;font-family:Consolas,Monaco,"Courier New",monospace;font-size:.9em;color:#d946ef;white-space:pre-wrap}#ai-summary-root .ai-summary-modal .ai-summary-content pre{background:#1f2937;color:#e5e7eb;padding:1em;border-radius:6px;overflow-x:auto;margin:1em 0;white-space:pre;word-wrap:normal}#ai-summary-root .ai-summary-modal .ai-summary-content pre code{background:0 0;color:inherit;padding:0;border-radius:0;font-size:inherit;white-space:pre}#ai-summary-root .ai-summary-modal .ai-summary-content table{border-collapse:collapse;width:100%;margin:1em 0;font-size:inherit}#ai-summary-root .ai-summary-modal .ai-summary-content td,#ai-summary-root .ai-summary-modal .ai-summary-content th{border:1px solid #d1d5db;padding:.5em;text-align:left;color:inherit;background:0 0}#ai-summary-root .ai-summary-modal .ai-summary-content th{background:#f9fafb;font-weight:600}#ai-summary-root .ai-summary-modal .ai-summary-footer{padding:15px 20px;border-top:1px solid #dee2e6;display:flex;justify-content:flex-end;gap:10px;background:#f8f9fa}#ai-summary-root .ai-settings-btn,#ai-summary-root .ai-summary-modal .ai-retry-btn{padding:8px;background:#6c757d;color:#fff;border:none;border-radius:4px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;transition:background .3s;width:36px;height:36px;min-width:36px;line-height:1}#ai-summary-root .ai-settings-btn:hover,#ai-summary-root .ai-settings-panel .cancel-btn:hover,#ai-summary-root .ai-settings-panel .save-btn:hover,#ai-summary-root .ai-summary-modal .ai-copy-btn:hover,#ai-summary-root .ai-summary-modal .ai-retry-btn:hover{background:#5a6268}#ai-summary-root .ai-summary-modal .ai-retry-btn svg{width:20px;height:20px}#ai-summary-root .ai-summary-modal .ai-copy-btn{padding:8px 16px;background:#6c757d;color:#fff;border:none;border-radius:4px;cursor:pointer;display:inline-flex;align-items:center;gap:8px;transition:background .3s;font-size:14px;line-height:1;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-loading{text-align:center;padding:20px;color:#6c757d;font-family:inherit}#ai-summary-root .ai-summary-modal .ai-loading-dots:after{content:'.';animation:1.5s steps(5,end) infinite dots}@keyframes dots{0%,20%{content:'.'}40%{content:'..'}60%{content:'...'}100%,80%{content:''}}#ai-summary-root .ai-settings-panel{display:none;top:50%;left:50%;width:90%;max-width:500px;background:#fff;padding:20px;border-radius:8px;z-index:100000}#ai-summary-root .ai-settings-panel textarea{resize:vertical;max-width:100%;height:100px;resize:vertical}#ai-summary-root .ai-settings-panel h3{margin:0 0 20px;padding-bottom:10px;border-bottom:1px solid #dee2e6;color:#495057;font-size:18px}#ai-summary-root .ai-settings-panel .form-group{margin-bottom:15px}#ai-summary-root .ai-settings-panel label{display:block;margin-bottom:5px;color:#495057;font-weight:500}#ai-summary-root .ai-settings-panel input,#ai-summary-root .ai-settings-panel textarea{max-width:100%;box-sizing:border-box;width:100%;padding:8px 12px;border:1px solid #ced4da;border-radius:4px;font-size:14px;line-height:1.5}#ai-summary-root .ai-settings-panel button{padding:8px 16px;border:none;border-radius:4px;cursor:pointer;font-size:14px;transition:.3s}#ai-summary-root .ai-settings-panel .cancel-btn,#ai-summary-root .ai-settings-panel .save-btn{background:#6c757d;color:#fff}#ai-summary-root .ai-settings-panel .clear-cache-btn{padding:8px 16px;background:#dc3545;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:14px;transition:.3s;margin-right:auto}#ai-summary-root .ai-settings-panel .clear-cache-btn:hover{background:#c82333}#ai-summary-root .ai-settings-panel .buttons{display:flex;justify-content:flex-end;gap:10px;margin-top:20px} `);

// 创建设置面板
function createSettingsPanel() {
const panel = document.createElement('div');
panel.className = 'ai-settings-panel';
panel.innerHTML = `

设置


API URL


API Key


模型


最大Token数


快捷键


总结提示词
${CONFIG.PROMPT}


清除缓存
取消
保存

`;

const overlay = document.createElement('div');
overlay.className = 'ai-summary-overlay';

// 事件监听
panel.querySelector('.save-btn').addEventListener('click', () => {
const newConfig = {
API_URL: panel.querySelector('#api-url').value,
API_KEY: panel.querySelector('#api-key').value,
MAX_TOKENS: parseInt(panel.querySelector('#max-tokens').value),
SHORTCUT: panel.querySelector('#shortcut').value,
PROMPT: panel.querySelector('#prompt').value,
MODEL: panel.querySelector('#model').value
};
saveConfig(newConfig);
panel.style.display = 'none';
document.querySelector('.ai-summary-overlay').style.display = 'none';
});

panel.querySelector('.cancel-btn').addEventListener('click', () => {
panel.style.display = 'none';
document.querySelector('.ai-summary-overlay').style.display = 'none';
});

// 清除缓存按钮事件
panel.querySelector('.clear-cache-btn').addEventListener('click', () => {
const keys = ['API_URL', 'API_KEY', 'MAX_TOKENS', 'SHORTCUT', 'PROMPT', 'MODEL'];
keys.forEach(key => GM_setValue(key, undefined)); // 设置为undefined模拟删除

// 重置为默认配置
CONFIG = { ...DEFAULT_CONFIG };

// 更新输入框的值
panel.querySelector('#api-url').value = CONFIG.API_URL;
panel.querySelector('#api-key').value = CONFIG.API_KEY;
panel.querySelector('#max-tokens').value = CONFIG.MAX_TOKENS;
panel.querySelector('#shortcut').value = CONFIG.SHORTCUT;
panel.querySelector('#prompt').value = CONFIG.PROMPT;
panel.querySelector('#model').value = CONFIG.MODEL;

alert('缓存已清除,已恢复默认设置');
});

return panel;
}

// 创建DOM元素
function createElements() {
// 创建根容器,并添加唯一ID
const rootContainer = document.createElement('div');
rootContainer.id = 'ai-summary-root';

// 创建容器和拖动把手
const container = document.createElement('div');
container.className = 'ai-summary-container';

const dragHandle = document.createElement('div');
dragHandle.className = 'ai-drag-handle';

const button = document.createElement('button');
button.className = 'ai-summary-btn';
button.textContent = '总结网页';

// 在footer中添加设置按钮
const settingsBtn = document.createElement('button');
settingsBtn.className = 'ai-settings-btn';
settingsBtn.title = '设置';
settingsBtn.innerHTML = `




`;

container.appendChild(dragHandle);
container.appendChild(button);
document.body.appendChild(container);

// 创建模态框和遮罩层
const modal = document.createElement('div');
modal.className = 'ai-summary-modal';
modal.innerHTML = `

网页内容总结

×












复制内容

`;

const overlay = document.createElement('div');
overlay.className = 'ai-summary-overlay';

document.body.appendChild(overlay);
document.body.appendChild(modal);

modal.querySelector('.ai-summary-footer').insertBefore(
settingsBtn,
modal.querySelector('.ai-retry-btn')
);

const settingsPanel = createSettingsPanel();

// 将容器添加到根容器
rootContainer.appendChild(container);
rootContainer.appendChild(overlay);
rootContainer.appendChild(modal);
rootContainer.appendChild(settingsPanel);

document.body.appendChild(rootContainer); // 将根容器添加到body

return { container, button, modal, overlay, dragHandle, settingsBtn, settingsPanel, rootContainer };
}


// 获取网页内容
function getPageContent() {
const title = document.title;
const content = document.body.innerText;
return { title, content };
}

// 显示错误信息
function showError(container, error, details = '') {
container.innerHTML = `


错误: ${error}

${details ? `

${details}

` : ''}
`;
}

// 调用API进行总结
async function summarizeContent(content) {
return new Promise(async (resolve, reject) => {
const contentContainer = document.querySelector('.ai-summary-content');
contentContainer.innerHTML = '

正在生成总结

';

let summary = '';
const md = createMarkdownRenderer();

// 添加超时检查
const timeout = setTimeout(() => {
reject(new Error('请求超时,请检查API URL、API Key和网络连接'));
}, 20000);

try {
const response = await fetch(CONFIG.API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CONFIG.API_KEY}`
},
body: JSON.stringify({
model: CONFIG.MODEL,
messages: [
{ role: 'system', content: CONFIG.PROMPT },
{ role: 'user', content: content }
],
max_tokens: CONFIG.MAX_TOKENS,
temperature: 0.7,
stream: true
})
});

// 检查响应状态
if (!response.ok) {
clearTimeout(timeout);
throw new Error(`API请求失败 (${response.status}): 请检查API URL和Key是否正确`);
}

const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");

while (true) {
const { done, value } = await reader.read();
if (done) break;

const chunk = decoder.decode(value, { stream: true });
const lines = chunk.split('\n');

for (const line of lines) {
if (line.trim() === '' || line.trim() === 'data: [DONE]') continue;

const jsonLine = line.replace(/^data: /, '');
try {
const parsedData = JSON.parse(jsonLine);
if (parsedData.choices && parsedData.choices[0] && parsedData.choices[0].delta) {
if (parsedData.choices[0].delta.content) {
summary += parsedData.choices[0].delta.content;
contentContainer.innerHTML = md.render(summary);
}
}
} catch (e) {
console.warn('忽略无法解析的行:', line);
continue;
}
}
}

clearTimeout(timeout);
resolve(summary);

} catch (error) {
clearTimeout(timeout);
reject(error);
}
});
}

// 初始化拖动功能
function initializeDrag(container, dragHandle) {
let isDragging = false;
let currentX;
let currentY;
let initialX;
let initialY;

dragHandle.addEventListener('mousedown', (e) => {
isDragging = true;
initialX = e.clientX - container.offsetLeft;
initialY = e.clientY - container.offsetTop;
});

document.addEventListener('mousemove', (e) => {
if (isDragging) {
e.preventDefault();
currentX = e.clientX - initialX;
currentY = e.clientY - initialY;

// 确保不会拖出屏幕
const maxX = window.innerWidth - container.offsetWidth;
const maxY = window.innerHeight - container.offsetHeight;
currentX = Math.max(0, Math.min(currentX, maxX));
currentY = Math.max(0, Math.min(currentY, maxY));

container.style.left = currentX + 'px';
container.style.top = currentY + 'px';
container.style.right = 'auto';
container.style.bottom = 'auto';
}
});

document.addEventListener('mouseup', () => {
isDragging = false;
});
}

// 初始化事件监听
function initializeEvents(elements) {
const { container, button, modal, overlay, dragHandle, settingsBtn, settingsPanel, rootContainer } = elements;

// 初始化拖动功能
initializeDrag(container, dragHandle);

// 点击按钮显示模态框
button.addEventListener('click', async () => {
// 检查是否是第一次点击且未配置API
if (!CONFIG.API_KEY || CONFIG.API_KEY === '' || CONFIG.API_KEY === 'YOUR_API_KEY') {
settingsPanel.style.display = 'block';
overlay.style.display = 'block';
return;
}

showModal(modal, overlay);
const contentContainer = modal.querySelector('.ai-summary-content');

try {
if (!CONFIG.API_URL || CONFIG.API_URL === 'YOUR_API_URL') {
throw new Error('请先配置API URL');
}
if (!CONFIG.API_KEY || CONFIG.API_KEY === 'YOUR_API_KEY') {
throw new Error('请先配置API Key');
}

const { content } = getPageContent();
const summary = await summarizeContent(content);
if (summary) {
contentContainer.innerHTML = window.markdownit().render(summary);
}
} catch (error) {
console.error('Summary Error:', error);
showError(contentContainer, error.message);
}
});

// 关闭模态框
modal.querySelector('.ai-summary-close').addEventListener('click', () => {
hideModal(modal, overlay);
});

overlay.addEventListener('click', () => {
hideModal(modal, overlay);
settingsPanel.style.display = 'none';
});

// 复制按钮功能
modal.querySelector('.ai-copy-btn').addEventListener('click', () => {
const content = modal.querySelector('.ai-summary-content').textContent;
navigator.clipboard.writeText(content).then(() => {
const copyBtn = modal.querySelector('.ai-copy-btn');
const originalText = copyBtn.innerHTML;
copyBtn.innerHTML = '已复制!';
setTimeout(() => {
copyBtn.innerHTML = originalText;
}, 2000);
});
});

// 添加快捷键支持
document.addEventListener('keydown', (e) => {
if (e.altKey && e.key.toLowerCase() === 's') {
button.click();
}
if (e.key === 'Escape' && modal.style.display === 'block') {
hideModal(modal, overlay);
}
});

// 添加重试按钮事件处理
modal.querySelector('.ai-retry-btn').addEventListener('click', async () => {
const contentContainer = modal.querySelector('.ai-summary-content');
try {
const { content } = getPageContent();
const summary = await summarizeContent(content);
if (summary) {
const md = window.markdownit({
html: true,
linkify: true,
typographer: true,
breaks: true
});
contentContainer.innerHTML = md.render(summary);
}
} catch (error) {
console.error('Retry Error:', error);
showError(contentContainer, error.message);
}
});

const allSettingsButtons = rootContainer.querySelectorAll('.ai-settings-btn');
allSettingsButtons.forEach(btn => {
btn.addEventListener('click', () => {
// 更新设置面板中的值
settingsPanel.querySelector('#api-url').value = CONFIG.API_URL;
settingsPanel.querySelector('#api-key').value = CONFIG.API_KEY;
settingsPanel.querySelector('#max-tokens').value = CONFIG.MAX_TOKENS;
settingsPanel.querySelector('#shortcut').value = CONFIG.SHORTCUT;
settingsPanel.querySelector('#prompt').value = CONFIG.PROMPT;
settingsPanel.querySelector('#model').value = CONFIG.MODEL;

settingsPanel.style.display = 'block';
overlay.style.display = 'block';
});
});
}

// 增强markdown-it配置
function createMarkdownRenderer() {
return window.markdownit({
html: true,
linkify: true,
typographer: true,
breaks: true
});
}

// 显示模态框
function showModal(modal, overlay) {
modal.style.display = 'block';
overlay.style.display = 'block';
}

// 隐藏模态框
function hideModal(modal, overlay) {
modal.style.display = 'none';
overlay.style.display = 'none';
}

// 初始化时加载配置
loadConfig();

// 初始化脚本
const elements = createElements();
initializeEvents(elements);
})();