diff --git a/__main__.py b/__main__.py index 7560b97..9ba62ad 100644 --- a/__main__.py +++ b/__main__.py @@ -79,7 +79,7 @@ class ChatBot(ChatBotFrame): with gr.Box(elem_id='chat_box'): with gr.Row(): gr.Button(elem_classes='sm_btn').style(size='sm', full_width=False) - gr.HTML(func_box.get_html("appearance_switcher.html").format(label=""), elem_classes="insert_block") + gr.HTML(func_box.get_html("appearance_switcher.html").format(label=""), elem_id='user_input_tb', elem_classes="insert_block") with gr.Row(): self.txt = gr.Textbox(show_label=False, placeholder="Input question here.", elem_classes='chat_input').style(container=False) self.input_copy = gr.State('') @@ -186,7 +186,7 @@ class ChatBot(ChatBotFrame): self.pro_func_prompt, self.pro_fp_state]) self.pro_reuse_btn.click( fn=func_box.reuse_chat, - inputs=[self.pro_results, self.chatbot, self.history, self.pro_name_txt], + inputs=[self.pro_results, self.chatbot, self.history, self.pro_name_txt, self.txt], outputs=[self.chatbot, self.history, self.txt, self.tabs_chatbot, self.pro_name_txt, self.examples_column] ) @@ -312,7 +312,7 @@ class ChatBot(ChatBotFrame): self.cancel_handles.append(self.txt.submit(**self.clear_agrs).then(**self.predict_args)) self.cancel_handles.append(self.submitBtn.click(**self.clear_agrs).then(**self.predict_args)) # self.cpopyBtn.click(fn=func_box.copy_result, inputs=[self.history], outputs=[self.status]) - self.resetBtn.click(lambda: ([], [], "已重置"), None, [self.chatbot, self.history, self.status]) + self.resetBtn.click(lambda: ([], [], "已重置"), None, [self.chatbot, self.history, self.status], _js='()=>{clearHistoryHtml();}') def signals_function(self): # 基础功能区的回调函数注册 diff --git a/docs/assets/custom.js b/docs/assets/custom.js index 9a07884..0100a6a 100644 --- a/docs/assets/custom.js +++ b/docs/assets/custom.js @@ -9,7 +9,7 @@ var user_input_ta; var gradioContainer = null; var user_input_ta = null; -var chat_txt = null; +var user_input_tb = null; var userInfoDiv = null; var appTitleDiv = null; var chatbot = null; @@ -55,11 +55,11 @@ function gradioLoaded(mutations) { if (mutations[i].addedNodes.length) { loginUserForm = document.querySelector(".gradio-container > .main > .wrap > .panel > .form") gradioContainer = document.querySelector(".gradio-container"); - chat_txt = document.getElementById('chat_txt'); + user_input_tb = document.getElementById('user_input_tb'); userInfoDiv = document.getElementById("user_info"); appTitleDiv = document.getElementById("app_title"); - chatbot = document.querySelector('#废弃'); - chatbotWrap = document.querySelector('#废弃 > .wrap'); + chatbot = document.querySelector('#main_chatbot'); + chatbotWrap = document.querySelector('#main_chatbot > .wrap'); apSwitch = document.querySelector('.apSwitch input[type="checkbox"]'); if (loginUserForm) { @@ -70,21 +70,18 @@ function gradioLoaded(mutations) { if (gradioContainer && apSwitch) { // gradioCainter 加载出来了没? adjustDarkMode(); } - if (chat_txt) { // chat_txt 加载出来了没? - selectHistory(); + if (user_input_tb) { // user_input_tb 加载出来了没? } if (userInfoDiv && appTitleDiv) { // userInfoDiv 和 appTitleDiv 加载出来了没? if (!usernameGotten) { getUserInfo(); } - setTimeout(showOrHideUserInfo(), 2000); } if (chatbot) { // chatbot 加载出来了没? setChatbotHeight(); } if (chatbotWrap) { if (!historyLoaded) { - loadHistoryHtml(); } setChatbotScroll(); } @@ -116,54 +113,6 @@ function showConfirmationDialog(a, file, c) { return [a, "CANCELED", c]; } -function selectHistory() { - user_input_ta = chat_txt.querySelector("textarea"); - if (user_input_ta) { - observer.disconnect(); // 停止监听 - // 在 textarea 上监听 keydown 事件 - user_input_ta.addEventListener("keydown", function (event) { - var value = user_input_ta.value.trim(); - // 判断按下的是否为方向键 - if (event.code === 'ArrowUp' || event.code === 'ArrowDown') { - // 如果按下的是方向键,且输入框中有内容,且历史记录中没有该内容,则不执行操作 - if (value && key_down_history.indexOf(value) === -1) - return; - // 对于需要响应的动作,阻止默认行为。 - event.preventDefault(); - var length = key_down_history.length; - if (length === 0) { - currentIndex = -1; // 如果历史记录为空,直接将当前选中的记录重置 - return; - } - if (currentIndex === -1) { - currentIndex = length; - } - if (event.code === 'ArrowUp' && currentIndex > 0) { - currentIndex--; - user_input_ta.value = key_down_history[currentIndex]; - } else if (event.code === 'ArrowDown' && currentIndex < length - 1) { - currentIndex++; - user_input_ta.value = key_down_history[currentIndex]; - } - user_input_ta.selectionStart = user_input_ta.value.length; - user_input_ta.selectionEnd = user_input_ta.value.length; - const input_event = new InputEvent("input", { bubbles: true, cancelable: true }); - user_input_ta.dispatchEvent(input_event); - } else if (event.code === "Enter") { - if (value) { - currentIndex = -1; - if (key_down_history.indexOf(value) === -1) { - key_down_history.push(value); - if (key_down_history.length > MAX_HISTORY_LENGTH) { - key_down_history.shift(); - } - } - } - } - }); - } -} - var username = null; function getUserInfo() { if (usernameGotten) { @@ -186,7 +135,6 @@ function getUserInfo() { username = username.match(/User:\s*(.*)/)[1] || username; localStorage.setItem("username", username); usernameGotten = true; - clearHistoryHtml(); } } } @@ -413,8 +361,7 @@ var mObserver = new MutationObserver(function (mutationsList) { if (mmutation.type === 'childList') { for (var node of mmutation.addedNodes) { if (node.nodeType === 1 && node.classList.contains('message') && node.getAttribute('data-testid') === 'bot') { - saveHistoryHtml(); - document.querySelectorAll('#废弃>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton); + document.querySelectorAll('#main_chatbot>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton); } if (node.tagName === 'INPUT' && node.getAttribute('type') === 'range') { setSlider(); @@ -422,8 +369,7 @@ var mObserver = new MutationObserver(function (mutationsList) { } for (var node of mmutation.removedNodes) { if (node.nodeType === 1 && node.classList.contains('message') && node.getAttribute('data-testid') === 'bot') { - saveHistoryHtml(); - document.querySelectorAll('#废弃>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton); + document.querySelectorAll('#main_chatbot>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton); } } } else if (mmutation.type === 'attributes') { @@ -433,8 +379,7 @@ var mObserver = new MutationObserver(function (mutationsList) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { isThrottled = false; - document.querySelectorAll('#废弃>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton); - saveHistoryHtml(); + document.querySelectorAll('#main_chatbot>.wrap>.message-wrap .message.bot').forEach(addChuanhuButton); }, 500); } } @@ -442,59 +387,6 @@ var mObserver = new MutationObserver(function (mutationsList) { }); mObserver.observe(document.documentElement, { attributes: true, childList: true, subtree: true }); -var loadhistorytime = 0; // for debugging -function saveHistoryHtml() { - var historyHtml = document.querySelector('#废弃 > .wrap'); - localStorage.setItem('chatHistory', historyHtml.innerHTML); - // console.log("History Saved") - historyLoaded = false; -} -function loadHistoryHtml() { - var historyHtml = localStorage.getItem('chatHistory'); - if (!historyHtml) { - historyLoaded = true; - return; // no history, do nothing - } - userLogged = localStorage.getItem('userLogged'); - if (userLogged){ - historyLoaded = true; - return; // logged in, do nothing - } - if (!historyLoaded) { - var tempDiv = document.createElement('div'); - tempDiv.innerHTML = historyHtml; - var buttons = tempDiv.querySelectorAll('button.chuanhu-btn'); - var gradioCopyButtons = tempDiv.querySelectorAll('button.copy_code_button'); - for (var i = 0; i < buttons.length; i++) { - buttons[i].parentNode.removeChild(buttons[i]); - } - for (var i = 0; i < gradioCopyButtons.length; i++) { - gradioCopyButtons[i].parentNode.removeChild(gradioCopyButtons[i]); - } - var fakeHistory = document.createElement('div'); - fakeHistory.classList.add('history-message'); - fakeHistory.innerHTML = tempDiv.innerHTML; - webLocale(); - chatbotWrap.insertBefore(fakeHistory, chatbotWrap.firstChild); - // var fakeHistory = document.createElement('div'); - // fakeHistory.classList.add('history-message'); - // fakeHistory.innerHTML = historyHtml; - // chatbotWrap.insertBefore(fakeHistory, chatbotWrap.firstChild); - historyLoaded = true; - console.log("History Loaded"); - loadhistorytime += 1; // for debugging - } else { - historyLoaded = false; - } -} -function clearHistoryHtml() { - localStorage.removeItem("chatHistory"); - historyMessages = chatbotWrap.querySelector('.history-message'); - if (historyMessages) { - chatbotWrap.removeChild(historyMessages); - console.log("History Cleared"); - } -} // 监视页面内部 DOM 变动 var observer = new MutationObserver(function (mutations) { @@ -502,11 +394,6 @@ var observer = new MutationObserver(function (mutations) { }); observer.observe(targetNode, { childList: true, subtree: true }); -// 监视页面变化 -window.addEventListener("DOMContentLoaded", function () { - isInIframe = (window.self !== window.top); - historyLoaded = false; -}); window.addEventListener('resize', setChatbotHeight); window.addEventListener('scroll', setChatbotHeight); window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", adjustDarkMode); diff --git a/docs/test_markdown_format.py b/docs/test_markdown_format.py index 896f6f1..74ba8f5 100644 --- a/docs/test_markdown_format.py +++ b/docs/test_markdown_format.py @@ -49,7 +49,7 @@ def markdown_convertion(txt): """ 将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。 """ - pre = '
' + pre = '
' suf = '
' if txt.startswith(pre) and txt.endswith(suf): # print('警告,输入了已经经过转化的字符串,二次转化可能出问题') diff --git a/func_box.py b/func_box.py index 4123c24..3b80c61 100644 --- a/func_box.py +++ b/func_box.py @@ -32,6 +32,7 @@ import random import gradio as gr import toolbox from prompt_generator import SqliteHandle +from bs4 import BeautifulSoup """contextlib 是 Python 标准库中的一个模块,提供了一些工具函数和装饰器,用于支持编写上下文管理器和处理上下文的常见任务,例如资源管理、异常处理等。 官网:https://docs.python.org/3/library/contextlib.html""" @@ -498,19 +499,22 @@ def show_prompt_result(index, data: gr.Dataset, chatbot): return chatbot -pattern_markdown = re.compile(r'^

|<\/p><\/div>$') -pattern_markdown_p = re.compile(r'^

|<\/div>$') + +def pattern_html(html): + bs = BeautifulSoup(html, 'html.parser') + return bs.get_text(separator='') + def thread_write_chat(chatbot, history): """ 对话记录写入数据库 """ private_key = toolbox.get_conf('private_key')[0] chat_title = chatbot[0][1].split() - i_say = pattern_markdown.sub('', chatbot[-1][0]) + i_say = pattern_html(chatbot[-1][0]) if history: gpt_result = history else: # 如果历史对话不存在,那么读取对话框 - gpt_result = [pattern_markdown.sub('', v) for i in chatbot for v in i] + gpt_result = [pattern_html(v) for i in chatbot for v in i] if private_key in chat_title: SqliteHandle(f'ai_private_{chat_title[-2]}').inset_prompt({i_say: gpt_result}) else: @@ -520,20 +524,19 @@ def thread_write_chat(chatbot, history): base_path = os.path.dirname(__file__) prompt_path = os.path.join(base_path, 'users_data') -def reuse_chat(result, chatbot, history, pro_numb): +def reuse_chat(result, chatbot, history, pro_numb, say): """复用对话记录""" if result is None or result == []: return chatbot, history, gr.update(), gr.update(), '', gr.Column.update() else: if pro_numb: chatbot += result - history += [pattern_markdown.sub('', _) for i in result for _ in i] + history += [pattern_html(_) for i in result for _ in i] else: chatbot.append(result[-1]) - history += [pattern_markdown.sub('', _) for i in result[-2:] for _ in i] + history += [pattern_html(_) for i in result[-2:] for _ in i] print(chatbot[-1][0]) - i_say = pattern_markdown.sub('', chatbot[-1][0]) - return chatbot, history, i_say, gr.Tabs.update(selected='chatbot'), '', gr.Column.update(visible=False) + return chatbot, history, say, gr.Tabs.update(selected='chatbot'), '', gr.Column.update(visible=False) def num_tokens_from_string(listing: list, encoding_name: str = 'cl100k_base') -> int: @@ -550,10 +553,8 @@ def spinner_chatbot_loading(chatbot): # 将元组转换为列表并修改元素 loading_msg = copy.deepcopy(chatbot) temp_list = list(loading_msg[-1]) - if pattern_markdown.match(temp_list[1]): - temp_list[1] = pattern_markdown.sub('', temp_list[1]) + f'{random.choice(loading)}' - else: - temp_list[1] = pattern_markdown_p.sub('', temp_list[1]) + f'{random.choice(loading)}' + + temp_list[1] = pattern_html(temp_list[1]) + f'{random.choice(loading)}' # 将列表转换回元组并替换原始元组 loading_msg[-1] = tuple(temp_list) return loading_msg diff --git a/theme.py b/theme.py index 7a99211..ed39e45 100644 --- a/theme.py +++ b/theme.py @@ -182,26 +182,26 @@ textarea { width: 100%; height: 100%; } -.markdown-body table { +.md-message table { margin: 1em 0; border-collapse: collapse; empty-cells: show; } -.markdown-body th, .markdown-body td { +.md-message th, .md-message td { border: 1.2px solid var(--border-color-primary); padding: 5px; } -.markdown-body thead { +.md-message thead { background-color: rgba(175,184,193,0.2); } -.markdown-body thead th { +.md-message thead th { padding: .5em .2em; } -.markdown-body ol, .markdown-body ul { +.md-message ol, .md-message ul { padding-inline-start: 2em !important; } @@ -240,7 +240,7 @@ textarea { } /* linein code block. */ -.markdown-body code { +.md-message code { display: inline; white-space: break-spaces; border-radius: 6px; @@ -250,7 +250,7 @@ textarea { color: #eff0f2; } -.dark .markdown-body code { +.dark .md-message code { display: inline; white-space: break-spaces; border-radius: 6px; @@ -260,7 +260,7 @@ textarea { } /* code block css */ -.markdown-body pre code { +.md-message pre code { display: block; overflow: auto; white-space: pre; @@ -270,7 +270,7 @@ textarea { margin: 1em 2em 1em 0.5em; } -.dark .markdown-body pre code { +.dark .md-message pre code { display: block; overflow: auto; white-space: pre; diff --git a/toolbox.py b/toolbox.py index 2755da1..286131e 100644 --- a/toolbox.py +++ b/toolbox.py @@ -1,3 +1,5 @@ +import html + import markdown import importlib import inspect @@ -297,8 +299,9 @@ def markdown_convertion(txt): """ 将Markdown格式的文本转换为HTML格式。如果包含数学公式,则先将公式转换为HTML格式。 """ - pre = '
' + pre = '
' suf = '
' + raw_hide = f'
%s
' if txt.startswith(pre) and txt.endswith(suf): # print('警告,输入了已经经过转化的字符串,二次转化可能出问题') return txt # 已经被转化过,不需要再次转化 @@ -362,9 +365,11 @@ def markdown_convertion(txt): convert_stage_1_resp = convert_stage_1.replace('
', '') convert_stage_2_2, n = re.subn(find_equation_pattern, replace_math_render, convert_stage_1_resp, flags=re.DOTALL) # cat them together - return pre + convert_stage_2_1 + f'{split}' + convert_stage_2_2 + suf + context = convert_stage_2_1 + f'{split}' + convert_stage_2_2 + return raw_hide.replace('%s', func_box.pattern_html(context)) + pre + context + suf else: - return pre + markdown.markdown(txt, extensions=['fenced_code', 'codehilite', 'tables', 'sane_lists']) + suf + context = markdown.markdown(txt, extensions=['fenced_code', 'codehilite', 'tables', 'sane_lists']) + return raw_hide.replace('%s', func_box.pattern_html(context)) + pre + context + suf def close_up_code_segment_during_stream(gpt_reply):