|
""" |
|
1. 用Mermaid Mardown来画各种图,包括:脑图、流程图、客户历程图、关系图等。 |
|
1. 目前ChatGPT级别和百度文星一言等级别的大模型都可以比较好的输出Mermaid Markdown格式图。 |
|
1. 注意Mermaid代码中,不需要任何的’‘’, ````,或者"",这里只需要直接写Mermaid代码即可。 |
|
1. 完成了regenerate功能。 |
|
1. 完成了历史记忆功能,可以对图进行持续优化。但是不能保存中间结果。 |
|
|
|
1. 已知问题和解决方法: |
|
1. 已解决。尝试了多个方法,目前无法把HTML展现的内容用图片保存,目前不行。直接保存MHTML文件。 |
|
1. HTML文件本身可以保存。 |
|
1. 用html2image库,可以把HTML文件转换为图片,但是无法在streamlit中展示(内容为空白)。 |
|
1. 可以想到的workaround:把HTML页面保存下来。 |
|
1. HTML的高度只能手工制定,无法自动调整。可能垂直的页面会被截断。已经解决,通过设定scrolling=True, 可以实现滚动条。高度不在重要。 |
|
1. 已解决。点击下载button后,页面会刷新。采用一个特殊的extension,https://github.com/PaleNeutron/streamlit-ext |
|
""" |
|
|
|
|
|
import json |
|
import pprint |
|
import streamlit as st |
|
import chatgpt |
|
|
|
import markdown |
|
import md_mermaid |
|
|
|
import requests |
|
import re |
|
from openai import OpenAI |
|
import streamlit_authenticator as stauth |
|
|
|
|
|
import streamlit_ext as ste |
|
|
|
from datetime import datetime |
|
from pytz import timezone |
|
|
|
|
|
st.set_page_config(layout="wide", page_icon='llm_icon.png') |
|
st.title(f"大语言模型 - 体系图 | 框架图 | 逻辑图 | 流程图 - 辅助设计中心", anchor='Title') |
|
st.subheader("AI Flowchart - Mindmap - Relation Diagram Design for Professionals") |
|
st.info('如果输出图例时遇见任何问题(如:syntax error)或者不满意当前结果,请在左侧重新提交您的问题即可。一般建议至少尝试3-10次。') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openai_client = OpenAI() |
|
|
|
|
|
system_prompt = f"""你是一个Mermaid Markdown方面的设计专家。你需要根据'我的要求'用Mermaid Markdown来画出对应的图。你仅需要提供Mermaid Markdown格式的代码,你不允许输出任何说明、解释或者提示的内容。""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
if "messages" not in st.session_state: |
|
st.session_state.messages = [] |
|
|
|
|
|
|
|
|
|
|
|
|
|
user_input = st.chat_input("说点什么吧...") |
|
|
|
|
|
|
|
|
|
|
|
print('st.session_state.messages:') |
|
pprint.pprint(st.session_state.messages) |
|
|
|
print('user_input now:') |
|
pprint.pprint(user_input) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def clear_all(): |
|
st.session_state.conversation = None |
|
st.session_state.chat_history = None |
|
st.session_state.messages = [] |
|
message_placeholder = st.empty() |
|
st.session_state["my_question"] = None |
|
return None |
|
|
|
|
|
|
|
|
|
def regenerate(): |
|
html_file = "" |
|
|
|
try: |
|
print('st.session_state.messages inside REGENERATE function:') |
|
pprint.pprint(st.session_state.messages) |
|
st.session_state.messages = st.session_state.messages[:-1] |
|
html_file = main(input=st.session_state.messages[0]['content']) |
|
|
|
except Exception as e: |
|
print('Error:', e) |
|
pass |
|
|
|
return html_file |
|
|
|
|
|
import yaml |
|
from yaml.loader import SafeLoader |
|
with open('./config.yaml') as file: |
|
config = yaml.load(file, Loader=SafeLoader) |
|
authenticator = stauth.Authenticate( |
|
config['credentials'], |
|
config['cookie']['name'], |
|
config['cookie']['key'], |
|
config['cookie']['expiry_days'], |
|
config['preauthorized'] |
|
) |
|
|
|
user, authentication_status, username = authenticator.login('main') |
|
|
|
|
|
|
|
|
|
if authentication_status: |
|
with st.sidebar: |
|
st.markdown( |
|
""" |
|
<style> |
|
[data-testid="stSidebar"][aria-expanded="true"]{ |
|
min-width: 450px; |
|
max-width: 450px; |
|
} |
|
""", |
|
unsafe_allow_html=True, |
|
) |
|
|
|
|
|
|
|
|
|
st.header(f'**欢迎 **{username}** 来到人工智能的世界** ♠') |
|
|
|
st.write(f'_Large Language Model System Environment_') |
|
authenticator.logout('登出', 'sidebar') |
|
|
|
|
|
st.sidebar.button("清除记录,重启一轮新对话", on_click=clear_all, use_container_width=True, type='primary') |
|
re_btn = st.sidebar.button("重新生成答案", use_container_width=True, type='secondary') |
|
|
|
|
|
|
|
|
|
|
|
|
|
tab_1, tab_2, tab_3, tab_4 = st.tabs(['基本介绍', '大模型参数', '提示词示例', '使用技巧']) |
|
|
|
|
|
with tab_1: |
|
|
|
|
|
|
|
with st.text(body="说明"): |
|
st.markdown("""* **使用大型语言模型设计体系图、框架图、逻辑图、流程图、关系图主要有以下几个步骤:** |
|
|
|
1. **明确目的和要表达的内容** |
|
在开始之前,你需要明确你想用图表来表达什么内容, 以及它的目的是什么。这将为接下来的步骤提供指导。 |
|
|
|
2. **收集并组织相关信息** |
|
根据你的目的,收集所有相关的信息、数据和要点。将它们按合理的方式分类和组织, 为后续生成图表做好准备。 |
|
|
|
3. **结构化输入** |
|
将组织好的内容转化为语言模型可以理解的结构化输入。比如使用简单描述、列表、树状结构等形式。 |
|
|
|
4. **生成参考版本** |
|
将结构化输入提交给大型语言模型, 让它尝试生成供参考的流程图、脑图或关系图。 |
|
|
|
* 需要注意的是, 尽管大型语言模型可以生成很好的草图和初始版本, 但最终结果的质量仍然取决于你对目标和输入的描述质量。人工审查和调整是必不可少的环节。模型只是辅助工具, 无法完全替代人的判断和创造力。""") |
|
|
|
|
|
|
|
with tab_2: |
|
max_tokens = st.slider(label='Max_Token(生成结果时最大字数)', min_value=100, max_value=4096, value=2048, step=100) |
|
temperature = st.slider(label='Temperature (温度)', min_value=0.0, max_value=1.0, value=0.8, step=0.1) |
|
top_p = st.slider(label='Top_P (核采样)', min_value=0.0, max_value=1.0, value=0.6, step=0.1) |
|
frequency_penalty = st.slider(label='Frequency Penalty (重复度惩罚因子)', min_value=-2.0, max_value=2.0, value=1.0, step=0.1) |
|
presence_penalty = st.slider(label='Presence Penalty (控制主题的重复度)', min_value=-2.0, max_value=2.0, value=1.0, step=0.1) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with tab_3: |
|
|
|
st.code(body="你输出一个复杂的电子商务流程示意图,必须包含客户投诉退款环节。", language='plaintext') |
|
st.code(body="给我一个复杂的业务需求分析流程图。", language='plaintext') |
|
st.code(body="完整的Hermes客户体验流程图。", language='plaintext') |
|
st.code(body="完整的苹果公司线下实体店客户历程图。", language='plaintext') |
|
st.code(body="绘制一个横向的详细的IT运维流程示例。", language='plaintext') |
|
st.code(body="画一个汽车4S店的用户历程的复杂流程(至少要包含:客户邀约,客户试驾等)。", language='plaintext') |
|
st.code(body="绘制一张保险项目的甘特图。", language='plaintext') |
|
st.code(body="画一个用户历程的复杂流程。", language='plaintext') |
|
st.code(body="绘制一张复杂的绩效管理脑图。", language='plaintext') |
|
st.code(body="给我一个复杂的客户体验脑图示例。", language='plaintext') |
|
st.code(body="你给我一个全面质量管理的头脑风暴脑图。", language='plaintext') |
|
st.code(body="给我一个全面且复杂的精益管理流程图,图上需要每一步的说明。", language='plaintext') |
|
st.code(body="你做一个青少儿教育培训机构的完整电话邀约流程。", language='plaintext') |
|
st.code(body="在上面流程的基础上,继续细化”系统设计“部分的内容。", language='plaintext') |
|
|
|
with tab_4: |
|
st.markdown(''' |
|
1. 使用`下载图例`按钮,可以直接下载MHTML格式的文件,大部分浏览器支持直接打开。 |
|
|
|
1. 使用`下载代码`按钮,可以下载原始的Markdown代码,然后可以在类似 `https://mermaid.live/` 网站手动编辑。 |
|
|
|
1. 目前支持持续修改流程版本,但不建议过度修改。修改的中间过程内容不会被保存。 |
|
''') |
|
|
|
|
|
elif authentication_status == False: |
|
st.error('⛔ 用户名或密码错误!') |
|
elif authentication_status == None: |
|
st.warning('⬆ 请先登录!') |
|
|
|
|
|
|
|
def get_current_time(): |
|
beijing_tz = timezone('Asia/Shanghai') |
|
beijing_time = datetime.now(beijing_tz) |
|
current_time = beijing_time.strftime('%H:%M:%S') |
|
return current_time |
|
|
|
|
|
def mermaid(code: str): |
|
|
|
from streamlit import components |
|
|
|
|
|
html_file = components.v1.html( |
|
f""" |
|
<pre class="mermaid"> |
|
{code} |
|
</pre> |
|
|
|
<script type="module"> |
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; |
|
|
|
mermaid.initialize({{ startOnLoad: true }}); |
|
</script> |
|
""" |
|
, |
|
height=400, |
|
scrolling=True, |
|
) |
|
|
|
|
|
html_file = str(f""" |
|
<pre class="mermaid"> |
|
{code} |
|
</pre> |
|
|
|
<script type="module"> |
|
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs'; |
|
|
|
mermaid.initialize({{ startOnLoad: true }}); |
|
</script> |
|
""") |
|
|
|
|
|
mermaid_str = code |
|
|
|
return html_file, mermaid_str |
|
|
|
|
|
|
|
def markdown_chart(input:str): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if input: |
|
|
|
|
|
|
|
|
|
with st.chat_message("assistant", avatar="./llm_icon.png"): |
|
message_placeholder = st.empty() |
|
full_response = "" |
|
|
|
print('st.session_state.messages:') |
|
pprint.pprint(st.session_state.messages) |
|
|
|
chatgpt_response = openai_client.chat.completions.create(model="gpt-3.5-turbo-16k", |
|
messages=[ |
|
{"role": "system", "content": system_prompt}, |
|
{"role": "user", "content": json.dumps(st.session_state.messages, ensure_ascii=False)}, |
|
], |
|
|
|
|
|
|
|
|
|
stream=False, |
|
) |
|
|
|
llm_response = chatgpt_response.choices[0].message.content |
|
message_placeholder.markdown('结果如下:') |
|
|
|
st.session_state.messages.append( |
|
{"role": "assistant", "content": llm_response}) |
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pattern = r'```mermaid([\s\S]*?)```' |
|
match = re.search(pattern, llm_response) |
|
|
|
if match: |
|
md_input = match.group(1).strip() |
|
|
|
|
|
if md_input: |
|
md_input = md_input.replace('mermaid', '') |
|
|
|
else: |
|
md_input = llm_response.replace('mermaid', '') |
|
md_input = md_input.replace("```", '') |
|
except Exception as e: |
|
print('Error:', e) |
|
md_input = llm_response |
|
|
|
|
|
html_file = mermaid(md_input) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return html_file |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.markdown(""" |
|
<style> |
|
div[data-testid="column"] { |
|
width: fit-content !important; |
|
flex: unset; |
|
} |
|
div[data-testid="column"] * { |
|
width: fit-content !important; |
|
} |
|
</style> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
|
|
def main(input): |
|
|
|
if input: |
|
|
|
|
|
with st.chat_message("user"): |
|
st.markdown(input) |
|
st.session_state.messages.append({"role": "user", "content": input}) |
|
spinner = st.spinner('处理中...请耐心等待') |
|
with spinner: |
|
html_file, mermaid_code = markdown_chart(input=input) |
|
diagram_time = get_current_time() |
|
st.success(body=f'程序运行完成!当前时间:{diagram_time}。', icon='💯') |
|
|
|
|
|
if html_file: |
|
col1, col2, col3 = st.columns([1, 1, 8]) |
|
with col1: |
|
ste.download_button( |
|
label="下载图例", |
|
data=html_file, |
|
file_name='mydiagram.html', |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with col2: |
|
ste.download_button( |
|
label="下载代码", |
|
data=mermaid_code, |
|
file_name='mydiagram.txt', |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return html_file |
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
html_file = main(input=user_input) |
|
|
|
|
|
re_btn = None |
|
if re_btn: |
|
regenerate() |