PageSourceSearch

https://johnsmith9982-chuanhuchatgpt.hf.space/file=web_assets/javascript/ChuanhuChat.js?1703171411.0

js johnsmith9982-chuanhuchatgpt.hf.space collected 2026-10-03 10:19:00 UTC 16,228 bytes, 460 lines download raw bytes

1
2// ChuanhuChat core javascript
3
4const MAX_HISTORY_LENGTH = 32;
5
6var key_down_history = [];
7var currentIndex = -1;
8
9var gradioContainer = null;
10var user_input_ta = null;
11var user_input_tb = null;
12var userInfoDiv = null;
13var appTitleDiv = null;
14var chatbotArea = null;
15var chatbot = null;
16var chatbotIndicator = null;
17var uploaderIndicator = null;
18var chatListIndicator = null;
19var chatbotWrap = null;
20var apSwitch = null;
21var messageBotDivs = null;
22var loginUserForm = null;
23var logginUser = null;
24var updateToast = null;
25var sendBtn = null;
26var cancelBtn = null;
27var sliders = null;
28var updateChuanhuBtn = null;
29var statusDisplay = null;
30
31var historySelector = null;
32var chuanhuPopup = null;
33var settingBox = null;
34var trainingBox = null;
35var popupWrapper = null;
36var chuanhuHeader = null;
37var menu = null;
38var toolbox = null;
39// var trainBody = null;
40
41var isInIframe = (window.self !== window.top);
42var currentTime = new Date().getTime();
43
44let windowWidth = window.innerWidth; // 初始窗口宽度
45
46function addInit() {
47    var needInit = {chatbotIndicator, uploaderIndicator};
48
49    chatbotIndicator = gradioApp().querySelector('#chuanhu-chatbot > div.wrap');
50    uploaderIndicator = gradioApp().querySelector('#upload-index-file > div.wrap');
51    chatListIndicator = gradioApp().querySelector('#history-select-dropdown > div.wrap');
52
53    for (let elem in needInit) {
54        if (needInit[elem] == null) {
55            // addInited = false;
56            return false;
57        }
58    }
59
60    chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true });
61    chatListObserver.observe(chatListIndicator, { attributes: true });
62    setUploader();
63
64    return true;
65}
66
67function initialize() {
68    gradioObserver.observe(gradioApp(), { childList: true, subtree: true });
69
70    loginUserForm = gradioApp().querySelector(".gradio-container > .main > .wrap > .panel > .form")
71    gradioContainer = gradioApp().querySelector(".gradio-container");
72    user_input_tb = gradioApp().getElementById('user-input-tb');
73    userInfoDiv = gradioApp().getElementById("user-info");
74    appTitleDiv = gradioApp().getElementById("app-title");
75    chatbotArea = gradioApp().querySelector('#chatbot-area');
76    chatbot = gradioApp().querySelector('#chuanhu-chatbot');
77    chatbotWrap = gradioApp().querySelector('#chuanhu-chatbot > .wrapper > .wrap');
78    apSwitch = gradioApp().querySelector('.apSwitch input[type="checkbox"]');
79    updateToast = gradioApp().querySelector("#toast-update");
80    sendBtn = gradioApp().getElementById("submit-btn");
81    cancelBtn = gradioApp().getElementById("cancel-btn");
82    sliders = gradioApp().querySelectorAll('input[type="range"]');
83    updateChuanhuBtn = gradioApp().getElementById("update-chuanhu-btn");
84    statusDisplay = gradioApp().querySelector('#status-display');
85
86    historySelector = gradioApp().querySelector('#history-select-dropdown');
87    chuanhuPopup = gradioApp().querySelector('#chuanhu-popup');
88    settingBox = gradioApp().querySelector('#chuanhu-setting');
89    trainingBox = gradioApp().querySelector('#chuanhu-training');
90    popupWrapper = gradioApp().querySelector('#popup-wrapper');
91    chuanhuHeader = gradioApp().querySelector('#chuanhu-header');
92    menu = gradioApp().querySelector('#menu-area');
93    toolbox = gradioApp().querySelector('#toolbox-area');
94    // trainBody = gradioApp().querySelector('#train-body');
95
96    // if (loginUserForm) {
97    // localStorage.setItem("userLogged", true);
98    // userLogged = true;
99    // }
100
101    adjustDarkMode();
102    adjustSide();
103    setChatList();
104    setChatListHeader();
105    setLoclize();
106    selectHistory();
107    // setChatbotHeight();
108    setPopupBoxPosition();
109    setSlider();
110    setCheckboxes();
111    checkModel();
112
113    settingBox.classList.add('hideBox');
114    trainingBox.classList.add('hideBox');
115
116    if (!historyLoaded) loadHistoryHtml();
117    if (!usernameGotten) getUserInfo();
118
119    setUpdater();
120
121    setChatbotScroll();
122    setTimeout(showOrHideUserInfo(), 2000);
123
124    // setHistroyPanel();
125    // trainBody.classList.add('hide-body');
126
127
128
129    return true;
130}
131
132function gradioApp() {
133    const elems = document.getElementsByTagName('gradio-app');
134    const elem = elems.length == 0 ? document : elems[0];
135
136    if (elem !== document) {
137        elem.getElementById = function(id) {
138            return document.getElementById(id);
139        };
140    }
141    return elem.shadowRoot ? elem.shadowRoot : elem;
142}
143
144function showConfirmationDialog(a, file, c) {
145    if (file != "") {
146        var result = confirm(i18n(deleteConfirm_i18n_pref) + file + i18n(deleteConfirm_i18n_suff));
147        if (result) {
148            return [a, file, c];
149        }
150    }
151    return [a, "CANCELED", c];
152}
153
154function selectHistory() {
155    user_input_ta = user_input_tb.querySelector("textarea");
156    if (user_input_ta) {
157        disableSendBtn();
158        // 在 textarea 上监听 keydown 事件
159        user_input_ta.addEventListener("keydown", function (event) {
160            var value = user_input_ta.value.trim();
161            // 判断按下的是否为方向键
162            if (event.code === 'ArrowUp' || event.code === 'ArrowDown') {
163                // 如果按下的是方向键,且输入框中有内容,且历史记录中没有该内容,则不执行操作
164                if (value && key_down_history.indexOf(value) === -1)
165                    return;
166                // 对于需要响应的动作,阻止默认行为。
167                event.preventDefault();
168                var length = key_down_history.length;
169                if (length === 0) {
170                    currentIndex = -1; // 如果历史记录为空,直接将当前选中的记录重置
171                    return;
172                }
173                if (currentIndex === -1) {
174                    currentIndex = length;
175                }
176                if (event.code === 'ArrowUp' && currentIndex > 0) {
177                    currentIndex--;
178                    user_input_ta.value = key_down_history[currentIndex];
179                } else if (event.code === 'ArrowDown' && currentIndex < length - 1) {
180                    currentIndex++;
181                    user_input_ta.value = key_down_history[currentIndex];
182                }
183                user_input_ta.selectionStart = user_input_ta.value.length;
184                user_input_ta.selectionEnd = user_input_ta.value.length;
185                const input_event = new InputEvent("input", { bubbles: true, cancelable: true });
186                user_input_ta.dispatchEvent(input_event);
187            } else if (event.code === "Enter") {
188                if (value) {
189                    currentIndex = -1;
190                    if (key_down_history.indexOf(value) === -1) {
191                        key_down_history.push(value);
192                        if (key_down_history.length > MAX_HISTORY_LENGTH) {
193                            key_down_history.shift();
194                        }
195                    }
196                }
197            }
198        });
199    }
200}
201
202function disableSendBtn() {
203    sendBtn.disabled = user_input_ta.value.trim() === '';
204    user_input_ta.addEventListener('input', () => {
205        sendBtn.disabled = user_input_ta.value.trim() === '';
206    });
207}
208
209function checkModel() {
210    const model = gradioApp().querySelector('#model-select-dropdown input');
211    var modelValue = model.value;
212    checkGPT();
213    checkXMChat();
214    function checkGPT() {
215        modelValue = model.value;
216        if (modelValue.toLowerCase().includes('gpt')) {
217            gradioApp().querySelector('#header-btn-groups').classList.add('is-gpt');
218        } else {
219            gradioApp().querySelector('#header-btn-groups').classList.remove('is-gpt');
220        }
221        // console.log('gpt model checked')
222    }
223    function checkXMChat() {
224        modelValue = model.value;
225        if (modelValue.includes('xmchat')) {
226            chatbotArea.classList.add('is-xmchat');
227        } else {
228            chatbotArea.classList.remove('is-xmchat');
229        }
230    }
231
232    model.addEventListener('blur', ()=>{
233        setTimeout(()=>{
234            checkGPT();
235            checkXMChat();
236        }, 100);
237    });
238}
239
240function toggleDarkMode(isEnabled) {
241    if (isEnabled) {
242        document.body.classList.add("dark");
243        document.querySelector('meta[name="theme-color"]').setAttribute('content', '#171717');
244        document.body.style.setProperty("background-color", "var(--neutral-950)", "important");
245    } else {
246        document.body.classList.remove("dark");
247        document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff');
248        document.body.style.backgroundColor = "";
249    }
250}
251function adjustDarkMode() {
252    const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)");
253    apSwitch.checked = darkModeQuery.matches;
254    toggleDarkMode(darkModeQuery.matches);
255    darkModeQuery.addEventListener("change", (e) => {
256        apSwitch.checked = e.matches;
257        toggleDarkMode(e.matches);
258    });
259    apSwitch.addEventListener("change", (e) => {
260        toggleDarkMode(e.target.checked);
261    });
262}
263function btnToggleDarkMode() {
264    apSwitch.checked = !apSwitch.checked;
265    toggleDarkMode(apSwitch.checked);
266}
267
268function setScrollShadow() {
269    const toolboxScroll = toolbox.querySelector('#toolbox-area > .gradio-box > .gradio-tabs > div.tab-nav');
270    const toolboxTabs = toolboxScroll.querySelectorAll('button');
271    let toolboxScrollWidth = 0;
272    toolboxTabs.forEach((tab) => {
273        toolboxScrollWidth += tab.offsetWidth; // 获取按钮宽度并累加
274    });
275    function adjustScrollShadow() {
276        if (toolboxScroll.scrollLeft > 0) {
277            toolboxScroll.classList.add('scroll-shadow-left');
278        } else {
279            toolboxScroll.classList.remove('scroll-shadow-left');
280        }
281
282        if (toolboxScroll.scrollLeft + toolboxScroll.clientWidth < toolboxScrollWidth) {
283            toolboxScroll.classList.add('scroll-shadow-right');
284        } else {
285            toolboxScroll.classList.remove('scroll-shadow-right');
286        }
287    }
288    toolboxScroll.addEventListener('scroll', () => {
289        adjustScrollShadow();
290    });
291    // no, I failed to make shadow appear on the top layer...
292}
293
294function setPopupBoxPosition() {
295    const screenWidth = window.innerWidth;
296    const screenHeight = window.innerHeight;
297    popupWrapper.style.height = `${screenHeight}px`;
298    popupWrapper.style.width = `${screenWidth}px`;
299    // const popupBoxWidth = 680;
300    // const popupBoxHeight = 400;
301    // chuanhuPopup.style.left = `${(screenWidth - popupBoxWidth) / 2}px`;
302    // chuanhuPopup.style.top = `${(screenHeight - popupBoxHeight) / 2}px`;
303}
304
305function updateVH() {
306    const vh = window.innerHeight * 0.01;
307    document.documentElement.style.setProperty('--vh', `${vh}px`);
308}
309
310function setChatbotHeight() {
311    return;
312    const screenWidth = window.innerWidth;
313    const statusDisplay = document.querySelector('#status-display');
314    const statusDisplayHeight = statusDisplay ? statusDisplay.offsetHeight : 0;
315    const vh = window.innerHeight * 0.01;
316    document.documentElement.style.setProperty('--vh', `${vh}px`);
317    if (isInIframe) {
318        chatbot.style.height = `700px`;
319        chatbotWrap.style.maxHeight = `calc(700px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`
320    } else {
321        if (screenWidth <= 320) {
322            chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px)`;
323            chatbotWrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
324        } else if (screenWidth <= 499) {
325            chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px)`;
326            chatbotWrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
327        } else {
328            chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px)`;
329            chatbotWrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`;
330        }
331    }
332}
333function setChatbotScroll() {
334    var scrollHeight = chatbotWrap.scrollHeight;
335    chatbotWrap.scrollTo(0,scrollHeight)
336}
337
338function clearChatbot(a, b) {
339    clearHistoryHtml();
340    // clearMessageRows();
341    return [a, b]
342}
343
344function chatbotContentChanged(attempt = 1, force = false) {
345    for (var i = 0; i < attempt; i++) {
346        setTimeout(() => {
347            // clearMessageRows();
348            saveHistoryHtml();
349            disableSendBtn();
350
351            gradioApp().querySelectorAll('#chuanhu-chatbot .message-wrap .message.bot').forEach(addChuanhuButton);
352
353            if (chatbotIndicator.classList.contains('hide')) { // generation finished
354                setLatestMessage();
355                setChatList();
356            }
357
358            if (!chatbotIndicator.classList.contains('translucent')) { // message deleted
359                var checkLatestAdded = setInterval(() => {
360                    var latestMessageNow = gradioApp().querySelector('#chuanhu-chatbot > .wrapper > .wrap > .message-wrap .message.bot.latest');
361                    if (latestMessageNow && latestMessageNow.querySelector('.message-btn-row')) {
362                        clearInterval(checkLatestAdded);
363                    } else {
364                        setLatestMessage();
365                    }
366                }, 200);
367            }
368
369
370        }, i === 0 ? 0 : 200);
371    }
372    // 理论上是不需要多次尝试执行的,可惜gradio的bug导致message可能没有渲染完毕,所以尝试500ms后再次执行
373}
374
375var chatbotObserver = new MutationObserver(() => {
376    chatbotContentChanged(1);
377    if (chatbotIndicator.classList.contains('hide')) {
378        // setLatestMessage();
379        chatbotContentChanged(2);
380    }
381    if (!chatbotIndicator.classList.contains('translucent')) {
382        chatbotContentChanged(2);
383    }
384
385});
386
387var chatListObserver = new MutationObserver(() => {
388    setChatList();
389});
390
391// 监视页面内部 DOM 变动
392var gradioObserver = new MutationObserver(function (mutations) {
393    for (var i = 0; i < mutations.length; i++) {
394        if (mutations[i].addedNodes.length) {
395            if (addInit()) {
396                gradioObserver.disconnect();
397                return;
398            }
399        }
400    }
401});
402
403// 监视页面变化
404window.addEventListener("DOMContentLoaded", function () {
405    // const ga = document.getElementsByTagName("gradio-app");
406    updateVH();
407    windowWidth = window.innerWidth;
408    gradioApp().addEventListener("render", initialize);
409    isInIframe = (window.self !== window.top);
410    historyLoaded = false;
411});
412window.addEventListener('resize', ()=>{
413    // setChatbotHeight();
414    updateVH();
415    windowWidth = window.innerWidth;
416    setPopupBoxPosition();
417    adjustSide();
418});
419window.addEventListener('orientationchange', (event) => {
420    updateVH();
421    windowWidth = window.innerWidth;
422    setPopupBoxPosition();
423    adjustSide();
424});
425window.addEventListener('scroll', ()=>{setPopupBoxPosition();});
426window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode);
427
428// console suprise
429var styleTitle1 = `
430font-size: 16px;
431font-family: ui-monospace, monospace;
432color: #06AE56;
433`
434var styleDesc1 = `
435font-size: 12px;
436font-family: ui-monospace, monospace;
437`
438function makeML(str) {
439    let l = new String(str)
440    l = l.substring(l.indexOf("/*") + 3, l.lastIndexOf("*/"))
441    return l
442}
443let ChuanhuInfo = function () {
444    /*
445   ________                      __             ________          __
446  / ____/ /_  __  ______ _____  / /_  __  __   / ____/ /_  ____ _/ /_
447 / /   / __ \/ / / / __ `/ __ \/ __ \/ / / /  / /   / __ \/ __ `/ __/
448/ /___/ / / / /_/ / /_/ / / / / / / / /_/ /  / /___/ / / / /_/ / /_
449\____/_/ /_/\__,_/\__,_/_/ /_/_/ /_/\__,_/   \____/_/ /_/\__,_/\__/
450
451   川虎Chat (Chuanhu Chat) - GUI for ChatGPT API and many LLMs
452 */
453}
454let description = `
455© 2023 Chuanhu, MZhao, Keldos
456GitHub repository: [https://github.com/GaiZhenbiao/ChuanhuChatGPT]\n
457Enjoy our project!\n
458`
459console.log(`%c${makeML(ChuanhuInfo)}`,styleTitle1);
460console.log(`%c${description}`, styleDesc1);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.