Metadata-Version: 2.4
Name: office2md
Version: 0.5.6
Summary: Convert Microsoft Office documents (DOCX, XLSX, PPTX) and PDFs to Markdown
Author-email: Rodrigo <rod.gui@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/rodgui/office2md
Project-URL: Documentation, https://github.com/rodgui/office2md#readme
Project-URL: Repository, https://github.com/rodgui/office2md.git
Project-URL: Issues, https://github.com/rodgui/office2md/issues
Project-URL: Changelog, https://github.com/rodgui/office2md/blob/main/CHANGELOG.md
Keywords: markdown,docx,xlsx,pptx,pdf,converter,office,word,excel,powerpoint
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Text Processing :: Markup :: Markdown
Classifier: Topic :: Office/Business
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-docx>=1.1.0
Requires-Dist: openpyxl>=3.1.0
Requires-Dist: python-pptx>=0.6.23
Requires-Dist: mammoth>=1.6.0
Requires-Dist: markdownify>=0.11.0
Requires-Dist: Pillow>=9.0.0
Provides-Extra: pdf
Requires-Dist: docling>=1.0.0; extra == "pdf"
Provides-Extra: visual
Requires-Dist: PyMuPDF>=1.23.0; extra == "visual"
Provides-Extra: dev
Requires-Dist: pytest>=7.0.0; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
Requires-Dist: black>=23.0.0; extra == "dev"
Requires-Dist: ruff>=0.1.0; extra == "dev"
Requires-Dist: mypy>=1.0.0; extra == "dev"
Provides-Extra: all
Requires-Dist: office2md[dev,pdf,visual]; extra == "all"
Dynamic: license-file

# office2md

Convert Microsoft Office documents to Markdown with intelligent converter selection.

[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## Features

- **DOCX** → Markdown with images, tables, and formatting
- **XLSX** → Markdown tables (single or all sheets)
- **PPTX** → Markdown with slide content and speaker notes
- **PDF** → Markdown using local ML/OCR extraction (via Docling)
- **Batch processing** with recursive directory support
- **Automatic image extraction** to a separate folder with sanitized paths
- **Normalized DOCX pipeline** — recovers section hierarchy from Word documents that use auto-numbered lists instead of real headings
- **Optional local-only privacy mode** for sensitive documents
- **Optional visual QA gate** with rendered page diffs and JSON/HTML reports
- **Standalone wiki builder** for simple, semantic/agent, or MkDocs-published Markdown wikis

## Installation

```bash
pip install office2md
```

For best results with DOCX files, also install Pandoc:

```bash
# macOS
brew install pandoc

# Ubuntu/Debian
sudo apt-get install pandoc

# Windows
choco install pandoc
```

For PDF support:

```bash
pip install docling
```

For visual QA:

```bash
pip install office2md[visual]
# DOCX visual QA also requires LibreOffice/soffice on PATH.
```

## Quick Start

```bash
# Convert a single file (auto-selects best converter)
office2md document.docx

# Specify output path
office2md document.docx -o output/result.md

# Convert all files in a directory
office2md --batch ./input -o ./output

# Recursive batch processing
office2md --batch ./input -o ./output --recursive

# Mirror a source tree into an idempotent Markdown tree for wiki/KB work
office2md --mirror ./input -o ./output --recursive --dry-run
office2md --mirror ./input -o ./output --recursive --overwrite --include docx,pdf

# Build an agent-facing Markdown wiki from converted output
office2md-wiki ./output -o ./knowledge-wiki --title "Knowledge Wiki" --mode semantic
```

## Normalized DOCX Pipeline

Many corporate Word documents are structured using **auto-numbered lists** instead of real heading styles. When converted with standard tools, these documents lose their section hierarchy — chapters and sub-sections become flat bullet lists.

The `office2md` converter detects this automatically and handles it transparently — no flags, no extra steps. When you run a batch conversion, each document is analyzed before conversion:

- **Document already has real headings** → converted directly with Pandoc
- **Document uses auto-numbered lists as sections** → pre-processed to promote those paragraphs to real headings, then converted with Pandoc

```bash
# This is all you need — normalization happens automatically when required
office2md --batch ./input -o ./output
```

### What it does internally

For documents that need normalization:

1. Detects the `numId` used as section headings by analyzing the DOCX numbering XML
2. Identifies the full family of structural numIds (main sections + sub-sections)
3. Promotes those paragraphs to real `Heading` styles with correct hierarchy (`##`, `###`)
4. Runs Pandoc on the pre-processed DOCX
5. Cleans up TOC links and image paths

For documents that already have proper heading styles (e.g. most technical specs), step 1–4 are skipped entirely — no modification to the original file.

### Output structure

```
output/
  ├── My-Document.md
  ├── My-Document_images/
  │   ├── image1.png
  │   └── image2.png
  └── Another-Document.md
```

Image references in the Markdown use relative paths:

```markdown
![Diagram](./My-Document_images/image1.png)
```

> **Note:** filenames are sanitized to be AzDO Wiki / filesystem-safe: spaces become hyphens, special characters are removed.

### Table of Contents

Every converted document gets a `[[_TOC_]]` tag at the very top, followed by a standard Markdown `## Índice` block with anchor links:

```markdown
[[_TOC_]]

## Índice

- [1. Objetivo](#1-objetivo)
- [2. Descrição da Solução](#2-descrição-da-solução)
...
```

- **`[[_TOC_]]`** is rendered natively by Azure DevOps Wiki, Confluence, and GitLab as an auto-generated index. In viewers that don't support it (GitHub, Obsidian, VSCode preview) it appears as harmless literal text and can be deleted.
- **`## Índice`** is a portable Markdown TOC that works everywhere. Anchor slugs follow the GitHub Slugger algorithm (Unicode-preserving, each space → `-`), ensuring compatibility with AzDO Wiki, VSCode, and GitHub.

### Pandoc Markdown Variant

When using Pandoc (the default converter), you can choose between two output flavors:

```bash
# GFM — GitHub Flavored Markdown (default)
office2md --batch ./input -o ./output

# Classic — standard Pandoc Markdown (pipe tables, ATX headings)
office2md --batch ./input -o ./output --pandoc-variant classic
```

| Variant | Flag | Images | Tables | Best for |
|---------|------|--------|--------|----------|
| **GFM** (default) | _(none)_ | `![](relative.png)` | GFM pipe tables | GitHub, AzDO Wiki, Obsidian |
| **Classic** | `--pandoc-variant classic` | `![](relative.png)` | Pandoc pipe tables | MkDocs, Sphinx, generic MD |

## Converter Selection

### DOCX Converters (Priority Order)

| Converter       | Quality   | Tables      | Requirements    |
| --------------- | --------- | ----------- | --------------- |
| **Pandoc**      | ⭐⭐⭐ Best | ✅ Excellent | External binary |
| **Mammoth**     | ⭐⭐ Good  | ⚠️ Partial  | Pure Python     |
| **python-docx** | ⭐ Basic  | ✅ Basic     | Pure Python     |

By default, office2md automatically selects the best available converter:

```
Pandoc (if installed) → Mammoth → python-docx
```

Force a specific converter:

```bash
office2md document.docx --use-pandoc    # best for complex tables
office2md document.docx --use-mammoth   # good pure-Python formatting
office2md document.docx --use-basic     # python-docx fallback
```

### PDF Converter

```bash
office2md document.pdf --use-docling    # ML-based, excellent for scanned docs
```

> **Note**: Docling is for PDF only. For DOCX, use the default converter or Pandoc.

## CLI Reference

```
office2md [OPTIONS] INPUT

Arguments:
  INPUT                     Input file or directory (with --batch or --mirror)

Options:
  -o, --output PATH         Output file or directory
  -v, --verbose             Enable verbose output

DOCX Converter Selection:
  --use-pandoc              Force Pandoc (best tables)
  --use-mammoth             Force Mammoth (good formatting)
  --use-basic               Force python-docx (fallback)
  --use-docling             Use Docling (PDF only, local ML-based extraction)
  --local-only              Privacy mode: no LLM/cloud APIs; set offline flags for ML dependencies

Image Options:
  --skip-images             Skip image extraction
  --images-dir PATH         Custom directory for images

Visual QA:
  --visual-qa               Render source/Markdown pages and write visual QA reports
  --visual-threshold FLOAT  Minimum visual score for the optional QA gate
  --quality-report PATH     Directory for JSON/HTML quality reports

Batch Processing:
  --batch                   Process directory of files
  -r, --recursive           Process subdirectories

Mirror Options:
  --mirror                  Mirror origin directory to destination (idempotent)
  --overwrite               Overwrite existing Markdown files
  --dry-run                 Plan but do not execute conversions
  --include EXT             Comma-separated extensions (default: docx,pdf)

Format-Specific Options:
  --first-sheet-only        XLSX: Convert only first sheet
  --no-notes                PPTX: Skip speaker notes
```

### Batch vs Mirror

Use `--batch` for quick one-off bulk conversion.
Use `--mirror` when you need repeatable, idempotent runs — for wikis, knowledge bases, or any pipeline you will run again.

| Feature | `--batch` | `--mirror` |
|---|---|---|
| Skips already-converted files | ❌ | ✅ |
| Dry-run preview | ❌ | ✅ |
| Extension filtering (`--include`) | ❌ | ✅ |
| Per-document asset isolation | ❌ | ✅ |
| Richer reporting | ❌ | ✅ |

```bash
# Quick bulk conversion
office2md --batch ./documents -o ./markdown --use-pandoc

# Repeatable mirror with dry-run first
office2md --mirror ./documents -o ./markdown --recursive --dry-run
office2md --mirror ./documents -o ./markdown --recursive --overwrite --include docx,pdf
```

### Wiki Builder CLI

`office2md-wiki` builds a wiki from a directory of converted Markdown files.

```
office2md-wiki SOURCE_DIR -o OUTPUT_DIR [OPTIONS]

Options:
  -o, --output PATH         Output wiki directory
  --title TEXT              Wiki title
  --mode MODE               semantic, simple, or published (default: semantic)
  --no-overwrite            Do not delete the output directory before building
```

Modes:

- `semantic` — best for AI-agent knowledge bases. Creates `SCHEMA.md`, `index.md`, `raw/`, `products/`, `concepts/` structure.
- `simple` — preserves the converted tree and adds navigation indexes (Obsidian-style).
- `published` — creates a MkDocs Material site structure with `mkdocs.yml`.

```bash
# Convert first, then build wiki
office2md --mirror ./source-documents -o ./converted-markdown --recursive
office2md-wiki ./converted-markdown -o ./knowledge-wiki --title "Architecture KB" --mode semantic
```

Full guide: [`docs/wiki-builder.md`](docs/wiki-builder.md).

## Privacy and Data Handling

`office2md` is a **local document conversion tool**. It does not send documents to OpenAI, Anthropic, Azure OpenAI, or any other cloud API during conversion.

- DOCX uses Pandoc, Mammoth, or `python-docx` — all local.
- XLSX uses `openpyxl` — local.
- PPTX uses `python-pptx` — local.
- PDF uses Docling — local ML/OCR pipeline.

For sensitive documents, use `--local-only`:

```bash
office2md confidential.pdf --use-docling --local-only
office2md --mirror ./documents -o ./markdown --recursive --local-only
```

`--local-only` sets `HF_HUB_OFFLINE=1`, `TRANSFORMERS_OFFLINE=1`, `HF_DATASETS_OFFLINE=1`, `HF_HUB_DISABLE_TELEMETRY=1`, and `DO_NOT_TRACK=1`. It is a best-effort application-level guard — not an OS firewall. For hard guarantees on regulated data, run in a network-blocked container or VM.

## Python API

```python
from office2md import ConverterFactory

# Auto-select converter
converter = ConverterFactory.create("document.docx")
markdown = converter.convert()
converter.save(markdown)

# With options
converter = ConverterFactory.create(
    "document.docx",
    output_path="output.md",
    extract_images=True,
    images_dir="./images"
)
markdown = converter.convert()
converter.save(markdown)
```

### Using Specific Converters

```python
from office2md.converters import DocxConverter, PandocConverter

converter = DocxConverter("document.docx", use_pandoc=True)

# Or use Pandoc directly
converter = PandocConverter("document.docx")
markdown = converter.convert()
```

### Mirror via Python API

```python
from office2md.automation import MirrorOptions, execute_mirror

report = execute_mirror(
    "./source-docs",
    "./markdown",
    options=MirrorOptions(overwrite=False),
)
print(report.converted_count, report.failed_count, report.skipped_count)
```

Mirrored assets are placed beside the generated Markdown:

```text
source-docs/runbooks/app/manual.docx
  ↓
markdown/runbooks/app/manual.md
markdown/runbooks/app/_assets/manual/image_1.png
```

## Quality Comparison

Compare converters on a specific document:

```bash
python scripts/quality_check.py document.docx
```

```
🏆 BEST CONVERTER: pandoc (score: 100/100)

Converter    Status   Time     Size       Images   Headings   Tables   Issues
pandoc       ✅        3.25s    62,678     30       1          0        0
default      ✅        4.19s    24,338     30       1          0        2
```

## Supported Formats

| Format     | Extension | Converter                  | Notes                          |
| ---------- | --------- | -------------------------- | ------------------------------ |
| Word       | `.docx`   | Pandoc/Mammoth/python-docx | Auto-fallback                  |
| Excel      | `.xlsx`   | openpyxl                   | All sheets or first only       |
| PowerPoint | `.pptx`   | python-pptx                | With/without notes             |
| PDF        | `.pdf`    | Docling                    | Requires `pip install docling` |

## Troubleshooting

### "Pandoc not available"

```bash
# macOS
brew install pandoc

# Ubuntu
sudo apt-get install pandoc
```

### Tables not rendering correctly

Force Pandoc — it handles complex tables best:

```bash
office2md document.docx --use-pandoc
```

### Section headings become bullet lists

Your DOCX uses auto-numbered lists instead of real heading styles. Use the [Normalized DOCX Pipeline](#normalized-docx-pipeline).

### Images not showing in Markdown

Check that the `_images` folder is beside the `.md` file and that the image paths in the Markdown use relative references (e.g. `./My-Document_images/image1.png`). The normalized pipeline handles this automatically.

### PDF conversion fails

```bash
pip install docling
```

## Development

```bash
git clone https://github.com/rodgui/office2md.git
cd office2md
pip install -e ".[dev]"
pytest
pytest --cov=office2md
```

## License

MIT License — see [LICENSE](LICENSE) for details.

## Contributing

1. Fork the repository
2. Create a feature branch: `git checkout -b feature/my-feature`
3. Commit your changes: `git commit -m 'Add my feature'`
4. Push and open a Pull Request
