Spaces:
Sleeping
Sleeping
| // ChuanhuChat core javascript | |
| const MAX_HISTORY_LENGTH = 32; | |
| var key_down_history = []; | |
| var currentIndex = -1; | |
| var gradioContainer = null; | |
| var user_input_ta = null; | |
| var user_input_tb = null; | |
| var userInfoDiv = null; | |
| var appTitleDiv = null; | |
| var chatbotArea = null; | |
| var chatbot = null; | |
| var chatbotIndicator = null; | |
| var uploaderIndicator = null; | |
| var chatListIndicator = null; | |
| var chatbotWrap = null; | |
| var apSwitch = null; | |
| var messageBotDivs = null; | |
| var loginUserForm = null; | |
| var logginUser = null; | |
| var updateToast = null; | |
| var sendBtn = null; | |
| var cancelBtn = null; | |
| var sliders = null; | |
| var updateChuanhuBtn = null; | |
| var statusDisplay = null; | |
| var historySelector = null; | |
| var chuanhuPopup = null; | |
| var settingBox = null; | |
| var trainingBox = null; | |
| var popupWrapper = null; | |
| var chuanhuHeader = null; | |
| var menu = null; | |
| var toolbox = null; | |
| // var trainBody = null; | |
| var isInIframe = (window.self !== window.top); | |
| var currentTime = new Date().getTime(); | |
| let windowWidth = window.innerWidth; // 初始窗口宽度 | |
| function addInit() { | |
| var needInit = {chatbotIndicator, uploaderIndicator}; | |
| chatbotIndicator = gradioApp().querySelector('#chuanhu-chatbot > div.wrap'); | |
| uploaderIndicator = gradioApp().querySelector('#upload-index-file > div.wrap'); | |
| chatListIndicator = gradioApp().querySelector('#history-select-dropdown > div.wrap'); | |
| for (let elem in needInit) { | |
| if (needInit[elem] == null) { | |
| // addInited = false; | |
| return false; | |
| } | |
| } | |
| chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true }); | |
| chatListObserver.observe(chatListIndicator, { attributes: true }); | |
| setUploader(); | |
| return true; | |
| } | |
| function initialize() { | |
| gradioObserver.observe(gradioApp(), { childList: true, subtree: true }); | |
| loginUserForm = gradioApp().querySelector(".gradio-container > .main > .wrap > .panel > .form") | |
| gradioContainer = gradioApp().querySelector(".gradio-container"); | |
| user_input_tb = gradioApp().getElementById('user-input-tb'); | |
| userInfoDiv = gradioApp().getElementById("user-info"); | |
| appTitleDiv = gradioApp().getElementById("app-title"); | |
| chatbotArea = gradioApp().querySelector('#chatbot-area'); | |
| chatbot = gradioApp().querySelector('#chuanhu-chatbot'); | |
| chatbotWrap = gradioApp().querySelector('#chuanhu-chatbot > .wrapper > .wrap'); | |
| apSwitch = gradioApp().querySelector('.apSwitch input[type="checkbox"]'); | |
| updateToast = gradioApp().querySelector("#toast-update"); | |
| sendBtn = gradioApp().getElementById("submit-btn"); | |
| cancelBtn = gradioApp().getElementById("cancel-btn"); | |
| sliders = gradioApp().querySelectorAll('input[type="range"]'); | |
| updateChuanhuBtn = gradioApp().getElementById("update-chuanhu-btn"); | |
| statusDisplay = gradioApp().querySelector('#status-display'); | |
| historySelector = gradioApp().querySelector('#history-select-dropdown'); | |
| chuanhuPopup = gradioApp().querySelector('#chuanhu-popup'); | |
| settingBox = gradioApp().querySelector('#chuanhu-setting'); | |
| trainingBox = gradioApp().querySelector('#chuanhu-training'); | |
| popupWrapper = gradioApp().querySelector('#popup-wrapper'); | |
| chuanhuHeader = gradioApp().querySelector('#chuanhu-header'); | |
| menu = gradioApp().querySelector('#menu-area'); | |
| toolbox = gradioApp().querySelector('#toolbox-area'); | |
| // trainBody = gradioApp().querySelector('#train-body'); | |
| // if (loginUserForm) { | |
| // localStorage.setItem("userLogged", true); | |
| // userLogged = true; | |
| // } | |
| adjustDarkMode(); | |
| adjustSide(); | |
| setChatList(); | |
| setChatListHeader(); | |
| setLoclize(); | |
| selectHistory(); | |
| // setChatbotHeight(); | |
| setPopupBoxPosition(); | |
| setSlider(); | |
| setCheckboxes(); | |
| checkModel(); | |
| settingBox.classList.add('hideBox'); | |
| trainingBox.classList.add('hideBox'); | |
| if (!historyLoaded) loadHistoryHtml(); | |
| if (!usernameGotten) getUserInfo(); | |
| setUpdater(); | |
| setChatbotScroll(); | |
| setTimeout(showOrHideUserInfo(), 2000); | |
| // setHistroyPanel(); | |
| // trainBody.classList.add('hide-body'); | |
| return true; | |
| } | |
| function gradioApp() { | |
| const elems = document.getElementsByTagName('gradio-app'); | |
| const elem = elems.length == 0 ? document : elems[0]; | |
| if (elem !== document) { | |
| elem.getElementById = function(id) { | |
| return document.getElementById(id); | |
| }; | |
| } | |
| return elem.shadowRoot ? elem.shadowRoot : elem; | |
| } | |
| function showConfirmationDialog(a, file, c) { | |
| if (file != "") { | |
| var result = confirm(i18n(deleteConfirm_i18n_pref) + file + i18n(deleteConfirm_i18n_suff)); | |
| if (result) { | |
| return [a, file, c]; | |
| } | |
| } | |
| return [a, "CANCELED", c]; | |
| } | |
| function selectHistory() { | |
| user_input_ta = user_input_tb.querySelector("textarea"); | |
| if (user_input_ta) { | |
| disableSendBtn(); | |
| // 在 textarea 上监听 keydown 事件 | |
| user_input_ta.addEventListener("keydown", function (event) { | |
| var value = user_input_ta.value.trim(); | |
| // 判断按下的是否为方向键 | |
| if (event.code === 'ArrowUp' || event.code === 'ArrowDown') { | |
| // 如果按下的是方向键,且输入框中有内容,且历史记录中没有该内容,则不执行操作 | |
| if (value && key_down_history.indexOf(value) === -1) | |
| return; | |
| // 对于需要响应的动作,阻止默认行为。 | |
| event.preventDefault(); | |
| var length = key_down_history.length; | |
| if (length === 0) { | |
| currentIndex = -1; // 如果历史记录为空,直接将当前选中的记录重置 | |
| return; | |
| } | |
| if (currentIndex === -1) { | |
| currentIndex = length; | |
| } | |
| if (event.code === 'ArrowUp' && currentIndex > 0) { | |
| currentIndex--; | |
| user_input_ta.value = key_down_history[currentIndex]; | |
| } else if (event.code === 'ArrowDown' && currentIndex < length - 1) { | |
| currentIndex++; | |
| user_input_ta.value = key_down_history[currentIndex]; | |
| } | |
| user_input_ta.selectionStart = user_input_ta.value.length; | |
| user_input_ta.selectionEnd = user_input_ta.value.length; | |
| const input_event = new InputEvent("input", { bubbles: true, cancelable: true }); | |
| user_input_ta.dispatchEvent(input_event); | |
| } else if (event.code === "Enter") { | |
| if (value) { | |
| currentIndex = -1; | |
| if (key_down_history.indexOf(value) === -1) { | |
| key_down_history.push(value); | |
| if (key_down_history.length > MAX_HISTORY_LENGTH) { | |
| key_down_history.shift(); | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| } | |
| } | |
| function disableSendBtn() { | |
| sendBtn.disabled = user_input_ta.value.trim() === ''; | |
| user_input_ta.addEventListener('input', () => { | |
| sendBtn.disabled = user_input_ta.value.trim() === ''; | |
| }); | |
| } | |
| function checkModel() { | |
| const model = gradioApp().querySelector('#model-select-dropdown input'); | |
| var modelValue = model.value; | |
| checkGPT(); | |
| checkXMChat(); | |
| function checkGPT() { | |
| modelValue = model.value; | |
| if (modelValue.toLowerCase().includes('gpt')) { | |
| gradioApp().querySelector('#header-btn-groups').classList.add('is-gpt'); | |
| } else { | |
| gradioApp().querySelector('#header-btn-groups').classList.remove('is-gpt'); | |
| } | |
| // console.log('gpt model checked') | |
| } | |
| function checkXMChat() { | |
| modelValue = model.value; | |
| if (modelValue.includes('xmchat')) { | |
| chatbotArea.classList.add('is-xmchat'); | |
| } else { | |
| chatbotArea.classList.remove('is-xmchat'); | |
| } | |
| } | |
| model.addEventListener('blur', ()=>{ | |
| setTimeout(()=>{ | |
| checkGPT(); | |
| checkXMChat(); | |
| }, 100); | |
| }); | |
| } | |
| function toggleDarkMode(isEnabled) { | |
| if (isEnabled) { | |
| document.body.classList.add("dark"); | |
| document.querySelector('meta[name="theme-color"]').setAttribute('content', '#171717'); | |
| document.body.style.setProperty("background-color", "var(--neutral-950)", "important"); | |
| } else { | |
| document.body.classList.remove("dark"); | |
| document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff'); | |
| document.body.style.backgroundColor = ""; | |
| } | |
| } | |
| function adjustDarkMode() { | |
| const darkModeQuery = window.matchMedia("(prefers-color-scheme: dark)"); | |
| apSwitch.checked = darkModeQuery.matches; | |
| toggleDarkMode(darkModeQuery.matches); | |
| darkModeQuery.addEventListener("change", (e) => { | |
| apSwitch.checked = e.matches; | |
| toggleDarkMode(e.matches); | |
| }); | |
| apSwitch.addEventListener("change", (e) => { | |
| toggleDarkMode(e.target.checked); | |
| }); | |
| } | |
| function btnToggleDarkMode() { | |
| apSwitch.checked = !apSwitch.checked; | |
| toggleDarkMode(apSwitch.checked); | |
| } | |
| function setScrollShadow() { | |
| const toolboxScroll = toolbox.querySelector('#toolbox-area > .gradio-box > .gradio-tabs > div.tab-nav'); | |
| const toolboxTabs = toolboxScroll.querySelectorAll('button'); | |
| let toolboxScrollWidth = 0; | |
| toolboxTabs.forEach((tab) => { | |
| toolboxScrollWidth += tab.offsetWidth; // 获取按钮宽度并累加 | |
| }); | |
| function adjustScrollShadow() { | |
| if (toolboxScroll.scrollLeft > 0) { | |
| toolboxScroll.classList.add('scroll-shadow-left'); | |
| } else { | |
| toolboxScroll.classList.remove('scroll-shadow-left'); | |
| } | |
| if (toolboxScroll.scrollLeft + toolboxScroll.clientWidth < toolboxScrollWidth) { | |
| toolboxScroll.classList.add('scroll-shadow-right'); | |
| } else { | |
| toolboxScroll.classList.remove('scroll-shadow-right'); | |
| } | |
| } | |
| toolboxScroll.addEventListener('scroll', () => { | |
| adjustScrollShadow(); | |
| }); | |
| // no, I failed to make shadow appear on the top layer... | |
| } | |
| function setPopupBoxPosition() { | |
| const screenWidth = window.innerWidth; | |
| const screenHeight = window.innerHeight; | |
| popupWrapper.style.height = `${screenHeight}px`; | |
| popupWrapper.style.width = `${screenWidth}px`; | |
| // const popupBoxWidth = 680; | |
| // const popupBoxHeight = 400; | |
| // chuanhuPopup.style.left = `${(screenWidth - popupBoxWidth) / 2}px`; | |
| // chuanhuPopup.style.top = `${(screenHeight - popupBoxHeight) / 2}px`; | |
| } | |
| function updateVH() { | |
| const vh = window.innerHeight * 0.01; | |
| document.documentElement.style.setProperty('--vh', `${vh}px`); | |
| } | |
| function setChatbotHeight() { | |
| return; | |
| const screenWidth = window.innerWidth; | |
| const statusDisplay = document.querySelector('#status-display'); | |
| const statusDisplayHeight = statusDisplay ? statusDisplay.offsetHeight : 0; | |
| const vh = window.innerHeight * 0.01; | |
| document.documentElement.style.setProperty('--vh', `${vh}px`); | |
| if (isInIframe) { | |
| chatbot.style.height = `700px`; | |
| chatbotWrap.style.maxHeight = `calc(700px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))` | |
| } else { | |
| if (screenWidth <= 320) { | |
| chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px)`; | |
| chatbotWrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 150}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`; | |
| } else if (screenWidth <= 499) { | |
| chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px)`; | |
| chatbotWrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 100}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`; | |
| } else { | |
| chatbot.style.height = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px)`; | |
| chatbotWrap.style.maxHeight = `calc(var(--vh, 1vh) * 100 - ${statusDisplayHeight + 160}px - var(--line-sm) * 1rem - 2 * var(--block-label-margin))`; | |
| } | |
| } | |
| } | |
| function setChatbotScroll() { | |
| var scrollHeight = chatbotWrap.scrollHeight; | |
| chatbotWrap.scrollTo(0,scrollHeight) | |
| } | |
| function clearChatbot(a, b) { | |
| clearHistoryHtml(); | |
| // clearMessageRows(); | |
| return [a, b] | |
| } | |
| function chatbotContentChanged(attempt = 1, force = false) { | |
| for (var i = 0; i < attempt; i++) { | |
| setTimeout(() => { | |
| // clearMessageRows(); | |
| saveHistoryHtml(); | |
| disableSendBtn(); | |
| gradioApp().querySelectorAll('#chuanhu-chatbot .message-wrap .message.bot').forEach(addChuanhuButton); | |
| if (chatbotIndicator.classList.contains('hide')) { // generation finished | |
| setLatestMessage(); | |
| setChatList(); | |
| } | |
| if (!chatbotIndicator.classList.contains('translucent')) { // message deleted | |
| var checkLatestAdded = setInterval(() => { | |
| var latestMessageNow = gradioApp().querySelector('#chuanhu-chatbot > .wrapper > .wrap > .message-wrap .message.bot.latest'); | |
| if (latestMessageNow && latestMessageNow.querySelector('.message-btn-row')) { | |
| clearInterval(checkLatestAdded); | |
| } else { | |
| setLatestMessage(); | |
| } | |
| }, 200); | |
| } | |
| }, i === 0 ? 0 : 200); | |
| } | |
| // 理论上是不需要多次尝试执行的,可惜gradio的bug导致message可能没有渲染完毕,所以尝试500ms后再次执行 | |
| } | |
| var chatbotObserver = new MutationObserver(() => { | |
| chatbotContentChanged(1); | |
| if (chatbotIndicator.classList.contains('hide')) { | |
| // setLatestMessage(); | |
| chatbotContentChanged(2); | |
| } | |
| if (!chatbotIndicator.classList.contains('translucent')) { | |
| chatbotContentChanged(2); | |
| } | |
| }); | |
| var chatListObserver = new MutationObserver(() => { | |
| setChatList(); | |
| }); | |
| // 监视页面内部 DOM 变动 | |
| var gradioObserver = new MutationObserver(function (mutations) { | |
| for (var i = 0; i < mutations.length; i++) { | |
| if (mutations[i].addedNodes.length) { | |
| if (addInit()) { | |
| gradioObserver.disconnect(); | |
| return; | |
| } | |
| } | |
| } | |
| }); | |
| // 监视页面变化 | |
| window.addEventListener("DOMContentLoaded", function () { | |
| // const ga = document.getElementsByTagName("gradio-app"); | |
| updateVH(); | |
| windowWidth = window.innerWidth; | |
| gradioApp().addEventListener("render", initialize); | |
| isInIframe = (window.self !== window.top); | |
| historyLoaded = false; | |
| }); | |
| window.addEventListener('resize', ()=>{ | |
| // setChatbotHeight(); | |
| updateVH(); | |
| windowWidth = window.innerWidth; | |
| setPopupBoxPosition(); | |
| adjustSide(); | |
| }); | |
| window.addEventListener('orientationchange', (event) => { | |
| updateVH(); | |
| windowWidth = window.innerWidth; | |
| setPopupBoxPosition(); | |
| adjustSide(); | |
| }); | |
| window.addEventListener('scroll', ()=>{setPopupBoxPosition();}); | |
| window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode); | |
| // console suprise | |
| var styleTitle1 = ` | |
| font-size: 16px; | |
| font-family: ui-monospace, monospace; | |
| color: #06AE56; | |
| ` | |
| var styleDesc1 = ` | |
| font-size: 12px; | |
| font-family: ui-monospace, monospace; | |
| ` | |
| function makeML(str) { | |
| let l = new String(str) | |
| l = l.substring(l.indexOf("/*") + 3, l.lastIndexOf("*/")) | |
| return l | |
| } | |
| let ChuanhuInfo = function () { | |
| /* | |
| ________ __ ________ __ | |
| / ____/ /_ __ ______ _____ / /_ __ __ / ____/ /_ ____ _/ /_ | |
| / / / __ \/ / / / __ `/ __ \/ __ \/ / / / / / / __ \/ __ `/ __/ | |
| / /___/ / / / /_/ / /_/ / / / / / / / /_/ / / /___/ / / / /_/ / /_ | |
| \____/_/ /_/\__,_/\__,_/_/ /_/_/ /_/\__,_/ \____/_/ /_/\__,_/\__/ | |
| 川虎Chat (Chuanhu Chat) - GUI for ChatGPT API and many LLMs | |
| */ | |
| } | |
| let description = ` | |
| © 2023 Chuanhu, MZhao, Keldos | |
| GitHub repository: [https://github.com/GaiZhenbiao/ChuanhuChatGPT]\n | |
| Enjoy our project!\n | |
| ` | |
| console.log(`%c${makeML(ChuanhuInfo)}`,styleTitle1); | |
| console.log(`%c${description}`, styleDesc1); | |