support diagram plotting via mermaid !

This commit is contained in:
binary-husky 2024-01-15 02:49:21 +08:00
parent a2099f1622
commit 71adc40901
8 changed files with 1825 additions and 8 deletions

View File

@ -603,6 +603,20 @@ def get_crazy_functions():
except:
print(trimmed_format_exc())
print('Load function plugin failed')
try:
from crazy_functions.高级功能函数模板 import 测试图表渲染
function_plugins.update({
"绘制逻辑关系(测试图表渲染)": {
"Group": "智能体",
"Color": "stop",
"AsButton": True,
"Function": HotReload(测试图表渲染)
}
})
except:
print(trimmed_format_exc())
print('Load function plugin failed')
# try:
# from crazy_functions.chatglm微调工具 import 微调数据集生成

View File

@ -26,4 +26,46 @@ def 高阶功能模板函数(txt, llm_kwargs, plugin_kwargs, chatbot, history, s
)
chatbot[-1] = (i_say, gpt_say)
history.append(i_say);history.append(gpt_say)
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新
PROMPT = """
请你给出围绕{subject}的逻辑关系图使用mermaid语法mermaid语法举例
```mermaid
graph TD
P(编程) --> L1(Python)
P(编程) --> L2(C)
P(编程) --> L3(C++)
P(编程) --> L4(Javascipt)
P(编程) --> L5(PHP)
```
"""
@CatchException
def 测试图表渲染(txt, llm_kwargs, plugin_kwargs, chatbot, history, system_prompt, web_port):
"""
txt 输入栏用户输入的文本例如需要翻译的一段话再例如一个包含了待处理文件的路径
llm_kwargs gpt模型参数如温度和top_p等一般原样传递下去就行
plugin_kwargs 插件模型的参数用于灵活调整复杂功能的各种参数
chatbot 聊天显示框的句柄用于显示给用户
history 聊天历史前情提要
system_prompt 给gpt的静默提醒
web_port 当前软件运行的端口号
"""
history = [] # 清空历史,以免输入溢出
chatbot.append(("这是什么功能?", "一个测试mermaid绘制图表的功能您可以在输入框中输入一些关键词然后使用mermaid+llm绘制图表。"))
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 由于请求gpt需要一段时间我们先及时地做一次界面更新
if txt == "": txt = "空白的输入栏" # 调皮一下
i_say_show_user = f'请绘制有关“{txt}”的逻辑关系图。'
i_say = PROMPT.format(subject=txt)
gpt_say = yield from request_gpt_model_in_new_thread_with_ui_alive(
inputs=i_say,
inputs_show_user=i_say_show_user,
llm_kwargs=llm_kwargs, chatbot=chatbot, history=[],
sys_prompt=""
)
history.append(i_say); history.append(gpt_say)
yield from update_ui(chatbot=chatbot, history=history) # 刷新界面 # 界面更新

View File

@ -3,8 +3,9 @@ import re
import os
import math
from textwrap import dedent
from functools import lru_cache
from pymdownx.superfences import fence_div_format, fence_code_format
from latex2mathml.converter import convert as tex2mathml
from functools import wraps, lru_cache
from shared_utils.config_loader import get_conf as get_conf
pj = os.path.join
@ -17,10 +18,16 @@ markdown_extension_configs = {
},
}
code_highlight_configs = {
"pymdownx.superfences": {
'css_class': 'codehilite',
"custom_fences": [
{
'name': 'mermaid',
'class': 'mermaid',
'format': fence_code_format
}
]
},
"pymdownx.highlight": {
'css_class': 'codehilite',

View File

@ -14,10 +14,24 @@ for filename in os.listdir(directory):
```
Replace 'Tex/' with the actual directory path where your files are located before running the script.
"""
md = """
Following code including wrapper
```mermaid
graph TD
A[Enter Chart Definition] --> B(Preview)
B --> C{decide}
C --> D[Keep]
C --> E[Edit Definition]
E --> B
D --> F[Save Image and Code]
F --> B
```
"""
def validate_path():
import os, sys

View File

@ -229,6 +229,27 @@ 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;
func.apply(this, args);
} else if (!timeoutID) {
timeoutID = setTimeout(() => {
timeoutID = null;
lastInvocationTime = Date.now();
func.apply(this, lastArgs);
}, min_interval - (now - lastInvocationTime));
}
}
}
function chatbotContentChanged(attempt = 1, force = false) {
// https://github.com/GaiZhenbiao/ChuanhuChatGPT/tree/main/web_assets/javascript
for (var i = 0; i < attempt; i++) {
@ -236,6 +257,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(500, function () {
const blocks = document.querySelectorAll(`pre.mermaid, diagram-div`);
if (blocks.length == 0) { return; }
uml("mermaid");
});
run_mermaid_render();
}
@ -660,8 +688,10 @@ function limit_scroll_position() {
}, { passive: false }); // Passive event listener option should be false
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// 第 6 部分: JS初始化函数
// 第 7 部分: JS初始化函数
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
function GptAcademicJavaScriptInit(LAYOUT = "LEFT-RIGHT") {
@ -674,4 +704,6 @@ function GptAcademicJavaScriptInit(LAYOUT = "LEFT-RIGHT") {
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

@ -67,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:

1589
themes/mermaid.min.js vendored Normal file

File diff suppressed because one or more lines are too long

113
themes/mermaid_loader.js Normal file
View File

@ -0,0 +1,113 @@
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
}
// 给出配置 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"
}
}
console.log('启动渲染');
// 加载配置 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.${className}, diagram-div`);
for (let i = 0; i < blocks.length; i++) {
var block = blocks[i]
// const res = await mermaid.render(`_diagram_${i}`, getFromCode(parentEl))
var code = getFromCode(block);
let code2Element = document.createElement("code2"); // 创建一个新的code2元素
let existingCode2Element = block.querySelector("code2"); // 如果block下已存在code2元素则获取它
let codeContent = block.querySelector("code").textContent; // 获取code元素中的文本内容
if(existingCode2Element){ // 如果block下已存在code2元素
existingCode2Element.style.display = "none";
if(existingCode2Element.textContent !== codeContent){
existingCode2Element.textContent = codeContent; // 如果现有的code2元素中的内容与code元素中的内容不同更新code2元素中的内容
}
else{
continue;
}
} else { // 如果不存在code2元素则将code元素中的内容添加到新创建的code2元素中
code2Element.style.display = "none";
code2Element.textContent = codeContent;
block.appendChild(code2Element); // 将新创建的code2元素添加到block中
}
/////////////////////////////////////////////////////////////////
//尝试获取已存在的<div class='mermaid_render'>
let mermaidRender = block.querySelector(".mermaid_render");
if (!mermaidRender) {
mermaidRender = document.createElement("div"); // 不存在,创建新的<div class='mermaid_render'>
mermaidRender.classList.add("mermaid_render");
block.appendChild(mermaidRender); // 将新创建的元素附加到block
}
/////////////////////////////////////////////////////////////////
const content = await mermaid.render(`_diagram_${i}`, code)
mermaidRender.innerHTML = content
}
}