diff --git a/README.md b/README.md index f644c7e..c3ca897 100644 --- a/README.md +++ b/README.md @@ -2,76 +2,97 @@ 统一文档解析工具 - 将 DOCX、XLSX、PPTX、PDF、HTML/URL 转换为 Markdown +## 项目概述 + +面向 AI Skill 的统一文档解析工具,支持多种文档格式解析为 Markdown,提供全文输出、字数统计、标题提取、内容搜索等功能。 + ## 开发环境 - 使用 uv 运行脚本和测试,禁用主机 Python - 依赖管理:使用 `uv run --with` 按需加载依赖 -- 快速获取建议:使用 `-a/--advice` 参数查看执行命令,无需手动查找依赖 +- 快速获取建议:使用 `-a/--advice` 参数查看执行命令 -## 项目结构 +## 项目架构 ``` -scripts/ # 核心代码 -├── core/ # 核心模块 -│ ├── advice_generator.py # 执行建议生成器(新增) -│ ├── parser.py # 解析调度 -│ ├── exceptions.py # 异常定义 -│ └── markdown.py # Markdown 工具 -├── readers/ # 格式阅读器 -├── utils/ # 工具函数 -└── config.py # 配置(含 DEPENDENCIES 依赖配置) -tests/ # 测试 -openspec/ # 规范文档 -skill/ # SKILL 文档 +scripts/ +├── lyxy_document_reader.py # CLI 入口 +├── config.py # 配置(含 DEPENDENCIES 依赖配置) +├── core/ # 核心模块 +│ ├── parser.py # 解析调度 +│ ├── advice_generator.py # --advice 执行建议生成器 +│ ├── markdown.py # Markdown 工具 +│ └── exceptions.py # 异常定义 +├── readers/ # 格式阅读器 +│ ├── base.py # Reader 基类 +│ ├── docx/ # DOCX 解析器 +│ ├── xlsx/ # XLSX 解析器 +│ ├── pptx/ # PPTX 解析器 +│ ├── pdf/ # PDF 解析器 +│ └── html/ # HTML/URL 解析器 +└── utils/ # 工具函数 + ├── file_detection.py # 文件检测 + └── encoding_detection.py # 编码检测 + +tests/ # 测试套件 +openspec/ # OpenSpec 规范文档 +README.md # 本文档(开发者文档) +SKILL.md # AI Skill 文档 ``` -## 开发工作流 +## 核心概念 -使用 `uv run --with` 方式运行测试和开发工具: +### Reader 机制 +每种文档格式对应一个 Reader 包,包含多个解析实现。Reader 基类定义 `supports()` 和 `parse()` 方法,解析器按顺序尝试,第一个成功的结果返回。 + +### 依赖配置 (config.DEPENDENCIES) + +按文件类型和平台组织依赖配置: + +```python +DEPENDENCIES = { + "pdf": { + "default": { + "python": None, + "dependencies": ["docling", "unstructured[pdf]", ...] + }, + "Darwin-x86_64": { + "python": "3.12", + "dependencies": ["docling==2.40.0", ...] + } + }, + ... +} +``` + +### --advice 生成机制 + +`--advice` 参数根据文件扩展名识别类型,检测当前平台,从 `config.DEPENDENCIES` 读取对应配置,生成 `uv run --with` 和 `pip install` 命令。 + +## 开发指南 + +### 如何添加新的 Reader + +1. 在 `scripts/readers/` 下创建新目录 +2. 继承 `BaseReader` 实现 `supports()` 和 `parse()` +3. 在 `scripts/readers/__init__.py` 中注册 +4. 在 `config.DEPENDENCIES` 中添加依赖配置 + +### 如何测试 + +项目包含完整的测试套件,覆盖 CLI 和所有 Reader 实现。根据测试类型使用对应的 `uv run --with` 命令。 + +#### 运行所有测试 ```bash -# 运行测试(需要先安装 pytest) uv run \ --with pytest \ --with pytest-cov \ --with chardet \ pytest - -# 运行测试并查看覆盖率 -uv run \ - --with pytest \ - --with pytest-cov \ - --with chardet \ - pytest --cov=scripts --cov-report=term-missing - -# 运行特定测试文件 -uv run \ - --with pytest \ - --with chardet \ - pytest tests/test_readers/test_docx/ - -# 运行特定测试类或方法 -uv run \ - --with pytest \ - --with chardet \ - pytest tests/test_cli/test_main.py::TestCLIDefaultOutput::test_default_output_docx - -# 代码格式化 -uv run \ - --with black \ - --with isort \ - --with chardet \ - bash -c "black . && isort ." - -# 类型检查 -uv run \ - --with mypy \ - --with chardet \ - mypy . ``` -**测试 DOCX reader**: - +#### 测试 DOCX reader ```bash uv run \ --with pytest \ @@ -85,8 +106,33 @@ uv run \ pytest tests/test_readers/test_docx/ ``` -**测试 PDF reader**: +#### 测试 XLSX reader +```bash +uv run \ + --with pytest \ + --with docling \ + --with "unstructured[xlsx]" \ + --with "markitdown[xlsx]" \ + --with pandas \ + --with tabulate \ + --with chardet \ + pytest tests/test_readers/test_xlsx/ +``` +#### 测试 PPTX reader +```bash +uv run \ + --with pytest \ + --with docling \ + --with "unstructured[pptx]" \ + --with "markitdown[pptx]" \ + --with python-pptx \ + --with markdownify \ + --with chardet \ + pytest tests/test_readers/test_pptx/ +``` + +#### 测试 PDF reader ```bash # 默认命令(macOS ARM、Linux、Windows) uv run \ @@ -97,6 +143,7 @@ uv run \ --with pypdf \ --with markdownify \ --with chardet \ + --with reportlab \ pytest tests/test_readers/test_pdf/ # macOS x86_64 (Intel) 特殊命令 @@ -110,35 +157,12 @@ uv run \ --with pypdf \ --with markdownify \ --with chardet \ + --with reportlab \ pytest tests/test_readers/test_pdf/ ``` -**测试其他格式**: - +#### 测试 HTML reader ```bash -# XLSX reader -uv run \ - --with pytest \ - --with docling \ - --with "unstructured[xlsx]" \ - --with "markitdown[xlsx]" \ - --with pandas \ - --with tabulate \ - --with chardet \ - pytest tests/test_readers/test_xlsx/ - -# PPTX reader -uv run \ - --with pytest \ - --with docling \ - --with "unstructured[pptx]" \ - --with "markitdown[pptx]" \ - --with python-pptx \ - --with markdownify \ - --with chardet \ - pytest tests/test_readers/test_pptx/ - -# HTML reader uv run \ --with pytest \ --with trafilatura \ @@ -151,74 +175,43 @@ uv run \ pytest tests/test_readers/test_html/ ``` -## 测试 +#### 运行特定测试文件或方法 +```bash +# 运行特定测试文件 +uv run \ + --with pytest \ + --with chardet \ + pytest tests/test_cli/test_main.py -项目包含完整的测试套件,覆盖 CLI 和所有 Reader 实现: +# 运行特定测试类或方法 +uv run \ + --with pytest \ + --with docling \ + --with chardet \ + pytest tests/test_cli/test_main.py::TestCLIDefaultOutput::test_default_output_docx +``` -- **测试覆盖率**: 69% -- **测试数量**: 193 个测试 -- **测试类型**: - - CLI 功能测试(字数统计、行数统计、标题提取、搜索等) - - Reader 解析测试(DOCX、PDF、HTML、PPTX、XLSX) - - 多 Reader 实现测试(每种格式测试多个解析库) - - 异常场景测试(文件不存在、空文件、损坏文件、特殊字符) - - 编码测试(GBK、UTF-8 BOM 等) - - 一致性测试(验证不同 Reader 解析结果的一致性) +#### 查看测试覆盖率 +```bash +uv run \ + --with pytest \ + --with pytest-cov \ + --with chardet \ + pytest --cov=scripts --cov-report=term-missing +``` -运行测试前,请根据测试类型使用 `uv run --with` 安装对应的依赖包。详见上方的"开发工作流"章节。 - - -## 代码规范 +### 代码规范 - 语言:仅中文(交流、注释、文档、代码) - 模块文件:150-300 行 - 错误处理:自定义异常 + 清晰信息 + 位置上下文 -- Git 提交:类型: 简短描述(feat/fix/refactor/docs/style/test/chore) +- Git 提交:`类型: 简短描述`(feat/fix/refactor/docs/style/test/chore) -## Skill 文档规范 +## 文档说明 -skill/SKILL.md 面向 AI 用户,必须遵循 Claude Skill 构建指南的最佳实践: - -### YAML frontmatter - -- **name**: kebab-case 格式 -- **description**: 包含功能说明、触发词、文件类型、典型任务 -- **license**: MIT -- **metadata**: 包含 version、author -- **compatibility**: 说明 Python 版本要求和依赖情况 - -### 文档章节结构 - -1. **Purpose**: 说明统一入口和双路径执行策略 -2. **When to Use**: 典型场景和触发词列表(中英文、文件扩展名) -3. **Quick Reference**: 命令参数表格 -4. **Workflow**: 4 步工作流程(检测环境、识别类型、执行解析、输出结果) -5. **使用示例**: 各文档类型的基本用法和高级用法 -6. **错误处理**: 常见错误及解决方案 -7. **References**: 指向项目文档的链接 - -### 依赖管理 - -- 使用 `uv run --with` 方式按需加载依赖 -- 必须使用具体的 pip 包名 -- 使用 `-a/--advice` 参数可快速获取针对具体文件的执行命令 - -## 解析器架构 - -### DOCX -docling、unstructured、pypandoc-binary、MarkItDown、python-docx、XML - -### XLSX -docling、unstructured、MarkItDown、pandas、XML - -### PPTX -docling、unstructured、MarkItDown、python-pptx、XML - -### PDF(OCR 优先) -docling OCR、unstructured OCR、docling、unstructured、MarkItDown、pypdf - -### HTML/URL -trafilatura、domscribe、MarkItDown、html2text +- **README.md**(本文档):面向项目开发者 +- **SKILL.md**:面向 AI 使用的 Skill 文档 +- **openspec/**:OpenSpec 规范文档 ## 许可证 diff --git a/SKILL.md b/SKILL.md index 3c5d031..bb19f32 100644 --- a/SKILL.md +++ b/SKILL.md @@ -5,92 +5,89 @@ license: MIT metadata: version: "1.0" author: lyxy -compatibility: Requires Python 3.11+. 使用 uv run --with 方式按需加载依赖。 +compatibility: Requires Python 3.11+。优先使用 lyxy-runner-python skill,次选 uv run --with,降级到主机 Python。 --- # 统一文档解析 Skill -将 DOCX、XLSX、PPTX、PDF、HTML 文件或 URL 网页内容解析为 Markdown 格式,支持多种查询模式。 - ## Purpose -**统一入口**:使用 `scripts/lyxy_document_reader.py` 作为统一的命令行入口,自动识别文件类型并执行解析。 +**第一步:获取执行建议** -**快速获取建议(必须优先使用)**:使用 `-a/--advice` 参数获取准确的执行建议,包含 `uv run --with ...` 命令和 `python` 命令,无需阅读此文档的后续内容。 +```bash +python scripts/lyxy_document_reader.py --advice <文件路径或URL> +``` -**支持的文档类型**: -- **DOCX**:Word 文档 -- **XLSX**:Excel 表格 -- **PPTX**:PowerPoint 演示文稿 -- **PDF**:PDF 文档(支持 OCR) -- **HTML/URL**:HTML 文件或网页地址 +这会输出准确的执行命令,包含所需的依赖配置。 + +**执行路径优先级** +1. **lyxy-runner-python skill(首选)** - 自动管理依赖 +2. **uv run --with** - 按需加载依赖 +3. **主机 Python + pip install** - 手动安装依赖 + +**支持格式** +- DOCX(Word 文档) +- XLSX(Excel 表格) +- PPTX(PowerPoint 演示文稿) +- PDF(PDF 文档,支持 OCR) +- HTML / URL(网页内容) ## When to Use -任何需要读取或解析 Office 文档、PDF、HTML 文件、URL 网页内容的任务都应使用此 skill。 - -### 典型场景 -- **文档转换**:将各类文档转换为可读的 Markdown 文本 -- **文档元数据**:获取文档的字数、行数等信息 -- **标题分析**:提取文档的标题结构 -- **章节提取**:提取特定章节的内容 -- **内容搜索**:在文档中搜索关键词或正则模式 +### 触发场景 +- 文档转换:将各类文档转为 Markdown +- 文档元数据:字数、行数统计 +- 标题分析:提取标题结构 +- 章节提取:提取特定章节 +- 内容搜索:关键词或正则搜索 ### 触发词 -- **中文**:"读取/解析/打开 文档/Word/Excel/PPT/PDF/网页" -- **英文**:"read/parse/extract document/docx/xlsx/pptx/pdf/html" -- **文件扩展名**:`.docx`、`.xlsx`、`.pptx`、`.pdf`、`.html`、`.htm` -- **URL 模式**:`http://`、`https://` +- 中文:"读取/解析/打开 文档/Word/Excel/PPT/PDF/网页" +- 英文:"read/parse/extract document/docx/xlsx/pptx/pdf/html" +- 文件扩展名:`.docx`、`.xlsx`、`.pptx`、`.pdf`、`.html`、`.htm` +- URL:`http://`、`https://` ## Quick Reference | 参数 | 说明 | |------|------| -| `-a` / `--advice` | 仅显示执行建议,不实际解析文件(必须优先使用) | -| (无参数) | 输出完整 Markdown 内容 | -| `-c` / `--count` | 字数统计 | -| `-l` / `--lines` | 行数统计 | -| `-t` / `--titles` | 提取所有标题(1-6级) | +| `-a/--advice` | 仅显示执行建议(**必须先运行此命令**) | +| (无) | 输出完整 Markdown | +| `-c/--count` | 字数统计 | +| `-l/--lines` | 行数统计 | +| `-t/--titles` | 提取所有标题(1-6级) | | `-tc ` | 提取指定标题的章节内容 | | `-s ` | 正则表达式搜索 | -| `-n ` / `--context ` | 与 `-s` 配合,指定上下文行数(默认2) | +| `-n /--context ` | 与 `-s` 配合,指定上下文行数(默认 2) | ## Workflow -0. **获取执行建议(必须优先执行)**: +1. **获取执行建议** ```bash - python scripts/lyxy_document_reader.py --advice <文件路径或URL> + python scripts/lyxy_document_reader.py --advice <文件> ``` - - 根据建议中的命令执行即可,无需继续阅读后续内容 -1. **检测执行环境**: - - 优先检测 **lyxy-runner-python skill** 是否可用 - - 可用 → 使用 lyxy-runner-python skill 执行 - - 不可用 → 回退到主机 Python 环境 +2. **选择执行方式** + - 优先使用 lyxy-runner-python skill + - 其次使用建议中的 uv 命令 + - 最后使用建议中的 pip + python 命令 -2. **识别文件类型**: - - 根据文件扩展名自动选择对应的解析器 - - URL 自动识别为 HTML/网页类型 +3. **添加需要的参数** + - 如 `-c`、`-t`、`-s` 等 -3. **输出结果**: - - 返回 Markdown 格式内容或统计信息 - -### 使用示例 +## 参数使用示例 ```bash -# 获取执行建议(必须优先执行此命令) +# 获取执行建议 python scripts/lyxy_document_reader.py --advice document.docx -# 读取 Word 文档 +# 读取全文 python scripts/lyxy_document_reader.py document.docx -# 解析网页内容 -python scripts/lyxy_document_reader.py https://example.com - # 统计字数 python scripts/lyxy_document_reader.py document.docx -c -# 提取所有标题 +# 提取标题 python scripts/lyxy_document_reader.py document.docx -t # 提取指定章节 @@ -102,17 +99,17 @@ python scripts/lyxy_document_reader.py document.docx -s "关键词" # 正则搜索 python scripts/lyxy_document_reader.py document.docx -s "\d{4}-\d{2}-\d{2}" -# 指定上下文行数 +# 指定搜索上下文行数 python scripts/lyxy_document_reader.py document.docx -s "关键词" -n 5 ``` ## 错误处理 -| 错误信息 | 原因 | 解决 | -|---------|------|------| +| 错误 | 原因 | 解决 | +|------|------|------| | 错误: input_path 不能为空 | 未提供输入 | 提供 file_path 或 URL | | 错误: 不支持的文件类型 | 无对应 reader | 检查文件扩展名 | | 所有解析方法均失败 | 所有解析器失败 | 检查文件是否损坏 | | 错误: 无效的正则表达式 | 正则语法错误 | 检查正则语法 | | 错误: 未找到匹配 | 搜索无结果 | 检查搜索词或正则 | -| ModuleNotFoundError: No module named 'xxx' | 缺少依赖 | 使用 lyxy-runner-python 或 pip 安装对应依赖 | +| ModuleNotFoundError | 缺少依赖 | 使用 --advice 获取正确的依赖命令 | diff --git a/openspec/specs/skill-documentation/spec.md b/openspec/specs/skill-documentation/spec.md index 8cc9297..398e9fa 100644 --- a/openspec/specs/skill-documentation/spec.md +++ b/openspec/specs/skill-documentation/spec.md @@ -1,7 +1,7 @@ ## ADDED Requirements ### Requirement: SKILL.md 遵循 Claude Skill 构建指南 -SKILL.md 文档必须遵循 Claude 官方 Skill 构建指南的最佳实践,包括渐进式披露的三级系统、清晰的触发词和完整的章节结构。 +SKILL.md 文档必须遵循 Claude 官方 Skill 构建指南的最佳实践,包括渐进式披露的三级系统、清晰的触发词和完整的章节结构。SKILL.md 必须将 --advice 参数作为首选方案放在最前面强调。 #### Scenario: Claude 正确加载 skill - **WHEN** 用户询问与文档解析相关的问题 @@ -11,6 +11,10 @@ SKILL.md 文档必须遵循 Claude 官方 Skill 构建指南的最佳实践, - **WHEN** skill 被加载 - **THEN** AI 应能从 Purpose 和 When to Use 章节了解何时使用此 skill +#### Scenario: --advice 放在最前面 +- **WHEN** AI 查看 SKILL.md +- **THEN** Purpose 章节第一部分就是 --advice 的使用说明 + ### Requirement: YAML frontmatter 包含完整元数据 YAML frontmatter 必须包含 name、description(带触发词)、license、metadata 和 compatibility 字段。 @@ -18,31 +22,39 @@ YAML frontmatter 必须包含 name、description(带触发词)、license、m - **WHEN** 查看 YAML frontmatter - **THEN** description 应包含功能说明、触发条件和用户可能说的具体任务 -#### Scenario: compatibility 说明依赖 +#### Scenario: compatibility 说明依赖和执行路径优先级 - **WHEN** 查看 YAML frontmatter -- **THEN** compatibility 应说明 Python 版本要求和两种执行路径的依赖情况 +- **THEN** compatibility 应说明 Python 版本要求和三种执行路径的优先级(lyxy-runner-python skill → uv → 主机 Python) -### Requirement: 双路径执行策略 -skill 文档必须说明两种执行路径:优先使用 lyxy-runner-python skill,回退到主机 Python 环境。 +### Requirement: 三路径执行策略 +skill 文档必须说明三种执行路径,优先级为:1. lyxy-runner-python skill,2. uv run --with,3. 主机 Python 环境。 #### Scenario: lyxy-runner-python 可用 - **WHEN** lyxy-runner-python skill 已安装 - **THEN** 文档说明使用 lyxy-runner-python 自动管理依赖 -#### Scenario: lyxy-runner-python 不可用 +#### Scenario: 使用 uv run --with - **WHEN** lyxy-runner-python skill 不可用 +- **THEN** 文档说明使用 --advice 获取 uv run --with 命令 + +#### Scenario: 降级到主机 Python +- **WHEN** uv 也不可用 - **THEN** 文档说明如何手动安装具体依赖包并使用主机 Python -### Requirement: 依赖说明使用具体包名 -文档必须列出每个文档类型需要的具体 pip 包名,不能使用 lyxy-document[xxx] 形式(因为发布时没有 pyproject.toml)。 +### Requirement: --advice 是首选方案 +SKILL.md 必须将 --advice 参数作为获取准确命令的首选方案,移除冗余的手动依赖命令示例块(仅保留简洁参考)。 -#### Scenario: 用户安装 DOCX 依赖 -- **WHEN** 用户需要解析 DOCX 文档 -- **THEN** 文档列出具体命令:pip install docling unstructured markitdown pypandoc-binary python-docx markdownify chardet +#### Scenario: --advice 是第一步 +- **WHEN** AI 阅读 SKILL.md +- **THEN** 首先看到 --advice 的使用说明 -#### Scenario: 用户安装 PDF 依赖 -- **WHEN** 用户需要解析 PDF 文档 -- **THEN** 文档列出具体命令:pip install docling unstructured unstructured-paddleocr markitdown pypdf markdownify chardet +#### Scenario: 依赖命令以 --advice 输出为准 +- **WHEN** AI 需要了解依赖命令 +- **THEN** 文档引导 AI 使用 --advice 获取,而非阅读文档中的示例 + +#### Scenario: 保留简洁参数示例 +- **WHEN** AI 需要了解参数用法 +- **THEN** 文档提供简洁的参数使用示例(不含大段依赖命令) ### Requirement: 文档包含关键章节 SKILL.md 必须包含 Purpose、When to Use、Quick Reference、Workflow 等章节,遵循渐进式披露原则。 @@ -53,7 +65,7 @@ SKILL.md 必须包含 Purpose、When to Use、Quick Reference、Workflow 等章 #### Scenario: 了解执行流程 - **WHEN** AI 需要理解解析流程 -- **THEN** Workflow 章节说明 4 步工作流程 +- **THEN** Workflow 章节说明 3 步工作流程(获取建议 → 选择执行方式 → 添加参数) ### Requirement: 触发词覆盖多种表达方式 description 和 When to Use 章节必须包含中文和英文的触发词,以及文件扩展名。 @@ -71,7 +83,7 @@ description 和 When to Use 章节必须包含中文和英文的触发词,以 #### Scenario: 依赖缺失错误 - **WHEN** 出现 ModuleNotFoundError -- **THEN** 错误处理表格说明需要安装对应的依赖包 +- **THEN** 错误处理表格说明需要使用 --advice 获取正确的依赖命令 #### Scenario: 文件类型不支持 - **WHEN** 出现"不支持的文件类型"错误 diff --git a/openspec/specs/uv-with-dependency-management/spec.md b/openspec/specs/uv-with-dependency-management/spec.md index a0c104e..6957ef6 100644 --- a/openspec/specs/uv-with-dependency-management/spec.md +++ b/openspec/specs/uv-with-dependency-management/spec.md @@ -7,12 +7,12 @@ ## Requirements ### Requirement: 文档驱动的依赖声明 -系统必须在 SKILL.md 和 README.md 中明确说明每种文档格式和平台所需的依赖包。 +系统必须在 SKILL.md 和 README.md 中明确说明每种文档格式和平台所需的依赖包。README.md 面向开发者,提供开发和测试的命令示例;SKILL.md 面向 AI,强调 --advice 优先。 -#### Scenario: SKILL.md 包含完整的依赖命令 +#### Scenario: SKILL.md 强调 --advice 而非完整命令 - **WHEN** AI 或用户阅读 SKILL.md -- **THEN** 文档必须为每种文档格式(DOCX/XLSX/PPTX/PDF/HTML)和平台提供完整的 `uv run --with` 命令示例 -- **AND** 命令必须包含所有必需的依赖包 +- **THEN** 文档引导使用 --advice 获取准确命令,不提供完整的 `uv run --with` 命令块 +- **AND** 仅保留简洁的参数使用示例 #### Scenario: README.md 包含开发依赖速查表 - **WHEN** 开发者阅读 README.md