// ==UserScript== // @name c.ai X Character Creation Helper // @namespace c.ai X Character Creation Helper // @version 1.0 // @license MIT // @description Does some stuff in the Definition // @author Vishanka // @match https://character.ai/* // @grant none // @downloadURL none // ==/UserScript== (function() { 'use strict'; // Function to check for element's presence and execute a callback when found const checkElementPresence = (selector, callback, maxAttempts = 10) => { let attempts = 0; const interval = setInterval(() => { const element = document.querySelector(selector); if (element) { clearInterval(interval); callback(element); } else if (++attempts >= maxAttempts) { clearInterval(interval); console.warn(`Element ${selector} not found after ${maxAttempts} attempts.`); } }, 1000); }; // Function to monitor elements on the page function monitorElements() { const initialElementIds = [ //'div.flex-auto:nth-child(1) > div:nth-child(2) > div:nth-child(1)', 'div.relative:nth-child(5) > div:nth-child(1) > div:nth-child(1)', // Greeting 'div.relative:nth-child(4) > div:nth-child(1) > div:nth-child(1)' // Description ]; initialElementIds.forEach(selector => { checkElementPresence(selector, (element) => { console.log(`Content of ${selector}:`, element.textContent); }); }); // Selector for the definition const definitionSelector = '.transition > div:nth-child(1) > div:nth-child(1) > div:nth-child(1)'; checkElementPresence(definitionSelector, (element) => { const textarea = element.querySelector('textarea'); if (textarea && !document.querySelector('.custom-definition-panel')) { updatePanel(textarea); // Initial panel setup // Observer to detect changes in the textarea content const observer = new MutationObserver(() => { updatePanel(textarea); }); observer.observe(textarea, {attributes: true, childList: true, subtree: true, characterData: true}); } }); } // Function to update or create the newPanel based on textarea content function updatePanel(textarea) { let newPanel = document.querySelector('.custom-definition-panel'); if (!newPanel) { newPanel = document.createElement('div'); newPanel.classList.add('custom-definition-panel'); textarea.parentNode.insertBefore(newPanel, textarea); } newPanel.innerHTML = ''; // Clear existing content newPanel.style.border = '0px solid #ccc'; newPanel.style.padding = '10px'; newPanel.style.marginBottom = '10px'; const cleanedContent = textarea.value.trim(); console.log(`Content of Definition:`, cleanedContent); const textLines = cleanedContent.split('\n'); let lastColor = '#222326'; let isDialogueContinuation = false; // Track if the current line continues a dialogue let prevColor = null; // Track the previous line's color for detecting color changes // Determine line color based on content and dialogue continuation logic let consecutiveCharCount = 0; let lastCharColor = ''; let lastNamedCharacterColor = ''; //let isDialogueContinuation = false; function determineLineColor(line, prevLine) { const dialogueStarterRegex = /^\{\{(?:char|user|random_user_[^\}]*)\}\}:|^[A-Za-z]+:/; const isDialogueStarter = dialogueStarterRegex.test(line); const continuesDialogue = prevLine && prevLine.trim().endsWith(':') && (line.startsWith(' ') || !dialogueStarterRegex.test(line)); if (isDialogueStarter) { isDialogueContinuation = true; if (line.startsWith('{{char}}:')) { consecutiveCharCount++; lastColor = consecutiveCharCount % 2 === 0 ? '#26272B' : '#292A2E'; lastCharColor = lastColor; } else if (line.match(/^[A-Za-z]+:/)) { lastNamedCharacterColor = lastNamedCharacterColor === '#474747' ? '#4C4C4D' : '#474747'; lastColor = lastNamedCharacterColor; } else if (line.match(/^\{\{random_user_[^\}]*\}\}:|^\{\{random_user_\}\}:|^{{random_user_}}/)) { lastNamedCharacterColor = lastNamedCharacterColor === '#474747' ? '#4C4C4D' : '#474747'; lastColor = lastNamedCharacterColor; } else { consecutiveCharCount = 0; lastColor = line.startsWith('{{user}}:') ? '#37362F' : '#3B3A32'; } } else if (line.startsWith('END_OF_DIALOG')) { isDialogueContinuation = false; lastColor = 'rgba(65, 65, 66, 0)'; } else if (isDialogueContinuation && continuesDialogue) { // Do nothing, continuation of dialogue } else if (isDialogueContinuation && !isDialogueStarter) { // Do nothing, continuation of dialogue } else { isDialogueContinuation = false; lastColor = 'rgba(65, 65, 66, 0)'; } return lastColor; } // Function to remove dialogue starters from the start of a line let trimmedParts = []; // Array to store trimmed parts let consecutiveLines = []; // Array to store consecutive lines with the same color //let prevColor = null; function trimDialogueStarters(line) { const dialogueStarterRegex = /^(\{\{char\}\}:|\{\{user\}\}:|\{\{random_user_[^\}]*\}\}:|[A-Za-z]+:)\s*/; const trimmed = line.match(dialogueStarterRegex); if (trimmed) { trimmedParts.push(trimmed[0]); // Store the trimmed part } return line.replace(dialogueStarterRegex, ''); } function groupConsecutiveLines(color, lineDiv) { // Check if there are consecutive lines with the same color if (consecutiveLines.length > 0 && consecutiveLines[0].color === color) { consecutiveLines.push({ color, lineDiv }); } else { // If not, append the previous group of consecutive lines and start a new group appendConsecutiveLines(); consecutiveLines.push({ color, lineDiv }); } } function appendConsecutiveLines() { if (consecutiveLines.length > 0) { const groupDiv = document.createElement('div'); const color = consecutiveLines[0].color; // Create a container div that could potentially use flexbox const containerDiv = document.createElement('div'); containerDiv.style.width = '100%'; groupDiv.style.backgroundColor = color; groupDiv.style.padding = '12px'; groupDiv.style.borderRadius = '16px'; groupDiv.style.display = 'inline-block'; groupDiv.style.maxWidth = '100%'; // You might adjust this as needed // Only apply flexbox styling if the color condition is met if (color === '#37362F' || color === '#3B3A32') { containerDiv.style.display = 'flex'; containerDiv.style.justifyContent = 'flex-end'; // Aligns the child div to the right } consecutiveLines.forEach(({ lineDiv }) => { groupDiv.appendChild(lineDiv); }); // Add the groupDiv to the containerDiv (flex or not based on color) containerDiv.appendChild(groupDiv); // Append the containerDiv to the newPanel newPanel.appendChild(containerDiv); consecutiveLines = []; // Clear the array } } function formatText(text) { // Handle headers; replace Markdown headers (# Header) with