当前位置: 首页 > news >正文

山东大学软件学院项目实训【个人8】

法律文书智能摘要系统文件上传实现分析

一、整体架构设计

该系统采用格式识别 + 策略路由的架构模式,在documents.py中实现统一的上传入口,根据文件扩展名和内容特征自动路由到不同解析器:

┌─────────────────────────────────────────────────────────────┐ │ /api/documents/upload │ └─────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────┐ │ 格式检测 │ │ ext = filename.split │ └─────────────────────────┘ │ │ │ ┌──────────┘ │ └──────────┐ ▼ ▼ ▼ ┌───────────┐ ┌─────────────┐ ┌─────────────┐ │ .txt │ │ .docx │ │ .pdf │ │ 直接解码 │ │ parse_word │ │ parse_pdf │ └───────────┘ └─────────────┘ └─────────────┘ │ ┌───────────┴───────────┐ ▼ ▼ ┌───────────┐ ┌───────────┐ │ is_scanned│ │is_scanned │ │ = False │ │ = True │ │ 返回文本块│ │ ocr_pdf │ └───────────┘ └───────────┘

二、各格式实现详解

1. TXT 格式 - 多编码兼容解码

核心实现documents.py:189-209):

with open(file_path, "rb") as f: raw = f.read() # 尝试不同编码,处理双重UTF-8编码情况 try: text = raw.decode("utf-8") # 检测是否为双重编码(mojibake) if any(c in text for c in ['å', 'é', 'ä', 'ç', 'è']) and not any('\u4e00' <= c <= '\u9fff' for c in text[:200]): text = text.encode('latin-1').decode('utf-8') except (UnicodeDecodeError, UnicodeEncodeError): try: text = raw.decode("gbk") except UnicodeDecodeError: text = raw.decode("utf-8", errors="replace")

技术要点

处理步骤技术手段解决的问题
首选UTF-8解码raw.decode("utf-8")处理标准UTF-8编码文件
双重编码检测mojibake特征字符检测处理Windows下常见的双重编码问题
GBK降级raw.decode("gbk")兼容传统中文Windows编码
容错兜底errors="replace"确保任何情况下都能解析

2. DOCX 格式 - python-docx 解析

核心实现pdf_parser.py:281-307):

def parse_word(file_path: str) -> tuple[DocumentMeta, list[TextBlock]]: from docx import Document as DocxDocument docx_doc = DocxDocument(file_path) blocks: list[TextBlock] = [] for i, para in enumerate(docx_doc.paragraphs): text = para.text.strip() if not text: continue block_type = "title" if para.style and "Heading" in (para.style.name or "") else "text" blocks.append(TextBlock( content=text, page=1, # Word无精确页码,标记为1 bbox=[0, i * 20, 500, (i + 1) * 20], # 近似坐标 block_type=block_type, ))

技术要点

特性实现方式说明
标题识别通过样式名判断"Heading" in para.style.name
段落分割按docx段落对象遍历天然保持段落结构
页码处理统一标记为1Word文档内部无固定页码概念
坐标模拟线性计算近似坐标[0, i*20, 500, (i+1)*20]

3. PDF 非扫描件 - PyMuPDF 高精度解析

核心实现pdf_parser.py:163-278):

def parse_pdf(file_path: str, filter_mode: FilterMode = "keep_all") -> tuple[DocumentMeta, list[TextBlock]]: doc = fitz.open(file_path) is_scanned = detect_scanned(doc) # 扫描件检测 if is_scanned: doc.close() return meta, [] # 返回空块,后续走OCR for page_num in range(len(doc)): page = doc[page_num] page_dict = page.get_text("dict") for block in page_dict.get("blocks", []): if block.get("type") == 0: # text block for line in block.get("lines", []): line_text = "" for span in line.get("spans", []): line_text += span.get("text", "").strip() # 判断行类型(页眉/页脚/正文/标题) block_type = "title" if max_font_size > 14 else "text" if line_bbox[1] < 50: block_type = "header" elif line_bbox[3] > page.rect.height - 50: block_type = "footer"

扫描件检测算法pdf_parser.py:12-19):

def detect_scanned(doc: fitz.Document, sample_pages: int = 3) -> bool: """检测PDF是否为扫描件:前几页文本极少则判定为扫描件""" pages_to_check = min(sample_pages, len(doc)) total_text = "" for i in range(pages_to_check): total_text += doc[i].get_text() return len(total_text.strip()) < 50 * pages_to_check

段落合并算法pdf_parser.py:50-107):

判断条件阈值说明
行尾空缺比例gap_ratio > 0.20行尾空白超过页面宽度20%
垂直间距> 2.5 * font_size段落间距大于2.5倍行高
字体大小变化> 1.5字号变化超过1.5磅

4. PDF 扫描件 - OCR + LLM勘误

核心实现ocr_service.py:65-150):

def ocr_pdf(file_path: str) -> list[TextBlock]: doc = fitz.open(file_path) blocks: list[TextBlock] = [] for page_num in range(len(doc)): page = doc[page_num] # 1. 页面渲染为图像(300 DPI) pix = page.get_pixmap(dpi=300) img = Image.open(io.BytesIO(pix.tobytes("png"))) # 2. 图像预处理 preprocessed_img = preprocess_image(img) # 3. Tesseract OCR ocr_data = pytesseract.image_to_data( preprocessed_img, lang="chi_sim", output_type=pytesseract.Output.DICT )

图像预处理流程ocr_service.py:21-62):

原始图像 → 灰度化 → 二值化(Otsu阈值)→ 中值滤波去噪 → 倾斜校正 → OCR识别

后端调用链路documents.py:174-185):

if meta.is_scanned: # 首先进行OCR识别 ocr_blocks = ocr_pdf(file_path) # 然后使用LLM进行勘误和标准化 blocks, ocr_correction = enhance_ocr_results(ocr_blocks)

三、四种格式实现对比

维度TXTDOCXPDF(非扫描)PDF(扫描件)
解析引擎Python内置解码python-docxPyMuPDFTesseract OCR
文本精度无损无损无损依赖图像质量
结构保留仅段落标题/段落完整结构+坐标OCR重建结构
页眉页脚处理N/AN/A可配置过滤OCR后处理
页码信息精确精确
坐标信息模拟精确像素转换
置信度N/AN/AN/A字符级置信度
处理耗时极快较快中等较慢
内存占用

四、技术亮点总结

1. 智能扫描件检测

  • 基于文本密度判断,阈值50 * pages_to_check
  • 兼顾准确性和性能,仅采样前3页

2. 多编码容错机制

  • UTF-8优先,GBK降级,容错兜底
  • 双重编码自动检测(mojibake特征)

3. 段落边界智能识别

  • 融合行尾空缺、垂直间距、字体变化三重判断
  • 自适应阈值,避免过度分割或合并

4. OCR质量优化

  • 完整的图像预处理流水线
  • 字符级置信度输出,支持后续LLM勘误

5. 渐进式处理策略

  • 同步完成:文件保存、基础解析、信息抽取、文本切片
  • 后台异步:LLM分类、向量化、A-MEM吸收
  • 提升用户体验,避免长时间等待
http://www.gsyq.cn/news/1506927.html

相关文章:

  • 15分钟搞定专业级黑苹果EFI配置:OpCore-Simplify终极指南
  • MPC7447A处理器硬件设计实战:从规格书解读到电源、时钟与热设计
  • Claude Fable 5 和 Opus 4.8 怎么选:性能、价格和场景一次讲清
  • 超越基础地图:用微信小程序map组件打造一个交互式区域标注工具
  • MPC852T PowerQUICC双核架构解析与嵌入式通信系统实战指南
  • 别再手动摆Off-Page了!用Tcl脚本给OrCAD Capture加个‘智能连线助手’(附完整源码)
  • P89LPC9408增强型51单片机:双时钟架构与低功耗设计实战
  • Keil5 C51项目里extern用错,ERROR L104报错怎么破?手把手教你正确声明全局变量
  • 一线通协议实战:从引脚中断到数据帧解析
  • 【无人机三维路径规划】基于蚁群算法ACO无人机三维路径规划(目标函数:最优成本 路径 高度 威胁 转角)附Matlab代码
  • 2026年 重庆化工原料厂家推荐榜单:元明粉/小苏打/硫酸镁/片碱(食品级)/纯碱/盐酸/硝酸/乙二醇等工业与食品级原料实力品牌 - 品牌发掘
  • 别只刷题了!蓝桥杯EDA设计与开发,客观题高分攻略与PCB工程师面试题解析
  • 如何高效获取网盘直链:一站式跨平台下载解决方案
  • 用Python打造你的专属密码生成器:从XKCD风格到命令行工具
  • 深入浅出解析Si24R1无线芯片:从寄存器配置到Arduino SPI驱动G01-S模块的底层逻辑
  • DDrawCompat终极指南:让Windows经典游戏在现代系统上完美运行
  • 解密FreeBSD 13.2上的OpenMP与ImageMagick问题
  • 企业级数据集成平台架构:基于Kettle的微服务化ETL解决方案
  • 技术深度解析:.NET MAUI Community Toolkit - 跨平台开发效率提升的10个实战案例
  • 如何在5分钟内掌握Vue Json Pretty:Vue.js JSON数据可视化终极指南
  • 汽车级LCD段码驱动芯片PCA8543:原理、配置与硬件设计实战
  • MPC8343EA时钟与热管理设计:从PLL配置到散热器选型实战
  • 如何实现个性化定制:Mi-Create 为小米穿戴设备打造专属表盘的完整指南
  • Figma中文界面汉化插件:5分钟告别英文设计障碍
  • 2026年重庆市场知名小程序开发公司,哪家才是可靠之选? - 资讯纵览
  • okbiye 论文降重降 AIGC:双维度优化破解高校双重检测关卡
  • 云函数平台兼容性探讨
  • 2026 海南注册公司全指南:税收优惠 | 政策流程 | 费用明细 | 代办避坑及本土机构 TOP6 - 资讯纵览
  • 给你的Modbus TCP通信加个‘监听器’:深入玩转modbus_tk的Hook函数
  • 如何高效管理多世代宝可梦存档:专业工具完全指南