简介
Streamlit是一个开放源代码的Python库,旨在帮助数据科学家和开发者快速构建并分享具有吸引力的交互式Web应用。这个工具特别适合那些没有前端开发背景的用户,使他们能够轻松地将数据脚本转化为可供非技术用户使用的交互式Web应用。Streamlit极大地简化了Web应用的开发流程,允许开发者将精力集中在数据处理和业务逻辑上,而非界面设计。它的核心设计理念是高效简洁,通过大幅减少模板代码的需求,让创建基于数据的应用变得异常简便。
我们作为人工智能的开发者,可以使用streamlit方便的进行前端的展示,结合后端的FastAPI接口框架,就能够达到我们所预期的效果,而且streamlit使用纯python编写,我们可以很方便的迁入我们的python代码,达到快速融合使用的效果。
页面配置,内容初始化,字体和工具导入:
st.set_page_config(
page_title="法律文书生成",
page_icon="🤖",
layout='wide',
initial_sidebar_state='collapsed'
)
st.markdown("# 法律文书生成")
st.sidebar.header("法律文书生成")
st.write(
"""这个模块提供法律文书生成功能,可以生成格式比较规范的法律文书"""
)
# @st.cache_data
import demo_tool
DEFAULT_SYSTEM_PROMPT = '''
你是由山东大学软件学院CLD团队开发的LecumentGEN中文法律文书大模型
'''.strip()
# 文泉驿微米黑字体的路径
font_path = '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc'
pdfmetrics.registerFont(TTFont('WenQuanYi Micro Hei', font_path))
PDF生成:
def generate_pdf(chat_history, output_file="generated_document.pdf"):
# 创建PDF文档的基础设置
doc = SimpleDocTemplate(output_file, pagesize=letter)
styles = getSampleStyleSheet()
# 定义正常段落样式
style = styles['Normal']
style.fontName = 'WenQuanYi Micro Hei'
style.fontSize = 12
style.leading = 20 # 增加行间距
style.spaceBefore = 5 # 段落前的额外空间
style.spaceAfter = 5 # 段落后的额外空间
style.firstLineIndent = 14 # 每段第一行缩进
# 定义右对齐样式,用于倒数第一行和倒数第二行
right_align_style = styles['Normal'].clone('RightAlign')
right_align_style.alignment = 2 # 右对齐
# 定义标题样式
title_style = styles['Title']
title_style.fontName = 'WenQuanYi Micro Hei'
title_style.fontSize = 16
title_style.leading = 24
title_style.alignment = 1 # 居中对齐
# 创建一个框架来定义文本的位置和大小
frame = Frame(72, 72, 450, 700, id='normal')
聊天历史处理和文档内容构建
处理 chat_history
输入,根据其类型将内容分割成段落列表。
将第一段文本作为标题处理,并在标题下方添加空间。
if isinstance(chat_history, str):
paragraphs = chat_history.split('\n\n')
elif isinstance(chat_history, list):
paragraphs = []
for paragraph in chat_history:
paragraphs.extend(paragraph.split('\n\n'))
else:
raise ValueError("Unsupported chat_history type. Must be either str or list.")
if paragraphs:
title_text = paragraphs[0].strip()
title = Paragraph(title_text, title_style)
story.append(title)
story.append(Spacer(1, 0.25 * inch))
paragraphs = paragraphs[1:]
遍历每个段落,并根据其位置选择相应的样式(正常或右对齐),将它们转换为 Paragraph
对象并添加到内容列表 story
中。
for idx, paragraph in enumerate(paragraphs):
lines = paragraph.split('\n')
for line_idx, line in enumerate(lines):
if idx >= len(paragraphs) - 2:
p = Paragraph(line.strip(), right_align_style)
else:
formatted_paragraph = ' ' + line.strip()
p = Paragraph(formatted_paragraph, style)
story.append(p)
文档构建:
page_template = PageTemplate(frames=[frame])
doc.addPageTemplates([page_template])
doc.build(story)
页面主题构建:
它包括初始化会话状态、处理用户响应、以及提供一个交互式的用户界面来收集数据和触发事件。
如果会话状态中没有chat_history
,则初始化一个空列表。这个列表用来存储用户与应用之间的互动历史。
定义了一个函数handle_response
,用于将用户的输入和应用的响应保存到聊天历史中:
def handle_response(response):
st.session_state['chat_history'].append(f"User: {prompt_text}\nBot: {response}")
# # Initialize session state for storing chat history
if 'chat_history' not in st.session_state:
st.session_state['chat_history'] = []
# if 'generated_content' not in st.session_state:
# st.session_state['generated_content'] = ""
# def update_state(key, new_value):
# st.session_state[key] = new_value
col1, col2 = st.columns([1, 3])
if 'clear_fields' not in st.session_state:
st.session_state['clear_fields'] = False
with col1:
document_type = st.selectbox("选择文书类型", ["刑事判决书", "调解书"], key='document_type')
# 根据清空标志设置输入框的默认值
default_text = "" if st.session_state['clear_fields'] else None
court_info = st.text_area("输入文书题目", value=default_text, key='court_info',height=50)
case_background = st.text_area("输入案情背景", value=default_text, key='case_background')
case_description = st.text_area("输入案情描述", value=default_text, key='case_description')
court_staff = st.text_area("输入法庭人员", value=default_text, key='court_staff')
generate_button = st.button("生成")
clear_button = st.button("清空")
generated_content=''
- 使用
st.columns
划分页面为两列,比例为1:3。在第一列中,使用st.selectbox
让用户选择文书类型,并提供多个st.text_area
让用户输入文书题目、案情背景、案情描述和法庭人员等信息。提供了“生成”和“清空”按钮,分别用于生成文书和清空已输入的字段。
4. 生成与清空按钮的逻辑
if clear button代码检查是否触发了clear_button
。如果是,它会在st.session_state
字典中设置clear_fields
键为True
,然后触发应用程序的实验性重新运行。这种重新运行实际上是刷新页面的方式,可用于重置字段或根据新的会话状态值更新显示。
if clear_button:
# 设置清空标志并重新运行以更新界面
st.session_state['clear_fields'] = True
st.experimental_rerun()
# public
with st.sidebar:
# # top_p = st.slider(
# # 'top_p', 0.0, 1.0, 0.7, step=0.01
# # )
# # temperature = st.slider(
# # 'temperature', 0.0, 1.5, 0.95, step=0.01
# # )
# # repetition_penalty = st.slider(
# # 'repetition_penalty', 0.0, 2.0, 1.1, step=0.01
# # )
# # max_new_token = st.slider(
# # 'Output length', 5, 32000, 2000, step=1
# # )
cols = st.columns(2)
export_btn = cols[0]
clear_history = cols[1].button("Clear History", use_container_width=True)
system_prompt = st.text_area(
label="System Prompt (Only for chat mode)",
height=300,
value=get_system_prompt(document_type),
)
这部分代码创建了一个文本区域,用于输入或显示系统提示(仅在聊天模式下使用)。get_system_prompt(document_type)
函数可能用于根据不同的文档类型获取相应的系统提示文本。文本区域的高度设置为300。
generator_button
当generate_button
被点击时,首先将st.session_state['clear_fields']
设置为False
,意味着不清空字段。然后,调用get_system_prompt
函数获取当前系统提示。接着,通过demo_generate.main
函数生成响应,此函数接收多个参数控制文本生成的行为,如随机性(top_p
和temperature
),输入的提示文本,以及生成的最大新词数。
if generate_button:
st.session_state['clear_fields'] = False # 重置清空标志
current_system_prompt = get_system_prompt(document_type)
response = demo_generate.main(
top_p=0.7,
temperature=0.95,
prompt_text=case_description,
system_prompt=system_prompt,
repetition_penalty=1.1,
max_new_tokens=2000
)
if response:
current_time = datetime.datetime.now().strftime("%Y-%m-%d")
generated_content = f"{court_info}\n\n{case_background}\n\n{case_description}\n\n{response}\n\n{court_staff}\n"
# st.session_state['generated_content'] = generated_content
st.session_state['chat_history'] = []
如果生成了响应,将当前时间格式化并与其他文本组合形成最终的生成内容。注释掉的代码可能用于保存生成的内容至会话状态,这里清空了chat_history
列表,这可能用于记录交互历史。
with col2:
st.text_area("生成内容", generated_content, height=600)
在列col2
中展示生成的内容,并设置文本区域高度为600。
if generate_button:
pdf_content = generated_content
generate_pdf([pdf_content])
with open("generated_document.pdf", "rb") as f:
st.download_button(
label="Download PDF",
data=f,
file_name="generated_document.pdf",
mime="application/pdf"
)
st.session_state['chat_history'] = []
如果再次点击生成按钮,生成PDF文档并提供下载按钮。这部分代码还包括读取生成的PDF文件并通过下载按钮提供下载。此外,还清除了chat_history
,保留生成的内容和PDF内容。
chat界面:
使用st.chat_input
方法接收用户的输入,并通过demo_chat.main
函数处理这些输入并生成响应。函数接收几个参数,包括输入文本、系统提示和控制生成文本的几个关键参数(如温度、惩罚因子等)。如果demo_chat.main
函数返回了响应,这部分代码将调用handle_response
函数来处理并可能显示这些响应。这个函数没有在代码片段中定义,可能是用户定义的或在其他部分的代码中定义。
import streamlit as st
import time
import numpy as np
st.set_page_config(page_title="法律问答", page_icon="🤔")
st.markdown("# 法律问答")
st.sidebar.header("法律问答")
st.write(
"""这个模块提供与法律相关的对话功能"""
)
import demo_chat
DEFAULT_SYSTEM_PROMPT = '''
'''.strip()
with st.sidebar:
# top_p = st.slider(
# 'top_p', 0.0, 1.0, 0.8, step=0.01
# )
# temperature = st.slider(
# 'temperature', 0.0, 1.5, 0.95, step=0.01
# )
# repetition_penalty = st.slider(
# 'repetition_penalty', 0.0, 2.0, 1.1, step=0.01
# )
# max_new_token = st.slider(
# 'Output length', 5, 32000, 256, step=1
# )
cols = st.columns(2)
export_btn = cols[0]
clear_history = cols[1].button("Clear History", use_container_width=True)
retry = export_btn.button("Retry", use_container_width=True)
#system_prompt = st.text_area(
# label="System Prompt (Only for chat mode)",
# height=300,
# value=DEFAULT_SYSTEM_PROMPT,
#)
# Initialize session state for storing chat history
if 'chat_history' not in st.session_state:
st.session_state['chat_history'] = []
if clear_history or retry:
prompt_text = ""
st.session_state['chat_history'] = []
prompt_text = st.chat_input(
'Chat with LecumentGEN!',
key='chat_input',
)
response = demo_chat.main(
retry=retry,
top_p=0.8,
temperature=0.95,
prompt_text=prompt_text,
system_prompt=DEFAULT_SYSTEM_PROMPT,
repetition_penalty=1.1,
max_new_tokens=512
)
if response:
handle_response(response)