~~~ // Copy/paste this whole script into the dev console of a character.ai chat window. // Your chat log will be stored in the clipboard. let copyJson = false; // true for JSON, false for text dump // Don't modify below this line unless you want to change the script usernames = new Map(); // Anonymized chat messages chatDom = document.getElementsByClassName("msg-row"); // Chat DOM items result = []; // Extracted chat messages // Messages are stored in the DOM in reverse order for (let i = chatDom.length-1; i >= 0; i--) { const msg = chatDom[i]; // The DOM isn't properly structured with id attributes. // We need to some hackish things to parse it. const spans = msg.getElementsByTagName("span"); const nameRow = spans[spans.length-1].innerText; // Check for this box to determine if the name should be anonymized const aiIcon = msg.getElementsByClassName("d-flex flex-column"); const isAI = aiIcon.length != 0; if (isAI) { // The first chunk of text is the actual name. // Append (AI) so it's obvious this is a bot message name = nameRow.split("\n")[0] + " (AI)"; } else { if (usernames.has(nameRow)) { // We already created a name for this user. Reuse it. name = usernames.get(nameRow); } else { // New user. Create an anonymized name. name = "Anonymous" + usernames.size; usernames.set(nameRow, name); } } const msgContent = msg.getElementsByTagName("p")[0].innerText; result.push({ name: name, content: msgContent }); } if (copyJson) { copy(JSON.stringify(result)); } else { let messageStrings = []; for (let msg of result) { messageStrings.push(msg.name + ": " + msg.content + "\n"); } copy(messageStrings.join("\n")); } ~~~