Greasy Fork is available in English.
Enhanced integration between SillyTavern and Sexy.AI with translation support
当前为
// ==UserScript==
// @name Sync between Sexy.AI and SillyTavern old
// @namespace http://tampermonkey.net/
// @version 2.7
// @description Enhanced integration between SillyTavern and Sexy.AI with translation support
// @author You
// @match https://sexy.ai/workflow*
// @match https://staticui.sexy.ai/*
// @match http://ducninh.top:8000/*
// @match http://127.0.0.1:8000/*
// @match http://*/*:8000/*
// @grant GM_setValue
// @grant GM_getValue
// @grant unsafeWindow
// ==/UserScript==
(function() {
'use strict';
console.log("Script started on URL:", window.location.href);
const isSexyAI = window.location.href.includes('sexy.ai') || window.location.href.includes('staticui.sexy.ai');
const isSillyTavern = window.location.href.includes(':8000');
// Utility Functions
function createStyledButton(text, onClick, isFixed = false) {
const button = document.createElement('button');
button.textContent = text;
let baseStyle = `
padding: 5px 8px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
font-size: 12px;
opacity: 0.8;
transition: all 0.3s;
z-index: 9999;
`;
if(isFixed) {
baseStyle += `
position: fixed;
right: 20px;
`;
} else {
baseStyle += `
margin-left: 5px;
`;
}
button.style.cssText = baseStyle;
button.addEventListener('mouseover', () => button.style.opacity = '1');
button.addEventListener('mouseout', () => button.style.opacity = '0.8');
button.addEventListener('click', onClick);
return button;
}
// Extract original text from message
function extractOriginalText(messageNode) {
// Try to get original text from data attribute first
const originalText = messageNode.getAttribute('data-original-text');
if (originalText) {
return originalText;
}
// If no stored original text, get current text
const messageText = messageNode.querySelector('.mes_text');
if (!messageText) return '';
// Clone the message text element to work with
const clone = messageText.cloneNode(true);
// Remove any button containers if they exist
const buttonContainer = clone.querySelector('.button-container');
if (buttonContainer) {
buttonContainer.remove();
}
return clone.textContent.trim();
}
// Store original text before translation
function storeOriginalText(messageNode) {
const messageText = messageNode.querySelector('.mes_text');
if (messageText && !messageNode.hasAttribute('data-original-text')) {
messageNode.setAttribute('data-original-text', messageText.textContent);
}
}
function showImageModal(imageUrl) {
// Tạo container cho ảnh
const imgContainer = document.createElement('div');
imgContainer.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
`;
// Tạo element ảnh
const img = document.createElement('img');
img.src = imageUrl.replace('.replace(')', '');
img.style.cssText = `
width: auto;
height: auto;
max-width: 160%; /* Tăng gấp đôi từ 80% */
max-height: 90vh; /* Tăng lên để ảnh có thể lớn hơn */
object-fit: contain;
`;
// Tạo nút đóng
const closeButton = document.createElement('button');
closeButton.textContent = '×';
closeButton.style.cssText = `
position: absolute;
top: -15px;
left: -15px; /* Đổi từ right sang left vì đã đặt ảnh bên phải */
background: #4CAF50;
border: none;
color: white;
width: 25px;
height: 25px;
border-radius: 50%;
font-size: 16px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
`;
const closeModal = () => imgContainer.remove();
closeButton.onclick = closeModal;
imgContainer.appendChild(img);
imgContainer.appendChild(closeButton);
document.body.appendChild(imgContainer);
}
// SexyAI Implementation
if (isSexyAI) {
if (window.location.href.includes('staticui.sexy.ai')) {
const promptButton = createStyledButton('Get Prompt', () => {
const prompt = GM_getValue('st_prompt', null);
if (prompt) {
const positiveInput = document.querySelector('textarea') ||
document.querySelector('input[type="text"]');
if (positiveInput) {
positiveInput.value = prompt;
const event = new Event('input', { bubbles: true });
positiveInput.dispatchEvent(event);
GM_setValue('st_prompt', null);
promptButton.style.backgroundColor = '#2196F3';
promptButton.textContent = 'Prompt Added';
setTimeout(() => {
promptButton.style.backgroundColor = '#4CAF50';
promptButton.textContent = 'Get Prompt';
}, 2000);
}
}
}, true);
promptButton.style.top = '80px';
document.body.appendChild(promptButton);
}
document.addEventListener('click', (e) => {
if (e.target.tagName === 'IMG') {
const markdownUrls = [``];
console.log('Saving image URL:', markdownUrls[0]);
GM_setValue('sexyai_images', markdownUrls.join('\n'));
// Visual feedback on image click
const overlay = document.createElement('div');
overlay.style.cssText = `
position: fixed;
top: 10px;
right: 10px;
background-color: #4CAF50;
color: white;
padding: 8px;
border-radius: 4px;
z-index: 10000;
opacity: 0;
transition: opacity 0.3s;
`;
overlay.textContent = 'Image Copied';
document.body.appendChild(overlay);
setTimeout(() => {
overlay.style.opacity = '1';
setTimeout(() => {
overlay.style.opacity = '0';
setTimeout(() => overlay.remove(), 300);
}, 1500);
}, 0);
}
}, true);
} else if (isSillyTavern) {
let isMonitoring = false;
function addMonitorButton() {
const extensionsButton = document.querySelector('#extensionsMenuButton');
if (extensionsButton && !document.querySelector('#monitor_button')) {
const monitorButton = document.createElement('div');
monitorButton.id = 'monitor_button';
monitorButton.className = 'fa-solid fa-eye menu_button';
monitorButton.title = 'Monitor Messages';
monitorButton.style.cssText = `
display: flex;
cursor: pointer;
opacity: 0.7;
margin: 0 5px;
font-size: 18px;
transition: all 0.3s;
`;
monitorButton.addEventListener('click', () => {
isMonitoring = !isMonitoring;
monitorButton.style.color = isMonitoring ? '#4CAF50' : '';
monitorButton.style.opacity = isMonitoring ? '1' : '0.7';
if (isMonitoring) {
processExistingMessages();
} else {
document.querySelectorAll('.button-container').forEach(container => {
container.remove();
});
}
});
extensionsButton.parentNode.insertBefore(monitorButton, extensionsButton.nextSibling);
}
}
function addButtonsToMessage(messageNode) {
if (!isMonitoring) return;
if (!messageNode || !messageNode.querySelector) return;
// Store original text before any translation happens
storeOriginalText(messageNode);
const messageText = messageNode.querySelector('.mes_text');
if (!messageText) return;
if (messageText.querySelector('.button-container')) return;
// Get original text for processing
const text = extractOriginalText(messageNode);
const hasImagePrompt = text.match(/image###([^#]+)###/);
if (hasImagePrompt) {
const buttonContainer = document.createElement('div');
buttonContainer.className = 'button-container';
buttonContainer.style.display = 'flex';
buttonContainer.style.gap = '5px';
buttonContainer.style.marginTop = '5px';
const showImageButton = createStyledButton('👁️ Show Image', async () => {
console.log('Show image button clicked');
const markdownUrls = GM_getValue('sexyai_images', null);
if (!markdownUrls) {
showImageButton.style.backgroundColor = '#f44336';
showImageButton.textContent = '❌ No Image';
setTimeout(() => {
showImageButton.style.backgroundColor = '#4CAF50';
showImageButton.textContent = '👁️ Show Image';
}, 2000);
return;
}
showImageModal(markdownUrls);
showImageButton.style.backgroundColor = '#2196F3';
showImageButton.textContent = '✓ Shown';
setTimeout(() => {
showImageButton.style.backgroundColor = '#4CAF50';
showImageButton.textContent = '👁️ Show Image';
}, 2000);
});
const sendPromptButton = createStyledButton('📤 Send Prompt', () => {
const text = extractOriginalText(messageNode);
const match = text.match(/image###([^#]+)###/);
if (match) {
const prompt = match[1].trim();
GM_setValue('st_prompt', prompt);
// Update visual text without affecting original stored text
const textNodes = Array.from(messageText.childNodes).filter(node => node.nodeType === Node.TEXT_NODE);
textNodes.forEach(node => {
node.textContent = node.textContent.replace(/(image###[^#]+)###/g, '');
});
sendPromptButton.style.backgroundColor = '#2196F3';
sendPromptButton.textContent = '✓ Sent';
setTimeout(() => {
sendPromptButton.style.backgroundColor = '#4CAF50';
sendPromptButton.textContent = '📤 Send Prompt';
}, 2000);
}
});
buttonContainer.appendChild(showImageButton);
buttonContainer.appendChild(sendPromptButton);
messageText.appendChild(buttonContainer);
}
}
function processExistingMessages() {
const messages = document.getElementsByClassName('mes');
Array.from(messages).forEach(addButtonsToMessage);
}
setInterval(addMonitorButton, 2000);
const observer = new MutationObserver((mutations) => {
if (!isMonitoring) return;
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === 1) {
if (node.classList?.contains('mes')) {
addButtonsToMessage(node);
}
const mesElements = node.getElementsByClassName('mes');
Array.from(mesElements).forEach(addButtonsToMessage);
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
})();