// ChuanhuChat core javascript
const MAX_HISTORY_LENGTH = 32;
var key_down_history = [];
var currentIndex = -1;
var user_input_ta;
var gradioContainer = null;
var user_input_ta = null;
var user_input_tb = null;
var userInfoDiv = null;
var appTitleDiv = null;
var chatbot = 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 isInIframe = (window.self !== window.top);
var currentTime = new Date().getTime();
// gradio 页面加载好了么??? 我能动你的元素了么??
function gradioLoaded(mutations) {
for (var i = 0; i < mutations.length; i++) {
if (mutations[i].addedNodes.length) {
loginUserForm = document.querySelector(".gradio-container > .main > .wrap > .panel > .form")
gradioContainer = document.querySelector(".gradio-container");
user_input_tb = document.getElementById('user-input-tb');
userInfoDiv = document.getElementById("user-info");
appTitleDiv = document.getElementById("app-title");
chatbot = document.querySelector('#chuanhu-chatbot');
chatbotWrap = document.querySelector('#chuanhu-chatbot > .wrapper > .wrap');
apSwitch = document.querySelector('.apSwitch input[type="checkbox"]');
updateToast = document.querySelector("#toast-update");
sendBtn = document.getElementById("submit-btn");
cancelBtn = document.getElementById("cancel-btn");
sliders = document.querySelectorAll('input[type="range"]');
updateChuanhuBtn = document.getElementById("update-chuanhu-btn");
statusDisplay = document.querySelector('#status-display');
if (loginUserForm) {
localStorage.setItem("userLogged", true);
userLogged = true;
}
if (gradioContainer && apSwitch) { // gradioCainter 加载出来了没?
adjustDarkMode();
}
if (user_input_tb) { // user_input_tb 加载出来了没?
selectHistory();
}
if (userInfoDiv && appTitleDiv) { // userInfoDiv 和 appTitleDiv 加载出来了没?
if (!usernameGotten) {
getUserInfo();
}
setTimeout(showOrHideUserInfo(), 2000);
}
if (chatbot) { // chatbot 加载出来了没?
setChatbotHeight();
}
if (chatbotWrap) {
if (!historyLoaded) {
loadHistoryHtml();
}
setChatbotScroll();
mObserver.observe(chatbotWrap, { attributes: true, childList: true, subtree: true, characterData: true});
}
if (statusDisplay) {
// statusObserver.observe(statusDisplay, { childList: true, subtree: true, characterData: true});
}
if (sliders) {
setSlider();
}
if (updateToast) {
const lastCheckTime = localStorage.getItem('lastCheckTime') || 0;
const longTimeNoCheck = currentTime - lastCheckTime > 3 * 24 * 60 * 60 * 1000;
if (longTimeNoCheck && !updateInfoGotten && !isLatestVersion || isLatestVersion && !updateInfoGotten) {
updateLatestVersion();
}
}
if (cancelBtn) {
submitObserver.observe(cancelBtn, { attributes: true, characterData: true});
}
}
}
}
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) {
observer.disconnect(); // 停止监听
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 adjustDarkMode() {
function toggleDarkMode(isEnabled) {
if (isEnabled) {
document.body.classList.add("dark");
document.body.style.setProperty("background-color", "var(--neutral-950)", "important");
} else {
document.body.classList.remove("dark");
document.body.style.backgroundColor = "";
}
}
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 setChatbotHeight() {
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)
}
var submitObserver = new MutationObserver(function (mutationsList) {
document.querySelectorAll('#chuanhu-chatbot .message-wrap .message.bot').forEach(addChuanhuButton);
saveHistoryHtml();
});
// 监视页面内部 DOM 变动
var observer = new MutationObserver(function (mutations) {
gradioLoaded(mutations);
});
// 监视页面变化
window.addEventListener("DOMContentLoaded", function () {
const ga = document.getElementsByTagName("gradio-app");
observer.observe(ga[0], { childList: true, subtree: true });
isInIframe = (window.self !== window.top);
historyLoaded = false;
});
window.addEventListener('resize', setChatbotHeight);
window.addEventListener('scroll', function(){setChatbotHeight(); setUpdateWindowHeight();});
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)
// button svg code
const copyIcon = '';
const copiedIcon = '';
const mdIcon = '';
const rawIcon = '';