diff --git a/main.py b/main.py
index dd23d49b..e54f6d9a 100644
--- a/main.py
+++ b/main.py
@@ -34,7 +34,7 @@ def encode_plugin_info(k, plugin)->str:
def main():
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.")
# 一些基础工具
@@ -57,7 +57,7 @@ def main():
# 如果WEB_PORT是-1, 则随机选取WEB端口
PORT = find_free_port() if WEB_PORT <= 0 else WEB_PORT
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 load_dynamic_theme, to_cookie_str, from_cookie_str, assign_user_uuid
title_html = f"
GPT 学术优化 {get_current_version()}
{theme_declaration}"
@@ -106,7 +106,7 @@ def main():
with gr_L2(scale=2, elem_id="gpt-chat"):
chatbot = gr.Chatbot(label=f"当前模型:{LLM_MODEL}", elem_id="gpt-chatbot")
if LAYOUT == "TOP-DOWN": chatbot.style(height=CHATBOT_HEIGHT)
- history, history_cache, history_cache_update = make_history_cache() # 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟
+ history, _, _ = make_history_cache() # 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟
with gr_L2(scale=1, elem_id="gpt-panel"):
with gr.Accordion("输入区", open=True, elem_id="input-panel") as area_input_primary:
with gr.Row():
@@ -174,6 +174,7 @@ def main():
with gr.Accordion("点击展开“文件下载区”。", open=False) as area_file_up:
file_upload = gr.Files(label="任何文件, 推荐上传压缩文件(zip, tar)", file_count="multiple", elem_id="elem_upload")
+
# 左上角工具栏定义
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 = \
@@ -183,6 +184,9 @@ def main():
from themes.gui_floating_menu import define_gui_floating_menu
area_input_secondary, txt2, area_customize, _, resetBtn2, clearBtn2, stopBtn2 = \
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
@@ -222,11 +226,11 @@ def main():
multiplex_sel.select(
None, [multiplex_sel], None, _js=f"""(multiplex_sel)=>run_multiplex_shift(multiplex_sel)""")
cancel_handles.append(submit_btn.click(**predict_args))
- resetBtn.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
- resetBtn2.click(None, None, [chatbot, history, status], _js=js_code_reset) # 先在前端快速清除chatbot&status
- reset_server_side_args = (lambda history: ([], [], "已重置", json.dumps(history)), [history], [chatbot, history, status, history_cache])
- resetBtn.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用
- resetBtn2.click(*reset_server_side_args) # 再在后端清除history,把history转存history_cache备用
+ 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="""(a,b,c)=>clear_conversation(a,b,c)""") # 先在前端快速清除chatbot&status
+ # reset_server_side_args = (lambda history: ([], [], "已重置"), [history], [chatbot, history, status])
+ # resetBtn.click(*reset_server_side_args) # 再在后端清除history
+ # resetBtn2.click(*reset_server_side_args) # 再在后端清除history
clearBtn.click(None, None, [txt, txt2], _js=js_code_clear)
clearBtn2.click(None, None, [txt, txt2], _js=js_code_clear)
if AUTO_CLEAR_TXT:
diff --git a/shared_utils/cookie_manager.py b/shared_utils/cookie_manager.py
index 88fe3a91..d503ce77 100644
--- a/shared_utils/cookie_manager.py
+++ b/shared_utils/cookie_manager.py
@@ -77,16 +77,28 @@ def make_history_cache():
# 定义 后端state(history)、前端(history_cache)、后端setter(history_cache_update)三兄弟
import gradio as gr
# 定义history的后端state
- history = gr.State([])
- # 定义history的一个孪生的前端存储区(隐藏)
- history_cache = gr.Textbox(visible=False, elem_id="history_cache")
- # 定义history_cache->history的更新方法(隐藏)。在触发这个按钮时,会先执行js代码更新history_cache,然后再执行python代码更新history
- def process_history_cache(history_cache):
- return json.loads(history_cache)
- # 另一种更简单的setter方法
- history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click(
- process_history_cache, inputs=[history_cache], outputs=[history])
- return history, history_cache, history_cache_update
+ # history = gr.State([])
+ history = gr.Textbox(visible=False, elem_id="history-ng")
+ # # 定义history的一个孪生的前端存储区(隐藏)
+ # history_cache = gr.Textbox(visible=False, elem_id="history_cache")
+ # # 定义history_cache->history的更新方法(隐藏)。在触发这个按钮时,会先执行js代码更新history_cache,然后再执行python代码更新history
+ # def process_history_cache(history_cache):
+ # return json.loads(history_cache)
+ # # 另一种更简单的setter方法
+ # history_cache_update = gr.Button("", elem_id="elem_update_history", visible=False).click(
+ # 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
diff --git a/themes/common.js b/themes/common.js
index c0b794cf..55727cc6 100644
--- a/themes/common.js
+++ b/themes/common.js
@@ -318,7 +318,7 @@ function addCopyButton(botElement, index, is_last_in_arr) {
}
});
- if (enable_tts){
+ if (enable_tts) {
var audioButton = document.createElement('button');
audioButton.classList.add('audio-toggle-btn');
audioButton.innerHTML = audioIcon;
@@ -346,7 +346,7 @@ function addCopyButton(botElement, index, is_last_in_arr) {
var messageBtnColumn = document.createElement('div');
messageBtnColumn.classList.add('message-btn-row');
messageBtnColumn.appendChild(copyButton);
- if (enable_tts){
+ if (enable_tts) {
messageBtnColumn.appendChild(audioButton);
}
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
addCopyButton(message, index, is_last_in_arr);
+
+ save_conversation_history();
});
// gradioApp().querySelectorAll('#gpt-chatbot .message-wrap .message.bot').forEach(addCopyButton);
}, i === 0 ? 0 : 200);
@@ -854,8 +856,7 @@ function limit_scroll_position() {
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function loadLive2D() {
- if (document.querySelector(".waifu") )
- {
+ if (document.querySelector(".waifu")) {
$('.waifu').show();
} else {
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) {
// console.log("js_code_reset");
a = btoa(unescape(encodeURIComponent(JSON.stringify(a))));
setCookie("js_previous_chat_cookie", a, 1);
+ b = btoa(unescape(encodeURIComponent(JSON.stringify(b))));
+ setCookie("js_previous_history_cookie", b, 1);
gen_restore_btn();
return [[], [], "已重置"];
}
// clear -> 将 history 缓存至 history_cache -> 点击复原 -> restore_previous_chat() -> 触发elem_update_history -> 读取 history_cache
function restore_previous_chat() {
- console.log("restore_previous_chat");
+ // console.log("restore_previous_chat");
let chat = getCookie("js_previous_chat_cookie");
chat = JSON.parse(decodeURIComponent(escape(atob(chat))));
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() {
@@ -1010,8 +1129,7 @@ function gen_restore_btn() {
`;
// only add when not exist
- if (!document.getElementById('recvButtonStyle'))
- {
+ if (!document.getElementById('recvButtonStyle')) {
document.head.appendChild(styleSheet);
}
@@ -1033,8 +1151,7 @@ function gen_restore_btn() {
document.body.removeChild(this);
});
// only add when not exist
- if (!document.getElementById('recvButton'))
- {
+ if (!document.getElementById('recvButton')) {
document.body.appendChild(button);
}
@@ -1043,7 +1160,7 @@ function gen_restore_btn() {
}
async function on_plugin_exe_complete(fn_name) {
- console.log(fn_name);
+ // console.log(fn_name);
if (fn_name === "保存当前的对话") {
// get chat profile path
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
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");
@@ -1104,22 +1221,22 @@ async function generate_menu(guiBase64String, btnName){
///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// 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;
push_data_to_gradio_component({
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,
placeholder: gui_args[key].description,
__type__: 'update'
}, 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_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");
}
- 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');
push_data_to_gradio_component(advance_arg_input_legacy, component_name, "obj");
@@ -1134,12 +1251,12 @@ async function generate_menu(guiBase64String, btnName){
///////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////// 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;
push_data_to_gradio_component({
visible: true,
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,
placeholder: gui_args[key].description,
__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');
const stringData = atob(guiBase64String);
let guiJsonData = JSON.parse(stringData);
@@ -1170,8 +1287,8 @@ async function execute_current_pop_up_plugin(){
let text_cnt = 0;
for (const key in gui_args) {
if (gui_args.hasOwnProperty(key)) {
- if (gui_args[key].type=='string'){ // PLUGIN_ARG_MENU
- corrisponding_elem_id = "plugin_arg_txt_"+text_cnt
+ if (gui_args[key].type == 'string') { // PLUGIN_ARG_MENU
+ corrisponding_elem_id = "plugin_arg_txt_" + text_cnt
gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id);
text_cnt += 1;
}
@@ -1180,8 +1297,8 @@ async function execute_current_pop_up_plugin(){
let dropdown_cnt = 0;
for (const key in gui_args) {
if (gui_args.hasOwnProperty(key)) {
- if (gui_args[key].type=='dropdown'){ // PLUGIN_ARG_MENU
- corrisponding_elem_id = "plugin_arg_drop_"+dropdown_cnt
+ if (gui_args[key].type == 'dropdown') { // PLUGIN_ARG_MENU
+ corrisponding_elem_id = "plugin_arg_drop_" + dropdown_cnt
gui_args[key].user_confirmed_value = await get_data_from_gradio_component(corrisponding_elem_id);
dropdown_cnt += 1;
}
@@ -1200,29 +1317,29 @@ async function execute_current_pop_up_plugin(){
}
-function hide_all_elem(){
- // PLUGIN_ARG_MENU
- for (text_cnt = 0; text_cnt < 8; text_cnt++){
+function hide_all_elem() {
+ // PLUGIN_ARG_MENU
+ for (text_cnt = 0; text_cnt < 8; text_cnt++) {
push_data_to_gradio_component({
visible: false,
label: "",
__type__: 'update'
- }, "plugin_arg_txt_"+text_cnt, "obj");
- document.getElementById("plugin_arg_txt_"+text_cnt).parentNode.parentNode.style.display = 'none';
+ }, "plugin_arg_txt_" + text_cnt, "obj");
+ 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({
visible: false,
choices: [],
label: "",
__type__: 'update'
- }, "plugin_arg_drop_"+dropdown_cnt, "obj");
- document.getElementById("plugin_arg_drop_"+dropdown_cnt).parentNode.style.display = 'none';
+ }, "plugin_arg_drop_" + dropdown_cnt, "obj");
+ document.getElementById("plugin_arg_drop_" + dropdown_cnt).parentNode.style.display = 'none';
}
}
-function close_current_pop_up_plugin(){
- // PLUGIN_ARG_MENU
+function close_current_pop_up_plugin() {
+ // PLUGIN_ARG_MENU
push_data_to_gradio_component({
visible: false,
__type__: 'update'
@@ -1233,15 +1350,13 @@ function close_current_pop_up_plugin(){
// 生成高级插件的选择菜单
plugin_init_info_lib = {}
-function register_plugin_init(key, base64String){
+function register_plugin_init(key, base64String) {
// console.log('x')
const stringData = atob(base64String);
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].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].arg_reminder = guiJsonData.ArgsReminder;
}
-function register_advanced_plugin_init_code(key, code){
- if (key in plugin_init_info_lib)
- {
+function register_advanced_plugin_init_code(key, code) {
+ if (key in plugin_init_info_lib) {
}
- else
- {
+ else {
plugin_init_info_lib[key] = {};
}
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
generate_menu(plugin_init_info_lib[key].secondary_menu_code, key);
}
-function on_flex_button_click(key){
- if (plugin_init_info_lib.hasOwnProperty(key) && plugin_init_info_lib[key].hasOwnProperty('secondary_menu_code')){
+function on_flex_button_click(key) {
+ if (plugin_init_info_lib.hasOwnProperty(key) && plugin_init_info_lib[key].hasOwnProperty('secondary_menu_code')) {
run_advanced_plugin_launch_code(key);
- }else{
+ } else {
document.getElementById("old_callback_btn_for_plugin_exe").click();
}
}
-async function run_dropdown_shift(dropdown){
+async function run_dropdown_shift(dropdown) {
let key = dropdown;
push_data_to_gradio_component({
value: key,
@@ -1281,7 +1394,7 @@ async function run_dropdown_shift(dropdown){
__type__: 'update'
}, "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({
visible: true,
label: plugin_init_info_lib[key].label,
@@ -1303,9 +1416,9 @@ async function duplicate_in_new_window() {
window.open(url, '_blank');
}
-async function run_classic_plugin_via_id(plugin_elem_id){
- for (key in plugin_init_info_lib){
- if (plugin_init_info_lib[key].elem_id == plugin_elem_id){
+async function run_classic_plugin_via_id(plugin_elem_id) {
+ for (key in plugin_init_info_lib) {
+ if (plugin_init_info_lib[key].elem_id == 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();
// 为了与旧插件兼容,生成菜单时,自动加载旧高级参数输入区的值
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"].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.
// REPLACE_EXTENDED_MULTIPLEX_FUNCTIONS_HERE
}
-async function run_multiplex_shift(multiplex_sel){
+async function run_multiplex_shift(multiplex_sel) {
let key = multiplex_sel;
if (multiplex_sel === "常规对话") {
key = "提交";
diff --git a/themes/gui_floating_menu.py b/themes/gui_floating_menu.py
index 90947c5d..614d9d97 100644
--- a/themes/gui_floating_menu.py
+++ b/themes/gui_floating_menu.py
@@ -1,7 +1,7 @@
import gradio as gr
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.Row() as row:
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")
- 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.Row() as row:
with gr.Column(scale=10):
diff --git a/themes/init.js b/themes/init.js
index 9ea8dd5a..179223de 100644
--- a/themes/init.js
+++ b/themes/init.js
@@ -3,6 +3,8 @@ async function GptAcademicJavaScriptInit(dark, prompt, live2d, layout, tts) {
audio_fn_init();
minor_ui_adjustment();
ButtonWithDropdown_init();
+ update_conversation_metadata();
+ window.addEventListener("gptac_restore_chat_from_local_storage", restore_chat_from_local_storage);
// 加载欢迎页面
const welcomeMessage = new WelcomeMessage();
diff --git a/themes/theme.py b/themes/theme.py
index 28195774..96c3eed6 100644
--- a/themes/theme.py
+++ b/themes/theme.py
@@ -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 = """
(a,b)=>{
diff --git a/themes/welcome.js b/themes/welcome.js
index 8296b1f5..a6378e5a 100644
--- a/themes/welcome.js
+++ b/themes/welcome.js
@@ -84,7 +84,7 @@ class WelcomeMessage {
this.max_welcome_card_num = 6;
this.card_array = [];
this.static_welcome_message_previous = [];
- this.reflesh_time_interval = 15*1000;
+ this.reflesh_time_interval = 15 * 1000;
const reflesh_render_status = () => {
@@ -105,7 +105,7 @@ class WelcomeMessage {
async startRefleshCards() {
await new Promise(r => setTimeout(r, this.reflesh_time_interval));
await this.reflesh_cards();
- if (this.visible){
+ if (this.visible) {
setTimeout(() => {
this.startRefleshCards.call(this);
}, 1);
@@ -113,7 +113,7 @@ class WelcomeMessage {
}
async reflesh_cards() {
- if (!this.visible){
+ if (!this.visible) {
return;
}
@@ -173,18 +173,18 @@ class WelcomeMessage {
}
shuffle(array) {
- var currentIndex = array.length, randomIndex;
+ var currentIndex = array.length, randomIndex;
// While there remain elements to shuffle...
while (currentIndex != 0) {
- // Pick a remaining element...
- randomIndex = Math.floor(Math.random() * currentIndex);
- currentIndex--;
+ // Pick a remaining element...
+ randomIndex = Math.floor(Math.random() * currentIndex);
+ currentIndex--;
- // And swap it with the current element.
- [array[currentIndex], array[randomIndex]] = [
- array[randomIndex], array[currentIndex]];
+ // And swap it with the current element.
+ [array[currentIndex], array[randomIndex]] = [
+ array[randomIndex], array[currentIndex]];
}
return array;
@@ -193,7 +193,7 @@ class WelcomeMessage {
async update() {
// console.log('update')
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 (this.visible) {
this.removeWelcome();
@@ -203,7 +203,7 @@ class WelcomeMessage {
}
return;
}
- if (this.visible){
+ if (this.visible) {
return;
}
// console.log("welcome");
@@ -220,28 +220,28 @@ class WelcomeMessage {
const title = document.createElement('div');
title.classList.add('welcome-card-title');
- // 创建图标
- const svg = document.createElement('img');
- svg.classList.add('welcome-svg');
- svg.src = message.svg;
- svg.style.height = '30px';
- title.appendChild(svg);
+ // 创建图标
+ const svg = document.createElement('img');
+ svg.classList.add('welcome-svg');
+ svg.src = message.svg;
+ svg.style.height = '30px';
+ title.appendChild(svg);
- // 创建标题
- const text = document.createElement('a');
- text.textContent = message.title;
- text.classList.add('welcome-title-text');
- text.href = message.url;
- text.target = "_blank";
- title.appendChild(text)
+ // 创建标题
+ const text = document.createElement('a');
+ text.textContent = message.title;
+ text.classList.add('welcome-title-text');
+ text.href = message.url;
+ text.target = "_blank";
+ title.appendChild(text)
// 创建内容
const content = document.createElement('div');
content.classList.add('welcome-content');
- const content_c = document.createElement('div');
- content_c.classList.add('welcome-content-c');
- content_c.textContent = message.content;
- content.appendChild(content_c);
+ const content_c = document.createElement('div');
+ content_c.classList.add('welcome-content-c');
+ content_c.textContent = message.content;
+ content.appendChild(content_c);
// 将标题和内容添加到卡片 div 中
card.appendChild(title);
@@ -307,28 +307,28 @@ class WelcomeMessage {
class PageFocusHandler {
constructor() {
- this.hasReturned = false;
- this.focusCallbacks = [];
+ this.hasReturned = false;
+ this.focusCallbacks = [];
- // Bind the focus and blur event handlers
- window.addEventListener('visibilitychange', this.handleFocus.bind(this));
+ // Bind the focus and blur event handlers
+ window.addEventListener('visibilitychange', this.handleFocus.bind(this));
}
// Method to handle the focus event
handleFocus() {
- if (this.hasReturned) {
- this.focusCallbacks.forEach(callback => callback());
- }
- this.hasReturned = true;
+ if (this.hasReturned) {
+ this.focusCallbacks.forEach(callback => callback());
+ }
+ this.hasReturned = true;
}
// Method to add a custom callback function
addFocusCallback(callback) {
- if (typeof callback === 'function') {
- this.focusCallbacks.push(callback);
- } else {
- throw new Error('Callback must be a function');
- }
+ if (typeof callback === 'function') {
+ this.focusCallbacks.push(callback);
+ } else {
+ throw new Error('Callback must be a function');
+ }
}
}
diff --git a/toolbox.py b/toolbox.py
index 060bf8dc..41c75178 100644
--- a/toolbox.py
+++ b/toolbox.py
@@ -8,6 +8,7 @@ import base64
import gradio
import shutil
import glob
+import json
import uuid
from loguru import logger
from functools import wraps
@@ -92,8 +93,9 @@ def ArgsGeneralWrapper(f):
"""
def decorated(request: gradio.Request, cookies:dict, max_length:int, llm_model:str,
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
+ history = json.loads(json_history) if json_history else []
if txt == "" and txt2 != "": txt_passon = txt2
# 引入一个有cookie的chatbot
if request.username is not None:
@@ -148,10 +150,11 @@ def ArgsGeneralWrapper(f):
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(
chatbot, ChatBotWithCookies
), "在传递chatbot的过程中不要将其丢弃。必要时, 可用clear将其清空, 然后用for+append循环重新赋值。"
@@ -175,10 +178,11 @@ def update_ui(chatbot:ChatBotWithCookies, history, msg="正常", **kwargs): #
else:
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="正常"): # 刷新界面
"""
刷新用户界面
"""