ChatGLM3-6B Streamlit实战:添加对话导出PDF/Markdown功能开发教程

📅 发布时间:2026/7/13 6:00:46 👁️ 浏览次数:
ChatGLM3-6B Streamlit实战:添加对话导出PDF/Markdown功能开发教程
ChatGLM3-6B Streamlit实战添加对话导出PDF/Markdown功能开发教程1. 引言想象一下你和ChatGLM3-6B进行了一场深入的技术讨论或者让它帮你分析了一份长文档。对话结束后你看着屏幕上那些有价值的问答记录是不是特别想把它保存下来分享给同事或者留作参考但手动复制粘贴不仅麻烦格式还容易乱。这就是我们今天要解决的问题。本文将手把手教你如何为你的ChatGLM3-6B Streamlit应用开发一个实用的对话导出功能支持一键保存为PDF或Markdown文件。这个功能看似简单却能极大提升工具的使用体验和实用性。学习目标理解如何在Streamlit应用中集成文件导出功能掌握使用reportlab生成PDF和markdown库处理Markdown的基本方法学会设计一个美观且实用的用户界面组件前置知识基本的Python编程知识对Streamlit框架有初步了解知道st.button、st.session_state等基本用法已经成功部署了ChatGLM3-6B Streamlit应用可以参考之前的部署教程教程价值 即使你是Streamlit新手跟着步骤走也能完成。我们将从零开始代码清晰注释详细确保你能看懂每一步在做什么最终获得一个即插即用的功能模块。2. 环境准备与功能设计在开始写代码之前我们需要先规划好这个功能要做什么以及需要哪些工具。2.1 功能需求分析我们希望新增的导出功能能做到以下几点完整记录能导出当前会话中的所有对话历史。格式友好支持两种常用格式——PDF便于打印和正式分享和Markdown便于在代码仓库、笔记软件中编辑和查看。操作简单在界面上有一个明显的按钮或区域用户点几下就能完成导出。样式美观导出的文件要有基本的排版比如区分用户和AI的发言有标题和时间戳。2.2 安装必要的Python库我们需要两个额外的库来帮忙reportlab一个强大的PDF生成库可以让我们用代码“画”出PDF的每一页。markdown虽然我们主要是生成.md文件内容但这个库可以帮助我们确保内容的格式正确。打开你的终端在ChatGLM3-6B项目所在的环境下执行以下命令安装pip install reportlabmarkdown库通常是基础环境的一部分如果未安装也可以执行pip install markdown3. 核心功能开发导出模块接下来我们创建核心的导出功能函数。我建议在项目根目录下新建一个名为export_utils.py的文件专门存放这些功能代码这样主程序文件不会变得太臃肿。3.1 编写导出工具函数打开export_utils.py开始编写代码# export_utils.py import io from datetime import datetime from reportlab.lib.pagesizes import A4 from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import inch from reportlab.lib import colors def export_to_pdf(conversation_history, filenameNone): 将对话历史导出为PDF文件。 参数: conversation_history (list): 对话历史列表每个元素是包含role和content的字典。 filename (str, optional): 导出的文件名。默认为 None会自动生成。 返回: bytes: PDF文件的二进制数据。 if filename is None: filename fchatglm_conversation_{datetime.now().strftime(%Y%m%d_%H%M%S)}.pdf # 创建一个字节缓冲区来存放PDF buffer io.BytesIO() # 创建PDF文档设置页面大小和边距 doc SimpleDocTemplate(buffer, pagesizeA4, rightMargin72, leftMargin72, topMargin72, bottomMargin72) # 获取样式表并创建自定义样式 styles getSampleStyleSheet() # 创建标题样式 title_style ParagraphStyle( CustomTitle, parentstyles[Heading1], fontSize16, spaceAfter30, alignment1, # 居中 textColorcolors.HexColor(#1E88E5) # 蓝色 ) # 创建用户消息样式 user_style ParagraphStyle( UserStyle, parentstyles[BodyText], fontSize10, leftIndent20, spaceBefore12, spaceAfter6, borderPadding5, borderColorcolors.HexColor(#BBDEFB), # 浅蓝色边框 backgroundColorcolors.HexColor(#E3F2FD), # 浅蓝色背景 backColorcolors.HexColor(#E3F2FD) ) # 创建AI消息样式 ai_style ParagraphStyle( AIStyle, parentstyles[BodyText], fontSize10, leftIndent20, spaceBefore12, spaceAfter6, borderPadding5, borderColorcolors.HexColor(#C8E6C9), # 浅绿色边框 backgroundColorcolors.HexColor(#E8F5E9), # 浅绿色背景 ) # 创建元信息样式时间、角色标签 meta_style ParagraphStyle( MetaStyle, parentstyles[Italic], fontSize8, textColorcolors.grey, spaceAfter3 ) # 开始构建PDF内容元素列表 story [] # 添加标题 title_text fChatGLM3-6B 对话记录 story.append(Paragraph(title_text, title_style)) story.append(Spacer(1, 20)) # 添加导出时间 export_time f导出时间: {datetime.now().strftime(%Y-%m-%d %H:%M:%S)} story.append(Paragraph(export_time, meta_style)) story.append(Spacer(1, 15)) # 遍历对话历史添加每条记录 for i, message in enumerate(conversation_history): role message.get(role, unknown) content message.get(content, ) # 添加角色标签和时间模拟 if role.lower() user: role_label 用户 style user_style else: # 假设是 assistant role_label AI助手 style ai_style # 创建角色标签段落 role_info fb{role_label}/b story.append(Paragraph(role_info, meta_style)) # 处理内容确保长文本能正确换行并转换一些基本HTML标签 # 替换换行符为HTML的br/这样Paragraph才能识别 formatted_content content.replace(\n, br/) # 简单处理代码块标记如果内容中有 if in formatted_content: # 这里可以更复杂地处理代码高亮但简单起见我们加个背景色提示 formatted_content formatted_content.replace(, font colordarkblue【代码块】/font) # 添加对话内容 story.append(Paragraph(formatted_content, style)) story.append(Spacer(1, 10)) # 每5条对话后加一个稍大的间隔提高可读性 if (i 1) % 5 0: story.append(Spacer(1, 20)) # 添加结束语 story.append(Spacer(1, 30)) footer f共 {len(conversation_history)} 条对话记录。 story.append(Paragraph(footer, meta_style)) # 构建PDF文档 doc.build(story) # 获取缓冲区中的PDF数据 pdf_data buffer.getvalue() buffer.close() return pdf_data def export_to_markdown(conversation_history, filenameNone): 将对话历史导出为Markdown格式的字符串。 参数: conversation_history (list): 对话历史列表。 filename (str, optional): 导出的文件名。默认为 None。 返回: str: Markdown格式的文本内容。 if filename is None: filename fchatglm_conversation_{datetime.now().strftime(%Y%m%d_%H%M%S)}.md # 创建Markdown内容 md_content [] # 添加标题 md_content.append(f# ChatGLM3-6B 对话记录\n) md_content.append(f**导出时间**: {datetime.now().strftime(%Y-%m-%d %H:%M:%S)}\n) md_content.append(f---\n) # 遍历对话历史 for i, message in enumerate(conversation_history): role message.get(role, unknown) content message.get(content, ) if role.lower() user: role_label **用户** # 用户消息用引用块表示 md_content.append(f{role_label}\n) # 确保内容中的换行在Markdown中有效 formatted_content content.replace(\n, \n) md_content.append(f {formatted_content}\n) else: # 假设是 assistant role_label **AI助手** md_content.append(f{role_label}\n) # AI消息普通段落但用代码块包裹可能的多行内容 if \n in content and not in content: # 如果内容中有换行且不是代码块用多行代码块包裹 md_content.append(f\n{content}\n\n) else: md_content.append(f{content}\n) md_content.append(\n) # 每条记录后空一行 md_content.append(f---\n) md_content.append(f*共 {len(conversation_history)} 条对话记录。*\n) # 将列表连接成一个字符串 return .join(md_content)代码解释export_to_pdf函数这是生成PDF的核心。我们使用reportlab的SimpleDocTemplate来定义页面用Paragraph和Spacer来组合文字和间距。通过定义不同的ParagraphStyle我们让用户和AI的对话在视觉上区分开来比如不同的背景色。export_to_markdown函数这个函数相对简单它把对话历史拼接成一个结构清晰的Markdown字符串。用户消息用引用块表示AI消息普通显示遇到多行内容则用代码块包裹确保格式不乱。文件名我们使用时间戳自动生成默认文件名避免重复。4. 集成到Streamlit主应用现在我们需要把这个导出功能“安装”到你的ChatGLM3-6B Streamlit应用里。假设你的主应用文件叫app.py。4.1 修改主应用文件打开app.py找到你管理对话历史的部分通常是一个保存在st.session_state里的列表比如st.session_state.messages。然后在界面上合适的位置比如侧边栏st.sidebar或者对话输入框附近添加导出控件。我们以添加到侧边栏为例# 在 app.py 的合适位置添加以下代码 # 通常是在初始化 session_state 和设置侧边栏的部分 import streamlit as st # 导入我们刚写的工具函数 from export_utils import export_to_pdf, export_to_markdown # ... 你原有的代码比如模型加载、对话函数等 ... # 在侧边栏添加导出功能区 with st.sidebar: st.header( 对话导出) # 检查是否有对话历史 if messages in st.session_state and len(st.session_state.messages) 0: st.success(f当前有 {len(st.session_state.messages)} 条对话记录。) # 提供一个输入框让用户自定义文件名可选 export_filename st.text_input( 导出文件名可选, valuefchatglm_dialog_{datetime.now().strftime(%Y%m%d)}, help如果不填将使用默认名称。 ) # 并排排列两个导出按钮 col1, col2 st.columns(2) with col1: if st.button( 导出为PDF, use_container_widthTrue, typeprimary): try: # 调用函数生成PDF数据 pdf_data export_to_pdf(st.session_state.messages, export_filename .pdf) # 提供下载按钮 st.download_button( label⬇️ 下载PDF文件, datapdf_data, file_nameexport_filename .pdf, mimeapplication/pdf, use_container_widthTrue ) st.balloons() # 增加一点成功反馈 except Exception as e: st.error(fPDF导出失败: {e}) with col2: if st.button( 导出为Markdown, use_container_widthTrue): try: # 调用函数生成Markdown文本 md_content export_to_markdown(st.session_state.messages, export_filename .md) # 提供下载按钮 st.download_button( label⬇️ 下载MD文件, datamd_content, file_nameexport_filename .md, mimetext/markdown, use_container_widthTrue ) st.snow() # 另一种成功反馈 except Exception as e: st.error(fMarkdown导出失败: {e}) # 提供一个预览区域可选 with st.expander( 预览最后几条对话Markdown格式): # 只预览最后3条避免侧边栏过长 preview_messages st.session_state.messages[-3:] if len(st.session_state.messages) 3 else st.session_state.messages preview_content export_to_markdown(preview_messages, preview.md) st.markdown(preview_content) else: st.info(暂无对话记录。开始聊天后即可在此导出。)4.2 代码逻辑说明条件显示只有当st.session_state.messages中有对话记录时才显示导出功能区否则提示用户先开始聊天。按钮触发点击“导出为PDF”或“导出为Markdown”按钮后程序会调用对应的工具函数。文件下载Streamlit的st.download_button非常方便它接收二进制数据PDF或文本数据MD并在浏览器中触发下载。用户体验我们添加了st.balloons()和st.snow()作为简单的成功视觉反馈。还提供了一个可展开的预览区域让用户先看看导出的大概样子。5. 运行与测试完成代码编写后让我们来测试一下这个新功能。启动应用在终端中进入项目目录运行streamlit run app.py。进行对话在应用中和ChatGLM3-6B进行几轮对话生成一些历史记录。找到导出按钮查看侧边栏你应该能看到新出现的“对话导出”区域。测试导出点击“导出为PDF”按钮页面会刷新并在按钮下方出现一个“下载PDF文件”的按钮。点击它一个格式工整的PDF文件就会保存到你的电脑。点击“导出为Markdown”按钮同样会出现下载按钮下载后得到一个.md文件用记事本、VS Code或任何Markdown编辑器都能很好地看着。看看效果PDF文件打开后你应该能看到带颜色的标题用户和AI的对话有不同颜色的背景框排版清晰。Markdown文件打开后用户消息以引用块形式呈现结构分明非常适合粘贴到Notion、Obsidian等笔记软件中继续编辑。6. 实用技巧与进阶想法基础功能已经完成这里还有一些小技巧和可以继续完善的方向6.1 处理超长对话如果对话历史非常长生成的PDF可能会超过一页。reportlab会自动处理分页但你可能需要调整样式确保分页时不会把一条完整的消息切开。可以在ParagraphStyle中设置keepWithNext等属性来优化。6.2 美化PDF样式添加Logo可以使用reportlab.platypus.Image在PDF页眉添加你的项目Logo。页眉页脚通过自定义SimpleDocTemplate的onFirstPage和onLaterPages方法添加页码和版权信息。代码高亮如果对话中包含大量代码可以集成Pygments库来实现PDF中的代码语法高亮但这会复杂一些。6.3 扩展导出格式除了PDF和Markdown你还可以轻松扩展其他格式导出为Word(.docx)使用python-docx库。导出为纯文本(.txt)最简单直接拼接字符串即可。导出为JSON保留最原始的结构化数据方便其他程序读取。json.dumps(st.session_state.messages, indent2, ensure_asciiFalse)一行代码就能搞定。6.4 添加到对话气泡菜单一个更酷的集成方式是在每条AI回复的气泡旁边添加一个小图标菜单提供“单独导出此条回复”的功能。这需要更精细的Streamlit组件操作但能提供更极致的用户体验。7. 总结通过这个教程我们成功为ChatGLM3-6B Streamlit应用添加了一个非常实用的对话导出功能。我们来回顾一下关键步骤规划与设计明确了要导出完整历史、支持PDF/Markdown格式、操作简单的目标。环境准备安装了核心的reportlab库。核心开发在export_utils.py中创建了两个函数分别用reportlab生成带样式的PDF以及拼接结构清晰的Markdown文本。应用集成在主应用app.py的侧边栏添加了导出功能区利用Streamlit的st.download_button实现了文件下载。测试优化运行应用测试功能并探讨了美化、扩展等进阶方向。这个功能虽然代码量不大但它将你的本地AI对话助手从一个“用完即走”的工具变成了一个可以积累知识、分享成果的生产力平台。希望这个教程能帮你更好地利用ChatGLM3-6B也欢迎你基于这个基础开发出更多有趣、有用的功能。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。