# -*- coding:utf-8 -*- from __future__ import annotations import html import logging import re import mdtex2html from markdown import markdown from pygments import highlight from pygments.formatters import HtmlFormatter from pygments.lexers import ClassNotFound from pygments.lexers import guess_lexer, get_lexer_by_name from app_modules.presets import * logging.basicConfig( level=logging.INFO, format="%(asctime)s [%(levelname)s] [%(filename)s:%(lineno)d] %(message)s", ) def markdown_to_html_with_syntax_highlight(md_str): def replacer(match): lang = match.group(1) or "text" code = match.group(2) lang = lang.strip() # print(1,lang) if lang == "text": lexer = guess_lexer(code) lang = lexer.name # print(2,lang) try: lexer = get_lexer_by_name(lang, stripall=True) except ValueError: lexer = get_lexer_by_name("python", stripall=True) formatter = HtmlFormatter() # print(3,lexer.name) highlighted_code = highlight(code, lexer, formatter) return f'
{highlighted_code}
' code_block_pattern = r"```(\w+)?\n([\s\S]+?)\n```" md_str = re.sub(code_block_pattern, replacer, md_str, flags=re.MULTILINE) html_str = markdown(md_str) return html_str def normalize_markdown(md_text: str) -> str: lines = md_text.split("\n") normalized_lines = [] inside_list = False for i, line in enumerate(lines): if re.match(r"^(\d+\.|-|\*|\+)\s", line.strip()): if not inside_list and i > 0 and lines[i - 1].strip() != "": normalized_lines.append("") inside_list = True normalized_lines.append(line) elif inside_list and line.strip() == "": if i < len(lines) - 1 and not re.match( r"^(\d+\.|-|\*|\+)\s", lines[i + 1].strip() ): normalized_lines.append(line) continue else: inside_list = False normalized_lines.append(line) return "\n".join(normalized_lines) def convert_mdtext(md_text): code_block_pattern = re.compile(r"```(.*?)(?:```|$)", re.DOTALL) inline_code_pattern = re.compile(r"`(.*?)`", re.DOTALL) code_blocks = code_block_pattern.findall(md_text) non_code_parts = code_block_pattern.split(md_text)[::2] result = [] for non_code, code in zip(non_code_parts, code_blocks + [""]): if non_code.strip(): non_code = normalize_markdown(non_code) if inline_code_pattern.search(non_code): result.append(markdown(non_code, extensions=["tables"])) else: result.append(mdtex2html.convert(non_code, extensions=["tables"])) if code.strip(): # _, code = detect_language(code) # 暂时去除代码高亮功能,因为在大段代码的情况下会出现问题 # code = code.replace("\n\n", "\n") # 暂时去除代码中的空行,因为在大段代码的情况下会出现问题 code = f"\n```{code}\n\n```" code = markdown_to_html_with_syntax_highlight(code) result.append(code) result = "".join(result) result += ALREADY_CONVERTED_MARK return result def convert_asis(userinput): return f"

{html.escape(userinput)}

" + ALREADY_CONVERTED_MARK def detect_converted_mark(userinput): if userinput.endswith(ALREADY_CONVERTED_MARK): return True else: return False def detect_language(code): if code.startswith("\n"): first_line = "" else: first_line = code.strip().split("\n", 1)[0] language = first_line.lower() if first_line else "" code_without_language = code[len(first_line):].lstrip() if first_line else code return language, code_without_language def convert_to_markdown(text): text = text.replace("$", "$") def replace_leading_tabs_and_spaces(line): new_line = [] for char in line: if char == "\t": new_line.append(" ") elif char == " ": new_line.append(" ") else: break return "".join(new_line) + line[len(new_line):] markdown_text = "" lines = text.split("\n") in_code_block = False for line in lines: if in_code_block is False and line.startswith("```"): in_code_block = True markdown_text += "```\n" elif in_code_block is True and line.startswith("```"): in_code_block = False markdown_text += "```\n" elif in_code_block: markdown_text += f"{line}\n" else: line = replace_leading_tabs_and_spaces(line) line = re.sub(r"^(#)", r"\\\1", line) markdown_text += f"{line} \n" return markdown_text def add_language_tag(text): def detect_language(code_block): try: lexer = guess_lexer(code_block) return lexer.name.lower() except ClassNotFound: return "" code_block_pattern = re.compile(r"(```)(\w*\n[^`]+```)", re.MULTILINE) def replacement(match): code_block = match.group(2) if match.group(2).startswith("\n"): language = detect_language(code_block) if language: return f"```{language}{code_block}```" else: return f"```\n{code_block}```" else: return match.group(1) + code_block + "```" text2 = code_block_pattern.sub(replacement, text) return text2 def delete_last_conversation(chatbot, history): if len(chatbot) > 0: chatbot.pop() if len(history) > 0: history.pop() return ( chatbot, history, "Delete Done", ) def reset_state(): return [], [], "Reset Done" def reset_textbox(): return gr.update(value=""), "" def cancel_outputing(): return "Stop Done" def transfer_input(inputs): # 一次性返回,降低延迟 textbox = reset_textbox() return ( inputs, gr.update(value=""), gr.Button.update(visible=True), ) class State: interrupted = False def interrupt(self): self.interrupted = True def recover(self): self.interrupted = False shared_state = State()