Greasy Fork

大模型多站点

提高效率

当前为 2025-05-31 提交的版本,查看 最新版本

// ==UserScript==
// @name         大模型多站点
// @namespace    http://tampermonkey.net/
// @version      1.1.3
// @description  提高效率
// @author       wz
// @match        https://www.kimi.com/*
// @match        https://chat.deepseek.com/*
// @match        https://www.tongyi.com/*
// @match        https://chatgpt.com/*
// @match        https://www.doubao.com/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @license      GPL-3.0-only
// ==/UserScript==

(function () {
    'use strict';
    console.log("ai script, start");

    const T = "tool-";
    const QUEUE = "tool-queue";
    const LEN = "len";
    const LAST_Q = "lastQ";
    const UID_KEY = "uid";
    const SPLIT_CHAR = ",,,";

    const MAX_QUEUE = 1000;

    let MAIN_SITE = 0;
    let site = 0;
    let url = window.location.href;

    const keywords = {
        "kimi": 0,
        "deepseek": 1,
        "tongyi": 2,
        "chatgpt": 3,
        "doubao": 4
    };
    for (const keyword in keywords) {
        if (url.indexOf(keyword) > -1) {
            site = keywords[keyword];
            break;
        }
    }

    const historySites = {
        0: "https://www.kimi.com/chat/",
        1: "https://chat.deepseek.com/a/chat/s/",
        2: "https://www.tongyi.com/?sessionId=",
        3: "https://chatgpt.com/c/",
        4: "https://www.doubao.com/chat/"
    }
    const newSites = {
        0: "https://www.kimi.com/",
        1: "https://chat.deepseek.com/",
        2: "https://www.tongyi.com/",
        3: "https://chatgpt.com/",
        4: "https://www.doubao.com/chat"
    }

    function getChatId(){
        let url = getUrl();
        let subStr = url.substring(url.lastIndexOf('/') + 1);
        // console.log("subStr: "+subStr);
        if(isEmpty(subStr)){
            return "";
        }
        if(site === 2){
            let mark = 'sessionId=';
            if(url.indexOf(mark) === -1){
                return "";
            }
            let tmp = url.lastIndexOf(mark) + mark.length;
            return url.substring(tmp);
        }else{
            return subStr;
        }
    }

    function getUrl(){
        return window.location.href;
    }


    // 在队列头部添加元素
    function enqueue(element) {
        let queue = JSON.parse(localStorage.getItem(QUEUE) || "[]");
        queue.unshift(element); // 在头部添加元素
        localStorage.setItem("queue", JSON.stringify(queue));
    }

    // 当队列长度超过阈值,删除队尾元素
    function dequeue() {
        let queue = JSON.parse(localStorage.getItem(QUEUE) || "[]");
        let len = queue.length;
        if(len > MAX_QUEUE){
            queue.pop();
            localStorage.setItem(QUEUE, JSON.stringify(queue));
        }
    }

    function getSK(key, jsonKey){
        let json = localStorage.getItem(key);
        if(isEmpty(json)){
            return "";
        }
        json = JSON.parse(json);
        return json[jsonKey];

    }

    function setSK(key, jsonKey, val){
        let json = JSON.parse(localStorage.getItem(key) || "{}");
        json[jsonKey] = val;
        localStorage.setItem(key, JSON.stringify(json));
    }

    function getS(key){
        return localStorage.getItem(key);
    }
    function setS(key, val){
        localStorage.setItem(key, val);
    }
    function setGV(key, value){
        GM_setValue(key, value);
    }
    function getGV(key){
        return GM_getValue(key);
    }


    let hasChatId = false;

    // setInterval(function(){
    //     masterCheckNew();
    //     receiveNew();
    // }, 3000);

    setTimeout(function(){
        setInterval(function(){
            masterCheckNew();
            receiveNew();
        }, 2000);

    }, 100);

    // 发送端
    let masterId = "";
    function masterCheckNew(){

        let questions = [];
        if(site == 0){
            questions = document.getElementsByClassName("user-content");
        }else if(site == 1){
            let scrollable = document.getElementsByClassName("scrollable")[1];
            if(!isEmpty(scrollable)){
                let list = scrollable.firstElementChild.firstElementChild.children
                let elementsArray = Array.from(list);
                questions = elementsArray.filter((item, index) => index % 2 === 0);
            }
        }else if(site == 2){
            questions = document.querySelectorAll('[class^="bubble-"]');
        }else if(site == 4){
            let list = document.querySelectorAll('[data-testid="message_text_content"]');
            let elementsArray = Array.from(list);
            questions = elementsArray.filter((item, index) => index % 2 === 0);
        }

        let lenNext = questions.length;
        if(lenNext > 0){
            masterId = getChatId();

            let len = getSK(T + masterId,"len");
            if(isEmpty(len)){
                len = 0;
            }
            if(lenNext > len){
                let lastestQ = questions[lenNext - 1].textContent;

                let lastQuestion = getSK(T + masterId,LAST_Q);
                if(!isEmpty(lastQuestion) && lastestQ === lastQuestion){
                    return;
                }
                masterReq(masterId, lastestQ);
                hasChatId = true;
                setSK(T + masterId, LEN, lenNext);
            }
        }
    };

    function masterReq(masterId, lastestQ){
        let uid = getSK(T + masterId, UID_KEY);
        if(isEmpty(uid)){
            uid = guid();
            setSK(T + masterId, UID_KEY, uid);
        }

        let message = {
            uid: uid,
            question: lastestQ
        };
        console.log(message);
        setGV("msg", message);
        setSK(T + masterId, LAST_Q, lastestQ);

        let uidJson = getGV(uid);
        // 若json非空,则其中一定有首次提问的主节点的信息;
        // 故json若空则必为首次,只有首次会走如下逻辑
        if(isEmpty(uidJson)){
            uidJson = {};
            uidJson[site] = masterId;
            console.log("master print uidJson: "+JSON.stringify(uidJson));
            setGV(uid, uidJson);

            // 存储管理(删除与添加)
            dequeue();
            enqueue(masterId);
        }
    }

    function receiveNew(){
        let curSlaveId = getChatId();
        if(curSlaveId.length < 12){
            curSlaveId = "";
        }

        let msg = getGV("msg");
        if(isEmpty(msg)){
            return;
        }
        let question = msg.question;
        let lastQuestion = getSK(T + curSlaveId, LAST_Q);

        let sameQuestion = !isEmpty(lastQuestion) && question === lastQuestion;
        console.log(new Date());
        console.log("question: "+question);
        console.log("lastQuestion: "+lastQuestion);
        if(sameQuestion){
            return;
        }

        let questionBeforeJump = getS("questionBeforeJump");

        // 如果是经跳转而来,无需处理主节点信息,直接从缓存取对话内容
        if(!isEmpty(questionBeforeJump)){
            console.log("questionBeforeJump: " + questionBeforeJump);
            let splits = questionBeforeJump.split(SPLIT_CHAR);
            let cachedQuestion = splits[0];
            let cachedUid = splits[1];

            if(!isEmpty(curSlaveId)){
                let cachedSlaveId = splits[2];
                if(curSlaveId !== cachedSlaveId){
                    return;
                }
            }

            // 清空跳转用的缓存
            setS("questionBeforeJump", "");
            console.log("h1 send");
            abstractSend(site, cachedQuestion);

            if(isEmpty(curSlaveId)){
                let uidJson = getGV(cachedUid);
                setUid(cachedUid, cachedQuestion, uidJson);
            }else{
                setSK(T + curSlaveId, LAST_Q, cachedQuestion);
            }
            return;
        }


        let uid = msg.uid;

        // 当前空,且之前chatId有值,则认为是手动打开的页面(若是从节点跟随跳转新页面的情况,前面已经拦截处理了)
        if(isEmpty(curSlaveId)){
            if(hasChatId){
                return;
            }
        }else{
            hasChatId = true;
        }

        let targetUrl = "";
        let slaveIdFlag = false;
        let slaveId = "";
        let uidJson = getGV(uid);
        let lastQuestionOfComingSlaveId = "";
        if(!isEmpty(uidJson)){
            slaveId = uidJson[site];
            lastQuestionOfComingSlaveId = getSK(T + slaveId, LAST_Q);
            if(question === lastQuestionOfComingSlaveId){
                return;
            }
            if(!isEmpty(slaveId)){
                slaveIdFlag = true;
            }
        }

        let curIdFlag = !isEmpty(curSlaveId);
        if(slaveIdFlag){
            if(curIdFlag){
                if(curSlaveId === slaveId){
                    if(!sameQuestion){
                        setSK(T + curSlaveId, LAST_Q, question);
                        console.log("h2 send");
                        abstractSend(site, question);
                    }
                }else{
                    targetUrl = historySites[site] + slaveId;
                }
            }else{
                targetUrl = historySites[site] + slaveId;
            }
        }else{
            if(curIdFlag){
                targetUrl = newSites[site];
            }else{
                console.log("h3 send");
                abstractSend(site, question);
                setUid(uid, question, uidJson);
            }
        }
        if(!isEmpty(targetUrl)){
            setS("questionBeforeJump", question + SPLIT_CHAR + uid + SPLIT_CHAR + slaveId);
            window.location.href = targetUrl;
        }
    }

    function setUid(uid, question, uidJson){
        let intervalId;
        let lastUrl = getUrl();
        let count = 0;
        let gap = 100;

        intervalId = setInterval(function() {
            count ++;
            if(count > 10000 / gap){
                clearInterval(intervalId);
            }
            let currentUrl = getUrl();
            if (currentUrl !== lastUrl) {
                let chatId = getChatId();
                hasChatId = true;

                if(!isEmpty(uidJson)){
                    if(isEmpty(uidJson[site])){
                        uidJson[site] = chatId;
                    }
                }else{
                    uidJson = {};
                    uidJson[site] = chatId;
                }
                setSK(T + chatId, LAST_Q, question);

                console.log("slave print uidJson: "+JSON.stringify(uidJson));
                setGV(uid, uidJson);
                setSK(T + chatId, UID_KEY, uid);

                // 存储管理(删除与添加)
                dequeue();
                enqueue(masterId);

                clearInterval(intervalId);
            }
        }, gap);

    }

    function abstractSend(site, content){
        let intervalId;
        let count = 0;
        let gap = 100;

        intervalId = setInterval(function() {
            count ++;
            if(count > 5000 / gap){
                clearInterval(intervalId);
            }
            let textarea = getTextArea(site);
            if (!isEmpty(textarea)) {
                textarea.focus();
                document.execCommand('insertText', false, content);
                setTimeout(function(){
                    let sendBtn = getBtn(site);
                    sendBtn.click();
                }, 100);
                clearInterval(intervalId);
            }
        }, gap);
    }

	function getTextArea(site){
        if(site == 0){
            return document.getElementsByClassName('chat-input-editor')[0];
        }else if(site === 1){
            return document.getElementById('chat-input');
        }else if([2, 4].includes(site)){
            return document.getElementsByTagName('textarea')[0];
        }else if(site === 3){
            return document.getElementById('prompt-textarea');
        }
	}
	function getBtn(site){
        if(site == 0){
            return document.getElementsByClassName('send-button-container')[0];
        }else if(site === 1){
            var btns = document.querySelectorAll('[role="button"]');
            return btns[btns.length - 1];
        }else if(site === 2){
            return document.querySelectorAll('[class^="operateBtn-"], [class*=" operateBtn-"]')[0];
        }else if(site === 3){
            return document.getElementById('composer-submit-button');
        }else if(site === 4){
            return document.getElementById('flow-end-msg-send');
        }
	}

    function isEmpty(item){
        if(item===null || item===undefined || item.length===0 || item === "null"){
            return true;
        }else{
            return false;
        }
    }

    function guid() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            var r = Math.random() * 16 | 0,
                v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }

})();