Greasy Fork

Greasy Fork is available in English.

大模型多站点

提高效率

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         大模型多站点
// @namespace    http://tampermonkey.net/
// @version      1.1.2
// @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 CACHE_PREFIX = "tool-";
    const LAST_QUESTION = "lastQuestion-";
    const SPLIT_CHAR = ",,,";
    const url = window.location.href;

    let MAIN_SITE = 0;
    let site = 0;

    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=';
            let tmp = url.lastIndexOf(mark) + mark.length;
            return url.substring(tmp);
        }else{
            return subStr;
        }
    }

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

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


    let len = 0;
    let hasChatId = false;

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

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

    }, 1000);

    // 发送端
    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();

            len = getS(CACHE_PREFIX + masterId);
            if(lenNext > len){
                let lastestQ = questions[lenNext - 1].textContent;

                let lastQuestion = getS(LAST_QUESTION + masterId);
                if(!isEmpty(lastQuestion) && lastestQ === lastQuestion){
                    return;
                }
                masterReq(masterId, lastestQ);
                hasChatId = true;
                setS(CACHE_PREFIX + masterId, lenNext);
            }
        }
    };

    function masterReq(masterId, lastestQ){
        let uid = getS(masterId);
        if(isEmpty(uid)){
            uid = guid();
            setS(masterId, uid);
        }

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

        // 其实只有首次发问题才需要如下处理
        let uidJson = getGV(uid);
        if(isEmpty(uidJson)){
            uidJson = {};
            uidJson[site] = masterId;
            console.log("master print uidJson: "+JSON.stringify(uidJson));
            setGV(uid, uidJson);
        }
    }

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

        let msg = getGV("msg");
        if(isEmpty(msg)){
            return;
        }
        let question = msg.question;
        let lastQuestion = getS(LAST_QUESTION + curSlaveId);

        let sameQuestion = !isEmpty(lastQuestion) && question === 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];

            // 清空跳转用的缓存
            setS("questionBeforeJump", "");
            abstractSend(site, cachedQuestion);

            if(isEmpty(curSlaveId)){
                let uidJson = getGV(cachedUid);
                setUid(cachedUid, cachedQuestion, uidJson);
            }else{
                setS(LAST_QUESTION + curSlaveId, 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 = getS(LAST_QUESTION + slaveId);
            if(question === lastQuestionOfComingSlaveId){
                return;
            }
            if(!isEmpty(slaveId)){
                slaveIdFlag = true;
            }
        }

        let curIdFlag = !isEmpty(curSlaveId);
        if(slaveIdFlag){
            if(curIdFlag){
                if(curSlaveId === slaveId){
                    if(!sameQuestion){
                        abstractSend(site, question);
                        setS(LAST_QUESTION + curSlaveId, question);
                    }
                }else{
                    targetUrl = historySites[site] + slaveId;
                }
            }else{
                targetUrl = historySites[site] + slaveId;
            }
        }else{
            if(curIdFlag){
                targetUrl = newSites[site];
            }else{
                abstractSend(site, question);
                setUid(uid, question, uidJson);
            }
        }
        if(!isEmpty(targetUrl)){
            setS("questionBeforeJump", question + SPLIT_CHAR + uid);
            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;
                }
                setS(LAST_QUESTION + chatId, question);

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

                clearInterval(intervalId);
            }
        }, gap);

    }

    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);
        });
    }

    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;
        }
    }


})();