markitdown-pro 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. markitdown_pro-0.1.0/PKG-INFO +367 -0
  2. markitdown_pro-0.1.0/README.md +325 -0
  3. markitdown_pro-0.1.0/markitdown_pro/__init__.py +1 -0
  4. markitdown_pro-0.1.0/markitdown_pro/common/__init__.py +0 -0
  5. markitdown_pro-0.1.0/markitdown_pro/common/logger.py +6 -0
  6. markitdown_pro-0.1.0/markitdown_pro/common/utils.py +59 -0
  7. markitdown_pro-0.1.0/markitdown_pro/conversion_pipeline.py +212 -0
  8. markitdown_pro-0.1.0/markitdown_pro/converters/__init__.py +0 -0
  9. markitdown_pro-0.1.0/markitdown_pro/converters/azure_docint.py +13 -0
  10. markitdown_pro-0.1.0/markitdown_pro/converters/base.py +26 -0
  11. markitdown_pro-0.1.0/markitdown_pro/converters/gpt4o_mini_vision.py +21 -0
  12. markitdown_pro-0.1.0/markitdown_pro/converters/markitdown_wrapper.py +44 -0
  13. markitdown_pro-0.1.0/markitdown_pro/converters/pymupdf_wrapper.py +42 -0
  14. markitdown_pro-0.1.0/markitdown_pro/converters/unstructured_wrapper.py +62 -0
  15. markitdown_pro-0.1.0/markitdown_pro/converters/youtube_wrapper.py +67 -0
  16. markitdown_pro-0.1.0/markitdown_pro/handlers/__init__.py +0 -0
  17. markitdown_pro-0.1.0/markitdown_pro/handlers/audio_handler.py +40 -0
  18. markitdown_pro-0.1.0/markitdown_pro/handlers/base_handler.py +16 -0
  19. markitdown_pro-0.1.0/markitdown_pro/handlers/email_handler.py +169 -0
  20. markitdown_pro-0.1.0/markitdown_pro/handlers/epub_handler.py +33 -0
  21. markitdown_pro-0.1.0/markitdown_pro/handlers/image_handler.py +48 -0
  22. markitdown_pro-0.1.0/markitdown_pro/handlers/ipynb_handler.py +31 -0
  23. markitdown_pro-0.1.0/markitdown_pro/handlers/markup_handler.py +75 -0
  24. markitdown_pro-0.1.0/markitdown_pro/handlers/office_handler.py +47 -0
  25. markitdown_pro-0.1.0/markitdown_pro/handlers/pdf_handler.py +122 -0
  26. markitdown_pro-0.1.0/markitdown_pro/handlers/pst_handler.py +153 -0
  27. markitdown_pro-0.1.0/markitdown_pro/handlers/tabular_handler.py +34 -0
  28. markitdown_pro-0.1.0/markitdown_pro/handlers/text_handler.py +38 -0
  29. markitdown_pro-0.1.0/markitdown_pro/services/__init__.py +0 -0
  30. markitdown_pro-0.1.0/markitdown_pro/services/azure_service.py +160 -0
  31. markitdown_pro-0.1.0/markitdown_pro/services/openai_services.py +209 -0
  32. markitdown_pro-0.1.0/markitdown_pro.egg-info/PKG-INFO +367 -0
  33. markitdown_pro-0.1.0/markitdown_pro.egg-info/SOURCES.txt +39 -0
  34. markitdown_pro-0.1.0/markitdown_pro.egg-info/dependency_links.txt +1 -0
  35. markitdown_pro-0.1.0/markitdown_pro.egg-info/requires.txt +24 -0
  36. markitdown_pro-0.1.0/markitdown_pro.egg-info/top_level.txt +1 -0
  37. markitdown_pro-0.1.0/pyproject.toml +41 -0
  38. markitdown_pro-0.1.0/setup.cfg +8 -0
  39. markitdown_pro-0.1.0/setup.py +45 -0
  40. markitdown_pro-0.1.0/tests/test.py +59 -0
@@ -0,0 +1,367 @@
1
+ Metadata-Version: 2.4
2
+ Name: markitdown-pro
3
+ Version: 0.1.0
4
+ Summary: A package that converts any file format to Markdown.
5
+ Author: Developer
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.12.2
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: pillow==11.1.0
12
+ Requires-Dist: requests
13
+ Requires-Dist: python-dotenv
14
+ Requires-Dist: azure-core
15
+ Requires-Dist: azure-ai-documentintelligence==1.0.0
16
+ Requires-Dist: azure-cognitiveservices-speech==1.42.0
17
+ Requires-Dist: azure-common==1.1.28
18
+ Requires-Dist: whisper
19
+ Requires-Dist: markitdown
20
+ Requires-Dist: langchain>=0.3.23
21
+ Requires-Dist: langchain-core>=0.3.51
22
+ Requires-Dist: langchain-openai>=0.3.12
23
+ Requires-Dist: langchain-text-splitters>=0.3.8
24
+ Requires-Dist: langdetect>=1.0.9
25
+ Requires-Dist: langsmith>=0.3.26
26
+ Requires-Dist: openai>=1.71.0
27
+ Requires-Dist: PyMuPDF
28
+ Requires-Dist: tabulate==0.9.0
29
+ Requires-Dist: chardet==5.2.0
30
+ Requires-Dist: unstructured[all-docs]
31
+ Requires-Dist: youtube-transcript-api
32
+ Requires-Dist: pyexiftool
33
+ Requires-Dist: pydub
34
+ Requires-Dist: nbformat
35
+ Dynamic: author
36
+ Dynamic: classifier
37
+ Dynamic: description
38
+ Dynamic: description-content-type
39
+ Dynamic: requires-dist
40
+ Dynamic: requires-python
41
+ Dynamic: summary
42
+
43
+ # MarkItDown-Pro
44
+
45
+ **MarkItDown-Pro** is an **improvement** of the **[Microsoft MarkItDown repository](https://github.com/markitdown)**, enhancing gaps and extending functionality by leveraging **Azure Document Intelligence SDK**, **Unstructured.io**, and other Azure services and libraries. The result is a comprehensive Python library and command-line tool designed to **convert diverse document formats into Markdown** with graceful fallbacks, including OCR support via GPT-4o-mini.
46
+
47
+ ---
48
+
49
+ ## Table of Contents
50
+
51
+ - [Folder Structure](#folder-structure)
52
+ - [Features & Highlights](#features--highlights)
53
+ - [How It Works](#how-it-works)
54
+ - [File-by-File Explanation](#file-by-file-explanation)
55
+ - [Main Files](#main-files)
56
+ - [Common Utils](#common-utils)
57
+ - [Converters](#converters)
58
+ - [Handlers](#handlers)
59
+ - [Testing](#testing)
60
+ - [Usage & Examples](#usage--examples)
61
+ - [CLI Usage](#cli-usage)
62
+ - [Programmatic Usage](#programmatic-usage)
63
+ - [Extra: Vector Database Chunking](#extra-vector-database-chunking)
64
+ - [Environment Variables](#environment-variables)
65
+ - [FAQ](#faq)
66
+
67
+ ---
68
+
69
+ ## Folder Structure
70
+
71
+ A typical layout for **MarkItDown-Pro** might look like this:
72
+ ```bash
73
+ markitdown-pro/
74
+ ├── .env
75
+ ├── README.md
76
+ ├── requirements.txt
77
+ ├── main.py
78
+ ├── conversion_pipeline.py
79
+ ├── common
80
+ │ └── utils.py
81
+ ├── converters
82
+ │ ├── markitdown_wrapper.py
83
+ │ ├── azure_docint.py
84
+ │ ├── unstructured_wrapper.py
85
+ │ └── gpt4o_mini_vision.py
86
+ ├── handlers
87
+ │ ├── pst_handler.py
88
+ │ ├── email_handler.py
89
+ │ ├── zip_handler.py
90
+ │ ├── audio_handler.py
91
+ │ └── pdf_handler.py
92
+ └── tests
93
+ ├── data
94
+ └── test.py
95
+ ```
96
+
97
+ | Folder/File | Description |
98
+ |----------------------------|---------------------------------------------------------------------------------------|
99
+ | **main.py** | Entry point for CLI usage; uses `argparse` to accept file paths. |
100
+ | **conversion_pipeline.py** | Orchestrates the fallback chain for converting documents to Markdown. |
101
+ | **common/** | Shared utility functions, e.g. for file detection, text cleanup, etc. |
102
+ | **converters/** | Contains modules for using various 3rd-party libraries or services to extract text. |
103
+ | **handlers/** | Specialized handlers for specific file types (PST, EML, ZIP, audio, PDF scanning). |
104
+ | **.env** | Environment variables (e.g., credentials for Azure GPT-4o-mini, Azure Doc Intelligence). |
105
+ | **requirements.txt** | Python dependencies needed to install and run this project. |
106
+ | **tests/test_markitdownpro.py**| Recursively scans /tests/data/ and attempts to convert each file using convert_document_to_md|
107
+ | **README.md** | This documentation file, explaining usage and details of the project. |
108
+
109
+ ---
110
+
111
+ ## Features & Highlights
112
+
113
+ 1. **MarkItDown with LLM**
114
+ - Uses **MarkItDown** to convert documents to Markdown, optionally leveraging an OpenAI LLM to create image captions if you have an **OPENAI_API_KEY**.
115
+ - Auto-checks for `exiftool` if you want EXIF metadata in your images.
116
+
117
+ 2. **Whisper-Based Audio Transcription**
118
+ - Converts audio files (`.mp3`, `.wav`, `.ogg`, etc.) into text using [OpenAI Whisper](https://github.com/openai/whisper).
119
+ - Gracefully falls back if Whisper is not installed.
120
+
121
+ 3. **PST Extraction**
122
+ - Parses Outlook PST files with [`libratom`](https://github.com/rafproject/libratom), extracting emails and attachments recursively.
123
+
124
+ 4. **Scanned PDF Detection & Concurrency**
125
+ - Identifies PDFs with no text or embedded images, and automatically performs OCR on each page with GPT-4o-mini.
126
+ - Offers concurrent page-by-page OCR for faster performance.
127
+
128
+ 5. **Fallback to Azure Document Intelligence & Unstructured**
129
+ - If standard MarkItDown or specialized handlers fail or yield insufficient text, it tries Azure’s Document Intelligence to extract textual layout.
130
+ - Unstructured.io library for broad coverage of file types.
131
+
132
+ 6. **GPT-4 Vision (or GPT-4o-mini) for Images & OCR**
133
+ - If an image or partially scanned PDF is detected, we can pass it to GPT-4o-mini for OCR.
134
+ - Supports local images (base64 encoding) or remote image URLs directly.
135
+
136
+ 7. **Handles ZIP & EML**
137
+ - **ZIP**: Unzips and processes each file inside, concatenating the results.
138
+ - **EML**: Extracts email text, attachments, and processes attachments recursively.
139
+
140
+ 8. **Graceful LLM Handling**
141
+ - If no **OPENAI_API_KEY** or GPT-4o-mini credentials are provided, it simply skips LLM-based features, logging a warning.
142
+
143
+ 9. **Helper Methods for URL & Stream Conversion**
144
+ - `convert_document_from_url(url, output_md)`
145
+ - `convert_document_from_stream(stream, extension, output_md)`
146
+ - `convert_document_to_md(local_path, output_md)`
147
+
148
+ 10. **Easy-to-Extend Architecture**
149
+ Each file type has its own **handler**. Each text-extraction library has its own **converter**. The main pipeline provides a centralized fallback sequence.
150
+
151
+ 11. **Environment-Driven Configuration**
152
+ - Pulls API keys, endpoints, and paths from `.env` to keep secrets out of source code.
153
+
154
+ 12. **Rich File Type Handling**
155
+
156
+ | Category | File Type(s) |
157
+ |-----------------------|-------------|
158
+ | PDF | .pdf |
159
+ | PowerPoint | .pot, .potm, .ppt, .pptm, .pptx |
160
+ | Word Processing | .abw, .doc, .docm, .docx, .dot, .dotm, .hwp, .zabw |
161
+ | Excel/Spreadsheet | .et, .fods, .uos1, .uos2, .wk2, .xls, .xlsb, .xlsm, .xlsx, .xlw |
162
+ | Images | .bmp, .gif, .heic, .jpeg, .jpg, .png, .prn, .svg, .tiff, .webp |
163
+ | Audio | .mp3, .wav, .ogg, .flac, .m4a, .aac, .wma, .webm, .opus |
164
+ | HTML | .htm, .html |
165
+ | Text-Based Formats | .csv, .json, .xml, .txt |
166
+ | ZIP Files | (Iterates over contents) |
167
+ | Email | .eml, .p7s |
168
+ | PST | .pst |
169
+ | EPUB | .epub |
170
+ | Markdown | .md |
171
+ | Org Mode | .org |
172
+ | Open Office | .odt, .sgl |
173
+ | Other | .eth, .mw, .pbd, .sdp, .uof, .web |
174
+ | Plain Text | .txt |
175
+ | reStructured Text | .rst |
176
+ | Rich Text | .rtf |
177
+ | StarOffice | .sxg |
178
+ | TSV | .tsv |
179
+ | Apple | .cwk, .mcw, .pages |
180
+ | Data Interchange | .dif |
181
+ | dBase | .dbf |
182
+ | Microsoft Office | .docx, .xlsx, .pptx |
183
+ | HEIF Image Format | .heif |
184
+
185
+
186
+ ---
187
+
188
+ ## How It Works
189
+
190
+ 1. **Detect File Type**: The pipeline checks the file extension or general signature (`.pdf`, `.zip`, `.eml`, `.docx`, `.mp3`, etc.).
191
+ 2. **Specialized Handlers**: If the file is PST, EML, ZIP, or audio, it’s handed off to a dedicated module that handles that format.
192
+ 3. **MarkItDown**: For most generic document conversions, we first try [MarkItDown](https://github.com/markitdown).
193
+ 4. **Unstructured**: If MarkItDown fails or yields minimal text, we turn to [Unstructured.io](https://unstructured.io/) next.
194
+ - **Why?** It's typically **cheaper** than Azure Document Intelligence, and can handle partial OCR scenarios (via Tesseract, PaddleOCR, etc., if you configure `OCR_AGENT`).
195
+ 5. **Azure Document Intelligence**: If Unstructured also fails or yields minimal text, we try Azure Document Intelligence (prebuilt-layout).
196
+ 6. **GPT-4o-mini**: As a final fallback or specifically for OCR on images/scanned pages.
197
+ 7. **Saves** the extracted text to a `.md` file once any method returns sufficient content.
198
+
199
+ ---
200
+
201
+ ## File-by-File Explanation
202
+
203
+ ### Main Files
204
+
205
+ - **`conversion_pipeline.py`**
206
+ The core logic that orchestrates the fallback chain. Checks each handler or converter in a specific order. Once a successful conversion with enough text is found, it writes to `.md` and stops.
207
+
208
+ ### Common Utils
209
+
210
+ - **`common/utils.py`**
211
+ - **File Detection**: Contains helper functions like `is_pdf`, `is_audio`, `detect_extension`.
212
+ - **Markdown Cleaning**: Functions like `clean_markdown()` and `ensure_minimum_content()` to tidy up text and ensure it’s not empty.
213
+
214
+ ### Converters
215
+
216
+ - **`converters/markitdown_wrapper.py`**
217
+ - Wraps the [MarkItDown](https://github.com/markitdown) library for docx/image extraction, EXIF reading, and optional LLM-based image captioning.
218
+ - If MarkItDown is not installed, or fails, returns `None`.
219
+
220
+ - **`converters/azure_docint.py`**
221
+ - Leverages Azure’s Document Intelligence (prebuilt-layout) to extract text from PDFs and other document types in Markdown format.
222
+
223
+ - **`converters/unstructured_wrapper.py`**
224
+ - Uses the [Unstructured.io](https://www.unstructured.io/) library to parse documents. Useful for handling broad, less-common file types.
225
+
226
+ - **`converters/gpt4o_mini_vision.py`**
227
+ - Uses GPT-4o-mini (Azure ChatOpenAI) for OCR tasks on **images** or **scanned PDFs**.
228
+ - **Concurrent** or **simple** page-by-page approaches for PDFs.
229
+ - Can pass **URL-based images** or **local images** via Base64 encoding.
230
+
231
+ ### Handlers
232
+
233
+ - **`handlers/pst_handler.py`**
234
+ - Parses PST archives with [`libratom`](https://github.com/rafproject/libratom) and extracts emails + attachments. Calls back into the pipeline for each attachment.
235
+
236
+ - **`handlers/email_handler.py`**
237
+ - Processes `.eml` files, extracting plain text, attachments, etc. Recursively processes attachments.
238
+
239
+ - **`handlers/zip_handler.py`**
240
+ - Unzips files, recurses into the pipeline for each contained file, and concatenates all Markdown output.
241
+
242
+ - **`handlers/audio_handler.py`**
243
+ - Uses [OpenAI Whisper](https://github.com/openai/whisper) to transcribe `.mp3`, `.wav`, `.ogg`, etc.
244
+ - Caches the model in memory to speed up repeated use.
245
+
246
+ - **`handlers/pdf_handler.py`**
247
+ - Utility to detect if a PDF is text-only, text+images, or fully scanned.
248
+ - Coordinates with GPT-4o-mini for OCR if needed.
249
+
250
+ ---
251
+
252
+ ## Installation
253
+
254
+ 1. **Clone the Repo**
255
+ ```bash
256
+ git clone https://github.com/YourName/markitdown-pro.git
257
+ cd markitdown-pro
258
+ ```
259
+ 2. **Create a Virtual Environment (recommended)**
260
+ ```bash
261
+ python -m venv venv
262
+ source venv/bin/activate # or venv\Scripts\activate on Windows
263
+ ```
264
+ 3. **Create a Virtual Environment (recommended)**
265
+ ```bash
266
+ python -m venv venv
267
+ source venv/bin/activate # or venv\Scripts\activate on Windows
268
+ ```
269
+ 4. **Install Dependencies**
270
+ ```bash
271
+ pip install --upgrade pip
272
+ pip install -r requirements.txt
273
+ ```
274
+ Note: You may also need system dependencies for libraries like PyMuPDF, libratom, etc.
275
+
276
+ 5. **Set Up .env**
277
+
278
+ - Copy the sample .env to your root folder, and fill in your Azure or OpenAI API keys, etc. For example:
279
+ ```bash
280
+ AZURE_DOCINTEL_ENDPOINT="https://<your-region>.api.cognitive.microsoft.com"
281
+ AZURE_DOCINTEL_KEY="YOUR_AZURE_KEY"
282
+ GPT4oMINI_DEPLOYMENT_NAME="your-azure-gpt4o-mini-deployment"
283
+ OPENAI_API_KEY="sk-...." # needed if you want LLM-based image captioning in MarkItDown
284
+ EXIFTOOL_PATH="/usr/local/bin/exiftool" # optional if exiftool is not in PATH
285
+ OCR_AGENT="unstructured.partition.utils.ocr_models.tesseract_ocr.OCRAgentTesseract" # or another supported agent for built-in OCR in Unstructured. S
286
+ ```
287
+ Make sure to source it or ensure python-dotenv can read it.
288
+ ---
289
+
290
+ ## Testing
291
+
292
+ We use **pytest** for running our test suite. The test files and scripts are located in the `/tests` directory:
293
+ ```bash
294
+ pytest tests/test_markitdownpro.py
295
+ ```
296
+
297
+ ---
298
+
299
+ ## Usage
300
+ ### CLI Usage
301
+ 1. **Basic:**
302
+ ```bash
303
+ python main.py /path/to/document.pdf
304
+ ```
305
+ This will produce /path/to/document.md if successful.
306
+
307
+ 2. **Specify Output Path:**
308
+ ```bash
309
+ python main.py /path/to/document.pst --output my_pst_output.md
310
+ ```
311
+ ### Programmatic Usage
312
+ You can import and call the pipeline directly from your Python code:
313
+ ```python
314
+ from conversion_pipeline import convert_document_to_md, convert_document_from_url
315
+
316
+ # 1) Local file example
317
+ md_text = convert_document_to_md("/path/to/my_file.pdf")
318
+ print("Extracted Markdown:", md_text)
319
+
320
+ # 2) URL example
321
+ md_from_url = convert_document_from_url("https://example.com/my_doc.docx", output_md="output_doc.md")
322
+ print("Output saved to output_doc.md")
323
+ ```
324
+ ---
325
+
326
+ ## Extra: Vector Database Chunking
327
+ After converting a document to Markdown, it’s common to chunk the text before sending it to a vector database. Here’s a minimal example using LangChain:
328
+
329
+ ```python
330
+ from langchain.text_splitter import MarkdownTextSplitter
331
+
332
+ # Load your Markdown content
333
+ with open('your_markdown_file.md', 'r') as file:
334
+ markdown_text = file.read()
335
+
336
+ # Initialize the MarkdownTextSplitter
337
+ markdown_splitter = MarkdownTextSplitter(chunk_size=1000, chunk_overlap=100)
338
+
339
+ # Split the text into chunks
340
+ chunks = markdown_splitter.create_documents([markdown_text])
341
+
342
+ # Each chunk is now ready for embedding and ingestion into your vector database
343
+ for chunk in chunks:
344
+ # e.g., push chunk.text to your VectorDB
345
+ pass
346
+ ```
347
+
348
+ ---
349
+ ## FAQ
350
+ 1. **What if MarkItDown or Whisper is not installed?**
351
+ The pipeline checks for each library’s availability. If a library is missing or fails, it gracefully moves on to the next fallback.
352
+
353
+ 2. **Do I need Azure/OpenAI credentials?**
354
+
355
+ Azure: If you want to use Document Intelligence or GPT-4o-mini, yes.
356
+ OpenAI: If you want MarkItDown’s LLM-based image captioning or are using Whisper from openai’s library, you need appropriate credentials or local models.
357
+ How do I handle large PST files?
358
+ Large PSTs can be slow to process, especially if they contain many attachments. We parse them message-by-message, recursively handling attachments. For extremely large archives, you might want to increase concurrency or filter out attachments you don’t need.
359
+
360
+ 3. **Does GPT-4o-mini require a publicly accessible image URL?**
361
+
362
+ If you provide a local file path, the code base64-encodes it. This is ideal for truly local images.
363
+ If you have a publicly hosted image, you can pass its URL directly.
364
+
365
+ 4. **Why is Unstructured tried before Azure Doc Intelligence now?**
366
+ We observed that **Unstructured** is typically **lower cost** to run (especially with Tesseract or local OCR) compared to Azure’s \$10 per 1,000 pages. So if MarkItDown fails, we want to try Unstructured next to potentially save cost. If that also fails, we move to Azure.
367
+
@@ -0,0 +1,325 @@
1
+ # MarkItDown-Pro
2
+
3
+ **MarkItDown-Pro** is an **improvement** of the **[Microsoft MarkItDown repository](https://github.com/markitdown)**, enhancing gaps and extending functionality by leveraging **Azure Document Intelligence SDK**, **Unstructured.io**, and other Azure services and libraries. The result is a comprehensive Python library and command-line tool designed to **convert diverse document formats into Markdown** with graceful fallbacks, including OCR support via GPT-4o-mini.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ - [Folder Structure](#folder-structure)
10
+ - [Features & Highlights](#features--highlights)
11
+ - [How It Works](#how-it-works)
12
+ - [File-by-File Explanation](#file-by-file-explanation)
13
+ - [Main Files](#main-files)
14
+ - [Common Utils](#common-utils)
15
+ - [Converters](#converters)
16
+ - [Handlers](#handlers)
17
+ - [Testing](#testing)
18
+ - [Usage & Examples](#usage--examples)
19
+ - [CLI Usage](#cli-usage)
20
+ - [Programmatic Usage](#programmatic-usage)
21
+ - [Extra: Vector Database Chunking](#extra-vector-database-chunking)
22
+ - [Environment Variables](#environment-variables)
23
+ - [FAQ](#faq)
24
+
25
+ ---
26
+
27
+ ## Folder Structure
28
+
29
+ A typical layout for **MarkItDown-Pro** might look like this:
30
+ ```bash
31
+ markitdown-pro/
32
+ ├── .env
33
+ ├── README.md
34
+ ├── requirements.txt
35
+ ├── main.py
36
+ ├── conversion_pipeline.py
37
+ ├── common
38
+ │ └── utils.py
39
+ ├── converters
40
+ │ ├── markitdown_wrapper.py
41
+ │ ├── azure_docint.py
42
+ │ ├── unstructured_wrapper.py
43
+ │ └── gpt4o_mini_vision.py
44
+ ├── handlers
45
+ │ ├── pst_handler.py
46
+ │ ├── email_handler.py
47
+ │ ├── zip_handler.py
48
+ │ ├── audio_handler.py
49
+ │ └── pdf_handler.py
50
+ └── tests
51
+ ├── data
52
+ └── test.py
53
+ ```
54
+
55
+ | Folder/File | Description |
56
+ |----------------------------|---------------------------------------------------------------------------------------|
57
+ | **main.py** | Entry point for CLI usage; uses `argparse` to accept file paths. |
58
+ | **conversion_pipeline.py** | Orchestrates the fallback chain for converting documents to Markdown. |
59
+ | **common/** | Shared utility functions, e.g. for file detection, text cleanup, etc. |
60
+ | **converters/** | Contains modules for using various 3rd-party libraries or services to extract text. |
61
+ | **handlers/** | Specialized handlers for specific file types (PST, EML, ZIP, audio, PDF scanning). |
62
+ | **.env** | Environment variables (e.g., credentials for Azure GPT-4o-mini, Azure Doc Intelligence). |
63
+ | **requirements.txt** | Python dependencies needed to install and run this project. |
64
+ | **tests/test_markitdownpro.py**| Recursively scans /tests/data/ and attempts to convert each file using convert_document_to_md|
65
+ | **README.md** | This documentation file, explaining usage and details of the project. |
66
+
67
+ ---
68
+
69
+ ## Features & Highlights
70
+
71
+ 1. **MarkItDown with LLM**
72
+ - Uses **MarkItDown** to convert documents to Markdown, optionally leveraging an OpenAI LLM to create image captions if you have an **OPENAI_API_KEY**.
73
+ - Auto-checks for `exiftool` if you want EXIF metadata in your images.
74
+
75
+ 2. **Whisper-Based Audio Transcription**
76
+ - Converts audio files (`.mp3`, `.wav`, `.ogg`, etc.) into text using [OpenAI Whisper](https://github.com/openai/whisper).
77
+ - Gracefully falls back if Whisper is not installed.
78
+
79
+ 3. **PST Extraction**
80
+ - Parses Outlook PST files with [`libratom`](https://github.com/rafproject/libratom), extracting emails and attachments recursively.
81
+
82
+ 4. **Scanned PDF Detection & Concurrency**
83
+ - Identifies PDFs with no text or embedded images, and automatically performs OCR on each page with GPT-4o-mini.
84
+ - Offers concurrent page-by-page OCR for faster performance.
85
+
86
+ 5. **Fallback to Azure Document Intelligence & Unstructured**
87
+ - If standard MarkItDown or specialized handlers fail or yield insufficient text, it tries Azure’s Document Intelligence to extract textual layout.
88
+ - Unstructured.io library for broad coverage of file types.
89
+
90
+ 6. **GPT-4 Vision (or GPT-4o-mini) for Images & OCR**
91
+ - If an image or partially scanned PDF is detected, we can pass it to GPT-4o-mini for OCR.
92
+ - Supports local images (base64 encoding) or remote image URLs directly.
93
+
94
+ 7. **Handles ZIP & EML**
95
+ - **ZIP**: Unzips and processes each file inside, concatenating the results.
96
+ - **EML**: Extracts email text, attachments, and processes attachments recursively.
97
+
98
+ 8. **Graceful LLM Handling**
99
+ - If no **OPENAI_API_KEY** or GPT-4o-mini credentials are provided, it simply skips LLM-based features, logging a warning.
100
+
101
+ 9. **Helper Methods for URL & Stream Conversion**
102
+ - `convert_document_from_url(url, output_md)`
103
+ - `convert_document_from_stream(stream, extension, output_md)`
104
+ - `convert_document_to_md(local_path, output_md)`
105
+
106
+ 10. **Easy-to-Extend Architecture**
107
+ Each file type has its own **handler**. Each text-extraction library has its own **converter**. The main pipeline provides a centralized fallback sequence.
108
+
109
+ 11. **Environment-Driven Configuration**
110
+ - Pulls API keys, endpoints, and paths from `.env` to keep secrets out of source code.
111
+
112
+ 12. **Rich File Type Handling**
113
+
114
+ | Category | File Type(s) |
115
+ |-----------------------|-------------|
116
+ | PDF | .pdf |
117
+ | PowerPoint | .pot, .potm, .ppt, .pptm, .pptx |
118
+ | Word Processing | .abw, .doc, .docm, .docx, .dot, .dotm, .hwp, .zabw |
119
+ | Excel/Spreadsheet | .et, .fods, .uos1, .uos2, .wk2, .xls, .xlsb, .xlsm, .xlsx, .xlw |
120
+ | Images | .bmp, .gif, .heic, .jpeg, .jpg, .png, .prn, .svg, .tiff, .webp |
121
+ | Audio | .mp3, .wav, .ogg, .flac, .m4a, .aac, .wma, .webm, .opus |
122
+ | HTML | .htm, .html |
123
+ | Text-Based Formats | .csv, .json, .xml, .txt |
124
+ | ZIP Files | (Iterates over contents) |
125
+ | Email | .eml, .p7s |
126
+ | PST | .pst |
127
+ | EPUB | .epub |
128
+ | Markdown | .md |
129
+ | Org Mode | .org |
130
+ | Open Office | .odt, .sgl |
131
+ | Other | .eth, .mw, .pbd, .sdp, .uof, .web |
132
+ | Plain Text | .txt |
133
+ | reStructured Text | .rst |
134
+ | Rich Text | .rtf |
135
+ | StarOffice | .sxg |
136
+ | TSV | .tsv |
137
+ | Apple | .cwk, .mcw, .pages |
138
+ | Data Interchange | .dif |
139
+ | dBase | .dbf |
140
+ | Microsoft Office | .docx, .xlsx, .pptx |
141
+ | HEIF Image Format | .heif |
142
+
143
+
144
+ ---
145
+
146
+ ## How It Works
147
+
148
+ 1. **Detect File Type**: The pipeline checks the file extension or general signature (`.pdf`, `.zip`, `.eml`, `.docx`, `.mp3`, etc.).
149
+ 2. **Specialized Handlers**: If the file is PST, EML, ZIP, or audio, it’s handed off to a dedicated module that handles that format.
150
+ 3. **MarkItDown**: For most generic document conversions, we first try [MarkItDown](https://github.com/markitdown).
151
+ 4. **Unstructured**: If MarkItDown fails or yields minimal text, we turn to [Unstructured.io](https://unstructured.io/) next.
152
+ - **Why?** It's typically **cheaper** than Azure Document Intelligence, and can handle partial OCR scenarios (via Tesseract, PaddleOCR, etc., if you configure `OCR_AGENT`).
153
+ 5. **Azure Document Intelligence**: If Unstructured also fails or yields minimal text, we try Azure Document Intelligence (prebuilt-layout).
154
+ 6. **GPT-4o-mini**: As a final fallback or specifically for OCR on images/scanned pages.
155
+ 7. **Saves** the extracted text to a `.md` file once any method returns sufficient content.
156
+
157
+ ---
158
+
159
+ ## File-by-File Explanation
160
+
161
+ ### Main Files
162
+
163
+ - **`conversion_pipeline.py`**
164
+ The core logic that orchestrates the fallback chain. Checks each handler or converter in a specific order. Once a successful conversion with enough text is found, it writes to `.md` and stops.
165
+
166
+ ### Common Utils
167
+
168
+ - **`common/utils.py`**
169
+ - **File Detection**: Contains helper functions like `is_pdf`, `is_audio`, `detect_extension`.
170
+ - **Markdown Cleaning**: Functions like `clean_markdown()` and `ensure_minimum_content()` to tidy up text and ensure it’s not empty.
171
+
172
+ ### Converters
173
+
174
+ - **`converters/markitdown_wrapper.py`**
175
+ - Wraps the [MarkItDown](https://github.com/markitdown) library for docx/image extraction, EXIF reading, and optional LLM-based image captioning.
176
+ - If MarkItDown is not installed, or fails, returns `None`.
177
+
178
+ - **`converters/azure_docint.py`**
179
+ - Leverages Azure’s Document Intelligence (prebuilt-layout) to extract text from PDFs and other document types in Markdown format.
180
+
181
+ - **`converters/unstructured_wrapper.py`**
182
+ - Uses the [Unstructured.io](https://www.unstructured.io/) library to parse documents. Useful for handling broad, less-common file types.
183
+
184
+ - **`converters/gpt4o_mini_vision.py`**
185
+ - Uses GPT-4o-mini (Azure ChatOpenAI) for OCR tasks on **images** or **scanned PDFs**.
186
+ - **Concurrent** or **simple** page-by-page approaches for PDFs.
187
+ - Can pass **URL-based images** or **local images** via Base64 encoding.
188
+
189
+ ### Handlers
190
+
191
+ - **`handlers/pst_handler.py`**
192
+ - Parses PST archives with [`libratom`](https://github.com/rafproject/libratom) and extracts emails + attachments. Calls back into the pipeline for each attachment.
193
+
194
+ - **`handlers/email_handler.py`**
195
+ - Processes `.eml` files, extracting plain text, attachments, etc. Recursively processes attachments.
196
+
197
+ - **`handlers/zip_handler.py`**
198
+ - Unzips files, recurses into the pipeline for each contained file, and concatenates all Markdown output.
199
+
200
+ - **`handlers/audio_handler.py`**
201
+ - Uses [OpenAI Whisper](https://github.com/openai/whisper) to transcribe `.mp3`, `.wav`, `.ogg`, etc.
202
+ - Caches the model in memory to speed up repeated use.
203
+
204
+ - **`handlers/pdf_handler.py`**
205
+ - Utility to detect if a PDF is text-only, text+images, or fully scanned.
206
+ - Coordinates with GPT-4o-mini for OCR if needed.
207
+
208
+ ---
209
+
210
+ ## Installation
211
+
212
+ 1. **Clone the Repo**
213
+ ```bash
214
+ git clone https://github.com/YourName/markitdown-pro.git
215
+ cd markitdown-pro
216
+ ```
217
+ 2. **Create a Virtual Environment (recommended)**
218
+ ```bash
219
+ python -m venv venv
220
+ source venv/bin/activate # or venv\Scripts\activate on Windows
221
+ ```
222
+ 3. **Create a Virtual Environment (recommended)**
223
+ ```bash
224
+ python -m venv venv
225
+ source venv/bin/activate # or venv\Scripts\activate on Windows
226
+ ```
227
+ 4. **Install Dependencies**
228
+ ```bash
229
+ pip install --upgrade pip
230
+ pip install -r requirements.txt
231
+ ```
232
+ Note: You may also need system dependencies for libraries like PyMuPDF, libratom, etc.
233
+
234
+ 5. **Set Up .env**
235
+
236
+ - Copy the sample .env to your root folder, and fill in your Azure or OpenAI API keys, etc. For example:
237
+ ```bash
238
+ AZURE_DOCINTEL_ENDPOINT="https://<your-region>.api.cognitive.microsoft.com"
239
+ AZURE_DOCINTEL_KEY="YOUR_AZURE_KEY"
240
+ GPT4oMINI_DEPLOYMENT_NAME="your-azure-gpt4o-mini-deployment"
241
+ OPENAI_API_KEY="sk-...." # needed if you want LLM-based image captioning in MarkItDown
242
+ EXIFTOOL_PATH="/usr/local/bin/exiftool" # optional if exiftool is not in PATH
243
+ OCR_AGENT="unstructured.partition.utils.ocr_models.tesseract_ocr.OCRAgentTesseract" # or another supported agent for built-in OCR in Unstructured. S
244
+ ```
245
+ Make sure to source it or ensure python-dotenv can read it.
246
+ ---
247
+
248
+ ## Testing
249
+
250
+ We use **pytest** for running our test suite. The test files and scripts are located in the `/tests` directory:
251
+ ```bash
252
+ pytest tests/test_markitdownpro.py
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Usage
258
+ ### CLI Usage
259
+ 1. **Basic:**
260
+ ```bash
261
+ python main.py /path/to/document.pdf
262
+ ```
263
+ This will produce /path/to/document.md if successful.
264
+
265
+ 2. **Specify Output Path:**
266
+ ```bash
267
+ python main.py /path/to/document.pst --output my_pst_output.md
268
+ ```
269
+ ### Programmatic Usage
270
+ You can import and call the pipeline directly from your Python code:
271
+ ```python
272
+ from conversion_pipeline import convert_document_to_md, convert_document_from_url
273
+
274
+ # 1) Local file example
275
+ md_text = convert_document_to_md("/path/to/my_file.pdf")
276
+ print("Extracted Markdown:", md_text)
277
+
278
+ # 2) URL example
279
+ md_from_url = convert_document_from_url("https://example.com/my_doc.docx", output_md="output_doc.md")
280
+ print("Output saved to output_doc.md")
281
+ ```
282
+ ---
283
+
284
+ ## Extra: Vector Database Chunking
285
+ After converting a document to Markdown, it’s common to chunk the text before sending it to a vector database. Here’s a minimal example using LangChain:
286
+
287
+ ```python
288
+ from langchain.text_splitter import MarkdownTextSplitter
289
+
290
+ # Load your Markdown content
291
+ with open('your_markdown_file.md', 'r') as file:
292
+ markdown_text = file.read()
293
+
294
+ # Initialize the MarkdownTextSplitter
295
+ markdown_splitter = MarkdownTextSplitter(chunk_size=1000, chunk_overlap=100)
296
+
297
+ # Split the text into chunks
298
+ chunks = markdown_splitter.create_documents([markdown_text])
299
+
300
+ # Each chunk is now ready for embedding and ingestion into your vector database
301
+ for chunk in chunks:
302
+ # e.g., push chunk.text to your VectorDB
303
+ pass
304
+ ```
305
+
306
+ ---
307
+ ## FAQ
308
+ 1. **What if MarkItDown or Whisper is not installed?**
309
+ The pipeline checks for each library’s availability. If a library is missing or fails, it gracefully moves on to the next fallback.
310
+
311
+ 2. **Do I need Azure/OpenAI credentials?**
312
+
313
+ Azure: If you want to use Document Intelligence or GPT-4o-mini, yes.
314
+ OpenAI: If you want MarkItDown’s LLM-based image captioning or are using Whisper from openai’s library, you need appropriate credentials or local models.
315
+ How do I handle large PST files?
316
+ Large PSTs can be slow to process, especially if they contain many attachments. We parse them message-by-message, recursively handling attachments. For extremely large archives, you might want to increase concurrency or filter out attachments you don’t need.
317
+
318
+ 3. **Does GPT-4o-mini require a publicly accessible image URL?**
319
+
320
+ If you provide a local file path, the code base64-encodes it. This is ideal for truly local images.
321
+ If you have a publicly hosted image, you can pass its URL directly.
322
+
323
+ 4. **Why is Unstructured tried before Azure Doc Intelligence now?**
324
+ We observed that **Unstructured** is typically **lower cost** to run (especially with Tesseract or local OCR) compared to Azure’s \$10 per 1,000 pages. So if MarkItDown fails, we want to try Unstructured next to potentially save cost. If that also fails, we move to Azure.
325
+
@@ -0,0 +1 @@
1
+ from . import common, converters, handlers, services # noqa F401