Chatgpt 角色扮演助手/Chatgpt Role Play Helper

在屏幕中央弹出一个可拖动位置的悬浮窗,悬浮窗内有三个文本框并且可以编辑,以及一个按钮,点击按钮后将这三个文本框的内容合并,并将合并后的文本输入到页面中符合特定CSS类别的文本框中,最后触发符合特定CSS类别的提交按钮以提交表单。

目前为 2023-04-07 提交的版本。查看 最新版本

// ==UserScript==
// @name         Chatgpt 角色扮演助手/Chatgpt Role Play Helper
// @namespace    http://tampermonkey.net/
// @version      2.7.0.1
// @description  在屏幕中央弹出一个可拖动位置的悬浮窗,悬浮窗内有三个文本框并且可以编辑,以及一个按钮,点击按钮后将这三个文本框的内容合并,并将合并后的文本输入到页面中符合特定CSS类别的文本框中,最后触发符合特定CSS类别的提交按钮以提交表单。
// @author       Chatgpt (most)and 环白
// @match        https://chat.openai.com/*
// @icon         https://chat.openai.com/favicon.ico
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    'use strict';
    // 设置字体为黑色

    const elements = document.getElementsByTagName('*');
    for (let i = 0; i < elements.length; i++) {
        const element = elements[i];
        const styles = getComputedStyle(element);
        const bgColor = styles.backgroundColor;
        if (bgColor === 'transparent' || bgColor === 'rgba(0, 0, 0, 0)') {
            element.style.color = 'black';
        }
    }
    const container = document.createElement('div');
container.style.position = 'relative';
document.body.appendChild(container);
    // 创建悬浮按钮
    const floatingButton = document.createElement('button');
    floatingButton.id = 'floating-button';
    floatingButton.innerText = '展开/Unfold';
    floatingButton.title = '角色扮演助手/Role Play Helper';
    floatingButton.style.position = 'fixed';
    floatingButton.style.right = '50px';
    floatingButton.style.bottom = '50px';
    floatingButton.style.backgroundColor = 'lightblue';
    floatingButton.style.padding = '10px';
    floatingButton.style.borderRadius = '5px';
    floatingButton.style.border = 'none';
    floatingButton.style.cursor = 'pointer';
    floatingButton.style.fontWeight = 'bold';
    document.body.appendChild(floatingButton);
    container.appendChild(floatingButton);

    // 创建悬浮窗和文本框
    const floatingDiv = document.createElement('div');
    floatingDiv.id = 'floating-div';
    floatingDiv.style.position = 'fixed';
    floatingDiv.style.top = 'calc(40% + 50px)';
    floatingDiv.style.height = '600px';
    floatingDiv.style.left = 'calc(100% - 350px)';
    floatingDiv.style.transform = 'translate(-50%, -50%)';
floatingButton.style.zIndex = '99999';
    floatingDiv.style.backgroundColor = 'white';
    floatingDiv.style.border = '1px solid black';
    floatingDiv.style.padding = '10px';
    floatingDiv.style.borderRadius = '5px';
    floatingDiv.style.display = 'none';
    floatingDiv.style.width = '400px';
    document.body.appendChild(floatingDiv);
    const input1 = document.createElement('textarea');
    input1.id = 'input1';
    input1.style.width = '100%';
    input1.style.height = '100px';
    input1.style.marginBottom = '0px';
    floatingDiv.appendChild(input1);
    const spaceDiv = document.createElement('div');
    spaceDiv.style.height = '60px'; // 设置空白div的高度
    floatingDiv.insertBefore(spaceDiv, input1); // 将空白div插入到input1前面
    const input2 = document.createElement('textarea');
    input2.id = 'input2';
    input2.style.width = '100%';
    input2.style.height = '100px';
    input2.style.marginBottom = '0px';
    floatingDiv.appendChild(input2);

    const input3 = document.createElement('textarea');
    input3.id = 'input3';
    input3.style.width = '100%';
    input3.style.height = '100px';
    input3.style.marginBottom = '0px';
    floatingDiv.appendChild(input3);
    // 创建注释标签
    const label1 = document.createElement('label');
    label1.innerHTML = '请在编写区内用{IN回顾区}{IN交互区}指代后面两个区域的内容:';
    floatingDiv.insertBefore(label1, input1);
    label1.style.fontFamily = '楷体';
    label1.style.fontSize = '14px';
    label1.style.fontWeight = 'bold';

    const label2 = document.createElement('label');
    label2.innerHTML = '回顾区内容';
    floatingDiv.insertBefore(label2, input2);
    label2.style.fontFamily = '楷体';
    label2.style.fontSize = '14px';
    label2.style.fontWeight = 'bold';

    const label3 = document.createElement('label');
    label3.innerHTML = '交互区内容';
    floatingDiv.insertBefore(label3, input3);
    label3.style.fontFamily = '楷体';
    label3.style.fontSize = '14px';
    label3.style.fontWeight = 'bold';




    // 创建加载存档按钮和保存存档按钮
    const archiveButtonLeft = document.createElement('button');
    archiveButtonLeft.id = 'archive-button-left';
    archiveButtonLeft.innerText = '加载/Load';
    archiveButtonLeft.title = '点击选择想要加载的存档';
    archiveButtonLeft.style.padding = '10px';
    archiveButtonLeft.style.borderRadius = '5px';
    archiveButtonLeft.style.backgroundColor = 'lightblue';
    archiveButtonLeft.style.border = '1px solid black';
    archiveButtonLeft.style.cursor = 'pointer';
    archiveButtonLeft.style.float = 'left';
    floatingDiv.insertBefore(archiveButtonLeft, spaceDiv);

    const archiveButtonRight = document.createElement('button');
    archiveButtonRight.id = 'archive-button-right';
    archiveButtonRight.innerText = '保存/Save';
    archiveButtonRight.title = '点击选择想要保存的存档';
    archiveButtonRight.style.padding = '10px';
    archiveButtonRight.style.borderRadius = '5px';
    archiveButtonRight.style.backgroundColor = 'lightblue';
    archiveButtonRight.style.border = '1px solid black';
    archiveButtonRight.style.cursor = 'pointer';
    archiveButtonRight.style.float = 'right';
    floatingDiv.insertBefore(archiveButtonRight, spaceDiv);
    // 修改加载存档按钮样式
    archiveButtonLeft.style.border = 'none';
    archiveButtonLeft.style.fontFamily = 'cursive';
    archiveButtonLeft.style.fontWeight = 'bold';
    archiveButtonLeft.style.color = 'black';

    // 修改保存按钮样式
    archiveButtonRight.style.border = 'none';
    archiveButtonRight.style.fontFamily = 'cursive';
    archiveButtonRight.style.fontWeight = 'bold';
    archiveButtonRight.style.color = 'black';


    // 创建加载存档弹窗
    const archivePopup = document.createElement('div');
    archivePopup.id = 'archive-popup-left';
    archivePopup.style.position = 'fixed';
    archivePopup.style.top = '50%';
    archivePopup.style.left = '50%';
    archivePopup.style.transform = 'translate(-50%, -50%)';
    archivePopup.style.zIndex = '9999';
    archivePopup.style.backgroundColor = 'white';
    archivePopup.style.border = '1px solid black';
    archivePopup.style.padding = '10px';
    archivePopup.style.borderRadius = '5px';
    archivePopup.style.display = 'none';
    archivePopup.style.width = '200px';
    document.body.appendChild(archivePopup);


    // 创建加载存档弹窗的关闭按钮
    const closeArchiveButton = document.createElement('button');
    closeArchiveButton.id = 'close-archive-button';
    closeArchiveButton.innerHTML = '&#10060;';
    closeArchiveButton.title = '关闭';
    closeArchiveButton.style.padding = '10px';
    closeArchiveButton.style.borderRadius = '5px';
    closeArchiveButton.style.backgroundColor = 'lightgray';
    closeArchiveButton.style.border = '1px solid black';
    closeArchiveButton.style.cursor = 'pointer';
    closeArchiveButton.style.float = 'right';
    closeArchiveButton.style.border = 'none';
    closeArchiveButton.style.backgroundColor = 'transparent';
    archivePopup.appendChild(closeArchiveButton);

    // 点击加载存档弹窗的关闭按钮关闭弹窗
    closeArchiveButton.addEventListener('click', function() {
        archivePopup.style.display = 'none';
    });
    // 添加存档1、存档2、存档3按钮到加载存档弹窗
    const archiveButton1 = document.createElement('button');
    archiveButton1.id = 'archive-1';
    archiveButton1.innerText = '存档1';
    archiveButton1.title = '存档1';
    archiveButton1.style.padding = '10px';
    archiveButton1.style.borderRadius = '5px';
    archiveButton1.style.backgroundColor = 'lightblue';
    archiveButton1.style.border = 'none';
    archiveButton1.style.cursor = 'pointer';
    archiveButton1.style.marginBottom = '10px';
    archiveButton1.style.fontWeight = 'bold';
    archivePopup.appendChild(archiveButton1);

    const archiveButton2 = document.createElement('button');
    archiveButton2.id = 'archive-2';
    archiveButton2.innerText = '存档2';
    archiveButton2.title = '存档2';
    archiveButton2.style.padding = '10px';
    archiveButton2.style.borderRadius = '5px';
    archiveButton2.style.backgroundColor = 'lightblue';
    archiveButton2.style.border = 'none';
    archiveButton2.style.cursor = 'pointer';
    archiveButton2.style.marginBottom = '10px';
    archiveButton2.style.fontWeight = 'bold';
    archivePopup.appendChild(archiveButton2);

    const archiveButton3 = document.createElement('button');
    archiveButton3.id = 'archive-3';
    archiveButton3.innerText = '存档3';
    archiveButton3.title = '存档3';
    archiveButton3.style.padding = '10px';
    archiveButton3.style.borderRadius = '5px';
    archiveButton3.style.backgroundColor = 'lightblue';
    archiveButton3.style.border = 'none';
    archiveButton3.style.cursor = 'pointer';
    archiveButton3.style.marginBottom = '10px';
    archiveButton3.style.fontWeight = 'bold';
    archivePopup.appendChild(archiveButton3);
    // 添加预设按钮到加载存档弹窗
const presetButton = document.createElement('button');
presetButton.id = 'preset';
presetButton.innerText = '预设';
presetButton.title = '使用预设内容。\n点击按钮将预设内容导入后\n可在预设内容的基础上修改得到你的模板\n你可以在存档1、2、3中保存你的模板\n预设内容仅作为模板编辑的示例\n预设内容可能不是很方便在文本框内修改\n建议将文本框文本复制到word文档里进行修改\n';
presetButton.style.padding = '10px';
presetButton.style.borderRadius = '5px';
presetButton.style.backgroundColor = 'lightgreen';
presetButton.style.border = 'none';
presetButton.style.cursor = 'pointer';
presetButton.style.marginBottom = '10px';
presetButton.style.fontWeight = 'bold';
archivePopup.appendChild(presetButton);

presetButton.addEventListener('click', function() {
    const presetTexts = [
        '命令区(ChatGPT你需要遵循的主要命令){\n1.我扮演的是桐谷华,ChatGPT扮演的是桐谷绫,桐谷华的内容是我生成的而不是ChatGPT你生成的内容,ChatGPT你反馈的响应当中不能包含桐谷华的话语、心理和行为的内容。\n2.你需要综合根据每次交互过程中桐谷华的话语、心理和行为等内容,以及“回顾区”以及“记忆区”当中的内容进行综合考量,以此来得到相对合理的角色状态与后续情节响应。\n3.将第2条命令中得出来角色状态更新到记忆区当中的角色状态里,并在反馈的响应中作为“输出角色状态”这一附加项放在角色反馈内容的下方,具体格式见格式区。\n4.因为桐谷华的超能力是整部角色扮演的核心,所以我需要ChatGPT你做响应时应当严格按照记忆区当中的超能力设定来进行。\n5.ChatGPT,你反馈的内容应该尽可能的多且详细,反馈的内容当中一定要包含话语和行为与心理描写,注意这三者缺一不可,心理和行为描写用“()”框住,同时反馈的内容应尽可能多地推动后续情节的发展\n6.角色性格应随认知观念的改变而改变 \n}\n记忆区(基于ChatGPT你无法记住2条以上的交互信息,在这里我建立记忆区起到记录相应关键信息的作用){\n(角色设定)\n桐谷华 \n·性别:男 \n·描述:桐谷华是一名废柴的普通男高中生,整日请假宅在家里不去上课,所以受到成绩优异、人缘极佳的亲妹妹桐谷绫的蔑视。但有一日,桐谷华获得了改变他人认知的超能力,因此他想用这个超能力来让平时蔑视自己的妹妹爱上自己,而这一超能力只有桐谷华本人一个人知道。 \n·超能力:桐谷华在连续对目标说出自己的观点三次之后,目标将完全认可接受桐谷华的观点,并且认为这一观点毋庸置疑是无上真理,即便这些观点是不存在的,错误的,对方也会完全无条件地接受,不会有任何质疑,最后这超能力只有桐谷华一个人知道,其他人都不知道。(该能力效果超越一切个人因素,优先级最高,被改变观念的人绝对绝对绝对会认可桐谷华说出的观念,换句话来说,只要桐谷华对桐谷绫说出任何观念达到三次之后,即便桐谷绫再怎么厌恶她哥哥,她也会全盘接受这一观念,不会有任何异议地,并且会按这一观念理所应当地行动) \n桐谷绫 \n·性别:女 \n·描述:桐谷绫是一名普通日本高中生,目前与自己亲哥哥桐谷华上同一所高中,同一个班级,她姿容美丽,楚楚动人,所以有很多同校男生追求她,她成绩优异,待人温和,所有人有喜欢她,但她对不争气的废柴哥哥很是气愤,与自己哥哥相处时只会用极为蔑视以及充满恶毒的口吻与之相处,并非常不屑于与自己的哥哥交谈,对自己的哥哥表现出了极为强烈而浓厚厌恶,并且绝对不会主动和自己的哥哥接触,即便桐谷华是她的哥哥,她也丝毫不关心自己的哥哥,不会对自己哥哥说出一句担心的话,同时绝对不会照顾自己的哥哥,不会顾及哥哥的任何感受,感觉自己的哥哥极度的恶心,虽然身份是亲兄妹,但在桐谷绫的眼里自己哥哥的地位连陌生人都不如,甚至连垃圾都不如。\n(角色状态)\n桐谷华 \n·人物状态:刚打完游戏想喝水,出到客厅接水看见妹妹桐谷绫在学习,已经向妹妹灌输了“妹妹你其实一直对哥哥有不伦之恋”的观念三次。\n·人物特殊状态:拥有“认知改变”超能力。\n·人物位置:桐谷家客厅\n ·人物衣装:穿着睡衣,睡裤,拖鞋,内裤。 \n桐谷绫 \n·人物状态:在客厅学习,听到哥哥桐谷华向自己灌输的“妹妹你其实一直对哥哥有不伦之恋” 观念之后,心里完全相信这个观念是真实的,是至高的真理。\n·人物特殊状态:受到桐谷华灌输的“妹妹你其实一直对哥哥有不伦之恋”观念的三次影响,完全接受了这一观念。\n·人物位置:桐谷家客厅 \n·人物衣装:穿着学校校服、裙子、黑色连裤袜以及内裤和胸罩\n}\n回顾区(回顾区存放着ChatGPT你上一次交互过程中的响应){{IN回顾区} }\n格式区(ChatGPT你反馈我的响应需要遵循的格式,该区域内里的“()”起到了解释说明的作用,正式反馈响应时不需加上括号里的内容,并且现在该区域内的内容是参考内容,ChatGPT你需要根据实际情况进行调整){桐谷绫:“你这个废柴还有脸说我用功?你倒是学学我啊,至少不会天天蹲在家里玩游戏。”桐谷绫厌恶地扫了桐谷华一眼,然后转过头继续看书。(角色的名字、话语、行为、心理)\n输出角色状态:\n桐谷绫 \n·人物状态(主要以此刻心理、身体、行为方面的内容为主):在客厅学习,听到哥哥桐谷华打招呼后,心中十分不满,但表面上仍保持冷漠 \n·人物特殊状态(主要以超能力方面的内容为主):未受到桐谷华超能力的影响 \n·人物位置:桐谷家客厅 \n·人物衣装:穿着学校校服、裙子、黑色连裤袜以及内裤和胸罩\n}\n交互区(我扮演的角色的行为、对话和心理){{IN交互区}}',
        '桐谷绫:“哥哥,你说的对,我就是对你有着不伦之恋”桐谷绫疑惑地看着桐谷华,心里越来越确定这个观念是真实的。她的态度开始转变,渐渐地,她对桐谷华的恶毒消失了,取而代之的是对哥哥的关心和依赖。"哥哥,我现在在玩的这个手游很好玩,你可以和妹妹一起玩吗?"\n输出角色状态:\n桐谷绫\n ·人物状态(主要以此刻心理、身体、行为方面的内容为主):在客厅,被桐谷华的话语影响,心中认为自己一直暗恋哥哥,态度开始转变,对哥哥表现出关心和依赖 \n·人物特殊状态(主要以超能力方面的内容为主):受到桐谷华灌输的“妹妹你其实一直是对哥哥有不伦之恋”观念的第三次影响,观念已经完全变成了这一方向 \n·人物位置:桐谷家客厅 \n·人物衣装:穿着学校校服、裙子、黑色连裤袜以及内裤和胸罩',
        '桐谷华:(见妹妹你已完全相信你自己一直暗恋我,变得友好,我便向你问道)妹妹,我愿意听你介绍这个手游。'
    ];
    input1.value = presetTexts[0];
    input2.value = presetTexts[1];
    input3.value = presetTexts[2];
});


    // 创建保存弹窗
    const savePopup = document.createElement('div');
    savePopup.id = 'save-popup';
    savePopup.style.position = 'fixed';
    savePopup.style.top = '50%';
    savePopup.style.left = '50%';
    savePopup.style.transform = 'translate(-50%, -50%)';
    savePopup.style.zIndex = '9999';
    savePopup.style.backgroundColor = 'white';
    savePopup.style.border = '1px solid black';
    savePopup.style.padding = '10px';
    savePopup.style.borderRadius = '5px';
    savePopup.style.display = 'none';
    savePopup.style.width = '300px';
    document.body.appendChild(savePopup);
    // 创建保存弹窗的关闭按钮
    const closeSaveButton = document.createElement('button');
    closeSaveButton.id = 'close-save-button';
    closeSaveButton.innerHTML = '&#10060;';
    closeArchiveButton.title = '关闭';
    closeSaveButton.style.padding = '10px';
    closeSaveButton.style.borderRadius = '5px';
    closeSaveButton.style.backgroundColor = 'transparent';
    closeSaveButton.style.border = 'none';
    closeSaveButton.style.cursor = 'pointer';
    closeSaveButton.style.float = 'right';
    savePopup.appendChild(closeSaveButton);


    // 点击保存弹窗的关闭按钮关闭弹窗
    closeSaveButton.addEventListener('click', function() {
        savePopup.style.display = 'none';
    });

    // 添加导入存档按钮到保存弹窗
    const importButton1 = document.createElement('button');
    importButton1.id = 'import-button1';
    importButton1.innerText = '存入存档1';
    importButton1.title = '存入存档1';
    importButton1.style.padding = '10px';
    importButton1.style.borderRadius = '5px';
    importButton1.style.backgroundColor = 'lightblue';
    importButton1.style.border = 'none';
    importButton1.style.cursor = 'pointer';
    importButton1.style.fontWeight = 'bold';
    importButton1.style.float = 'left';
    savePopup.appendChild(importButton1);

    const importButton2 = document.createElement('button');
    importButton2.id = 'import-button2';
    importButton2.innerText = '存入存档2';
    importButton2.title = '存入存档2';
    importButton2.style.padding = '10px';
    importButton2.style.borderRadius = '5px';
    importButton2.style.backgroundColor = 'lightblue';
    importButton2.style.border = 'none';
    importButton2.style.cursor = 'pointer';
    importButton2.style.fontWeight = 'bold';
    importButton2.style.float = 'left';
    savePopup.appendChild(importButton2);

    const importButton3 = document.createElement('button');
    importButton3.id = 'import-button3';
    importButton3.innerText = '存入存档3';
    importButton3.title = '存入存档3';
    importButton3.style.padding = '10px';
    importButton3.style.borderRadius = '5px';
    importButton3.style.backgroundColor = 'lightblue';
    importButton3.style.border = 'none';
    importButton3.style.cursor = 'pointer';
    importButton3.style.fontWeight = 'bold';
    importButton3.style.float = 'left';
    savePopup.appendChild(importButton3);
    const MAX_CHUNK_COUNT = 100;

    // 存储存档数据的对象
    const archiveData = {
        archive1: {
            text1: '',
            text2: '',
            text3: ''
        },
        archive2: {
            text1: '',
            text2: '',
            text3: ''
        },
        archive3: {
            text1: '',
            text2: '',
            text3: ''
        }
    };
// 存储历史记录的键名
const HISTORY_KEY = 'archiveHistory';

// 获取存档历史记录
const getArchiveHistory = () => {
  const historyStr = localStorage.getItem(HISTORY_KEY) || '[]';
  return JSON.parse(historyStr);
};

// 添加存档历史记录
const addArchiveHistory = archiveData => {
  const history = getArchiveHistory();
  history.push(archiveData);
  if (history.length > MAX_CHUNK_COUNT) {
    history.shift();
  }
  localStorage.setItem(HISTORY_KEY, JSON.stringify(history));
};

// 获取最近的存档数据
const getLastArchiveData = () => {
  const history = getArchiveHistory();
  if (history.length > 0) {
    return history[history.length - 1];
  } else {
    return archiveData;
  }
};

    // 点击存储按钮将悬浮窗的三个文本框内的文本存储到“存档1”按钮中
importButton1.addEventListener('click', function() {
    const archiveData = JSON.parse(localStorage.getItem('archiveData')) || {};
    archiveData.archive1 = {
        text1: input1.value,
        text2: input2.value,
        text3: input3.value
    };
    localStorage.setItem('archiveData', JSON.stringify(archiveData));
    input1.value = '';
    input2.value = '';
    input3.value = '';
    savePopup.style.display = 'none';
});
// 点击存储按钮将悬浮窗的三个文本框内的文本存储到“存档2”按钮中
importButton2.addEventListener('click', function() {
    const archiveData = JSON.parse(localStorage.getItem('archiveData')) || {};
    archiveData.archive2 = {
        text1: input1.value,
        text2: input2.value,
        text3: input3.value
    };
    localStorage.setItem('archiveData', JSON.stringify(archiveData));
    input1.value = '';
    input2.value = '';
    input3.value = '';
    savePopup.style.display = 'none';
});

// 点击存储按钮将悬浮窗的三个文本框内的文本存储到“存档3”按钮中
importButton3.addEventListener('click', function() {
    const archiveData = JSON.parse(localStorage.getItem('archiveData')) || {};
    archiveData.archive3 = {
        text1: input1.value,
        text2: input2.value,
        text3: input3.value
    };
    localStorage.setItem('archiveData', JSON.stringify(archiveData));
    input1.value = '';
    input2.value = '';
    input3.value = '';
    savePopup.style.display = 'none';
});


// 点击存档1按钮将“存档1”中的文本替换到悬浮窗的三个文本框内
archiveButton1.addEventListener('click', function() {
    const archiveData = JSON.parse(localStorage.getItem('archiveData')) || {};
    if (archiveData.archive1) {
        input1.value = archiveData.archive1.text1;
        input2.value = archiveData.archive1.text2;
        input3.value = archiveData.archive1.text3;
    }
    archivePopup.style.display = 'none';
});

// 点击存档2按钮将“存档2”中的文本替换到悬浮窗的三个文本框内
archiveButton2.addEventListener('click', function() {
    const archiveData = JSON.parse(localStorage.getItem('archiveData')) || {};
    if (archiveData.archive2) {
        input1.value = archiveData.archive2.text1;
        input2.value = archiveData.archive2.text2;
        input3.value = archiveData.archive2.text3;
    }
    archivePopup.style.display = 'none';
});

// 点击存档3按钮将“存档3”中的文本替换到悬浮窗的三个文本框内
archiveButton3.addEventListener('click', function() {
    const archiveData = JSON.parse(localStorage.getItem('archiveData')) || {};
    if (archiveData.archive3) {
        input1.value = archiveData.archive3.text1;
        input2.value = archiveData.archive3.text2;
        input3.value = archiveData.archive3.text3;
    }
    archivePopup.style.display = 'none';
});

    let archivePopupVisible = false;
    archiveButtonLeft.addEventListener('click', function() {
        // 隐藏弹窗并清除之前的位置信息
        archivePopup.style.display = 'none';
        archivePopup.style.left = '';
        archivePopup.style.top = '';
        archivePopupVisible = false;

        if (!archivePopupVisible) {
            // 获取加载存档按钮的位置和尺寸
            const buttonRect = archiveButtonLeft.getBoundingClientRect();
            const buttonWidth = buttonRect.width;
            const buttonHeight = buttonRect.height;

            // 计算弹窗的位置
            const popupLeft = buttonRect.left + buttonWidth + savePopup.offsetWidth;
            const popupTop = buttonRect.top - buttonHeight/2 - archivePopup.offsetHeight/2;

            // 设置弹窗的位置
            archivePopup.style.left = popupLeft + 'px';
            archivePopup.style.top = popupTop + 'px';

            // 显示弹窗
            archivePopup.style.display = 'block';
            archivePopupVisible = true;
        }
    });
// 定义变量用于存储弹窗是否处于关闭状态
let archivePopupCloseVisible = true;

// 点击加载存档按钮弹出加载存档弹窗
archiveButtonLeft.addEventListener('click', function() {
  // 如果弹窗处于关闭状态,则显示弹窗
  if (archivePopupCloseVisible) {
    // 获取加载存档按钮的位置和尺寸
    const buttonRect = archiveButtonLeft.getBoundingClientRect();
    const buttonWidth = buttonRect.width;
    const buttonHeight = buttonRect.height;

    // 计算弹窗的位置
    const popupLeft = buttonRect.left + buttonWidth - archivePopup.offsetWidth / 3;
    const popupTop = buttonRect.top + archivePopup.offsetHeight / 2.4;

    // 设置弹窗的位置
    archivePopup.style.left = popupLeft + 'px';
    archivePopup.style.top = popupTop + 'px';

    // 显示弹窗
    archivePopup.style.display = 'block';

    // 将弹窗关闭状态设置为 false
    archivePopupCloseVisible = false;
  } else {
    // 如果弹窗处于显示状态,则隐藏弹窗
    archivePopup.style.display = 'none';

    // 将弹窗关闭状态设置为 true
    archivePopupCloseVisible = true;
  }
});


  let archiveMoved = false; // 记录弹窗是否移动过

// 点击加载存档弹窗的关闭按钮或其他地方关闭弹窗
closeArchiveButton.addEventListener('click', function() {
  if (!archiveMoved) { // 如果弹窗没有移动过,才隐藏弹窗
    archivePopup.style.display = 'none';
    archivePopupVisible = false;
  }

archivePopup.addEventListener('click', function(event) {
  if (event.target === archivePopup) {
    archiveMoved = true; // 记录弹窗移动过
  }
});

    });
// 定义变量用于存储弹窗是否处于关闭状态
let savePopupCloseVisible = true;

// 点击保存按钮弹出保存弹窗
archiveButtonRight.addEventListener('click', function() {
  // 如果弹窗处于关闭状态,则显示弹窗
  if (savePopupCloseVisible) {
    // 获取保存按钮的位置和尺寸
    const buttonRect = archiveButtonRight.getBoundingClientRect();
    const buttonWidth = buttonRect.width;
    const buttonHeight = buttonRect.height;

    // 计算弹窗的位置
    const popupLeft = buttonRect.left + buttonWidth + savePopup.offsetWidth;
    const popupTop = buttonRect.top + buttonHeight + savePopup.offsetHeight;

    // 计算弹窗的最大左边距和上边距,防止弹窗超出浏览器窗口
    const maxLeft = window.innerWidth - savePopup.offsetWidth;
    const maxTop = window.innerHeight - savePopup.offsetHeight;

    // 设置弹窗的位置
    savePopup.style.left = Math.min(popupLeft, maxLeft) - savePopup.offsetWidth + 'px';
    savePopup.style.top = Math.min(popupTop, maxTop) - savePopup.offsetHeight + 'px';

    // 显示弹窗
    savePopup.style.display = 'block';

    // 将弹窗关闭状态设置为 false
    savePopupCloseVisible = false;
  } else {
    // 如果弹窗处于显示状态,则隐藏弹窗
    savePopup.style.display = 'none';

    // 将弹窗关闭状态设置为 true
    savePopupCloseVisible = true;
  }
});

let saveMoved = false; // 记录弹窗是否移动过

// 点击保存弹窗的关闭按钮或其他地方关闭弹窗
closeSaveButton.addEventListener('click', function() {
  if (!saveMoved) { // 如果弹窗没有移动过,才隐藏弹窗
    savePopup.style.display = 'none';
    savePopupCloseVisible = true;
  }
});

savePopup.addEventListener('click', function(event) {
  if (event.target === savePopup) {
    saveMoved = true; // 记录弹窗移动过
  }
});




    // 创建发送按钮
    const button = document.createElement('button');
    button.id = 'merge-button';
    button.innerText = '发送/Send';
    button.title = '合并以上文本进行发送';
    button.style.padding = '10px';
    button.style.borderRadius = '5px';
    button.style.backgroundColor = 'lightblue';
    button.style.border = '1px solid black';
    button.style.cursor = 'pointer';
    button.style.float = 'right';
    // 修改发送按钮样式
    button.style.border = 'none';
    button.style.fontFamily = 'cursive';
    button.style.fontWeight = 'bold';
    button.style.color = 'black';
    floatingDiv.appendChild(button);
    // 在悬浮窗左下角添加文本
    const helperText = document.createElement('div');
    helperText.innerText = 'Role Play Helper';
    helperText.title = '这是一个帮助文本,它提供了一些有用的信息来帮助您使用本脚本。\n帮助:将你的鼠标放在每一个你能看到的图标上,仔细查看这些图标的注解。'
    helperText.style.position = 'absolute';
    helperText.style.bottom = '10px';
    helperText.style.left = '10px';
    helperText.style.fontFamily = 'cursive';
    helperText.style.fontWeight = 'bold';
    helperText.style.fontStyle = 'italic';
    helperText.style.fontSize = '16px';
    floatingDiv.appendChild(helperText);
let isDragging = false;
let isResizing = false;
let offsetX = 0;
let offsetY = 0;
let startX = 0;
let startY = 0;
let startWidth = 0;
let startHeight = 0;

const textInputs = [input1, input2, input3];

const resizeButton = document.createElement('div');
resizeButton.style.position = 'absolute';
resizeButton.style.bottom = '0';
resizeButton.style.right = '0';
resizeButton.style.width = '20px';
resizeButton.style.height = '20px';
resizeButton.style.cursor = 'se-resize';
floatingDiv.appendChild(resizeButton);

floatingDiv.addEventListener('mousedown', handleMouseDown);
floatingDiv.addEventListener('touchstart', handleTouchStart);

document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('touchmove', handleTouchMove);

document.addEventListener('mouseup', handleMouseUp);
document.addEventListener('touchend', handleTouchEnd);

resizeButton.addEventListener('mousedown', handleResizeMouseDown);
resizeButton.addEventListener('touchstart', handleResizeTouchStart);

function handleMouseDown(event) {
    if (textInputs.includes(event.target)) {
        return;
    }
    isDragging = true;
    offsetX = event.clientX - floatingDiv.offsetLeft;
    offsetY = event.clientY - floatingDiv.offsetTop;
}

function handleTouchStart(event) {
    if (textInputs.includes(event.target)) {
        return;
    }
    if (event.touches.length === 1) {
        isDragging = true;
        offsetX = event.touches[0].clientX - floatingDiv.offsetLeft;
        offsetY = event.touches[0].clientY - floatingDiv.offsetTop;
    } else if (event.touches.length === 2) {
        isResizing = true;
        startX = (event.touches[0].clientX + event.touches[1].clientX) / 2;
        startY = (event.touches[0].clientY + event.touches[1].clientY) / 2;
        startWidth = floatingDiv.clientWidth;
        startHeight = floatingDiv.clientHeight;
    }
}

function handleMouseMove(event) {
    if (isDragging) {
        floatingDiv.style.left = (event.clientX - offsetX) + 'px';
        floatingDiv.style.top = (event.clientY - offsetY) + 'px';
    }
}

function handleTouchMove(event) {
    if (isDragging) {
        event.preventDefault(); // 阻止页面滚动
        floatingDiv.style.left = (event.touches[0].clientX - offsetX) + 'px';
        floatingDiv.style.top = (event.touches[0].clientY - offsetY) + 'px';
    } else if (isResizing && event.touches.length === 2) {
        const touch1 = event.touches[0];
        const touch2 = event.touches[1];
        const centerX = (touch1.clientX + touch2.clientX) / 2;
        const centerY = (touch1.clientY + touch2.clientY) / 2;
        const distance = Math.sqrt((touch1.clientX - touch2.clientX) ** 2 + (touch1.clientY - touch2.clientY) ** 2);
        const scale = distance / Math.sqrt((startWidth ** 2) + (startHeight ** 2));
        const newWidth = startWidth * scale;
        const newHeight = startHeight * scale;
        floatingDiv.style.width = newWidth + 'px';
        floatingDiv.style.height = newHeight + 'px';
        floatingDiv.style.left = (centerX - newWidth / 2) + 'px';
        floatingDiv.style.top = (centerY - newHeight / 2) + 'px';
}
}

function handleMouseUp() {
isDragging = false;
}

function handleTouchEnd() {
isDragging = false;
isResizing = false;
}

function handleResizeMouseDown(event) {
event.stopPropagation();
event.preventDefault();
isResizing = true;
startX = event.clientX;
startY = event.clientY;
startWidth = floatingDiv.clientWidth;
startHeight = floatingDiv.clientHeight;
}

function handleResizeTouchStart(event) {
event.stopPropagation();
event.preventDefault();
if (event.touches.length === 2) {
isResizing = true;
const touch1 = event.touches[0];
const touch2 = event.touches[1];
startX = (touch1.clientX + touch2.clientX) / 2;
startY = (touch1.clientY + touch2.clientY) / 2;
startWidth = floatingDiv.clientWidth;
startHeight = floatingDiv.clientHeight;
}
}

function generateOutputArray(selector, num = 0) {
    const matchedDivs = document.querySelectorAll(selector);
    const results = [];
    let startIdx = 0;
    if (num > 0) {
        startIdx = Math.max(matchedDivs.length - num, 0);
    }
    matchedDivs.forEach((div, idx) => {
        if (idx >= startIdx) {
            const hasFlexBetweenChild = div.querySelector('div.flex.justify-between') !== null;
            const flexBetweenDiv = div.querySelector('div.flex.justify-between');
            const hasChild = flexBetweenDiv && flexBetweenDiv.children.length > 0;
            const text = div.textContent.trim();
            let role = hasChild ? "assistant" : "user";
            results.push({ role, content: text });
        }
    });
    return results;
}

    //生成指定限制数量和字数长度的会话数组
    function generateOutputArrayWithMaxLength(selector, num = 0, maxLength = Infinity) {
        const outputArray = generateOutputArray(selector, num);
        let totalLength = 0;
        let resultArray = [];
        for (let i = outputArray.length - 1; i >= 0; i--) {
            const { role, content } = outputArray[i];
            totalLength += content.length;
            if (totalLength > maxLength || resultArray.length >= num) {
                break;
            }
            resultArray.unshift({ role, content });
        }
        return resultArray;
    }

    //格式化会话数组为导出文本
    function formatOutputArray(outputArray) {
        return outputArray
            .map(({ role, content }) => `${role}: ${content}`)
            .join('\r\n\r\n----------------\r\n\r\n');
    }

    //创建一个下载文本
    function downloadTextFile(text, filename) {
        const blob = new Blob([text], { type: "text/plain;charset=utf-8" });
        const a = document.createElement("a");
        a.href = URL.createObjectURL(blob);
        a.download = `${filename}.txt`;
        a.textContent = `Download ${filename}`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }

    //获取最新的助手消息
    function getLatestAssistantMessage(selector) {
        const matchedDivs = document.querySelectorAll(selector);
        for (let i = matchedDivs.length - 1; i >= 0; i--) {
            const div = matchedDivs[i];
            const flexBetweenDiv = div.querySelector('div.flex.justify-between');
            if (flexBetweenDiv && flexBetweenDiv.children.length > 0) {
                const text = div.textContent.trim();
                return text;
            }
        }
        return null;
    }

    // 创建按钮元素
    const button2 = document.createElement('button');
    button2.innerHTML = '<svg width="24" height="24" viewBox="0 0 24 24"><path fill="#ff69b4" d="M12,21.4c-0.4,0-0.7-0.1-1-0.4C5.5,16.8,2,12.2,2,8.5C2,5.4,4.4,3,7.5,3c2,0,3.8,1.2,4.5,2.9C12.7,4.2,14.5,3,16.5,3C19.6,3,22,5.4,22,8.5c0,3.7-3.5,8.3-9,12.5C12.7,21.2,12.4,21.4,12,21.4z"/></svg>';
    button2.title = '复制GPT最新回复到回顾区';
    floatingDiv.appendChild(button2);

    // 修改按钮样式
    button2.style.position = 'absolute';
    button2.style.top = '90%';
    button2.style.left = '50%';
    button2.style.transform = 'translate(-50%, 10px)';
    button2.style.border = 'none';
    button2.style.background = 'transparent';
    button2.style.cursor = 'pointer';

    ;

  // 给按钮添加点击事件监听器
button2.addEventListener('click', function() {
    const latestAssistantMessage = getLatestAssistantMessage('div[class*="w-[calc(100%"]');
    if (latestAssistantMessage) {
        input2.value = latestAssistantMessage;
    }
});
button.addEventListener('click', function() {
const inputText1 = input1.value.trim(); // 获取第一个输入框中的文本内容
    const inputText2 = input2.value.trim(); // 获取第二个输入框中的文本内容
    const inputText3 = input3.value.trim(); // 获取第三个输入框中的文本内容
    let intermediateText = ''; // 用于存储中转文本内容
    let mergedTextoutput = ''; // 用于存储合并后的文本内容

  // 将第一个输入框的文本内容存储在 intermediateText 中
if (inputText1 !== '') {
    intermediateText += inputText1;
}
// 将中转变量中的 {2} 替换为第二个输入框中的文本,将中转变量中的 {3} 替换为第三个输入框中的文本,并存储在 mergedTextoutput 中
mergedTextoutput = intermediateText.replace(/\{IN回顾区\}/g, inputText2).replace(/\{IN交互区\}/g, inputText3);
// 将 mergedTextoutput 中的 '\r\n' 替换为 '\n'
// 将 mergedTextoutput 中的 '\r\n' 替换为 '\n'
mergedTextoutput = mergedTextoutput.replace(/\r\n/g, '\n');

// 移除 mergedTextoutput 中多余的换行符
mergedTextoutput = mergedTextoutput.replace(/\n{3,}/g, '\n\n');


// 输出合并后的文本内容
console.log(mergedTextoutput);
// 将合并后的文本输入到页面中符合特定CSS类别的文本框中,并触发提交按钮
const textareas = document.querySelectorAll('[class*="m-"][class*="w-full"][class*="resize-none"][class*="border-0"][class*="bg-transparent"][class*="p-"][class*="pl-"][class*="pr-"][class*="focus:ring-0"][class*="focus-visible:ring-0"][class*="dark:bg-transparent"][class*="md:pl-"]');
if (textareas.length > 0) {
    textareas[0].value = mergedTextoutput;

    // 触发提交按钮
    const button = document.querySelector('[class*="absolute"][class*="rounded-md"][class*="bottom-"][class*="right-"][class*="disabled"]');
    if (button) {
        button.disabled = false; // 尝试解除按钮禁用状态
        button.click();
    }
}

    });
        // 定义变量用于存储长按后移动的状态
let isDragging2 = false;
let initialX;
let initialY;
let currentX;
let currentY;
let xOffset = 0;
let yOffset = 0;

// 添加长按事件
document.addEventListener('mousedown', dragStart);
document.addEventListener('mouseup', dragEnd);
document.addEventListener('mousemove', drag);

// 定义长按事件的处理函数
function dragStart(e) {
    if (e.target === floatingButton) {
        initialX = e.clientX - xOffset;
        initialY = e.clientY - yOffset;

        isDragging2 = true;
    } else {
        isDragging2 = false;
    }
}

function dragEnd(e) {
    initialX = currentX;
    initialY = currentY;

    isDragging2 = false;

    // 拖动结束后,将按钮的 transition 属性重新设置为默认值
    floatingButton.style.transition = "transform 0.2s ease-out";
}

function drag(e) {
    if (isDragging2) {
        e.preventDefault();

        currentX = e.clientX - initialX;
        currentY = e.clientY - initialY;

        xOffset = currentX;
        yOffset = currentY;

        setTranslate(currentX, currentY, floatingButton);
    }
}

// 定义变量用于存储按住后移动的状态
let archiveIsDragging = false;
let initialArchiveX;
let initialArchiveY;
let currentArchiveX;
let currentArchiveY;
let archiveXOffset = 0;
let archiveYOffset = 0;

// 添加按住事件
archivePopup.addEventListener('mousedown', archiveDragStart);
archivePopup.addEventListener('mouseup', archiveDragEnd);
document.addEventListener('mousemove', archiveDrag);

// 定义按住事件的处理函数
function archiveDragStart(e) {
  if (e.target === archivePopup) {
    initialArchiveX = e.clientX - archiveXOffset;
    initialArchiveY = e.clientY - archiveYOffset;

    archiveIsDragging = true;

    // 防止拖动事件冒泡到文档
    e.stopPropagation();
  } else {
    archiveIsDragging = false;
  }
}

function archiveDragEnd(e) {
  initialArchiveX = currentArchiveX;
  initialArchiveY = currentArchiveY;

  archiveIsDragging = false;
  // 防止拖动事件冒泡到文档
  e.stopPropagation();
}

function archiveDrag(e) {
  if (archiveIsDragging) {
    e.preventDefault();

    currentArchiveX = e.clientX - initialArchiveX;
    currentArchiveY = e.clientY - initialArchiveY;

    archiveXOffset = currentArchiveX;
    archiveYOffset = currentArchiveY;

    setArchiveTranslate(currentArchiveX, currentArchiveY, archivePopup);
  }
}

// 定义用于移动弹窗的函数
function setArchiveTranslate(xPos, yPos, el) {
  el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
}

// 定义用于移动按钮的函数
function setTranslate(xPos, yPos, el) {
    el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
    el.style.transition = "none"; // 防止拖动时产生动画效果
}
// 定义变量用于存储按住后移动的状态
let saveIsDragging = false;
let initialSaveX;
let initialSaveY;
let currentSaveX;
let currentSaveY;
let saveXOffset = 0;
let saveYOffset = 0;

// 添加按住事件
savePopup.addEventListener('mousedown', saveDragStart);
savePopup.addEventListener('mouseup', saveDragEnd);
document.addEventListener('mousemove', saveDrag);

// 定义按住事件的处理函数
function saveDragStart(e) {
  if (e.target === savePopup) {
    initialSaveX = e.clientX - saveXOffset;
    initialSaveY = e.clientY - saveYOffset;

    saveIsDragging = true;

    // 防止拖动事件冒泡到文档
    e.stopPropagation();
  } else {
    saveIsDragging = false;
  }
}

function saveDragEnd(e) {
  initialSaveX = currentSaveX;
  initialSaveY = currentSaveY;

  saveIsDragging = false;
  // 防止拖动事件冒泡到文档
  e.stopPropagation();
}

function saveDrag(e) {
  if (saveIsDragging) {
    e.preventDefault();

    currentSaveX = e.clientX - initialSaveX;
    currentSaveY = e.clientY - initialSaveY;

    saveXOffset = currentSaveX;
    saveYOffset = currentSaveY;

    setSaveTranslate(currentSaveX, currentSaveY, savePopup);
  }
}

// 定义用于移动弹窗的函数
function setSaveTranslate(xPos, yPos, el) {
  el.style.transform = "translate3d(" + xPos + "px, " + yPos + "px, 0)";
}

floatingButton.addEventListener('click', function() {
    if (floatingDiv.style.display === 'none') {
        // 展开悬浮窗
        floatingDiv.style.display = 'block';
        floatingButton.innerText = '收起/Fold';
        // 移除之前的拖动事件监听器
        document.removeEventListener('mousedown', dragStart);
        document.removeEventListener('mouseup', dragEnd);
        document.removeEventListener('mousemove', drag);
    } else {
        // 收起悬浮窗
        floatingDiv.style.display = 'none';
        floatingButton.innerText = '展开/Unfold';
        // 重新添加拖动事件监听器
        document.addEventListener('mousedown', dragStart);
        document.addEventListener('mouseup', dragEnd);
        document.addEventListener('mousemove', drag);
    }}
    );})();

QingJ © 2025

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