您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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.4 // @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'); return messageText ? messageText.textContent : ''; } // 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); } } // 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 editMessageAndAddImage(messageNode, markdownUrls) { return new Promise((resolve, reject) => { try { console.log('Starting edit process...'); const editButton = messageNode.querySelector('.mes_edit'); if (!editButton) { throw new Error('Edit button not found'); } editButton.click(); setTimeout(() => { const textarea = document.getElementById('curEditTextarea'); if (!textarea) { reject(new Error('Textarea not found')); return; } // Get original text if available const originalText = extractOriginalText(messageNode); textarea.value = originalText + '\n' + markdownUrls; textarea.dispatchEvent(new Event('input', { bubbles: true })); setTimeout(() => { const confirmButton = messageNode.querySelector('.mes_edit_done'); if (!confirmButton) { reject(new Error('Confirm button not found')); return; } confirmButton.click(); resolve(); }, 500); }, 500); } catch (error) { reject(error); } }); } 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 syncButton = createStyledButton('📥 Sync Image', async () => { console.log('Sync button clicked'); try { const markdownUrls = GM_getValue('sexyai_images', null); if (!markdownUrls) return; await editMessageAndAddImage(messageNode, markdownUrls); GM_setValue('sexyai_images', null); syncButton.style.backgroundColor = '#2196F3'; syncButton.textContent = '✓ Synced'; setTimeout(() => { syncButton.style.backgroundColor = '#4CAF50'; syncButton.textContent = '📥 Sync Image'; }, 2000); } catch (error) { console.error('Error in sync process:', error); syncButton.style.backgroundColor = '#f44336'; syncButton.textContent = '❌ Error'; setTimeout(() => { syncButton.style.backgroundColor = '#4CAF50'; syncButton.textContent = '📥 Sync 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(syncButton); 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 }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址