// ==UserScript==
// @name 导出DeepSeek回答为图片 | Export DeepSeek Answer to Image
// @namespace http://github.com/byronleeeee/exportDeepseek
// @version 1.2
// @description 将DeepSeek的回答导出为一张图片,支持选择多个聊天内容和添加用户头像
// @author ByronLeeeee
// @match *://chat.deepseek.com/*
// @grant none
// @require https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js
// @license MIT
// @downloadURL https://update.greasyfork.icu/scripts/530683/%E5%AF%BC%E5%87%BADeepSeek%E5%9B%9E%E7%AD%94%E4%B8%BA%E5%9B%BE%E7%89%87%20%7C%20Export%20DeepSeek%20Answer%20to%20Image.user.js
// @updateURL https://update.greasyfork.icu/scripts/530683/%E5%AF%BC%E5%87%BADeepSeek%E5%9B%9E%E7%AD%94%E4%B8%BA%E5%9B%BE%E7%89%87%20%7C%20Export%20DeepSeek%20Answer%20to%20Image.meta.js
// ==/UserScript==
(function() {
'use strict';
// i18n translations
const i18n = {
'zh': {
exportBtn: '导出AI回答为图片',
notFound: 'AI回答区域未找到!',
selectScheme: '选择配色方案:',
footer: '回答来自DeepSeek,仅供参考',
lastAnswer: '最新回答',
multiSelectMode: '多选模式',
exportSelected: '导出选中的对话',
selectAll: '全选',
deselectAll: '取消全选',
userMessage: '用户',
aiMessage: 'AI',
selectItems: '请选择要导出的对话内容:',
noItemsSelected: '请至少选择一个对话内容',
colorSchemes: [
{ name: '白色-蓝色', top: '#FFFFFF', bottom: '#4D6BFE', textTop: '#000000', textBottom: '#FFFFFF' },
{ name: '黑色-金色', top: '#121212', bottom: '#FFD700', textTop: '#FFFFFF', textBottom: '#000000' },
{ name: '浅灰-青色', top: '#F5F5F5', bottom: '#008080', textTop: '#000000', textBottom: '#FFFFFF' },
{ name: '深灰-紫色', top: '#333333', bottom: '#800080', textTop: '#FFFFFF', textBottom: '#FFFFFF' }
],
error: '生成图片失败,请查看控制台了解详情。',
cancel: '取消',
export: '导出',
next: '下一步',
back: '返回',
addCreator: '添加生成者信息',
creatorName: '生成者名称',
creatorPlaceholder: '输入你的名字',
addAvatar: '添加用户头像'
},
'en': {
exportBtn: 'Export AI Answer to Image',
notFound: 'AI answer div not found!',
selectScheme: 'Select a color scheme:',
footer: 'Answer from DeepSeek, for reference only',
lastAnswer: 'Last Answer',
multiSelectMode: 'Multi-select Mode',
exportSelected: 'Export Selected Items',
selectAll: 'Select All',
deselectAll: 'Deselect All',
userMessage: 'User',
aiMessage: 'AI',
selectItems: 'Please select chat items to export:',
noItemsSelected: 'Please select at least one chat item',
colorSchemes: [
{ name: 'White-Blue', top: '#FFFFFF', bottom: '#4D6BFE', textTop: '#000000', textBottom: '#FFFFFF' },
{ name: 'Black-Gold', top: '#121212', bottom: '#FFD700', textTop: '#FFFFFF', textBottom: '#000000' },
{ name: 'Light Gray-Teal', top: '#F5F5F5', bottom: '#008080', textTop: '#000000', textBottom: '#FFFFFF' },
{ name: 'Dark Gray-Purple', top: '#333333', bottom: '#800080', textTop: '#FFFFFF', textBottom: '#FFFFFF' }
],
error: 'Failed to generate image. Check console for details.',
cancel: 'Cancel',
export: 'Export',
next: 'Next',
back: 'Back',
addCreator: 'Add creator info',
creatorName: 'Creator name',
creatorPlaceholder: 'Enter your name',
addAvatar: 'Add user avatar'
}
};
const userLang = (navigator.language || navigator.userLanguage).split('-')[0];
const lang = i18n[userLang] ? userLang : 'en';
const texts = i18n[lang];
// Add styles with dark mode support
function addStyles() {
const style = document.createElement('style');
style.textContent = `
.ai-export-fab {
position: fixed;
bottom: 24px;
right: 24px;
width: 56px;
height: 56px;
border-radius: 50%;
background-color: #4D6BFE;
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
z-index: 9999;
transition: all 0.3s ease;
}
.ai-export-fab:hover {
transform: scale(1.05);
box-shadow: 0 6px 12px rgba(0,0,0,0.3);
}
.ai-export-fab-icon {
display: flex;
align-items: center;
justify-content: center;
}
.ai-export-tooltip {
position: absolute;
background: rgba(0,0,0,0.7);
color: white;
padding: 5px 10px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
right: 70px;
opacity: 0;
transition: opacity 0.3s;
pointer-events: none;
}
.ai-export-fab:hover .ai-export-tooltip {
opacity: 1;
}
.ai-color-scheme-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 10000;
}
.ai-modal-content {
background-color: white;
border-radius: 8px;
padding: 20px;
width: 400px;
max-width: 90%;
color: #000000;
}
body.dark .ai-modal-content {
background-color: #1e1e1e;
color: #ffffff;
}
.ai-modal-header {
font-size: 18px;
font-weight: bold;
margin-bottom: 15px;
}
.ai-scheme-options {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 15px;
}
.ai-scheme-option {
border: 2px solid transparent;
border-radius: 6px;
overflow: hidden;
cursor: pointer;
transition: all 0.2s;
}
.ai-scheme-option:hover {
transform: translateY(-2px);
}
.ai-scheme-option.selected {
border-color: #4D6BFE;
}
.ai-scheme-preview {
display: flex;
flex-direction: column;
height: 100px;
}
.ai-scheme-top {
flex: 3;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
.ai-scheme-bottom {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.ai-modal-buttons {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.ai-modal-button {
padding: 8px 16px;
border-radius: 4px;
border: none;
cursor: pointer;
font-weight: bold;
}
.ai-modal-button.primary {
background-color: #4D6BFE;
color: white;
}
.ai-modal-button.secondary {
background-color: #f1f1f1;
color: #333;
}
body.dark .ai-modal-button.secondary {
background-color: #333333;
color: #ffffff;
}
.ai-export-button {
position: absolute;
top: 10px;
right: 10px;
background-color: #4D6BFE;
color: white;
border: none;
border-radius: 4px;
padding: 4px 8px;
font-size: 12px;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s;
z-index: 100;
}
._4f9bf79:hover .ai-export-button,
.fbb737a4:hover .ai-export-button {
opacity: 1;
}
.ai-creator-option {
margin: 15px 0;
}
.ai-creator-checkbox {
margin-right: 8px;
}
.ai-creator-input {
margin-top: 8px;
width: 100%;
padding: 8px;
border-radius: 4px;
border: 1px solid #ccc;
box-sizing: border-box;
display: none;
}
body.dark .ai-creator-input {
background-color: #333;
color: #fff;
border-color: #555;
}
.ai-chat-selection {
max-height: 50vh;
overflow-y: auto;
margin: 15px 0;
border: 1px solid #eee;
border-radius: 8px;
padding: 10px;
}
body.dark .ai-chat-selection {
border-color: #333;
}
.ai-chat-item {
display: flex;
align-items: center;
padding: 8px;
margin: 5px 0;
border-radius: 4px;
background-color: #f9f9f9;
border-left: 4px solid transparent;
transition: all 0.2s;
}
body.dark .ai-chat-item {
background-color: #2a2a2a;
}
.ai-chat-item:hover {
background-color: #f1f1f1;
}
body.dark .ai-chat-item:hover {
background-color: #333;
}
.ai-chat-item.ai {
border-left-color: #4D6BFE;
}
.ai-chat-item.user {
border-left-color: #6FCF97;
}
.ai-chat-checkbox {
margin-right: 10px;
}
.ai-chat-preview {
flex-grow: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 14px;
}
.ai-chat-type {
font-size: 12px;
padding: 2px 6px;
border-radius: 10px;
margin-left: 8px;
}
.ai-chat-type.ai {
background-color: #E1E7FF;
color: #4D6BFE;
}
body.dark .ai-chat-type.ai {
background-color: #2a3a70;
color: #8aa3ff;
}
.ai-chat-type.user {
background-color: #E3F9EB;
color: #6FCF97;
}
body.dark .ai-chat-type.user {
background-color: #2a4a3a;
color: #8ae0a9;
}
.ai-selection-actions {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
}
.ai-selection-buttons {
display: flex;
gap: 8px;
}
.ai-select-button {
font-size: 12px;
padding: 4px 8px;
background-color: #f1f1f1;
border: none;
border-radius: 4px;
cursor: pointer;
}
body.dark .ai-select-button {
background-color: #333;
color: #fff;
}
.ai-select-button:hover {
background-color: #e1e1e1;
}
body.dark .ai-select-button:hover {
background-color: #444;
}
.ai-chat-wrapper {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: 15px;
padding: 10px;
}
.ai-chat-content {
flex-grow: 1;
}
.ai-user-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
margin-left: 10px;
}
`;
document.head.appendChild(style);
}
// Create FAB
function createFAB() {
const fab = document.createElement('div');
fab.innerHTML = `
`;
document.body.appendChild(fab);
fab.querySelector('.ai-export-fab').addEventListener('click', () => {
showMultiSelectModal();
});
}
// Add export buttons to each message
function addExportButtonsToMessages() {
const observer = new MutationObserver(() => {
const aiDivs = document.querySelectorAll('div._4f9bf79._43c05b5');
aiDivs.forEach(aiDiv => {
if (!aiDiv.querySelector('.ai-export-button')) {
const exportButton = document.createElement('button');
exportButton.className = 'ai-export-button';
exportButton.textContent = texts.exportBtn;
exportButton.addEventListener('click', () => {
showColorSchemeModal([aiDiv], false);
});
const parentDiv = aiDiv.closest('.ds-relative') || aiDiv;
parentDiv.style.position = 'relative';
parentDiv.appendChild(exportButton);
}
});
const userDivs = document.querySelectorAll('div.fbb737a4');
userDivs.forEach(userDiv => {
if (!userDiv.querySelector('.ai-export-button')) {
const exportButton = document.createElement('button');
exportButton.className = 'ai-export-button';
exportButton.textContent = texts.exportBtn;
exportButton.addEventListener('click', () => {
showColorSchemeModal([userDiv], false);
});
const parentDiv = userDiv.closest('.ds-relative') || userDiv;
parentDiv.style.position = 'relative';
parentDiv.appendChild(exportButton);
}
});
});
observer.observe(document.body, { childList: true, subtree: true });
const aiDivs = document.querySelectorAll('div._4f9bf79._43c05b5');
aiDivs.forEach(aiDiv => {
if (!aiDiv.querySelector('.ai-export-button')) {
const exportButton = document.createElement('button');
exportButton.className = 'ai-export-button';
exportButton.textContent = texts.exportBtn;
exportButton.addEventListener('click', () => {
showColorSchemeModal([aiDiv], false);
});
const parentDiv = aiDiv.closest('.ds-relative') || aiDiv;
parentDiv.style.position = 'relative';
parentDiv.appendChild(exportButton);
}
});
const userDivs = document.querySelectorAll('div.fbb737a4');
userDivs.forEach(userDiv => {
if (!userDiv.querySelector('.ai-export-button')) {
const exportButton = document.createElement('button');
exportButton.className = 'ai-export-button';
exportButton.textContent = texts.exportBtn;
exportButton.addEventListener('click', () => {
showColorSchemeModal([userDiv], false);
});
const parentDiv = userDiv.closest('.ds-relative') || userDiv;
parentDiv.style.position = 'relative';
parentDiv.appendChild(exportButton);
}
});
}
// Show multi-select modal
function showMultiSelectModal() {
const aiDivs = Array.from(document.querySelectorAll('div._4f9bf79._43c05b5'));
const userDivs = Array.from(document.querySelectorAll('div.fbb737a4'));
if (!aiDivs.length && !userDivs.length) {
alert(texts.notFound);
return;
}
const allMessages = [...aiDivs, ...userDivs].sort((a, b) => {
const position = a.compareDocumentPosition(b);
return position & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1;
});
const modal = document.createElement('div');
modal.className = 'ai-color-scheme-modal';
modal.innerHTML = `
${allMessages.map((div, index) => {
const isAI = div.classList.contains('_4f9bf79');
const type = isAI ? 'ai' : 'user';
const label = isAI ? texts.aiMessage : texts.userMessage;
let content;
if (isAI) {
content = div.textContent.trim();
} else {
// For user messages, remove ai-export-button and afb1eea3
const tempDiv = div.cloneNode(true);
const exportButton = tempDiv.querySelector('.ai-export-button');
if (exportButton) exportButton.remove();
const afb1eea3 = tempDiv.querySelector('.afb1eea3');
if (afb1eea3) afb1eea3.remove();
content = tempDiv.textContent.trim();
}
if (content.length > 60) content = content.substring(0, 57) + '...';
return `
${label}
`;
}).join('')}
`;
document.body.appendChild(modal);
modal.querySelector('#ai-select-all').addEventListener('click', () => {
modal.querySelectorAll('.ai-chat-checkbox').forEach(checkbox => {
checkbox.checked = true;
});
});
modal.querySelector('#ai-deselect-all').addEventListener('click', () => {
modal.querySelectorAll('.ai-chat-checkbox').forEach(checkbox => {
checkbox.checked = false;
});
});
modal.querySelector('#ai-cancel-btn').addEventListener('click', () => {
document.body.removeChild(modal);
});
modal.querySelector('#ai-continue-btn').addEventListener('click', () => {
const selectedIndices = [];
modal.querySelectorAll('.ai-chat-checkbox').forEach((checkbox, i) => {
if (checkbox.checked) {
const itemIndex = parseInt(checkbox.closest('.ai-chat-item').dataset.index);
selectedIndices.push(itemIndex);
}
});
if (selectedIndices.length === 0) {
alert(texts.noItemsSelected);
return;
}
const selectedDivs = selectedIndices.map(index => allMessages[index]);
document.body.removeChild(modal);
showColorSchemeModal(selectedDivs, true);
});
}
// Show color scheme modal
function showColorSchemeModal(selectedDivs, isMultiSelect) {
const modal = document.createElement('div');
modal.className = 'ai-color-scheme-modal';
let selectedSchemeIndex = 0;
let creatorName = '';
let addCreatorInfo = false;
let addUserAvatar = false;
const profileNameElement = document.querySelector('.ds-dropdown-menu-option__label');
const defaultCreatorName = profileNameElement ? profileNameElement.textContent.trim() : '';
modal.innerHTML = `
`;
document.body.appendChild(modal);
const schemeOptions = modal.querySelectorAll('.ai-scheme-option');
schemeOptions.forEach(option => {
option.addEventListener('click', () => {
schemeOptions.forEach(opt => opt.classList.remove('selected'));
option.classList.add('selected');
selectedSchemeIndex = parseInt(option.dataset.index);
});
});
const creatorCheckbox = modal.querySelector('.ai-creator-checkbox');
const creatorInput = modal.querySelector('.ai-creator-input');
const avatarCheckbox = modal.querySelector('.ai-avatar-checkbox');
creatorCheckbox.addEventListener('change', () => {
addCreatorInfo = creatorCheckbox.checked;
creatorInput.disabled = !addCreatorInfo;
creatorInput.style.display = addCreatorInfo ? 'block' : 'none';
});
avatarCheckbox.addEventListener('change', () => {
addUserAvatar = avatarCheckbox.checked;
});
addCreatorInfo = creatorCheckbox.checked;
creatorInput.style.display = addCreatorInfo ? 'block' : 'none';
if (isMultiSelect) {
modal.querySelector('#ai-back-btn').addEventListener('click', () => {
document.body.removeChild(modal);
showMultiSelectModal();
});
}
modal.querySelector('#ai-cancel-btn').addEventListener('click', () => {
document.body.removeChild(modal);
});
modal.querySelector('#ai-export-btn').addEventListener('click', async () => {
creatorName = creatorInput.value.trim();
document.body.removeChild(modal);
await generateAndDownloadImage(selectedDivs, texts.colorSchemes[selectedSchemeIndex], texts, addCreatorInfo, creatorName, addUserAvatar);
});
}
// Default SVG avatar (centered)
const defaultAvatarSVG = `
`;
// Generate and download image
async function generateAndDownloadImage(selectedDivs, colorScheme, texts, addCreatorInfo, creatorName, addUserAvatar) {
const container = document.createElement('div');
container.style.width = '600px';
container.style.borderRadius = '10px';
container.style.overflow = 'hidden';
container.style.boxShadow = '0 4px 8px rgba(0,0,0,0.1)';
container.style.display = 'flex';
container.style.flexDirection = 'column';
const topSection = document.createElement('div');
topSection.style.padding = '20px';
topSection.style.backgroundColor = colorScheme.top;
topSection.style.color = colorScheme.textTop;
// Get user avatar if selected, otherwise use default
let userAvatar = null;
if (addUserAvatar) {
const avatarImg = document.querySelector('img.fdf01f38');
if (avatarImg) {
userAvatar = avatarImg.cloneNode(true);
userAvatar.className = 'ai-user-avatar';
userAvatar.removeAttribute('aria-hidden');
}
}
if (!userAvatar) {
const avatarContainer = document.createElement('div');
avatarContainer.innerHTML = defaultAvatarSVG;
userAvatar = avatarContainer.firstElementChild;
}
selectedDivs.forEach(div => {
const isAI = div.classList.contains('_4f9bf79');
let contentDiv;
const chatWrapper = document.createElement('div');
chatWrapper.className = 'ai-chat-wrapper';
if (isAI) {
// For AI messages, clone the full div and remove unwanted elements
contentDiv = div.cloneNode(true);
const buttonDiv = contentDiv.querySelector('.ds-flex[style*="margin-top"]');
if (buttonDiv) buttonDiv.remove();
} else {
// For user messages, create a new div with only the text content from fbb737a4
contentDiv = document.createElement('div');
contentDiv.className = 'fbb737a4 ai-chat-content';
// Clone the div and remove export button and afb1eea3 before getting text
const tempDiv = div.cloneNode(true);
const exportButton = tempDiv.querySelector('.ai-export-button');
if (exportButton) exportButton.remove();
const afb1eea3 = tempDiv.querySelector('.afb1eea3');
if (afb1eea3) afb1eea3.remove();
contentDiv.textContent = tempDiv.textContent.trim();
}
chatWrapper.appendChild(contentDiv);
// Add avatar on the right for user messages
if (!isAI) {
const avatarClone = userAvatar.cloneNode(true);
chatWrapper.appendChild(avatarClone);
}
topSection.appendChild(chatWrapper);
});
let footerText = texts.footer;
if (addCreatorInfo && creatorName) {
footerText += ` — By ${creatorName}`;
}
const bottomSection = document.createElement('div');
bottomSection.textContent = footerText;
bottomSection.style.padding = '10px';
bottomSection.style.textAlign = 'center';
bottomSection.style.fontSize = '14px';
bottomSection.style.fontFamily = 'Arial, sans-serif';
bottomSection.style.backgroundColor = colorScheme.bottom;
bottomSection.style.color = colorScheme.textBottom;
container.appendChild(topSection);
container.appendChild(bottomSection);
container.style.position = 'absolute';
container.style.left = '-9999px';
document.body.appendChild(container);
try {
const canvas = await html2canvas(container, {
scale: 2,
backgroundColor: null,
useCORS: true,
logging: false
});
const link = document.createElement('a');
link.download = `chat_export_${new Date().toISOString().split('T')[0]}.png`;
link.href = canvas.toDataURL('image/png');
link.click();
} catch (error) {
console.error('Error generating image:', error);
alert(texts.error);
}
document.body.removeChild(container);
}
// Initialize
function init() {
addStyles();
createFAB();
addExportButtonsToMessages();
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
})();