upgrade gradio

This commit is contained in:
binary-husky
2024-12-07 15:59:30 +08:00
parent a88b119bf0
commit e9a7f9439f
8 changed files with 255 additions and 129 deletions

20
main.py
View File

@@ -34,7 +34,7 @@ def encode_plugin_info(k, plugin)->str:
def main(): def main():
import gradio as gr import gradio as gr
if gr.__version__ not in ['3.32.9', '3.32.10', '3.32.11']: if gr.__version__ not in ['3.32.12']:
raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.") raise ModuleNotFoundError("使用项目内置Gradio获取最优体验! 请运行 `pip install -r requirements.txt` 指令安装内置Gradio及其他依赖, 详情信息见requirements.txt.")
# 一些基础工具 # 一些基础工具
@@ -57,7 +57,7 @@ def main():
# 如果WEB_PORT是-1, 则随机选取WEB端口 # 如果WEB_PORT是-1, 则随机选取WEB端口
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
from check_proxy import get_current_version from check_proxy import get_current_version
from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_reset, js_code_show_or_hide, js_code_show_or_hide_group2 from themes.theme import adjust_theme, advanced_css, theme_declaration, js_code_clear, js_code_show_or_hide, js_code_show_or_hide_group2
from themes.theme import js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init from themes.theme import js_code_for_toggle_darkmode, js_code_for_persistent_cookie_init
from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid from themes.theme import load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid
title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}" title_html = f"<h1 align=\"center\">GPT 学术优化 {get_current_version()}</h1>{theme_declaration}"
@@ -106,7 +106,7 @@ def main():
with gr_L2(scale=2, elem_id="gpt-chat"): with gr_L2(scale=2, elem_id="gpt-chat"):
chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot") chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT) if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT)
history, history_cache, history_cache_update = make_history_cache() # 定义 后端statehistory、前端history_cache、后端setterhistory_cache_update三兄弟 history, _, _ = make_history_cache() # 定义 后端statehistory、前端history_cache、后端setterhistory_cache_update三兄弟
with gr_L2(scale=1, elem_id="gpt-panel"): with gr_L2(scale=1, elem_id="gpt-panel"):
with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary: with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
with gr.Row(): with gr.Row():
@@ -174,6 +174,7 @@ def main():
with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up: with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up:
file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload") file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload")
# 左上角工具栏定义 # 左上角工具栏定义
from themes.gui_toolbar import define_gui_toolbar from themes.gui_toolbar import define_gui_toolbar
checkboxes, checkboxes_2, max_length_sl, theme_dropdown, system_prompt, file_upload_2, md_dropdown, top_p, temperature = \ checkboxes, checkboxes_2, max_length_sl, theme_dropdown, system_prompt, file_upload_2, md_dropdown, top_p, temperature = \
@@ -183,6 +184,9 @@ def main():
from themes.gui_floating_menu import define_gui_floating_menu from themes.gui_floating_menu import define_gui_floating_menu
area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \ area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \
define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache) define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache)
# 浮动时间线定义
gr.Spark(label="", value="")
# 插件二级菜单的实现 # 插件二级菜单的实现
from themes.gui_advanced_plugin_class import define_gui_advanced_plugin_class from themes.gui_advanced_plugin_class import define_gui_advanced_plugin_class
@@ -222,11 +226,11 @@ def main():
multiplex_sel.select( multiplex_sel.select(
None, [multiplex_sel], None, _js=f"""(multiplex_sel)=>run_multiplex_shift(multiplex_sel)""") None, [multiplex_sel], None, _js=f"""(multiplex_sel)=>run_multiplex_shift(multiplex_sel)""")
cancel_handles.append(submit_btn.click(**predict_args)) cancel_handles.append(submit_btn.click(**predict_args))
resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status resetBtn.click(None, None, [chatbot, history, status], _js="""(a,b,c)=>clear_conversation(a,b,c)""") # 先在前端快速清除chatbot&status
resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status resetBtn2.click(None, None, [chatbot, history, status], _js="""(a,b,c)=>clear_conversation(a,b,c)""") # 先在前端快速清除chatbot&status
reset_server_side_args = (lambda history: ([], [], "已重置", json.dumps(history)), [history], [chatbot, history, status, history_cache]) # reset_server_side_args = (lambda history: ([], [], "已重置"), [history], [chatbot, history, status])
resetBtn.click(*reset_server_side_args) # 再在后端清除history把history转存history_cache备用 # resetBtn.click(*reset_server_side_args) # 再在后端清除history
resetBtn2.click(*reset_server_side_args) # 再在后端清除history把history转存history_cache备用 # resetBtn2.click(*reset_server_side_args) # 再在后端清除history
clearBtn.click(None, None, [txt, txt2], _js=js_code_clear) clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear) clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
if AUTO_CLEAR_TXT: if AUTO_CLEAR_TXT:

View File

@@ -77,16 +77,28 @@ def make_history_cache():
# 定义 后端statehistory、前端history_cache、后端setterhistory_cache_update三兄弟 # 定义 后端statehistory、前端history_cache、后端setterhistory_cache_update三兄弟
import gradio as gr import gradio as gr
# 定义history的后端state # 定义history的后端state
history = gr.State([]) # history = gr.State([])
# 定义history的一个孪生的前端存储区隐藏 history = gr.Textbox(visible=False, elem_id="history-ng")
history_cache = gr.Textbox(visible=False, elem_id="history_cache") # # 定义history的一个孪生的前端存储区隐藏
# 定义history_cache->history的更新方法隐藏。在触发这个按钮时会先执行js代码更新history_cache然后再执行python代码更新history # history_cache = gr.Textbox(visible=False, elem_id="history_cache")
def process_history_cache(history_cache): # # 定义history_cache->history的更新方法隐藏。在触发这个按钮时会先执行js代码更新history_cache然后再执行python代码更新history
return json.loads(history_cache) # def process_history_cache(history_cache):
# 另一种更简单的setter方法 # return json.loads(history_cache)
history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click( # # 另一种更简单的setter方法
process_history_cache, inputs=[history_cache], outputs=[history]) # history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click(
return history, history_cache, history_cache_update # process_history_cache, inputs=[history_cache], outputs=[history])
# # save history to history_cache
# def process_history_cache(history_cache):
# return json.dumps(history_cache)
# # 定义history->history_cache的更新方法隐藏
# def sync_history_cache(history):
# print("sync_history_cache", history)
# return json.dumps(history)
# # history.change(sync_history_cache, inputs=[history], outputs=[history_cache])
# # history_cache_sync = gr.Button("", elem_id="elem_sync_history", visible=False).click(
# # lambda history: (json.dumps(history)), inputs=[history_cache], outputs=[history])
return history, None, None

View File

@@ -318,7 +318,7 @@ function addCopyButton(botElement, index, is_last_in_arr) {
} }
}); });
if (enable_tts){ if (enable_tts) {
var audioButton = document.createElement('button'); var audioButton = document.createElement('button');
audioButton.classList.add('audio-toggle-btn'); audioButton.classList.add('audio-toggle-btn');
audioButton.innerHTML = audioIcon; audioButton.innerHTML = audioIcon;
@@ -346,7 +346,7 @@ function addCopyButton(botElement, index, is_last_in_arr) {
var messageBtnColumn = document.createElement('div'); var messageBtnColumn = document.createElement('div');
messageBtnColumn.classList.add('message-btn-row'); messageBtnColumn.classList.add('message-btn-row');
messageBtnColumn.appendChild(copyButton); messageBtnColumn.appendChild(copyButton);
if (enable_tts){ if (enable_tts) {
messageBtnColumn.appendChild(audioButton); messageBtnColumn.appendChild(audioButton);
} }
botElement.appendChild(messageBtnColumn); botElement.appendChild(messageBtnColumn);
@@ -391,6 +391,8 @@ function chatbotContentChanged(attempt = 1, force = false) {
// Now pass both the message element and the is_last_in_arr boolean to addCopyButton // Now pass both the message element and the is_last_in_arr boolean to addCopyButton
addCopyButton(message, index, is_last_in_arr); addCopyButton(message, index, is_last_in_arr);
save_conversation_history();
}); });
// gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton); // gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton);
}, i === 0 ? 0 : 200); }, i === 0 ? 0 : 200);
@@ -854,8 +856,7 @@ function limit_scroll_position() {
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function loadLive2D() { function loadLive2D() {
if (document.querySelector(".waifu") ) if (document.querySelector(".waifu")) {
{
$('.waifu').show(); $('.waifu').show();
} else { } else {
try { try {
@@ -937,22 +938,140 @@ function gpt_academic_gradio_saveload(
} }
} }
function update_conversation_metadata() {
// Create a conversation UUID and timestamp
const conversationId = crypto.randomUUID();
const timestamp = new Date().toISOString();
const conversationData = {
id: conversationId,
timestamp: timestamp
};
// Save to cookie
setCookie("conversation_metadata", JSON.stringify(conversationData), 2);
// read from cookie
let conversation_metadata = getCookie("conversation_metadata");
console.log("conversation_metadata", conversation_metadata);
}
// // Example schema for conversation data structure
// const example_conversation = {
// metadata: {
// id: "550e8400-e29b-41d4-a716-446655440000",
// timestamp: "2024-03-29T12:34:56.789Z"
// },
// conversation: [
// ["user", "Hello, how are you?"],
// ["assistant", "I'm doing well, thank you for asking! How can I help you today?"],
// ["user", "What is the weather like?"],
// ["assistant", "I don't have access to real-time weather information. You would need to check a weather service or look outside to know the current weather conditions."]
// ],
// preview: "A conversation about greetings and weather"
// }
// Helper function to generate conversation preview
function generatePreview(conversation, maxLength = 100) {
if (!conversation || conversation.length === 0) return "";
// Join all messages with dash separator
const preview = conversation.join("\n");
if (preview.length <= maxLength) return preview;
return preview.substring(0, maxLength) + "...";
}
async function save_conversation_history() {
// 505030475
let chatbot = await get_data_from_gradio_component('gpt-chatbot');
let history = await get_data_from_gradio_component('history-ng');
let conversation_metadata = getCookie("conversation_metadata");
conversation_metadata = JSON.parse(conversation_metadata);
// console.log("conversation_metadata", conversation_metadata);
let conversation = {
timestamp: conversation_metadata.timestamp,
id: conversation_metadata.id,
metadata: conversation_metadata,
conversation: chatbot,
history: history,
preview: generatePreview(JSON.parse(history))
};
// Get existing conversation history from local storage
let conversation_history = [];
try {
const stored = localStorage.getItem('conversation_history');
if (stored) {
conversation_history = JSON.parse(stored);
}
} catch (e) {
// console.error('Error reading conversation history from localStorage:', e);
}
// Find existing conversation with same ID
const existingIndex = conversation_history.findIndex(c => c.id === conversation.id);
if (existingIndex >= 0) {
// Update existing conversation
conversation_history[existingIndex] = conversation;
} else {
// Add new conversation
conversation_history.push(conversation);
}
// Sort conversations by timestamp, newest first
conversation_history.sort((a, b) => {
const timeA = new Date(a.timestamp).getTime();
const timeB = new Date(b.timestamp).getTime();
return timeB - timeA;
});
// Save back to local storage
try {
localStorage.setItem('conversation_history', JSON.stringify(conversation_history));
const LOCAL_STORAGE_UPDATED = "gptac_conversation_history_updated";
window.dispatchEvent(
new CustomEvent(LOCAL_STORAGE_UPDATED, {
detail: conversation_history
})
);
} catch (e) {
console.error('Error saving conversation history to localStorage:', e);
}
}
function restore_chat_from_local_storage(event) {
let conversation = event.detail;
push_data_to_gradio_component(conversation.conversation, "gpt-chatbot", "obj");
push_data_to_gradio_component(conversation.history, "history-ng", "obj");
console.log("restore_chat_from_local_storage", conversation);
}
function clear_conversation(a, b, c) {
update_conversation_metadata();
let stopButton = document.getElementById("elem_stop");
stopButton.click();
// console.log("clear_conversation");
return reset_conversation(a, b);
}
function reset_conversation(a, b) { function reset_conversation(a, b) {
// console.log("js_code_reset"); // console.log("js_code_reset");
a = btoa(unescape(encodeURIComponent(JSON.stringify(a)))); a = btoa(unescape(encodeURIComponent(JSON.stringify(a))));
setCookie("js_previous_chat_cookie", a, 1); setCookie("js_previous_chat_cookie", a, 1);
b = btoa(unescape(encodeURIComponent(JSON.stringify(b))));
setCookie("js_previous_history_cookie", b, 1);
gen_restore_btn(); gen_restore_btn();
return [[], [], "已重置"]; return [[], [], "已重置"];
} }
// clear -> 将 history 缓存至 history_cache -> 点击复原 -> restore_previous_chat() -> 触发elem_update_history -> 读取 history_cache // clear -> 将 history 缓存至 history_cache -> 点击复原 -> restore_previous_chat() -> 触发elem_update_history -> 读取 history_cache
function restore_previous_chat() { function restore_previous_chat() {
console.log("restore_previous_chat"); // console.log("restore_previous_chat");
let chat = getCookie("js_previous_chat_cookie"); let chat = getCookie("js_previous_chat_cookie");
chat = JSON.parse(decodeURIComponent(escape(atob(chat)))); chat = JSON.parse(decodeURIComponent(escape(atob(chat))));
push_data_to_gradio_component(chat, "gpt-chatbot", "obj"); push_data_to_gradio_component(chat, "gpt-chatbot", "obj");
document.querySelector("#elem_update_history").click(); // in order to call set_history_gr_state, and send history state to server let history = getCookie("js_previous_history_cookie");
history = JSON.parse(decodeURIComponent(escape(atob(history))));
push_data_to_gradio_component(history, "history-ng", "obj");
// document.querySelector("#elem_update_history").click(); // in order to call set_history_gr_state, and send history state to server
} }
function gen_restore_btn() { function gen_restore_btn() {
@@ -1010,8 +1129,7 @@ function gen_restore_btn() {
`; `;
// only add when not exist // only add when not exist
if (!document.getElementById('recvButtonStyle')) if (!document.getElementById('recvButtonStyle')) {
{
document.head.appendChild(styleSheet); document.head.appendChild(styleSheet);
} }
@@ -1033,8 +1151,7 @@ function gen_restore_btn() {
document.body.removeChild(this); document.body.removeChild(this);
}); });
// only add when not exist // only add when not exist
if (!document.getElementById('recvButton')) if (!document.getElementById('recvButton')) {
{
document.body.appendChild(button); document.body.appendChild(button);
} }
@@ -1043,7 +1160,7 @@ function gen_restore_btn() {
} }
async function on_plugin_exe_complete(fn_name) { async function on_plugin_exe_complete(fn_name) {
console.log(fn_name); // console.log(fn_name);
if (fn_name === "保存当前的对话") { if (fn_name === "保存当前的对话") {
// get chat profile path // get chat profile path
let chatbot = await get_data_from_gradio_component('gpt-chatbot'); let chatbot = await get_data_from_gradio_component('gpt-chatbot');
@@ -1070,7 +1187,7 @@ async function on_plugin_exe_complete(fn_name) {
} }
async function generate_menu(guiBase64String, btnName){ async function generate_menu(guiBase64String, btnName) {
// assign the button and menu data // assign the button and menu data
push_data_to_gradio_component(guiBase64String, "invisible_current_pop_up_plugin_arg", "string"); push_data_to_gradio_component(guiBase64String, "invisible_current_pop_up_plugin_arg", "string");
push_data_to_gradio_component(btnName, "invisible_callback_btn_for_plugin_exe", "string"); push_data_to_gradio_component(btnName, "invisible_callback_btn_for_plugin_exe", "string");
@@ -1104,22 +1221,22 @@ async function generate_menu(guiBase64String, btnName){
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// Textbox //////////////////////////////////// //////////////////////////////////// Textbox ////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
if (gui_args[key].type=='string'){ // PLUGIN_ARG_MENU if (gui_args[key].type == 'string') { // PLUGIN_ARG_MENU
const component_name = "plugin_arg_txt_" + text_cnt; const component_name = "plugin_arg_txt_" + text_cnt;
push_data_to_gradio_component({ push_data_to_gradio_component({
visible: true, visible: true,
label: gui_args[key].title + "(" + gui_args[key].description + ")", label: gui_args[key].title + "(" + gui_args[key].description + ")",
// label: gui_args[key].title, // label: gui_args[key].title,
placeholder: gui_args[key].description, placeholder: gui_args[key].description,
__type__: 'update' __type__: 'update'
}, component_name, "obj"); }, component_name, "obj");
if (key === "main_input"){ if (key === "main_input") {
// 为了与旧插件兼容,生成菜单时,自动加载输入栏的值 // 为了与旧插件兼容,生成菜单时,自动加载输入栏的值
let current_main_input = await get_data_from_gradio_component('user_input_main'); let current_main_input = await get_data_from_gradio_component('user_input_main');
let current_main_input_2 = await get_data_from_gradio_component('user_input_float'); let current_main_input_2 = await get_data_from_gradio_component('user_input_float');
push_data_to_gradio_component(current_main_input + current_main_input_2, component_name, "obj"); push_data_to_gradio_component(current_main_input + current_main_input_2, component_name, "obj");
} }
else if (key === "advanced_arg"){ else if (key === "advanced_arg") {
// 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值 // 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值
let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy'); let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy');
push_data_to_gradio_component(advance_arg_input_legacy, component_name, "obj"); push_data_to_gradio_component(advance_arg_input_legacy, component_name, "obj");
@@ -1134,12 +1251,12 @@ async function generate_menu(guiBase64String, btnName){
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// Dropdown //////////////////////////////////// //////////////////////////////////// Dropdown ////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
if (gui_args[key].type=='dropdown'){ // PLUGIN_ARG_MENU if (gui_args[key].type == 'dropdown') { // PLUGIN_ARG_MENU
const component_name = "plugin_arg_drop_" + dropdown_cnt; const component_name = "plugin_arg_drop_" + dropdown_cnt;
push_data_to_gradio_component({ push_data_to_gradio_component({
visible: true, visible: true,
choices: gui_args[key].options, choices: gui_args[key].options,
label: gui_args[key].title + "(" + gui_args[key].description + ")", label: gui_args[key].title + "(" + gui_args[key].description + ")",
// label: gui_args[key].title, // label: gui_args[key].title,
placeholder: gui_args[key].description, placeholder: gui_args[key].description,
__type__: 'update' __type__: 'update'
@@ -1154,7 +1271,7 @@ async function generate_menu(guiBase64String, btnName){
} }
} }
async function execute_current_pop_up_plugin(){ async function execute_current_pop_up_plugin() {
let guiBase64String = await get_data_from_gradio_component('invisible_current_pop_up_plugin_arg'); let guiBase64String = await get_data_from_gradio_component('invisible_current_pop_up_plugin_arg');
const stringData = atob(guiBase64String); const stringData = atob(guiBase64String);
let guiJsonData = JSON.parse(stringData); let guiJsonData = JSON.parse(stringData);
@@ -1170,8 +1287,8 @@ async function execute_current_pop_up_plugin(){
let text_cnt = 0; let text_cnt = 0;
for (const key in gui_args) { for (const key in gui_args) {
if (gui_args.hasOwnProperty(key)) { if (gui_args.hasOwnProperty(key)) {
if (gui_args[key].type=='string'){ // PLUGIN_ARG_MENU if (gui_args[key].type == 'string') { // PLUGIN_ARG_MENU
corrisponding_elem_id = "plugin_arg_txt_"+text_cnt corrisponding_elem_id = "plugin_arg_txt_" + text_cnt
gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id); gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id);
text_cnt += 1; text_cnt += 1;
} }
@@ -1180,8 +1297,8 @@ async function execute_current_pop_up_plugin(){
let dropdown_cnt = 0; let dropdown_cnt = 0;
for (const key in gui_args) { for (const key in gui_args) {
if (gui_args.hasOwnProperty(key)) { if (gui_args.hasOwnProperty(key)) {
if (gui_args[key].type=='dropdown'){ // PLUGIN_ARG_MENU if (gui_args[key].type == 'dropdown') { // PLUGIN_ARG_MENU
corrisponding_elem_id = "plugin_arg_drop_"+dropdown_cnt corrisponding_elem_id = "plugin_arg_drop_" + dropdown_cnt
gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id); gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id);
dropdown_cnt += 1; dropdown_cnt += 1;
} }
@@ -1200,29 +1317,29 @@ async function execute_current_pop_up_plugin(){
} }
function hide_all_elem(){ function hide_all_elem() {
// PLUGIN_ARG_MENU // PLUGIN_ARG_MENU
for (text_cnt = 0; text_cnt < 8; text_cnt++){ for (text_cnt = 0; text_cnt < 8; text_cnt++) {
push_data_to_gradio_component({ push_data_to_gradio_component({
visible: false, visible: false,
label: "", label: "",
__type__: 'update' __type__: 'update'
}, "plugin_arg_txt_"+text_cnt, "obj"); }, "plugin_arg_txt_" + text_cnt, "obj");
document.getElementById("plugin_arg_txt_"+text_cnt).parentNode.parentNode.style.display = 'none'; document.getElementById("plugin_arg_txt_" + text_cnt).parentNode.parentNode.style.display = 'none';
} }
for (dropdown_cnt = 0; dropdown_cnt < 8; dropdown_cnt++){ for (dropdown_cnt = 0; dropdown_cnt < 8; dropdown_cnt++) {
push_data_to_gradio_component({ push_data_to_gradio_component({
visible: false, visible: false,
choices: [], choices: [],
label: "", label: "",
__type__: 'update' __type__: 'update'
}, "plugin_arg_drop_"+dropdown_cnt, "obj"); }, "plugin_arg_drop_" + dropdown_cnt, "obj");
document.getElementById("plugin_arg_drop_"+dropdown_cnt).parentNode.style.display = 'none'; document.getElementById("plugin_arg_drop_" + dropdown_cnt).parentNode.style.display = 'none';
} }
} }
function close_current_pop_up_plugin(){ function close_current_pop_up_plugin() {
// PLUGIN_ARG_MENU // PLUGIN_ARG_MENU
push_data_to_gradio_component({ push_data_to_gradio_component({
visible: false, visible: false,
__type__: 'update' __type__: 'update'
@@ -1233,15 +1350,13 @@ function close_current_pop_up_plugin(){
// 生成高级插件的选择菜单 // 生成高级插件的选择菜单
plugin_init_info_lib = {} plugin_init_info_lib = {}
function register_plugin_init(key, base64String){ function register_plugin_init(key, base64String) {
// console.log('x') // console.log('x')
const stringData = atob(base64String); const stringData = atob(base64String);
let guiJsonData = JSON.parse(stringData); let guiJsonData = JSON.parse(stringData);
if (key in plugin_init_info_lib) if (key in plugin_init_info_lib) {
{
} }
else else {
{
plugin_init_info_lib[key] = {}; plugin_init_info_lib[key] = {};
} }
plugin_init_info_lib[key].info = guiJsonData.Info; plugin_init_info_lib[key].info = guiJsonData.Info;
@@ -1251,28 +1366,26 @@ function register_plugin_init(key, base64String){
plugin_init_info_lib[key].enable_advanced_arg = guiJsonData.AdvancedArgs; plugin_init_info_lib[key].enable_advanced_arg = guiJsonData.AdvancedArgs;
plugin_init_info_lib[key].arg_reminder = guiJsonData.ArgsReminder; plugin_init_info_lib[key].arg_reminder = guiJsonData.ArgsReminder;
} }
function register_advanced_plugin_init_code(key, code){ function register_advanced_plugin_init_code(key, code) {
if (key in plugin_init_info_lib) if (key in plugin_init_info_lib) {
{
} }
else else {
{
plugin_init_info_lib[key] = {}; plugin_init_info_lib[key] = {};
} }
plugin_init_info_lib[key].secondary_menu_code = code; plugin_init_info_lib[key].secondary_menu_code = code;
} }
function run_advanced_plugin_launch_code(key){ function run_advanced_plugin_launch_code(key) {
// convert js code string to function // convert js code string to function
generate_menu(plugin_init_info_lib[key].secondary_menu_code, key); generate_menu(plugin_init_info_lib[key].secondary_menu_code, key);
} }
function on_flex_button_click(key){ function on_flex_button_click(key) {
if (plugin_init_info_lib.hasOwnProperty(key) && plugin_init_info_lib[key].hasOwnProperty('secondary_menu_code')){ if (plugin_init_info_lib.hasOwnProperty(key) && plugin_init_info_lib[key].hasOwnProperty('secondary_menu_code')) {
run_advanced_plugin_launch_code(key); run_advanced_plugin_launch_code(key);
}else{ } else {
document.getElementById("old_callback_btn_for_plugin_exe").click(); document.getElementById("old_callback_btn_for_plugin_exe").click();
} }
} }
async function run_dropdown_shift(dropdown){ async function run_dropdown_shift(dropdown) {
let key = dropdown; let key = dropdown;
push_data_to_gradio_component({ push_data_to_gradio_component({
value: key, value: key,
@@ -1281,7 +1394,7 @@ async function run_dropdown_shift(dropdown){
__type__: 'update' __type__: 'update'
}, "elem_switchy_bt", "obj"); }, "elem_switchy_bt", "obj");
if (plugin_init_info_lib[key].enable_advanced_arg){ if (plugin_init_info_lib[key].enable_advanced_arg) {
push_data_to_gradio_component({ push_data_to_gradio_component({
visible: true, visible: true,
label: plugin_init_info_lib[key].label, label: plugin_init_info_lib[key].label,
@@ -1303,9 +1416,9 @@ async function duplicate_in_new_window() {
window.open(url, '_blank'); window.open(url, '_blank');
} }
async function run_classic_plugin_via_id(plugin_elem_id){ async function run_classic_plugin_via_id(plugin_elem_id) {
for (key in plugin_init_info_lib){ for (key in plugin_init_info_lib) {
if (plugin_init_info_lib[key].elem_id == plugin_elem_id){ if (plugin_init_info_lib[key].elem_id == plugin_elem_id) {
// 获取按钮名称 // 获取按钮名称
let current_btn_name = await get_data_from_gradio_component(plugin_elem_id); let current_btn_name = await get_data_from_gradio_component(plugin_elem_id);
// 执行 // 执行
@@ -1326,7 +1439,7 @@ async function call_plugin_via_name(current_btn_name) {
hide_all_elem(); hide_all_elem();
// 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值 // 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值
let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy'); let advance_arg_input_legacy = await get_data_from_gradio_component('advance_arg_input_legacy');
if (advance_arg_input_legacy.length != 0){ if (advance_arg_input_legacy.length != 0) {
gui_args["advanced_arg"] = {}; gui_args["advanced_arg"] = {};
gui_args["advanced_arg"].user_confirmed_value = advance_arg_input_legacy; gui_args["advanced_arg"].user_confirmed_value = advance_arg_input_legacy;
} }
@@ -1353,7 +1466,7 @@ async function multiplex_function_begin(multiplex_sel) {
// do not delete `REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE`! It will be read and replaced by Python code. // do not delete `REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE`! It will be read and replaced by Python code.
// REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE // REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE
} }
async function run_multiplex_shift(multiplex_sel){ async function run_multiplex_shift(multiplex_sel) {
let key = multiplex_sel; let key = multiplex_sel;
if (multiplex_sel === "常规对话") { if (multiplex_sel === "常规对话") {
key = "提交"; key = "提交";

View File

@@ -1,7 +1,7 @@
import gradio as gr import gradio as gr
def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache): def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookies, web_cookie_cache):
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_input_secondary: with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top", elem_id="f_area_input_secondary") as area_input_secondary:
with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"): with gr.Accordion("浮动输入区", open=True, elem_id="input-panel2"):
with gr.Row() as row: with gr.Row() as row:
row.style(equal_height=True) row.style(equal_height=True)
@@ -17,7 +17,7 @@ def define_gui_floating_menu(customize_btns, functional, predefined_btns, cookie
clearBtn2 = gr.Button("清除", elem_id="elem_clear2", variant="secondary", visible=False); clearBtn2.style(size="sm") clearBtn2 = gr.Button("清除", elem_id="elem_clear2", variant="secondary", visible=False); clearBtn2.style(size="sm")
with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top") as area_customize: with gr.Floating(init_x="20%", init_y="50%", visible=False, width="40%", drag="top", elem_id="f_area_customize") as area_customize:
with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"): with gr.Accordion("自定义菜单", open=True, elem_id="edit-panel"):
with gr.Row() as row: with gr.Row() as row:
with gr.Column(scale=10): with gr.Column(scale=10):

View File

@@ -3,6 +3,8 @@ async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout, tts) {
audio_fn_init(); audio_fn_init();
minor_ui_adjustment(); minor_ui_adjustment();
ButtonWithDropdown_init(); ButtonWithDropdown_init();
update_conversation_metadata();
window.addEventListener("gptac_restore_chat_from_local_storage", restore_chat_from_local_storage);
// 加载欢迎页面 // 加载欢迎页面
const welcomeMessage = new WelcomeMessage(); const welcomeMessage = new WelcomeMessage();

View File

@@ -92,15 +92,6 @@ js_code_for_persistent_cookie_init = """(web_cookie_cache, cookie) => {
} }
""" """
# 详见 themes/common.js
js_code_reset = """
(a,b,c)=>{
let stopButton = document.getElementById("elem_stop");
stopButton.click();
return reset_conversation(a,b);
}
"""
js_code_clear = """ js_code_clear = """
(a,b)=>{ (a,b)=>{

View File

@@ -84,7 +84,7 @@ class WelcomeMessage {
this.max_welcome_card_num = 6; this.max_welcome_card_num = 6;
this.card_array = []; this.card_array = [];
this.static_welcome_message_previous = []; this.static_welcome_message_previous = [];
this.reflesh_time_interval = 15*1000; this.reflesh_time_interval = 15 * 1000;
const reflesh_render_status = () => { const reflesh_render_status = () => {
@@ -105,7 +105,7 @@ class WelcomeMessage {
async startRefleshCards() { async startRefleshCards() {
await new Promise(r => setTimeout(r, this.reflesh_time_interval)); await new Promise(r => setTimeout(r, this.reflesh_time_interval));
await this.reflesh_cards(); await this.reflesh_cards();
if (this.visible){ if (this.visible) {
setTimeout(() => { setTimeout(() => {
this.startRefleshCards.call(this); this.startRefleshCards.call(this);
}, 1); }, 1);
@@ -113,7 +113,7 @@ class WelcomeMessage {
} }
async reflesh_cards() { async reflesh_cards() {
if (!this.visible){ if (!this.visible) {
return; return;
} }
@@ -173,18 +173,18 @@ class WelcomeMessage {
} }
shuffle(array) { shuffle(array) {
var currentIndex = array.length, randomIndex; var currentIndex = array.length, randomIndex;
// While there remain elements to shuffle... // While there remain elements to shuffle...
while (currentIndex != 0) { while (currentIndex != 0) {
// Pick a remaining element... // Pick a remaining element...
randomIndex = Math.floor(Math.random() * currentIndex); randomIndex = Math.floor(Math.random() * currentIndex);
currentIndex--; currentIndex--;
// And swap it with the current element. // And swap it with the current element.
[array[currentIndex], array[randomIndex]] = [ [array[currentIndex], array[randomIndex]] = [
array[randomIndex], array[currentIndex]]; array[randomIndex], array[currentIndex]];
} }
return array; return array;
@@ -193,7 +193,7 @@ class WelcomeMessage {
async update() { async update() {
// console.log('update') // console.log('update')
var page_width = document.documentElement.clientWidth; var page_width = document.documentElement.clientWidth;
const width_to_hide_welcome = 1200; const width_to_hide_welcome = 1000;
if (!await this.isChatbotEmpty() || page_width < width_to_hide_welcome) { if (!await this.isChatbotEmpty() || page_width < width_to_hide_welcome) {
if (this.visible) { if (this.visible) {
this.removeWelcome(); this.removeWelcome();
@@ -203,7 +203,7 @@ class WelcomeMessage {
} }
return; return;
} }
if (this.visible){ if (this.visible) {
return; return;
} }
// console.log("welcome"); // console.log("welcome");
@@ -220,28 +220,28 @@ class WelcomeMessage {
const title = document.createElement('div'); const title = document.createElement('div');
title.classList.add('welcome-card-title'); title.classList.add('welcome-card-title');
// 创建图标 // 创建图标
const svg = document.createElement('img'); const svg = document.createElement('img');
svg.classList.add('welcome-svg'); svg.classList.add('welcome-svg');
svg.src = message.svg; svg.src = message.svg;
svg.style.height = '30px'; svg.style.height = '30px';
title.appendChild(svg); title.appendChild(svg);
// 创建标题 // 创建标题
const text = document.createElement('a'); const text = document.createElement('a');
text.textContent = message.title; text.textContent = message.title;
text.classList.add('welcome-title-text'); text.classList.add('welcome-title-text');
text.href = message.url; text.href = message.url;
text.target = "_blank"; text.target = "_blank";
title.appendChild(text) title.appendChild(text)
// 创建内容 // 创建内容
const content = document.createElement('div'); const content = document.createElement('div');
content.classList.add('welcome-content'); content.classList.add('welcome-content');
const content_c = document.createElement('div'); const content_c = document.createElement('div');
content_c.classList.add('welcome-content-c'); content_c.classList.add('welcome-content-c');
content_c.textContent = message.content; content_c.textContent = message.content;
content.appendChild(content_c); content.appendChild(content_c);
// 将标题和内容添加到卡片 div 中 // 将标题和内容添加到卡片 div 中
card.appendChild(title); card.appendChild(title);
@@ -307,28 +307,28 @@ class WelcomeMessage {
class PageFocusHandler { class PageFocusHandler {
constructor() { constructor() {
this.hasReturned = false; this.hasReturned = false;
this.focusCallbacks = []; this.focusCallbacks = [];
// Bind the focus and blur event handlers // Bind the focus and blur event handlers
window.addEventListener('visibilitychange', this.handleFocus.bind(this)); window.addEventListener('visibilitychange', this.handleFocus.bind(this));
} }
// Method to handle the focus event // Method to handle the focus event
handleFocus() { handleFocus() {
if (this.hasReturned) { if (this.hasReturned) {
this.focusCallbacks.forEach(callback => callback()); this.focusCallbacks.forEach(callback => callback());
} }
this.hasReturned = true; this.hasReturned = true;
} }
// Method to add a custom callback function // Method to add a custom callback function
addFocusCallback(callback) { addFocusCallback(callback) {
if (typeof callback === 'function') { if (typeof callback === 'function') {
this.focusCallbacks.push(callback); this.focusCallbacks.push(callback);
} else { } else {
throw new Error('Callback must be a function'); throw new Error('Callback must be a function');
} }
} }
} }

View File

@@ -8,6 +8,7 @@ import base64
import gradio import gradio
import shutil import shutil
import glob import glob
import json
import uuid import uuid
from loguru import logger from loguru import logger
from functools import wraps from functools import wraps
@@ -92,8 +93,9 @@ def ArgsGeneralWrapper(f):
""" """
def decorated(request: gradio.Request, cookies:dict, max_length:int, llm_model:str, def decorated(request: gradio.Request, cookies:dict, max_length:int, llm_model:str,
txt:str, txt2:str, top_p:float, temperature:float, chatbot:list, txt:str, txt2:str, top_p:float, temperature:float, chatbot:list,
history:list, system_prompt:str, plugin_advanced_arg:dict, *args): json_history:str, system_prompt:str, plugin_advanced_arg:dict, *args):
txt_passon = txt txt_passon = txt
history = json.loads(json_history) if json_history else []
if txt == "" and txt2 != "": txt_passon = txt2 if txt == "" and txt2 != "": txt_passon = txt2
# 引入一个有cookie的chatbot # 引入一个有cookie的chatbot
if request.username is not None: if request.username is not None:
@@ -148,10 +150,11 @@ def ArgsGeneralWrapper(f):
return decorated return decorated
def update_ui(chatbot:ChatBotWithCookies, history, msg="正常", **kwargs): # 刷新界面 def update_ui(chatbot:ChatBotWithCookies, history:list, msg:str="正常", **kwargs): # 刷新界面
""" """
刷新用户界面 刷新用户界面
""" """
assert isinstance(history, list), "history必须是一个list"
assert isinstance( assert isinstance(
chatbot, ChatBotWithCookies chatbot, ChatBotWithCookies
), "在传递chatbot的过程中不要将其丢弃。必要时, 可用clear将其清空, 然后用for+append循环重新赋值。" ), "在传递chatbot的过程中不要将其丢弃。必要时, 可用clear将其清空, 然后用for+append循环重新赋值。"
@@ -175,10 +178,11 @@ def update_ui(chatbot:ChatBotWithCookies, history, msg="正常", **kwargs): #
else: else:
chatbot_gr = chatbot chatbot_gr = chatbot
yield cookies, chatbot_gr, history, msg json_history = json.dumps(history, ensure_ascii=False)
yield cookies, chatbot_gr, json_history, msg
def update_ui_lastest_msg(lastmsg:str, chatbot:ChatBotWithCookies, history:list, delay=1, msg="正常"): # 刷新界面 def update_ui_lastest_msg(lastmsg:str, chatbot:ChatBotWithCookies, history:list, delay:float=1, msg:str="正常"): # 刷新界面
""" """
刷新用户界面 刷新用户界面
""" """