update gr

This commit is contained in:
binary-husky
2024-01-23 15:54:09 +08:00
parent eaf27df32a
commit 47289f863d
85 changed files with 5302 additions and 1788 deletions

View File

@@ -94,6 +94,10 @@
background-color: var(--block-background-fill) !important;
}
#cbsc {
background-color: var(--block-background-fill) !important;
}
#interact-panel .form {
border: hidden
}
@@ -111,4 +115,4 @@
border: solid;
border-width: thin;
border-top-width: 0;
}
}

View File

@@ -74,6 +74,7 @@ function toast_up(msg) {
m.style.cssText = "font-size: var(--text-md) !important; color: rgb(255, 255, 255); background-color: rgba(0, 0, 100, 0.6); padding: 10px 15px; margin: 0 0 0 -60px; border-radius: 4px; position: fixed; top: 50%; left: 50%; width: auto; text-align: center;";
document.body.appendChild(m);
}
function toast_down() {
var m = document.getElementById('toast_up');
if (m) {
@@ -81,6 +82,97 @@ function toast_down() {
}
}
function begin_loading_status() {
// Create the loader div and add styling
var loader = document.createElement('div');
loader.id = 'Js_File_Loading';
var C1 = document.createElement('div');
var C2 = document.createElement('div');
// var C3 = document.createElement('span');
// C3.textContent = '上传中...'
// C3.style.position = "fixed";
// C3.style.top = "50%";
// C3.style.left = "50%";
// C3.style.width = "80px";
// C3.style.height = "80px";
// C3.style.margin = "-40px 0 0 -40px";
C1.style.position = "fixed";
C1.style.top = "50%";
C1.style.left = "50%";
C1.style.width = "80px";
C1.style.height = "80px";
C1.style.borderLeft = "12px solid #00f3f300";
C1.style.borderRight = "12px solid #00f3f300";
C1.style.borderTop = "12px solid #82aaff";
C1.style.borderBottom = "12px solid #82aaff"; // Added for effect
C1.style.borderRadius = "50%";
C1.style.margin = "-40px 0 0 -40px";
C1.style.animation = "spinAndPulse 2s linear infinite";
C2.style.position = "fixed";
C2.style.top = "50%";
C2.style.left = "50%";
C2.style.width = "40px";
C2.style.height = "40px";
C2.style.borderLeft = "12px solid #00f3f300";
C2.style.borderRight = "12px solid #00f3f300";
C2.style.borderTop = "12px solid #33c9db";
C2.style.borderBottom = "12px solid #33c9db"; // Added for effect
C2.style.borderRadius = "50%";
C2.style.margin = "-20px 0 0 -20px";
C2.style.animation = "spinAndPulse2 2s linear infinite";
loader.appendChild(C1);
loader.appendChild(C2);
// loader.appendChild(C3);
document.body.appendChild(loader); // Add the loader to the body
// Set the CSS animation keyframes for spin and pulse to be synchronized
var styleSheet = document.createElement('style');
styleSheet.id = 'Js_File_Loading_Style';
styleSheet.textContent = `
@keyframes spinAndPulse {
0% { transform: rotate(0deg) scale(1); }
25% { transform: rotate(90deg) scale(1.1); }
50% { transform: rotate(180deg) scale(1); }
75% { transform: rotate(270deg) scale(0.9); }
100% { transform: rotate(360deg) scale(1); }
}
@keyframes spinAndPulse2 {
0% { transform: rotate(-90deg);}
25% { transform: rotate(-180deg);}
50% { transform: rotate(-270deg);}
75% { transform: rotate(-360deg);}
100% { transform: rotate(-450deg);}
}
`;
document.head.appendChild(styleSheet);
}
function cancel_loading_status() {
// remove the loader from the body
var loadingElement = document.getElementById('Js_File_Loading');
if (loadingElement) {
document.body.removeChild(loadingElement);
}
var loadingStyle = document.getElementById('Js_File_Loading_Style');
if (loadingStyle) {
document.head.removeChild(loadingStyle);
}
// create new listen event
let clearButton = document.querySelectorAll('div[id*="elem_upload"] button[aria-label="Clear"]');
for (let button of clearButton) {
button.addEventListener('click', function () {
setTimeout(function () {
register_upload_event();
}, 50);
});
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 第 2 部分: 复制按钮
@@ -94,8 +186,7 @@ function addCopyButton(botElement) {
const messageBtnColumnElement = botElement.querySelector('.message-btn-row');
if (messageBtnColumnElement) {
// Do something if .message-btn-column exists, for example, remove it
// messageBtnColumnElement.remove();
// if .message-btn-column exists
return;
}
@@ -138,6 +229,33 @@ function addCopyButton(botElement) {
botElement.appendChild(messageBtnColumn);
}
let timeoutID = null;
let lastInvocationTime = 0;
let lastArgs = null;
function do_something_but_not_too_frequently(min_interval, func) {
return function(...args) {
lastArgs = args;
const now = Date.now();
if (!lastInvocationTime || (now - lastInvocationTime) >= min_interval) {
lastInvocationTime = now;
// 现在就执行
setTimeout(() => {
func.apply(this, lastArgs);
}, 0);
} else if (!timeoutID) {
// 等一会执行
timeoutID = setTimeout(() => {
timeoutID = null;
lastInvocationTime = Date.now();
func.apply(this, lastArgs);
}, min_interval - (now - lastInvocationTime));
} else {
// 压根不执行
}
}
}
function chatbotContentChanged(attempt = 1, force = false) {
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
for (var i = 0; i < attempt; i++) {
@@ -145,6 +263,13 @@ function chatbotContentChanged(attempt = 1, force = false) {
gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton);
}, i === 0 ? 0 : 200);
}
const run_mermaid_render = do_something_but_not_too_frequently(1000, function () {
const blocks = document.querySelectorAll(`pre.mermaid, diagram-div`);
if (blocks.length == 0) { return; }
uml("mermaid");
});
run_mermaid_render();
}
@@ -154,7 +279,7 @@ function chatbotContentChanged(attempt = 1, force = false) {
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function chatbotAutoHeight() {
// 自动调整高度
// 自动调整高度:立即
function update_height() {
var { height_target, chatbot_height, chatbot } = get_elements(true);
if (height_target != chatbot_height) {
@@ -163,23 +288,25 @@ function chatbotAutoHeight() {
}
}
// 自动调整高度:缓慢
function update_height_slow() {
var { height_target, chatbot_height, chatbot } = get_elements();
if (height_target != chatbot_height) {
// sign = (height_target - chatbot_height)/Math.abs(height_target - chatbot_height);
// speed = Math.max(Math.abs(height_target - chatbot_height), 1);
new_panel_height = (height_target - chatbot_height) * 0.5 + chatbot_height;
if (Math.abs(new_panel_height - height_target) < 10) {
new_panel_height = height_target;
}
// console.log(chatbot_height, height_target, new_panel_height);
var pixelString = new_panel_height.toString() + 'px';
chatbot.style.maxHeight = pixelString; chatbot.style.height = pixelString;
}
}
monitoring_input_box()
update_height();
setInterval(function () {
update_height_slow()
}, 50); // 每50毫秒执行一次
window.addEventListener('resize', function () { update_height(); });
window.addEventListener('scroll', function () { update_height_slow(); });
setInterval(function () { update_height_slow() }, 50); // 每50毫秒执行一次
}
swapped = false;
@@ -197,8 +324,8 @@ function swap_input_area() {
// Swap the elements
parent.insertBefore(element2, element1);
parent.insertBefore(element1, nextSibling);
if (swapped) {swapped = false;}
else {swapped = true;}
if (swapped) { swapped = false; }
else { swapped = true; }
}
function get_elements(consider_state_panel = false) {
@@ -221,18 +348,18 @@ function get_elements(consider_state_panel = false) {
var height_target = parseInt(height_target);
var chatbot_height = chatbot.style.height;
// 交换输入区位置,使得输入区始终可用
if (!swapped){
if (panel1.top!=0 && panel1.top < 0){ swap_input_area(); }
if (!swapped) {
if (panel1.top != 0 && (panel1.bottom + panel1.top) / 2 < 0) { swap_input_area(); }
}
else if (swapped){
if (panel2.top!=0 && panel2.top > 0){ swap_input_area(); }
else if (swapped) {
if (panel2.top != 0 && panel2.top > 0) { swap_input_area(); }
}
// 调整高度
const err_tor = 5;
if (Math.abs(panel1.left - chatbot.getBoundingClientRect().left) < err_tor){
if (Math.abs(panel1.left - chatbot.getBoundingClientRect().left) < err_tor) {
// 是否处于窄屏模式
height_target = window.innerHeight * 0.6;
}else{
} else {
// 调整高度
const chatbot_height_exceed = 15;
const chatbot_height_exceed_m = 10;
@@ -259,9 +386,46 @@ var elem_upload_float = null;
var elem_input_main = null;
var elem_input_float = null;
var elem_chatbot = null;
var elem_upload_component_float = null;
var elem_upload_component = null;
var exist_file_msg = '⚠️请先删除上传区(左上方)中的历史文件,再尝试上传。'
function add_func_paste(input) {
function locate_upload_elems() {
elem_upload = document.getElementById('elem_upload')
elem_upload_float = document.getElementById('elem_upload_float')
elem_input_main = document.getElementById('user_input_main')
elem_input_float = document.getElementById('user_input_float')
elem_chatbot = document.getElementById('gpt-chatbot')
elem_upload_component_float = elem_upload_float.querySelector("input[type=file]");
elem_upload_component = elem_upload.querySelector("input[type=file]");
}
async function upload_files(files) {
let totalSizeMb = 0
elem_upload_component_float = elem_upload_float.querySelector("input[type=file]");
if (files && files.length > 0) {
// 执行具体的上传逻辑
if (elem_upload_component_float) {
for (let i = 0; i < files.length; i++) {
// 将从文件数组中获取的文件大小(单位为字节)转换为MB
totalSizeMb += files[i].size / 1024 / 1024;
}
// 检查文件总大小是否超过20MB
if (totalSizeMb > 20) {
toast_push('⚠️文件夹大于 20MB 🚀上传文件中', 3000);
}
let event = new Event("change");
Object.defineProperty(event, "target", { value: elem_upload_component_float, enumerable: true });
Object.defineProperty(event, "currentTarget", { value: elem_upload_component_float, enumerable: true });
Object.defineProperty(elem_upload_component_float, "files", { value: files, enumerable: true });
elem_upload_component_float.dispatchEvent(event);
} else {
toast_push(exist_file_msg, 3000);
}
}
}
function register_func_paste(input) {
let paste_files = [];
if (input) {
input.addEventListener("paste", async function (e) {
@@ -287,7 +451,7 @@ function add_func_paste(input) {
}
}
function add_func_drag(elem) {
function register_func_drag(elem) {
if (elem) {
const dragEvents = ["dragover"];
const leaveEvents = ["dragleave", "dragend", "drop"];
@@ -323,113 +487,74 @@ function add_func_drag(elem) {
}
}
async function upload_files(files) {
const uploadInputElement = elem_upload_float.querySelector("input[type=file]");
let totalSizeMb = 0
if (files && files.length > 0) {
// 执行具体的上传逻辑
if (uploadInputElement) {
for (let i = 0; i < files.length; i++) {
// 将从文件数组中获取的文件大小(单位为字节)转换为MB
totalSizeMb += files[i].size / 1024 / 1024;
}
// 检查文件总大小是否超过20MB
if (totalSizeMb > 20) {
toast_push('⚠️文件夹大于 20MB 🚀上传文件中', 3000)
// return; // 如果超过了指定大小, 可以不进行后续上传操作
}
// 监听change事件 原生Gradio可以实现
// uploadInputElement.addEventListener('change', function(){replace_input_string()});
let event = new Event("change");
Object.defineProperty(event, "target", { value: uploadInputElement, enumerable: true });
Object.defineProperty(event, "currentTarget", { value: uploadInputElement, enumerable: true });
Object.defineProperty(uploadInputElement, "files", { value: files, enumerable: true });
uploadInputElement.dispatchEvent(event);
} else {
toast_push(exist_file_msg, 3000)
}
}
}
function begin_loading_status() {
// Create the loader div and add styling
var loader = document.createElement('div');
loader.id = 'Js_File_Loading';
loader.style.position = "absolute";
loader.style.top = "50%";
loader.style.left = "50%";
loader.style.width = "60px";
loader.style.height = "60px";
loader.style.border = "16px solid #f3f3f3";
loader.style.borderTop = "16px solid #3498db";
loader.style.borderRadius = "50%";
loader.style.animation = "spin 2s linear infinite";
loader.style.transform = "translate(-50%, -50%)";
document.body.appendChild(loader); // Add the loader to the body
// Set the CSS animation keyframes
var styleSheet = document.createElement('style');
// styleSheet.type = 'text/css';
styleSheet.id = 'Js_File_Loading_Style'
styleSheet.innerText = `
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}`;
document.head.appendChild(styleSheet);
}
function cancel_loading_status() {
var loadingElement = document.getElementById('Js_File_Loading');
if (loadingElement) {
document.body.removeChild(loadingElement); // remove the loader from the body
}
var loadingStyle = document.getElementById('Js_File_Loading_Style');
if (loadingStyle) {
document.head.removeChild(loadingStyle);
}
let clearButton = document.querySelectorAll('div[id*="elem_upload"] button[aria-label="Clear"]');
for (let button of clearButton) {
button.addEventListener('click', function () {
setTimeout(function () {
register_upload_event();
}, 50);
function elem_upload_component_pop_message(elem) {
if (elem) {
const dragEvents = ["dragover"];
const leaveEvents = ["dragleave", "dragend", "drop"];
dragEvents.forEach(event => {
elem.addEventListener(event, function (e) {
e.preventDefault();
e.stopPropagation();
if (elem_upload_float.querySelector("input[type=file]")) {
toast_up('⚠️释放以上传文件')
} else {
toast_up(exist_file_msg)
}
});
});
}
}
function register_upload_event() {
elem_upload_float = document.getElementById('elem_upload_float')
const upload_component = elem_upload_float.querySelector("input[type=file]");
if (upload_component) {
upload_component.addEventListener('change', function (event) {
leaveEvents.forEach(event => {
elem.addEventListener(event, function (e) {
toast_down();
e.preventDefault();
e.stopPropagation();
});
});
elem.addEventListener("drop", async function (e) {
toast_push('正在上传中,请稍等。', 2000);
begin_loading_status();
});
}
}
function register_upload_event() {
locate_upload_elems();
if (elem_upload_float) {
_upload = document.querySelector("#elem_upload_float div.center.boundedheight.flex")
elem_upload_component_pop_message(_upload);
}
if (elem_upload_component_float) {
elem_upload_component_float.addEventListener('change', function (event) {
toast_push('正在上传中,请稍等。', 2000);
begin_loading_status();
});
}
if (elem_upload_component) {
elem_upload_component.addEventListener('change', function (event) {
toast_push('正在上传中,请稍等。', 2000);
begin_loading_status();
});
} else {
toast_push("oppps", 3000);
}
}
function monitoring_input_box() {
register_upload_event();
elem_upload = document.getElementById('elem_upload')
elem_upload_float = document.getElementById('elem_upload_float')
elem_input_main = document.getElementById('user_input_main')
elem_input_float = document.getElementById('user_input_float')
elem_chatbot = document.getElementById('gpt-chatbot')
if (elem_input_main) {
if (elem_input_main.querySelector("textarea")) {
add_func_paste(elem_input_main.querySelector("textarea"))
register_func_paste(elem_input_main.querySelector("textarea"))
}
}
if (elem_input_float) {
if (elem_input_float.querySelector("textarea")) {
add_func_paste(elem_input_float.querySelector("textarea"))
register_func_paste(elem_input_float.querySelector("textarea"))
}
}
if (elem_chatbot) {
add_func_drag(elem_chatbot)
register_func_drag(elem_chatbot)
}
}
@@ -483,19 +608,108 @@ function audio_fn_init() {
}
}
function minor_ui_adjustment() {
let cbsc_area = document.getElementById('cbsc');
cbsc_area.style.paddingTop = '15px';
var bar_btn_width = [];
// 自动隐藏超出范围的toolbar按钮
function auto_hide_toolbar() {
var qq = document.getElementById('tooltip');
var tab_nav = qq.getElementsByClassName('tab-nav');
if (tab_nav.length == 0) { return; }
var btn_list = tab_nav[0].getElementsByTagName('button')
if (btn_list.length == 0) { return; }
// 获取页面宽度
var page_width = document.documentElement.clientWidth;
// 总是保留的按钮数量
const always_preserve = 2;
// 获取最后一个按钮的右侧位置
var cur_right = btn_list[always_preserve - 1].getBoundingClientRect().right;
if (bar_btn_width.length == 0) {
// 首次运行,记录每个按钮的宽度
for (var i = 0; i < btn_list.length; i++) {
bar_btn_width.push(btn_list[i].getBoundingClientRect().width);
}
}
// 处理每一个按钮
for (var i = always_preserve; i < btn_list.length; i++) {
var element = btn_list[i];
var element_right = element.getBoundingClientRect().right;
if (element_right != 0) { cur_right = element_right; }
if (element.style.display === 'none') {
if ((cur_right + bar_btn_width[i]) < (page_width * 0.37)) {
// 恢复显示当前按钮
element.style.display = 'block';
return;
} else {
return;
}
} else {
if (cur_right > (page_width * 0.38)) {
// 隐藏当前按钮以及右侧所有按钮
for (var j = i; j < btn_list.length; j++) {
if (btn_list[j].style.display !== 'none') {
btn_list[j].style.display = 'none';
}
}
return;
}
}
}
}
setInterval(function () {
auto_hide_toolbar()
}, 200); // 每50毫秒执行一次
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 第 6 部分: 避免滑动
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
let prevented_offset = 0;
function limit_scroll_position() {
let scrollableDiv = document.querySelector('#gpt-chatbot > div.wrap');
scrollableDiv.addEventListener('wheel', function (e) {
let preventScroll = false;
if (e.deltaX != 0) { prevented_offset = 0; return;}
if (this.scrollHeight == this.clientHeight) { prevented_offset = 0; return;}
if (e.deltaY < 0) { prevented_offset = 0; return;}
if (e.deltaY > 0 && this.scrollHeight - this.clientHeight - this.scrollTop <= 1) { preventScroll = true; }
if (preventScroll) {
prevented_offset += e.deltaY;
if (Math.abs(prevented_offset) > 499) {
if (prevented_offset > 500) { prevented_offset = 500; }
if (prevented_offset < -500) { prevented_offset = -500; }
preventScroll = false;
}
} else {
prevented_offset = 0;
}
if (preventScroll) {
e.preventDefault();
return;
}
}, { passive: false }); // Passive event listener option should be false
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 第 6 部分: JS初始化函数
// 第 7 部分: JS初始化函数
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function GptAcademicJavaScriptInit(LAYOUT = "LEFT-RIGHT") {
audio_fn_init();
minor_ui_adjustment();
chatbotIndicator = gradioApp().querySelector('#gpt-chatbot > div.wrap');
var chatbotObserver = new MutationObserver(() => {
chatbotContentChanged(1);
});
chatbotObserver.observe(chatbotIndicator, { attributes: true, childList: true, subtree: true });
if (LAYOUT === "LEFT-RIGHT") { chatbotAutoHeight(); }
}
if (LAYOUT === "LEFT-RIGHT") { limit_scroll_position(); }
// setInterval(function () { uml("mermaid") }, 5000); // 每50毫秒执行一次
}

View File

@@ -17,7 +17,7 @@
--button-primary-text-color-hover: #FFFFFF;
--button-secondary-text-color: #FFFFFF;
--button-secondary-text-color-hover: #FFFFFF;
--border-bottom-right-radius: 0px;
--border-bottom-left-radius: 0px;
@@ -51,8 +51,8 @@
--button-primary-border-color-hover: #3cff00;
--button-secondary-border-color: #3cff00;
--button-secondary-border-color-hover: #3cff00;
--body-background-fill: #000000;
--background-fill-primary: #000000;
--background-fill-secondary: #000000;
@@ -103,7 +103,7 @@
--button-primary-text-color-hover: #FFFFFF;
--button-secondary-text-color: #FFFFFF;
--button-secondary-text-color-hover: #FFFFFF;
--border-bottom-right-radius: 0px;
@@ -138,8 +138,8 @@
--button-primary-border-color-hover: #3cff00;
--button-secondary-border-color: #3cff00;
--button-secondary-border-color-hover: #3cff00;
--body-background-fill: #000000;
--background-fill-primary: #000000;
--background-fill-secondary: #000000;
@@ -479,4 +479,3 @@
.dark .codehilite .vi { color: #89DDFF } /* Name.Variable.Instance */
.dark .codehilite .vm { color: #82AAFF } /* Name.Variable.Magic */
.dark .codehilite .il { color: #F78C6C } /* Literal.Number.Integer.Long */

View File

@@ -1,18 +1,26 @@
import os
import gradio as gr
from toolbox import get_conf
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'LAYOUT')
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT")
theme_dir = os.path.dirname(__file__)
def adjust_theme():
def adjust_theme():
try:
color_er = gr.themes.utils.colors.fuchsia
set_theme = gr.themes.Default(
primary_hue=gr.themes.utils.colors.orange,
neutral_hue=gr.themes.utils.colors.gray,
font=["Helvetica", "Microsoft YaHei", "ui-sans-serif", "sans-serif", "system-ui"],
font_mono=["ui-monospace", "Consolas", "monospace"])
font=[
"Helvetica",
"Microsoft YaHei",
"ui-sans-serif",
"sans-serif",
"system-ui",
],
font_mono=["ui-monospace", "Consolas", "monospace"],
)
set_theme.set(
# Colors
input_background_fill_dark="*neutral_800",
@@ -59,9 +67,15 @@ def adjust_theme():
button_cancel_text_color_dark="white",
)
with open(os.path.join(theme_dir, 'common.js'), 'r', encoding='utf8') as f:
js = f"<script>{f.read()}</script>"
js = ""
for jsf in [
os.path.join(theme_dir, "common.js"),
os.path.join(theme_dir, "mermaid.min.js"),
os.path.join(theme_dir, "mermaid_loader.js"),
]:
with open(jsf, "r", encoding="utf8") as f:
js += f"<script>{f.read()}</script>"
# 添加一个萌萌的看板娘
if ADD_WAIFU:
js += """
@@ -69,21 +83,26 @@ def adjust_theme():
<script src="file=docs/waifu_plugin/jquery-ui.min.js"></script>
<script src="file=docs/waifu_plugin/autoload.js"></script>
"""
if not hasattr(gr, 'RawTemplateResponse'):
if not hasattr(gr, "RawTemplateResponse"):
gr.RawTemplateResponse = gr.routes.templates.TemplateResponse
gradio_original_template_fn = gr.RawTemplateResponse
def gradio_new_template_fn(*args, **kwargs):
res = gradio_original_template_fn(*args, **kwargs)
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
res.body = res.body.replace(b"</html>", f"{js}</html>".encode("utf8"))
res.init_headers()
return res
gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template
gr.routes.templates.TemplateResponse = (
gradio_new_template_fn # override gradio template
)
except:
set_theme = None
print('gradio版本较旧, 不能自定义字体和颜色')
print("gradio版本较旧, 不能自定义字体和颜色")
return set_theme
with open(os.path.join(theme_dir, 'contrast.css'), "r", encoding="utf-8") as f:
with open(os.path.join(theme_dir, "contrast.css"), "r", encoding="utf-8") as f:
advanced_css = f.read()
with open(os.path.join(theme_dir, 'common.css'), "r", encoding="utf-8") as f:
with open(os.path.join(theme_dir, "common.css"), "r", encoding="utf-8") as f:
advanced_css += f.read()

View File

@@ -303,4 +303,3 @@
.dark .codehilite .vi { color: #89DDFF } /* Name.Variable.Instance */
.dark .codehilite .vm { color: #82AAFF } /* Name.Variable.Magic */
.dark .codehilite .il { color: #F78C6C } /* Literal.Number.Integer.Long */

View File

@@ -1,17 +1,26 @@
import os
import gradio as gr
from toolbox import get_conf
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'LAYOUT')
theme_dir = os.path.dirname(__file__)
def adjust_theme():
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT")
theme_dir = os.path.dirname(__file__)
def adjust_theme():
try:
color_er = gr.themes.utils.colors.fuchsia
set_theme = gr.themes.Default(
primary_hue=gr.themes.utils.colors.orange,
neutral_hue=gr.themes.utils.colors.gray,
font=["Helvetica", "Microsoft YaHei", "ui-sans-serif", "sans-serif", "system-ui"],
font_mono=["ui-monospace", "Consolas", "monospace"])
font=[
"Helvetica",
"Microsoft YaHei",
"ui-sans-serif",
"sans-serif",
"system-ui",
],
font_mono=["ui-monospace", "Consolas", "monospace"],
)
set_theme.set(
# Colors
input_background_fill_dark="*neutral_800",
@@ -58,8 +67,14 @@ def adjust_theme():
button_cancel_text_color_dark="white",
)
with open(os.path.join(theme_dir, 'common.js'), 'r', encoding='utf8') as f:
js = f"<script>{f.read()}</script>"
js = ""
for jsf in [
os.path.join(theme_dir, "common.js"),
os.path.join(theme_dir, "mermaid.min.js"),
os.path.join(theme_dir, "mermaid_loader.js"),
]:
with open(jsf, "r", encoding="utf8") as f:
js += f"<script>{f.read()}</script>"
# 添加一个萌萌的看板娘
if ADD_WAIFU:
@@ -68,21 +83,26 @@ def adjust_theme():
<script src="file=docs/waifu_plugin/jquery-ui.min.js"></script>
<script src="file=docs/waifu_plugin/autoload.js"></script>
"""
if not hasattr(gr, 'RawTemplateResponse'):
if not hasattr(gr, "RawTemplateResponse"):
gr.RawTemplateResponse = gr.routes.templates.TemplateResponse
gradio_original_template_fn = gr.RawTemplateResponse
def gradio_new_template_fn(*args, **kwargs):
res = gradio_original_template_fn(*args, **kwargs)
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
res.body = res.body.replace(b"</html>", f"{js}</html>".encode("utf8"))
res.init_headers()
return res
gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template
gr.routes.templates.TemplateResponse = (
gradio_new_template_fn # override gradio template
)
except:
set_theme = None
print('gradio版本较旧, 不能自定义字体和颜色')
print("gradio版本较旧, 不能自定义字体和颜色")
return set_theme
with open(os.path.join(theme_dir, 'default.css'), "r", encoding="utf-8") as f:
with open(os.path.join(theme_dir, "default.css"), "r", encoding="utf-8") as f:
advanced_css = f.read()
with open(os.path.join(theme_dir, 'common.css'), "r", encoding="utf-8") as f:
with open(os.path.join(theme_dir, "common.css"), "r", encoding="utf-8") as f:
advanced_css += f.read()

View File

@@ -2,30 +2,44 @@ import logging
import os
import gradio as gr
from toolbox import get_conf, ProxyNetworkActivate
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'LAYOUT')
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT")
theme_dir = os.path.dirname(__file__)
def dynamic_set_theme(THEME):
set_theme = gr.themes.ThemeClass()
with ProxyNetworkActivate('Download_Gradio_Theme'):
logging.info('正在下载Gradio主题请稍等。')
if THEME.startswith('Huggingface-'): THEME = THEME.lstrip('Huggingface-')
if THEME.startswith('huggingface-'): THEME = THEME.lstrip('huggingface-')
with ProxyNetworkActivate("Download_Gradio_Theme"):
logging.info("正在下载Gradio主题请稍等。")
if THEME.startswith("Huggingface-"):
THEME = THEME.lstrip("Huggingface-")
if THEME.startswith("huggingface-"):
THEME = THEME.lstrip("huggingface-")
set_theme = set_theme.from_hub(THEME.lower())
return set_theme
def adjust_theme():
try:
set_theme = gr.themes.ThemeClass()
with ProxyNetworkActivate('Download_Gradio_Theme'):
logging.info('正在下载Gradio主题请稍等。')
THEME = get_conf('THEME')
if THEME.startswith('Huggingface-'): THEME = THEME.lstrip('Huggingface-')
if THEME.startswith('huggingface-'): THEME = THEME.lstrip('huggingface-')
with ProxyNetworkActivate("Download_Gradio_Theme"):
logging.info("正在下载Gradio主题请稍等。")
THEME = get_conf("THEME")
if THEME.startswith("Huggingface-"):
THEME = THEME.lstrip("Huggingface-")
if THEME.startswith("huggingface-"):
THEME = THEME.lstrip("huggingface-")
set_theme = set_theme.from_hub(THEME.lower())
with open(os.path.join(theme_dir, 'common.js'), 'r', encoding='utf8') as f:
js = f"<script>{f.read()}</script>"
js = ""
for jsf in [
os.path.join(theme_dir, "common.js"),
os.path.join(theme_dir, "mermaid.min.js"),
os.path.join(theme_dir, "mermaid_loader.js"),
]:
with open(jsf, "r", encoding="utf8") as f:
js += f"<script>{f.read()}</script>"
# 添加一个萌萌的看板娘
if ADD_WAIFU:
@@ -34,20 +48,26 @@ def adjust_theme():
<script src="file=docs/waifu_plugin/jquery-ui.min.js"></script>
<script src="file=docs/waifu_plugin/autoload.js"></script>
"""
if not hasattr(gr, 'RawTemplateResponse'):
if not hasattr(gr, "RawTemplateResponse"):
gr.RawTemplateResponse = gr.routes.templates.TemplateResponse
gradio_original_template_fn = gr.RawTemplateResponse
def gradio_new_template_fn(*args, **kwargs):
res = gradio_original_template_fn(*args, **kwargs)
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
res.body = res.body.replace(b"</html>", f"{js}</html>".encode("utf8"))
res.init_headers()
return res
gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template
except Exception as e:
gr.routes.templates.TemplateResponse = (
gradio_new_template_fn # override gradio template
)
except Exception:
set_theme = None
from toolbox import trimmed_format_exc
logging.error('gradio版本较旧, 不能自定义字体和颜色:', trimmed_format_exc())
logging.error("gradio版本较旧, 不能自定义字体和颜色:", trimmed_format_exc())
return set_theme
with open(os.path.join(theme_dir, 'common.css'), "r", encoding="utf-8") as f:
with open(os.path.join(theme_dir, "common.css"), "r", encoding="utf-8") as f:
advanced_css = f.read()

View File

@@ -197,12 +197,12 @@ footer {
}
textarea.svelte-1pie7s6 {
background: #e7e6e6 !important;
width: 96% !important;
width: 100% !important;
}
.dark textarea.svelte-1pie7s6 {
background: var(--input-background-fill) !important;
width: 96% !important;
width: 100% !important;
}
.dark input[type=number].svelte-1cl284s {
@@ -508,12 +508,14 @@ ol:not(.options), ul:not(.options) {
[data-testid = "bot"] {
max-width: 85%;
border-bottom-left-radius: 0 !important;
box-shadow: 2px 2px 0px 1px rgba(0, 0, 0, 0.06);
background-color: var(--message-bot-background-color-light) !important;
}
[data-testid = "user"] {
max-width: 85%;
width: auto !important;
border-bottom-right-radius: 0 !important;
box-shadow: 2px 2px 0px 1px rgba(0, 0, 0, 0.06);
background-color: var(--message-user-background-color-light) !important;
}
.dark [data-testid = "bot"] {

View File

@@ -38,4 +38,4 @@ function setSlider() {
window.addEventListener("DOMContentLoaded", () => {
set_elements();
});
});

View File

@@ -1,9 +1,11 @@
import os
import gradio as gr
from toolbox import get_conf
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf('CODE_HIGHLIGHT', 'ADD_WAIFU', 'LAYOUT')
CODE_HIGHLIGHT, ADD_WAIFU, LAYOUT = get_conf("CODE_HIGHLIGHT", "ADD_WAIFU", "LAYOUT")
theme_dir = os.path.dirname(__file__)
def adjust_theme():
try:
set_theme = gr.themes.Soft(
@@ -50,7 +52,6 @@ def adjust_theme():
c900="#2B2B2B",
c950="#171717",
),
radius_size=gr.themes.sizes.radius_sm,
).set(
button_primary_background_fill="*primary_500",
@@ -75,8 +76,14 @@ def adjust_theme():
chatbot_code_background_color_dark="*neutral_950",
)
with open(os.path.join(theme_dir, 'common.js'), 'r', encoding='utf8') as f:
js = f"<script>{f.read()}</script>"
js = ""
for jsf in [
os.path.join(theme_dir, "common.js"),
os.path.join(theme_dir, "mermaid.min.js"),
os.path.join(theme_dir, "mermaid_loader.js"),
]:
with open(jsf, "r", encoding="utf8") as f:
js += f"<script>{f.read()}</script>"
# 添加一个萌萌的看板娘
if ADD_WAIFU:
@@ -86,24 +93,29 @@ def adjust_theme():
<script src="file=docs/waifu_plugin/autoload.js"></script>
"""
with open(os.path.join(theme_dir, 'green.js'), 'r', encoding='utf8') as f:
with open(os.path.join(theme_dir, "green.js"), "r", encoding="utf8") as f:
js += f"<script>{f.read()}</script>"
if not hasattr(gr, 'RawTemplateResponse'):
if not hasattr(gr, "RawTemplateResponse"):
gr.RawTemplateResponse = gr.routes.templates.TemplateResponse
gradio_original_template_fn = gr.RawTemplateResponse
def gradio_new_template_fn(*args, **kwargs):
res = gradio_original_template_fn(*args, **kwargs)
res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
res.body = res.body.replace(b"</html>", f"{js}</html>".encode("utf8"))
res.init_headers()
return res
gr.routes.templates.TemplateResponse = gradio_new_template_fn # override gradio template
gr.routes.templates.TemplateResponse = (
gradio_new_template_fn # override gradio template
)
except:
set_theme = None
print('gradio版本较旧, 不能自定义字体和颜色')
print("gradio版本较旧, 不能自定义字体和颜色")
return set_theme
with open(os.path.join(theme_dir, 'green.css'), "r", encoding="utf-8") as f:
with open(os.path.join(theme_dir, "green.css"), "r", encoding="utf-8") as f:
advanced_css = f.read()
with open(os.path.join(theme_dir, 'common.css'), "r", encoding="utf-8") as f:
with open(os.path.join(theme_dir, "common.css"), "r", encoding="utf-8") as f:
advanced_css += f.read()

1589
themes/mermaid.min.js vendored Normal file

File diff suppressed because one or more lines are too long

55
themes/mermaid_editor.js Normal file
View File

@@ -0,0 +1,55 @@
import { deflate, inflate } from 'https://fastly.jsdelivr.net/gh/nodeca/pako@master/dist/pako.esm.mjs';
import { toUint8Array, fromUint8Array, toBase64, fromBase64 } from 'https://cdn.jsdelivr.net/npm/js-base64@3.7.2/base64.mjs';
const base64Serde = {
serialize: (state) => {
return toBase64(state, true);
},
deserialize: (state) => {
return fromBase64(state);
}
};
const pakoSerde = {
serialize: (state) => {
const data = new TextEncoder().encode(state);
const compressed = deflate(data, { level: 9 });
return fromUint8Array(compressed, true);
},
deserialize: (state) => {
const data = toUint8Array(state);
return inflate(data, { to: 'string' });
}
};
const serdes = {
base64: base64Serde,
pako: pakoSerde
};
export const serializeState = (state, serde = 'pako') => {
if (!(serde in serdes)) {
throw new Error(`Unknown serde type: ${serde}`);
}
const json = JSON.stringify(state);
const serialized = serdes[serde].serialize(json);
return `${serde}:${serialized}`;
};
const deserializeState = (state) => {
let type, serialized;
if (state.includes(':')) {
let tempType;
[tempType, serialized] = state.split(':');
if (tempType in serdes) {
type = tempType;
} else {
throw new Error(`Unknown serde type: ${tempType}`);
}
} else {
type = 'base64';
serialized = state;
}
const json = serdes[type].deserialize(serialized);
return JSON.parse(json);
};

189
themes/mermaid_loader.js Normal file
View File

@@ -0,0 +1,189 @@
const uml = async className => {
// Custom element to encapsulate Mermaid content.
class MermaidDiv extends HTMLElement {
/**
* Creates a special Mermaid div shadow DOM.
* Works around issues of shared IDs.
* @return {void}
*/
constructor() {
super()
// Create the Shadow DOM and attach style
const shadow = this.attachShadow({ mode: "open" })
const style = document.createElement("style")
style.textContent = `
:host {
display: block;
line-height: initial;
font-size: 16px;
}
div.diagram {
margin: 0;
overflow: visible;
}`
shadow.appendChild(style)
}
}
if (typeof customElements.get("diagram-div") === "undefined") {
customElements.define("diagram-div", MermaidDiv)
}
const getFromCode = parent => {
// Handles <pre><code> text extraction.
let text = ""
for (let j = 0; j < parent.childNodes.length; j++) {
const subEl = parent.childNodes[j]
if (subEl.tagName.toLowerCase() === "code") {
for (let k = 0; k < subEl.childNodes.length; k++) {
const child = subEl.childNodes[k]
const whitespace = /^\s*$/
if (child.nodeName === "#text" && !(whitespace.test(child.nodeValue))) {
text = child.nodeValue
break
}
}
}
}
return text
}
function createOrUpdateHyperlink(parentElement, linkText, linkHref) {
// Search for an existing anchor element within the parentElement
let existingAnchor = parentElement.querySelector("a");
// Check if an anchor element already exists
if (existingAnchor) {
// Update the hyperlink reference if it's different from the current one
if (existingAnchor.href !== linkHref) {
existingAnchor.href = linkHref;
}
// Update the target attribute to ensure it opens in a new tab
existingAnchor.target = '_blank';
// If the text must be dynamic, uncomment and use the following line:
// existingAnchor.textContent = linkText;
} else {
// If no anchor exists, create one and append it to the parentElement
let anchorElement = document.createElement("a");
anchorElement.href = linkHref; // Set hyperlink reference
anchorElement.textContent = linkText; // Set text displayed
anchorElement.target = '_blank'; // Ensure it opens in a new tab
parentElement.appendChild(anchorElement); // Append the new anchor element to the parent
}
}
function removeLastLine(str) {
// 将字符串按换行符分割成数组
var lines = str.split('\n');
lines.pop();
// 将数组重新连接成字符串,并按换行符连接
var result = lines.join('\n');
return result;
}
// 给出配置 Provide a default config in case one is not specified
const defaultConfig = {
startOnLoad: false,
theme: "default",
flowchart: {
htmlLabels: false
},
er: {
useMaxWidth: false
},
sequence: {
useMaxWidth: false,
noteFontWeight: "14px",
actorFontSize: "14px",
messageFontSize: "16px"
}
}
if (document.body.classList.contains("dark")) {
defaultConfig.theme = "dark"
}
const Module = await import('./file=themes/mermaid_editor.js');
function do_render(block, code, codeContent, cnt) {
var rendered_content = mermaid.render(`_diagram_${cnt}`, code);
////////////////////////////// 记录有哪些代码已经被渲染了 ///////////////////////////////////
let codeFinishRenderElement = block.querySelector("code_finish_render"); // 如果block下已存在code_already_rendered元素则获取它
if (codeFinishRenderElement) { // 如果block下已存在code_already_rendered元素
codeFinishRenderElement.style.display = "none";
} else {
// 如果不存在code_finish_render元素则将code元素中的内容添加到新创建的code_finish_render元素中
let codeFinishRenderElementNew = document.createElement("code_finish_render"); // 创建一个新的code_already_rendered元素
codeFinishRenderElementNew.style.display = "none";
codeFinishRenderElementNew.textContent = "";
block.appendChild(codeFinishRenderElementNew); // 将新创建的code_already_rendered元素添加到block中
codeFinishRenderElement = codeFinishRenderElementNew;
}
////////////////////////////// 创建一个用于渲染的容器 ///////////////////////////////////
let mermaidRender = block.querySelector(".mermaid_render"); // 尝试获取已存在的<div class='mermaid_render'>
if (!mermaidRender) {
mermaidRender = document.createElement("div"); // 不存在,创建新的<div class='mermaid_render'>
mermaidRender.classList.add("mermaid_render");
block.appendChild(mermaidRender); // 将新创建的元素附加到block
}
mermaidRender.innerHTML = rendered_content
codeFinishRenderElement.textContent = code // 标记已经渲染的部分
////////////////////////////// 创建一个“点击这里编辑脑图” ///////////////////////////////
let pako_encode = Module.serializeState({
"code": codeContent,
"mermaid": "{\n \"theme\": \"default\"\n}",
"autoSync": true,
"updateDiagram": false
});
createOrUpdateHyperlink(block, "点击这里编辑脑图", "https://mermaid.live/edit#" + pako_encode)
}
// 加载配置 Load up the config
mermaid.mermaidAPI.globalReset() // 全局复位
const config = (typeof mermaidConfig === "undefined") ? defaultConfig : mermaidConfig
mermaid.initialize(config)
// 查找需要渲染的元素 Find all of our Mermaid sources and render them.
const blocks = document.querySelectorAll(`pre.mermaid`);
for (let i = 0; i < blocks.length; i++) {
var block = blocks[i]
////////////////////////////// 如果代码没有发生变化,就不渲染了 ///////////////////////////////////
var code = getFromCode(block);
let codeContent = block.querySelector("code").textContent; // 获取code元素中的文本内容
let codePendingRenderElement = block.querySelector("code_pending_render"); // 如果block下已存在code_already_rendered元素则获取它
if (codePendingRenderElement) { // 如果block下已存在code_pending_render元素
codePendingRenderElement.style.display = "none";
if (codePendingRenderElement.textContent !== codeContent) {
codePendingRenderElement.textContent = codeContent; // 如果现有的code_pending_render元素中的内容与code元素中的内容不同更新code_pending_render元素中的内容
}
else {
continue; // 如果相同,就不处理了
}
} else { // 如果不存在code_pending_render元素则将code元素中的内容添加到新创建的code_pending_render元素中
let codePendingRenderElementNew = document.createElement("code_pending_render"); // 创建一个新的code_already_rendered元素
codePendingRenderElementNew.style.display = "none";
codePendingRenderElementNew.textContent = codeContent;
block.appendChild(codePendingRenderElementNew); // 将新创建的code_pending_render元素添加到block中
codePendingRenderElement = codePendingRenderElementNew;
}
////////////////////////////// 在这里才真正开始渲染 ///////////////////////////////////
try {
do_render(block, code, codeContent, i);
// console.log("渲染", codeContent);
} catch (err) {
try {
var lines = code.split('\n'); if (lines.length < 2) { continue; }
do_render(block, removeLastLine(code), codeContent, i);
// console.log("渲染", codeContent);
} catch (err) {
console.log("以下代码不能渲染", code, removeLastLine(code), err);
}
}
}
}

View File

@@ -10,29 +10,33 @@ from toolbox import get_conf
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
"""
def load_dynamic_theme(THEME):
adjust_dynamic_theme = None
if THEME == 'Chuanhu-Small-and-Beautiful':
if THEME == "Chuanhu-Small-and-Beautiful":
from .green import adjust_theme, advanced_css
theme_declaration = "<h2 align=\"center\" class=\"small\">[Chuanhu-Small-and-Beautiful主题]</h2>"
elif THEME == 'High-Contrast':
theme_declaration = (
'<h2 align="center" class="small">[Chuanhu-Small-and-Beautiful主题]</h2>'
)
elif THEME == "High-Contrast":
from .contrast import adjust_theme, advanced_css
theme_declaration = ""
elif '/' in THEME:
elif "/" in THEME:
from .gradios import adjust_theme, advanced_css
from .gradios import dynamic_set_theme
adjust_dynamic_theme = dynamic_set_theme(THEME)
theme_declaration = ""
else:
from .default import adjust_theme, advanced_css
theme_declaration = ""
return adjust_theme, advanced_css, theme_declaration, adjust_dynamic_theme
adjust_theme, advanced_css, theme_declaration, _ = load_dynamic_theme(get_conf('THEME'))
adjust_theme, advanced_css, theme_declaration, _ = load_dynamic_theme(get_conf("THEME"))
"""
@@ -42,26 +46,26 @@ cookie相关工具函数
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
"""
def init_cookie(cookies, chatbot):
# 为每一位访问的用户赋予一个独一无二的uuid编码
cookies.update({'uuid': uuid.uuid4()})
cookies.update({"uuid": uuid.uuid4()})
return cookies
def to_cookie_str(d):
# Pickle the dictionary and encode it as a string
pickled_dict = pickle.dumps(d)
cookie_value = base64.b64encode(pickled_dict).decode('utf-8')
cookie_value = base64.b64encode(pickled_dict).decode("utf-8")
return cookie_value
def from_cookie_str(c):
# Decode the base64-encoded string and unpickle it into a dictionary
pickled_dict = base64.b64decode(c.encode('utf-8'))
pickled_dict = base64.b64decode(c.encode("utf-8"))
return pickle.loads(pickled_dict)
"""
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
第 3 部分
@@ -107,6 +111,7 @@ js_code_for_toggle_darkmode = """() => {
} else {
document.querySelector('body').classList.add('dark');
}
document.querySelectorAll('code_pending_render').forEach(code => {code.remove();})
}"""
@@ -114,5 +119,3 @@ js_code_for_persistent_cookie_init = """(persistent_cookie) => {
return getCookie("persistent_cookie");
}
"""