GLM-OCR Web UI定制开发:添加OCR结果导出Word/PDF/Markdown功能
1. 引言
你有没有遇到过这样的场景?用GLM-OCR识别了一份重要的合同文档,得到了准确的文本结果,然后...然后你需要把这些文本复制到Word里重新排版,或者手动整理成报告格式。这个过程不仅耗时,还容易出错。
GLM-OCR确实是个强大的工具,它能准确识别文本、表格甚至公式,但它的Web界面有个明显的短板——识别结果只能显示在页面上,想要保存下来进一步使用,就得手动复制粘贴。对于需要批量处理文档或者生成正式报告的用户来说,这个限制相当影响效率。
今天,我就来分享一个实用的定制开发方案:为GLM-OCR的Web UI添加OCR结果导出功能,支持一键导出为Word文档、PDF文件和Markdown格式。这个功能实现后,你可以:
- 把识别出的合同直接保存为格式规范的Word文档
- 将表格识别结果导出为PDF,方便打印和分享
- 把技术文档转换为Markdown格式,直接用于博客或文档系统
接下来,我会手把手带你完成这个功能的开发,从需求分析到代码实现,再到实际测试,整个过程都会详细讲解。即使你不是专业的Web开发人员,只要跟着步骤走,也能顺利完成这个定制化功能。
2. 项目环境准备
2.1 了解现有项目结构
在开始开发之前,我们先看看GLM-OCR项目的现有结构。根据项目说明,主要文件如下:
/root/GLM-OCR/ ├── serve_gradio.py # Gradio 服务脚本 ├── start_vllm.sh # 启动脚本 ├── USAGE.md # 详细文档 └── logs/ # 运行日志我们需要修改的是serve_gradio.py文件,这是Web界面的核心代码。Gradio是一个Python库,可以快速构建机器学习应用的Web界面,GLM-OCR就是用这个库搭建的用户界面。
2.2 安装必要的依赖包
导出功能需要一些额外的Python库支持。我们先激活项目使用的conda环境,然后安装必要的包:
# 激活conda环境 source /opt/miniconda3/bin/activate py310 # 安装导出功能所需的库 /opt/miniconda3/envs/py310/bin/pip install python-docx reportlab markdown这三个库的作用分别是:
python-docx:用于生成Word文档reportlab:用于生成PDF文件markdown:用于处理Markdown格式转换
如果你还需要其他格式的支持,比如Excel,可以额外安装openpyxl:
/opt/miniconda3/envs/py310/bin/pip install openpyxl2.3 备份原始文件
在修改代码之前,做个备份是个好习惯:
cd /root/GLM-OCR cp serve_gradio.py serve_gradio.py.backup这样,如果修改过程中出现问题,我们可以随时恢复原始版本。
3. 导出功能设计与实现
3.1 功能需求分析
我们要实现的导出功能需要满足以下几个核心需求:
- 支持多种格式:至少包括Word、PDF、Markdown三种常用格式
- 保持内容结构:文本、表格、公式等不同内容类型要正确转换
- 操作简单:用户点击按钮就能导出,不需要复杂的配置
- 文件命名合理:自动生成有意义的文件名,比如基于上传图片的名称
- 错误处理完善:导出过程中出现问题时给用户明确的提示
基于这些需求,我设计了下面的实现方案。
3.2 创建导出工具模块
为了保持代码的清晰和可维护性,我们创建一个单独的导出工具模块。在/root/GLM-OCR目录下新建一个文件export_utils.py:
""" GLM-OCR 导出工具模块 支持将OCR结果导出为Word、PDF、Markdown格式 """ import os import tempfile from datetime import datetime from docx import Document from docx.shared import Inches, Pt from docx.enum.text import WD_ALIGN_PARAGRAPH from reportlab.lib.pagesizes import letter from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.units import inch from reportlab.lib import colors import markdown from io import BytesIO class OCRExporter: """OCR结果导出器""" def __init__(self, ocr_result, image_name=None): """ 初始化导出器 参数: ocr_result: OCR识别结果文本 image_name: 原始图片名称,用于生成导出文件名 """ self.ocr_result = ocr_result self.image_name = image_name or "ocr_result" # 清理文件名,移除扩展名和特殊字符 if self.image_name: base_name = os.path.splitext(os.path.basename(self.image_name))[0] self.base_name = ''.join(c for c in base_name if c.isalnum() or c in (' ', '-', '_')) else: self.base_name = "ocr_result" def export_to_word(self, output_path=None): """ 导出为Word文档 参数: output_path: 输出文件路径,如果为None则生成临时文件 返回: 文件路径 """ if output_path is None: # 生成临时文件 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/{self.base_name}_{timestamp}.docx" # 创建Word文档 doc = Document() # 添加标题 title = doc.add_heading(f'OCR识别结果 - {self.base_name}', 0) title.alignment = WD_ALIGN_PARAGRAPH.CENTER # 添加生成时间 time_str = datetime.now().strftime("%Y年%m月%d日 %H:%M:%S") time_para = doc.add_paragraph(f'生成时间: {time_str}') time_para.alignment = WD_ALIGN_PARAGRAPH.CENTER doc.add_paragraph() # 空行 # 处理OCR结果 lines = self.ocr_result.strip().split('\n') for line in lines: if line.strip(): # 跳过空行 # 简单判断是否为表格行(包含多个制表符或连续空格) if '\t' in line or ' ' in line: # 尝试按制表符或空格分割 if '\t' in line: cells = line.split('\t') else: cells = line.split(' ') # 创建表格 table = doc.add_table(rows=1, cols=len(cells)) table.style = 'Light Grid Accent 1' # 填充表格数据 for i, cell in enumerate(cells): table.cell(0, i).text = cell.strip() else: # 普通文本段落 para = doc.add_paragraph(line.strip()) # 设置段落格式 para_format = para.paragraph_format para_format.line_spacing = 1.5 # 保存文档 doc.save(output_path) return output_path def export_to_pdf(self, output_path=None): """ 导出为PDF文档 参数: output_path: 输出文件路径,如果为None则生成临时文件 返回: 文件路径 """ if output_path is None: # 生成临时文件 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/{self.base_name}_{timestamp}.pdf" # 创建PDF文档 doc = SimpleDocTemplate(output_path, pagesize=letter) styles = getSampleStyleSheet() # 自定义样式 title_style = ParagraphStyle( 'CustomTitle', parent=styles['Heading1'], fontSize=16, spaceAfter=12, alignment=1 # 居中 ) content_style = ParagraphStyle( 'CustomContent', parent=styles['Normal'], fontSize=10, spaceAfter=6, leading=14 # 行距 ) # 构建内容 story = [] # 添加标题 title_text = f'OCR识别结果 - {self.base_name}' story.append(Paragraph(title_text, title_style)) story.append(Spacer(1, 12)) # 添加生成时间 time_str = datetime.now().strftime("%Y年%m月%d日 %H:%M:%S") story.append(Paragraph(f'生成时间: {time_str}', styles['Normal'])) story.append(Spacer(1, 24)) # 处理OCR结果 lines = self.ocr_result.strip().split('\n') for line in lines: if line.strip(): # 简单判断是否为表格行 if '\t' in line or ' ' in line: # 创建表格数据 if '\t' in line: cells = line.split('\t') else: cells = line.split(' ') # 创建表格 table_data = [[cell.strip() for cell in cells]] table = Table(table_data) # 设置表格样式 table.setStyle(TableStyle([ ('BACKGROUND', (0, 0), (-1, 0), colors.grey), ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke), ('ALIGN', (0, 0), (-1, -1), 'CENTER'), ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'), ('FONTSIZE', (0, 0), (-1, 0), 10), ('BOTTOMPADDING', (0, 0), (-1, 0), 12), ('BACKGROUND', (0, 1), (-1, -1), colors.beige), ('GRID', (0, 0), (-1, -1), 1, colors.black) ])) story.append(table) story.append(Spacer(1, 12)) else: # 普通文本 story.append(Paragraph(line.strip(), content_style)) # 生成PDF doc.build(story) return output_path def export_to_markdown(self, output_path=None): """ 导出为Markdown文档 参数: output_path: 输出文件路径,如果为None则生成临时文件 返回: 文件路径 """ if output_path is None: # 生成临时文件 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/{self.base_name}_{timestamp}.md" # 构建Markdown内容 md_content = f"""# OCR识别结果 - {self.base_name} **生成时间**: {datetime.now().strftime("%Y年%m%d日 %H:%M:%S")} --- ## 识别内容 """ # 处理OCR结果 lines = self.ocr_result.strip().split('\n') for line in lines: if line.strip(): # 判断是否为表格行 if '\t' in line: # Markdown表格格式 cells = line.split('\t') md_content += '| ' + ' | '.join(cell.strip() for cell in cells) + ' |\n' elif ' ' in line and len(line.split(' ')) > 1: # 多个空格分隔的表格 cells = [c.strip() for c in line.split(' ') if c.strip()] if len(cells) > 1: md_content += '| ' + ' | '.join(cells) + ' |\n' else: # 普通文本 md_content += line.strip() + '\n\n' # 保存Markdown文件 with open(output_path, 'w', encoding='utf-8') as f: f.write(md_content) return output_path def export(self, format_type, output_path=None): """ 通用导出方法 参数: format_type: 导出格式,支持 'word', 'pdf', 'markdown' output_path: 输出文件路径 返回: 文件路径 """ format_type = format_type.lower() if format_type == 'word': return self.export_to_word(output_path) elif format_type == 'pdf': return self.export_to_pdf(output_path) elif format_type == 'markdown': return self.export_to_markdown(output_path) else: raise ValueError(f"不支持的格式: {format_type}") def test_export(): """测试导出功能""" # 测试数据 test_result = """这是一个测试文档 表格示例: 姓名 年龄 职业 张三 25 工程师 李四 30 设计师 王五 28 产品经理 这是普通文本段落,包含一些重要的信息。 公式示例: E = mc² 文档结束。""" # 测试各种格式导出 exporter = OCRExporter(test_result, "test_document.jpg") print("测试Word导出...") word_file = exporter.export_to_word() print(f"Word文件已生成: {word_file}") print("\n测试PDF导出...") pdf_file = exporter.export_to_pdf() print(f"PDF文件已生成: {pdf_file}") print("\n测试Markdown导出...") md_file = exporter.export_to_markdown() print(f"Markdown文件已生成: {md_file}") return word_file, pdf_file, md_file if __name__ == "__main__": test_export()这个导出工具模块提供了完整的导出功能,支持三种格式,并且有基本的表格识别和格式处理能力。
3.3 修改Gradio界面
现在我们需要修改serve_gradio.py文件,在现有的Web界面中添加导出功能。打开文件,找到合适的位置添加导出相关的代码。
首先,在文件开头导入我们刚创建的导出工具:
# 在现有import语句后面添加 import os import tempfile from export_utils import OCRExporter然后,找到创建Gradio界面的部分。通常这个文件会有一个create_ui()函数或者类似的界面创建代码。我们需要在识别结果的输出区域添加导出按钮。
假设现有的界面代码大致是这样的结构:
def create_ui(): with gr.Blocks() as demo: gr.Markdown("# GLM-OCR 文档识别系统") with gr.Row(): with gr.Column(): image_input = gr.Image(label="上传图片", type="filepath") prompt_input = gr.Textbox(label="任务类型", value="Text Recognition:", interactive=True) submit_btn = gr.Button("开始识别", variant="primary") with gr.Column(): output_text = gr.Textbox(label="识别结果", lines=20, interactive=False) # 在这里添加导出功能 with gr.Row(): with gr.Column(): gr.Markdown("### 导出选项") format_select = gr.Dropdown( choices=["Word文档 (.docx)", "PDF文件 (.pdf)", "Markdown (.md)"], label="选择导出格式", value="Word文档 (.docx)" ) export_btn = gr.Button("导出结果", variant="secondary") download_file = gr.File(label="下载文件", interactive=False) # 导出按钮点击事件 def export_result(ocr_text, format_choice, image_info): if not ocr_text or ocr_text.strip() == "": return None, "请先进行OCR识别" try: # 从格式选择中提取格式类型 format_map = { "Word文档 (.docx)": "word", "PDF文件 (.pdf)": "pdf", "Markdown (.md)": "markdown" } format_type = format_map.get(format_choice, "word") # 获取图片名称(如果有) image_name = None if image_info and isinstance(image_info, dict) and 'name' in image_info: image_name = image_info['name'] elif isinstance(image_info, str): image_name = os.path.basename(image_info) # 创建导出器并导出 exporter = OCRExporter(ocr_text, image_name) export_file = exporter.export(format_type) # 返回文件路径 return export_file, "导出成功!" except Exception as e: return None, f"导出失败: {str(e)}" # 连接按钮事件 export_btn.click( fn=export_result, inputs=[output_text, format_select, image_input], outputs=[download_file, gr.Textbox(label="导出状态", visible=True)] ) # 原有的识别功能保持不变 # ... 原有的识别逻辑代码 ... return demo这里的关键点:
- 在界面中添加了导出格式选择下拉框
- 添加了导出按钮
- 添加了文件下载组件
- 实现了导出函数,处理格式转换和文件生成
- 将导出按钮与导出函数绑定
3.4 完整修改示例
由于我不知道serve_gradio.py的具体内容,这里提供一个完整的修改示例。你可以根据实际情况调整:
""" GLM-OCR Gradio服务脚本 - 增强版(添加导出功能) """ import gradio as gr import torch from transformers import AutoModelForCausalLM, AutoTokenizer from PIL import Image import argparse import os import sys from datetime import datetime # 添加导出工具导入 from export_utils import OCRExporter def load_model(model_path): """加载模型""" print(f"正在加载模型: {model_path}") # 原有的模型加载代码 tokenizer = AutoTokenizer.from_pretrained( model_path, trust_remote_code=True ) model = AutoModelForCausalLM.from_pretrained( model_path, torch_dtype=torch.float16, device_map="auto", trust_remote_code=True ) print("模型加载完成") return model, tokenizer def process_image(image_path, prompt, model, tokenizer): """处理图片并返回OCR结果""" try: # 打开图片 image = Image.open(image_path).convert("RGB") # 构建输入 query = f"<image>\n{prompt}" inputs = tokenizer.build_conversation_input_ids( tokenizer, query=query, images=[image], template_version="chatml" ) inputs = { 'input_ids': inputs['input_ids'].unsqueeze(0).cuda(), 'token_type_ids': inputs['token_type_ids'].unsqueeze(0).cuda(), 'attention_mask': inputs['attention_mask'].unsqueeze(0).cuda(), 'images': [[inputs['images'][0].cuda().to(torch.float16)]] } # 生成输出 with torch.no_grad(): outputs = model.generate( **inputs, max_new_tokens=1024, do_sample=False ) # 解码输出 response = tokenizer.decode(outputs[0], skip_special_tokens=True) # 提取OCR结果(移除prompt部分) if prompt in response: result = response.split(prompt)[-1].strip() else: result = response.strip() return result except Exception as e: return f"处理失败: {str(e)}" def export_ocr_result(ocr_text, format_choice, image_info): """导出OCR结果到指定格式""" if not ocr_text or ocr_text.strip() == "": return None, "请先进行OCR识别" try: # 映射格式选择到实际格式 format_map = { "Word文档 (.docx)": "word", "PDF文件 (.pdf)": "pdf", "Markdown (.md)": "markdown" } format_type = format_map.get(format_choice, "word") # 获取图片名称 image_name = None if image_info: if isinstance(image_info, str): image_name = os.path.basename(image_info) elif hasattr(image_info, 'name'): image_name = image_info.name # 创建导出器 exporter = OCRExporter(ocr_text, image_name) # 导出文件 export_file = exporter.export(format_type) return export_file, "导出成功!文件已准备好下载。" except Exception as e: return None, f"导出失败: {str(e)}" def create_ui(model, tokenizer): """创建Gradio用户界面""" def process_wrapper(image, prompt): """包装处理函数,处理Gradio的输入""" if image is None: return "请上传图片" # 保存临时图片文件 temp_dir = "/tmp/glm_ocr" os.makedirs(temp_dir, exist_ok=True) temp_path = os.path.join(temp_dir, f"temp_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png") if hasattr(image, 'save'): image.save(temp_path) else: # 如果是文件路径 import shutil shutil.copy(image, temp_path) # 处理图片 result = process_image(temp_path, prompt, model, tokenizer) # 清理临时文件 try: os.remove(temp_path) except: pass return result with gr.Blocks(title="GLM-OCR 文档识别系统", theme=gr.themes.Soft()) as demo: gr.Markdown(""" # 📄 GLM-OCR 文档识别系统 支持文本识别、表格识别、公式识别等多种OCR功能。 """) with gr.Row(): with gr.Column(scale=1): # 图片上传区域 image_input = gr.Image( label="上传文档图片", type="pil", sources=["upload"], height=400 ) # 任务选择 task_select = gr.Dropdown( choices=[ "Text Recognition:", "Table Recognition:", "Formula Recognition:" ], value="Text Recognition:", label="选择识别任务", interactive=True ) # 自定义提示词 custom_prompt = gr.Textbox( label="自定义提示词(可选)", placeholder="留空使用默认提示词", lines=2 ) # 识别按钮 recognize_btn = gr.Button( "开始识别", variant="primary", size="lg" ) with gr.Column(scale=2): # 识别结果显示 output_text = gr.Textbox( label="识别结果", lines=25, interactive=True, show_copy_button=True ) # 导出功能区域 with gr.Group(): gr.Markdown("### 📤 导出功能") with gr.Row(): format_select = gr.Dropdown( choices=[ "Word文档 (.docx)", "PDF文件 (.pdf)", "Markdown (.md)" ], value="Word文档 (.docx)", label="选择导出格式", scale=3 ) export_btn = gr.Button( "导出结果", variant="secondary", scale=1 ) # 状态提示 export_status = gr.Textbox( label="导出状态", interactive=False, visible=False ) # 文件下载 download_file = gr.File( label="下载文件", interactive=False, visible=False ) # 识别按钮事件 def on_recognize(image, task, custom_text): if image is None: return "请上传图片" # 使用自定义提示词或默认提示词 prompt = custom_text.strip() if custom_text.strip() else task return process_wrapper(image, prompt) recognize_btn.click( fn=on_recognize, inputs=[image_input, task_select, custom_prompt], outputs=output_text ) # 导出按钮事件 def on_export(ocr_text, format_choice, image): if not ocr_text or ocr_text.strip() == "": return gr.update(visible=False), gr.update(value="请先进行OCR识别", visible=True), gr.update(visible=False) file_path, status = export_ocr_result(ocr_text, format_choice, image) if file_path: return gr.update(value=file_path, visible=True), gr.update(value=status, visible=True), gr.update(visible=True) else: return gr.update(visible=False), gr.update(value=status, visible=True), gr.update(visible=False) export_btn.click( fn=on_export, inputs=[output_text, format_select, image_input], outputs=[download_file, export_status, gr.Textbox(visible=True)] # 添加一个占位符保持输出数量一致 ) # 示例部分 with gr.Accordion("使用示例", open=False): gr.Markdown(""" **文本识别示例:** - 上传包含文字的图片 - 选择"Text Recognition:" - 点击"开始识别" **表格识别示例:** - 上传包含表格的图片 - 选择"Table Recognition:" - 点击"开始识别" **公式识别示例:** - 上传包含数学公式的图片 - 选择"Formula Recognition:" - 点击"开始识别" **导出功能:** 1. 先进行OCR识别获取结果 2. 选择要导出的格式(Word/PDF/Markdown) 3. 点击"导出结果"按钮 4. 下载生成的文件 """) # 提示信息 gr.Markdown(""" --- **提示:** - 支持PNG、JPG、WEBP格式图片 - 首次识别需要加载模型,请耐心等待 - 导出功能需要先进行OCR识别 - 导出的文件保存在临时目录,请及时下载 """) return demo def main(): """主函数""" parser = argparse.ArgumentParser() parser.add_argument("--model-path", type=str, default="/root/ai-models/ZhipuAI/GLM-OCR", help="模型路径") parser.add_argument("--server-name", type=str, default="0.0.0.0", help="服务器地址") parser.add_argument("--server-port", type=int, default=7860, help="服务器端口") parser.add_argument("--share", action="store_true", help="是否创建公开分享链接") args = parser.parse_args() # 检查模型路径 if not os.path.exists(args.model_path): print(f"错误: 模型路径不存在: {args.model_path}") sys.exit(1) # 加载模型 model, tokenizer = load_model(args.model_path) # 创建界面 demo = create_ui(model, tokenizer) # 启动服务 demo.launch( server_name=args.server_name, server_port=args.server_port, share=args.share, show_error=True ) if __name__ == "__main__": main()这个完整的示例包含了:
- 原有的OCR识别功能
- 新增的导出功能
- 改进的用户界面布局
- 完整的错误处理
- 使用说明和示例
4. 功能测试与优化
4.1 测试导出功能
修改完成后,我们需要测试导出功能是否正常工作。首先启动服务:
cd /root/GLM-OCR ./start_vllm.sh服务启动后,在浏览器中打开http://localhost:7860,你会看到新的界面,多了一个导出功能区域。
测试步骤:
- 上传一张包含文字的图片
- 点击"开始识别"按钮
- 等待识别完成,查看结果
- 选择导出格式(比如Word文档)
- 点击"导出结果"按钮
- 下载生成的文件并打开验证
4.2 常见问题解决
在测试过程中可能会遇到一些问题,这里提供一些解决方案:
问题1:导出按钮点击后没反应
可能原因:JavaScript错误或函数调用问题 解决方法:
- 检查浏览器控制台是否有错误信息
- 确认
export_utils.py文件在正确位置 - 检查Python依赖是否安装完整
问题2:导出的文件格式不正确
可能原因:文件内容处理逻辑有问题 解决方法:
- 检查
OCRExporter类中的格式处理逻辑 - 确保文本内容正确传递
- 验证文件扩展名是否正确
问题3:中文内容显示乱码
可能原因:编码问题 解决方法:
- 确保所有文件操作使用UTF-8编码
- 在Word和PDF生成时指定中文字体
- 修改
export_utils.py,添加中文字体支持
4.3 添加中文字体支持
为了让导出的Word和PDF正确显示中文,我们需要修改导出工具,添加中文字体支持。更新export_utils.py中的相关方法:
# 在OCRExporter类的export_to_word方法中添加中文字体支持 def export_to_word(self, output_path=None): """导出为Word文档(支持中文)""" if output_path is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/{self.base_name}_{timestamp}.docx" # 创建Word文档 doc = Document() # 添加中文字体支持 from docx.oxml.ns import qn from docx.shared import RGBColor # 设置文档默认字体 doc.styles['Normal'].font.name = '微软雅黑' doc.styles['Normal']._element.rPr.rFonts.set(qn('w:eastAsia'), '微软雅黑') # ... 其余代码保持不变 ...对于PDF,需要确保系统中有中文字体,或者使用支持中文的字体文件。
4.4 性能优化建议
如果处理大量文档或大文件时性能不佳,可以考虑以下优化:
- 异步处理:将导出操作改为异步,避免阻塞界面
- 进度提示:添加导出进度提示
- 批量导出:支持批量处理多个识别结果
- 缓存机制:对相同内容使用缓存,避免重复生成
5. 高级功能扩展
5.1 添加更多导出格式
除了基本的三种格式,你还可以添加更多导出选项:
# 在export_utils.py中添加新格式支持 def export_to_txt(self, output_path=None): """导出为纯文本文件""" if output_path is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/{self.base_name}_{timestamp}.txt" with open(output_path, 'w', encoding='utf-8') as f: f.write(f"OCR识别结果 - {self.base_name}\n") f.write(f"生成时间: {datetime.now().strftime('%Y年%m月%d日 %H:%M:%S')}\n") f.write("=" * 50 + "\n\n") f.write(self.ocr_result) return output_path def export_to_html(self, output_path=None): """导出为HTML文件""" if output_path is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/{self.base_name}_{timestamp}.html" html_content = f"""<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>OCR识别结果 - {self.base_name}</title> <style> body {{ font-family: Arial, sans-serif; margin: 40px; }} .header {{ text-align: center; margin-bottom: 30px; }} .content {{ line-height: 1.6; }} table {{ border-collapse: collapse; width: 100%; margin: 20px 0; }} th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }} th {{ background-color: #f2f2f2; }} </style> </head> <body> <div class="header"> <h1>OCR识别结果 - {self.base_name}</h1> <p>生成时间: {datetime.now().strftime('%Y年%m月%d日 %H:%M:%S')}</p> </div> <div class="content"> {self._ocr_to_html()} </div> </body> </html>""" with open(output_path, 'w', encoding='utf-8') as f: f.write(html_content) return output_path def _ocr_to_html(self): """将OCR结果转换为HTML""" lines = self.ocr_result.strip().split('\n') html_lines = [] for line in lines: if line.strip(): # 判断是否为表格行 if '\t' in line: cells = line.split('\t') if len(html_lines) == 0 or not html_lines[-1].startswith('<table'): html_lines.append('<table>') html_lines.append('<tr>') html_lines.extend(f'<th>{cell.strip()}</th>' for cell in cells) html_lines.append('</tr>') else: html_lines.append('<tr>') html_lines.extend(f'<td>{cell.strip()}</td>' for cell in cells) html_lines.append('</tr>') else: # 结束表格(如果有) if html_lines and html_lines[-1].startswith('</tr>'): html_lines.append('</table>') # 添加段落 html_lines.append(f'<p>{line.strip()}</p>') # 确保表格闭合 if html_lines and html_lines[-1].startswith('</tr>'): html_lines.append('</table>') return '\n'.join(html_lines)然后在界面中添加这些新格式的选项。
5.2 添加批量导出功能
如果需要处理多个文档,可以添加批量导出功能:
def batch_export(ocr_results, format_type, output_dir=None): """ 批量导出多个OCR结果 参数: ocr_results: 列表,每个元素是(图片名, OCR文本)的元组 format_type: 导出格式 output_dir: 输出目录 返回: 压缩包路径 """ import zipfile if output_dir is None: output_dir = "/tmp/ocr_batch_export" os.makedirs(output_dir, exist_ok=True) exported_files = [] for i, (image_name, ocr_text) in enumerate(ocr_results): exporter = OCRExporter(ocr_text, image_name) file_path = exporter.export(format_type, os.path.join(output_dir, f"document_{i+1}")) exported_files.append(file_path) # 创建压缩包 zip_path = os.path.join(output_dir, "batch_export.zip") with zipfile.ZipFile(zip_path, 'w') as zipf: for file_path in exported_files: zipf.write(file_path, os.path.basename(file_path)) return zip_path5.3 添加自定义模板功能
对于需要固定格式的报告,可以添加模板功能:
def export_with_template(self, template_path, output_path=None): """ 使用模板导出 参数: template_path: 模板文件路径(支持.docx) output_path: 输出文件路径 """ from docx import Document # 加载模板 doc = Document(template_path) # 在模板中查找替换标记并替换为OCR内容 # 这里需要根据实际模板设计替换逻辑 if output_path is None: timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") output_path = f"/tmp/{self.base_name}_template_{timestamp}.docx" doc.save(output_path) return output_path6. 总结
通过本文的步骤,我们成功为GLM-OCR的Web UI添加了强大的导出功能。现在,这个OCR工具不仅能够准确识别文档内容,还能将识别结果一键导出为多种常用格式,大大提升了实用性和工作效率。
6.1 实现的核心功能
- 多格式支持:实现了Word、PDF、Markdown三种主流格式的导出
- 智能格式处理:能够识别文本中的表格结构并正确转换
- 用户友好界面:在原有界面上无缝集成,操作简单直观
- 错误处理完善:对各种异常情况都有相应的处理机制
- 中文字体支持:确保中文内容正确显示
6.2 主要改进点
- 实用性提升:从只能查看结果到可以导出使用,完成了工具闭环
- 用户体验优化:添加了状态提示、错误反馈等细节
- 代码结构清晰:将导出功能模块化,便于维护和扩展
- 兼容性良好:与原有功能完全兼容,不影响正常使用
6.3 使用建议
- 日常使用:对于简单的文档识别,直接使用Web界面导出即可
- 批量处理:如果需要处理大量文档,可以考虑扩展批量导出功能
- 定制需求:对于有特殊格式要求的场景,可以开发自定义模板功能
- 性能优化:如果导出速度较慢,可以考虑添加异步处理和进度提示
6.4 扩展可能性
这个导出功能框架具有良好的扩展性,未来可以根据需要添加:
- 更多格式支持:如Excel、PowerPoint、JSON等
- 云端存储集成:直接导出到云盘或协作平台
- API接口:提供REST API供其他系统调用
- 自动化工作流:与自动化工具集成,实现全自动文档处理
通过这次定制开发,我们不仅解决了GLM-OCR的实际使用痛点,也展示了如何基于开源项目进行功能扩展的思路和方法。希望这个方案对你有所帮助,也欢迎在此基础上继续优化和创新。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。