Sexy.AI to SillyTavern origin

Sync between Sexy.AI and SillyTavern

目前為 2024-11-20 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Sexy.AI to SillyTavern origin
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Sync between Sexy.AI and SillyTavern
// @author       You
// @match        https://sexy.ai/workflow*
// @match        https://staticui.sexy.ai/*
// @match        http://ducninh.top:8000/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        unsafeWindow
// @grant        GM_addStyle
// ==/UserScript==

(function() {
   'use strict';

   // Add CSS for mobile
   GM_addStyle(`
       .ai-button {
           display: inline-block !important;
           padding: 8px 12px !important;
           background-color: #4CAF50 !important;
           color: white !important;
           border: none !important;
           border-radius: 5px !important;
           cursor: pointer !important;
           font-size: 16px !important;
           margin: 5px !important;
           opacity: 0.8;
           transition: opacity 0.3s;
           -webkit-tap-highlight-color: transparent;
           touch-action: manipulation;
       }
       .ai-button:active {
           opacity: 1;
       }
       .button-container {
           display: flex;
           flex-wrap: wrap;
           gap: 5px;
           margin-top: 5px;
           width: 100%;
       }
       @media (max-width: 768px) {
           .ai-button {
               padding: 10px 15px !important;
               font-size: 18px !important;
               min-width: 100px;
           }
       }
   `);

   function createStyledButton(text, onClick, isFixed = false) {
       const button = document.createElement('button');
       button.textContent = text;
       button.className = 'ai-button';

       if(isFixed) {
           button.style.cssText = `
               position: fixed;
               z-index: 9999;
               right: 20px;
           `;
       }

       button.addEventListener('click', onClick);
       button.addEventListener('touchstart', () => button.style.opacity = '1');
       button.addEventListener('touchend', () => button.style.opacity = '0.8');

       return button;
   }

   const isSexyAI = window.location.href.includes('staticui.sexy.ai');
   const isSillyTavern = window.location.href.includes('ducninh.top:8000');

   if (isSexyAI) {
       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);
                   alert('Prompt added!');
               } else {
                   console.error('Available inputs:', document.querySelectorAll('input, textarea'));
                   alert('Input field not found.');
               }
           } else {
               alert('No prompt found. Copy from SillyTavern first.');
           }
       }, true);

       promptButton.style.top = '80px';
       document.body.appendChild(promptButton);

       document.addEventListener('click', (e) => {
           if (e.target.tagName === 'IMG') {
               const markdownUrls = [`![alt-text](${e.target.src})`];
               GM_setValue('sexyai_images', markdownUrls.join('\n'));
               alert('Image copied! Switch to SillyTavern tab.');
           }
       }, true);

   } else if (isSillyTavern) {
       // Monitor DOM changes to add buttons to new messages
       const observer = new MutationObserver((mutations) => {
           mutations.forEach((mutation) => {
               mutation.addedNodes.forEach((node) => {
                   if (node.classList?.contains('mes')) {
                       const messageText = node.querySelector('.mes_text');
                       if (messageText && !messageText.querySelector('.button-container')) {
                           const buttonContainer = document.createElement('div');
                           buttonContainer.className = 'button-container';

                           // Sync Image button
                           const syncButton = createStyledButton('📥 Sync Image', () => {
                               const markdownUrls = GM_getValue('sexyai_images', null);
                               if (!markdownUrls) {
                                   alert('No images found. Click an image in Sexy.AI first.');
                                   return;
                               }

                               const editButton = node.querySelector('.mes_edit');
                               if (editButton) {
                                   editButton.click();
                                   setTimeout(() => {
                                       const textarea = document.getElementById('curEditTextarea');
                                       if (textarea) {
                                           textarea.value = textarea.value + '\n' + markdownUrls;
                                           setTimeout(() => {
                                               const confirmButton = node.querySelector('.mes_edit_done');
                                               if (confirmButton) {
                                                   confirmButton.click();
                                                   GM_setValue('sexyai_images', null);
                                                   alert('Images added successfully!');
                                               }
                                           }, 100);
                                       }
                                   }, 100);
                               }
                           });

                           // Send Prompt button
                           const sendPromptButton = createStyledButton('📤 Send Prompt', () => {
                               const text = messageText.textContent;
                               const match = text.match(/image###([^#]+)###/);
                               if (match) {
                                   const prompt = match[1].trim();
                                   GM_setValue('st_prompt', prompt);
                                   alert('Prompt copied! Click "Get Prompt" in Sexy.AI tab');
                               } else {
                                   alert('No valid prompt found. Message should contain image###prompt###');
                               }
                           });

                           buttonContainer.appendChild(syncButton);
                           buttonContainer.appendChild(sendPromptButton);
                           messageText.appendChild(buttonContainer);
                       }
                   }
               });
           });
       });

       observer.observe(document.body, {
           childList: true,
           subtree: true
       });
   }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址