一、背景
利用chatllama的方法进行数据增广,接入chatgpt 4o得到大量创建图表的mermaid代码。投喂大模型第一步就是将mermaid代码渲染成xml,为后续再将xml渲染成jpg提供铺垫。
mermaid介绍
Mermaid 是一种基于 JavaScript 的开源图表生成工具,使用一种简单的 Markdown 风格的语法,创建各种类型的图表和图形,包括流程图、序列图、甘特图、类图等。
得到的JSON文档中包含mermaid代码和markdown代码
二、方法
在 draw.io 网站上自动插入并导出 Mermaid 图表,从json中关键字“id”中的内容作为文件名保存xml文件。
代码功能概述
- validate_mermaid_code:清洗并验证 Mermaid 代码。
def validate_mermaid_code(text):
# 清洗并验证Mermaid代码
if text.startswith('```mermaid') and text.endswith('```'):
text = text[11:-3].strip()
return text
- click_menu_option:模拟点击 draw.io 菜单选项。
def click_menu_option(page, menu_text, option_text):
for ele in page.ele('tag:div@class=geMenubar').eles('tag:a@class=geItem'):
if ele.text == menu_text:
ele.click()
break
for ele in page.eles('tag:td@class=mxPopupMenuItem'):
if ele.text == option_text:
ele.click()
break
- drawio:将 Mermaid 代码插入到 draw.io 中,并导出为 XML 文件。
def drawio(page, text, file_name, error_dir):
try:
click_menu_option(page, '调整图形', '插入')
click_menu_option(page, '插入', '高级')
click_menu_option(page, '高级', 'Mermaid...')
textarea = page.ele(
'tag:textarea@style=box-sizing: border-box; resize: none; width: 100%; height: 354px; margin-bottom: 16px;') #找到重置tag的属性
textarea.clear()
textarea.input(text)
for ele in page.eles('tag:button@class=geBtn gePrimaryBtn'):
if ele.text == '插入':
ele.click()
if page.ele('tag:div@title=出错'):
error_message = page.ele('tag:div@title=出错').text
print(f"Error detected: {error_message}")
page.ele('tag:button@class=geBtn').click()
raise Exception("Error detected in Mermaid code insertion.")
click_menu_option(page, '文件', '导出为')
click_menu_option(page, '导出为', 'XML...')
for ele in page.eles('tag:button@class=geBtn gePrimaryBtn'):
if ele.text == '导出':
ele.click()
ele = page.ele('tag:input@@type=text@@style=box-sizing: border-box; width: 100%;')
if ele.value == "未命名绘图.drawio.xml":
ele.clear()
ele.input(file_name)
page.ele('tag:select@style=text-overflow: ellipsis; grid-column: 1;').select("设备")
ele = page.ele('tag:div@style=flex-basis: 100%; text-align: right; margin-top: 16px;').ele(
'tag:button@class=geBtn gePrimaryBtn')
if ele.text == "保存":
ele.click()
click_menu_option(page, '文件', '关闭')
ele = page.ele('tag:div@style=text-align: center; white-space: nowrap; margin-top: 12px;').ele(
'tag:button@class=geBtn')
if ele.text == "放弃更改":
ele.click()
try:
page.ele('稍后再决定').click()
except:
pass
except Exception as e:
print(f"Error encountered: {e}")
os.makedirs(error_dir, exist_ok=True)
with open(os.path.join(error_dir, file_name.replace('.xml', '.txt')), 'w', encoding='utf-8') as f:
f.write(text)
raise e
- 使用
click_menu_option
依次点击菜单,直到打开 Mermaid 插入窗口。 - 清空文本区域并插入新的 Mermaid 代码。
- 检查是否有错误信息,如果有则处理错误。
- 依次点击菜单,直到导出 XML 文件。
- 处理导出文件的命名和保存。
- 如果遇到异常,创建错误文件夹并将出错的 Mermaid 代码保存到文件中。
- run:读取 JSON 文件中的 Mermaid 代码,并循环处理这些代码,将其插入到 draw.io 并导出。
def run(url, file_list, start_idx=0):
page = WebPage()
page.get(url)
try:
page.ele('稍后再决定').click()
except:
pass
for cnt, text in tqdm(enumerate(file_list[start_idx:]), total=6500):
try:
file_name = f"{text['id'].replace('#', '_')}.xml"
validated_text = validate_mermaid_code(text['answer_mode4'])
drawio(page, validated_text, file_name, error_dir='./error_output')
os.makedirs("./output", exist_ok=True)
with open(f"./output/{text['id'].replace('#', '_')}.txt", 'w', encoding='utf-8') as f:
f.write(text['answer_mode4'])
except Exception as e:
print(f"Failed | {e}")
continue
这里是最麻烦的,网页卡住不动,程序就死掉了。需要设想好各种情况,如果出错或者网页崩溃,能够做到自更新。
main函数
if __name__ == '__main__':
url = "https://app.diagrams.net/"
data = []
with open(r'g1149_syn_mermaid_v2.json', 'r', encoding='utf-8') as f:
for line in f.readlines():
rec = json.loads(line.strip())
if 'answer_mode4' in rec:
text = rec['answer_mode4']
data.append({"id": rec['id'], "answer_mode4": text})
run(url, data, start_idx=0) #设置start_idx方便调试
三、实际问题
1、需要科学上网才能跑,如果科学上网工具不行,网络波动大,那这个是跑不了的。
2、页面容易崩溃,崩溃后需要手动重启,这是最抓马的。大概4h崩溃一次。所以添加调试功能非常重要。
3、生成流程图的时候很快,但是在保存xml的时候就很慢很慢,我搜索了很多资料,也问了老师,老师说是页面渲染需要时间,无法解决。但是我知道肯定不是这样的原因,如果有大佬能优化这个,球球告知分享。
4、开始时,窗口要最大化,不然第一条的属性栏会莫名其貌的被隐藏。导致程序无法正常运行。
四、完整代码
# -*- coding: utf-8 -*-
import os
import json
from DrissionPage import WebPage
from tqdm import tqdm
def validate_mermaid_code(text):
# 清洗并验证Mermaid代码
if text.startswith('```mermaid') and text.endswith('```'):
text = text[11:-3].strip()
return text
def click_menu_option(page, menu_text, option_text):
for ele in page.ele('tag:div@class=geMenubar').eles('tag:a@class=geItem'):
if ele.text == menu_text:
ele.click()
break
for ele in page.eles('tag:td@class=mxPopupMenuItem'):
if ele.text == option_text:
ele.click()
break
def drawio(page, text, file_name, error_dir):
try:
print("Attempting to insert and export Mermaid code.")
click_menu_option(page, '调整图形', '插入')
click_menu_option(page, '插入', '高级')
click_menu_option(page, '高级', 'Mermaid...')
textarea = page.ele(
'tag:textarea@style=box-sizing: border-box; resize: none; width: 100%; height: 354px; margin-bottom: 16px;')
textarea.clear()
textarea.input(text)
for ele in page.eles('tag:button@class=geBtn gePrimaryBtn'):
if ele.text == '插入':
ele.click()
# 检查是否有错误信息
if page.ele('tag:div@title=出错'):
error_message = page.ele('tag:div@title=出错').text
print(f"Error detected: {error_message}")
# 点击确认按钮
page.ele('tag:button@class=geBtn').click()
raise Exception("Error detected in Mermaid code insertion.")
click_menu_option(page, '文件', '导出为')
click_menu_option(page, '导出为', 'XML...')
for ele in page.eles('tag:button@class=geBtn gePrimaryBtn'):
if ele.text == '导出':
ele.click()
ele = page.ele('tag:input@@type=text@@style=box-sizing: border-box; width: 100%;')
if ele.value == "未命名绘图.drawio.xml":
ele.clear()
ele.input(file_name)
page.ele('tag:select@style=text-overflow: ellipsis; grid-column: 1;').select("设备")
ele = page.ele('tag:div@style=flex-basis: 100%; text-align: right; margin-top: 16px;').ele(
'tag:button@class=geBtn gePrimaryBtn')
if ele.text == "保存":
ele.click()
click_menu_option(page, '文件', '关闭')
ele = page.ele('tag:div@style=text-align: center; white-space: nowrap; margin-top: 12px;').ele(
'tag:button@class=geBtn')
if ele.text == "放弃更改":
ele.click()
try:
page.ele('稍后再决定').click()
except:
pass
except Exception as e:
print(f"Error encountered: {e}")
# 将出错文件复制到新文件夹
os.makedirs(error_dir, exist_ok=True)
with open(os.path.join(error_dir, file_name.replace('.xml', '.txt')), 'w', encoding='utf-8') as f:
f.write(text)
raise e
def run(url, file_list, start_idx=0):
page = WebPage()
page.get(url)
try:
page.ele('稍后再决定').click()
except:
pass
for cnt, text in tqdm(enumerate(file_list[start_idx:]),total=6500):
try:
# 使用文件名中的ID命名文件
file_name = f"{text['id'].replace('#', '_')}.xml"
validated_text = validate_mermaid_code(text['answer_mode4'])
drawio(page, validated_text, file_name, error_dir='./error_output')
# 写入TXT文件
os.makedirs("./output", exist_ok=True)
with open(f"./output/{text['id'].replace('#', '_')}.txt", 'w', encoding='utf-8') as f:
f.write(text['answer_mode4'])
except Exception as e:
print(f"Failed | {e}")
continue
if __name__ == '__main__':
url = "https://app.diagrams.net/"
data = []
with open(r'g1149_syn_mermaid_v2.json', 'r', encoding='utf-8') as f:
for line in f.readlines():
rec = json.loads(line.strip())
if 'answer_mode4' in rec:
text = rec['answer_mode4']
data.append({"id": rec['id'], "answer_mode4": text})
run(url, data, start_idx=0)
五、后续工作
将渲染的xml文件再次渲染为JPG文件 。
标签:xml,text,ele,click,tag,diagrams,menu,page,mermaid From: https://blog.csdn.net/weixin_46636042/article/details/139835570