| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- """
- utils.py - 工具函数模块
- 提供日志配置、文本分块和表格转换等通用工具函数。
- """
- import logging
- import sys
- logger = logging.getLogger(__name__)
- def setup_logging(verbose: bool = False):
- """配置日志格式。
- - verbose=True: DEBUG级别,显示文件名行号
- - verbose=False: INFO级别,简洁格式
- Args:
- verbose: 是否开启详细日志模式
- """
- level = logging.DEBUG if verbose else logging.INFO
- fmt = (
- "%(asctime)s [%(levelname)s] %(name)s (%(filename)s:%(lineno)d): %(message)s"
- if verbose
- else "[%(levelname)s] %(message)s"
- )
- logging.basicConfig(
- level=level,
- format=fmt,
- stream=sys.stderr,
- force=True,
- )
- def chunk_text(text: str, max_chars: int = 4000) -> list[str]:
- """将长文本按最大字符数切分,尽量在段落边界处切分。
- Args:
- text: 待切分的文本
- max_chars: 每个块的最大字符数(默认 4000)
- Returns:
- 切分后的文本块列表
- """
- if not text:
- logger.debug("chunk_text 收到空文本,返回空列表")
- return []
- if max_chars <= 0:
- logger.warning("max_chars=%d 无效,使用默认值 4000", max_chars)
- max_chars = 4000
- if len(text) <= max_chars:
- logger.debug("文本长度 %d <= %d,无需切分", len(text), max_chars)
- return [text]
- chunks: list[str] = []
- start = 0
- while start < len(text):
- # 如果剩余文本不足 max_chars,直接取剩余全部
- if start + max_chars >= len(text):
- chunks.append(text[start:])
- break
- # 在当前块末尾附近寻找段落边界(换行符)
- end = start + max_chars
- # 在 [start+max_chars//2, start+max_chars] 范围内向前找最后一个换行符
- search_start = max(start + max_chars // 2, start)
- boundary = text.rfind("\n", search_start, end)
- if boundary <= start:
- # 找不到合适换行符,在最大范围内向后找
- boundary = text.find("\n", end)
- if boundary == -1 or boundary >= start + int(max_chars * 1.5):
- # 仍然找不到,直接在 max_chars 处切分
- boundary = end
- chunk = text[start:boundary].strip()
- if chunk:
- chunks.append(chunk)
- start = boundary + 1 # 跳过换行符
- logger.debug("文本已切分为 %d 个块", len(chunks))
- return chunks
- def table_to_markdown(table_info) -> str:
- """将 pdf_table_to_docx.table_parser.TableInfo 转换为 Markdown 表格格式。
- 用于将表格内容序列化为文本,方便传给 AI。
- Args:
- table_info: 来自 pdf_table_to_docx 的 TableInfo 对象
- Returns:
- Markdown 格式的表格字符串
- """
- # 输入校验
- if table_info is None:
- logger.warning("table_to_markdown 收到 None 输入")
- return "(空表格)"
- if not hasattr(table_info, "cells"):
- logger.warning("table_to_markdown 收到的对象没有 cells 属性")
- return "(空表格)"
- rows = table_info.cells # list[list[CellInfo]]
- if not rows:
- logger.debug("table_to_markdown: 空表格(无行)")
- return "(空表格)"
- lines: list[str] = []
- for row_idx, row in enumerate(rows):
- # 提取该行每个单元格的文本,去除首尾空白
- cell_texts = [cell.text.strip() if hasattr(cell, "text") else str(cell).strip() for cell in row]
- # 用 | 分隔单元格
- lines.append("| " + " | ".join(cell_texts) + " |")
- # 在第一行之后添加分隔行(表头分隔符)
- if row_idx == 0:
- lines.append("|" + "|".join("---" for _ in row) + "|")
- return "\n".join(lines)
|