From 7bea2672a05f5877acb8690b20222593dab13788 Mon Sep 17 00:00:00 2001 From: ZeyuTeng96 <96521059+ZeyuTeng96@users.noreply.github.com> Date: Sun, 9 Feb 2025 12:28:35 +0800 Subject: [PATCH 01/33] remove leading and trailing \n for HtmlConverter (#262) --- src/markitdown/_markitdown.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/markitdown/_markitdown.py b/src/markitdown/_markitdown.py index ae6a7b4..6f40547 100644 --- a/src/markitdown/_markitdown.py +++ b/src/markitdown/_markitdown.py @@ -236,6 +236,9 @@ class HtmlConverter(DocumentConverter): assert isinstance(webpage_text, str) + # remove leading and trailing \n + webpage_text = webpage_text.strip() + return DocumentConverterResult( title=None if soup.title is None else soup.title.string, text_content=webpage_text, From 3090917a49dc8ec94682c47747f3e2692e3953ae Mon Sep 17 00:00:00 2001 From: James Hickey Date: Sun, 9 Feb 2025 00:30:13 -0400 Subject: [PATCH 02/33] Typo fixed (#270) --- src/markitdown/_markitdown.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/markitdown/_markitdown.py b/src/markitdown/_markitdown.py index 6f40547..e4884ec 100644 --- a/src/markitdown/_markitdown.py +++ b/src/markitdown/_markitdown.py @@ -217,7 +217,7 @@ class HtmlConverter(DocumentConverter): return result def _convert(self, html_content: str) -> Union[None, DocumentConverterResult]: - """Helper function that converts and HTML string.""" + """Helper function that converts an HTML string.""" # Parse the string soup = BeautifulSoup(html_content, "html.parser") From 7cf5e0bb23980cd004ceeea476c1bde3246d3c84 Mon Sep 17 00:00:00 2001 From: masquare Date: Sun, 9 Feb 2025 05:37:34 +0100 Subject: [PATCH 03/33] feat(pptx): support image description with LLM for pptx files (#306) --- src/markitdown/_markitdown.py | 62 +++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/src/markitdown/_markitdown.py b/src/markitdown/_markitdown.py index e4884ec..9f610f6 100644 --- a/src/markitdown/_markitdown.py +++ b/src/markitdown/_markitdown.py @@ -787,6 +787,35 @@ class PptxConverter(HtmlConverter): Converts PPTX files to Markdown. Supports heading, tables and images with alt text. """ + def _get_llm_description( + self, llm_client, llm_model, image_blob, content_type, prompt=None + ): + if prompt is None or prompt.strip() == "": + prompt = "Write a detailed alt text for this image with less than 50 words." + + image_base64 = base64.b64encode(image_blob).decode("utf-8") + data_uri = f"data:{content_type};base64,{image_base64}" + + messages = [ + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": data_uri, + }, + }, + {"type": "text", "text": prompt}, + ], + } + ] + + response = llm_client.chat.completions.create( + model=llm_model, messages=messages + ) + return response.choices[0].message.content + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: # Bail if not a PPTX extension = kwargs.get("file_extension", "") @@ -807,17 +836,38 @@ class PptxConverter(HtmlConverter): # Pictures if self._is_picture(shape): # https://github.com/scanny/python-pptx/pull/512#issuecomment-1713100069 - alt_text = "" - try: - alt_text = shape._element._nvXxPr.cNvPr.attrib.get("descr", "") - except Exception: - pass + + llm_description = None + alt_text = None + + llm_client = kwargs.get("llm_client") + llm_model = kwargs.get("llm_model") + if llm_client is not None and llm_model is not None: + try: + llm_description = self._get_llm_description( + llm_client, + llm_model, + shape.image.blob, + shape.image.content_type, + ) + except Exception: + # Unable to describe with LLM + pass + + if not llm_description: + try: + alt_text = shape._element._nvXxPr.cNvPr.attrib.get( + "descr", "" + ) + except Exception: + # Unable to get alt text + pass # A placeholder name filename = re.sub(r"\W", "", shape.name) + ".jpg" md_content += ( "\n![" - + (alt_text if alt_text else shape.name) + + (llm_description or alt_text or shape.name) + "](" + filename + ")\n" From 2a4f7bb6a8e3a5a4bd73e0dcfe1849205f62708a Mon Sep 17 00:00:00 2001 From: Werner Robitza Date: Sun, 9 Feb 2025 05:50:38 +0100 Subject: [PATCH 04/33] fix: argparse CLI option ordering, fixes #268 (#290) * fix: argparse CLI option ordering, fixes #268 * Fixed formatting. --- src/markitdown/__main__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/markitdown/__main__.py b/src/markitdown/__main__.py index 69e8f0e..353be84 100644 --- a/src/markitdown/__main__.py +++ b/src/markitdown/__main__.py @@ -4,8 +4,8 @@ import argparse import sys from textwrap import dedent -from __about__ import __version__ -from _markitdown import MarkItDown, DocumentConverterResult +from .__about__ import __version__ +from ._markitdown import MarkItDown, DocumentConverterResult def main(): @@ -51,24 +51,27 @@ def main(): help="show the version number and exit", ) - parser.add_argument("filename", nargs="?") parser.add_argument( "-o", "--output", help="Output file name. If not provided, output is written to stdout.", ) + parser.add_argument( "-d", "--use-docintel", action="store_true", help="Use Document Intelligence to extract text instead of offline conversion. Requires a valid Document Intelligence Endpoint.", ) + parser.add_argument( "-e", "--endpoint", type=str, help="Document Intelligence Endpoint. Required if using Document Intelligence.", ) + + parser.add_argument("filename", nargs="?") args = parser.parse_args() if args.use_docintel: From 73ba69d8cd44d3a95bbeb8d99188087777963402 Mon Sep 17 00:00:00 2001 From: wunde005 Date: Sat, 8 Feb 2025 22:58:13 -0600 Subject: [PATCH 05/33] For csv files mimetypes.guess_type is returning "application/vnd.ms-excel" on windows causing an invalid mime type in plaintextconverter. In reference to issue: https://github.com/microsoft/markitdown/issues/150 (#273) --- src/markitdown/_markitdown.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/markitdown/_markitdown.py b/src/markitdown/_markitdown.py index 9f610f6..e68b099 100644 --- a/src/markitdown/_markitdown.py +++ b/src/markitdown/_markitdown.py @@ -46,6 +46,9 @@ from azure.identity import DefaultAzureCredential # This constant is a temporary fix until the bug is resolved. CONTENT_FORMAT = "markdown" +# Override mimetype for csv to fix issue on windows +mimetypes.add_type("text/csv", ".csv") + # Optional Transcription support IS_AUDIO_TRANSCRIPTION_CAPABLE = False try: From c73afcffeadfbc116ff0260df6f720a804bb9675 Mon Sep 17 00:00:00 2001 From: afourney Date: Mon, 10 Feb 2025 15:21:44 -0800 Subject: [PATCH 06/33] Cleanup and refactor, in preparation for plugin support. (#318) * Work started moving converters to individual files. * Significant cleanup and refactor. * Moved everything to a packages subfolder. * Added sample plugin. * Added instructions to the README.md * Bumped version, and added a note about compatibility. --- .github/workflows/tests.yml | 9 +- README.md | 91 +- packages/markitdown-sample-plugin/README.md | 96 + .../markitdown-sample-plugin/pyproject.toml | 70 + .../markitdown_sample_plugin}/__about__.py | 2 +- .../src/markitdown_sample_plugin/__init__.py | 13 + .../src/markitdown_sample_plugin/_plugin.py | 39 + .../src/markitdown_sample_plugin}/py.typed | 0 .../tests}/__init__.py | 0 .../tests/test_files/test.rtf | 251 +++ .../tests/test_sample_plugin.py | 40 + packages/markitdown/README.md | 52 + .../markitdown/pyproject.toml | 0 .../markitdown/src/markitdown/__about__.py | 4 + .../markitdown/src/markitdown/__init__.py | 22 + .../markitdown/src}/markitdown/__main__.py | 37 +- .../markitdown/src/markitdown/_exceptions.py | 37 + .../markitdown/src/markitdown/_markitdown.py | 440 ++++ .../src/markitdown/converters/__init__.py | 45 + .../src/markitdown/converters/_base.py | 34 + .../converters/_bing_serp_converter.py | 81 + .../converters/_doc_intel_converter.py | 85 + .../markitdown/converters/_docx_converter.py | 31 + .../markitdown/converters/_html_converter.py | 51 + .../markitdown/converters/_image_converter.py | 87 + .../markitdown/converters/_ipynb_converter.py | 70 + .../src/markitdown/converters/_markdownify.py | 87 + .../markitdown/converters/_media_converter.py | 36 + .../markitdown/converters/_mp3_converter.py | 84 + .../converters/_outlook_msg_converter.py | 76 + .../markitdown/converters/_pdf_converter.py | 21 + .../converters/_plain_text_converter.py | 33 + .../markitdown/converters/_pptx_converter.py | 180 ++ .../markitdown/converters/_rss_converter.py | 143 ++ .../markitdown/converters/_wav_converter.py | 67 + .../converters/_wikipedia_converter.py | 56 + .../markitdown/converters/_xlsx_converter.py | 54 + .../converters/_youtube_converter.py | 148 ++ .../markitdown/converters/_zip_converter.py | 135 ++ packages/markitdown/src/markitdown/py.typed | 0 packages/markitdown/tests/__init__.py | 3 + .../markitdown/tests}/test_files/test.docx | Bin .../markitdown/tests}/test_files/test.jpg | Bin .../markitdown/tests}/test_files/test.json | 0 .../markitdown/tests}/test_files/test.pptx | Bin .../markitdown/tests}/test_files/test.xls | Bin .../markitdown/tests}/test_files/test.xlsx | Bin .../tests}/test_files/test_blog.html | 0 .../tests}/test_files/test_files.zip | Bin .../markitdown/tests}/test_files/test_llm.jpg | Bin .../tests}/test_files/test_mskanji.csv | 0 .../tests}/test_files/test_notebook.ipynb | 0 .../tests}/test_files/test_outlook_msg.msg | Bin .../markitdown/tests}/test_files/test_rss.xml | 0 .../tests}/test_files/test_serp.html | 0 .../tests}/test_files/test_wikipedia.html | 0 .../tests}/test_files/test_with_comment.docx | Bin .../markitdown/tests}/test_markitdown.py | 34 - src/markitdown/__init__.py | 11 - src/markitdown/_markitdown.py | 1801 ----------------- 60 files changed, 2755 insertions(+), 1901 deletions(-) create mode 100644 packages/markitdown-sample-plugin/README.md create mode 100644 packages/markitdown-sample-plugin/pyproject.toml rename {src/markitdown => packages/markitdown-sample-plugin/src/markitdown_sample_plugin}/__about__.py (81%) create mode 100644 packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__init__.py create mode 100644 packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py rename {src/markitdown => packages/markitdown-sample-plugin/src/markitdown_sample_plugin}/py.typed (100%) rename {tests => packages/markitdown-sample-plugin/tests}/__init__.py (100%) create mode 100755 packages/markitdown-sample-plugin/tests/test_files/test.rtf create mode 100644 packages/markitdown-sample-plugin/tests/test_sample_plugin.py create mode 100644 packages/markitdown/README.md rename pyproject.toml => packages/markitdown/pyproject.toml (100%) create mode 100644 packages/markitdown/src/markitdown/__about__.py create mode 100644 packages/markitdown/src/markitdown/__init__.py rename {src => packages/markitdown/src}/markitdown/__main__.py (67%) create mode 100644 packages/markitdown/src/markitdown/_exceptions.py create mode 100644 packages/markitdown/src/markitdown/_markitdown.py create mode 100644 packages/markitdown/src/markitdown/converters/__init__.py create mode 100644 packages/markitdown/src/markitdown/converters/_base.py create mode 100644 packages/markitdown/src/markitdown/converters/_bing_serp_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_doc_intel_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_docx_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_html_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_image_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_ipynb_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_markdownify.py create mode 100644 packages/markitdown/src/markitdown/converters/_media_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_mp3_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_pdf_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_plain_text_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_pptx_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_rss_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_wav_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_wikipedia_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_xlsx_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_youtube_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_zip_converter.py create mode 100644 packages/markitdown/src/markitdown/py.typed create mode 100644 packages/markitdown/tests/__init__.py rename {tests => packages/markitdown/tests}/test_files/test.docx (100%) rename {tests => packages/markitdown/tests}/test_files/test.jpg (100%) rename {tests => packages/markitdown/tests}/test_files/test.json (100%) rename {tests => packages/markitdown/tests}/test_files/test.pptx (100%) rename {tests => packages/markitdown/tests}/test_files/test.xls (100%) rename {tests => packages/markitdown/tests}/test_files/test.xlsx (100%) rename {tests => packages/markitdown/tests}/test_files/test_blog.html (100%) rename {tests => packages/markitdown/tests}/test_files/test_files.zip (100%) rename {tests => packages/markitdown/tests}/test_files/test_llm.jpg (100%) rename {tests => packages/markitdown/tests}/test_files/test_mskanji.csv (100%) rename {tests => packages/markitdown/tests}/test_files/test_notebook.ipynb (100%) rename {tests => packages/markitdown/tests}/test_files/test_outlook_msg.msg (100%) rename {tests => packages/markitdown/tests}/test_files/test_rss.xml (100%) rename {tests => packages/markitdown/tests}/test_files/test_serp.html (100%) rename {tests => packages/markitdown/tests}/test_files/test_wikipedia.html (100%) rename {tests => packages/markitdown/tests}/test_files/test_with_comment.docx (100%) rename {tests => packages/markitdown/tests}/test_markitdown.py (92%) delete mode 100644 src/markitdown/__init__.py delete mode 100644 src/markitdown/_markitdown.py diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c4dbdcf..78c7cdc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,14 +12,7 @@ jobs: 3.10 3.11 3.12 - - name: Set up pip cache - if: runner.os == 'Linux' - uses: actions/cache@v4 - with: - path: ~/.cache/pip - key: ${{ runner.os }}-pip-${{ hashFiles('pyproject.toml') }} - restore-keys: ${{ runner.os }}-pip- - name: Install Hatch run: pipx install hatch - name: Run tests - run: hatch test + run: cd packages/markitdown; hatch test diff --git a/README.md b/README.md index 76a4d3f..8ac2fe3 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ ![PyPI - Downloads](https://img.shields.io/pypi/dd/markitdown) [![Built by AutoGen Team](https://img.shields.io/badge/Built%20by-AutoGen%20Team-blue)](https://github.com/microsoft/autogen) +> [!IMPORTANT] +> MarkItDown 0.0.2 alpha 1 (0.0.2a1) introduces a plugin-based architecture. As much as was possible, command-line and Python interfaces have remained the same as 0.0.1a3 to support backward compatibility. Please report any issues you encounter. Some interface changes may yet occur as we continue to refine MarkItDown to a first non-alpha release. MarkItDown is a utility for converting various files to Markdown (e.g., for indexing, text analysis, etc). It supports: @@ -16,8 +18,15 @@ It supports: - HTML - Text-based formats (CSV, JSON, XML) - ZIP files (iterates over contents) +- ... and more! -To install MarkItDown, use pip: `pip install markitdown`. Alternatively, you can install it from the source: `pip install -e .` +To install MarkItDown, use pip: `pip install markitdown`. Alternatively, you can install it from the source: + +```bash +git clone git@github.com:microsoft/markitdown.git +cd markitdown +pip install -e packages/markitdown +``` ## Usage @@ -33,20 +42,39 @@ Or use `-o` to specify the output file: markitdown path-to-file.pdf -o document.md ``` -To use Document Intelligence conversion: - -```bash -markitdown path-to-file.pdf -o document.md -d -e "" -``` - You can also pipe content: ```bash cat path-to-file.pdf | markitdown ``` +### Plugins + +MarkItDown also supports 3rd-party plugins. Plugins are disabled by default. To list installed plugins: + +```bash +markitdown --list-plugins +``` + +To enable plugins use: + +```bash +markitdown --use-plugins path-to-file.pdf +``` + +To find available plugins, search GitHub for the hashtag `#markitdown-plugin`. To develop a plugin, see `packages/markitdown-sample-plugin`. + +### Azure Document Intelligence + +To use Microsoft Document Intelligence for conversion: + +```bash +markitdown path-to-file.pdf -o document.md -d -e "" +``` + More information about how to set up an Azure Document Intelligence Resource can be found [here](https://learn.microsoft.com/en-us/azure/ai-services/document-intelligence/how-to-guides/create-document-intelligence-resource?view=doc-intel-4.0.0) + ### Python API Basic usage in Python: @@ -54,7 +82,7 @@ Basic usage in Python: ```python from markitdown import MarkItDown -md = MarkItDown() +md = MarkItDown(enable_plugins=False) # Set to True to enable plugins result = md.convert("test.xlsx") print(result.text_content) ``` @@ -87,42 +115,6 @@ print(result.text_content) docker build -t markitdown:latest . docker run --rm -i markitdown:latest < ~/your-file.pdf > output.md ``` -
- -Batch Processing Multiple Files - -This example shows how to convert multiple files to markdown format in a single run. The script processes all supported files in a directory and creates corresponding markdown files. - - -```python convert.py -from markitdown import MarkItDown -from openai import OpenAI -import os -client = OpenAI(api_key="your-api-key-here") -md = MarkItDown(llm_client=client, llm_model="gpt-4o-2024-11-20") -supported_extensions = ('.pptx', '.docx', '.pdf', '.jpg', '.jpeg', '.png') -files_to_convert = [f for f in os.listdir('.') if f.lower().endswith(supported_extensions)] -for file in files_to_convert: - print(f"\nConverting {file}...") - try: - md_file = os.path.splitext(file)[0] + '.md' - result = md.convert(file) - with open(md_file, 'w') as f: - f.write(result.text_content) - - print(f"Successfully converted {file} to {md_file}") - except Exception as e: - print(f"Error converting {file}: {str(e)}") - -print("\nAll conversions completed!") -``` -2. Place the script in the same directory as your files -3. Install required packages: like openai -4. Run script ```bash python convert.py ``` - -Note that original files will remain unchanged and new markdown files are created with the same base name. - -
## Contributing @@ -154,6 +146,12 @@ You can help by looking at issues or helping review PRs. Any issue or PR is welc ### Running Tests and Checks +- Navigate to the MarkItDown package: + + ```sh + cd packages/markitdown + ``` + - Install `hatch` in your environment and run tests: ```sh pip install hatch # Other ways of installing hatch: https://hatch.pypa.io/dev/install/ @@ -169,6 +167,11 @@ You can help by looking at issues or helping review PRs. Any issue or PR is welc - Run pre-commit checks before submitting a PR: `pre-commit run --all-files` +### Contributing 3rd-party Plugins + +You can also contribute by creating and sharing 3rd party plugins. See `packages/markitdown-sample-plugin` for more details. + + ## Trademarks This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft diff --git a/packages/markitdown-sample-plugin/README.md b/packages/markitdown-sample-plugin/README.md new file mode 100644 index 0000000..9b15ca0 --- /dev/null +++ b/packages/markitdown-sample-plugin/README.md @@ -0,0 +1,96 @@ +# MarkItDown Sample Plugin + +[![PyPI](https://img.shields.io/pypi/v/markitdown.svg)](https://pypi.org/project/markitdown/) +![PyPI - Downloads](https://img.shields.io/pypi/dd/markitdown) +[![Built by AutoGen Team](https://img.shields.io/badge/Built%20by-AutoGen%20Team-blue)](https://github.com/microsoft/autogen) + + +This project shows how to create a sample plugin for MarkItDown. The most important parts are as follows: + +FNext, implement your custom DocumentConverter: + +```python +from typing import Union +from markitdown import DocumentConverter, DocumentConverterResult + +class RtfConverter(DocumentConverter): + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not an RTF file + extension = kwargs.get("file_extension", "") + if extension.lower() != ".rtf": + return None + + # Implement the conversion logic here ... + + # Return the result + return DocumentConverterResult( + title=title, + text_content=text_content, + ) +``` + +Next, make sure your package implements and exports the following: + +```python +# The version of the plugin interface that this plugin uses. +# The only supported version is 1 for now. +__plugin_interface_version__ = 1 + +# The main entrypoint for the plugin. This is called each time MarkItDown instances are created. +def register_converters(markitdown: MarkItDown, **kwargs): + """ + Called during construction of MarkItDown instances to register converters provided by plugins. + """ + + # Simply create and attach an RtfConverter instance + markitdown.register_converter(RtfConverter()) +``` + + +Finally, create an entrypoint in the `pyproject.toml` file: + +```toml +[project.entry-points."markitdown.plugin"] +sample_plugin = "markitdown_sample_plugin" +``` + +Here, the value of `sample_plugin` can be any key, but should ideally be the name of the plugin. The value is the fully qualified name of the package implementing the plugin. + + +## Installation + +To use the plugin with MarkItDown, it must be installed. To install the plugin from the current directory use: + +```bash +pip install -e . +``` + +Once the plugin package is installed, verify that it is available to MarkItDown by running: + +```bash +markitdown --list-plugins +``` + +To use the plugin for a conversion use the `--use-plugins` flag. For example, to convert a PDF: + +```bash +markitdown --use-plugins path-to-file.pdf +``` + +In Python, plugins can be enabled as follows: + +```python +from markitdown import MarkItDown + +md = MarkItDown(enable_plugins=True) +result = md.convert("path-to-file.pdf") +print(result.text_content) +``` + +## Trademarks + +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft +trademarks or logos is subject to and must follow +[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). +Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. +Any use of third-party trademarks or logos are subject to those third-party's policies. diff --git a/packages/markitdown-sample-plugin/pyproject.toml b/packages/markitdown-sample-plugin/pyproject.toml new file mode 100644 index 0000000..aaf2012 --- /dev/null +++ b/packages/markitdown-sample-plugin/pyproject.toml @@ -0,0 +1,70 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "markitdown-sample-plugin" +dynamic = ["version"] +description = 'A sample plugin for the "markitdown" library.' +readme = "README.md" +requires-python = ">=3.10" +license = "MIT" +keywords = [] +authors = [ + { name = "Adam Fourney", email = "adamfo@microsoft.com" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] +dependencies = [ + "markitdown", + "striprtf", +] + +[project.urls] +Documentation = "https://github.com/microsoft/markitdown#readme" +Issues = "https://github.com/microsoft/markitdown/issues" +Source = "https://github.com/microsoft/markitdown" + +[tool.hatch.version] +path = "src/markitdown_sample_plugin/__about__.py" + +# IMPORTANT: MarkItDown will look for this entry point to find the plugin. +[project.entry-points."markitdown.plugin"] +sample_plugin = "markitdown_sample_plugin" + +[tool.hatch.envs.types] +extra-dependencies = [ + "mypy>=1.0.0", +] +[tool.hatch.envs.types.scripts] +check = "mypy --install-types --non-interactive {args:src/markitdown_sample_plugin tests}" + +[tool.coverage.run] +source_pkgs = ["markitdown-sample-plugin", "tests"] +branch = true +parallel = true +omit = [ + "src/markitdown_sample_plugin/__about__.py", +] + +[tool.coverage.paths] +markitdown-sample-plugin = ["src/markitdown_sample_plugin", "*/markitdown-sample-plugin/src/markitdown_sample_plugin"] +tests = ["tests", "*/markitdown-sample-plugin/tests"] + +[tool.coverage.report] +exclude_lines = [ + "no cov", + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] + +[tool.hatch.build.targets.sdist] +only-include = ["src/markitdown_sample_plugin"] diff --git a/src/markitdown/__about__.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py similarity index 81% rename from src/markitdown/__about__.py rename to packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py index a365900..fa67ccb 100644 --- a/src/markitdown/__about__.py +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.0.1a3" +__version__ = "0.0.1a2" diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__init__.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__init__.py new file mode 100644 index 0000000..8a64f99 --- /dev/null +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__init__.py @@ -0,0 +1,13 @@ +# SPDX-FileCopyrightText: 2024-present Adam Fourney +# +# SPDX-License-Identifier: MIT + +from ._plugin import __plugin_interface_version__, register_converters, RtfConverter +from .__about__ import __version__ + +__all__ = [ + "__version__", + "__plugin_interface_version__", + "register_converters", + "RtfConverter", +] diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py new file mode 100644 index 0000000..c8c4fef --- /dev/null +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py @@ -0,0 +1,39 @@ +from typing import Union +from striprtf.striprtf import rtf_to_text + +from markitdown import MarkItDown, DocumentConverter, DocumentConverterResult + +__plugin_interface_version__ = ( + 1 # The version of the plugin interface that this plugin uses +) + + +def register_converters(markitdown: MarkItDown, **kwargs): + """ + Called during construction of MarkItDown instances to register converters provided by plugins. + """ + + # Simply create and attach an RtfConverter instance + markitdown.register_converter(RtfConverter()) + + +class RtfConverter(DocumentConverter): + """ + Converts an RTF file to in the simplest possible way. + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a DOCX + extension = kwargs.get("file_extension", "") + if extension.lower() != ".rtf": + return None + + # Read the RTF file + with open(local_path, "r") as f: + rtf = f.read() + + # Return the result + return DocumentConverterResult( + title=None, + text_content=rtf_to_text(rtf), + ) diff --git a/src/markitdown/py.typed b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/py.typed similarity index 100% rename from src/markitdown/py.typed rename to packages/markitdown-sample-plugin/src/markitdown_sample_plugin/py.typed diff --git a/tests/__init__.py b/packages/markitdown-sample-plugin/tests/__init__.py similarity index 100% rename from tests/__init__.py rename to packages/markitdown-sample-plugin/tests/__init__.py diff --git a/packages/markitdown-sample-plugin/tests/test_files/test.rtf b/packages/markitdown-sample-plugin/tests/test_files/test.rtf new file mode 100755 index 0000000..48629ef --- /dev/null +++ b/packages/markitdown-sample-plugin/tests/test_files/test.rtf @@ -0,0 +1,251 @@ +{\rtf1\adeflang1025\ansi\ansicpg1252\uc1\adeff31507\deff0\stshfdbch31506\stshfloch31506\stshfhich31506\stshfbi31507\deflang1033\deflangfe1033\themelang1033\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f34\fbidi \froman\fcharset0\fprq2{\*\panose 02040503050406030204}Cambria Math;} +{\f42\fbidi \fswiss\fcharset0\fprq2 Aptos Display;}{\f43\fbidi \fswiss\fcharset0\fprq2 Aptos;}{\flomajor\f31500\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\fdbmajor\f31501\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \fswiss\fcharset0\fprq2 Aptos Display;}{\fbimajor\f31503\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;} +{\flominor\f31504\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fdbminor\f31505\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset0\fprq2 Aptos;} +{\fbiminor\f31507\fbidi \froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f51\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\f52\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\f54\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f55\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f56\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f57\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} +{\f58\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f59\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f391\fbidi \froman\fcharset238\fprq2 Cambria Math CE;}{\f392\fbidi \froman\fcharset204\fprq2 Cambria Math Cyr;} +{\f394\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f395\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f398\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f399\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);} +{\f471\fbidi \fswiss\fcharset238\fprq2 Aptos Display CE;}{\f472\fbidi \fswiss\fcharset204\fprq2 Aptos Display Cyr;}{\f474\fbidi \fswiss\fcharset161\fprq2 Aptos Display Greek;}{\f475\fbidi \fswiss\fcharset162\fprq2 Aptos Display Tur;} +{\f478\fbidi \fswiss\fcharset186\fprq2 Aptos Display Baltic;}{\f479\fbidi \fswiss\fcharset163\fprq2 Aptos Display (Vietnamese);}{\f481\fbidi \fswiss\fcharset238\fprq2 Aptos CE;}{\f482\fbidi \fswiss\fcharset204\fprq2 Aptos Cyr;} +{\f484\fbidi \fswiss\fcharset161\fprq2 Aptos Greek;}{\f485\fbidi \fswiss\fcharset162\fprq2 Aptos Tur;}{\f488\fbidi \fswiss\fcharset186\fprq2 Aptos Baltic;}{\f489\fbidi \fswiss\fcharset163\fprq2 Aptos (Vietnamese);} +{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31509\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} +{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} +{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\fdbmajor\f31519\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Aptos Display CE;}{\fhimajor\f31529\fbidi \fswiss\fcharset204\fprq2 Aptos Display Cyr;} +{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Aptos Display Greek;}{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Aptos Display Tur;}{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Aptos Display Baltic;} +{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Aptos Display (Vietnamese);}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbimajor\f31539\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} +{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31549\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} +{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} +{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} +{\fdbminor\f31559\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} +{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} +{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Aptos CE;}{\fhiminor\f31569\fbidi \fswiss\fcharset204\fprq2 Aptos Cyr;} +{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Aptos Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Aptos Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Aptos Baltic;} +{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Aptos (Vietnamese);}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fbiminor\f31579\fbidi \froman\fcharset204\fprq2 Times New Roman Cyr;} +{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} +{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}} +{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0; +\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;\red0\green0\blue0;\red0\green0\blue0;\caccentone\ctint255\cshade191\red15\green71\blue97; +\ctextone\ctint166\cshade255\red89\green89\blue89;\ctextone\ctint216\cshade255\red39\green39\blue39;\ctextone\ctint191\cshade255\red64\green64\blue64;}{\*\defchp \f31506\fs24\kerning2 }{\*\defpap \ql \li0\ri0\sa160\sl278\slmult1 +\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl278\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs24\alang1025 +\ltrch\fcs0 \f31506\fs24\lang1033\langfe1033\kerning2\cgrid\langnp1033\langfenp1033 \snext0 \sqformat \spriority0 Normal;}{\s1\ql \li0\ri0\sb360\sa80\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31503\afs40\alang1025 \ltrch\fcs0 +\fs40\cf19\lang1033\langfe1033\kerning2\loch\f31502\hich\af31502\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink15 \sqformat \spriority9 \styrsid15678446 heading 1;}{\s2\ql \li0\ri0\sb160\sa80\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel1\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31503\afs32\alang1025 \ltrch\fcs0 +\fs32\cf19\lang1033\langfe1033\kerning2\loch\f31502\hich\af31502\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink16 \ssemihidden \sunhideused \sqformat \spriority9 \styrsid15678446 heading 2;}{\s3\ql \li0\ri0\sb160\sa80\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel2\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31503\afs28\alang1025 \ltrch\fcs0 +\fs28\cf19\lang1033\langfe1033\kerning2\loch\f31506\hich\af31506\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink17 \ssemihidden \sunhideused \sqformat \spriority9 \styrsid15678446 heading 3;}{\s4\ql \li0\ri0\sb80\sa40\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel3\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ai\af31503\afs24\alang1025 \ltrch\fcs0 +\i\fs24\cf19\lang1033\langfe1033\kerning2\loch\f31506\hich\af31506\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink18 \ssemihidden \sunhideused \sqformat \spriority9 \styrsid15678446 heading 4;}{\s5\ql \li0\ri0\sb80\sa40\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel4\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31503\afs24\alang1025 \ltrch\fcs0 +\fs24\cf19\lang1033\langfe1033\kerning2\loch\f31506\hich\af31506\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink19 \ssemihidden \sunhideused \sqformat \spriority9 \styrsid15678446 heading 5;}{\s6\ql \li0\ri0\sb40\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel5\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ai\af31503\afs24\alang1025 \ltrch\fcs0 +\i\fs24\cf20\lang1033\langfe1033\kerning2\loch\f31506\hich\af31506\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink20 \ssemihidden \sunhideused \sqformat \spriority9 \styrsid15678446 heading 6;}{\s7\ql \li0\ri0\sb40\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel6\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31503\afs24\alang1025 \ltrch\fcs0 +\fs24\cf20\lang1033\langfe1033\kerning2\loch\f31506\hich\af31506\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink21 \ssemihidden \sunhideused \sqformat \spriority9 \styrsid15678446 heading 7;}{\s8\ql \li0\ri0\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel7\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ai\af31503\afs24\alang1025 \ltrch\fcs0 +\i\fs24\cf21\lang1033\langfe1033\kerning2\loch\f31506\hich\af31506\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink22 \ssemihidden \sunhideused \sqformat \spriority9 \styrsid15678446 heading 8;}{\s9\ql \li0\ri0\sl278\slmult1 +\keep\keepn\widctlpar\wrapdefault\aspalpha\aspnum\faauto\outlinelevel8\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31503\afs24\alang1025 \ltrch\fcs0 +\fs24\cf21\lang1033\langfe1033\kerning2\loch\f31506\hich\af31506\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink23 \ssemihidden \sunhideused \sqformat \spriority9 \styrsid15678446 heading 9;}{\*\cs10 \additive +\ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\* +\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa160\sl278\slmult1 +\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs24\alang1025 \ltrch\fcs0 \f31506\fs24\lang1033\langfe1033\kerning2\cgrid\langnp1033\langfenp1033 \snext11 \ssemihidden \sunhideused Normal Table;}{\*\cs15 +\additive \rtlch\fcs1 \af31503\afs40 \ltrch\fcs0 \fs40\cf19\loch\f31502\hich\af31502\dbch\af31501 \sbasedon10 \slink1 \spriority9 \styrsid15678446 Heading 1 Char;}{\*\cs16 \additive \rtlch\fcs1 \af31503\afs32 \ltrch\fcs0 +\fs32\cf19\loch\f31502\hich\af31502\dbch\af31501 \sbasedon10 \slink2 \ssemihidden \spriority9 \styrsid15678446 Heading 2 Char;}{\*\cs17 \additive \rtlch\fcs1 \af31503\afs28 \ltrch\fcs0 \fs28\cf19\dbch\af31501 +\sbasedon10 \slink3 \ssemihidden \spriority9 \styrsid15678446 Heading 3 Char;}{\*\cs18 \additive \rtlch\fcs1 \ai\af31503 \ltrch\fcs0 \i\cf19\dbch\af31501 \sbasedon10 \slink4 \ssemihidden \spriority9 \styrsid15678446 Heading 4 Char;}{\*\cs19 \additive +\rtlch\fcs1 \af31503 \ltrch\fcs0 \cf19\dbch\af31501 \sbasedon10 \slink5 \ssemihidden \spriority9 \styrsid15678446 Heading 5 Char;}{\*\cs20 \additive \rtlch\fcs1 \ai\af31503 \ltrch\fcs0 \i\cf20\dbch\af31501 +\sbasedon10 \slink6 \ssemihidden \spriority9 \styrsid15678446 Heading 6 Char;}{\*\cs21 \additive \rtlch\fcs1 \af31503 \ltrch\fcs0 \cf20\dbch\af31501 \sbasedon10 \slink7 \ssemihidden \spriority9 \styrsid15678446 Heading 7 Char;}{\*\cs22 \additive +\rtlch\fcs1 \ai\af31503 \ltrch\fcs0 \i\cf21\dbch\af31501 \sbasedon10 \slink8 \ssemihidden \spriority9 \styrsid15678446 Heading 8 Char;}{\*\cs23 \additive \rtlch\fcs1 \af31503 \ltrch\fcs0 \cf21\dbch\af31501 +\sbasedon10 \slink9 \ssemihidden \spriority9 \styrsid15678446 Heading 9 Char;}{\s24\ql \li0\ri0\sa80\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\contextualspace \rtlch\fcs1 \af31503\afs56\alang1025 \ltrch\fcs0 +\fs56\expnd-2\expndtw-10\lang1033\langfe1033\kerning28\loch\f31502\hich\af31502\dbch\af31501\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink25 \sqformat \spriority10 \styrsid15678446 Title;}{\*\cs25 \additive \rtlch\fcs1 \af31503\afs56 +\ltrch\fcs0 \fs56\expnd-2\expndtw-10\kerning28\loch\f31502\hich\af31502\dbch\af31501 \sbasedon10 \slink24 \spriority10 \styrsid15678446 Title Char;}{\s26\ql \li0\ri0\sa160\sl278\slmult1 +\widctlpar\wrapdefault\aspalpha\aspnum\faauto\ilvl1\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31503\afs28\alang1025 \ltrch\fcs0 \fs28\expnd3\expndtw15\cf20\lang1033\langfe1033\kerning2\loch\f31506\hich\af31506\dbch\af31501\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext0 \slink27 \sqformat \spriority11 \styrsid15678446 Subtitle;}{\*\cs27 \additive \rtlch\fcs1 \af31503\afs28 \ltrch\fcs0 \fs28\expnd3\expndtw15\cf20\dbch\af31501 \sbasedon10 \slink26 \spriority11 \styrsid15678446 Subtitle Char;}{ +\s28\qc \li0\ri0\sb160\sa160\sl278\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \ai\af31507\afs24\alang1025 \ltrch\fcs0 \i\f31506\fs24\cf22\lang1033\langfe1033\kerning2\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext0 \slink29 \sqformat \spriority29 \styrsid15678446 Quote;}{\*\cs29 \additive \rtlch\fcs1 \ai\af0 \ltrch\fcs0 \i\cf22 \sbasedon10 \slink28 \spriority29 \styrsid15678446 Quote Char;}{\s30\ql \li720\ri0\sa160\sl278\slmult1 +\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin720\itap0\contextualspace \rtlch\fcs1 \af31507\afs24\alang1025 \ltrch\fcs0 \f31506\fs24\lang1033\langfe1033\kerning2\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext30 \sqformat \spriority34 \styrsid15678446 List Paragraph;}{\*\cs31 \additive \rtlch\fcs1 \ai\af0 \ltrch\fcs0 \i\cf19 \sbasedon10 \sqformat \spriority21 \styrsid15678446 Intense Emphasis;}{\s32\qc \li864\ri864\sb360\sa360\sl278\slmult1 +\widctlpar\brdrt\brdrs\brdrw10\brsp200\brdrcf19 \brdrb\brdrs\brdrw10\brsp200\brdrcf19 \wrapdefault\aspalpha\aspnum\faauto\adjustright\rin864\lin864\itap0 \rtlch\fcs1 \ai\af31507\afs24\alang1025 \ltrch\fcs0 +\i\f31506\fs24\cf19\lang1033\langfe1033\kerning2\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 \slink33 \sqformat \spriority30 \styrsid15678446 Intense Quote;}{\*\cs33 \additive \rtlch\fcs1 \ai\af0 \ltrch\fcs0 \i\cf19 +\sbasedon10 \slink32 \spriority30 \styrsid15678446 Intense Quote Char;}{\*\cs34 \additive \rtlch\fcs1 \ab\af0 \ltrch\fcs0 \b\scaps\expnd1\expndtw5\cf19 \sbasedon10 \sqformat \spriority32 \styrsid15678446 Intense Reference;}}{\*\rsidtbl \rsid3543682 +\rsid6316520\rsid7364952\rsid8278432\rsid9589131\rsid10298217\rsid15678446\rsid15953651}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\author Adam Fourney} +{\operator Adam Fourney}{\creatim\yr2025\mo2\dy9\hr22\min56}{\revtim\yr2025\mo2\dy9\hr22\min58}{\version1}{\edmins2}{\nofpages1}{\nofwords17}{\nofchars98}{\nofcharsws114}{\vern115}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordm +l}}\paperw12240\paperh15840\margl1440\margr1440\margt1440\margb1440\gutter0\ltrsect +\widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont1\relyonvml0\donotembedlingdata0\grfdocevents0\validatexml1\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors1\noxlattoyen +\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\formshade\horzdoc\dgmargin\dghspace180\dgvspace180\dghorigin1440\dgvorigin1440\dghshow1\dgvshow1 +\jexpand\viewkind1\viewscale100\pgbrdrhead\pgbrdrfoot\splytwnine\ftnlytwnine\htmautsp\nolnhtadjtbl\useltbaln\alntblind\lytcalctblwd\lyttblrtgr\lnbrkrule\nobrkwrptbl\snaptogridincell\allowfieldendsel\wrppunct +\asianbrkrule\rsidroot15678446\newtblstyruls\nogrowautofit\usenormstyforlist\noindnmbrts\felnbrelev\nocxsptable\indrlsweleven\noafcnsttbl\afelev\utinl\hwelev\spltpgpar\notcvasp\notbrkcnstfrctbl\notvatxbx\krnprsnet\cachedcolbal \nouicompat \fet0 +{\*\wgrffmtfilter 2450}\nofeaturethrottle1\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\endnhere\sectlinegrid360\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang +{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang +{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}} +\pard\plain \ltrpar\s24\ql \li0\ri0\sa80\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0\pararsid15678446\contextualspace \rtlch\fcs1 \af31503\afs56\alang1025 \ltrch\fcs0 +\fs56\expnd-2\expndtw-10\lang1033\langfe1033\kerning28\loch\af31502\hich\af31502\dbch\af31501\cgrid\langnp1033\langfenp1033 {\rtlch\fcs1 \af31503 \ltrch\fcs0 \insrsid15678446 \hich\af31502\dbch\af31501\loch\f31502 This is a +\hich\af31502\dbch\af31501\loch\f31502 S\hich\af31502\dbch\af31501\loch\f31502 ample RT\hich\af31502\dbch\af31501\loch\f31502 F \hich\af31502\dbch\af31501\loch\f31502 File}{\rtlch\fcs1 \af31503 \ltrch\fcs0 \insrsid8278432 +\par }\pard\plain \ltrpar\ql \li0\ri0\sa160\sl278\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs24\alang1025 \ltrch\fcs0 \f31506\fs24\lang1033\langfe1033\kerning2\cgrid\langnp1033\langfenp1033 { +\rtlch\fcs1 \af31507 \ltrch\fcs0 \insrsid15678446 +\par It is included to test if the MarkItDown sample plugin can correctly convert RTF files. +\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a +9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad +5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 +b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 +0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 +a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f +c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 +0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 +a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 +6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b +4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b +4757e8d3f729e245eb2b260a0238fd010000ffff0300504b030414000600080000002100d3d1e707f007000012220000160000007468656d652f7468656d652f +7468656d65312e786d6cec5a4b8fdbc811be07c87f20789745ea414903cb0b3d3d6bcfd8034b76b0c796d812dbd36413ecd6cc080b0381f794cb020b6c825c02 +e496431064812c90452ef931066c249b1f91ea2645754b2dcf030662043373215b5f557f5d555d556cf2e1175731752e70c6094bbaaeffc0731d9ccc59489265 +d77d391d57daaec3054a42445982bbee1a73f78b47bffcc5437424221c6307e4137e84ba6e24447a54adf2390c23fe80a53881df162c8b9180db6c590d337409 +7a635aad795e508d11495c274131a87dbe58903976a652a5fb68a37c44e136115c0ecc693691aab121a1b0e1b92f117ccd0734732e10edba304fc82ea7f84ab8 +0e455cc00f5dd7537f6ef5d1c32a3a2a84a83820abc98dd55f21570884e7353567b69c95937aa35abbe197fa15808a7ddca82dff4b7d0a80e6735869ce45d7e9 +3703af5d2bb01a28bfb4e8eeb4fcba89d7f4d7f738fb9da05f6b18fa1528d7dfd8c37be3ce68d834f00a94e39b7bf89e57eb77ea065e81727cb0876f8c7aadda +c8c02b50444972be8f0e5aed7650a04bc882d1632bbc13045e6b58c0b728888632bae4140b968843b116a3d72c1b03400229122471c43ac50b348728eea58271 +6748784ad1da755294300ec35ecdf721f41a5eadfc571647471869d2921730e17b43928fc3e7194945d77d025a5d0df2fea79fdebdfdf1dddbbfbffbe69b776f +ffea9c906524725586dc314a96badccf7ffaee3f7ff8b5f3efbffdf1e7ef7f6bc7731dffe12fbff9f08f7f7e4c3d6cb5ad29deffee870f3ffef0fef7dffeebcf +df5bb4f73234d3e1531263ee3cc397ce0b16c30295294cfe7896dd4e621a21a24bf49225470992b358f48f4464a09fad1145165c1f9b767c9541aab1011faf5e +1b842751b612c4a2f169141bc053c6689f65562b3c957369669eae92a57df26ca5e35e2074619b7b8012c3cba3550a3996d8540e226cd03ca328116889132c1c +f91b3bc7d8b2baaf0831ec7a4ae619e36c219caf88d347c46a92299919d1b4153a2631f8656d2308fe366c73facae9336a5bf5105f9848d81b885ac84f3135cc +f818ad048a6d2aa728a6bac14f90886c2427eb6caee3465c80a7979832671462ce6d32cf3358afe6f4a708b29bd5eda7741d9bc84c90739bce13c4988e1cb2f3 +4184e2d4869d9024d2b15ff2730851e49c3161839f327387c87bf0034a0ebafb15c186bbafcf062f21cbe994b601227f5965165f3ec6cc88dfc99a2e10b6a59a +5e161b29b697116b74f4574b23b44f30a6e81285183b2fbfb430e8b3d4b0f996f49308b2ca31b605d61364c6aabc4f30875e493637fb79f2847023642778c90e +f0395def249e354a62941dd2fc0cbcaedb7c34cb60335a283ca7f3731df88c400f08f16235ca730e3ab4e03ea8f52c42460193f7dc1eafebccf0df4df618eccb +d7068d1bec4b90c1b79681c4aecb7cd43653448d09b6013345c439b1a55b1031dcbf1591c55589adac720b73d36edd00dd91d1f4c424b9a603fadf743e9640fc +343d8f5db191b06ed9ed1c4a28c73b3dce21dc6e67336059483effc6668856c919865ab29fb5eefb9afbbec6fdbfef6b0eede7fb6ee650cf71dfcdb8d065dc77 +33c501cba7e966b60d0cf436f290213fec51473ff1c1939f05a17422d6149f7075f8c3e199261cc3a09453a79eb83c094c23b894650e263070cb0c29192763e2 +5744449308a57042e4bb52c99217aa97dc4919878323356cd52df174159fb2303ff054274c5e5e593912db71af09474ff9381c56891c1db48a41c94f9daa025f +c576a90e5b3704a4ec6d4868939924ea1612adcde03524e4d9d9a761d1b1b0684bf51b57ed9902a8955e81876e071ed5bb6eb32109c149399f43831e4a3fe5ae +de785739f3537afa90318d0880c3c57c2570345f7aba23b91e5c9e5c5d1e6a37f0b4414239250f2b9384b28c6af078048fc24574cad19bd0b8adaf3b5b971af4 +a429d47c10df5b1aadf6c758dcd5d720b79b1b68a2670a9a38975d37a8372164e628edba0b383886cb3885d8e1f2b90bd125bc7d998b2cdff077c92c69c6c510 +f12837b84a3ab97b622270e65012775db9fcd20d3451394471f36b90103e5b721d482b9f1b3970bae964bc58e0b9d0ddae8d484be7b790e1f35c61fd5589df1d +2c25d90adc3d89c24b674657d90b0421d66cf9d28021e1f0fec0cfad191278215626b26dfced14a622f9eb6fa4540ce5e388a6112a2a8a9ecc73b8aa27251d75 +57da40bb2bd60c06d54c5214c2d9521658dda846352d4b57cee160d5bd5e485a4e4b9adb9a6964155935ed59cc98615306766c79b722afb1da9818729a5ee1f3 +d4bd9b723b9b5cb7d3279455020c5edaef6ea55fa3b69dcca02619efa76199b38b51b3766c16780db59b14092deb071bb53b762b6b84753a18bc53e507b9dda8 +85a1c5a6af5496566fcef597db6cf61a92c710badc15cd5f77d304ee6454f2f42c53be9db1705d5c529e279adce7b22795489abcc00b8784579b7eb2746fbe3d +f257ae7ed10c28b41493b5ab14b4367ba6608197a2f986bd8d7029a16686d6bb1456c78ab67e575c6d28cb561df0ca843c5f3598b6b0145ced5b118ec83304ad +ed44357679ee05da57a2c82f70e5ac32d275bff69abdc6a0d61c54bc76735469d41b5ea5ddecd52bbd66b3ee8f9abe37ecd7de003d11c57e33fff4610c6f82e8 +baf800428def7d04116f5e763d98b3b8cad4470e55e57df511845f3bfc110438126805b571a7dee907954ebd37ae3486fd76a53308fa956130680dc7c341b3dd +19bf719d0b056ef4ea8346306a57027f30a834024fd26f772aad46add66bb47aed51a3f7a6703fac3ccfc1852dc07c8ad7a3ff020000ffff0300504b03041400 +06000800000021000dd1909fb60000001b010000270000007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c7384 +8f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae995719ac16d +b8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757da0f19b017c +c524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d001400060008 +0000002100e9de0fbfff0000001c0200001300000000000000000000000000000000005b436f6e74656e745f54797065735d2e786d6c504b01022d0014000600 +080000002100a5d6a7e7c0000000360100000b00000000000000000000000000300100005f72656c732f2e72656c73504b01022d00140006000800000021006b +799616830000008a0000001c00000000000000000000000000190200007468656d652f7468656d652f7468656d654d616e616765722e786d6c504b01022d0014 +000600080000002100d3d1e707f0070000122200001600000000000000000000000000d60200007468656d652f7468656d652f7468656d65312e786d6c504b01 +022d00140006000800000021000dd1909fb60000001b0100002700000000000000000000000000fa0a00007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000f50b00000000} +{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d +617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 +6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 +656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} +{\*\latentstyles\lsdstimax376\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6; +\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature;\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong; +\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Table;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 1; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 3; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 6; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 6; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Contemporary;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Elegant;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Professional; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 2; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Theme;\lsdsemihidden1 \lsdlocked0 Placeholder Text; +\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2; +\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List; +\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;\lsdpriority61 \lsdlocked0 Light List Accent 1; +\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdsemihidden1 \lsdlocked0 Revision; +\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1; +\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;\lsdpriority72 \lsdlocked0 Colorful List Accent 1; +\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2; +\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2; +\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2; +\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3; +\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3; +\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4; +\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4; +\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4; +\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5; +\lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; +\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; +\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; +\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; +\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; +\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; +\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; +\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; +\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; +\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; +\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; +\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; +\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; +\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; +\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; +\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; +\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; +\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; +\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; +\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; +\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; +\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; +\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Mention; +\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hashtag;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Unresolved Mention;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Smart Link;}}{\*\datastore 01050000 +02000000180000004d73786d6c322e534158584d4c5265616465722e362e3000000000000000000000060000 +d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff090006000000000000000000000001000000010000000000000000100000feffffff00000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +fffffffffffffffffdfffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffffffffffff0c6ad98892f1d411a65f0040963251e5000000000000000000000000f0af +5b31897bdb01feffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000105000000000000}} \ No newline at end of file diff --git a/packages/markitdown-sample-plugin/tests/test_sample_plugin.py b/packages/markitdown-sample-plugin/tests/test_sample_plugin.py new file mode 100644 index 0000000..49d54aa --- /dev/null +++ b/packages/markitdown-sample-plugin/tests/test_sample_plugin.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 -m pytest +import os +import pytest + +from markitdown import MarkItDown +from markitdown_sample_plugin import RtfConverter + +TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "test_files") + +RTF_TEST_STRINGS = { + "This is a Sample RTF File", + "It is included to test if the MarkItDown sample plugin can correctly convert RTF files.", +} + + +def test_converter() -> None: + """Tests the RTF converter dirctly.""" + converter = RtfConverter() + result = converter.convert( + os.path.join(TEST_FILES_DIR, "test.rtf"), file_extension=".rtf" + ) + + for test_string in RTF_TEST_STRINGS: + assert test_string in result.text_content + + +def test_markitdown() -> None: + """Tests that MarkItDown correctly loads the plugin.""" + md = MarkItDown() + result = md.convert(os.path.join(TEST_FILES_DIR, "test.rtf")) + + for test_string in RTF_TEST_STRINGS: + assert test_string in result.text_content + + +if __name__ == "__main__": + """Runs this file's tests from the command line.""" + test_converter() + test_markitdown() + print("All tests passed.") diff --git a/packages/markitdown/README.md b/packages/markitdown/README.md new file mode 100644 index 0000000..54453ab --- /dev/null +++ b/packages/markitdown/README.md @@ -0,0 +1,52 @@ +# MarkItDown + +> [!IMPORTANT] +> MarkItDown is a Python package and command-line utility for converting various files to Markdown (e.g., for indexing, text analysis, etc). +> +> For more information, and full documentation, see the project [README.md](https://github.com/microsoft/markitdown) on GitHub. + +## Installation + +From PyPI: + +```bash +pip install markitdown +``` + +From source: + +```bash +git clone git@github.com:microsoft/markitdown.git +cd markitdown +pip install -e packages/markitdown +``` + +## Usage + +### Command-Line + +```bash +markitdown path-to-file.pdf > document.md +``` + +### Python API + +```python +from markitdown import MarkItDown + +md = MarkItDown() +result = md.convert("test.xlsx") +print(result.text_content) +``` + +### More Information + +For more information, and full documentation, see the project [README.md](https://github.com/microsoft/markitdown) on GitHub. + +## Trademarks + +This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft +trademarks or logos is subject to and must follow +[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). +Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. +Any use of third-party trademarks or logos are subject to those third-party's policies. diff --git a/pyproject.toml b/packages/markitdown/pyproject.toml similarity index 100% rename from pyproject.toml rename to packages/markitdown/pyproject.toml diff --git a/packages/markitdown/src/markitdown/__about__.py b/packages/markitdown/src/markitdown/__about__.py new file mode 100644 index 0000000..dc5aafc --- /dev/null +++ b/packages/markitdown/src/markitdown/__about__.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2024-present Adam Fourney +# +# SPDX-License-Identifier: MIT +__version__ = "0.0.2a1" diff --git a/packages/markitdown/src/markitdown/__init__.py b/packages/markitdown/src/markitdown/__init__.py new file mode 100644 index 0000000..5407233 --- /dev/null +++ b/packages/markitdown/src/markitdown/__init__.py @@ -0,0 +1,22 @@ +# SPDX-FileCopyrightText: 2024-present Adam Fourney +# +# SPDX-License-Identifier: MIT + +from ._markitdown import MarkItDown +from ._exceptions import ( + MarkItDownException, + ConverterPrerequisiteException, + FileConversionException, + UnsupportedFormatException, +) +from .converters import DocumentConverter, DocumentConverterResult + +__all__ = [ + "MarkItDown", + "DocumentConverter", + "DocumentConverterResult", + "MarkItDownException", + "ConverterPrerequisiteException", + "FileConversionException", + "UnsupportedFormatException", +] diff --git a/src/markitdown/__main__.py b/packages/markitdown/src/markitdown/__main__.py similarity index 67% rename from src/markitdown/__main__.py rename to packages/markitdown/src/markitdown/__main__.py index 353be84..6a24391 100644 --- a/src/markitdown/__main__.py +++ b/packages/markitdown/src/markitdown/__main__.py @@ -4,6 +4,7 @@ import argparse import sys from textwrap import dedent +from importlib.metadata import entry_points from .__about__ import __version__ from ._markitdown import MarkItDown, DocumentConverterResult @@ -71,9 +72,39 @@ def main(): help="Document Intelligence Endpoint. Required if using Document Intelligence.", ) + parser.add_argument( + "-p", + "--use-plugins", + action="store_true", + help="Use 3rd-party plugins to convert files. Use --list-plugins to see installed plugins.", + ) + + parser.add_argument( + "--list-plugins", + action="store_true", + help="List installed 3rd-party plugins. Plugins are loaded when using the -p or --use-plugin option.", + ) + parser.add_argument("filename", nargs="?") args = parser.parse_args() + if args.list_plugins: + # List installed plugins, then exit + print("Installed MarkItDown 3rd-party Plugins:\n") + plugin_entry_points = list(entry_points(group="markitdown.plugin")) + if len(plugin_entry_points) == 0: + print(" * No 3rd-party plugins installed.") + print( + "\nFind plugins by searching for the hashtag #markitdown-plugin on GitHub.\n" + ) + else: + for entry_point in plugin_entry_points: + print(f" * {entry_point.name:<16}\t(package: {entry_point.value})") + print( + "\nUse the -p (or --use-plugins) option to enable 3rd-party plugins.\n" + ) + sys.exit(0) + if args.use_docintel: if args.endpoint is None: raise ValueError( @@ -81,9 +112,11 @@ def main(): ) elif args.filename is None: raise ValueError("Filename is required when using Document Intelligence.") - markitdown = MarkItDown(docintel_endpoint=args.endpoint) + markitdown = MarkItDown( + enable_plugins=args.use_plugins, docintel_endpoint=args.endpoint + ) else: - markitdown = MarkItDown() + markitdown = MarkItDown(enable_plugins=args.use_plugins) if args.filename is None: result = markitdown.convert_stream(sys.stdin.buffer) diff --git a/packages/markitdown/src/markitdown/_exceptions.py b/packages/markitdown/src/markitdown/_exceptions.py new file mode 100644 index 0000000..30c4dc5 --- /dev/null +++ b/packages/markitdown/src/markitdown/_exceptions.py @@ -0,0 +1,37 @@ +class MarkItDownException(BaseException): + """ + Base exception class for MarkItDown. + """ + + pass + + +class ConverterPrerequisiteException(MarkItDownException): + """ + Thrown when instantiating a DocumentConverter in cases where + a required library or dependency is not installed, an API key + is not set, or some other prerequisite is not met. + + This is not necessarily a fatal error. If thrown during + MarkItDown's plugin loading phase, the converter will simply be + skipped, and a warning will be issued. + """ + + pass + + +class FileConversionException(MarkItDownException): + """ + Thrown when a suitable converter was found, but the conversion + process fails for any reason. + """ + + pass + + +class UnsupportedFormatException(MarkItDownException): + """ + Thrown when no suitable converter was found for the given file. + """ + + pass diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py new file mode 100644 index 0000000..b7ac5bc --- /dev/null +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -0,0 +1,440 @@ +import copy +import mimetypes +import os +import re +import tempfile +import warnings +import traceback +from importlib.metadata import entry_points +from typing import Any, List, Optional, Union +from pathlib import Path +from urllib.parse import urlparse +from warnings import warn + +# File-format detection +import puremagic +import requests + +from .converters import ( + DocumentConverter, + DocumentConverterResult, + PlainTextConverter, + HtmlConverter, + RssConverter, + WikipediaConverter, + YouTubeConverter, + IpynbConverter, + BingSerpConverter, + PdfConverter, + DocxConverter, + XlsxConverter, + XlsConverter, + PptxConverter, + ImageConverter, + WavConverter, + Mp3Converter, + OutlookMsgConverter, + ZipConverter, + DocumentIntelligenceConverter, +) + +from ._exceptions import ( + FileConversionException, + UnsupportedFormatException, + ConverterPrerequisiteException, +) + +# Override mimetype for csv to fix issue on windows +mimetypes.add_type("text/csv", ".csv") + +PRIORITY_SPECIFIC_FILE_FORMAT = 0.0 +PRIORITY_GENERIC_FILE_FORMAT = 10.0 + + +_plugins: Union[None | List[Any]] = None + + +def _load_plugins() -> Union[None | List[Any]]: + """Lazy load plugins, exiting early if already loaded.""" + global _plugins + + # Skip if we've already loaded plugins + if _plugins is not None: + return _plugins + + # Load plugins + _plugins = [] + for entry_point in entry_points(group="markitdown.plugin"): + try: + _plugins.append(entry_point.load()) + except Exception: + tb = traceback.format_exc() + warn(f"Plugin '{entry_point.name}' failed to load ... skipping:\n{tb}") + + return _plugins + + +class MarkItDown: + """(In preview) An extremely simple text-based document reader, suitable for LLM use. + This reader will convert common file-types or webpages to Markdown.""" + + def __init__( + self, + *, + enable_builtins: Union[None, bool] = None, + enable_plugins: Union[None, bool] = None, + **kwargs, + ): + self._builtins_enabled = False + self._plugins_enabled = False + + requests_session = kwargs.get("requests_session") + if requests_session is None: + self._requests_session = requests.Session() + else: + self._requests_session = requests_session + + # TODO - remove these (see enable_builtins) + self._llm_client = None + self._llm_model = None + self._exiftool_path = None + self._style_map = None + + # Register the converters + self._page_converters: List[DocumentConverter] = [] + + if ( + enable_builtins is None or enable_builtins + ): # Default to True when not specified + self.enable_builtins(**kwargs) + + if enable_plugins: + self.enable_plugins(**kwargs) + + def enable_builtins(self, **kwargs) -> None: + """ + Enable and register built-in converters. + Built-in converters are enabled by default. + This method should only be called once, if built-ins were initially disabled. + """ + if not self._builtins_enabled: + # TODO: Move these into converter constructors + self._llm_client = kwargs.get("llm_client") + self._llm_model = kwargs.get("llm_model") + self._exiftool_path = kwargs.get("exiftool_path") + self._style_map = kwargs.get("style_map") + + # Register converters for successful browsing operations + # Later registrations are tried first / take higher priority than earlier registrations + # To this end, the most specific converters should appear below the most generic converters + self.register_converter(PlainTextConverter()) + self.register_converter(ZipConverter()) + self.register_converter(HtmlConverter()) + self.register_converter(RssConverter()) + self.register_converter(WikipediaConverter()) + self.register_converter(YouTubeConverter()) + self.register_converter(BingSerpConverter()) + self.register_converter(DocxConverter()) + self.register_converter(XlsxConverter()) + self.register_converter(XlsConverter()) + self.register_converter(PptxConverter()) + self.register_converter(WavConverter()) + self.register_converter(Mp3Converter()) + self.register_converter(ImageConverter()) + self.register_converter(IpynbConverter()) + self.register_converter(PdfConverter()) + self.register_converter(OutlookMsgConverter()) + + # Register Document Intelligence converter at the top of the stack if endpoint is provided + docintel_endpoint = kwargs.get("docintel_endpoint") + if docintel_endpoint is not None: + self.register_converter( + DocumentIntelligenceConverter(endpoint=docintel_endpoint) + ) + + self._builtins_enabled = True + else: + warn("Built-in converters are already enabled.", RuntimeWarning) + + def enable_plugins(self, **kwargs) -> None: + """ + Enable and register converters provided by plugins. + Plugins are disabled by default. + This method should only be called once, if plugins were initially disabled. + """ + if not self._plugins_enabled: + # Load plugins + for plugin in _load_plugins(): + try: + plugin.register_converters(self, **kwargs) + except Exception: + tb = traceback.format_exc() + warn(f"Plugin '{plugin}' failed to register converters:\n{tb}") + self._plugins_enabled = True + else: + warn("Plugins converters are already enabled.", RuntimeWarning) + + def convert( + self, source: Union[str, requests.Response, Path], **kwargs: Any + ) -> DocumentConverterResult: # TODO: deal with kwargs + """ + Args: + - source: can be a string representing a path either as string pathlib path object or url, or a requests.response object + - extension: specifies the file extension to use when interpreting the file. If None, infer from source (path, uri, content-type, etc.) + """ + + # Local path or url + if isinstance(source, str): + if ( + source.startswith("http://") + or source.startswith("https://") + or source.startswith("file://") + ): + return self.convert_url(source, **kwargs) + else: + return self.convert_local(source, **kwargs) + # Request response + elif isinstance(source, requests.Response): + return self.convert_response(source, **kwargs) + elif isinstance(source, Path): + return self.convert_local(source, **kwargs) + + def convert_local( + self, path: Union[str, Path], **kwargs: Any + ) -> DocumentConverterResult: # TODO: deal with kwargs + if isinstance(path, Path): + path = str(path) + # Prepare a list of extensions to try (in order of priority) + ext = kwargs.get("file_extension") + extensions = [ext] if ext is not None else [] + + # Get extension alternatives from the path and puremagic + base, ext = os.path.splitext(path) + self._append_ext(extensions, ext) + + for g in self._guess_ext_magic(path): + self._append_ext(extensions, g) + + # Convert + return self._convert(path, extensions, **kwargs) + + # TODO what should stream's type be? + def convert_stream( + self, stream: Any, **kwargs: Any + ) -> DocumentConverterResult: # TODO: deal with kwargs + # Prepare a list of extensions to try (in order of priority) + ext = kwargs.get("file_extension") + extensions = [ext] if ext is not None else [] + + # Save the file locally to a temporary file. It will be deleted before this method exits + handle, temp_path = tempfile.mkstemp() + fh = os.fdopen(handle, "wb") + result = None + try: + # Write to the temporary file + content = stream.read() + if isinstance(content, str): + fh.write(content.encode("utf-8")) + else: + fh.write(content) + fh.close() + + # Use puremagic to check for more extension options + for g in self._guess_ext_magic(temp_path): + self._append_ext(extensions, g) + + # Convert + result = self._convert(temp_path, extensions, **kwargs) + # Clean up + finally: + try: + fh.close() + except Exception: + pass + os.unlink(temp_path) + + return result + + def convert_url( + self, url: str, **kwargs: Any + ) -> DocumentConverterResult: # TODO: fix kwargs type + # Send a HTTP request to the URL + response = self._requests_session.get(url, stream=True) + response.raise_for_status() + return self.convert_response(response, **kwargs) + + def convert_response( + self, response: requests.Response, **kwargs: Any + ) -> DocumentConverterResult: # TODO fix kwargs type + # Prepare a list of extensions to try (in order of priority) + ext = kwargs.get("file_extension") + extensions = [ext] if ext is not None else [] + + # Guess from the mimetype + content_type = response.headers.get("content-type", "").split(";")[0] + self._append_ext(extensions, mimetypes.guess_extension(content_type)) + + # Read the content disposition if there is one + content_disposition = response.headers.get("content-disposition", "") + m = re.search(r"filename=([^;]+)", content_disposition) + if m: + base, ext = os.path.splitext(m.group(1).strip("\"'")) + self._append_ext(extensions, ext) + + # Read from the extension from the path + base, ext = os.path.splitext(urlparse(response.url).path) + self._append_ext(extensions, ext) + + # Save the file locally to a temporary file. It will be deleted before this method exits + handle, temp_path = tempfile.mkstemp() + fh = os.fdopen(handle, "wb") + result = None + try: + # Download the file + for chunk in response.iter_content(chunk_size=512): + fh.write(chunk) + fh.close() + + # Use puremagic to check for more extension options + for g in self._guess_ext_magic(temp_path): + self._append_ext(extensions, g) + + # Convert + result = self._convert(temp_path, extensions, url=response.url, **kwargs) + # Clean up + finally: + try: + fh.close() + except Exception: + pass + os.unlink(temp_path) + + return result + + def _convert( + self, local_path: str, extensions: List[Union[str, None]], **kwargs + ) -> DocumentConverterResult: + error_trace = "" + + # Create a copy of the page_converters list, sorted by priority. + # We do this with each call to _convert because the priority of converters may change between calls. + # The sort is guaranteed to be stable, so converters with the same priority will remain in the same order. + sorted_converters = sorted(self._page_converters, key=lambda x: x.priority) + + for ext in extensions + [None]: # Try last with no extension + for converter in sorted_converters: + _kwargs = copy.deepcopy(kwargs) + + # Overwrite file_extension appropriately + if ext is None: + if "file_extension" in _kwargs: + del _kwargs["file_extension"] + else: + _kwargs.update({"file_extension": ext}) + + # Copy any additional global options + if "llm_client" not in _kwargs and self._llm_client is not None: + _kwargs["llm_client"] = self._llm_client + + if "llm_model" not in _kwargs and self._llm_model is not None: + _kwargs["llm_model"] = self._llm_model + + if "style_map" not in _kwargs and self._style_map is not None: + _kwargs["style_map"] = self._style_map + + if "exiftool_path" not in _kwargs and self._exiftool_path is not None: + _kwargs["exiftool_path"] = self._exiftool_path + + # Add the list of converters for nested processing + _kwargs["_parent_converters"] = self._page_converters + + # If we hit an error log it and keep trying + # try: + if True: + res = converter.convert(local_path, **_kwargs) + # except Exception: + # error_trace = ("\n\n" + traceback.format_exc()).strip() + + if res is not None: + # Normalize the content + res.text_content = "\n".join( + [line.rstrip() for line in re.split(r"\r?\n", res.text_content)] + ) + res.text_content = re.sub(r"\n{3,}", "\n\n", res.text_content) + + # Todo + return res + + # If we got this far without success, report any exceptions + if len(error_trace) > 0: + raise FileConversionException( + f"Could not convert '{local_path}' to Markdown. File type was recognized as {extensions}. While converting the file, the following error was encountered:\n\n{error_trace}" + ) + + # Nothing can handle it! + raise UnsupportedFormatException( + f"Could not convert '{local_path}' to Markdown. The formats {extensions} are not supported." + ) + + def _append_ext(self, extensions, ext): + """Append a unique non-None, non-empty extension to a list of extensions.""" + if ext is None: + return + ext = ext.strip() + if ext == "": + return + # if ext not in extensions: + extensions.append(ext) + + def _guess_ext_magic(self, path): + """Use puremagic (a Python implementation of libmagic) to guess a file's extension based on the first few bytes.""" + # Use puremagic to guess + try: + guesses = puremagic.magic_file(path) + + # Fix for: https://github.com/microsoft/markitdown/issues/222 + # If there are no guesses, then try again after trimming leading ASCII whitespaces. + # ASCII whitespace characters are those byte values in the sequence b' \t\n\r\x0b\f' + # (space, tab, newline, carriage return, vertical tab, form feed). + if len(guesses) == 0: + with open(path, "rb") as file: + while True: + char = file.read(1) + if not char: # End of file + break + if not char.isspace(): + file.seek(file.tell() - 1) + break + try: + guesses = puremagic.magic_stream(file) + except puremagic.main.PureError: + pass + + extensions = list() + for g in guesses: + ext = g.extension.strip() + if len(ext) > 0: + if not ext.startswith("."): + ext = "." + ext + if ext not in extensions: + extensions.append(ext) + return extensions + except FileNotFoundError: + pass + except IsADirectoryError: + pass + except PermissionError: + pass + return [] + + def register_page_converter(self, converter: DocumentConverter) -> None: + """DEPRECATED: User register_converter instead.""" + warn( + "register_page_converter is deprecated. Use register_converter instead.", + DeprecationWarning, + ) + self.register_converter(converter) + + def register_converter(self, converter: DocumentConverter) -> None: + """Register a page text converter.""" + self._page_converters.insert(0, converter) diff --git a/packages/markitdown/src/markitdown/converters/__init__.py b/packages/markitdown/src/markitdown/converters/__init__.py new file mode 100644 index 0000000..1e5afe4 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/__init__.py @@ -0,0 +1,45 @@ +# SPDX-FileCopyrightText: 2024-present Adam Fourney +# +# SPDX-License-Identifier: MIT + +from ._base import DocumentConverter, DocumentConverterResult +from ._plain_text_converter import PlainTextConverter +from ._html_converter import HtmlConverter +from ._rss_converter import RssConverter +from ._wikipedia_converter import WikipediaConverter +from ._youtube_converter import YouTubeConverter +from ._ipynb_converter import IpynbConverter +from ._bing_serp_converter import BingSerpConverter +from ._pdf_converter import PdfConverter +from ._docx_converter import DocxConverter +from ._xlsx_converter import XlsxConverter, XlsConverter +from ._pptx_converter import PptxConverter +from ._image_converter import ImageConverter +from ._wav_converter import WavConverter +from ._mp3_converter import Mp3Converter +from ._outlook_msg_converter import OutlookMsgConverter +from ._zip_converter import ZipConverter +from ._doc_intel_converter import DocumentIntelligenceConverter + +__all__ = [ + "DocumentConverter", + "DocumentConverterResult", + "PlainTextConverter", + "HtmlConverter", + "RssConverter", + "WikipediaConverter", + "YouTubeConverter", + "IpynbConverter", + "BingSerpConverter", + "PdfConverter", + "DocxConverter", + "XlsxConverter", + "XlsConverter", + "PptxConverter", + "ImageConverter", + "WavConverter", + "Mp3Converter", + "OutlookMsgConverter", + "ZipConverter", + "DocumentIntelligenceConverter", +] diff --git a/packages/markitdown/src/markitdown/converters/_base.py b/packages/markitdown/src/markitdown/converters/_base.py new file mode 100644 index 0000000..6d0a5a4 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_base.py @@ -0,0 +1,34 @@ +from typing import Any, Union + + +class DocumentConverterResult: + """The result of converting a document to text.""" + + def __init__(self, title: Union[str, None] = None, text_content: str = ""): + self.title: Union[str, None] = title + self.text_content: str = text_content + + +class DocumentConverter: + """Abstract superclass of all DocumentConverters.""" + + def __init__(self, priority: float = 0.0): + self._priority = priority + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + raise NotImplementedError("Subclasses must implement this method") + + @property + def priority(self) -> float: + """Priority of the converter in markitdown's converter list. Higher priority values are tried first.""" + return self._priority + + @priority.setter + def radius(self, value: float): + self._priority = value + + @priority.deleter + def radius(self): + raise AttributeError("Cannot delete the priority attribute") diff --git a/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py b/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py new file mode 100644 index 0000000..b903724 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py @@ -0,0 +1,81 @@ +# type: ignore +import base64 +import re + +from typing import Union +from urllib.parse import parse_qs, urlparse +from bs4 import BeautifulSoup + +from ._base import DocumentConverter, DocumentConverterResult +from ._markdownify import _CustomMarkdownify + + +class BingSerpConverter(DocumentConverter): + """ + Handle Bing results pages (only the organic search results). + NOTE: It is better to use the Bing API + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a Bing SERP + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".html", ".htm"]: + return None + url = kwargs.get("url", "") + if not re.search(r"^https://www\.bing\.com/search\?q=", url): + return None + + # Parse the query parameters + parsed_params = parse_qs(urlparse(url).query) + query = parsed_params.get("q", [""])[0] + + # Parse the file + soup = None + with open(local_path, "rt", encoding="utf-8") as fh: + soup = BeautifulSoup(fh.read(), "html.parser") + + # Clean up some formatting + for tptt in soup.find_all(class_="tptt"): + if hasattr(tptt, "string") and tptt.string: + tptt.string += " " + for slug in soup.find_all(class_="algoSlug_icon"): + slug.extract() + + # Parse the algorithmic results + _markdownify = _CustomMarkdownify() + results = list() + for result in soup.find_all(class_="b_algo"): + # Rewrite redirect urls + for a in result.find_all("a", href=True): + parsed_href = urlparse(a["href"]) + qs = parse_qs(parsed_href.query) + + # The destination is contained in the u parameter, + # but appears to be base64 encoded, with some prefix + if "u" in qs: + u = ( + qs["u"][0][2:].strip() + "==" + ) # Python 3 doesn't care about extra padding + + try: + # RFC 4648 / Base64URL" variant, which uses "-" and "_" + a["href"] = base64.b64decode(u, altchars="-_").decode("utf-8") + except UnicodeDecodeError: + pass + except binascii.Error: + pass + + # Convert to markdown + md_result = _markdownify.convert_soup(result).strip() + lines = [line.strip() for line in re.split(r"\n+", md_result)] + results.append("\n".join([line for line in lines if len(line) > 0])) + + webpage_text = ( + f"## A Bing search for '{query}' found the following results:\n\n" + + "\n\n".join(results) + ) + + return DocumentConverterResult( + title=None if soup.title is None else soup.title.string, + text_content=webpage_text, + ) diff --git a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py new file mode 100644 index 0000000..94acc9f --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py @@ -0,0 +1,85 @@ +from typing import Any, Union + +# Azure imports +from azure.ai.documentintelligence import DocumentIntelligenceClient +from azure.ai.documentintelligence.models import ( + AnalyzeDocumentRequest, + AnalyzeResult, + DocumentAnalysisFeature, +) +from azure.identity import DefaultAzureCredential + +from ._base import DocumentConverter, DocumentConverterResult + + +# TODO: currently, there is a bug in the document intelligence SDK with importing the "ContentFormat" enum. +# This constant is a temporary fix until the bug is resolved. +CONTENT_FORMAT = "markdown" + + +class DocumentIntelligenceConverter(DocumentConverter): + """Specialized DocumentConverter that uses Document Intelligence to extract text from documents.""" + + def __init__( + self, + endpoint: str, + api_version: str = "2024-07-31-preview", + ): + self.endpoint = endpoint + self.api_version = api_version + self.doc_intel_client = DocumentIntelligenceClient( + endpoint=self.endpoint, + api_version=self.api_version, + credential=DefaultAzureCredential(), + ) + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + # Bail if extension is not supported by Document Intelligence + extension = kwargs.get("file_extension", "") + docintel_extensions = [ + ".pdf", + ".docx", + ".xlsx", + ".pptx", + ".html", + ".jpeg", + ".jpg", + ".png", + ".bmp", + ".tiff", + ".heif", + ] + if extension.lower() not in docintel_extensions: + return None + + # Get the bytestring for the local path + with open(local_path, "rb") as f: + file_bytes = f.read() + + # Certain document analysis features are not availiable for filetypes (.xlsx, .pptx, .html) + if extension.lower() in [".xlsx", ".pptx", ".html"]: + analysis_features = [] + else: + analysis_features = [ + DocumentAnalysisFeature.FORMULAS, # enable formula extraction + DocumentAnalysisFeature.OCR_HIGH_RESOLUTION, # enable high resolution OCR + DocumentAnalysisFeature.STYLE_FONT, # enable font style extraction + ] + + # Extract the text using Azure Document Intelligence + poller = self.doc_intel_client.begin_analyze_document( + model_id="prebuilt-layout", + body=AnalyzeDocumentRequest(bytes_source=file_bytes), + features=analysis_features, + output_content_format=CONTENT_FORMAT, # TODO: replace with "ContentFormat.MARKDOWN" when the bug is fixed + ) + result: AnalyzeResult = poller.result() + + # remove comments from the markdown content generated by Doc Intelligence and append to markdown string + markdown_text = re.sub(r"", "", result.content, flags=re.DOTALL) + return DocumentConverterResult( + title=None, + text_content=markdown_text, + ) diff --git a/packages/markitdown/src/markitdown/converters/_docx_converter.py b/packages/markitdown/src/markitdown/converters/_docx_converter.py new file mode 100644 index 0000000..fb61cca --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_docx_converter.py @@ -0,0 +1,31 @@ +from typing import Union + +import mammoth + +from ._base import ( + DocumentConverterResult, +) + +from ._html_converter import HtmlConverter + + +class DocxConverter(HtmlConverter): + """ + Converts DOCX files to Markdown. Style information (e.g.m headings) and tables are preserved where possible. + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a DOCX + extension = kwargs.get("file_extension", "") + if extension.lower() != ".docx": + return None + + result = None + with open(local_path, "rb") as docx_file: + style_map = kwargs.get("style_map", None) + + result = mammoth.convert_to_html(docx_file, style_map=style_map) + html_content = result.value + result = self._convert(html_content) + + return result diff --git a/packages/markitdown/src/markitdown/converters/_html_converter.py b/packages/markitdown/src/markitdown/converters/_html_converter.py new file mode 100644 index 0000000..ae7259e --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_html_converter.py @@ -0,0 +1,51 @@ +from typing import Any, Union +from bs4 import BeautifulSoup + +from ._base import DocumentConverter, DocumentConverterResult +from ._markdownify import _CustomMarkdownify + + +class HtmlConverter(DocumentConverter): + """Anything with content type text/html""" + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + # Bail if not html + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".html", ".htm"]: + return None + + result = None + with open(local_path, "rt", encoding="utf-8") as fh: + result = self._convert(fh.read()) + + return result + + def _convert(self, html_content: str) -> Union[None, DocumentConverterResult]: + """Helper function that converts an HTML string.""" + + # Parse the string + soup = BeautifulSoup(html_content, "html.parser") + + # Remove javascript and style blocks + for script in soup(["script", "style"]): + script.extract() + + # Print only the main content + body_elm = soup.find("body") + webpage_text = "" + if body_elm: + webpage_text = _CustomMarkdownify().convert_soup(body_elm) + else: + webpage_text = _CustomMarkdownify().convert_soup(soup) + + assert isinstance(webpage_text, str) + + # remove leading and trailing \n + webpage_text = webpage_text.strip() + + return DocumentConverterResult( + title=None if soup.title is None else soup.title.string, + text_content=webpage_text, + ) diff --git a/packages/markitdown/src/markitdown/converters/_image_converter.py b/packages/markitdown/src/markitdown/converters/_image_converter.py new file mode 100644 index 0000000..f3dee6b --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_image_converter.py @@ -0,0 +1,87 @@ +from typing import Union +from ._base import DocumentConverterResult +from ._media_converter import MediaConverter + + +class ImageConverter(MediaConverter): + """ + Converts images to markdown via extraction of metadata (if `exiftool` is installed), OCR (if `easyocr` is installed), and description via a multimodal LLM (if an llm_client is configured). + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not an image + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".jpg", ".jpeg", ".png"]: + return None + + md_content = "" + + # Add metadata + metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) + + if metadata: + for f in [ + "ImageSize", + "Title", + "Caption", + "Description", + "Keywords", + "Artist", + "Author", + "DateTimeOriginal", + "CreateDate", + "GPSPosition", + ]: + if f in metadata: + md_content += f"{f}: {metadata[f]}\n" + + # Try describing the image with GPTV + llm_client = kwargs.get("llm_client") + llm_model = kwargs.get("llm_model") + if llm_client is not None and llm_model is not None: + md_content += ( + "\n# Description:\n" + + self._get_llm_description( + local_path, + extension, + llm_client, + llm_model, + prompt=kwargs.get("llm_prompt"), + ).strip() + + "\n" + ) + + return DocumentConverterResult( + title=None, + text_content=md_content, + ) + + def _get_llm_description(self, local_path, extension, client, model, prompt=None): + if prompt is None or prompt.strip() == "": + prompt = "Write a detailed caption for this image." + + data_uri = "" + with open(local_path, "rb") as image_file: + content_type, encoding = mimetypes.guess_type("_dummy" + extension) + if content_type is None: + content_type = "image/jpeg" + image_base64 = base64.b64encode(image_file.read()).decode("utf-8") + data_uri = f"data:{content_type};base64,{image_base64}" + + messages = [ + { + "role": "user", + "content": [ + {"type": "text", "text": prompt}, + { + "type": "image_url", + "image_url": { + "url": data_uri, + }, + }, + ], + } + ] + + response = client.chat.completions.create(model=model, messages=messages) + return response.choices[0].message.content diff --git a/packages/markitdown/src/markitdown/converters/_ipynb_converter.py b/packages/markitdown/src/markitdown/converters/_ipynb_converter.py new file mode 100644 index 0000000..cdeb478 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_ipynb_converter.py @@ -0,0 +1,70 @@ +import json +from typing import Any, Union + +from ._base import ( + DocumentConverter, + DocumentConverterResult, +) + +from .._exceptions import FileConversionException + + +class IpynbConverter(DocumentConverter): + """Converts Jupyter Notebook (.ipynb) files to Markdown.""" + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + # Bail if not ipynb + extension = kwargs.get("file_extension", "") + if extension.lower() != ".ipynb": + return None + + # Parse and convert the notebook + result = None + with open(local_path, "rt", encoding="utf-8") as fh: + notebook_content = json.load(fh) + result = self._convert(notebook_content) + + return result + + def _convert(self, notebook_content: dict) -> Union[None, DocumentConverterResult]: + """Helper function that converts notebook JSON content to Markdown.""" + try: + md_output = [] + title = None + + for cell in notebook_content.get("cells", []): + cell_type = cell.get("cell_type", "") + source_lines = cell.get("source", []) + + if cell_type == "markdown": + md_output.append("".join(source_lines)) + + # Extract the first # heading as title if not already found + if title is None: + for line in source_lines: + if line.startswith("# "): + title = line.lstrip("# ").strip() + break + + elif cell_type == "code": + # Code cells are wrapped in Markdown code blocks + md_output.append(f"```python\n{''.join(source_lines)}\n```") + elif cell_type == "raw": + md_output.append(f"```\n{''.join(source_lines)}\n```") + + md_text = "\n\n".join(md_output) + + # Check for title in notebook metadata + title = notebook_content.get("metadata", {}).get("title", title) + + return DocumentConverterResult( + title=title, + text_content=md_text, + ) + + except Exception as e: + raise FileConversionException( + f"Error converting .ipynb file: {str(e)}" + ) from e diff --git a/packages/markitdown/src/markitdown/converters/_markdownify.py b/packages/markitdown/src/markitdown/converters/_markdownify.py new file mode 100644 index 0000000..5b6d739 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_markdownify.py @@ -0,0 +1,87 @@ +import re +import markdownify + +from typing import Any +from urllib.parse import quote, unquote, urlparse, urlunparse + + +class _CustomMarkdownify(markdownify.MarkdownConverter): + """ + A custom version of markdownify's MarkdownConverter. Changes include: + + - Altering the default heading style to use '#', '##', etc. + - Removing javascript hyperlinks. + - Truncating images with large data:uri sources. + - Ensuring URIs are properly escaped, and do not conflict with Markdown syntax + """ + + def __init__(self, **options: Any): + options["heading_style"] = options.get("heading_style", markdownify.ATX) + # Explicitly cast options to the expected type if necessary + super().__init__(**options) + + def convert_hn(self, n: int, el: Any, text: str, convert_as_inline: bool) -> str: + """Same as usual, but be sure to start with a new line""" + if not convert_as_inline: + if not re.search(r"^\n", text): + return "\n" + super().convert_hn(n, el, text, convert_as_inline) # type: ignore + + return super().convert_hn(n, el, text, convert_as_inline) # type: ignore + + def convert_a(self, el: Any, text: str, convert_as_inline: bool): + """Same as usual converter, but removes Javascript links and escapes URIs.""" + prefix, suffix, text = markdownify.chomp(text) # type: ignore + if not text: + return "" + href = el.get("href") + title = el.get("title") + + # Escape URIs and skip non-http or file schemes + if href: + try: + parsed_url = urlparse(href) # type: ignore + if parsed_url.scheme and parsed_url.scheme.lower() not in ["http", "https", "file"]: # type: ignore + return "%s%s%s" % (prefix, text, suffix) + href = urlunparse(parsed_url._replace(path=quote(unquote(parsed_url.path)))) # type: ignore + except ValueError: # It's not clear if this ever gets thrown + return "%s%s%s" % (prefix, text, suffix) + + # For the replacement see #29: text nodes underscores are escaped + if ( + self.options["autolinks"] + and text.replace(r"\_", "_") == href + and not title + and not self.options["default_title"] + ): + # Shortcut syntax + return "<%s>" % href + if self.options["default_title"] and not title: + title = href + title_part = ' "%s"' % title.replace('"', r"\"") if title else "" + return ( + "%s[%s](%s%s)%s" % (prefix, text, href, title_part, suffix) + if href + else text + ) + + def convert_img(self, el: Any, text: str, convert_as_inline: bool) -> str: + """Same as usual converter, but removes data URIs""" + + alt = el.attrs.get("alt", None) or "" + src = el.attrs.get("src", None) or "" + title = el.attrs.get("title", None) or "" + title_part = ' "%s"' % title.replace('"', r"\"") if title else "" + if ( + convert_as_inline + and el.parent.name not in self.options["keep_inline_images_in"] + ): + return alt + + # Remove dataURIs + if src.startswith("data:"): + src = src.split(",")[0] + "..." + + return "![%s](%s%s)" % (alt, src, title_part) + + def convert_soup(self, soup: Any) -> str: + return super().convert_soup(soup) # type: ignore diff --git a/packages/markitdown/src/markitdown/converters/_media_converter.py b/packages/markitdown/src/markitdown/converters/_media_converter.py new file mode 100644 index 0000000..07d2bde --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_media_converter.py @@ -0,0 +1,36 @@ +import subprocess +import shutil +import json +from warnings import warn + +from ._base import DocumentConverter + + +class MediaConverter(DocumentConverter): + """ + Abstract class for multi-modal media (e.g., images and audio) + """ + + def _get_metadata(self, local_path, exiftool_path=None): + if not exiftool_path: + which_exiftool = shutil.which("exiftool") + if which_exiftool: + warn( + f"""Implicit discovery of 'exiftool' is disabled. If you would like to continue to use exiftool in MarkItDown, please set the exiftool_path parameter in the MarkItDown consructor. E.g., + + md = MarkItDown(exiftool_path="{which_exiftool}") + +This warning will be removed in future releases. +""", + DeprecationWarning, + ) + + return None + else: + try: + result = subprocess.run( + [exiftool_path, "-json", local_path], capture_output=True, text=True + ).stdout + return json.loads(result)[0] + except Exception: + return None diff --git a/packages/markitdown/src/markitdown/converters/_mp3_converter.py b/packages/markitdown/src/markitdown/converters/_mp3_converter.py new file mode 100644 index 0000000..6b2786b --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_mp3_converter.py @@ -0,0 +1,84 @@ +import tempfile +from typing import Union +from ._base import DocumentConverterResult +from ._wav_converter import WavConverter +from warnings import resetwarnings, catch_warnings + +# Optional Transcription support +IS_AUDIO_TRANSCRIPTION_CAPABLE = False +try: + # Using warnings' catch_warnings to catch + # pydub's warning of ffmpeg or avconv missing + with catch_warnings(record=True) as w: + import pydub + + if w: + raise ModuleNotFoundError + import speech_recognition as sr + + IS_AUDIO_TRANSCRIPTION_CAPABLE = True +except ModuleNotFoundError: + pass +finally: + resetwarnings() + + +class Mp3Converter(WavConverter): + """ + Converts MP3 files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` AND `pydub` are installed). + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a MP3 + extension = kwargs.get("file_extension", "") + if extension.lower() != ".mp3": + return None + + md_content = "" + + # Add metadata + metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) + if metadata: + for f in [ + "Title", + "Artist", + "Author", + "Band", + "Album", + "Genre", + "Track", + "DateTimeOriginal", + "CreateDate", + "Duration", + ]: + if f in metadata: + md_content += f"{f}: {metadata[f]}\n" + + # Transcribe + if IS_AUDIO_TRANSCRIPTION_CAPABLE: + handle, temp_path = tempfile.mkstemp(suffix=".wav") + os.close(handle) + try: + sound = pydub.AudioSegment.from_mp3(local_path) + sound.export(temp_path, format="wav") + + _args = dict() + _args.update(kwargs) + _args["file_extension"] = ".wav" + + try: + transcript = super()._transcribe_audio(temp_path).strip() + md_content += "\n\n### Audio Transcript:\n" + ( + "[No speech detected]" if transcript == "" else transcript + ) + except Exception: + md_content += "\n\n### Audio Transcript:\nError. Could not transcribe this audio." + + finally: + os.unlink(temp_path) + + # Return the result + return DocumentConverterResult( + title=None, + text_content=md_content.strip(), + ) diff --git a/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py b/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py new file mode 100644 index 0000000..e83001c --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py @@ -0,0 +1,76 @@ +import olefile +from typing import Any, Union +from ._base import DocumentConverter, DocumentConverterResult + + +class OutlookMsgConverter(DocumentConverter): + """Converts Outlook .msg files to markdown by extracting email metadata and content. + + Uses the olefile package to parse the .msg file structure and extract: + - Email headers (From, To, Subject) + - Email body content + """ + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + # Bail if not a MSG file + extension = kwargs.get("file_extension", "") + if extension.lower() != ".msg": + return None + + try: + msg = olefile.OleFileIO(local_path) + # Extract email metadata + md_content = "# Email Message\n\n" + + # Get headers + headers = { + "From": self._get_stream_data(msg, "__substg1.0_0C1F001F"), + "To": self._get_stream_data(msg, "__substg1.0_0E04001F"), + "Subject": self._get_stream_data(msg, "__substg1.0_0037001F"), + } + + # Add headers to markdown + for key, value in headers.items(): + if value: + md_content += f"**{key}:** {value}\n" + + md_content += "\n## Content\n\n" + + # Get email body + body = self._get_stream_data(msg, "__substg1.0_1000001F") + if body: + md_content += body + + msg.close() + + return DocumentConverterResult( + title=headers.get("Subject"), text_content=md_content.strip() + ) + + except Exception as e: + raise FileConversionException( + f"Could not convert MSG file '{local_path}': {str(e)}" + ) + + def _get_stream_data( + self, msg: olefile.OleFileIO, stream_path: str + ) -> Union[str, None]: + """Helper to safely extract and decode stream data from the MSG file.""" + try: + if msg.exists(stream_path): + data = msg.openstream(stream_path).read() + # Try UTF-16 first (common for .msg files) + try: + return data.decode("utf-16-le").strip() + except UnicodeDecodeError: + # Fall back to UTF-8 + try: + return data.decode("utf-8").strip() + except UnicodeDecodeError: + # Last resort - ignore errors + return data.decode("utf-8", errors="ignore").strip() + except Exception: + pass + return None diff --git a/packages/markitdown/src/markitdown/converters/_pdf_converter.py b/packages/markitdown/src/markitdown/converters/_pdf_converter.py new file mode 100644 index 0000000..dcffc62 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_pdf_converter.py @@ -0,0 +1,21 @@ +import pdfminer +import pdfminer.high_level +from typing import Union +from ._base import DocumentConverter, DocumentConverterResult + + +class PdfConverter(DocumentConverter): + """ + Converts PDFs to Markdown. Most style information is ignored, so the results are essentially plain-text. + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a PDF + extension = kwargs.get("file_extension", "") + if extension.lower() != ".pdf": + return None + + return DocumentConverterResult( + title=None, + text_content=pdfminer.high_level.extract_text(local_path), + ) diff --git a/packages/markitdown/src/markitdown/converters/_plain_text_converter.py b/packages/markitdown/src/markitdown/converters/_plain_text_converter.py new file mode 100644 index 0000000..2912d24 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_plain_text_converter.py @@ -0,0 +1,33 @@ +import mimetypes + +from charset_normalizer import from_path +from typing import Any, Union + +from ._base import DocumentConverter, DocumentConverterResult + + +class PlainTextConverter(DocumentConverter): + """Anything with content type text/plain""" + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + # Guess the content type from any file extension that might be around + content_type, _ = mimetypes.guess_type( + "__placeholder" + kwargs.get("file_extension", "") + ) + + # Only accept text files + if content_type is None: + return None + elif all( + not content_type.lower().startswith(type_prefix) + for type_prefix in ["text/", "application/json"] + ): + return None + + text_content = str(from_path(local_path).best()) + return DocumentConverterResult( + title=None, + text_content=text_content, + ) diff --git a/packages/markitdown/src/markitdown/converters/_pptx_converter.py b/packages/markitdown/src/markitdown/converters/_pptx_converter.py new file mode 100644 index 0000000..a48880a --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_pptx_converter.py @@ -0,0 +1,180 @@ +import base64 +import pptx +import re +import html + +from typing import Union + +from ._base import DocumentConverterResult, DocumentConverter +from ._html_converter import HtmlConverter + + +class PptxConverter(HtmlConverter): + """ + Converts PPTX files to Markdown. Supports heading, tables and images with alt text. + """ + + def _get_llm_description( + self, llm_client, llm_model, image_blob, content_type, prompt=None + ): + if prompt is None or prompt.strip() == "": + prompt = "Write a detailed alt text for this image with less than 50 words." + + image_base64 = base64.b64encode(image_blob).decode("utf-8") + data_uri = f"data:{content_type};base64,{image_base64}" + + messages = [ + { + "role": "user", + "content": [ + { + "type": "image_url", + "image_url": { + "url": data_uri, + }, + }, + {"type": "text", "text": prompt}, + ], + } + ] + + response = llm_client.chat.completions.create( + model=llm_model, messages=messages + ) + return response.choices[0].message.content + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a PPTX + extension = kwargs.get("file_extension", "") + if extension.lower() != ".pptx": + return None + + md_content = "" + + presentation = pptx.Presentation(local_path) + slide_num = 0 + for slide in presentation.slides: + slide_num += 1 + + md_content += f"\n\n\n" + + title = slide.shapes.title + for shape in slide.shapes: + # Pictures + if self._is_picture(shape): + # https://github.com/scanny/python-pptx/pull/512#issuecomment-1713100069 + + llm_description = None + alt_text = None + + llm_client = kwargs.get("llm_client") + llm_model = kwargs.get("llm_model") + if llm_client is not None and llm_model is not None: + try: + llm_description = self._get_llm_description( + llm_client, + llm_model, + shape.image.blob, + shape.image.content_type, + ) + except Exception: + # Unable to describe with LLM + pass + + if not llm_description: + try: + alt_text = shape._element._nvXxPr.cNvPr.attrib.get( + "descr", "" + ) + except Exception: + # Unable to get alt text + pass + + # A placeholder name + filename = re.sub(r"\W", "", shape.name) + ".jpg" + md_content += ( + "\n![" + + (llm_description or alt_text or shape.name) + + "](" + + filename + + ")\n" + ) + + # Tables + if self._is_table(shape): + html_table = "" + first_row = True + for row in shape.table.rows: + html_table += "" + for cell in row.cells: + if first_row: + html_table += "" + else: + html_table += "" + html_table += "" + first_row = False + html_table += "
" + html.escape(cell.text) + "" + html.escape(cell.text) + "
" + md_content += ( + "\n" + self._convert(html_table).text_content.strip() + "\n" + ) + + # Charts + if shape.has_chart: + md_content += self._convert_chart_to_markdown(shape.chart) + + # Text areas + elif shape.has_text_frame: + if shape == title: + md_content += "# " + shape.text.lstrip() + "\n" + else: + md_content += shape.text + "\n" + + md_content = md_content.strip() + + if slide.has_notes_slide: + md_content += "\n\n### Notes:\n" + notes_frame = slide.notes_slide.notes_text_frame + if notes_frame is not None: + md_content += notes_frame.text + md_content = md_content.strip() + + return DocumentConverterResult( + title=None, + text_content=md_content.strip(), + ) + + def _is_picture(self, shape): + if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.PICTURE: + return True + if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.PLACEHOLDER: + if hasattr(shape, "image"): + return True + return False + + def _is_table(self, shape): + if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.TABLE: + return True + return False + + def _convert_chart_to_markdown(self, chart): + md = "\n\n### Chart" + if chart.has_title: + md += f": {chart.chart_title.text_frame.text}" + md += "\n\n" + data = [] + category_names = [c.label for c in chart.plots[0].categories] + series_names = [s.name for s in chart.series] + data.append(["Category"] + series_names) + + for idx, category in enumerate(category_names): + row = [category] + for series in chart.series: + row.append(series.values[idx]) + data.append(row) + + markdown_table = [] + for row in data: + markdown_table.append("| " + " | ".join(map(str, row)) + " |") + header = markdown_table[0] + separator = "|" + "|".join(["---"] * len(data[0])) + "|" + return md + "\n".join([header, separator] + markdown_table[1:]) diff --git a/packages/markitdown/src/markitdown/converters/_rss_converter.py b/packages/markitdown/src/markitdown/converters/_rss_converter.py new file mode 100644 index 0000000..eb2f09c --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_rss_converter.py @@ -0,0 +1,143 @@ +from xml.dom import minidom +from typing import Union +from bs4 import BeautifulSoup + +from ._markdownify import _CustomMarkdownify +from ._base import DocumentConverter, DocumentConverterResult + + +class RssConverter(DocumentConverter): + """Convert RSS / Atom type to markdown""" + + def convert( + self, local_path: str, **kwargs + ) -> Union[None, DocumentConverterResult]: + # Bail if not RSS type + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".xml", ".rss", ".atom"]: + return None + try: + doc = minidom.parse(local_path) + except BaseException as _: + return None + result = None + if doc.getElementsByTagName("rss"): + # A RSS feed must have a root element of + result = self._parse_rss_type(doc) + elif doc.getElementsByTagName("feed"): + root = doc.getElementsByTagName("feed")[0] + if root.getElementsByTagName("entry"): + # An Atom feed must have a root element of and at least one + result = self._parse_atom_type(doc) + else: + return None + else: + # not rss or atom + return None + + return result + + def _parse_atom_type( + self, doc: minidom.Document + ) -> Union[None, DocumentConverterResult]: + """Parse the type of an Atom feed. + + Returns None if the feed type is not recognized or something goes wrong. + """ + try: + root = doc.getElementsByTagName("feed")[0] + title = self._get_data_by_tag_name(root, "title") + subtitle = self._get_data_by_tag_name(root, "subtitle") + entries = root.getElementsByTagName("entry") + md_text = f"# {title}\n" + if subtitle: + md_text += f"{subtitle}\n" + for entry in entries: + entry_title = self._get_data_by_tag_name(entry, "title") + entry_summary = self._get_data_by_tag_name(entry, "summary") + entry_updated = self._get_data_by_tag_name(entry, "updated") + entry_content = self._get_data_by_tag_name(entry, "content") + + if entry_title: + md_text += f"\n## {entry_title}\n" + if entry_updated: + md_text += f"Updated on: {entry_updated}\n" + if entry_summary: + md_text += self._parse_content(entry_summary) + if entry_content: + md_text += self._parse_content(entry_content) + + return DocumentConverterResult( + title=title, + text_content=md_text, + ) + except BaseException as _: + return None + + def _parse_rss_type( + self, doc: minidom.Document + ) -> Union[None, DocumentConverterResult]: + """Parse the type of an RSS feed. + + Returns None if the feed type is not recognized or something goes wrong. + """ + try: + root = doc.getElementsByTagName("rss")[0] + channel = root.getElementsByTagName("channel") + if not channel: + return None + channel = channel[0] + channel_title = self._get_data_by_tag_name(channel, "title") + channel_description = self._get_data_by_tag_name(channel, "description") + items = channel.getElementsByTagName("item") + if channel_title: + md_text = f"# {channel_title}\n" + if channel_description: + md_text += f"{channel_description}\n" + if not items: + items = [] + for item in items: + title = self._get_data_by_tag_name(item, "title") + description = self._get_data_by_tag_name(item, "description") + pubDate = self._get_data_by_tag_name(item, "pubDate") + content = self._get_data_by_tag_name(item, "content:encoded") + + if title: + md_text += f"\n## {title}\n" + if pubDate: + md_text += f"Published on: {pubDate}\n" + if description: + md_text += self._parse_content(description) + if content: + md_text += self._parse_content(content) + + return DocumentConverterResult( + title=channel_title, + text_content=md_text, + ) + except BaseException as _: + print(traceback.format_exc()) + return None + + def _parse_content(self, content: str) -> str: + """Parse the content of an RSS feed item""" + try: + # using bs4 because many RSS feeds have HTML-styled content + soup = BeautifulSoup(content, "html.parser") + return _CustomMarkdownify().convert_soup(soup) + except BaseException as _: + return content + + def _get_data_by_tag_name( + self, element: minidom.Element, tag_name: str + ) -> Union[str, None]: + """Get data from first child element with the given tag name. + Returns None when no such element is found. + """ + nodes = element.getElementsByTagName(tag_name) + if not nodes: + return None + fc = nodes[0].firstChild + if fc: + return fc.data + return None diff --git a/packages/markitdown/src/markitdown/converters/_wav_converter.py b/packages/markitdown/src/markitdown/converters/_wav_converter.py new file mode 100644 index 0000000..6fc8932 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_wav_converter.py @@ -0,0 +1,67 @@ +from typing import Union +from ._base import DocumentConverterResult +from ._media_converter import MediaConverter + +# Optional Transcription support +IS_AUDIO_TRANSCRIPTION_CAPABLE = False +try: + import speech_recognition as sr + + IS_AUDIO_TRANSCRIPTION_CAPABLE = True +except ModuleNotFoundError: + pass + + +class WavConverter(MediaConverter): + """ + Converts WAV files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` is installed). + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a WAV + extension = kwargs.get("file_extension", "") + if extension.lower() != ".wav": + return None + + md_content = "" + + # Add metadata + metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) + if metadata: + for f in [ + "Title", + "Artist", + "Author", + "Band", + "Album", + "Genre", + "Track", + "DateTimeOriginal", + "CreateDate", + "Duration", + ]: + if f in metadata: + md_content += f"{f}: {metadata[f]}\n" + + # Transcribe + if IS_AUDIO_TRANSCRIPTION_CAPABLE: + try: + transcript = self._transcribe_audio(local_path) + md_content += "\n\n### Audio Transcript:\n" + ( + "[No speech detected]" if transcript == "" else transcript + ) + except Exception: + md_content += ( + "\n\n### Audio Transcript:\nError. Could not transcribe this audio." + ) + + return DocumentConverterResult( + title=None, + text_content=md_content.strip(), + ) + + def _transcribe_audio(self, local_path) -> str: + recognizer = sr.Recognizer() + with sr.AudioFile(local_path) as source: + audio = recognizer.record(source) + return recognizer.recognize_google(audio).strip() diff --git a/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py b/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py new file mode 100644 index 0000000..4097ef0 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py @@ -0,0 +1,56 @@ +import re + +from typing import Any, Union +from bs4 import BeautifulSoup + +from ._base import DocumentConverter, DocumentConverterResult +from ._markdownify import _CustomMarkdownify + + +class WikipediaConverter(DocumentConverter): + """Handle Wikipedia pages separately, focusing only on the main document content.""" + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + # Bail if not Wikipedia + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".html", ".htm"]: + return None + url = kwargs.get("url", "") + if not re.search(r"^https?:\/\/[a-zA-Z]{2,3}\.wikipedia.org\/", url): + return None + + # Parse the file + soup = None + with open(local_path, "rt", encoding="utf-8") as fh: + soup = BeautifulSoup(fh.read(), "html.parser") + + # Remove javascript and style blocks + for script in soup(["script", "style"]): + script.extract() + + # Print only the main content + body_elm = soup.find("div", {"id": "mw-content-text"}) + title_elm = soup.find("span", {"class": "mw-page-title-main"}) + + webpage_text = "" + main_title = None if soup.title is None else soup.title.string + + if body_elm: + # What's the title + if title_elm and len(title_elm) > 0: + main_title = title_elm.string # type: ignore + assert isinstance(main_title, str) + + # Convert the page + webpage_text = f"# {main_title}\n\n" + _CustomMarkdownify().convert_soup( + body_elm + ) + else: + webpage_text = _CustomMarkdownify().convert_soup(soup) + + return DocumentConverterResult( + title=main_title, + text_content=webpage_text, + ) diff --git a/packages/markitdown/src/markitdown/converters/_xlsx_converter.py b/packages/markitdown/src/markitdown/converters/_xlsx_converter.py new file mode 100644 index 0000000..683349c --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_xlsx_converter.py @@ -0,0 +1,54 @@ +from typing import Union + +import pandas as pd + +from ._base import DocumentConverterResult +from ._html_converter import HtmlConverter + + +class XlsxConverter(HtmlConverter): + """ + Converts XLSX files to Markdown, with each sheet presented as a separate Markdown table. + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a XLSX + extension = kwargs.get("file_extension", "") + if extension.lower() != ".xlsx": + return None + + sheets = pd.read_excel(local_path, sheet_name=None, engine="openpyxl") + md_content = "" + for s in sheets: + md_content += f"## {s}\n" + html_content = sheets[s].to_html(index=False) + md_content += self._convert(html_content).text_content.strip() + "\n\n" + + return DocumentConverterResult( + title=None, + text_content=md_content.strip(), + ) + + +class XlsConverter(HtmlConverter): + """ + Converts XLS files to Markdown, with each sheet presented as a separate Markdown table. + """ + + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: + # Bail if not a XLS + extension = kwargs.get("file_extension", "") + if extension.lower() != ".xls": + return None + + sheets = pd.read_excel(local_path, sheet_name=None, engine="xlrd") + md_content = "" + for s in sheets: + md_content += f"## {s}\n" + html_content = sheets[s].to_html(index=False) + md_content += self._convert(html_content).text_content.strip() + "\n\n" + + return DocumentConverterResult( + title=None, + text_content=md_content.strip(), + ) diff --git a/packages/markitdown/src/markitdown/converters/_youtube_converter.py b/packages/markitdown/src/markitdown/converters/_youtube_converter.py new file mode 100644 index 0000000..fe198e8 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_youtube_converter.py @@ -0,0 +1,148 @@ +import re + +from typing import Any, Union, Dict, List +from urllib.parse import parse_qs, urlparse +from bs4 import BeautifulSoup + +from ._base import DocumentConverter, DocumentConverterResult + + +# Optional YouTube transcription support +try: + from youtube_transcript_api import YouTubeTranscriptApi + + IS_YOUTUBE_TRANSCRIPT_CAPABLE = True +except ModuleNotFoundError: + pass + + +class YouTubeConverter(DocumentConverter): + """Handle YouTube specially, focusing on the video title, description, and transcript.""" + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + # Bail if not YouTube + extension = kwargs.get("file_extension", "") + if extension.lower() not in [".html", ".htm"]: + return None + url = kwargs.get("url", "") + if not url.startswith("https://www.youtube.com/watch?"): + return None + + # Parse the file + soup = None + with open(local_path, "rt", encoding="utf-8") as fh: + soup = BeautifulSoup(fh.read(), "html.parser") + + # Read the meta tags + assert soup.title is not None and soup.title.string is not None + metadata: Dict[str, str] = {"title": soup.title.string} + for meta in soup(["meta"]): + for a in meta.attrs: + if a in ["itemprop", "property", "name"]: + metadata[meta[a]] = meta.get("content", "") + break + + # We can also try to read the full description. This is more prone to breaking, since it reaches into the page implementation + try: + for script in soup(["script"]): + content = script.text + if "ytInitialData" in content: + lines = re.split(r"\r?\n", content) + obj_start = lines[0].find("{") + obj_end = lines[0].rfind("}") + if obj_start >= 0 and obj_end >= 0: + data = json.loads(lines[0][obj_start : obj_end + 1]) + attrdesc = self._findKey(data, "attributedDescriptionBodyText") # type: ignore + if attrdesc: + metadata["description"] = str(attrdesc["content"]) + break + except Exception: + pass + + # Start preparing the page + webpage_text = "# YouTube\n" + + title = self._get(metadata, ["title", "og:title", "name"]) # type: ignore + assert isinstance(title, str) + + if title: + webpage_text += f"\n## {title}\n" + + stats = "" + views = self._get(metadata, ["interactionCount"]) # type: ignore + if views: + stats += f"- **Views:** {views}\n" + + keywords = self._get(metadata, ["keywords"]) # type: ignore + if keywords: + stats += f"- **Keywords:** {keywords}\n" + + runtime = self._get(metadata, ["duration"]) # type: ignore + if runtime: + stats += f"- **Runtime:** {runtime}\n" + + if len(stats) > 0: + webpage_text += f"\n### Video Metadata\n{stats}\n" + + description = self._get(metadata, ["description", "og:description"]) # type: ignore + if description: + webpage_text += f"\n### Description\n{description}\n" + + if IS_YOUTUBE_TRANSCRIPT_CAPABLE: + transcript_text = "" + parsed_url = urlparse(url) # type: ignore + params = parse_qs(parsed_url.query) # type: ignore + if "v" in params: + assert isinstance(params["v"][0], str) + video_id = str(params["v"][0]) + try: + youtube_transcript_languages = kwargs.get( + "youtube_transcript_languages", ("en",) + ) + # Must be a single transcript. + transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=youtube_transcript_languages) # type: ignore + transcript_text = " ".join([part["text"] for part in transcript]) # type: ignore + # Alternative formatting: + # formatter = TextFormatter() + # formatter.format_transcript(transcript) + except Exception: + pass + if transcript_text: + webpage_text += f"\n### Transcript\n{transcript_text}\n" + + title = title if title else soup.title.string + assert isinstance(title, str) + + return DocumentConverterResult( + title=title, + text_content=webpage_text, + ) + + def _get( + self, + metadata: Dict[str, str], + keys: List[str], + default: Union[str, None] = None, + ) -> Union[str, None]: + for k in keys: + if k in metadata: + return metadata[k] + return default + + def _findKey(self, json: Any, key: str) -> Union[str, None]: # TODO: Fix json type + if isinstance(json, list): + for elm in json: + ret = self._findKey(elm, key) + if ret is not None: + return ret + elif isinstance(json, dict): + for k in json: + if k == key: + return json[k] + else: + ret = self._findKey(json[k], key) + if ret is not None: + return ret + return None diff --git a/packages/markitdown/src/markitdown/converters/_zip_converter.py b/packages/markitdown/src/markitdown/converters/_zip_converter.py new file mode 100644 index 0000000..918c357 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_zip_converter.py @@ -0,0 +1,135 @@ +import os +import zipfile +import shutil +from typing import Any, Union + +from ._base import DocumentConverter, DocumentConverterResult + + +class ZipConverter(DocumentConverter): + """Converts ZIP files to markdown by extracting and converting all contained files. + + The converter extracts the ZIP contents to a temporary directory, processes each file + using appropriate converters based on file extensions, and then combines the results + into a single markdown document. The temporary directory is cleaned up after processing. + + Example output format: + ```markdown + Content from the zip file `example.zip`: + + ## File: docs/readme.txt + + This is the content of readme.txt + Multiple lines are preserved + + ## File: images/example.jpg + + ImageSize: 1920x1080 + DateTimeOriginal: 2024-02-15 14:30:00 + Description: A beautiful landscape photo + + ## File: data/report.xlsx + + ## Sheet1 + | Column1 | Column2 | Column3 | + |---------|---------|---------| + | data1 | data2 | data3 | + | data4 | data5 | data6 | + ``` + + Key features: + - Maintains original file structure in headings + - Processes nested files recursively + - Uses appropriate converters for each file type + - Preserves formatting of converted content + - Cleans up temporary files after processing + """ + + def convert( + self, local_path: str, **kwargs: Any + ) -> Union[None, DocumentConverterResult]: + # Bail if not a ZIP + extension = kwargs.get("file_extension", "") + if extension.lower() != ".zip": + return None + + # Get parent converters list if available + parent_converters = kwargs.get("_parent_converters", []) + if not parent_converters: + return DocumentConverterResult( + title=None, + text_content=f"[ERROR] No converters available to process zip contents from: {local_path}", + ) + + extracted_zip_folder_name = ( + f"extracted_{os.path.basename(local_path).replace('.zip', '_zip')}" + ) + extraction_dir = os.path.normpath( + os.path.join(os.path.dirname(local_path), extracted_zip_folder_name) + ) + md_content = f"Content from the zip file `{os.path.basename(local_path)}`:\n\n" + + try: + # Extract the zip file safely + with zipfile.ZipFile(local_path, "r") as zipObj: + # Safeguard against path traversal + for member in zipObj.namelist(): + member_path = os.path.normpath(os.path.join(extraction_dir, member)) + if ( + not os.path.commonprefix([extraction_dir, member_path]) + == extraction_dir + ): + raise ValueError( + f"Path traversal detected in zip file: {member}" + ) + + # Extract all files safely + zipObj.extractall(path=extraction_dir) + + # Process each extracted file + for root, dirs, files in os.walk(extraction_dir): + for name in files: + file_path = os.path.join(root, name) + relative_path = os.path.relpath(file_path, extraction_dir) + + # Get file extension + _, file_extension = os.path.splitext(name) + + # Update kwargs for the file + file_kwargs = kwargs.copy() + file_kwargs["file_extension"] = file_extension + file_kwargs["_parent_converters"] = parent_converters + + # Try converting the file using available converters + for converter in parent_converters: + # Skip the zip converter to avoid infinite recursion + if isinstance(converter, ZipConverter): + continue + + result = converter.convert(file_path, **file_kwargs) + if result is not None: + md_content += f"\n## File: {relative_path}\n\n" + md_content += result.text_content + "\n\n" + break + + # Clean up extracted files if specified + if kwargs.get("cleanup_extracted", True): + shutil.rmtree(extraction_dir) + + return DocumentConverterResult(title=None, text_content=md_content.strip()) + + except zipfile.BadZipFile: + return DocumentConverterResult( + title=None, + text_content=f"[ERROR] Invalid or corrupted zip file: {local_path}", + ) + except ValueError as ve: + return DocumentConverterResult( + title=None, + text_content=f"[ERROR] Security error in zip file {local_path}: {str(ve)}", + ) + except Exception as e: + return DocumentConverterResult( + title=None, + text_content=f"[ERROR] Failed to process zip file {local_path}: {str(e)}", + ) diff --git a/packages/markitdown/src/markitdown/py.typed b/packages/markitdown/src/markitdown/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/packages/markitdown/tests/__init__.py b/packages/markitdown/tests/__init__.py new file mode 100644 index 0000000..44af7d7 --- /dev/null +++ b/packages/markitdown/tests/__init__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2024-present Adam Fourney +# +# SPDX-License-Identifier: MIT diff --git a/tests/test_files/test.docx b/packages/markitdown/tests/test_files/test.docx similarity index 100% rename from tests/test_files/test.docx rename to packages/markitdown/tests/test_files/test.docx diff --git a/tests/test_files/test.jpg b/packages/markitdown/tests/test_files/test.jpg similarity index 100% rename from tests/test_files/test.jpg rename to packages/markitdown/tests/test_files/test.jpg diff --git a/tests/test_files/test.json b/packages/markitdown/tests/test_files/test.json similarity index 100% rename from tests/test_files/test.json rename to packages/markitdown/tests/test_files/test.json diff --git a/tests/test_files/test.pptx b/packages/markitdown/tests/test_files/test.pptx similarity index 100% rename from tests/test_files/test.pptx rename to packages/markitdown/tests/test_files/test.pptx diff --git a/tests/test_files/test.xls b/packages/markitdown/tests/test_files/test.xls similarity index 100% rename from tests/test_files/test.xls rename to packages/markitdown/tests/test_files/test.xls diff --git a/tests/test_files/test.xlsx b/packages/markitdown/tests/test_files/test.xlsx similarity index 100% rename from tests/test_files/test.xlsx rename to packages/markitdown/tests/test_files/test.xlsx diff --git a/tests/test_files/test_blog.html b/packages/markitdown/tests/test_files/test_blog.html similarity index 100% rename from tests/test_files/test_blog.html rename to packages/markitdown/tests/test_files/test_blog.html diff --git a/tests/test_files/test_files.zip b/packages/markitdown/tests/test_files/test_files.zip similarity index 100% rename from tests/test_files/test_files.zip rename to packages/markitdown/tests/test_files/test_files.zip diff --git a/tests/test_files/test_llm.jpg b/packages/markitdown/tests/test_files/test_llm.jpg similarity index 100% rename from tests/test_files/test_llm.jpg rename to packages/markitdown/tests/test_files/test_llm.jpg diff --git a/tests/test_files/test_mskanji.csv b/packages/markitdown/tests/test_files/test_mskanji.csv similarity index 100% rename from tests/test_files/test_mskanji.csv rename to packages/markitdown/tests/test_files/test_mskanji.csv diff --git a/tests/test_files/test_notebook.ipynb b/packages/markitdown/tests/test_files/test_notebook.ipynb similarity index 100% rename from tests/test_files/test_notebook.ipynb rename to packages/markitdown/tests/test_files/test_notebook.ipynb diff --git a/tests/test_files/test_outlook_msg.msg b/packages/markitdown/tests/test_files/test_outlook_msg.msg similarity index 100% rename from tests/test_files/test_outlook_msg.msg rename to packages/markitdown/tests/test_files/test_outlook_msg.msg diff --git a/tests/test_files/test_rss.xml b/packages/markitdown/tests/test_files/test_rss.xml similarity index 100% rename from tests/test_files/test_rss.xml rename to packages/markitdown/tests/test_files/test_rss.xml diff --git a/tests/test_files/test_serp.html b/packages/markitdown/tests/test_files/test_serp.html similarity index 100% rename from tests/test_files/test_serp.html rename to packages/markitdown/tests/test_files/test_serp.html diff --git a/tests/test_files/test_wikipedia.html b/packages/markitdown/tests/test_files/test_wikipedia.html similarity index 100% rename from tests/test_files/test_wikipedia.html rename to packages/markitdown/tests/test_files/test_wikipedia.html diff --git a/tests/test_files/test_with_comment.docx b/packages/markitdown/tests/test_files/test_with_comment.docx similarity index 100% rename from tests/test_files/test_with_comment.docx rename to packages/markitdown/tests/test_files/test_with_comment.docx diff --git a/tests/test_markitdown.py b/packages/markitdown/tests/test_markitdown.py similarity index 92% rename from tests/test_markitdown.py rename to packages/markitdown/tests/test_markitdown.py index 689d6f3..be71722 100644 --- a/tests/test_markitdown.py +++ b/packages/markitdown/tests/test_markitdown.py @@ -306,40 +306,6 @@ def test_markitdown_exiftool() -> None: assert target in result.text_content -def test_markitdown_deprecation() -> None: - try: - with catch_warnings(record=True) as w: - test_client = object() - markitdown = MarkItDown(mlm_client=test_client) - assert len(w) == 1 - assert w[0].category is DeprecationWarning - assert markitdown._llm_client == test_client - finally: - resetwarnings() - - try: - with catch_warnings(record=True) as w: - markitdown = MarkItDown(mlm_model="gpt-4o") - assert len(w) == 1 - assert w[0].category is DeprecationWarning - assert markitdown._llm_model == "gpt-4o" - finally: - resetwarnings() - - try: - test_client = object() - markitdown = MarkItDown(mlm_client=test_client, llm_client=test_client) - assert False - except ValueError: - pass - - try: - markitdown = MarkItDown(mlm_model="gpt-4o", llm_model="gpt-4o") - assert False - except ValueError: - pass - - @pytest.mark.skipif( skip_llm, reason="do not run llm tests without a key", diff --git a/src/markitdown/__init__.py b/src/markitdown/__init__.py deleted file mode 100644 index 482f428..0000000 --- a/src/markitdown/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-FileCopyrightText: 2024-present Adam Fourney -# -# SPDX-License-Identifier: MIT - -from ._markitdown import MarkItDown, FileConversionException, UnsupportedFormatException - -__all__ = [ - "MarkItDown", - "FileConversionException", - "UnsupportedFormatException", -] diff --git a/src/markitdown/_markitdown.py b/src/markitdown/_markitdown.py deleted file mode 100644 index e68b099..0000000 --- a/src/markitdown/_markitdown.py +++ /dev/null @@ -1,1801 +0,0 @@ -# type: ignore -import base64 -import binascii -import copy -import html -import json -import mimetypes -import os -import re -import shutil -import subprocess -import sys -import tempfile -import traceback -import zipfile -from xml.dom import minidom -from typing import Any, Dict, List, Optional, Union -from pathlib import Path -from urllib.parse import parse_qs, quote, unquote, urlparse, urlunparse -from warnings import warn, resetwarnings, catch_warnings - -import mammoth -import markdownify -import olefile -import pandas as pd -import pdfminer -import pdfminer.high_level -import pptx - -# File-format detection -import puremagic -import requests -from bs4 import BeautifulSoup -from charset_normalizer import from_path - -# Azure imports -from azure.ai.documentintelligence import DocumentIntelligenceClient -from azure.ai.documentintelligence.models import ( - AnalyzeDocumentRequest, - AnalyzeResult, - DocumentAnalysisFeature, -) -from azure.identity import DefaultAzureCredential - -# TODO: currently, there is a bug in the document intelligence SDK with importing the "ContentFormat" enum. -# This constant is a temporary fix until the bug is resolved. -CONTENT_FORMAT = "markdown" - -# Override mimetype for csv to fix issue on windows -mimetypes.add_type("text/csv", ".csv") - -# Optional Transcription support -IS_AUDIO_TRANSCRIPTION_CAPABLE = False -try: - # Using warnings' catch_warnings to catch - # pydub's warning of ffmpeg or avconv missing - with catch_warnings(record=True) as w: - import pydub - - if w: - raise ModuleNotFoundError - import speech_recognition as sr - - IS_AUDIO_TRANSCRIPTION_CAPABLE = True -except ModuleNotFoundError: - pass -finally: - resetwarnings() - -# Optional YouTube transcription support -try: - from youtube_transcript_api import YouTubeTranscriptApi - - IS_YOUTUBE_TRANSCRIPT_CAPABLE = True -except ModuleNotFoundError: - pass - - -class _CustomMarkdownify(markdownify.MarkdownConverter): - """ - A custom version of markdownify's MarkdownConverter. Changes include: - - - Altering the default heading style to use '#', '##', etc. - - Removing javascript hyperlinks. - - Truncating images with large data:uri sources. - - Ensuring URIs are properly escaped, and do not conflict with Markdown syntax - """ - - def __init__(self, **options: Any): - options["heading_style"] = options.get("heading_style", markdownify.ATX) - # Explicitly cast options to the expected type if necessary - super().__init__(**options) - - def convert_hn(self, n: int, el: Any, text: str, convert_as_inline: bool) -> str: - """Same as usual, but be sure to start with a new line""" - if not convert_as_inline: - if not re.search(r"^\n", text): - return "\n" + super().convert_hn(n, el, text, convert_as_inline) # type: ignore - - return super().convert_hn(n, el, text, convert_as_inline) # type: ignore - - def convert_a(self, el: Any, text: str, convert_as_inline: bool): - """Same as usual converter, but removes Javascript links and escapes URIs.""" - prefix, suffix, text = markdownify.chomp(text) # type: ignore - if not text: - return "" - href = el.get("href") - title = el.get("title") - - # Escape URIs and skip non-http or file schemes - if href: - try: - parsed_url = urlparse(href) # type: ignore - if parsed_url.scheme and parsed_url.scheme.lower() not in ["http", "https", "file"]: # type: ignore - return "%s%s%s" % (prefix, text, suffix) - href = urlunparse(parsed_url._replace(path=quote(unquote(parsed_url.path)))) # type: ignore - except ValueError: # It's not clear if this ever gets thrown - return "%s%s%s" % (prefix, text, suffix) - - # For the replacement see #29: text nodes underscores are escaped - if ( - self.options["autolinks"] - and text.replace(r"\_", "_") == href - and not title - and not self.options["default_title"] - ): - # Shortcut syntax - return "<%s>" % href - if self.options["default_title"] and not title: - title = href - title_part = ' "%s"' % title.replace('"', r"\"") if title else "" - return ( - "%s[%s](%s%s)%s" % (prefix, text, href, title_part, suffix) - if href - else text - ) - - def convert_img(self, el: Any, text: str, convert_as_inline: bool) -> str: - """Same as usual converter, but removes data URIs""" - - alt = el.attrs.get("alt", None) or "" - src = el.attrs.get("src", None) or "" - title = el.attrs.get("title", None) or "" - title_part = ' "%s"' % title.replace('"', r"\"") if title else "" - if ( - convert_as_inline - and el.parent.name not in self.options["keep_inline_images_in"] - ): - return alt - - # Remove dataURIs - if src.startswith("data:"): - src = src.split(",")[0] + "..." - - return "![%s](%s%s)" % (alt, src, title_part) - - def convert_soup(self, soup: Any) -> str: - return super().convert_soup(soup) # type: ignore - - -class DocumentConverterResult: - """The result of converting a document to text.""" - - def __init__(self, title: Union[str, None] = None, text_content: str = ""): - self.title: Union[str, None] = title - self.text_content: str = text_content - - -class DocumentConverter: - """Abstract superclass of all DocumentConverters.""" - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - raise NotImplementedError() - - -class PlainTextConverter(DocumentConverter): - """Anything with content type text/plain""" - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Guess the content type from any file extension that might be around - content_type, _ = mimetypes.guess_type( - "__placeholder" + kwargs.get("file_extension", "") - ) - - # Only accept text files - if content_type is None: - return None - elif all( - not content_type.lower().startswith(type_prefix) - for type_prefix in ["text/", "application/json"] - ): - return None - - text_content = str(from_path(local_path).best()) - return DocumentConverterResult( - title=None, - text_content=text_content, - ) - - -class HtmlConverter(DocumentConverter): - """Anything with content type text/html""" - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not html - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".html", ".htm"]: - return None - - result = None - with open(local_path, "rt", encoding="utf-8") as fh: - result = self._convert(fh.read()) - - return result - - def _convert(self, html_content: str) -> Union[None, DocumentConverterResult]: - """Helper function that converts an HTML string.""" - - # Parse the string - soup = BeautifulSoup(html_content, "html.parser") - - # Remove javascript and style blocks - for script in soup(["script", "style"]): - script.extract() - - # Print only the main content - body_elm = soup.find("body") - webpage_text = "" - if body_elm: - webpage_text = _CustomMarkdownify().convert_soup(body_elm) - else: - webpage_text = _CustomMarkdownify().convert_soup(soup) - - assert isinstance(webpage_text, str) - - # remove leading and trailing \n - webpage_text = webpage_text.strip() - - return DocumentConverterResult( - title=None if soup.title is None else soup.title.string, - text_content=webpage_text, - ) - - -class RSSConverter(DocumentConverter): - """Convert RSS / Atom type to markdown""" - - def convert( - self, local_path: str, **kwargs - ) -> Union[None, DocumentConverterResult]: - # Bail if not RSS type - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".xml", ".rss", ".atom"]: - return None - try: - doc = minidom.parse(local_path) - except BaseException as _: - return None - result = None - if doc.getElementsByTagName("rss"): - # A RSS feed must have a root element of - result = self._parse_rss_type(doc) - elif doc.getElementsByTagName("feed"): - root = doc.getElementsByTagName("feed")[0] - if root.getElementsByTagName("entry"): - # An Atom feed must have a root element of and at least one - result = self._parse_atom_type(doc) - else: - return None - else: - # not rss or atom - return None - - return result - - def _parse_atom_type( - self, doc: minidom.Document - ) -> Union[None, DocumentConverterResult]: - """Parse the type of an Atom feed. - - Returns None if the feed type is not recognized or something goes wrong. - """ - try: - root = doc.getElementsByTagName("feed")[0] - title = self._get_data_by_tag_name(root, "title") - subtitle = self._get_data_by_tag_name(root, "subtitle") - entries = root.getElementsByTagName("entry") - md_text = f"# {title}\n" - if subtitle: - md_text += f"{subtitle}\n" - for entry in entries: - entry_title = self._get_data_by_tag_name(entry, "title") - entry_summary = self._get_data_by_tag_name(entry, "summary") - entry_updated = self._get_data_by_tag_name(entry, "updated") - entry_content = self._get_data_by_tag_name(entry, "content") - - if entry_title: - md_text += f"\n## {entry_title}\n" - if entry_updated: - md_text += f"Updated on: {entry_updated}\n" - if entry_summary: - md_text += self._parse_content(entry_summary) - if entry_content: - md_text += self._parse_content(entry_content) - - return DocumentConverterResult( - title=title, - text_content=md_text, - ) - except BaseException as _: - return None - - def _parse_rss_type( - self, doc: minidom.Document - ) -> Union[None, DocumentConverterResult]: - """Parse the type of an RSS feed. - - Returns None if the feed type is not recognized or something goes wrong. - """ - try: - root = doc.getElementsByTagName("rss")[0] - channel = root.getElementsByTagName("channel") - if not channel: - return None - channel = channel[0] - channel_title = self._get_data_by_tag_name(channel, "title") - channel_description = self._get_data_by_tag_name(channel, "description") - items = channel.getElementsByTagName("item") - if channel_title: - md_text = f"# {channel_title}\n" - if channel_description: - md_text += f"{channel_description}\n" - if not items: - items = [] - for item in items: - title = self._get_data_by_tag_name(item, "title") - description = self._get_data_by_tag_name(item, "description") - pubDate = self._get_data_by_tag_name(item, "pubDate") - content = self._get_data_by_tag_name(item, "content:encoded") - - if title: - md_text += f"\n## {title}\n" - if pubDate: - md_text += f"Published on: {pubDate}\n" - if description: - md_text += self._parse_content(description) - if content: - md_text += self._parse_content(content) - - return DocumentConverterResult( - title=channel_title, - text_content=md_text, - ) - except BaseException as _: - print(traceback.format_exc()) - return None - - def _parse_content(self, content: str) -> str: - """Parse the content of an RSS feed item""" - try: - # using bs4 because many RSS feeds have HTML-styled content - soup = BeautifulSoup(content, "html.parser") - return _CustomMarkdownify().convert_soup(soup) - except BaseException as _: - return content - - def _get_data_by_tag_name( - self, element: minidom.Element, tag_name: str - ) -> Union[str, None]: - """Get data from first child element with the given tag name. - Returns None when no such element is found. - """ - nodes = element.getElementsByTagName(tag_name) - if not nodes: - return None - fc = nodes[0].firstChild - if fc: - return fc.data - return None - - -class WikipediaConverter(DocumentConverter): - """Handle Wikipedia pages separately, focusing only on the main document content.""" - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not Wikipedia - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".html", ".htm"]: - return None - url = kwargs.get("url", "") - if not re.search(r"^https?:\/\/[a-zA-Z]{2,3}\.wikipedia.org\/", url): - return None - - # Parse the file - soup = None - with open(local_path, "rt", encoding="utf-8") as fh: - soup = BeautifulSoup(fh.read(), "html.parser") - - # Remove javascript and style blocks - for script in soup(["script", "style"]): - script.extract() - - # Print only the main content - body_elm = soup.find("div", {"id": "mw-content-text"}) - title_elm = soup.find("span", {"class": "mw-page-title-main"}) - - webpage_text = "" - main_title = None if soup.title is None else soup.title.string - - if body_elm: - # What's the title - if title_elm and len(title_elm) > 0: - main_title = title_elm.string # type: ignore - assert isinstance(main_title, str) - - # Convert the page - webpage_text = f"# {main_title}\n\n" + _CustomMarkdownify().convert_soup( - body_elm - ) - else: - webpage_text = _CustomMarkdownify().convert_soup(soup) - - return DocumentConverterResult( - title=main_title, - text_content=webpage_text, - ) - - -class YouTubeConverter(DocumentConverter): - """Handle YouTube specially, focusing on the video title, description, and transcript.""" - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not YouTube - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".html", ".htm"]: - return None - url = kwargs.get("url", "") - if not url.startswith("https://www.youtube.com/watch?"): - return None - - # Parse the file - soup = None - with open(local_path, "rt", encoding="utf-8") as fh: - soup = BeautifulSoup(fh.read(), "html.parser") - - # Read the meta tags - assert soup.title is not None and soup.title.string is not None - metadata: Dict[str, str] = {"title": soup.title.string} - for meta in soup(["meta"]): - for a in meta.attrs: - if a in ["itemprop", "property", "name"]: - metadata[meta[a]] = meta.get("content", "") - break - - # We can also try to read the full description. This is more prone to breaking, since it reaches into the page implementation - try: - for script in soup(["script"]): - content = script.text - if "ytInitialData" in content: - lines = re.split(r"\r?\n", content) - obj_start = lines[0].find("{") - obj_end = lines[0].rfind("}") - if obj_start >= 0 and obj_end >= 0: - data = json.loads(lines[0][obj_start : obj_end + 1]) - attrdesc = self._findKey(data, "attributedDescriptionBodyText") # type: ignore - if attrdesc: - metadata["description"] = str(attrdesc["content"]) - break - except Exception: - pass - - # Start preparing the page - webpage_text = "# YouTube\n" - - title = self._get(metadata, ["title", "og:title", "name"]) # type: ignore - assert isinstance(title, str) - - if title: - webpage_text += f"\n## {title}\n" - - stats = "" - views = self._get(metadata, ["interactionCount"]) # type: ignore - if views: - stats += f"- **Views:** {views}\n" - - keywords = self._get(metadata, ["keywords"]) # type: ignore - if keywords: - stats += f"- **Keywords:** {keywords}\n" - - runtime = self._get(metadata, ["duration"]) # type: ignore - if runtime: - stats += f"- **Runtime:** {runtime}\n" - - if len(stats) > 0: - webpage_text += f"\n### Video Metadata\n{stats}\n" - - description = self._get(metadata, ["description", "og:description"]) # type: ignore - if description: - webpage_text += f"\n### Description\n{description}\n" - - if IS_YOUTUBE_TRANSCRIPT_CAPABLE: - transcript_text = "" - parsed_url = urlparse(url) # type: ignore - params = parse_qs(parsed_url.query) # type: ignore - if "v" in params: - assert isinstance(params["v"][0], str) - video_id = str(params["v"][0]) - try: - youtube_transcript_languages = kwargs.get( - "youtube_transcript_languages", ("en",) - ) - # Must be a single transcript. - transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=youtube_transcript_languages) # type: ignore - transcript_text = " ".join([part["text"] for part in transcript]) # type: ignore - # Alternative formatting: - # formatter = TextFormatter() - # formatter.format_transcript(transcript) - except Exception: - pass - if transcript_text: - webpage_text += f"\n### Transcript\n{transcript_text}\n" - - title = title if title else soup.title.string - assert isinstance(title, str) - - return DocumentConverterResult( - title=title, - text_content=webpage_text, - ) - - def _get( - self, - metadata: Dict[str, str], - keys: List[str], - default: Union[str, None] = None, - ) -> Union[str, None]: - for k in keys: - if k in metadata: - return metadata[k] - return default - - def _findKey(self, json: Any, key: str) -> Union[str, None]: # TODO: Fix json type - if isinstance(json, list): - for elm in json: - ret = self._findKey(elm, key) - if ret is not None: - return ret - elif isinstance(json, dict): - for k in json: - if k == key: - return json[k] - else: - ret = self._findKey(json[k], key) - if ret is not None: - return ret - return None - - -class IpynbConverter(DocumentConverter): - """Converts Jupyter Notebook (.ipynb) files to Markdown.""" - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not ipynb - extension = kwargs.get("file_extension", "") - if extension.lower() != ".ipynb": - return None - - # Parse and convert the notebook - result = None - with open(local_path, "rt", encoding="utf-8") as fh: - notebook_content = json.load(fh) - result = self._convert(notebook_content) - - return result - - def _convert(self, notebook_content: dict) -> Union[None, DocumentConverterResult]: - """Helper function that converts notebook JSON content to Markdown.""" - try: - md_output = [] - title = None - - for cell in notebook_content.get("cells", []): - cell_type = cell.get("cell_type", "") - source_lines = cell.get("source", []) - - if cell_type == "markdown": - md_output.append("".join(source_lines)) - - # Extract the first # heading as title if not already found - if title is None: - for line in source_lines: - if line.startswith("# "): - title = line.lstrip("# ").strip() - break - - elif cell_type == "code": - # Code cells are wrapped in Markdown code blocks - md_output.append(f"```python\n{''.join(source_lines)}\n```") - elif cell_type == "raw": - md_output.append(f"```\n{''.join(source_lines)}\n```") - - md_text = "\n\n".join(md_output) - - # Check for title in notebook metadata - title = notebook_content.get("metadata", {}).get("title", title) - - return DocumentConverterResult( - title=title, - text_content=md_text, - ) - - except Exception as e: - raise FileConversionException( - f"Error converting .ipynb file: {str(e)}" - ) from e - - -class BingSerpConverter(DocumentConverter): - """ - Handle Bing results pages (only the organic search results). - NOTE: It is better to use the Bing API - """ - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a Bing SERP - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".html", ".htm"]: - return None - url = kwargs.get("url", "") - if not re.search(r"^https://www\.bing\.com/search\?q=", url): - return None - - # Parse the query parameters - parsed_params = parse_qs(urlparse(url).query) - query = parsed_params.get("q", [""])[0] - - # Parse the file - soup = None - with open(local_path, "rt", encoding="utf-8") as fh: - soup = BeautifulSoup(fh.read(), "html.parser") - - # Clean up some formatting - for tptt in soup.find_all(class_="tptt"): - if hasattr(tptt, "string") and tptt.string: - tptt.string += " " - for slug in soup.find_all(class_="algoSlug_icon"): - slug.extract() - - # Parse the algorithmic results - _markdownify = _CustomMarkdownify() - results = list() - for result in soup.find_all(class_="b_algo"): - # Rewrite redirect urls - for a in result.find_all("a", href=True): - parsed_href = urlparse(a["href"]) - qs = parse_qs(parsed_href.query) - - # The destination is contained in the u parameter, - # but appears to be base64 encoded, with some prefix - if "u" in qs: - u = ( - qs["u"][0][2:].strip() + "==" - ) # Python 3 doesn't care about extra padding - - try: - # RFC 4648 / Base64URL" variant, which uses "-" and "_" - a["href"] = base64.b64decode(u, altchars="-_").decode("utf-8") - except UnicodeDecodeError: - pass - except binascii.Error: - pass - - # Convert to markdown - md_result = _markdownify.convert_soup(result).strip() - lines = [line.strip() for line in re.split(r"\n+", md_result)] - results.append("\n".join([line for line in lines if len(line) > 0])) - - webpage_text = ( - f"## A Bing search for '{query}' found the following results:\n\n" - + "\n\n".join(results) - ) - - return DocumentConverterResult( - title=None if soup.title is None else soup.title.string, - text_content=webpage_text, - ) - - -class PdfConverter(DocumentConverter): - """ - Converts PDFs to Markdown. Most style information is ignored, so the results are essentially plain-text. - """ - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a PDF - extension = kwargs.get("file_extension", "") - if extension.lower() != ".pdf": - return None - - return DocumentConverterResult( - title=None, - text_content=pdfminer.high_level.extract_text(local_path), - ) - - -class DocxConverter(HtmlConverter): - """ - Converts DOCX files to Markdown. Style information (e.g.m headings) and tables are preserved where possible. - """ - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a DOCX - extension = kwargs.get("file_extension", "") - if extension.lower() != ".docx": - return None - - result = None - with open(local_path, "rb") as docx_file: - style_map = kwargs.get("style_map", None) - - result = mammoth.convert_to_html(docx_file, style_map=style_map) - html_content = result.value - result = self._convert(html_content) - - return result - - -class XlsxConverter(HtmlConverter): - """ - Converts XLSX files to Markdown, with each sheet presented as a separate Markdown table. - """ - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a XLSX - extension = kwargs.get("file_extension", "") - if extension.lower() != ".xlsx": - return None - - sheets = pd.read_excel(local_path, sheet_name=None, engine="openpyxl") - md_content = "" - for s in sheets: - md_content += f"## {s}\n" - html_content = sheets[s].to_html(index=False) - md_content += self._convert(html_content).text_content.strip() + "\n\n" - - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) - - -class XlsConverter(HtmlConverter): - """ - Converts XLS files to Markdown, with each sheet presented as a separate Markdown table. - """ - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a XLS - extension = kwargs.get("file_extension", "") - if extension.lower() != ".xls": - return None - - sheets = pd.read_excel(local_path, sheet_name=None, engine="xlrd") - md_content = "" - for s in sheets: - md_content += f"## {s}\n" - html_content = sheets[s].to_html(index=False) - md_content += self._convert(html_content).text_content.strip() + "\n\n" - - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) - - -class PptxConverter(HtmlConverter): - """ - Converts PPTX files to Markdown. Supports heading, tables and images with alt text. - """ - - def _get_llm_description( - self, llm_client, llm_model, image_blob, content_type, prompt=None - ): - if prompt is None or prompt.strip() == "": - prompt = "Write a detailed alt text for this image with less than 50 words." - - image_base64 = base64.b64encode(image_blob).decode("utf-8") - data_uri = f"data:{content_type};base64,{image_base64}" - - messages = [ - { - "role": "user", - "content": [ - { - "type": "image_url", - "image_url": { - "url": data_uri, - }, - }, - {"type": "text", "text": prompt}, - ], - } - ] - - response = llm_client.chat.completions.create( - model=llm_model, messages=messages - ) - return response.choices[0].message.content - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a PPTX - extension = kwargs.get("file_extension", "") - if extension.lower() != ".pptx": - return None - - md_content = "" - - presentation = pptx.Presentation(local_path) - slide_num = 0 - for slide in presentation.slides: - slide_num += 1 - - md_content += f"\n\n\n" - - title = slide.shapes.title - for shape in slide.shapes: - # Pictures - if self._is_picture(shape): - # https://github.com/scanny/python-pptx/pull/512#issuecomment-1713100069 - - llm_description = None - alt_text = None - - llm_client = kwargs.get("llm_client") - llm_model = kwargs.get("llm_model") - if llm_client is not None and llm_model is not None: - try: - llm_description = self._get_llm_description( - llm_client, - llm_model, - shape.image.blob, - shape.image.content_type, - ) - except Exception: - # Unable to describe with LLM - pass - - if not llm_description: - try: - alt_text = shape._element._nvXxPr.cNvPr.attrib.get( - "descr", "" - ) - except Exception: - # Unable to get alt text - pass - - # A placeholder name - filename = re.sub(r"\W", "", shape.name) + ".jpg" - md_content += ( - "\n![" - + (llm_description or alt_text or shape.name) - + "](" - + filename - + ")\n" - ) - - # Tables - if self._is_table(shape): - html_table = "" - first_row = True - for row in shape.table.rows: - html_table += "" - for cell in row.cells: - if first_row: - html_table += "" - else: - html_table += "" - html_table += "" - first_row = False - html_table += "
" + html.escape(cell.text) + "" + html.escape(cell.text) + "
" - md_content += ( - "\n" + self._convert(html_table).text_content.strip() + "\n" - ) - - # Charts - if shape.has_chart: - md_content += self._convert_chart_to_markdown(shape.chart) - - # Text areas - elif shape.has_text_frame: - if shape == title: - md_content += "# " + shape.text.lstrip() + "\n" - else: - md_content += shape.text + "\n" - - md_content = md_content.strip() - - if slide.has_notes_slide: - md_content += "\n\n### Notes:\n" - notes_frame = slide.notes_slide.notes_text_frame - if notes_frame is not None: - md_content += notes_frame.text - md_content = md_content.strip() - - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) - - def _is_picture(self, shape): - if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.PICTURE: - return True - if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.PLACEHOLDER: - if hasattr(shape, "image"): - return True - return False - - def _is_table(self, shape): - if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.TABLE: - return True - return False - - def _convert_chart_to_markdown(self, chart): - md = "\n\n### Chart" - if chart.has_title: - md += f": {chart.chart_title.text_frame.text}" - md += "\n\n" - data = [] - category_names = [c.label for c in chart.plots[0].categories] - series_names = [s.name for s in chart.series] - data.append(["Category"] + series_names) - - for idx, category in enumerate(category_names): - row = [category] - for series in chart.series: - row.append(series.values[idx]) - data.append(row) - - markdown_table = [] - for row in data: - markdown_table.append("| " + " | ".join(map(str, row)) + " |") - header = markdown_table[0] - separator = "|" + "|".join(["---"] * len(data[0])) + "|" - return md + "\n".join([header, separator] + markdown_table[1:]) - - -class MediaConverter(DocumentConverter): - """ - Abstract class for multi-modal media (e.g., images and audio) - """ - - def _get_metadata(self, local_path, exiftool_path=None): - if not exiftool_path: - which_exiftool = shutil.which("exiftool") - if which_exiftool: - warn( - f"""Implicit discovery of 'exiftool' is disabled. If you would like to continue to use exiftool in MarkItDown, please set the exiftool_path parameter in the MarkItDown consructor. E.g., - - md = MarkItDown(exiftool_path="{which_exiftool}") - -This warning will be removed in future releases. -""", - DeprecationWarning, - ) - - return None - else: - try: - result = subprocess.run( - [exiftool_path, "-json", local_path], capture_output=True, text=True - ).stdout - return json.loads(result)[0] - except Exception: - return None - - -class WavConverter(MediaConverter): - """ - Converts WAV files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` is installed). - """ - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a WAV - extension = kwargs.get("file_extension", "") - if extension.lower() != ".wav": - return None - - md_content = "" - - # Add metadata - metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) - if metadata: - for f in [ - "Title", - "Artist", - "Author", - "Band", - "Album", - "Genre", - "Track", - "DateTimeOriginal", - "CreateDate", - "Duration", - ]: - if f in metadata: - md_content += f"{f}: {metadata[f]}\n" - - # Transcribe - if IS_AUDIO_TRANSCRIPTION_CAPABLE: - try: - transcript = self._transcribe_audio(local_path) - md_content += "\n\n### Audio Transcript:\n" + ( - "[No speech detected]" if transcript == "" else transcript - ) - except Exception: - md_content += ( - "\n\n### Audio Transcript:\nError. Could not transcribe this audio." - ) - - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) - - def _transcribe_audio(self, local_path) -> str: - recognizer = sr.Recognizer() - with sr.AudioFile(local_path) as source: - audio = recognizer.record(source) - return recognizer.recognize_google(audio).strip() - - -class Mp3Converter(WavConverter): - """ - Converts MP3 files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` AND `pydub` are installed). - """ - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a MP3 - extension = kwargs.get("file_extension", "") - if extension.lower() != ".mp3": - return None - - md_content = "" - - # Add metadata - metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) - if metadata: - for f in [ - "Title", - "Artist", - "Author", - "Band", - "Album", - "Genre", - "Track", - "DateTimeOriginal", - "CreateDate", - "Duration", - ]: - if f in metadata: - md_content += f"{f}: {metadata[f]}\n" - - # Transcribe - if IS_AUDIO_TRANSCRIPTION_CAPABLE: - handle, temp_path = tempfile.mkstemp(suffix=".wav") - os.close(handle) - try: - sound = pydub.AudioSegment.from_mp3(local_path) - sound.export(temp_path, format="wav") - - _args = dict() - _args.update(kwargs) - _args["file_extension"] = ".wav" - - try: - transcript = super()._transcribe_audio(temp_path).strip() - md_content += "\n\n### Audio Transcript:\n" + ( - "[No speech detected]" if transcript == "" else transcript - ) - except Exception: - md_content += "\n\n### Audio Transcript:\nError. Could not transcribe this audio." - - finally: - os.unlink(temp_path) - - # Return the result - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) - - -class ImageConverter(MediaConverter): - """ - Converts images to markdown via extraction of metadata (if `exiftool` is installed), OCR (if `easyocr` is installed), and description via a multimodal LLM (if an llm_client is configured). - """ - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not an image - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".jpg", ".jpeg", ".png"]: - return None - - md_content = "" - - # Add metadata - metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) - if metadata: - for f in [ - "ImageSize", - "Title", - "Caption", - "Description", - "Keywords", - "Artist", - "Author", - "DateTimeOriginal", - "CreateDate", - "GPSPosition", - ]: - if f in metadata: - md_content += f"{f}: {metadata[f]}\n" - - # Try describing the image with GPTV - llm_client = kwargs.get("llm_client") - llm_model = kwargs.get("llm_model") - if llm_client is not None and llm_model is not None: - md_content += ( - "\n# Description:\n" - + self._get_llm_description( - local_path, - extension, - llm_client, - llm_model, - prompt=kwargs.get("llm_prompt"), - ).strip() - + "\n" - ) - - return DocumentConverterResult( - title=None, - text_content=md_content, - ) - - def _get_llm_description(self, local_path, extension, client, model, prompt=None): - if prompt is None or prompt.strip() == "": - prompt = "Write a detailed caption for this image." - - data_uri = "" - with open(local_path, "rb") as image_file: - content_type, encoding = mimetypes.guess_type("_dummy" + extension) - if content_type is None: - content_type = "image/jpeg" - image_base64 = base64.b64encode(image_file.read()).decode("utf-8") - data_uri = f"data:{content_type};base64,{image_base64}" - - messages = [ - { - "role": "user", - "content": [ - {"type": "text", "text": prompt}, - { - "type": "image_url", - "image_url": { - "url": data_uri, - }, - }, - ], - } - ] - - response = client.chat.completions.create(model=model, messages=messages) - return response.choices[0].message.content - - -class OutlookMsgConverter(DocumentConverter): - """Converts Outlook .msg files to markdown by extracting email metadata and content. - - Uses the olefile package to parse the .msg file structure and extract: - - Email headers (From, To, Subject) - - Email body content - """ - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not a MSG file - extension = kwargs.get("file_extension", "") - if extension.lower() != ".msg": - return None - - try: - msg = olefile.OleFileIO(local_path) - # Extract email metadata - md_content = "# Email Message\n\n" - - # Get headers - headers = { - "From": self._get_stream_data(msg, "__substg1.0_0C1F001F"), - "To": self._get_stream_data(msg, "__substg1.0_0E04001F"), - "Subject": self._get_stream_data(msg, "__substg1.0_0037001F"), - } - - # Add headers to markdown - for key, value in headers.items(): - if value: - md_content += f"**{key}:** {value}\n" - - md_content += "\n## Content\n\n" - - # Get email body - body = self._get_stream_data(msg, "__substg1.0_1000001F") - if body: - md_content += body - - msg.close() - - return DocumentConverterResult( - title=headers.get("Subject"), text_content=md_content.strip() - ) - - except Exception as e: - raise FileConversionException( - f"Could not convert MSG file '{local_path}': {str(e)}" - ) - - def _get_stream_data( - self, msg: olefile.OleFileIO, stream_path: str - ) -> Union[str, None]: - """Helper to safely extract and decode stream data from the MSG file.""" - try: - if msg.exists(stream_path): - data = msg.openstream(stream_path).read() - # Try UTF-16 first (common for .msg files) - try: - return data.decode("utf-16-le").strip() - except UnicodeDecodeError: - # Fall back to UTF-8 - try: - return data.decode("utf-8").strip() - except UnicodeDecodeError: - # Last resort - ignore errors - return data.decode("utf-8", errors="ignore").strip() - except Exception: - pass - return None - - -class ZipConverter(DocumentConverter): - """Converts ZIP files to markdown by extracting and converting all contained files. - - The converter extracts the ZIP contents to a temporary directory, processes each file - using appropriate converters based on file extensions, and then combines the results - into a single markdown document. The temporary directory is cleaned up after processing. - - Example output format: - ```markdown - Content from the zip file `example.zip`: - - ## File: docs/readme.txt - - This is the content of readme.txt - Multiple lines are preserved - - ## File: images/example.jpg - - ImageSize: 1920x1080 - DateTimeOriginal: 2024-02-15 14:30:00 - Description: A beautiful landscape photo - - ## File: data/report.xlsx - - ## Sheet1 - | Column1 | Column2 | Column3 | - |---------|---------|---------| - | data1 | data2 | data3 | - | data4 | data5 | data6 | - ``` - - Key features: - - Maintains original file structure in headings - - Processes nested files recursively - - Uses appropriate converters for each file type - - Preserves formatting of converted content - - Cleans up temporary files after processing - """ - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not a ZIP - extension = kwargs.get("file_extension", "") - if extension.lower() != ".zip": - return None - - # Get parent converters list if available - parent_converters = kwargs.get("_parent_converters", []) - if not parent_converters: - return DocumentConverterResult( - title=None, - text_content=f"[ERROR] No converters available to process zip contents from: {local_path}", - ) - - extracted_zip_folder_name = ( - f"extracted_{os.path.basename(local_path).replace('.zip', '_zip')}" - ) - extraction_dir = os.path.normpath( - os.path.join(os.path.dirname(local_path), extracted_zip_folder_name) - ) - md_content = f"Content from the zip file `{os.path.basename(local_path)}`:\n\n" - - try: - # Extract the zip file safely - with zipfile.ZipFile(local_path, "r") as zipObj: - # Safeguard against path traversal - for member in zipObj.namelist(): - member_path = os.path.normpath(os.path.join(extraction_dir, member)) - if ( - not os.path.commonprefix([extraction_dir, member_path]) - == extraction_dir - ): - raise ValueError( - f"Path traversal detected in zip file: {member}" - ) - - # Extract all files safely - zipObj.extractall(path=extraction_dir) - - # Process each extracted file - for root, dirs, files in os.walk(extraction_dir): - for name in files: - file_path = os.path.join(root, name) - relative_path = os.path.relpath(file_path, extraction_dir) - - # Get file extension - _, file_extension = os.path.splitext(name) - - # Update kwargs for the file - file_kwargs = kwargs.copy() - file_kwargs["file_extension"] = file_extension - file_kwargs["_parent_converters"] = parent_converters - - # Try converting the file using available converters - for converter in parent_converters: - # Skip the zip converter to avoid infinite recursion - if isinstance(converter, ZipConverter): - continue - - result = converter.convert(file_path, **file_kwargs) - if result is not None: - md_content += f"\n## File: {relative_path}\n\n" - md_content += result.text_content + "\n\n" - break - - # Clean up extracted files if specified - if kwargs.get("cleanup_extracted", True): - shutil.rmtree(extraction_dir) - - return DocumentConverterResult(title=None, text_content=md_content.strip()) - - except zipfile.BadZipFile: - return DocumentConverterResult( - title=None, - text_content=f"[ERROR] Invalid or corrupted zip file: {local_path}", - ) - except ValueError as ve: - return DocumentConverterResult( - title=None, - text_content=f"[ERROR] Security error in zip file {local_path}: {str(ve)}", - ) - except Exception as e: - return DocumentConverterResult( - title=None, - text_content=f"[ERROR] Failed to process zip file {local_path}: {str(e)}", - ) - - -class DocumentIntelligenceConverter(DocumentConverter): - """Specialized DocumentConverter that uses Document Intelligence to extract text from documents.""" - - def __init__( - self, - endpoint: str, - api_version: str = "2024-07-31-preview", - ): - self.endpoint = endpoint - self.api_version = api_version - self.doc_intel_client = DocumentIntelligenceClient( - endpoint=self.endpoint, - api_version=self.api_version, - credential=DefaultAzureCredential(), - ) - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if extension is not supported by Document Intelligence - extension = kwargs.get("file_extension", "") - docintel_extensions = [ - ".pdf", - ".docx", - ".xlsx", - ".pptx", - ".html", - ".jpeg", - ".jpg", - ".png", - ".bmp", - ".tiff", - ".heif", - ] - if extension.lower() not in docintel_extensions: - return None - - # Get the bytestring for the local path - with open(local_path, "rb") as f: - file_bytes = f.read() - - # Certain document analysis features are not availiable for filetypes (.xlsx, .pptx, .html) - if extension.lower() in [".xlsx", ".pptx", ".html"]: - analysis_features = [] - else: - analysis_features = [ - DocumentAnalysisFeature.FORMULAS, # enable formula extraction - DocumentAnalysisFeature.OCR_HIGH_RESOLUTION, # enable high resolution OCR - DocumentAnalysisFeature.STYLE_FONT, # enable font style extraction - ] - - # Extract the text using Azure Document Intelligence - poller = self.doc_intel_client.begin_analyze_document( - model_id="prebuilt-layout", - body=AnalyzeDocumentRequest(bytes_source=file_bytes), - features=analysis_features, - output_content_format=CONTENT_FORMAT, # TODO: replace with "ContentFormat.MARKDOWN" when the bug is fixed - ) - result: AnalyzeResult = poller.result() - - # remove comments from the markdown content generated by Doc Intelligence and append to markdown string - markdown_text = re.sub(r"", "", result.content, flags=re.DOTALL) - return DocumentConverterResult( - title=None, - text_content=markdown_text, - ) - - -class FileConversionException(BaseException): - pass - - -class UnsupportedFormatException(BaseException): - pass - - -class MarkItDown: - """(In preview) An extremely simple text-based document reader, suitable for LLM use. - This reader will convert common file-types or webpages to Markdown.""" - - def __init__( - self, - requests_session: Optional[requests.Session] = None, - llm_client: Optional[Any] = None, - llm_model: Optional[str] = None, - style_map: Optional[str] = None, - exiftool_path: Optional[str] = None, - docintel_endpoint: Optional[str] = None, - # Deprecated - mlm_client: Optional[Any] = None, - mlm_model: Optional[str] = None, - ): - if requests_session is None: - self._requests_session = requests.Session() - else: - self._requests_session = requests_session - - if exiftool_path is None: - exiftool_path = os.environ.get("EXIFTOOL_PATH") - - # Handle deprecation notices - ############################# - if mlm_client is not None: - if llm_client is None: - warn( - "'mlm_client' is deprecated, and was renamed 'llm_client'.", - DeprecationWarning, - ) - llm_client = mlm_client - mlm_client = None - else: - raise ValueError( - "'mlm_client' is deprecated, and was renamed 'llm_client'. Do not use both at the same time. Just use 'llm_client' instead." - ) - - if mlm_model is not None: - if llm_model is None: - warn( - "'mlm_model' is deprecated, and was renamed 'llm_model'.", - DeprecationWarning, - ) - llm_model = mlm_model - mlm_model = None - else: - raise ValueError( - "'mlm_model' is deprecated, and was renamed 'llm_model'. Do not use both at the same time. Just use 'llm_model' instead." - ) - ############################# - - self._llm_client = llm_client - self._llm_model = llm_model - self._style_map = style_map - self._exiftool_path = exiftool_path - - self._page_converters: List[DocumentConverter] = [] - - # Register converters for successful browsing operations - # Later registrations are tried first / take higher priority than earlier registrations - # To this end, the most specific converters should appear below the most generic converters - self.register_page_converter(PlainTextConverter()) - self.register_page_converter(HtmlConverter()) - self.register_page_converter(RSSConverter()) - self.register_page_converter(WikipediaConverter()) - self.register_page_converter(YouTubeConverter()) - self.register_page_converter(BingSerpConverter()) - self.register_page_converter(DocxConverter()) - self.register_page_converter(XlsxConverter()) - self.register_page_converter(XlsConverter()) - self.register_page_converter(PptxConverter()) - self.register_page_converter(WavConverter()) - self.register_page_converter(Mp3Converter()) - self.register_page_converter(ImageConverter()) - self.register_page_converter(IpynbConverter()) - self.register_page_converter(PdfConverter()) - self.register_page_converter(ZipConverter()) - self.register_page_converter(OutlookMsgConverter()) - - # Register Document Intelligence converter at the top of the stack if endpoint is provided - if docintel_endpoint is not None: - self.register_page_converter( - DocumentIntelligenceConverter(endpoint=docintel_endpoint) - ) - - def convert( - self, source: Union[str, requests.Response, Path], **kwargs: Any - ) -> DocumentConverterResult: # TODO: deal with kwargs - """ - Args: - - source: can be a string representing a path either as string pathlib path object or url, or a requests.response object - - extension: specifies the file extension to use when interpreting the file. If None, infer from source (path, uri, content-type, etc.) - """ - - # Local path or url - if isinstance(source, str): - if ( - source.startswith("http://") - or source.startswith("https://") - or source.startswith("file://") - ): - return self.convert_url(source, **kwargs) - else: - return self.convert_local(source, **kwargs) - # Request response - elif isinstance(source, requests.Response): - return self.convert_response(source, **kwargs) - elif isinstance(source, Path): - return self.convert_local(source, **kwargs) - - def convert_local( - self, path: Union[str, Path], **kwargs: Any - ) -> DocumentConverterResult: # TODO: deal with kwargs - if isinstance(path, Path): - path = str(path) - # Prepare a list of extensions to try (in order of priority) - ext = kwargs.get("file_extension") - extensions = [ext] if ext is not None else [] - - # Get extension alternatives from the path and puremagic - base, ext = os.path.splitext(path) - self._append_ext(extensions, ext) - - for g in self._guess_ext_magic(path): - self._append_ext(extensions, g) - - # Convert - return self._convert(path, extensions, **kwargs) - - # TODO what should stream's type be? - def convert_stream( - self, stream: Any, **kwargs: Any - ) -> DocumentConverterResult: # TODO: deal with kwargs - # Prepare a list of extensions to try (in order of priority) - ext = kwargs.get("file_extension") - extensions = [ext] if ext is not None else [] - - # Save the file locally to a temporary file. It will be deleted before this method exits - handle, temp_path = tempfile.mkstemp() - fh = os.fdopen(handle, "wb") - result = None - try: - # Write to the temporary file - content = stream.read() - if isinstance(content, str): - fh.write(content.encode("utf-8")) - else: - fh.write(content) - fh.close() - - # Use puremagic to check for more extension options - for g in self._guess_ext_magic(temp_path): - self._append_ext(extensions, g) - - # Convert - result = self._convert(temp_path, extensions, **kwargs) - # Clean up - finally: - try: - fh.close() - except Exception: - pass - os.unlink(temp_path) - - return result - - def convert_url( - self, url: str, **kwargs: Any - ) -> DocumentConverterResult: # TODO: fix kwargs type - # Send a HTTP request to the URL - response = self._requests_session.get(url, stream=True) - response.raise_for_status() - return self.convert_response(response, **kwargs) - - def convert_response( - self, response: requests.Response, **kwargs: Any - ) -> DocumentConverterResult: # TODO fix kwargs type - # Prepare a list of extensions to try (in order of priority) - ext = kwargs.get("file_extension") - extensions = [ext] if ext is not None else [] - - # Guess from the mimetype - content_type = response.headers.get("content-type", "").split(";")[0] - self._append_ext(extensions, mimetypes.guess_extension(content_type)) - - # Read the content disposition if there is one - content_disposition = response.headers.get("content-disposition", "") - m = re.search(r"filename=([^;]+)", content_disposition) - if m: - base, ext = os.path.splitext(m.group(1).strip("\"'")) - self._append_ext(extensions, ext) - - # Read from the extension from the path - base, ext = os.path.splitext(urlparse(response.url).path) - self._append_ext(extensions, ext) - - # Save the file locally to a temporary file. It will be deleted before this method exits - handle, temp_path = tempfile.mkstemp() - fh = os.fdopen(handle, "wb") - result = None - try: - # Download the file - for chunk in response.iter_content(chunk_size=512): - fh.write(chunk) - fh.close() - - # Use puremagic to check for more extension options - for g in self._guess_ext_magic(temp_path): - self._append_ext(extensions, g) - - # Convert - result = self._convert(temp_path, extensions, url=response.url, **kwargs) - # Clean up - finally: - try: - fh.close() - except Exception: - pass - os.unlink(temp_path) - - return result - - def _convert( - self, local_path: str, extensions: List[Union[str, None]], **kwargs - ) -> DocumentConverterResult: - error_trace = "" - for ext in extensions + [None]: # Try last with no extension - for converter in self._page_converters: - _kwargs = copy.deepcopy(kwargs) - - # Overwrite file_extension appropriately - if ext is None: - if "file_extension" in _kwargs: - del _kwargs["file_extension"] - else: - _kwargs.update({"file_extension": ext}) - - # Copy any additional global options - if "llm_client" not in _kwargs and self._llm_client is not None: - _kwargs["llm_client"] = self._llm_client - - if "llm_model" not in _kwargs and self._llm_model is not None: - _kwargs["llm_model"] = self._llm_model - - if "style_map" not in _kwargs and self._style_map is not None: - _kwargs["style_map"] = self._style_map - - if "exiftool_path" not in _kwargs and self._exiftool_path is not None: - _kwargs["exiftool_path"] = self._exiftool_path - - # Add the list of converters for nested processing - _kwargs["_parent_converters"] = self._page_converters - - # If we hit an error log it and keep trying - try: - res = converter.convert(local_path, **_kwargs) - except Exception: - error_trace = ("\n\n" + traceback.format_exc()).strip() - - if res is not None: - # Normalize the content - res.text_content = "\n".join( - [line.rstrip() for line in re.split(r"\r?\n", res.text_content)] - ) - res.text_content = re.sub(r"\n{3,}", "\n\n", res.text_content) - - # Todo - return res - - # If we got this far without success, report any exceptions - if len(error_trace) > 0: - raise FileConversionException( - f"Could not convert '{local_path}' to Markdown. File type was recognized as {extensions}. While converting the file, the following error was encountered:\n\n{error_trace}" - ) - - # Nothing can handle it! - raise UnsupportedFormatException( - f"Could not convert '{local_path}' to Markdown. The formats {extensions} are not supported." - ) - - def _append_ext(self, extensions, ext): - """Append a unique non-None, non-empty extension to a list of extensions.""" - if ext is None: - return - ext = ext.strip() - if ext == "": - return - # if ext not in extensions: - extensions.append(ext) - - def _guess_ext_magic(self, path): - """Use puremagic (a Python implementation of libmagic) to guess a file's extension based on the first few bytes.""" - # Use puremagic to guess - try: - guesses = puremagic.magic_file(path) - - # Fix for: https://github.com/microsoft/markitdown/issues/222 - # If there are no guesses, then try again after trimming leading ASCII whitespaces. - # ASCII whitespace characters are those byte values in the sequence b' \t\n\r\x0b\f' - # (space, tab, newline, carriage return, vertical tab, form feed). - if len(guesses) == 0: - with open(path, "rb") as file: - while True: - char = file.read(1) - if not char: # End of file - break - if not char.isspace(): - file.seek(file.tell() - 1) - break - try: - guesses = puremagic.magic_stream(file) - except puremagic.main.PureError: - pass - - extensions = list() - for g in guesses: - ext = g.extension.strip() - if len(ext) > 0: - if not ext.startswith("."): - ext = "." + ext - if ext not in extensions: - extensions.append(ext) - return extensions - except FileNotFoundError: - pass - except IsADirectoryError: - pass - except PermissionError: - pass - return [] - - def register_page_converter(self, converter: DocumentConverter) -> None: - """Register a page text converter.""" - self._page_converters.insert(0, converter) From 4b625064519af97f8f0b905d352d13a31355ce08 Mon Sep 17 00:00:00 2001 From: Adam Fourney Date: Mon, 10 Feb 2025 15:24:28 -0800 Subject: [PATCH 07/33] Small typo in README. --- packages/markitdown-sample-plugin/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/markitdown-sample-plugin/README.md b/packages/markitdown-sample-plugin/README.md index 9b15ca0..06324cd 100644 --- a/packages/markitdown-sample-plugin/README.md +++ b/packages/markitdown-sample-plugin/README.md @@ -7,7 +7,7 @@ This project shows how to create a sample plugin for MarkItDown. The most important parts are as follows: -FNext, implement your custom DocumentConverter: +Next, implement your custom DocumentConverter: ```python from typing import Union From 3a5ca22a8df772ef37c2caa41198468442de4dbc Mon Sep 17 00:00:00 2001 From: Tomasz Kalinowski Date: Tue, 11 Feb 2025 10:13:17 -0500 Subject: [PATCH 08/33] Don't generate md links in 'pre' blocks (#322) --- packages/markitdown/src/markitdown/converters/_markdownify.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/markitdown/src/markitdown/converters/_markdownify.py b/packages/markitdown/src/markitdown/converters/_markdownify.py index 5b6d739..e15f607 100644 --- a/packages/markitdown/src/markitdown/converters/_markdownify.py +++ b/packages/markitdown/src/markitdown/converters/_markdownify.py @@ -33,6 +33,10 @@ class _CustomMarkdownify(markdownify.MarkdownConverter): prefix, suffix, text = markdownify.chomp(text) # type: ignore if not text: return "" + + if el.find_parent("pre") is not None: + return text + href = el.get("href") title = el.get("title") From 5ce85c236c5c456eac2f0ca7459b088d67f96250 Mon Sep 17 00:00:00 2001 From: Ruijun Gao Date: Wed, 12 Feb 2025 02:33:52 +0800 Subject: [PATCH 09/33] Fix a typo in sample RTF plugin (#320) --- .../src/markitdown_sample_plugin/_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py index c8c4fef..98e660e 100644 --- a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py @@ -23,7 +23,7 @@ class RtfConverter(DocumentConverter): """ def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a DOCX + # Bail if not a RTF extension = kwargs.get("file_extension", "") if extension.lower() != ".rtf": return None From 935da9976c9bbcc0cec6ca795ff245c8475d48fc Mon Sep 17 00:00:00 2001 From: afourney Date: Tue, 11 Feb 2025 12:36:32 -0800 Subject: [PATCH 10/33] Added priority argument to all converter constructors. (#324) * Added priority argument to all converter constructors. --- .../markitdown/src/markitdown/_markitdown.py | 13 +++----- .../src/markitdown/converters/_base.py | 31 ++++++++++++++++++- .../converters/_bing_serp_converter.py | 5 +++ .../converters/_doc_intel_converter.py | 4 +++ .../markitdown/converters/_docx_converter.py | 6 ++++ .../markitdown/converters/_html_converter.py | 5 +++ .../markitdown/converters/_image_converter.py | 7 ++++- .../markitdown/converters/_ipynb_converter.py | 5 +++ .../markitdown/converters/_media_converter.py | 11 +++++-- .../markitdown/converters/_mp3_converter.py | 7 ++++- .../converters/_outlook_msg_converter.py | 5 +++ .../markitdown/converters/_pdf_converter.py | 5 +++ .../converters/_plain_text_converter.py | 5 +++ .../markitdown/converters/_pptx_converter.py | 5 +++ .../markitdown/converters/_rss_converter.py | 5 +++ .../markitdown/converters/_wav_converter.py | 7 ++++- .../converters/_wikipedia_converter.py | 5 +++ .../markitdown/converters/_xlsx_converter.py | 7 ++++- .../converters/_youtube_converter.py | 5 +++ .../markitdown/converters/_zip_converter.py | 5 +++ packages/markitdown/tests/test_markitdown.py | 6 ++-- 21 files changed, 135 insertions(+), 19 deletions(-) diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index b7ac5bc..297f554 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -47,10 +47,6 @@ from ._exceptions import ( # Override mimetype for csv to fix issue on windows mimetypes.add_type("text/csv", ".csv") -PRIORITY_SPECIFIC_FILE_FORMAT = 0.0 -PRIORITY_GENERIC_FILE_FORMAT = 10.0 - - _plugins: Union[None | List[Any]] = None @@ -123,6 +119,8 @@ class MarkItDown: self._llm_model = kwargs.get("llm_model") self._exiftool_path = kwargs.get("exiftool_path") self._style_map = kwargs.get("style_map") + if self._exiftool_path is None: + self._exiftool_path = os.getenv("EXIFTOOL_PATH") # Register converters for successful browsing operations # Later registrations are tried first / take higher priority than earlier registrations @@ -349,11 +347,10 @@ class MarkItDown: _kwargs["_parent_converters"] = self._page_converters # If we hit an error log it and keep trying - # try: - if True: + try: res = converter.convert(local_path, **_kwargs) - # except Exception: - # error_trace = ("\n\n" + traceback.format_exc()).strip() + except Exception: + error_trace = ("\n\n" + traceback.format_exc()).strip() if res is not None: # Normalize the content diff --git a/packages/markitdown/src/markitdown/converters/_base.py b/packages/markitdown/src/markitdown/converters/_base.py index 6d0a5a4..3947797 100644 --- a/packages/markitdown/src/markitdown/converters/_base.py +++ b/packages/markitdown/src/markitdown/converters/_base.py @@ -12,7 +12,36 @@ class DocumentConverterResult: class DocumentConverter: """Abstract superclass of all DocumentConverters.""" - def __init__(self, priority: float = 0.0): + # Lower priority values are tried first. + PRIORITY_SPECIFIC_FILE_FORMAT = ( + 0.0 # e.g., .docx, .pdf, .xlsx, Or specific pages, e.g., wikipedia + ) + PRIORITY_GENERIC_FILE_FORMAT = ( + 10.0 # Near catch-all converters for mimetypes like text/*, etc. + ) + + def __init__(self, priority: float = PRIORITY_SPECIFIC_FILE_FORMAT): + """ + Initialize the DocumentConverter with a given priority. + + Priorities work as follows: By default, most converters get priority + DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT (== 0). The exception + is the PlainTextConverter, which gets priority PRIORITY_SPECIFIC_FILE_FORMAT (== 10), + with lower values being tried first (i.e., higher priority). + + Just prior to conversion, the converters are sorted by priority, using + a stable sort. This means that converters with the same priority will + remain in the same order, with the most recently registered converters + appearing first. + + We have tight control over the order of built-in converters, but + plugins can register converters in any order. A converter's priority + field reasserts some control over the order of converters. + + Plugins can register converters with any priority, to appear before or + after the built-ins. For example, a plugin with priority 9 will run + before the PlainTextConverter, but after the built-in converters. + """ self._priority = priority def convert( diff --git a/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py b/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py index b903724..d1b11a6 100644 --- a/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py +++ b/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py @@ -16,6 +16,11 @@ class BingSerpConverter(DocumentConverter): NOTE: It is better to use the Bing API """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: # Bail if not a Bing SERP extension = kwargs.get("file_extension", "") diff --git a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py index 94acc9f..835345a 100644 --- a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py +++ b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py @@ -22,9 +22,13 @@ class DocumentIntelligenceConverter(DocumentConverter): def __init__( self, + *, + priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT, endpoint: str, api_version: str = "2024-07-31-preview", ): + super().__init__(priority=priority) + self.endpoint = endpoint self.api_version = api_version self.doc_intel_client = DocumentIntelligenceClient( diff --git a/packages/markitdown/src/markitdown/converters/_docx_converter.py b/packages/markitdown/src/markitdown/converters/_docx_converter.py index fb61cca..8515f6d 100644 --- a/packages/markitdown/src/markitdown/converters/_docx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_docx_converter.py @@ -6,6 +6,7 @@ from ._base import ( DocumentConverterResult, ) +from ._base import DocumentConverter from ._html_converter import HtmlConverter @@ -14,6 +15,11 @@ class DocxConverter(HtmlConverter): Converts DOCX files to Markdown. Style information (e.g.m headings) and tables are preserved where possible. """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: # Bail if not a DOCX extension = kwargs.get("file_extension", "") diff --git a/packages/markitdown/src/markitdown/converters/_html_converter.py b/packages/markitdown/src/markitdown/converters/_html_converter.py index ae7259e..68c2536 100644 --- a/packages/markitdown/src/markitdown/converters/_html_converter.py +++ b/packages/markitdown/src/markitdown/converters/_html_converter.py @@ -8,6 +8,11 @@ from ._markdownify import _CustomMarkdownify class HtmlConverter(DocumentConverter): """Anything with content type text/html""" + def __init__( + self, priority: float = DocumentConverter.PRIORITY_GENERIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert( self, local_path: str, **kwargs: Any ) -> Union[None, DocumentConverterResult]: diff --git a/packages/markitdown/src/markitdown/converters/_image_converter.py b/packages/markitdown/src/markitdown/converters/_image_converter.py index f3dee6b..a46b67c 100644 --- a/packages/markitdown/src/markitdown/converters/_image_converter.py +++ b/packages/markitdown/src/markitdown/converters/_image_converter.py @@ -1,5 +1,5 @@ from typing import Union -from ._base import DocumentConverterResult +from ._base import DocumentConverter, DocumentConverterResult from ._media_converter import MediaConverter @@ -8,6 +8,11 @@ class ImageConverter(MediaConverter): Converts images to markdown via extraction of metadata (if `exiftool` is installed), OCR (if `easyocr` is installed), and description via a multimodal LLM (if an llm_client is configured). """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: # Bail if not an image extension = kwargs.get("file_extension", "") diff --git a/packages/markitdown/src/markitdown/converters/_ipynb_converter.py b/packages/markitdown/src/markitdown/converters/_ipynb_converter.py index cdeb478..b487f41 100644 --- a/packages/markitdown/src/markitdown/converters/_ipynb_converter.py +++ b/packages/markitdown/src/markitdown/converters/_ipynb_converter.py @@ -12,6 +12,11 @@ from .._exceptions import FileConversionException class IpynbConverter(DocumentConverter): """Converts Jupyter Notebook (.ipynb) files to Markdown.""" + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert( self, local_path: str, **kwargs: Any ) -> Union[None, DocumentConverterResult]: diff --git a/packages/markitdown/src/markitdown/converters/_media_converter.py b/packages/markitdown/src/markitdown/converters/_media_converter.py index 07d2bde..5c7d82b 100644 --- a/packages/markitdown/src/markitdown/converters/_media_converter.py +++ b/packages/markitdown/src/markitdown/converters/_media_converter.py @@ -11,6 +11,11 @@ class MediaConverter(DocumentConverter): Abstract class for multi-modal media (e.g., images and audio) """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_GENERIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def _get_metadata(self, local_path, exiftool_path=None): if not exiftool_path: which_exiftool = shutil.which("exiftool") @@ -27,10 +32,10 @@ This warning will be removed in future releases. return None else: - try: + if True: result = subprocess.run( [exiftool_path, "-json", local_path], capture_output=True, text=True ).stdout return json.loads(result)[0] - except Exception: - return None + # except Exception: + # return None diff --git a/packages/markitdown/src/markitdown/converters/_mp3_converter.py b/packages/markitdown/src/markitdown/converters/_mp3_converter.py index 6b2786b..91fd270 100644 --- a/packages/markitdown/src/markitdown/converters/_mp3_converter.py +++ b/packages/markitdown/src/markitdown/converters/_mp3_converter.py @@ -1,6 +1,6 @@ import tempfile from typing import Union -from ._base import DocumentConverterResult +from ._base import DocumentConverter, DocumentConverterResult from ._wav_converter import WavConverter from warnings import resetwarnings, catch_warnings @@ -28,6 +28,11 @@ class Mp3Converter(WavConverter): Converts MP3 files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` AND `pydub` are installed). """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: # Bail if not a MP3 extension = kwargs.get("file_extension", "") diff --git a/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py b/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py index e83001c..6764fc5 100644 --- a/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py +++ b/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py @@ -11,6 +11,11 @@ class OutlookMsgConverter(DocumentConverter): - Email body content """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert( self, local_path: str, **kwargs: Any ) -> Union[None, DocumentConverterResult]: diff --git a/packages/markitdown/src/markitdown/converters/_pdf_converter.py b/packages/markitdown/src/markitdown/converters/_pdf_converter.py index dcffc62..3a2b671 100644 --- a/packages/markitdown/src/markitdown/converters/_pdf_converter.py +++ b/packages/markitdown/src/markitdown/converters/_pdf_converter.py @@ -9,6 +9,11 @@ class PdfConverter(DocumentConverter): Converts PDFs to Markdown. Most style information is ignored, so the results are essentially plain-text. """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: # Bail if not a PDF extension = kwargs.get("file_extension", "") diff --git a/packages/markitdown/src/markitdown/converters/_plain_text_converter.py b/packages/markitdown/src/markitdown/converters/_plain_text_converter.py index 2912d24..75f74a8 100644 --- a/packages/markitdown/src/markitdown/converters/_plain_text_converter.py +++ b/packages/markitdown/src/markitdown/converters/_plain_text_converter.py @@ -9,6 +9,11 @@ from ._base import DocumentConverter, DocumentConverterResult class PlainTextConverter(DocumentConverter): """Anything with content type text/plain""" + def __init__( + self, priority: float = DocumentConverter.PRIORITY_GENERIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert( self, local_path: str, **kwargs: Any ) -> Union[None, DocumentConverterResult]: diff --git a/packages/markitdown/src/markitdown/converters/_pptx_converter.py b/packages/markitdown/src/markitdown/converters/_pptx_converter.py index a48880a..afb37a0 100644 --- a/packages/markitdown/src/markitdown/converters/_pptx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_pptx_converter.py @@ -14,6 +14,11 @@ class PptxConverter(HtmlConverter): Converts PPTX files to Markdown. Supports heading, tables and images with alt text. """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def _get_llm_description( self, llm_client, llm_model, image_blob, content_type, prompt=None ): diff --git a/packages/markitdown/src/markitdown/converters/_rss_converter.py b/packages/markitdown/src/markitdown/converters/_rss_converter.py index eb2f09c..b279c85 100644 --- a/packages/markitdown/src/markitdown/converters/_rss_converter.py +++ b/packages/markitdown/src/markitdown/converters/_rss_converter.py @@ -9,6 +9,11 @@ from ._base import DocumentConverter, DocumentConverterResult class RssConverter(DocumentConverter): """Convert RSS / Atom type to markdown""" + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert( self, local_path: str, **kwargs ) -> Union[None, DocumentConverterResult]: diff --git a/packages/markitdown/src/markitdown/converters/_wav_converter.py b/packages/markitdown/src/markitdown/converters/_wav_converter.py index 6fc8932..3c8d842 100644 --- a/packages/markitdown/src/markitdown/converters/_wav_converter.py +++ b/packages/markitdown/src/markitdown/converters/_wav_converter.py @@ -1,5 +1,5 @@ from typing import Union -from ._base import DocumentConverterResult +from ._base import DocumentConverter, DocumentConverterResult from ._media_converter import MediaConverter # Optional Transcription support @@ -17,6 +17,11 @@ class WavConverter(MediaConverter): Converts WAV files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` is installed). """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: # Bail if not a WAV extension = kwargs.get("file_extension", "") diff --git a/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py b/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py index 4097ef0..f27fe23 100644 --- a/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py +++ b/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py @@ -10,6 +10,11 @@ from ._markdownify import _CustomMarkdownify class WikipediaConverter(DocumentConverter): """Handle Wikipedia pages separately, focusing only on the main document content.""" + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert( self, local_path: str, **kwargs: Any ) -> Union[None, DocumentConverterResult]: diff --git a/packages/markitdown/src/markitdown/converters/_xlsx_converter.py b/packages/markitdown/src/markitdown/converters/_xlsx_converter.py index 683349c..2bdfd5d 100644 --- a/packages/markitdown/src/markitdown/converters/_xlsx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_xlsx_converter.py @@ -2,7 +2,7 @@ from typing import Union import pandas as pd -from ._base import DocumentConverterResult +from ._base import DocumentConverter, DocumentConverterResult from ._html_converter import HtmlConverter @@ -11,6 +11,11 @@ class XlsxConverter(HtmlConverter): Converts XLSX files to Markdown, with each sheet presented as a separate Markdown table. """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: # Bail if not a XLSX extension = kwargs.get("file_extension", "") diff --git a/packages/markitdown/src/markitdown/converters/_youtube_converter.py b/packages/markitdown/src/markitdown/converters/_youtube_converter.py index fe198e8..b961b88 100644 --- a/packages/markitdown/src/markitdown/converters/_youtube_converter.py +++ b/packages/markitdown/src/markitdown/converters/_youtube_converter.py @@ -19,6 +19,11 @@ except ModuleNotFoundError: class YouTubeConverter(DocumentConverter): """Handle YouTube specially, focusing on the video title, description, and transcript.""" + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert( self, local_path: str, **kwargs: Any ) -> Union[None, DocumentConverterResult]: diff --git a/packages/markitdown/src/markitdown/converters/_zip_converter.py b/packages/markitdown/src/markitdown/converters/_zip_converter.py index 918c357..026900d 100644 --- a/packages/markitdown/src/markitdown/converters/_zip_converter.py +++ b/packages/markitdown/src/markitdown/converters/_zip_converter.py @@ -45,6 +45,11 @@ class ZipConverter(DocumentConverter): - Cleans up temporary files after processing """ + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) + def convert( self, local_path: str, **kwargs: Any ) -> Union[None, DocumentConverterResult]: diff --git a/packages/markitdown/tests/test_markitdown.py b/packages/markitdown/tests/test_markitdown.py index be71722..efd45ac 100644 --- a/packages/markitdown/tests/test_markitdown.py +++ b/packages/markitdown/tests/test_markitdown.py @@ -327,8 +327,8 @@ def test_markitdown_llm() -> None: if __name__ == "__main__": """Runs this file's tests from the command line.""" - # test_markitdown_remote() - # test_markitdown_local() + test_markitdown_remote() + test_markitdown_local() test_markitdown_exiftool() - # test_markitdown_deprecation() # test_markitdown_llm() + print("All tests passed!") From 97eeed5f325d15ab3f1bc65e6a4f146c4e7e0680 Mon Sep 17 00:00:00 2001 From: KennyZhang1 <90438893+KennyZhang1@users.noreply.github.com> Date: Tue, 11 Feb 2025 19:01:46 -0500 Subject: [PATCH 11/33] Doc Intelligence fixes for refactored code (#325) * added priority flag to doc intel converter constructor * fixed analysis features bug for docx --- .../src/markitdown/converters/_doc_intel_converter.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py index 835345a..ed8aabf 100644 --- a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py +++ b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py @@ -1,4 +1,5 @@ from typing import Any, Union +import re # Azure imports from azure.ai.documentintelligence import DocumentIntelligenceClient @@ -36,6 +37,7 @@ class DocumentIntelligenceConverter(DocumentConverter): api_version=self.api_version, credential=DefaultAzureCredential(), ) + self._priority = priority def convert( self, local_path: str, **kwargs: Any @@ -62,8 +64,8 @@ class DocumentIntelligenceConverter(DocumentConverter): with open(local_path, "rb") as f: file_bytes = f.read() - # Certain document analysis features are not availiable for filetypes (.xlsx, .pptx, .html) - if extension.lower() in [".xlsx", ".pptx", ".html"]: + # Certain document analysis features are not availiable for office filetypes (.xlsx, .pptx, .html, .docx) + if extension.lower() in [".xlsx", ".pptx", ".html", ".docx"]: analysis_features = [] else: analysis_features = [ From dbdf2c0c1031dadc257a20f03cf9091907cb5972 Mon Sep 17 00:00:00 2001 From: afourney Date: Tue, 11 Feb 2025 20:42:50 -0800 Subject: [PATCH 12/33] Added CLI tests. (#327) --- .../markitdown/src/markitdown/__init__.py | 2 + packages/markitdown/tests/test_cli.py | 119 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 packages/markitdown/tests/test_cli.py diff --git a/packages/markitdown/src/markitdown/__init__.py b/packages/markitdown/src/markitdown/__init__.py index 5407233..59d9750 100644 --- a/packages/markitdown/src/markitdown/__init__.py +++ b/packages/markitdown/src/markitdown/__init__.py @@ -2,6 +2,7 @@ # # SPDX-License-Identifier: MIT +from .__about__ import __version__ from ._markitdown import MarkItDown from ._exceptions import ( MarkItDownException, @@ -12,6 +13,7 @@ from ._exceptions import ( from .converters import DocumentConverter, DocumentConverterResult __all__ = [ + "__version__", "MarkItDown", "DocumentConverter", "DocumentConverterResult", diff --git a/packages/markitdown/tests/test_cli.py b/packages/markitdown/tests/test_cli.py new file mode 100644 index 0000000..1e2b095 --- /dev/null +++ b/packages/markitdown/tests/test_cli.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python3 -m pytest +import os +import subprocess +import pytest +from markitdown import __version__ + +try: + from .test_markitdown import TEST_FILES_DIR, DOCX_TEST_STRINGS +except ImportError: + from test_markitdown import TEST_FILES_DIR, DOCX_TEST_STRINGS + + +@pytest.fixture(scope="session") +def shared_tmp_dir(tmp_path_factory): + return tmp_path_factory.mktemp("pytest_tmp") + + +def test_version(shared_tmp_dir) -> None: + result = subprocess.run( + ["python", "-m", "markitdown", "--version"], capture_output=True, text=True + ) + + assert result.returncode == 0, f"CLI exited with error: {result.stderr}" + assert __version__ in result.stdout, f"Version not found in output: {result.stdout}" + + +def test_invalid_flag(shared_tmp_dir) -> None: + result = subprocess.run( + ["python", "-m", "markitdown", "--foobar"], capture_output=True, text=True + ) + + assert result.returncode != 0, f"CLI exited with error: {result.stderr}" + assert ( + "unrecognized arguments" in result.stderr + ), f"Expected 'unrecognized arguments' to appear in STDERR" + assert "SYNTAX" in result.stderr, f"Expected 'SYNTAX' to appear in STDERR" + + +def test_output_to_stdout(shared_tmp_dir) -> None: + # DOC X + result = subprocess.run( + ["python", "-m", "markitdown", os.path.join(TEST_FILES_DIR, "test.docx")], + capture_output=True, + text=True, + ) + + assert result.returncode == 0, f"CLI exited with error: {result.stderr}" + for test_string in DOCX_TEST_STRINGS: + assert ( + test_string in result.stdout + ), f"Expected string not found in output: {test_string}" + + +def test_output_to_file(shared_tmp_dir) -> None: + # DOC X, flag -o at the end + docx_output_file_1 = os.path.join(shared_tmp_dir, "test_docx_1.md") + result = subprocess.run( + [ + "python", + "-m", + "markitdown", + os.path.join(TEST_FILES_DIR, "test.docx"), + "-o", + docx_output_file_1, + ], + capture_output=True, + text=True, + ) + + assert result.returncode == 0, f"CLI exited with error: {result.stderr}" + assert os.path.exists( + docx_output_file_1 + ), f"Output file not created: {docx_output_file_1}" + + with open(docx_output_file_1, "r") as f: + output = f.read() + for test_string in DOCX_TEST_STRINGS: + assert ( + test_string in output + ), f"Expected string not found in output: {test_string}" + + # DOC X, flag -o at the beginning + docx_output_file_2 = os.path.join(shared_tmp_dir, "test_docx_2.md") + result = subprocess.run( + [ + "python", + "-m", + "markitdown", + "-o", + docx_output_file_2, + os.path.join(TEST_FILES_DIR, "test.docx"), + ], + capture_output=True, + text=True, + ) + + assert result.returncode == 0, f"CLI exited with error: {result.stderr}" + assert os.path.exists( + docx_output_file_2 + ), f"Output file not created: {docx_output_file_2}" + + with open(docx_output_file_2, "r") as f: + output = f.read() + for test_string in DOCX_TEST_STRINGS: + assert ( + test_string in output + ), f"Expected string not found in output: {test_string}" + + +if __name__ == "__main__": + """Runs this file's tests from the command line.""" + import tempfile + + with tempfile.TemporaryDirectory() as tmp_dir: + test_version(tmp_dir) + test_invalid_flag(tmp_dir) + test_output_to_stdout(tmp_dir) + test_output_to_file(tmp_dir) + print("All tests passed!") From e4b419ba4099ed5463627ab58a99e025780d20eb Mon Sep 17 00:00:00 2001 From: afourney Date: Thu, 27 Feb 2025 23:09:33 -0800 Subject: [PATCH 13/33] Pin Markdownify version. (#1069) * Pin markdownify version. TODO: update code for compatibility with Markdownify 1.0.0 --- packages/markitdown/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/markitdown/pyproject.toml b/packages/markitdown/pyproject.toml index 2a4e203..a321fee 100644 --- a/packages/markitdown/pyproject.toml +++ b/packages/markitdown/pyproject.toml @@ -27,7 +27,7 @@ dependencies = [ "beautifulsoup4", "requests", "mammoth", - "markdownify", + "markdownify~=0.14.1", "numpy", "python-pptx", "pandas", From d0ed74fdf4708e9931d8bc4dc5c711b1e9d444fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menezes?= <77670471+menezesandre@users.noreply.github.com> Date: Fri, 28 Feb 2025 07:11:27 +0000 Subject: [PATCH 14/33] Fix UnboundLocalError in MarkItDown._convert (#1038) Initialize `res` at the beginning of `_convert`. If the first converter raises an exception, then the `res` variable was not initialized and we got an error when checking `if res is not None` --- packages/markitdown/src/markitdown/_markitdown.py | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index 297f554..7c8d006 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -312,6 +312,7 @@ class MarkItDown: def _convert( self, local_path: str, extensions: List[Union[str, None]], **kwargs ) -> DocumentConverterResult: + res: Union[None, DocumentConverterResult] = None error_trace = "" # Create a copy of the page_converters list, sorted by priority. From a87fbf01ee663bae6a76cc6e076372fcfc832d9c Mon Sep 17 00:00:00 2001 From: tanreinama Date: Fri, 28 Feb 2025 16:16:09 +0900 Subject: [PATCH 15/33] add necessary imports (#861) * add necessary imports --- .../markitdown/src/markitdown/converters/_image_converter.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/markitdown/src/markitdown/converters/_image_converter.py b/packages/markitdown/src/markitdown/converters/_image_converter.py index a46b67c..3c848dd 100644 --- a/packages/markitdown/src/markitdown/converters/_image_converter.py +++ b/packages/markitdown/src/markitdown/converters/_image_converter.py @@ -1,6 +1,8 @@ from typing import Union from ._base import DocumentConverter, DocumentConverterResult from ._media_converter import MediaConverter +import base64 +import mimetypes class ImageConverter(MediaConverter): From a394cc7c2738c8b5395fd2c55824e3d85cd6307d Mon Sep 17 00:00:00 2001 From: Nima Akbarzadeh Date: Fri, 28 Feb 2025 08:17:54 +0100 Subject: [PATCH 16/33] fix: Implement retry logic for YouTube transcript fetching and fix URL decoding issue (#1035) * fix: add error handling, refactor _findKey to use json.items() * fix: improve metadata and description extraction logic * fix: improve YouTube transcript extraction reliability * fix: implement retry logic for YouTube transcript fetching and fix URL decoding issue * fix(readme): add youtube URLs as markitdown supports --- README.md | 45 ++++----- .../converters/_youtube_converter.py | 97 +++++++++++++------ packages/markitdown/tests/test_markitdown.py | 6 +- 3 files changed, 93 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 8ac2fe3..70f188d 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ MarkItDown is a utility for converting various files to Markdown (e.g., for indexing, text analysis, etc). It supports: + - PDF - PowerPoint - Word @@ -18,9 +19,10 @@ It supports: - HTML - Text-based formats (CSV, JSON, XML) - ZIP files (iterates over contents) +- Youtube URLs - ... and more! -To install MarkItDown, use pip: `pip install markitdown`. Alternatively, you can install it from the source: +To install MarkItDown, use pip: `pip install markitdown`. Alternatively, you can install it from the source: ```bash git clone git@github.com:microsoft/markitdown.git @@ -74,7 +76,6 @@ markitdown path-to-file.pdf -o document.md -d -e " output.md ``` - + ## Contributing -This project welcomes contributions and suggestions. Most contributions require you to agree to a +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. @@ -134,13 +135,12 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio You can help by looking at issues or helping review PRs. Any issue or PR is welcome, but we have also marked some as 'open for contribution' and 'open for reviewing' to help facilitate community contributions. These are ofcourse just suggestions and you are welcome to contribute in any way you like. -
-| | All | Especially Needs Help from Community | -|-----------------------|------------------------------------------|------------------------------------------------------------------------------------------| -| **Issues** | [All Issues](https://github.com/microsoft/markitdown/issues) | [Issues open for contribution](https://github.com/microsoft/markitdown/issues?q=is%3Aissue+is%3Aopen+label%3A%22open+for+contribution%22) | -| **PRs** | [All PRs](https://github.com/microsoft/markitdown/pulls) | [PRs open for reviewing](https://github.com/microsoft/markitdown/pulls?q=is%3Apr+is%3Aopen+label%3A%22open+for+reviewing%22) | +| | All | Especially Needs Help from Community | +| ---------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | +| **Issues** | [All Issues](https://github.com/microsoft/markitdown/issues) | [Issues open for contribution](https://github.com/microsoft/markitdown/issues?q=is%3Aissue+is%3Aopen+label%3A%22open+for+contribution%22) | +| **PRs** | [All PRs](https://github.com/microsoft/markitdown/pulls) | [PRs open for reviewing](https://github.com/microsoft/markitdown/pulls?q=is%3Apr+is%3Aopen+label%3A%22open+for+reviewing%22) |
@@ -148,22 +148,24 @@ You can help by looking at issues or helping review PRs. Any issue or PR is welc - Navigate to the MarkItDown package: - ```sh - cd packages/markitdown - ``` + ```sh + cd packages/markitdown + ``` - Install `hatch` in your environment and run tests: - ```sh - pip install hatch # Other ways of installing hatch: https://hatch.pypa.io/dev/install/ - hatch shell - hatch test - ``` + + ```sh + pip install hatch # Other ways of installing hatch: https://hatch.pypa.io/dev/install/ + hatch shell + hatch test + ``` (Alternative) Use the Devcontainer which has all the dependencies installed: - ```sh - # Reopen the project in Devcontainer and run: - hatch test - ``` + + ```sh + # Reopen the project in Devcontainer and run: + hatch test + ``` - Run pre-commit checks before submitting a PR: `pre-commit run --all-files` @@ -171,7 +173,6 @@ You can help by looking at issues or helping review PRs. Any issue or PR is welc You can also contribute by creating and sharing 3rd party plugins. See `packages/markitdown-sample-plugin` for more details. - ## Trademarks This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft diff --git a/packages/markitdown/src/markitdown/converters/_youtube_converter.py b/packages/markitdown/src/markitdown/converters/_youtube_converter.py index b961b88..e61b208 100644 --- a/packages/markitdown/src/markitdown/converters/_youtube_converter.py +++ b/packages/markitdown/src/markitdown/converters/_youtube_converter.py @@ -1,4 +1,7 @@ import re +import json +import urllib.parse +import time from typing import Any, Union, Dict, List from urllib.parse import parse_qs, urlparse @@ -13,7 +16,7 @@ try: IS_YOUTUBE_TRANSCRIPT_CAPABLE = True except ModuleNotFoundError: - pass + IS_YOUTUBE_TRANSCRIPT_CAPABLE = False class YouTubeConverter(DocumentConverter): @@ -24,6 +27,20 @@ class YouTubeConverter(DocumentConverter): ): super().__init__(priority=priority) + def retry_operation(self, operation, retries=3, delay=2): + """Retries the operation if it fails.""" + attempt = 0 + while attempt < retries: + try: + return operation() # Attempt the operation + except Exception as e: + print(f"Attempt {attempt + 1} failed: {e}") + if attempt < retries - 1: + time.sleep(delay) # Wait before retrying + attempt += 1 + # If all attempts fail, raise the last exception + raise Exception(f"Operation failed after {retries} attempts.") + def convert( self, local_path: str, **kwargs: Any ) -> Union[None, DocumentConverterResult]: @@ -32,38 +49,50 @@ class YouTubeConverter(DocumentConverter): if extension.lower() not in [".html", ".htm"]: return None url = kwargs.get("url", "") + + url = urllib.parse.unquote(url) + url = url.replace(r"\?", "?").replace(r"\=", "=") + if not url.startswith("https://www.youtube.com/watch?"): return None - # Parse the file - soup = None - with open(local_path, "rt", encoding="utf-8") as fh: - soup = BeautifulSoup(fh.read(), "html.parser") + # Parse the file with error handling + try: + with open(local_path, "rt", encoding="utf-8") as fh: + soup = BeautifulSoup(fh.read(), "html.parser") + except Exception as e: + print(f"Error reading YouTube page: {e}") + return None + + if not soup.title or not soup.title.string: + return None # Read the meta tags - assert soup.title is not None and soup.title.string is not None metadata: Dict[str, str] = {"title": soup.title.string} for meta in soup(["meta"]): for a in meta.attrs: if a in ["itemprop", "property", "name"]: - metadata[meta[a]] = meta.get("content", "") + content = meta.get("content", "") + if content: # Only add non-empty content + metadata[meta[a]] = content break - # We can also try to read the full description. This is more prone to breaking, since it reaches into the page implementation + # Try reading the description try: for script in soup(["script"]): - content = script.text + if not script.string: # Skip empty scripts + continue + content = script.string if "ytInitialData" in content: - lines = re.split(r"\r?\n", content) - obj_start = lines[0].find("{") - obj_end = lines[0].rfind("}") - if obj_start >= 0 and obj_end >= 0: - data = json.loads(lines[0][obj_start : obj_end + 1]) - attrdesc = self._findKey(data, "attributedDescriptionBodyText") # type: ignore - if attrdesc: - metadata["description"] = str(attrdesc["content"]) + match = re.search(r"var ytInitialData = ({.*?});", content) + if match: + data = json.loads(match.group(1)) + attrdesc = self._findKey(data, "attributedDescriptionBodyText") + if attrdesc and isinstance(attrdesc, dict): + metadata["description"] = str(attrdesc.get("content", "")) break - except Exception: + except Exception as e: + print(f"Error extracting description: {e}") pass # Start preparing the page @@ -99,21 +128,29 @@ class YouTubeConverter(DocumentConverter): transcript_text = "" parsed_url = urlparse(url) # type: ignore params = parse_qs(parsed_url.query) # type: ignore - if "v" in params: - assert isinstance(params["v"][0], str) + if "v" in params and params["v"][0]: video_id = str(params["v"][0]) try: youtube_transcript_languages = kwargs.get( "youtube_transcript_languages", ("en",) ) - # Must be a single transcript. - transcript = YouTubeTranscriptApi.get_transcript(video_id, languages=youtube_transcript_languages) # type: ignore - transcript_text = " ".join([part["text"] for part in transcript]) # type: ignore + # Retry the transcript fetching operation + transcript = self.retry_operation( + lambda: YouTubeTranscriptApi.get_transcript( + video_id, languages=youtube_transcript_languages + ), + retries=3, # Retry 3 times + delay=2, # 2 seconds delay between retries + ) + if transcript: + transcript_text = " ".join( + [part["text"] for part in transcript] + ) # type: ignore # Alternative formatting: # formatter = TextFormatter() # formatter.format_transcript(transcript) - except Exception: - pass + except Exception as e: + print(f"Error fetching transcript: {e}") if transcript_text: webpage_text += f"\n### Transcript\n{transcript_text}\n" @@ -131,23 +168,23 @@ class YouTubeConverter(DocumentConverter): keys: List[str], default: Union[str, None] = None, ) -> Union[str, None]: + """Get first non-empty value from metadata matching given keys.""" for k in keys: if k in metadata: return metadata[k] return default def _findKey(self, json: Any, key: str) -> Union[str, None]: # TODO: Fix json type + """Recursively search for a key in nested dictionary/list structures.""" if isinstance(json, list): for elm in json: ret = self._findKey(elm, key) if ret is not None: return ret elif isinstance(json, dict): - for k in json: + for k, v in json.items(): if k == key: return json[k] - else: - ret = self._findKey(json[k], key) - if ret is not None: - return ret + if result := self._findKey(v, key): + return result return None diff --git a/packages/markitdown/tests/test_markitdown.py b/packages/markitdown/tests/test_markitdown.py index efd45ac..55afcc3 100644 --- a/packages/markitdown/tests/test_markitdown.py +++ b/packages/markitdown/tests/test_markitdown.py @@ -184,9 +184,9 @@ def test_markitdown_remote() -> None: # Youtube # TODO: This test randomly fails for some reason. Haven't been able to repro it yet. Disabling until I can debug the issue - # result = markitdown.convert(YOUTUBE_TEST_URL) - # for test_string in YOUTUBE_TEST_STRINGS: - # assert test_string in result.text_content + result = markitdown.convert(YOUTUBE_TEST_URL) + for test_string in YOUTUBE_TEST_STRINGS: + assert test_string in result.text_content def test_markitdown_local() -> None: From e82e0c137271a0b4c2dee9375efdc43abc483004 Mon Sep 17 00:00:00 2001 From: Matthew Powers <121959840+C0dingMast3r@users.noreply.github.com> Date: Fri, 28 Feb 2025 02:21:51 -0500 Subject: [PATCH 17/33] Add Support For PPTX Shape Groups (Fix in code design to not miss out on slide content) (#331) * Adds support for Shape Groups * Update to Test PPtx for nested shape * This line was accidentally removed and is added back here --- .../markitdown/converters/_pptx_converter.py | 12 +++++++++++- .../markitdown/tests/test_files/test.pptx | Bin 124277 -> 127413 bytes 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/markitdown/src/markitdown/converters/_pptx_converter.py b/packages/markitdown/src/markitdown/converters/_pptx_converter.py index afb37a0..76c481a 100644 --- a/packages/markitdown/src/markitdown/converters/_pptx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_pptx_converter.py @@ -64,7 +64,9 @@ class PptxConverter(HtmlConverter): md_content += f"\n\n\n" title = slide.shapes.title - for shape in slide.shapes: + + def get_shape_content(shape, **kwargs): + nonlocal md_content # Pictures if self._is_picture(shape): # https://github.com/scanny/python-pptx/pull/512#issuecomment-1713100069 @@ -134,6 +136,14 @@ class PptxConverter(HtmlConverter): else: md_content += shape.text + "\n" + # Group Shapes + if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.GROUP: + for subshape in shape.shapes: + get_shape_content(subshape, **kwargs) + + for shape in slide.shapes: + get_shape_content(shape, **kwargs) + md_content = md_content.strip() if slide.has_notes_slide: diff --git a/packages/markitdown/tests/test_files/test.pptx b/packages/markitdown/tests/test_files/test.pptx index ea1bbcb0f84f4e1007be35f2262173529215e484..e6d16f3cbb7836ff92b701b5fa61d92c165c50ab 100644 GIT binary patch delta 16933 zcmZ8|Wk4KDvo?!Ma1ZVf+})kvmOzl;?yifwFR-|~1t+)#2@>30g1b8($$P)|+!bR$$ceyC5c7{R$XtuWWk144pS6J) zr?6B#K{@n_alR@ILd84>yc{{_p&0>`)6*Tc3>spyflqezSF#CkvfAGxUNf*%Z`iwP!^Whhu5^;-<}Wf z!nnwK1|*%}G8X@)gKhfytQ5x)fxnenvnTT@DjJ1fFtDsHiYDd2m`)amahxW5uFsy( zr6CyZ!=gCeM_`|2`)q4;v1rV{8lCbX&6Y=zjOQ?O-RBgV#FOT39!a#Sxnc1;Q`S_^ z9bR|DRtsi8NBCxWOw6KY3gz;}$~FDPsYN5+Qnz+MGuE&PAsJoLOg8 zilClqgYUyYxb&c5zUq2rX9b#);KmaevchWFgg)%CSQBCOqV(T*?NU}8#YyFT89zb; z%u6GisM6y4rcOWkbdAhVh)bCZ3O}LLDo`HI5JKxPB1@KtRAj*V#hTK?2Jp3zk;H zl$Fs+QCSpB-SX2(5=!gs>~tzxCT(H7QrXQEJLD7gy^XYQLdY!5J_`ME{539DTwnR| zrLB!X*9ixqB4AdF;U0$~d+gU(kf;G^ow8&2i%%o+#l_1loi?L9pkyLnuVB$e8tBF4@kS%V1jA@2WFjpn3*wfSEzPCxhLh>;263%`~YX z!cl?ayEa-#Ilk<;=Aq>d&xfVSgc1T3pbE;O)L?>n%Frho@HSBoc*KDQG)^bmt#ZgL zyv59wPM&{DzLXT#fj~}IeyF^Zr>a|jz&;UD&ciGlFQ|K}hc#2Wt_>in_cNhSex;UE zyQc>#KWxTmY$G_K!&a(o)_o}=OuW7IW}AwI9`0xNO8V{y z0YOoQ+aJK$c3w1k1JeF7tN0(^q+lUnP)+T2&4cyP(K1W@S1{DybuQK#!rVE z<*>60eo)y0APFTBe;U2Ehna+udwly35q`?J4>)#shy*1m|vjz(JBpsFa`5$OgCN)ezJjp z=es4(5IIOJJi6m2iNt~{lOok>X@!IeH}kyBV)RZFa)a|+3*TS$R7y{6iWV5 zmxMHeh3Frer+^Fx0pUguipRwPax%HwSRZMx#B4QUcQB8;kve~CkT`Hdvm^aEOWt*4 zTAd{TA)R2uiBYI}^+XAehP9{bze*`$hlu49kavuEUAqvvw-MW)g+JD{gf%L^xezR= zvc18(#vA(NU7;k@ZcE^-b)I`NKkcZ`i&OS_B8l^hLM8JrC;r-TQd)Wo;8cyJ<%)XX z_5Pv$>jCJ+*jx^}Zoyuxcvd^?#h490!ewT1Lu2mKyDUcjRaHQfHzyr$J7lR1dv^?` zytX#`@W^iH$Z7I$ONps&jRie*J(?b;y5CN3%Sot;HZZI{>l0L%O5JJ6)q4hd90j^> z;=o_!a*gx9309dO*sF*;fvo~tB}@QjB-TYphS?tiEWOi=t?JP~+xN?BWR>7?pGRBW>(zUcATV4F%WOJ=vI87PQp03zNLeQHV!*ze%c*&9QlA zpcqb@_a2sByJT%mXYXcZiVxppOxH~{<1X=1PY{NBgvg#nXB@-Q0Aapi4P~!LMG^>{ zDSyFjBWNjf*Kn?MxW;2$C!AwHCvSN2B#y(E4eUYzd06sKFx0X$_qwiAb`W?qlbGCd z!$OREw0)qb?$dVhReVL`pT6S;jYv8Ku*z~ol-*n4o;`}%6T^8i4w2YzLnj5HL!I5lHMAm7|m zcV+FTUblHAwc)U~7JFxTXiF&VYb@{^#-Cu-0c)Fz zQ4y!P3Afy=&4ZxZ$%YPa93@(Y8G$DJLhkfh8x&uGCJfo>sohdNdU5M*@2AE0oVRq$;fK$}0d0l{%UY9= z3iB~0a!5Cfodf>pOK>0sI_r8IBTr3aJ_QdVI#f&(%m7vH7U6_S z9G>$Nkuy2rCIufN#>(nK8um)k=Wf5Hb}!*)4IJo;cgk>BHk95JRKDie`nt=DiRGQ* zBc4#t=AsLJt65(}O0~E}z6EAZpKoCDgm0D7`vZ#`XlHqC4tJz5M8>U&X@anJ|6Md=P^*7ET4n21Fm3D$b`;X9|_l-!pMBk zF}^PZ(;gN8+Jkzq?AP&>!PX;4P|AuG@0la8gpldCu{{KBUVCnAs5&Jk`Qg7BR0 z(omf6Kc$?97rz$I2~PG>2nzg90TxG64-a{wPIz0lQ) zM&DzV=4nDpOsO!fw*wZ>Je9*<>g}U*yg_*-16zulL}UnlXW{cM7!mKYyt;szZhM9G zUhWdvq-)A83CIr#2b7LT1>gjABTm=3lA!|-7ahXC$iA7sX0Ua!6ifhM(wb!;3trzT zoEO~B=cvWS=iJ3~)-yvEu3HF;r)d@i%Ad>Lk0v%XA9Uw~-S0Cgcb|CTj9VY8=!;=W zQ`XThbWwS`N(b?n$*;16R+h=6Eqd5h5m3+%L~?b#eHwg%Bg~y-k}6bU95z0P70!-A z^+zNtWB!hS{jT*hxFVbjn9pD@z6VDK0hiU(?YQT^8D9)CMo*A6y_l-&bKsEQB%p2d3lP0L_Gpw0kue&M~!H?q%v}kBfi#)J3 zTDO?O9Tz;%HOwrJV-R6Th48rA&<5v#y59Bj6EA1JDs8+KIN||X{A<87+T$wa7qMYq zlAxg7%_tUi8|V!&&WcJ-cPCZz+HdO$ZrJZmhDGY*D{#wL+0>rbJV$Jz)`Y(^SZ^bRqL3zub zIQQ|j<#eAd+B;ps2Y+l*4Dr`X;dQ=p@uiij)-`IAIcY$;ToHSVG!T`rAfc7cj1XC4%EY z3=Y3ehLY~$TxG6kkK@V6iO-3^@5o%G5>$aQ8jy=)A5AhW^k(Ks)+Gh?X3z-N`vmop z`ccmK1odEk1N0`hTspfydbO=`yRQ&`NGx7CB0@M^77(5O3pc{{R~Oi^asqJ(+G2fa-fBmP>06OTf_VXA+QsofPPmeHsy4w8`)l z8UjKR1GFJa4tnK)1Fkq`aA9?v%CGt7&LPUkKniG?`2{PQW&D^@AchE>9S-V5Jf5|s zX7{MPak!uq#8}sTrED<&8)A>(a?bDSkmHZu!UP?6W+KtR3@lD zf4XKuTU{yo+a`5RmmcS)5bx;Ifbi>8t?>JU3(C%;#v#ZkS0K+2?u}IG%b-JuAw`hVq*s%|B}xjSQ^{4@O7?9jwU8UpY7{` z?O?k8mOu9+xHiI}X8s#adXw8cPWly!m6=c%FORx3C!ZTXAzLUrwb<^!oda9RLVjfh z&dmS=1?xxl2(}cmgMO?&I%E~8Hc~3zWVBe|WGk!ihXNo=;*;jD$(|>iOa+ZW+r8NX z$q7ynlc@&)l%gna$t=v&&JZI=m}es8jU_=T7UdL^V7yP|f5^(*m0bkwH+E^BXJ6!A z++{`{@=`!A^iFdLpprHh-$Wl7FE4nLE~^-vK&=4UcVCmg3GV=zjKI6B#0y6u6b!Zg zau3@#&jF?eMLjIH_w9zQkd#J#r)R!CVaM|yXk+9e67VsjFcmCGYN-fLJ+)l60zI^G zz7Y6+ta%~A3GKw;nk$ZhQ)t|Jg2_dCiFd)9AFuqFcIno!H>tGLGc}{KK655{? z>jI>5XSwO{miNQt;_pI{$%vMNFtF-ESQ75KDZLd`*BhAi!*s14 znC)8Y`^{;M%wrG=H=mJO_QGS0d?$hJnG(4_g=N8qyKhnz&dG;DP+&6Z4o}sDYus#hHMmoE6T~+vk#R!O1 zIQ}b-f%;vug`Wx@G(#9&c)}eVye;zYe%g~*8zwTBy1kct1^2MMtYk~ynV0=Bj>FML z-d0f_uc9EYkLGaV?{lD`Ho^~~Htdp;X90R;2xTr;!W9=O|=!cUyb7_3#n+hN+IrKBE8VG&^cN zsYn=_K`9z#D93nI*6B5KQiXrhWHyt?c{my=ixbzS64HM$rNsH!(>m!kqKwJJfrN_7v2}J!%qM< zqDmT-gwor(sEqn&U91!2qk#er`pcNSzlRf}!+m#T;~@$2{LG5|in{U?ZX4vZg4RJv z=$ji9sIntT)>4b20u7I%jZZJTUHtjHE6W4~tZiEL5c#^2cK{c?57oGtw96mVh~ zvR`aA)RG##EIY*`qLmncWe9mjj^cliBt+T~>X0lYyYoAZpXf(yb3RV&mg0ag%f$K6 z6P}n`!C3Nv)ki`vCRYtQb|QoKJdS6YP@U7~{(I#q? zfIYjfkbfdzh`ZV;+&nN45F*%rHH$wJHV}+8O-HG<2wPyo(uDf9eZim(%s1!OQpx$& zAgGvaOi8t%nC5!22;EUbdyvt4nsG|uvRyn@bvU$uxB#|ccbmZ6}PwY^kwhII)wi&0z^oE}29Z-Kh`O z6_z}V37?gnIAoc9P|Zy{Xw8y;gd8Rfva>Lj+^Puj|RsJ1GcrXokQ^L{LbMv@!>*!*U?uM&{!Wzm#(isX70}0W@afpJHJA|7_Jj|DFcM9L+j|Lw1?I~BmcV@thSrewE z4&723k1w&CDI7)n63zuvIo{bJNHXXS{4~h zjXI1rG0}b8CU)$+iY+)*LgxINGW$e|nq3c7)P|j{V#yE}$%RgW;Y>-_n*ySpe} zY#Pyx!yI@f!+b&nH&>{f!d8HprH3Vqwo#7+J~Nc23LUoBFJA1>m7Wdi+)342Ho;Od z!JnUVqaQnWs`M-phJJNLp%U_68a)@dma#eIgu%Ayp;(n%e*bXU6k|!Gk~rj%buA|| zpedcr!xx6Y6UPF5YK?;Fn*M9fMAo&IL!+glR;OY~&Q29ByF|?3U3&_!2tewK2Z{55 z7sO-Y7euB*$?+RKidZjK3JW$ae&!ZFiA^{s!&{*wOf>8%Klp*lh0leW`G`!DD_CfJ zbllTMZ?7r&nh%Y+$liUqNkgl^L}P(KJSB{N-?~oDZt8FYPt7Dh1fS$ovXhvO{P{r}e)l2>F-P#uC*Vr|? z*zi9T;%{w*$~sF<7luHYj``Yo=8A7O*f;%_#)ZNc z){Vq+%I^&!t8H~5q9NarGmn#C7z}yfrzVVu0Mr05%tuEknSN}ihg zP$e;YgjE9kb^gvk*J9)*U=oetSivFn=g3hm|HG58qY-F%vXN6&2#Zi~CYGBRbEF+j z!X5z7W`JK0mj(>bnfwU!l>mj}F3bHCbpYD3m44(7KM{V|wnJZuElg8VXTBz*%fL;4 z7$xdi2*-$l56`3B`MSZ5k|$ZQiT0Kpjg16=N5h(HAn!2b2B%<0Ys1lEGzL~8d42gkH30PO+BamL%GObvIX0hG z#DXCl@P#IqP!qxRhr81HDKZ3K=&&8iDjVg>Cm}o+lO>?YuluMtSjBiO><=GvQS&U8 z)2T%d*?)G$heufpXXUP+c6Hs5FjjZ+d)Bg`(e8F$(M1XzxWD?NKn17Yfh)@6&Ff0(kIPH#K%pVE%rcq$jSvz;@ z&lG~Ghd-yO3X4Kl+2bH$!t?bED%4HqJIEm*RUs*SBeUsl^*J0KKz)6>Iq&U^Ro0bf zf5uL&we_TMOEAWXN1l}^9p<}Z6GuYMc%d>|nR8Z0%>3n^ zvPlF3HT$PvL`Ak43L^M|Nb7a75=~q#7-E#5!~3#Lim?aERVV(_G@EOIr(dm;pf04V;2mvm8ip;SFjtK!5An$p)HL>5Nj?P1+oJ$Weo7@>)n3qT~gzHV@mG8bQ;UC zM#q;-Fl($FhbWqyYzbW415A(u>UVXKufrmSn{okSu1V(F3KpdmOPrnFj}N!ZYaK6_ zP_>cGQ6zK&y4;nb{8_s!l)-QUGGZd$(m)m?tRO5*a={HbLi6M4xaHZHgJlJN7ndw9 zm!wqY=5gZfx`=6nU+C(wT|LA!vL{rvT$-0cQzzwCt8K9d`AHKp29}f-EtZwTzI&cw zu0BtWK4*U=5Ft&r_i-Ky0^+uAU3L}{IDgKf{vM7-Ocef2_}aD;fbN51uj1TnQ;es4 z3cp)}F7@d)mIdSuH%$jG0dUDxn0wp|5>{`PN+jk^@!fBPCJjg9jzAGHNqQ4E%(eqcM9&CqiZ&gOYeakVv4>+%fv-1PkHTZ) zx+5&Yzjn&f7k&`Qfzaww$PdsVY%?X`Jx%=9CrN`QcuahYny0+B$=pQlI8LrsaLFF4 z*iJu6PD{x@kd@pO z5}yC`Kjx38uFgu(8|SVO{+d4oiU`00F06r5`fDPzcGs?cJiKFLn0M+)lM2%dJ`ivM z`1Rg1?xyUzl8bYeBxczK1F$qp3Lk!x$KSxF_wwHG?!NY(?Ht?8@kx^vo9@jq30>++ zU(G0UKaVaxpLIyo9Lh)Ba@vLJRjhzgmYa6pylPV&1sk7krCw3qYANB$yG7s%J!h4G zUD-|E*3<$^1aa0e?1BSK(?x$d)ho1>Tcxyjwg-`&r&~C9ES$u(wFo0Um(Mxx(*8I;j1(R9=YEM-ZYr1exr>L%w4xFJ_JvT|I+vc$%zm z6Z!Vbi)}VFd1tIEh%07ZE)do%^#wML7m(ZRxMnm)e+n{%&O37HAnca?PMSxxVJyf` zH&$&)NmMu?O>cN?W{}0fp^~H;LAz#;s12Ylp%m4LD;bgPI&tPOEtdl#<`3I7{6?yi zPIFbD3bmLot+U+2;bAZ$r74Qc;M*8uxTqt&M(FYNLywdRPjCk1u_(!5NCT*3-J7l; z9UJpYd%no&dw%6i?T^fT;Ng9SNV5nxLpT*Q)xG99!7Z|cv76RcMzC|^V;u*KA$~Sv z_dxp!kXSJl_nA!B>oo^PdCw?XmMd1WaOZa%K`5x%1R?1ZQHoF+3*~8vDdSMRo2WNt z72KQg*XC z!7un~e0oUFbWgIz$ad?-VX~MefVB9!h4XoN$Uqrlp{XmL1nWDn;HyK%5A?+@Of0hr z*uo%5+89UeZ2*#3c88EXKb6_$i-0{sW!?C~Jg(n~Nnw%Zfz8r%kB8e{RVSvvohXbF zl9c#73^t6SvM7RNdJvBNNF1_}P^6l6N5}e^K}eQhDX&LxU=i(*K(RpxybijFO2{Nj z|KOOvL)uPa;?WB*C$+vn(D-)w^7kRQ6L|mdI~$ircjRm5MB|}pV>QSGfx;sr_uUl6 zgaQT`552g02%yjdr`SW;+*L}Rqz7+QEZ?_3u;fHi7ptU)j-kxrrF>jtao~>B+H@-FO^%&Qj_?#G8Fx2T(L;qo-saJBcANc8oN~gb>OTu zR7N7Btwkvq)%j&x!E8QFd_GOnRV3eQjYt)^(q(-(EX*_u#QfO1h|RJ76JbO^keRJq zPR<f+lUb4C&?%7RJALC8ZxD|+8hUG^AURhdVM=-%fh%V102ExJG()Al(#h!)`rLsVrFp3wtwmtC@Z@^bt9@31X{~uH7o?# zS|}$3e4kJSKxFT@7sXHa)H`4AR>MKfkT@F%m1yCNxaYdi!APGhm|XskWNLk!~^VQDl(_eKHch0^dB3 z9G?T3KR$q`f&+&K*F)3zx<%hUq>uT0!H{5B71Bt2d_6s>WZggDeU-F$3Lk}^)5!{K z);5{UI?y%HGf@`MDDh%k>rxT9T^vNV>^+}Z=2wkwP42xr*W+AR8$@Hic!x*Lp@@$^+9WOm@TRJ%SvV7uBBxb>n# z&B&0+x{}p9X(WH^Q@A5_a7jK^aBZrkXNzzmq}EL&g`Zxk#$3dX6_i534FC0Z2aWli zQS3rD@GP^4p6zp8X4>gOuON_aLPCWwBoQX83tI&YH)vLE*U(GrTtcFX(aIfOq?Vw` z(jtC23?2i%zQxCc*T`D;((l_WGzP_j6yW|Pb`KdfYC?`Je6{=X! zHucqWjep!d#Vze2&^n!OZq2_&aM3KOd}PobD9ymse3hWY`$Ri8utN{_$Rlqlh6cK&mHh1C3lbCQHxWX#qLn(JIx| z@_>56XV+v`TEb1IY+vHqL~Fapv#w%wjXXnOPKk+9@yW03cL+MP03sn8=rhrVp-a%Z zz?m3WP;kR1wVbyV47@ze*dR9HaLBNaX-6YMBU+!BjVosW>NS`gqWVu4vWPm37fzTDNoB0VhGWZv5wubh>6ooj7!9g|0B!{_iI$0(4i|X9B6O&s$o3*Ma znGbdCPE#|M1}M2pXu6MA$d5;V6FU8aBNDUUJUTNpP}L`jI&U3EC?EzB<{*cIEdmUa z`TWuaIqrS7Tj?EeZ)e1LxJ8jO=o`X77Tv~V*d*yCxiL*tE~NpPqn3F-7S1!}RU3zM zR+c?IomBsG`%jnxTj~{5#rT1^lU=dnU&_pfW!wGf3YRAk_PeQ&iUMOF4d=uy0-&~G zWdjI9SRM1Ho#>*C$Ly0aLGklsH1Nw5gxv8y7?CDnA)R0inO3 zgvcA&Dbd=C_O2%H%2x}Ys-Bze?Tk7PxBg|Ibe2`q*w)Ck4M8D?o62?{0(p=pJQOT% zp-Mvk>J+9eUEkpM&N+FJ1JlW8`MOuwePUcoV2G#6Co1mMigdRoh}*0~-B`o9ZXQvO zbrGkUI;`L-1#|?5H!l7nd<6n|RyRH&IJz?LJm7h4ONm=#75(^#7D7Yr8<#VWL}Xmd z;Ub%Xk?}YeZK@pCxW1D6{Cjv8==*qazb3uMEoU_>oB&?wt{WAV-)$kst{O z(A&>lc0!N^u_)@kv5$Y7$?fYo%bRNg$MjG&`3i~=oG|O1Zs_Zep(j}H${q`hr|`1F zK12G;zR`!eXlmJfX4z7`18i35iT1DvpBI0jd(=OX*}5asRSZxh5@H=NjTlfj4B_6a6=IU2b`m09e>uT!(spFn_P+qGn0fzvL zkUde~60ec^Td{4wiyg_k_95$Hf(Y6O1tSX)s(ZsHNMy6N&zT57CHq3rYvW83OtKk- zgoAeoXRY&dDmkk?#RX6AZ9`PgV8|;8mDe{xr@Bb$vEKJJqL7cohP+__R;oqCq99G2 z1BFuc-NpA)rK7v@d-^a;Yuy(01W`|~%4c)$oD}OHCGym=I;@{f_Aje6Y|dl3eB8OV(~+BlvE! zzVskJ-+~tUSZv;a*)>TN=3vv>7kLcdqZu%av3nr#fzkSt<%(u6$mr!=Ot@CAomJpU z+T5I;39}Bjc8FN?CTvhg8)p~=O{fQ>7VIIQv(2Szo39yG-AeZ@yhRF z%|gcvZPMd=+(XvcqVPWi))x`p^G_whebG|#V~-xIA^q$r)t%&DGAr6#Ip{i4b@<)d z=*+4r=z4ofi>*w_Ev`AFgZ75cxS=xz2;Tz0x+eZnBKHB~w?n&qUX{zWrm+{L~akpQ=CaN~` zrihTm{-*VeclwU-rRzOKlhLuM&M8tE33m=?Ha-pc(B0u7!c^pirbS5Rw0nL>0 z_^C6$7VyTTT;0b$H_dj&yxpL8Z~(T`mGX+$QCO5Cv+LyfM1@7BMP)oy(MwDCm?qQs zp)V+j*XeQTb8db=o16n%{^XB?0R8NB-tp}lS{<~=?R z-?ZHzYWhOdrqhLmm+W_!dfu{EvS97+3GBo?7eIEc&c;d7{V#OdjqrV$B?K;0qDL|| zW|Rt(Sp*1fyabSjhVzHE3T)DGbi2v^2=m5z)ULLY^K{yL?O!mFK%%Zu(!=a0=Dwy> z>uv){7hD_c7rN@ASv$z+(T(g8l?D+-E29xV&$mEoG>T+LW;++m#&_x8HBx9>dY78oJcnuHO= zl@YeJz(swC{cxNm$LF@UYf{_+A_JQ|g`u(GsRDh8SHNMo>-dxx(s0CcHG{D+@ zdo%p#9?5>wEdW@MdPUDtj2Fwo!;rDqbTJ_5PQzcFdk`jR4YB>U@Y(hykmH2})a8K{ zs9n^gT?9xV1MhDE(3+Be0xAH&1!vU=^S3lUn742k`dcj4-rkwn)xyM0+0oA4=}$g< zRDz&gFDY8ct=uzeSbMkZm!<|ov(iN>@xt#b=wIOwpdb_GpRWatcFTXp{p|2+zRluK zVP2HVt+dyBpSiV9*)3yk`hD6ZrgJzp^iz~~PMVrY{h$MlfF9PZn^QW_rf}Ye7aDfa zjAP&s%~~qV%xXeem{rq!{KMA!_oU988!;zc-&Ks0Dd{Xqrrj&tnx@ms66D(m8ZClQ z0>d#QVEt~bES^_KS2s;F&%R=okHsP4Dc-`(C=u4gZdkJ@o)wlrUUXKM?K&rabu3Hj zm)bw3Q^=QK@@Y%ZArx-}s(OdT%}pooOvz?#QL#dGk~4`eRmEaz;zruL-1Aifdvt6y8Fl*%_iWi(7gAj zHI3RU1##Ce^VrhE0;pXW6PXxje3Q!|sQhs}7Bp`}*x{ zx8mF?3??mi5$D@WCJ#p>&T;|e5Z~Q<)v5)kFTrZ4SM{225AFGK2d34bFZ32d`S)X+ zFlyJbd@0^w`K&0`nJeX9(Zfc9HLZ`@SGf;)j9Ci33Cri`tNT(hlpf3Lb$C2Xbfo^u z8et*ux!=h*>VBWKL^do`IM_qgxA@bVCenMk;yPNze9A9<_+uSs);CQQrc^rW6l|Ou-Qzft}~4N6l8@?8csguXky7s5Qkw25=DVtR9@)Q2chT`)EpSvdap~QKM>p?-C`nvO zPbs>363Jn-BNkcjnjhGAm;pdevO))X`0W-+!y#21cZ-N!?1MPxDd)KLIX~^3uwy2J zX=B2w-cD-lqLQoo0dFHZ{eCA*k>8HNS~S0ZmJeh{VG14IJP26G`x;axz(9YH;ffDt zUrqF1nJca?y$`UpEI<)hpi$)=pE_@F(s0s*J&*rw0y{CFh$XD+Zvbh+AbWYR+4x3g4Qz`eDAFT_(d)vcEbFbC4P>xiZMA6f52T#yX)1L(g=(MEqN*Fq~7g z=b(^93jGJT*8KBWx*xW7G}d-G0$)C9w5ZOf(T%xCC7f=YjZ6Jg!-w!r*)3lv~Nzypl! zjQ%e8%tkIw&UQ9`)_u}EXaH>v1Rz%w0IW~^82M-Yxeb1S%WvWW@g{OCa~^l_W%6FdiKV2A6wXWe)#Nyw!hX;`uqzDD{c7MVvG)jbP$n z4zcZsm=wm}MILDupOM}^8E2V!wUa(untgDhVG>qPYzdJtgCK&X{)yDf^wj$c@G*wX zXe@(yU~Zgt#!-vF_o&d7Oo|ryeu8hRcS8Z?X_8*iwyc2VNz6?6_*dZEm&DG#G5-Ty z`VVK7)Q2t9VIplm=UBuh5O*B1L?zIB=-Ye;!Re=@cucXZ@EnKj*Tu(MmoHFO#!X|q zF=07)2~y}O@QI>D3GhV{G7_JE0WJD(2u9Ns5no?_Vy~R_wK#0_=QH$L>4pI3UqEbG za?MFqri!b|hCv7tcv9ymR4_#_5kg~Pnev6c2`67|Keax46y~SEB+A1)?-kp!fPE+i zwD6{W(v0)nySK_G6)7x+;SGftrO+mbq!sdF;i-uQkFYD6vc@ZL)@=WhW}nyRQtea! zMX}Ay+abS0SAeh+hbC$dqDv+hibUp{>0dP84YZzV`Dm~EbG(zK*9wi<_m3|Q-ua_a zD5e4Ckcj`BbOtBQ0=OyvIlT%2f%K;L|G7-xoOgXk6Kf}C@Wv_tn?V2npVLH!fWZ0( z_D0QvN#_7GV8I2zd&o*ekR2%=sFEBJ?6m+u11HS^-UG_P)pGzbfDridPn8Mgnt!W) zfIa2`w7mbEy@P)5BjJx>OO!;jUi-L#S$w823EMqPSC{gdDJZ`7f{8;TgLwFJN>{3nO&-zX2!zbJ#n zH`G6A3jao(N&Q8Y{O#+%Tk-!!Eq?rqy8VOt?}qc6!2I7oPNVu4CAIv9`e$?X-zXu? zzo?`?sDJi){*3}?gSu5H!28Q@ocJf0`ES&@{@=c)R^IyhCvXP=LH@tz1ER|04MhSD zdP5QXH!y|zZ&WlGeGPyGve$VB=6FMb_g3Dfj@u6OV9N9#Vg5Up$@YKe(#IST9JLDg z0GZ+N=N`Pg3gCdubNowlt-aADPJih)f#iU!a(<(k{>ae>$a00Vw|1 zw(p_BrvPA;VE`6b>up&g{I8AsW-tA5JpQ?sXTZVR01Co?tSJZxw10knqnhWzKehqn zjQ>}S{clL%G63RVN)0@@4Pb(FS_4D=21r6?uY+ZO1Bg*LAvhr#-y~vx<4qkx{67z8 BcVPek delta 14520 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 From 9a19fdd134b4de99ffbba6d50fd7848df6a6c50a Mon Sep 17 00:00:00 2001 From: afourney Date: Fri, 28 Feb 2025 07:43:03 -0800 Subject: [PATCH 18/33] Make sure extensions are unique in MarkItDown's convert methods. (#1076) --- packages/markitdown/src/markitdown/_markitdown.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index 7c8d006..51f5c33 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -381,7 +381,8 @@ class MarkItDown: ext = ext.strip() if ext == "": return - # if ext not in extensions: + if ext in extensions: + return extensions.append(ext) def _guess_ext_magic(self, path): From 9182923375fb84892d88acaf3ca9d361bce53b0b Mon Sep 17 00:00:00 2001 From: afourney Date: Fri, 28 Feb 2025 09:54:19 -0800 Subject: [PATCH 19/33] Don't have ZipConverter accept OOXML files. This will never yield a good result. (#1078) --- .../markitdown/src/markitdown/converters/_zip_converter.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/markitdown/src/markitdown/converters/_zip_converter.py b/packages/markitdown/src/markitdown/converters/_zip_converter.py index 026900d..e2b5fe6 100644 --- a/packages/markitdown/src/markitdown/converters/_zip_converter.py +++ b/packages/markitdown/src/markitdown/converters/_zip_converter.py @@ -77,6 +77,10 @@ class ZipConverter(DocumentConverter): try: # Extract the zip file safely with zipfile.ZipFile(local_path, "r") as zipObj: + # Bail if we discover it's an Office OOXML file + if "[Content_Types].xml" in zipObj.namelist(): + return None + # Safeguard against path traversal for member in zipObj.namelist(): member_path = os.path.normpath(os.path.join(extraction_dir, member)) From 43bd79adc98552ab994360940d207e32c8a59466 Mon Sep 17 00:00:00 2001 From: afourney Date: Fri, 28 Feb 2025 16:07:47 -0800 Subject: [PATCH 20/33] Print and log better exceptions when file conversions fail. (#1080) * Print and log better exceptions when file conversions fail. * Added unit tests for exceptions. --- .../markitdown/src/markitdown/__init__.py | 2 + .../markitdown/src/markitdown/_exceptions.py | 46 ++++++++++++++---- .../markitdown/src/markitdown/_markitdown.py | 20 +++++--- .../markitdown/tests/test_files/random.bin | Bin 0 -> 1024 bytes packages/markitdown/tests/test_markitdown.py | 18 ++++++- 5 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 packages/markitdown/tests/test_files/random.bin diff --git a/packages/markitdown/src/markitdown/__init__.py b/packages/markitdown/src/markitdown/__init__.py index 59d9750..c6d5363 100644 --- a/packages/markitdown/src/markitdown/__init__.py +++ b/packages/markitdown/src/markitdown/__init__.py @@ -7,6 +7,7 @@ from ._markitdown import MarkItDown from ._exceptions import ( MarkItDownException, ConverterPrerequisiteException, + FailedConversionAttempt, FileConversionException, UnsupportedFormatException, ) @@ -19,6 +20,7 @@ __all__ = [ "DocumentConverterResult", "MarkItDownException", "ConverterPrerequisiteException", + "FailedConversionAttempt", "FileConversionException", "UnsupportedFormatException", ] diff --git a/packages/markitdown/src/markitdown/_exceptions.py b/packages/markitdown/src/markitdown/_exceptions.py index 30c4dc5..50d2496 100644 --- a/packages/markitdown/src/markitdown/_exceptions.py +++ b/packages/markitdown/src/markitdown/_exceptions.py @@ -1,3 +1,6 @@ +from typing import Optional, List, Any + + class MarkItDownException(BaseException): """ Base exception class for MarkItDown. @@ -20,18 +23,43 @@ class ConverterPrerequisiteException(MarkItDownException): pass -class FileConversionException(MarkItDownException): - """ - Thrown when a suitable converter was found, but the conversion - process fails for any reason. - """ - - pass - - class UnsupportedFormatException(MarkItDownException): """ Thrown when no suitable converter was found for the given file. """ pass + + +class FailedConversionAttempt(object): + """ + Represents an a single attempt to convert a file. + """ + + def __init__(self, converter: Any, exc_info: Optional[tuple] = None): + self.converter = converter + self.exc_info = exc_info + + +class FileConversionException(MarkItDownException): + """ + Thrown when a suitable converter was found, but the conversion + process fails for any reason. + """ + + def __init__( + self, + message: Optional[str] = None, + attempts: Optional[List[FailedConversionAttempt]] = None, + ): + self.attempts = attempts + + if message is None: + if attempts is None: + message = "File conversion failed." + else: + message = f"File conversion failed after {len(attempts)} attempts:\n" + for attempt in attempts: + message += f" - {type(attempt.converter).__name__} threw {attempt.exc_info[0].__name__} with message: {attempt.exc_info[1]}\n" + + super().__init__(message) diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index 51f5c33..49b817d 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -2,6 +2,7 @@ import copy import mimetypes import os import re +import sys import tempfile import warnings import traceback @@ -42,6 +43,7 @@ from ._exceptions import ( FileConversionException, UnsupportedFormatException, ConverterPrerequisiteException, + FailedConversionAttempt, ) # Override mimetype for csv to fix issue on windows @@ -313,7 +315,9 @@ class MarkItDown: self, local_path: str, extensions: List[Union[str, None]], **kwargs ) -> DocumentConverterResult: res: Union[None, DocumentConverterResult] = None - error_trace = "" + + # Keep track of which converters throw exceptions + failed_attempts: List[FailedConversionAttempt] = [] # Create a copy of the page_converters list, sorted by priority. # We do this with each call to _convert because the priority of converters may change between calls. @@ -351,7 +355,11 @@ class MarkItDown: try: res = converter.convert(local_path, **_kwargs) except Exception: - error_trace = ("\n\n" + traceback.format_exc()).strip() + failed_attempts.append( + FailedConversionAttempt( + converter=converter, exc_info=sys.exc_info() + ) + ) if res is not None: # Normalize the content @@ -364,14 +372,12 @@ class MarkItDown: return res # If we got this far without success, report any exceptions - if len(error_trace) > 0: - raise FileConversionException( - f"Could not convert '{local_path}' to Markdown. File type was recognized as {extensions}. While converting the file, the following error was encountered:\n\n{error_trace}" - ) + if len(failed_attempts) > 0: + raise FileConversionException(attempts=failed_attempts) # Nothing can handle it! raise UnsupportedFormatException( - f"Could not convert '{local_path}' to Markdown. The formats {extensions} are not supported." + f"Could not convert '{local_path}' to Markdown. No converter attempted a conversion, suggesting that the filetype is simply not supported." ) def _append_ext(self, extensions, ext): diff --git a/packages/markitdown/tests/test_files/random.bin b/packages/markitdown/tests/test_files/random.bin new file mode 100644 index 0000000000000000000000000000000000000000..e673935e3fe247eb568b532edda79cfa6d7cfd23 GIT binary patch literal 1024 zcmV+b1poVZqDUF|I@MPm@I2ba$0^0xsbp5=o$th>YH+h(LnR-*n?R?s5~^bsp5l$X z7!7%l(k=#N0Jw)Mg|7LqVl#M>YgXS>F_7qT+Ta$BOcL@<=D?8&Tyzbza0M!}1$;|W zE280En|hWp5mqOnj+8dseB-OIb=`)1NzxJ`L~!o}I7|^;+VBtH0Eryk+!aOZQtBbu z+d)OC*Sj!C8hXD<05H0AteX&eRn;m*M-^4a)GnCF&Oy_Xtl2HYT$Q4Cl5VSs&Ep6m zBH}pJ@5V)56TBb@{sw}78^asVLNQvD&&bza?s=)<`Aum^Nwp9aYfaNz@n1(ZtEb3T zn1_qrM48Xdk_Sp=F9@=dlt0+n(CwH7(8{%|5AU1C`0=y}c8wJ(VA?k|Fxn_-03S<% z$$npfgt!B__+tzm3hvzTwmBh^;BS#Xmy#m!uK{z{@z~TV;a{SJXCFB0G0>@izrxvx zLDXFsvXHb$p}6ONcFotcO_yhBU>g^5`itQOtrNzb33~pIm^}+Nu)R^|`okXdo2=yR zql__p$hJ^g1zP)QpcN+YcA2?NB5#bK&KyY*C&eZHEFLGUm&Zeypx-Y>RQV_7eJE?j{;Fovw#+-GF2oxJtV}EyPNi0fN&@c zy$8z^dxzdPjCj{s>*ZM6XASd9ew9-p$NFR)ABLs}(MEP|*<4wZP9tC-Dmu2BTG{ez zM9(1*o!NO|rTs52NkHUb8t^@X;Gb=?g5W+B@PHq)d9}wi50J=^)9pDfUine~u}mW@EAyzV60qXX@FPW%u??=}_W#YoyH!tqHeq^X1rTURVlV uZ!;^~(Qhc=?1Mm6xcY{dXP^%X3G4bAv$;g8TUZ literal 0 HcmV?d00001 diff --git a/packages/markitdown/tests/test_markitdown.py b/packages/markitdown/tests/test_markitdown.py index 55afcc3..0a3b56e 100644 --- a/packages/markitdown/tests/test_markitdown.py +++ b/packages/markitdown/tests/test_markitdown.py @@ -8,7 +8,7 @@ import requests from warnings import catch_warnings, resetwarnings -from markitdown import MarkItDown +from markitdown import MarkItDown, UnsupportedFormatException, FileConversionException skip_remote = ( True if os.environ.get("GITHUB_ACTIONS") else False @@ -272,6 +272,21 @@ def test_markitdown_local() -> None: assert "# Test" in result.text_content +def test_exceptions() -> None: + # Check that an exception is raised when trying to convert an unsupported format + markitdown = MarkItDown() + with pytest.raises(UnsupportedFormatException): + markitdown.convert(os.path.join(TEST_FILES_DIR, "random.bin")) + + # Check that an exception is raised when trying to convert a file that is corrupted + with pytest.raises(FileConversionException) as exc_info: + markitdown.convert( + os.path.join(TEST_FILES_DIR, "random.bin"), file_extension=".pptx" + ) + assert len(exc_info.value.attempts) == 1 + assert type(exc_info.value.attempts[0].converter).__name__ == "PptxConverter" + + @pytest.mark.skipif( skip_exiftool, reason="do not run if exiftool is not installed", @@ -329,6 +344,7 @@ if __name__ == "__main__": """Runs this file's tests from the command line.""" test_markitdown_remote() test_markitdown_local() + test_exceptions() test_markitdown_exiftool() # test_markitdown_llm() print("All tests passed!") From f01c6c52774ba284cf29796f44c62ad786030b7c Mon Sep 17 00:00:00 2001 From: afourney Date: Fri, 28 Feb 2025 16:28:35 -0800 Subject: [PATCH 21/33] Exceptions should subclass Exception not BaseException. (#1082) --- packages/markitdown/src/markitdown/_exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/markitdown/src/markitdown/_exceptions.py b/packages/markitdown/src/markitdown/_exceptions.py index 50d2496..4f443b2 100644 --- a/packages/markitdown/src/markitdown/_exceptions.py +++ b/packages/markitdown/src/markitdown/_exceptions.py @@ -1,7 +1,7 @@ from typing import Optional, List, Any -class MarkItDownException(BaseException): +class MarkItDownException(Exception): """ Base exception class for MarkItDown. """ From c5cd659f6381b40ccf5e7a936bb30c2f6a28b018 Mon Sep 17 00:00:00 2001 From: afourney Date: Mon, 3 Mar 2025 09:06:19 -0800 Subject: [PATCH 22/33] Exploring ways to allow Optional dependencies (#1079) * Enable optional dependencies. Starting with pptx. * Fix CLI tests.... have them install [all] * Added .docx to optional dependencies * Reuse error messages for missing dependencies. * Added xlsx and xls * Added pdfs * Added Ole files. * Updated READMEs, and finished remaining feature-categories. * Move OpenAI to hatch-test environment. --- README.md | 29 ++++++++++-- packages/markitdown/README.md | 4 +- packages/markitdown/pyproject.toml | 36 +++++++++++---- .../markitdown/src/markitdown/__init__.py | 4 +- .../markitdown/src/markitdown/_exceptions.py | 22 ++++++--- .../markitdown/src/markitdown/_markitdown.py | 1 - .../converters/_doc_intel_converter.py | 36 +++++++++++---- .../markitdown/converters/_docx_converter.py | 26 ++++++++++- .../markitdown/converters/_image_converter.py | 2 +- .../converters/_outlook_msg_converter.py | 32 +++++++++++-- .../markitdown/converters/_pdf_converter.py | 26 ++++++++++- .../converters/_plain_text_converter.py | 11 +++++ .../markitdown/converters/_pptx_converter.py | 25 ++++++++++- .../markitdown/converters/_xlsx_converter.py | 45 ++++++++++++++++++- 14 files changed, 254 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 70f188d..2563a68 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,8 @@ [![Built by AutoGen Team](https://img.shields.io/badge/Built%20by-AutoGen%20Team-blue)](https://github.com/microsoft/autogen) > [!IMPORTANT] -> MarkItDown 0.0.2 alpha 1 (0.0.2a1) introduces a plugin-based architecture. As much as was possible, command-line and Python interfaces have remained the same as 0.0.1a3 to support backward compatibility. Please report any issues you encounter. Some interface changes may yet occur as we continue to refine MarkItDown to a first non-alpha release. +> Breaking changes between 0.0.1 to 0.0.2: +> * Dependencies are now organized into optional feature-groups (further details below). Use `pip install markitdown[all]` to have backward-compatible behavior. MarkItDown is a utility for converting various files to Markdown (e.g., for indexing, text analysis, etc). It supports: @@ -22,12 +23,12 @@ It supports: - Youtube URLs - ... and more! -To install MarkItDown, use pip: `pip install markitdown`. Alternatively, you can install it from the source: +To install MarkItDown, use pip: `pip install markitdown[all]`. Alternatively, you can install it from the source: ```bash git clone git@github.com:microsoft/markitdown.git cd markitdown -pip install -e packages/markitdown +pip install -e packages/markitdown[all] ``` ## Usage @@ -50,6 +51,28 @@ You can also pipe content: cat path-to-file.pdf | markitdown ``` +### Optional Dependencies +MarkItDown has optional dependencies for activating various file formats. Earlier in this document, we installed all optional dependencies with the `[all]` option. However, you can also install them individually for more control. For example: + +```bash +pip install markitdown[pdf, docx, pptx] +``` + +will install only the dependencies for PDF, DOCX, and PPTX files. + +At the moment, the following optional dependencies are available: + +* `[all]` Installs all optional dependencies +* `[pptx]` Installs dependencies for PowerPoint files +* `[docx]` Installs dependencies for Word files +* `[xlsx]` Installs dependencies for Excel files +* `[xls]` Installs dependencies for older Excel files +* `[pdf]` Installs dependencies for PDF files +* `[outlook]` Installs dependencies for Outlook messages +* `[az-doc-intel]` Installs dependencies for Azure Document Intelligence +* `[audio-transcription]` Installs dependencies for audio transcription of wav and mp3 files +* `[youtube-transcription]` Installs dependencies for fetching YouTube video transcription + ### Plugins MarkItDown also supports 3rd-party plugins. Plugins are disabled by default. To list installed plugins: diff --git a/packages/markitdown/README.md b/packages/markitdown/README.md index 54453ab..edd2701 100644 --- a/packages/markitdown/README.md +++ b/packages/markitdown/README.md @@ -10,7 +10,7 @@ From PyPI: ```bash -pip install markitdown +pip install markitdown[all] ``` From source: @@ -18,7 +18,7 @@ From source: ```bash git clone git@github.com:microsoft/markitdown.git cd markitdown -pip install -e packages/markitdown +pip install -e packages/markitdown[all] ``` ## Usage diff --git a/packages/markitdown/pyproject.toml b/packages/markitdown/pyproject.toml index a321fee..c053c7b 100644 --- a/packages/markitdown/pyproject.toml +++ b/packages/markitdown/pyproject.toml @@ -26,25 +26,36 @@ classifiers = [ dependencies = [ "beautifulsoup4", "requests", - "mammoth", "markdownify~=0.14.1", - "numpy", + "puremagic", + "pathvalidate", + "charset-normalizer", +] + +[project.optional-dependencies] +all = [ "python-pptx", + "mammoth", "pandas", "openpyxl", "xlrd", "pdfminer.six", - "puremagic", - "pydub", "olefile", - "youtube-transcript-api", + "pydub", "SpeechRecognition", - "pathvalidate", - "charset-normalizer", - "openai", + "youtube-transcript-api", "azure-ai-documentintelligence", "azure-identity" ] +pptx = ["python-pptx"] +docx = ["mammoth"] +xlsx = ["pandas", "openpyxl"] +xls = ["pandas", "xlrd"] +pdf = ["pdfminer.six"] +outlook = ["olefile"] +audio-transcription = ["pydub", "SpeechRecognition"] +youtube-transcription = ["youtube-transcript-api"] +az-doc-intel = ["azure-ai-documentintelligence", "azure-identity"] [project.urls] Documentation = "https://github.com/microsoft/markitdown#readme" @@ -57,6 +68,15 @@ path = "src/markitdown/__about__.py" [project.scripts] markitdown = "markitdown.__main__:main" +[tool.hatch.envs.default] +features = ["all"] + +[tool.hatch.envs.hatch-test] +features = ["all"] +extra-dependencies = [ + "openai", +] + [tool.hatch.envs.types] extra-dependencies = [ "mypy>=1.0.0", diff --git a/packages/markitdown/src/markitdown/__init__.py b/packages/markitdown/src/markitdown/__init__.py index c6d5363..9f7db16 100644 --- a/packages/markitdown/src/markitdown/__init__.py +++ b/packages/markitdown/src/markitdown/__init__.py @@ -6,7 +6,7 @@ from .__about__ import __version__ from ._markitdown import MarkItDown from ._exceptions import ( MarkItDownException, - ConverterPrerequisiteException, + MissingDependencyException, FailedConversionAttempt, FileConversionException, UnsupportedFormatException, @@ -19,7 +19,7 @@ __all__ = [ "DocumentConverter", "DocumentConverterResult", "MarkItDownException", - "ConverterPrerequisiteException", + "MissingDependencyException", "FailedConversionAttempt", "FileConversionException", "UnsupportedFormatException", diff --git a/packages/markitdown/src/markitdown/_exceptions.py b/packages/markitdown/src/markitdown/_exceptions.py index 4f443b2..abfebc6 100644 --- a/packages/markitdown/src/markitdown/_exceptions.py +++ b/packages/markitdown/src/markitdown/_exceptions.py @@ -1,5 +1,12 @@ from typing import Optional, List, Any +MISSING_DEPENDENCY_MESSAGE = """{converter} recognized the input as a potential {extension} file, but the dependencies needed to read {extension} files have not been installed. To resolve this error, include the optional dependency [{feature}] or [all] when installing MarkItDown. For example: + +* pip install markitdown[{feature}] +* pip install markitdown[all] +* pip install markitdown[{feature}, ...] +* etc.""" + class MarkItDownException(Exception): """ @@ -9,15 +16,16 @@ class MarkItDownException(Exception): pass -class ConverterPrerequisiteException(MarkItDownException): +class MissingDependencyException(MarkItDownException): """ - Thrown when instantiating a DocumentConverter in cases where - a required library or dependency is not installed, an API key - is not set, or some other prerequisite is not met. + Converters shipped with MarkItDown may depend on optional + dependencies. This exception is thrown when a converter's + convert() method is called, but the required dependency is not + installed. This is not necessarily a fatal error, as the converter + will simply be skipped (an error will bubble up only if no other + suitable converter is found). - This is not necessarily a fatal error. If thrown during - MarkItDown's plugin loading phase, the converter will simply be - skipped, and a warning will be issued. + Error messages should clearly indicate which dependency is missing. """ pass diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index 49b817d..8f1bd46 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -42,7 +42,6 @@ from .converters import ( from ._exceptions import ( FileConversionException, UnsupportedFormatException, - ConverterPrerequisiteException, FailedConversionAttempt, ) diff --git a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py index ed8aabf..6fe79c0 100644 --- a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py +++ b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py @@ -1,16 +1,24 @@ from typing import Any, Union import re - -# Azure imports -from azure.ai.documentintelligence import DocumentIntelligenceClient -from azure.ai.documentintelligence.models import ( - AnalyzeDocumentRequest, - AnalyzeResult, - DocumentAnalysisFeature, -) -from azure.identity import DefaultAzureCredential +import sys from ._base import DocumentConverter, DocumentConverterResult +from .._exceptions import MissingDependencyException + +# Try loading optional (but in this case, required) dependencies +# Save reporting of any exceptions for later +_dependency_exc_info = None +try: + from azure.ai.documentintelligence import DocumentIntelligenceClient + from azure.ai.documentintelligence.models import ( + AnalyzeDocumentRequest, + AnalyzeResult, + DocumentAnalysisFeature, + ) + from azure.identity import DefaultAzureCredential +except ImportError: + # Preserve the error and stack trace for later + _dependency_exc_info = sys.exc_info() # TODO: currently, there is a bug in the document intelligence SDK with importing the "ContentFormat" enum. @@ -30,6 +38,16 @@ class DocumentIntelligenceConverter(DocumentConverter): ): super().__init__(priority=priority) + # Raise an error if the dependencies are not available. + # This is different than other converters since this one isn't even instantiated + # unless explicitly requested. + if _dependency_exc_info is not None: + raise MissingDependencyException( + "DocumentIntelligenceConverter requires the optional dependency [az-doc-intel] (or [all]) to be installed. E.g., `pip install markitdown[az-doc-intel]`" + ) from _dependency_exc_info[1].with_traceback( + _dependency_exc_info[2] + ) # Restore the original traceback + self.endpoint = endpoint self.api_version = api_version self.doc_intel_client = DocumentIntelligenceClient( diff --git a/packages/markitdown/src/markitdown/converters/_docx_converter.py b/packages/markitdown/src/markitdown/converters/_docx_converter.py index 8515f6d..0866e59 100644 --- a/packages/markitdown/src/markitdown/converters/_docx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_docx_converter.py @@ -1,6 +1,6 @@ -from typing import Union +import sys -import mammoth +from typing import Union from ._base import ( DocumentConverterResult, @@ -8,6 +8,16 @@ from ._base import ( from ._base import DocumentConverter from ._html_converter import HtmlConverter +from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE + +# Try loading optional (but in this case, required) dependencies +# Save reporting of any exceptions for later +_dependency_exc_info = None +try: + import mammoth +except ImportError: + # Preserve the error and stack trace for later + _dependency_exc_info = sys.exc_info() class DocxConverter(HtmlConverter): @@ -26,6 +36,18 @@ class DocxConverter(HtmlConverter): if extension.lower() != ".docx": return None + # Check: the dependencies + if _dependency_exc_info is not None: + raise MissingDependencyException( + MISSING_DEPENDENCY_MESSAGE.format( + converter=type(self).__name__, + extension=".docx", + feature="docx", + ) + ) from _dependency_exc_info[1].with_traceback( + _dependency_exc_info[2] + ) # Restore the original traceback + result = None with open(local_path, "rb") as docx_file: style_map = kwargs.get("style_map", None) diff --git a/packages/markitdown/src/markitdown/converters/_image_converter.py b/packages/markitdown/src/markitdown/converters/_image_converter.py index 3c848dd..4eb6155 100644 --- a/packages/markitdown/src/markitdown/converters/_image_converter.py +++ b/packages/markitdown/src/markitdown/converters/_image_converter.py @@ -7,7 +7,7 @@ import mimetypes class ImageConverter(MediaConverter): """ - Converts images to markdown via extraction of metadata (if `exiftool` is installed), OCR (if `easyocr` is installed), and description via a multimodal LLM (if an llm_client is configured). + Converts images to markdown via extraction of metadata (if `exiftool` is installed), and description via a multimodal LLM (if an llm_client is configured). """ def __init__( diff --git a/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py b/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py index 6764fc5..eb7a065 100644 --- a/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py +++ b/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py @@ -1,6 +1,16 @@ -import olefile +import sys from typing import Any, Union from ._base import DocumentConverter, DocumentConverterResult +from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE + +# Try loading optional (but in this case, required) dependencies +# Save reporting of any exceptions for later +_dependency_exc_info = None +try: + import olefile +except ImportError: + # Preserve the error and stack trace for later + _dependency_exc_info = sys.exc_info() class OutlookMsgConverter(DocumentConverter): @@ -24,6 +34,18 @@ class OutlookMsgConverter(DocumentConverter): if extension.lower() != ".msg": return None + # Check: the dependencies + if _dependency_exc_info is not None: + raise MissingDependencyException( + MISSING_DEPENDENCY_MESSAGE.format( + converter=type(self).__name__, + extension=".msg", + feature="outlook", + ) + ) from _dependency_exc_info[1].with_traceback( + _dependency_exc_info[2] + ) # Restore the original traceback + try: msg = olefile.OleFileIO(local_path) # Extract email metadata @@ -59,10 +81,12 @@ class OutlookMsgConverter(DocumentConverter): f"Could not convert MSG file '{local_path}': {str(e)}" ) - def _get_stream_data( - self, msg: olefile.OleFileIO, stream_path: str - ) -> Union[str, None]: + def _get_stream_data(self, msg: Any, stream_path: str) -> Union[str, None]: """Helper to safely extract and decode stream data from the MSG file.""" + assert isinstance( + msg, olefile.OleFileIO + ) # Ensure msg is of the correct type (type hinting is not possible with the optional olefile package) + try: if msg.exists(stream_path): data = msg.openstream(stream_path).read() diff --git a/packages/markitdown/src/markitdown/converters/_pdf_converter.py b/packages/markitdown/src/markitdown/converters/_pdf_converter.py index 3a2b671..3c5ecad 100644 --- a/packages/markitdown/src/markitdown/converters/_pdf_converter.py +++ b/packages/markitdown/src/markitdown/converters/_pdf_converter.py @@ -1,7 +1,17 @@ -import pdfminer -import pdfminer.high_level +import sys from typing import Union from ._base import DocumentConverter, DocumentConverterResult +from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE + +# Try loading optional (but in this case, required) dependencies +# Save reporting of any exceptions for later +_dependency_exc_info = None +try: + import pdfminer + import pdfminer.high_level +except ImportError: + # Preserve the error and stack trace for later + _dependency_exc_info = sys.exc_info() class PdfConverter(DocumentConverter): @@ -20,6 +30,18 @@ class PdfConverter(DocumentConverter): if extension.lower() != ".pdf": return None + # Check the dependencies + if _dependency_exc_info is not None: + raise MissingDependencyException( + MISSING_DEPENDENCY_MESSAGE.format( + converter=type(self).__name__, + extension=".pdf", + feature="pdf", + ) + ) from _dependency_exc_info[1].with_traceback( + _dependency_exc_info[2] + ) # Restore the original traceback + return DocumentConverterResult( title=None, text_content=pdfminer.high_level.extract_text(local_path), diff --git a/packages/markitdown/src/markitdown/converters/_plain_text_converter.py b/packages/markitdown/src/markitdown/converters/_plain_text_converter.py index 75f74a8..b4c9282 100644 --- a/packages/markitdown/src/markitdown/converters/_plain_text_converter.py +++ b/packages/markitdown/src/markitdown/converters/_plain_text_converter.py @@ -6,6 +6,13 @@ from typing import Any, Union from ._base import DocumentConverter, DocumentConverterResult +# Mimetypes to ignore (commonly confused extensions) +IGNORE_MIMETYPES = [ + "text/vnd.in3d.spot", # .spo wich is confused with xls, doc, etc. + "text/vnd.graphviz", # .dot which is confused with xls, doc, etc. +] + + class PlainTextConverter(DocumentConverter): """Anything with content type text/plain""" @@ -22,6 +29,10 @@ class PlainTextConverter(DocumentConverter): "__placeholder" + kwargs.get("file_extension", "") ) + # Ignore common false positives + if content_type in IGNORE_MIMETYPES: + content_type = None + # Only accept text files if content_type is None: return None diff --git a/packages/markitdown/src/markitdown/converters/_pptx_converter.py b/packages/markitdown/src/markitdown/converters/_pptx_converter.py index 76c481a..431b6a0 100644 --- a/packages/markitdown/src/markitdown/converters/_pptx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_pptx_converter.py @@ -1,12 +1,22 @@ import base64 -import pptx import re import html +import sys from typing import Union from ._base import DocumentConverterResult, DocumentConverter from ._html_converter import HtmlConverter +from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE + +# Try loading optional (but in this case, required) dependencies +# Save reporting of any exceptions for later +_dependency_exc_info = None +try: + import pptx +except ImportError: + # Preserve the error and stack trace for later + _dependency_exc_info = sys.exc_info() class PptxConverter(HtmlConverter): @@ -54,9 +64,20 @@ class PptxConverter(HtmlConverter): if extension.lower() != ".pptx": return None - md_content = "" + # Check the dependencies + if _dependency_exc_info is not None: + raise MissingDependencyException( + MISSING_DEPENDENCY_MESSAGE.format( + converter=type(self).__name__, + extension=".pptx", + feature="pptx", + ) + ) from _dependency_exc_info[1].with_traceback( + _dependency_exc_info[2] + ) # Restore the original traceback presentation = pptx.Presentation(local_path) + md_content = "" slide_num = 0 for slide in presentation.slides: slide_num += 1 diff --git a/packages/markitdown/src/markitdown/converters/_xlsx_converter.py b/packages/markitdown/src/markitdown/converters/_xlsx_converter.py index 2bdfd5d..56398ca 100644 --- a/packages/markitdown/src/markitdown/converters/_xlsx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_xlsx_converter.py @@ -1,9 +1,26 @@ -from typing import Union +import sys -import pandas as pd +from typing import Union from ._base import DocumentConverter, DocumentConverterResult from ._html_converter import HtmlConverter +from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE + +# Try loading optional (but in this case, required) dependencies +# Save reporting of any exceptions for later +_xlsx_dependency_exc_info = None +try: + import pandas as pd + import openpyxl +except ImportError: + _xlsx_dependency_exc_info = sys.exc_info() + +_xls_dependency_exc_info = None +try: + import pandas as pd + import xlrd +except ImportError: + _xls_dependency_exc_info = sys.exc_info() class XlsxConverter(HtmlConverter): @@ -22,6 +39,18 @@ class XlsxConverter(HtmlConverter): if extension.lower() != ".xlsx": return None + # Check the dependencies + if _xlsx_dependency_exc_info is not None: + raise MissingDependencyException( + MISSING_DEPENDENCY_MESSAGE.format( + converter=type(self).__name__, + extension=".xlsx", + feature="xlsx", + ) + ) from _xlsx_dependency_exc_info[1].with_traceback( + _xlsx_dependency_exc_info[2] + ) # Restore the original traceback + sheets = pd.read_excel(local_path, sheet_name=None, engine="openpyxl") md_content = "" for s in sheets: @@ -46,6 +75,18 @@ class XlsConverter(HtmlConverter): if extension.lower() != ".xls": return None + # Load the dependencies + if _xls_dependency_exc_info is not None: + raise MissingDependencyException( + MISSING_DEPENDENCY_MESSAGE.format( + converter=type(self).__name__, + extension=".xls", + feature="xls", + ) + ) from _xls_dependency_exc_info[1].with_traceback( + _xls_dependency_exc_info[2] + ) # Restore the original traceback + sheets = pd.read_excel(local_path, sheet_name=None, engine="xlrd") md_content = "" for s in sheets: From 1d2f231146c42713cc5c121c10004770267bdc0e Mon Sep 17 00:00:00 2001 From: afourney Date: Mon, 3 Mar 2025 09:45:36 -0800 Subject: [PATCH 23/33] Fixed property name (#1085) --- packages/markitdown/src/markitdown/converters/_base.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/markitdown/src/markitdown/converters/_base.py b/packages/markitdown/src/markitdown/converters/_base.py index 3947797..0f351fc 100644 --- a/packages/markitdown/src/markitdown/converters/_base.py +++ b/packages/markitdown/src/markitdown/converters/_base.py @@ -55,9 +55,9 @@ class DocumentConverter: return self._priority @priority.setter - def radius(self, value: float): + def priority(self, value: float): self._priority = value @priority.deleter - def radius(self): + def priority(self): raise AttributeError("Cannot delete the priority attribute") From e921497f794e8f6a6cdf9872d2a29e187448c7eb Mon Sep 17 00:00:00 2001 From: afourney Date: Wed, 5 Mar 2025 21:16:55 -0800 Subject: [PATCH 24/33] Update converter API, user streams rather than file paths (#1088) * Updated DocumentConverter interface * Updated all DocumentConverter classes * Added support for various new audio files. * Updated sample plugin to new DocumentConverter interface. * Updated project README with notes about changes, and use-cases. * Updated DocumentConverter documentation. * Move priority to outside DocumentConverter, allowing them to be reprioritized, and keeping the DocumentConverter interface simple. --------- Co-authored-by: Kenny Zhang --- .gitattributes | 3 +- README.md | 17 +- packages/markitdown-sample-plugin/README.md | 47 +- .../markitdown-sample-plugin/pyproject.toml | 2 +- .../src/markitdown_sample_plugin/__about__.py | 2 +- .../src/markitdown_sample_plugin/_plugin.py | 59 ++- .../tests/test_sample_plugin.py | 20 +- packages/markitdown/pyproject.toml | 7 +- .../markitdown/src/markitdown/__about__.py | 2 +- .../markitdown/src/markitdown/__init__.py | 12 +- .../src/markitdown/_base_converter.py | 108 ++++ .../markitdown/src/markitdown/_exceptions.py | 5 +- .../markitdown/src/markitdown/_markitdown.py | 484 +++++++++++------- .../markitdown/src/markitdown/_stream_info.py | 122 +++++ .../src/markitdown/converters/__init__.py | 9 +- .../markitdown/converters/_audio_converter.py | 102 ++++ .../src/markitdown/converters/_base.py | 63 --- .../converters/_bing_serp_converter.py | 73 ++- .../converters/_doc_intel_converter.py | 143 ++++-- .../markitdown/converters/_docx_converter.py | 70 ++- .../src/markitdown/converters/_exiftool.py | 44 ++ .../markitdown/converters/_html_converter.py | 84 ++- .../markitdown/converters/_image_converter.py | 114 +++-- .../markitdown/converters/_ipynb_converter.py | 69 ++- .../src/markitdown/converters/_llm_caption.py | 50 ++ .../src/markitdown/converters/_markdownify.py | 27 +- .../markitdown/converters/_media_converter.py | 41 -- .../markitdown/converters/_mp3_converter.py | 89 ---- .../converters/_outlook_msg_converter.py | 133 +++-- .../markitdown/converters/_pdf_converter.py | 60 ++- .../converters/_plain_text_converter.py | 79 +-- .../markitdown/converters/_pptx_converter.py | 183 ++++--- .../markitdown/converters/_rss_converter.py | 225 ++++---- .../converters/_transcribe_audio.py | 43 ++ .../markitdown/converters/_wav_converter.py | 72 --- .../converters/_wikipedia_converter.py | 72 ++- .../markitdown/converters/_xlsx_converter.py | 125 +++-- .../converters/_youtube_converter.py | 117 +++-- .../markitdown/converters/_zip_converter.py | 163 +++--- packages/markitdown/tests/test_cli.py | 2 +- packages/markitdown/tests/test_files/test.m4a | Bin 0 -> 165924 bytes packages/markitdown/tests/test_files/test.mp3 | Bin 0 -> 156258 bytes packages/markitdown/tests/test_files/test.pdf | Bin 0 -> 92971 bytes .../markitdown/tests/test_files/test.pptx | Bin 127413 -> 277515 bytes packages/markitdown/tests/test_files/test.wav | Bin 0 -> 1237070 bytes .../tests/test_files/test_notebook.ipynb | 174 +++---- packages/markitdown/tests/test_markitdown.py | 277 +++++++++- 47 files changed, 2329 insertions(+), 1264 deletions(-) create mode 100644 packages/markitdown/src/markitdown/_base_converter.py create mode 100644 packages/markitdown/src/markitdown/_stream_info.py create mode 100644 packages/markitdown/src/markitdown/converters/_audio_converter.py delete mode 100644 packages/markitdown/src/markitdown/converters/_base.py create mode 100644 packages/markitdown/src/markitdown/converters/_exiftool.py create mode 100644 packages/markitdown/src/markitdown/converters/_llm_caption.py delete mode 100644 packages/markitdown/src/markitdown/converters/_media_converter.py delete mode 100644 packages/markitdown/src/markitdown/converters/_mp3_converter.py create mode 100644 packages/markitdown/src/markitdown/converters/_transcribe_audio.py delete mode 100644 packages/markitdown/src/markitdown/converters/_wav_converter.py create mode 100755 packages/markitdown/tests/test_files/test.m4a create mode 100644 packages/markitdown/tests/test_files/test.mp3 create mode 100644 packages/markitdown/tests/test_files/test.pdf create mode 100644 packages/markitdown/tests/test_files/test.wav diff --git a/.gitattributes b/.gitattributes index d2f31ef..f787c0e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -tests/test_files/** linguist-vendored +packages/markitdown/tests/test_files/** linguist-vendored +packages/markitdown-sample-plugin/tests/test_files/** linguist-vendored diff --git a/README.md b/README.md index 2563a68..5f9ef70 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,11 @@ > [!IMPORTANT] > Breaking changes between 0.0.1 to 0.0.2: > * Dependencies are now organized into optional feature-groups (further details below). Use `pip install markitdown[all]` to have backward-compatible behavior. +> * The DocumentConverter class interface has changed to read from file-like streams rather than file paths. *No temporary files are created anymore*. If you are the maintainer of a plugin, or custom DocumentConverter, you likely need to update your code. Otherwise, if only using the MarkItDown class or CLI (as in these examples), you should not need to change anything. -MarkItDown is a utility for converting various files to Markdown (e.g., for indexing, text analysis, etc). -It supports: +MarkItDown is a lightweight Python utility for converting various files to Markdown for use with LLMs and related text analysis pipelines. To this end, it is most comparable to [textract](https://github.com/deanmalmgren/textract), but with a focus on preserving important document structure and content as Markdown (including: headings, lists, tables, links, etc.) While the output is often reasonably presentable and human-friendly, it is meant to be consumed by text analysis tools -- and may not be the best option for high-fidelity document conversions for human consumption. + +At present, MarkItDown supports: - PDF - PowerPoint @@ -23,6 +25,17 @@ It supports: - Youtube URLs - ... and more! +## Why Markdown? + +Markdown is extremely close to plain text, with minimal markup or formatting, but still +provides a way to represent important document structure. Mainstream LLMs, such as +OpenAI's GPT-4o, natively "_speak_" Markdown, and often incorporate Markdown into their +responses unprompted. This suggests that they have been trained on vast amounts of +Markdown-formatted text, and understand it well. As a side benefit, Markdown conventions +are also highly token-efficient. + +## Installation + To install MarkItDown, use pip: `pip install markitdown[all]`. Alternatively, you can install it from the source: ```bash diff --git a/packages/markitdown-sample-plugin/README.md b/packages/markitdown-sample-plugin/README.md index 06324cd..fd7115f 100644 --- a/packages/markitdown-sample-plugin/README.md +++ b/packages/markitdown-sample-plugin/README.md @@ -10,23 +10,38 @@ This project shows how to create a sample plugin for MarkItDown. The most import Next, implement your custom DocumentConverter: ```python -from typing import Union -from markitdown import DocumentConverter, DocumentConverterResult +from typing import BinaryIO, Any +from markitdown import MarkItDown, DocumentConverter, DocumentConverterResult, StreamInfo class RtfConverter(DocumentConverter): - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not an RTF file - extension = kwargs.get("file_extension", "") - if extension.lower() != ".rtf": - return None - # Implement the conversion logic here ... + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) - # Return the result - return DocumentConverterResult( - title=title, - text_content=text_content, - ) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, + ) -> bool: + + # Implement logic to check if the file stream is an RTF file + # ... + raise NotImplementedError() + + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, + ) -> DocumentConverterResult: + + # Implement logic to convert the file stream to Markdown + # ... + raise NotImplementedError() ``` Next, make sure your package implements and exports the following: @@ -71,10 +86,10 @@ Once the plugin package is installed, verify that it is available to MarkItDown markitdown --list-plugins ``` -To use the plugin for a conversion use the `--use-plugins` flag. For example, to convert a PDF: +To use the plugin for a conversion use the `--use-plugins` flag. For example, to convert an RTF file: ```bash -markitdown --use-plugins path-to-file.pdf +markitdown --use-plugins path-to-file.rtf ``` In Python, plugins can be enabled as follows: @@ -83,7 +98,7 @@ In Python, plugins can be enabled as follows: from markitdown import MarkItDown md = MarkItDown(enable_plugins=True) -result = md.convert("path-to-file.pdf") +result = md.convert("path-to-file.rtf") print(result.text_content) ``` diff --git a/packages/markitdown-sample-plugin/pyproject.toml b/packages/markitdown-sample-plugin/pyproject.toml index aaf2012..d8668aa 100644 --- a/packages/markitdown-sample-plugin/pyproject.toml +++ b/packages/markitdown-sample-plugin/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ "Programming Language :: Python :: Implementation :: PyPy", ] dependencies = [ - "markitdown", + "markitdown>=0.0.2a2", "striprtf", ] diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py index fa67ccb..a365900 100644 --- a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.0.1a2" +__version__ = "0.0.1a3" diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py index 98e660e..1362818 100644 --- a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py @@ -1,12 +1,26 @@ -from typing import Union +import locale +from typing import BinaryIO, Any from striprtf.striprtf import rtf_to_text -from markitdown import MarkItDown, DocumentConverter, DocumentConverterResult +from markitdown import ( + MarkItDown, + DocumentConverter, + DocumentConverterResult, + StreamInfo, +) + __plugin_interface_version__ = ( 1 # The version of the plugin interface that this plugin uses ) +ACCEPTED_MIME_TYPE_PREFIXES = [ + "text/rtf", + "application/rtf", +] + +ACCEPTED_FILE_EXTENSIONS = [".rtf"] + def register_converters(markitdown: MarkItDown, **kwargs): """ @@ -22,18 +36,41 @@ class RtfConverter(DocumentConverter): Converts an RTF file to in the simplest possible way. """ - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a RTF - extension = kwargs.get("file_extension", "") - if extension.lower() != ".rtf": - return None + def __init__( + self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + ): + super().__init__(priority=priority) - # Read the RTF file - with open(local_path, "r") as f: - rtf = f.read() + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, + ) -> DocumentConverterResult: + # Read the file stream into an str using hte provided charset encoding, or using the system default + encoding = stream_info.charset or locale.getpreferredencoding() + stream_data = file_stream.read().decode(encoding) # Return the result return DocumentConverterResult( title=None, - text_content=rtf_to_text(rtf), + markdown=rtf_to_text(stream_data), ) diff --git a/packages/markitdown-sample-plugin/tests/test_sample_plugin.py b/packages/markitdown-sample-plugin/tests/test_sample_plugin.py index 49d54aa..6d0102d 100644 --- a/packages/markitdown-sample-plugin/tests/test_sample_plugin.py +++ b/packages/markitdown-sample-plugin/tests/test_sample_plugin.py @@ -2,7 +2,7 @@ import os import pytest -from markitdown import MarkItDown +from markitdown import MarkItDown, StreamInfo from markitdown_sample_plugin import RtfConverter TEST_FILES_DIR = os.path.join(os.path.dirname(__file__), "test_files") @@ -15,18 +15,22 @@ RTF_TEST_STRINGS = { def test_converter() -> None: """Tests the RTF converter dirctly.""" - converter = RtfConverter() - result = converter.convert( - os.path.join(TEST_FILES_DIR, "test.rtf"), file_extension=".rtf" - ) + with open(os.path.join(TEST_FILES_DIR, "test.rtf"), "rb") as file_stream: + converter = RtfConverter() + result = converter.convert( + file_stream=file_stream, + stream_info=StreamInfo( + mimetype="text/rtf", extension=".rtf", filename="test.rtf" + ), + ) - for test_string in RTF_TEST_STRINGS: - assert test_string in result.text_content + for test_string in RTF_TEST_STRINGS: + assert test_string in result.text_content def test_markitdown() -> None: """Tests that MarkItDown correctly loads the plugin.""" - md = MarkItDown() + md = MarkItDown(enable_plugins=True) result = md.convert(os.path.join(TEST_FILES_DIR, "test.rtf")) for test_string in RTF_TEST_STRINGS: diff --git a/packages/markitdown/pyproject.toml b/packages/markitdown/pyproject.toml index c053c7b..d0f515e 100644 --- a/packages/markitdown/pyproject.toml +++ b/packages/markitdown/pyproject.toml @@ -26,7 +26,7 @@ classifiers = [ dependencies = [ "beautifulsoup4", "requests", - "markdownify~=0.14.1", + "markdownify", "puremagic", "pathvalidate", "charset-normalizer", @@ -78,11 +78,14 @@ extra-dependencies = [ ] [tool.hatch.envs.types] +features = ["all"] extra-dependencies = [ + "openai", "mypy>=1.0.0", ] + [tool.hatch.envs.types.scripts] -check = "mypy --install-types --non-interactive {args:src/markitdown tests}" +check = "mypy --install-types --non-interactive --ignore-missing-imports {args:src/markitdown tests}" [tool.coverage.run] source_pkgs = ["markitdown", "tests"] diff --git a/packages/markitdown/src/markitdown/__about__.py b/packages/markitdown/src/markitdown/__about__.py index dc5aafc..4ebb498 100644 --- a/packages/markitdown/src/markitdown/__about__.py +++ b/packages/markitdown/src/markitdown/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.0.2a1" +__version__ = "0.0.2a2" diff --git a/packages/markitdown/src/markitdown/__init__.py b/packages/markitdown/src/markitdown/__init__.py index 9f7db16..af356dd 100644 --- a/packages/markitdown/src/markitdown/__init__.py +++ b/packages/markitdown/src/markitdown/__init__.py @@ -3,7 +3,13 @@ # SPDX-License-Identifier: MIT from .__about__ import __version__ -from ._markitdown import MarkItDown +from ._markitdown import ( + MarkItDown, + PRIORITY_SPECIFIC_FILE_FORMAT, + PRIORITY_GENERIC_FILE_FORMAT, +) +from ._base_converter import DocumentConverterResult, DocumentConverter +from ._stream_info import StreamInfo from ._exceptions import ( MarkItDownException, MissingDependencyException, @@ -11,7 +17,6 @@ from ._exceptions import ( FileConversionException, UnsupportedFormatException, ) -from .converters import DocumentConverter, DocumentConverterResult __all__ = [ "__version__", @@ -23,4 +28,7 @@ __all__ = [ "FailedConversionAttempt", "FileConversionException", "UnsupportedFormatException", + "StreamInfo", + "PRIORITY_SPECIFIC_FILE_FORMAT", + "PRIORITY_GENERIC_FILE_FORMAT", ] diff --git a/packages/markitdown/src/markitdown/_base_converter.py b/packages/markitdown/src/markitdown/_base_converter.py new file mode 100644 index 0000000..2f0ca9d --- /dev/null +++ b/packages/markitdown/src/markitdown/_base_converter.py @@ -0,0 +1,108 @@ +import os +import tempfile +from warnings import warn +from typing import Any, Union, BinaryIO, Optional, List +from ._stream_info import StreamInfo + + +class DocumentConverterResult: + """The result of converting a document to Markdown.""" + + def __init__( + self, + markdown: str, + *, + title: Optional[str] = None, + ): + """ + Initialize the DocumentConverterResult. + + The only required parameter is the converted Markdown text. + The title, and any other metadata that may be added in the future, are optional. + + Parameters: + - markdown: The converted Markdown text. + - title: Optional title of the document. + """ + self.markdown = markdown + self.title = title + + @property + def text_content(self) -> str: + """Soft-deprecated alias for `markdown`. New code should migrate to using `markdown` or __str__.""" + return self.markdown + + @text_content.setter + def text_content(self, markdown: str): + """Soft-deprecated alias for `markdown`. New code should migrate to using `markdown` or __str__.""" + self.markdown = markdown + + def __str__(self) -> str: + """Return the converted Markdown text.""" + return self.markdown + + +class DocumentConverter: + """Abstract superclass of all DocumentConverters.""" + + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + """ + Return a quick determination on if the converter should attempt converting the document. + This is primarily based `stream_info` (typically, `stream_info.mimetype`, `stream_info.extension`). + In cases where the data is retrieved via HTTP, the `steam_info.url` might also be referenced to + make a determination (e.g., special converters for Wikipedia, YouTube etc). + Finally, it is conceivable that the `stream_info.filename` might be used to in cases + where the filename is well-known (e.g., `Dockerfile`, `Makefile`, etc) + + NOTE: The method signature is designed to match that of the convert() method. This provides some + assurance that, if accepts() returns True, the convert() method will also be able to handle the document. + + IMPORTANT: In rare cases, (e.g., OutlookMsgConverter) we need to read more from the stream to make a final + determination. Read operations inevitably advances the position in file_stream. In these case, the position + MUST be reset it MUST be reset before returning. This is because the convert() method may be called immediately + after accepts(), and will expect the file_stream to be at the original position. + + E.g., + cur_pos = file_stream.tell() # Save the current position + data = file_stream.read(100) # ... peek at the first 100 bytes, etc. + file_stream.seek(cur_pos) # Reset the position to the original position + + Prameters: + - file_stream: The file-like object to convert. Must support seek(), tell(), and read() methods. + - stream_info: The StreamInfo object containing metadata about the file (mimetype, extension, charset, set) + - kwargs: Additional keyword arguments for the converter. + + Returns: + - bool: True if the converter can handle the document, False otherwise. + """ + raise NotImplementedError( + f"The subclass, {type(self).__name__}, must implement the accepts() method to determine if they can handle the document." + ) + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: + """ + Convert a document to Markdown text. + + Prameters: + - file_stream: The file-like object to convert. Must support seek(), tell(), and read() methods. + - stream_info: The StreamInfo object containing metadata about the file (mimetype, extension, charset, set) + - kwargs: Additional keyword arguments for the converter. + + Returns: + - DocumentConverterResult: The result of the conversion, which includes the title and markdown content. + + Raises: + - FileConversionException: If the mimetype is recognized, but the conversion fails for some other reason. + - MissingDependencyException: If the converter requires a dependency that is not installed. + """ + raise NotImplementedError("Subclasses must implement this method") diff --git a/packages/markitdown/src/markitdown/_exceptions.py b/packages/markitdown/src/markitdown/_exceptions.py index abfebc6..93f8f0e 100644 --- a/packages/markitdown/src/markitdown/_exceptions.py +++ b/packages/markitdown/src/markitdown/_exceptions.py @@ -68,6 +68,9 @@ class FileConversionException(MarkItDownException): else: message = f"File conversion failed after {len(attempts)} attempts:\n" for attempt in attempts: - message += f" - {type(attempt.converter).__name__} threw {attempt.exc_info[0].__name__} with message: {attempt.exc_info[1]}\n" + if attempt.exc_info is None: + message += " - {type(attempt.converter).__name__} provided no execution info." + else: + message += f" - {type(attempt.converter).__name__} threw {attempt.exc_info[0].__name__} with message: {attempt.exc_info[1]}\n" super().__init__(message) diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index 8f1bd46..6086eb9 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -6,8 +6,10 @@ import sys import tempfile import warnings import traceback +import io +from dataclasses import dataclass from importlib.metadata import entry_points -from typing import Any, List, Optional, Union +from typing import Any, List, Optional, Union, BinaryIO from pathlib import Path from urllib.parse import urlparse from warnings import warn @@ -16,9 +18,9 @@ from warnings import warn import puremagic import requests +from ._stream_info import StreamInfo, _guess_stream_info_from_stream + from .converters import ( - DocumentConverter, - DocumentConverterResult, PlainTextConverter, HtmlConverter, RssConverter, @@ -32,26 +34,34 @@ from .converters import ( XlsConverter, PptxConverter, ImageConverter, - WavConverter, - Mp3Converter, + AudioConverter, OutlookMsgConverter, ZipConverter, DocumentIntelligenceConverter, ) +from ._base_converter import DocumentConverter, DocumentConverterResult + from ._exceptions import ( FileConversionException, UnsupportedFormatException, FailedConversionAttempt, ) -# Override mimetype for csv to fix issue on windows -mimetypes.add_type("text/csv", ".csv") -_plugins: Union[None | List[Any]] = None +# Lower priority values are tried first. +PRIORITY_SPECIFIC_FILE_FORMAT = ( + 0.0 # e.g., .docx, .pdf, .xlsx, Or specific pages, e.g., wikipedia +) +PRIORITY_GENERIC_FILE_FORMAT = ( + 10.0 # Near catch-all converters for mimetypes like text/*, etc. +) -def _load_plugins() -> Union[None | List[Any]]: +_plugins: List[Any] = [] + + +def _load_plugins() -> List[Any]: """Lazy load plugins, exiting early if already loaded.""" global _plugins @@ -71,6 +81,14 @@ def _load_plugins() -> Union[None | List[Any]]: return _plugins +@dataclass(kw_only=True, frozen=True) +class ConverterRegistration: + """A registration of a converter with its priority and other metadata.""" + + converter: DocumentConverter + priority: float + + class MarkItDown: """(In preview) An extremely simple text-based document reader, suitable for LLM use. This reader will convert common file-types or webpages to Markdown.""" @@ -92,13 +110,13 @@ class MarkItDown: self._requests_session = requests_session # TODO - remove these (see enable_builtins) - self._llm_client = None - self._llm_model = None - self._exiftool_path = None - self._style_map = None + self._llm_client: Any = None + self._llm_model: Union[str | None] = None + self._exiftool_path: Union[str | None] = None + self._style_map: Union[str | None] = None # Register the converters - self._page_converters: List[DocumentConverter] = [] + self._converters: List[ConverterRegistration] = [] if ( enable_builtins is None or enable_builtins @@ -126,9 +144,15 @@ class MarkItDown: # Register converters for successful browsing operations # Later registrations are tried first / take higher priority than earlier registrations # To this end, the most specific converters should appear below the most generic converters - self.register_converter(PlainTextConverter()) - self.register_converter(ZipConverter()) - self.register_converter(HtmlConverter()) + self.register_converter( + PlainTextConverter(), priority=PRIORITY_GENERIC_FILE_FORMAT + ) + self.register_converter( + ZipConverter(markitdown=self), priority=PRIORITY_GENERIC_FILE_FORMAT + ) + self.register_converter( + HtmlConverter(), priority=PRIORITY_GENERIC_FILE_FORMAT + ) self.register_converter(RssConverter()) self.register_converter(WikipediaConverter()) self.register_converter(YouTubeConverter()) @@ -137,8 +161,7 @@ class MarkItDown: self.register_converter(XlsxConverter()) self.register_converter(XlsConverter()) self.register_converter(PptxConverter()) - self.register_converter(WavConverter()) - self.register_converter(Mp3Converter()) + self.register_converter(AudioConverter()) self.register_converter(ImageConverter()) self.register_converter(IpynbConverter()) self.register_converter(PdfConverter()) @@ -174,12 +197,17 @@ class MarkItDown: warn("Plugins converters are already enabled.", RuntimeWarning) def convert( - self, source: Union[str, requests.Response, Path], **kwargs: Any + self, + source: Union[str, requests.Response, Path, BinaryIO], + *, + stream_info: Optional[StreamInfo] = None, + **kwargs: Any, ) -> DocumentConverterResult: # TODO: deal with kwargs """ Args: - - source: can be a string representing a path either as string pathlib path object or url, or a requests.response object - - extension: specifies the file extension to use when interpreting the file. If None, infer from source (path, uri, content-type, etc.) + - source: can be a path (str or Path), url, or a requests.response object + - stream_info: optional stream info to use for the conversion. If None, infer from source + - kwargs: additional arguments to pass to the converter """ # Local path or url @@ -191,68 +219,120 @@ class MarkItDown: ): return self.convert_url(source, **kwargs) else: - return self.convert_local(source, **kwargs) + return self.convert_local(source, stream_info=stream_info, **kwargs) + # Path object + elif isinstance(source, Path): + return self.convert_local(source, stream_info=stream_info, **kwargs) # Request response elif isinstance(source, requests.Response): return self.convert_response(source, **kwargs) - elif isinstance(source, Path): - return self.convert_local(source, **kwargs) + # Binary stream + elif ( + hasattr(source, "read") + and callable(source.read) + and not isinstance(source, io.TextIOBase) + ): + return self.convert_stream(source, **kwargs) + else: + raise TypeError( + f"Invalid source type: {type(source)}. Expected str, requests.Response, BinaryIO." + ) def convert_local( - self, path: Union[str, Path], **kwargs: Any - ) -> DocumentConverterResult: # TODO: deal with kwargs + self, + path: Union[str, Path], + *, + stream_info: Optional[StreamInfo] = None, + file_extension: Optional[str] = None, # Deprecated -- use stream_info + url: Optional[str] = None, # Deprecated -- use stream_info + **kwargs: Any, + ) -> DocumentConverterResult: if isinstance(path, Path): path = str(path) - # Prepare a list of extensions to try (in order of priority) - ext = kwargs.get("file_extension") - extensions = [ext] if ext is not None else [] - # Get extension alternatives from the path and puremagic - base, ext = os.path.splitext(path) - self._append_ext(extensions, ext) + # Build a base StreamInfo object from which to start guesses + base_stream_info = StreamInfo( + local_path=path, + extension=os.path.splitext(path)[1], + filename=os.path.basename(path), + ) - for g in self._guess_ext_magic(path): - self._append_ext(extensions, g) + # Extend the base_stream_info with any additional info from the arguments + if stream_info is not None: + base_stream_info = base_stream_info.copy_and_update(stream_info) - # Convert - return self._convert(path, extensions, **kwargs) + if file_extension is not None: + # Deprecated -- use stream_info + base_stream_info = base_stream_info.copy_and_update( + extension=file_extension + ) + + if url is not None: + # Deprecated -- use stream_info + base_stream_info = base_stream_info.copy_and_update(url=url) + + with open(path, "rb") as fh: + # Prepare a list of configurations to try, starting with the base_stream_info + guesses: List[StreamInfo] = [base_stream_info] + for guess in _guess_stream_info_from_stream( + file_stream=fh, filename_hint=path + ): + guesses.append(base_stream_info.copy_and_update(guess)) + return self._convert(file_stream=fh, stream_info_guesses=guesses, **kwargs) - # TODO what should stream's type be? def convert_stream( - self, stream: Any, **kwargs: Any - ) -> DocumentConverterResult: # TODO: deal with kwargs - # Prepare a list of extensions to try (in order of priority) - ext = kwargs.get("file_extension") - extensions = [ext] if ext is not None else [] + self, + stream: BinaryIO, + *, + stream_info: Optional[StreamInfo] = None, + file_extension: Optional[str] = None, # Deprecated -- use stream_info + url: Optional[str] = None, # Deprecated -- use stream_info + **kwargs: Any, + ) -> DocumentConverterResult: + guesses: List[StreamInfo] = [] - # Save the file locally to a temporary file. It will be deleted before this method exits - handle, temp_path = tempfile.mkstemp() - fh = os.fdopen(handle, "wb") - result = None - try: - # Write to the temporary file - content = stream.read() - if isinstance(content, str): - fh.write(content.encode("utf-8")) + # Do we have anything on which to base a guess? + base_guess = None + if stream_info is not None or file_extension is not None or url is not None: + # Start with a non-Null base guess + if stream_info is None: + base_guess = StreamInfo() else: - fh.write(content) - fh.close() + base_guess = stream_info - # Use puremagic to check for more extension options - for g in self._guess_ext_magic(temp_path): - self._append_ext(extensions, g) + if file_extension is not None: + # Deprecated -- use stream_info + assert base_guess is not None # for mypy + base_guess = base_guess.copy_and_update(extension=file_extension) - # Convert - result = self._convert(temp_path, extensions, **kwargs) - # Clean up - finally: - try: - fh.close() - except Exception: - pass - os.unlink(temp_path) + if url is not None: + # Deprecated -- use stream_info + assert base_guess is not None # for mypy + base_guess = base_guess.copy_and_update(url=url) - return result + # Append the base guess, if it's non-trivial + if base_guess is not None: + if base_guess.mimetype is not None or base_guess.extension is not None: + guesses.append(base_guess) + else: + # Create a base guess with no information + base_guess = StreamInfo() + + # Create a placeholder filename to help with guessing + placeholder_filename = None + if base_guess.filename is not None: + placeholder_filename = base_guess.filename + elif base_guess.extension is not None: + placeholder_filename = "placeholder" + base_guess.extension + + # Add guesses based on stream content + for guess in _guess_stream_info_from_stream( + file_stream=stream, filename_hint=placeholder_filename + ): + guesses.append(base_guess.copy_and_update(guess)) + + # Perform the conversion + return self._convert(file_stream=stream, stream_info_guesses=guesses, **kwargs) def convert_url( self, url: str, **kwargs: Any @@ -263,55 +343,94 @@ class MarkItDown: return self.convert_response(response, **kwargs) def convert_response( - self, response: requests.Response, **kwargs: Any - ) -> DocumentConverterResult: # TODO fix kwargs type - # Prepare a list of extensions to try (in order of priority) - ext = kwargs.get("file_extension") - extensions = [ext] if ext is not None else [] + self, + response: requests.Response, + *, + stream_info: Optional[StreamInfo] = None, + file_extension: Optional[str] = None, # Deprecated -- use stream_info + url: Optional[str] = None, # Deprecated -- use stream_info + **kwargs: Any, + ) -> DocumentConverterResult: + # If there is a content-type header, get the mimetype and charset (if present) + mimetype: Optional[str] = None + charset: Optional[str] = None - # Guess from the mimetype - content_type = response.headers.get("content-type", "").split(";")[0] - self._append_ext(extensions, mimetypes.guess_extension(content_type)) + if "content-type" in response.headers: + parts = response.headers["content-type"].split(";") + mimetype = parts.pop(0).strip() + for part in parts: + if part.strip().startswith("charset="): + _charset = part.split("=")[1].strip() + if len(_charset) > 0: + charset = _charset - # Read the content disposition if there is one - content_disposition = response.headers.get("content-disposition", "") - m = re.search(r"filename=([^;]+)", content_disposition) - if m: - base, ext = os.path.splitext(m.group(1).strip("\"'")) - self._append_ext(extensions, ext) + # If there is a content-disposition header, get the filename and possibly the extension + filename: Optional[str] = None + extension: Optional[str] = None + if "content-disposition" in response.headers: + m = re.search(r"filename=([^;]+)", response.headers["content-disposition"]) + if m: + filename = m.group(1).strip("\"'") + _, _extension = os.path.splitext(filename) + if len(_extension) > 0: + extension = _extension - # Read from the extension from the path - base, ext = os.path.splitext(urlparse(response.url).path) - self._append_ext(extensions, ext) + # If there is still no filename, try to read it from the url + if filename is None: + parsed_url = urlparse(response.url) + _, _extension = os.path.splitext(parsed_url.path) + if len(_extension) > 0: # Looks like this might be a file! + filename = os.path.basename(parsed_url.path) + extension = _extension - # Save the file locally to a temporary file. It will be deleted before this method exits - handle, temp_path = tempfile.mkstemp() - fh = os.fdopen(handle, "wb") - result = None - try: - # Download the file - for chunk in response.iter_content(chunk_size=512): - fh.write(chunk) - fh.close() + # Create an initial guess from all this information + base_guess = StreamInfo( + mimetype=mimetype, + charset=charset, + filename=filename, + extension=extension, + url=response.url, + ) - # Use puremagic to check for more extension options - for g in self._guess_ext_magic(temp_path): - self._append_ext(extensions, g) + # Update with any additional info from the arguments + if stream_info is not None: + base_guess = base_guess.copy_and_update(stream_info) + if file_extension is not None: + # Deprecated -- use stream_info + base_guess = base_guess.copy_and_update(extension=file_extension) + if url is not None: + # Deprecated -- use stream_info + base_guess = base_guess.copy_and_update(url=url) - # Convert - result = self._convert(temp_path, extensions, url=response.url, **kwargs) - # Clean up - finally: - try: - fh.close() - except Exception: - pass - os.unlink(temp_path) + # Add the guess if its non-trivial + guesses: List[StreamInfo] = [] + if base_guess.mimetype is not None or base_guess.extension is not None: + guesses.append(base_guess) - return result + # Read into BytesIO + buffer = io.BytesIO() + for chunk in response.iter_content(chunk_size=512): + buffer.write(chunk) + buffer.seek(0) + + # Create a placeholder filename to help with guessing + placeholder_filename = None + if base_guess.filename is not None: + placeholder_filename = base_guess.filename + elif base_guess.extension is not None: + placeholder_filename = "placeholder" + base_guess.extension + + # Add guesses based on stream content + for guess in _guess_stream_info_from_stream( + file_stream=buffer, filename_hint=placeholder_filename + ): + guesses.append(base_guess.copy_and_update(guess)) + + # Convert + return self._convert(file_stream=buffer, stream_info_guesses=guesses, **kwargs) def _convert( - self, local_path: str, extensions: List[Union[str, None]], **kwargs + self, *, file_stream: BinaryIO, stream_info_guesses: List[StreamInfo], **kwargs ) -> DocumentConverterResult: res: Union[None, DocumentConverterResult] = None @@ -321,19 +440,21 @@ class MarkItDown: # Create a copy of the page_converters list, sorted by priority. # We do this with each call to _convert because the priority of converters may change between calls. # The sort is guaranteed to be stable, so converters with the same priority will remain in the same order. - sorted_converters = sorted(self._page_converters, key=lambda x: x.priority) + sorted_registrations = sorted(self._converters, key=lambda x: x.priority) + + # Remember the initial stream position so that we can return to it + cur_pos = file_stream.tell() + + for stream_info in stream_info_guesses + [StreamInfo()]: + for converter_registration in sorted_registrations: + converter = converter_registration.converter + # Sanity check -- make sure the cur_pos is still the same + assert ( + cur_pos == file_stream.tell() + ), f"File stream position should NOT change between guess iterations" - for ext in extensions + [None]: # Try last with no extension - for converter in sorted_converters: _kwargs = copy.deepcopy(kwargs) - # Overwrite file_extension appropriately - if ext is None: - if "file_extension" in _kwargs: - del _kwargs["file_extension"] - else: - _kwargs.update({"file_extension": ext}) - # Copy any additional global options if "llm_client" not in _kwargs and self._llm_client is not None: _kwargs["llm_client"] = self._llm_client @@ -348,17 +469,40 @@ class MarkItDown: _kwargs["exiftool_path"] = self._exiftool_path # Add the list of converters for nested processing - _kwargs["_parent_converters"] = self._page_converters + _kwargs["_parent_converters"] = self._converters - # If we hit an error log it and keep trying + # Add legaxy kwargs + if stream_info is not None: + if stream_info.extension is not None: + _kwargs["file_extension"] = stream_info.extension + + if stream_info.url is not None: + _kwargs["url"] = stream_info.url + + # Check if the converter will accept the file, and if so, try to convert it + _accepts = False try: - res = converter.convert(local_path, **_kwargs) - except Exception: - failed_attempts.append( - FailedConversionAttempt( - converter=converter, exc_info=sys.exc_info() + _accepts = converter.accepts(file_stream, stream_info, **_kwargs) + except NotImplementedError: + pass + + # accept() should not have changed the file stream position + assert ( + cur_pos == file_stream.tell() + ), f"{type(converter).__name__}.accept() should NOT change the file_stream position" + + # Attempt the conversion + if _accepts: + try: + res = converter.convert(file_stream, stream_info, **_kwargs) + except Exception: + failed_attempts.append( + FailedConversionAttempt( + converter=converter, exc_info=sys.exc_info() + ) ) - ) + finally: + file_stream.seek(cur_pos) if res is not None: # Normalize the content @@ -366,8 +510,6 @@ class MarkItDown: [line.rstrip() for line in re.split(r"\r?\n", res.text_content)] ) res.text_content = re.sub(r"\n{3,}", "\n\n", res.text_content) - - # Todo return res # If we got this far without success, report any exceptions @@ -376,61 +518,9 @@ class MarkItDown: # Nothing can handle it! raise UnsupportedFormatException( - f"Could not convert '{local_path}' to Markdown. No converter attempted a conversion, suggesting that the filetype is simply not supported." + f"Could not convert stream to Markdown. No converter attempted a conversion, suggesting that the filetype is simply not supported." ) - def _append_ext(self, extensions, ext): - """Append a unique non-None, non-empty extension to a list of extensions.""" - if ext is None: - return - ext = ext.strip() - if ext == "": - return - if ext in extensions: - return - extensions.append(ext) - - def _guess_ext_magic(self, path): - """Use puremagic (a Python implementation of libmagic) to guess a file's extension based on the first few bytes.""" - # Use puremagic to guess - try: - guesses = puremagic.magic_file(path) - - # Fix for: https://github.com/microsoft/markitdown/issues/222 - # If there are no guesses, then try again after trimming leading ASCII whitespaces. - # ASCII whitespace characters are those byte values in the sequence b' \t\n\r\x0b\f' - # (space, tab, newline, carriage return, vertical tab, form feed). - if len(guesses) == 0: - with open(path, "rb") as file: - while True: - char = file.read(1) - if not char: # End of file - break - if not char.isspace(): - file.seek(file.tell() - 1) - break - try: - guesses = puremagic.magic_stream(file) - except puremagic.main.PureError: - pass - - extensions = list() - for g in guesses: - ext = g.extension.strip() - if len(ext) > 0: - if not ext.startswith("."): - ext = "." + ext - if ext not in extensions: - extensions.append(ext) - return extensions - except FileNotFoundError: - pass - except IsADirectoryError: - pass - except PermissionError: - pass - return [] - def register_page_converter(self, converter: DocumentConverter) -> None: """DEPRECATED: User register_converter instead.""" warn( @@ -439,6 +529,34 @@ class MarkItDown: ) self.register_converter(converter) - def register_converter(self, converter: DocumentConverter) -> None: - """Register a page text converter.""" - self._page_converters.insert(0, converter) + def register_converter( + self, + converter: DocumentConverter, + *, + priority: float = PRIORITY_SPECIFIC_FILE_FORMAT, + ) -> None: + """ + Register a DocumentConverter with a given priority. + + Priorities work as follows: By default, most converters get priority + DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT (== 0). The exception + is the PlainTextConverter, HtmlConverter, and ZipConverter, which get + priority PRIORITY_SPECIFIC_FILE_FORMAT (== 10), with lower values + being tried first (i.e., higher priority). + + Just prior to conversion, the converters are sorted by priority, using + a stable sort. This means that converters with the same priority will + remain in the same order, with the most recently registered converters + appearing first. + + We have tight control over the order of built-in converters, but + plugins can register converters in any order. The registration's priority + field reasserts some control over the order of converters. + + Plugins can register converters with any priority, to appear before or + after the built-ins. For example, a plugin with priority 9 will run + before the PlainTextConverter, but after the built-in converters. + """ + self._converters.insert( + 0, ConverterRegistration(converter=converter, priority=priority) + ) diff --git a/packages/markitdown/src/markitdown/_stream_info.py b/packages/markitdown/src/markitdown/_stream_info.py new file mode 100644 index 0000000..1eaa4d2 --- /dev/null +++ b/packages/markitdown/src/markitdown/_stream_info.py @@ -0,0 +1,122 @@ +import puremagic +import mimetypes +import os +from dataclasses import dataclass, asdict +from typing import Optional, BinaryIO, List, TypeVar, Type + +# Mimetype substitutions table +MIMETYPE_SUBSTITUTIONS = { + "application/excel": "application/vnd.ms-excel", + "application/mspowerpoint": "application/vnd.ms-powerpoint", +} + + +@dataclass(kw_only=True, frozen=True) +class StreamInfo: + """The StreamInfo class is used to store information about a file stream. + All fields can be None, and will depend on how the stream was opened. + """ + + mimetype: Optional[str] = None + extension: Optional[str] = None + charset: Optional[str] = None + filename: Optional[ + str + ] = None # From local path, url, or Content-Disposition header + local_path: Optional[str] = None # If read from disk + url: Optional[str] = None # If read from url + + def copy_and_update(self, *args, **kwargs): + """Copy the StreamInfo object and update it with the given StreamInfo + instance and/or other keyword arguments.""" + new_info = asdict(self) + + for si in args: + assert isinstance(si, StreamInfo) + new_info.update({k: v for k, v in asdict(si).items() if v is not None}) + + if len(kwargs) > 0: + new_info.update(kwargs) + + return StreamInfo(**new_info) + + +# Behavior subject to change. +# Do not rely on this outside of this module. +def _guess_stream_info_from_stream( + file_stream: BinaryIO, + *, + filename_hint: Optional[str] = None, +) -> List[StreamInfo]: + """ + Guess StreamInfo properties (mostly mimetype and extension) from a stream. + + Args: + - stream: The stream to guess the StreamInfo from. + - filename_hint [Optional]: A filename hint to help with the guessing (may be a placeholder, and not actually be the file name) + + Returns a list of StreamInfo objects in order of confidence. + """ + guesses: List[StreamInfo] = [] + + # Add a guess purely based on the filename hint + if filename_hint: + try: + # Requires Python 3.13+ + mimetype, _ = mimetypes.guess_file_type(filename_hint) # type: ignore + except AttributeError: + mimetype, _ = mimetypes.guess_type(filename_hint) + + if mimetype: + guesses.append( + StreamInfo( + mimetype=mimetype, extension=os.path.splitext(filename_hint)[1] + ) + ) + + def _puremagic( + file_stream, filename_hint + ) -> List[puremagic.main.PureMagicWithConfidence]: + """Wrap guesses to handle exceptions.""" + try: + return puremagic.magic_stream(file_stream, filename=filename_hint) + except puremagic.main.PureError as e: + return [] + + cur_pos = file_stream.tell() + type_guesses = _puremagic(file_stream, filename_hint=filename_hint) + if len(type_guesses) == 0: + # Fix for: https://github.com/microsoft/markitdown/issues/222 + # If there are no guesses, then try again after trimming leading ASCII whitespaces. + # ASCII whitespace characters are those byte values in the sequence b' \t\n\r\x0b\f' + # (space, tab, newline, carriage return, vertical tab, form feed). + + # Eat all the leading whitespace + file_stream.seek(cur_pos) + while True: + char = file_stream.read(1) + if not char: # End of file + break + if not char.isspace(): + file_stream.seek(file_stream.tell() - 1) + break + + # Try again + type_guesses = _puremagic(file_stream, filename_hint=filename_hint) + file_stream.seek(cur_pos) + + # Convert and return the guesses + for guess in type_guesses: + kwargs: dict[str, str] = {} + if guess.extension: + kwargs["extension"] = guess.extension + if guess.mime_type: + kwargs["mimetype"] = MIMETYPE_SUBSTITUTIONS.get( + guess.mime_type, guess.mime_type + ) + if len(kwargs) > 0: + # We don't add the filename_hint, because sometimes it's just a placeholder, + # and, in any case, doesn't add new information. + guesses.append(StreamInfo(**kwargs)) + + return guesses diff --git a/packages/markitdown/src/markitdown/converters/__init__.py b/packages/markitdown/src/markitdown/converters/__init__.py index 1e5afe4..f43efe3 100644 --- a/packages/markitdown/src/markitdown/converters/__init__.py +++ b/packages/markitdown/src/markitdown/converters/__init__.py @@ -2,7 +2,6 @@ # # SPDX-License-Identifier: MIT -from ._base import DocumentConverter, DocumentConverterResult from ._plain_text_converter import PlainTextConverter from ._html_converter import HtmlConverter from ._rss_converter import RssConverter @@ -15,15 +14,12 @@ from ._docx_converter import DocxConverter from ._xlsx_converter import XlsxConverter, XlsConverter from ._pptx_converter import PptxConverter from ._image_converter import ImageConverter -from ._wav_converter import WavConverter -from ._mp3_converter import Mp3Converter +from ._audio_converter import AudioConverter from ._outlook_msg_converter import OutlookMsgConverter from ._zip_converter import ZipConverter from ._doc_intel_converter import DocumentIntelligenceConverter __all__ = [ - "DocumentConverter", - "DocumentConverterResult", "PlainTextConverter", "HtmlConverter", "RssConverter", @@ -37,8 +33,7 @@ __all__ = [ "XlsConverter", "PptxConverter", "ImageConverter", - "WavConverter", - "Mp3Converter", + "AudioConverter", "OutlookMsgConverter", "ZipConverter", "DocumentIntelligenceConverter", diff --git a/packages/markitdown/src/markitdown/converters/_audio_converter.py b/packages/markitdown/src/markitdown/converters/_audio_converter.py new file mode 100644 index 0000000..845ad5d --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_audio_converter.py @@ -0,0 +1,102 @@ +import io +from typing import Any, BinaryIO, Optional + +from ._exiftool import exiftool_metadata +from ._transcribe_audio import transcribe_audio +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo +from .._exceptions import MissingDependencyException + +ACCEPTED_MIME_TYPE_PREFIXES = [ + "audio/x-wav", + "audio/mpeg", + "video/mp4", +] + +ACCEPTED_FILE_EXTENSIONS = [ + ".wav", + ".mp3", + ".m4a", + ".mp4", +] + + +class AudioConverter(DocumentConverter): + """ + Converts audio files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` is installed). + """ + + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: + md_content = "" + + # Add metadata + metadata = exiftool_metadata( + file_stream, exiftool_path=kwargs.get("exiftool_path") + ) + if metadata: + for f in [ + "Title", + "Artist", + "Author", + "Band", + "Album", + "Genre", + "Track", + "DateTimeOriginal", + "CreateDate", + # "Duration", -- Wrong values when read from memory + "NumChannels", + "SampleRate", + "AvgBytesPerSec", + "BitsPerSample", + ]: + if f in metadata: + md_content += f"{f}: {metadata[f]}\n" + + # Figure out the audio format for transcription + if stream_info.extension == ".wav" or stream_info.mimetype == "audio/x-wav": + audio_format = "wav" + elif stream_info.extension == ".mp3" or stream_info.mimetype == "audio/mpeg": + audio_format = "mp3" + elif ( + stream_info.extension in [".mp4", ".m4a"] + or stream_info.mimetype == "video/mp4" + ): + audio_format = "mp4" + else: + audio_format = None + + # Transcribe + if audio_format: + try: + transcript = transcribe_audio(file_stream, audio_format=audio_format) + if transcript: + md_content += "\n\n### Audio Transcript:\n" + transcript + except MissingDependencyException: + pass + + # Return the result + return DocumentConverterResult(markdown=md_content.strip()) diff --git a/packages/markitdown/src/markitdown/converters/_base.py b/packages/markitdown/src/markitdown/converters/_base.py deleted file mode 100644 index 0f351fc..0000000 --- a/packages/markitdown/src/markitdown/converters/_base.py +++ /dev/null @@ -1,63 +0,0 @@ -from typing import Any, Union - - -class DocumentConverterResult: - """The result of converting a document to text.""" - - def __init__(self, title: Union[str, None] = None, text_content: str = ""): - self.title: Union[str, None] = title - self.text_content: str = text_content - - -class DocumentConverter: - """Abstract superclass of all DocumentConverters.""" - - # Lower priority values are tried first. - PRIORITY_SPECIFIC_FILE_FORMAT = ( - 0.0 # e.g., .docx, .pdf, .xlsx, Or specific pages, e.g., wikipedia - ) - PRIORITY_GENERIC_FILE_FORMAT = ( - 10.0 # Near catch-all converters for mimetypes like text/*, etc. - ) - - def __init__(self, priority: float = PRIORITY_SPECIFIC_FILE_FORMAT): - """ - Initialize the DocumentConverter with a given priority. - - Priorities work as follows: By default, most converters get priority - DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT (== 0). The exception - is the PlainTextConverter, which gets priority PRIORITY_SPECIFIC_FILE_FORMAT (== 10), - with lower values being tried first (i.e., higher priority). - - Just prior to conversion, the converters are sorted by priority, using - a stable sort. This means that converters with the same priority will - remain in the same order, with the most recently registered converters - appearing first. - - We have tight control over the order of built-in converters, but - plugins can register converters in any order. A converter's priority - field reasserts some control over the order of converters. - - Plugins can register converters with any priority, to appear before or - after the built-ins. For example, a plugin with priority 9 will run - before the PlainTextConverter, but after the built-in converters. - """ - self._priority = priority - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - raise NotImplementedError("Subclasses must implement this method") - - @property - def priority(self) -> float: - """Priority of the converter in markitdown's converter list. Higher priority values are tried first.""" - return self._priority - - @priority.setter - def priority(self, value: float): - self._priority = value - - @priority.deleter - def priority(self): - raise AttributeError("Cannot delete the priority attribute") diff --git a/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py b/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py index d1b11a6..7dd9e24 100644 --- a/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py +++ b/packages/markitdown/src/markitdown/converters/_bing_serp_converter.py @@ -1,14 +1,24 @@ -# type: ignore -import base64 +import io import re - -from typing import Union +import base64 from urllib.parse import parse_qs, urlparse +from typing import Any, BinaryIO, Optional from bs4 import BeautifulSoup -from ._base import DocumentConverter, DocumentConverterResult +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo from ._markdownify import _CustomMarkdownify +ACCEPTED_MIME_TYPE_PREFIXES = [ + "text/html", + "application/xhtml", +] + +ACCEPTED_FILE_EXTENSIONS = [ + ".html", + ".htm", +] + class BingSerpConverter(DocumentConverter): """ @@ -16,28 +26,47 @@ class BingSerpConverter(DocumentConverter): NOTE: It is better to use the Bing API """ - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + """ + Make sure we're dealing with HTML content *from* Bing. + """ + + url = stream_info.url or "" + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a Bing SERP - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".html", ".htm"]: - return None - url = kwargs.get("url", "") if not re.search(r"^https://www\.bing\.com/search\?q=", url): - return None + # Not a Bing SERP URL + return False + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + # Not HTML content + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Parse the query parameters - parsed_params = parse_qs(urlparse(url).query) + parsed_params = parse_qs(urlparse(stream_info.url).query) query = parsed_params.get("q", [""])[0] - # Parse the file - soup = None - with open(local_path, "rt", encoding="utf-8") as fh: - soup = BeautifulSoup(fh.read(), "html.parser") + # Parse the stream + encoding = "utf-8" if stream_info.charset is None else stream_info.charset + soup = BeautifulSoup(file_stream, "html.parser", from_encoding=encoding) # Clean up some formatting for tptt in soup.find_all(class_="tptt"): @@ -81,6 +110,6 @@ class BingSerpConverter(DocumentConverter): ) return DocumentConverterResult( + markdown=webpage_text, title=None if soup.title is None else soup.title.string, - text_content=webpage_text, ) diff --git a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py index 6fe79c0..2f116d0 100644 --- a/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py +++ b/packages/markitdown/src/markitdown/converters/_doc_intel_converter.py @@ -1,9 +1,12 @@ -from typing import Any, Union -import re import sys +import re -from ._base import DocumentConverter, DocumentConverterResult -from .._exceptions import MissingDependencyException +from typing import BinaryIO, Any, List + +from ._html_converter import HtmlConverter +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo +from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE # Try loading optional (but in this case, required) dependencies # Save reporting of any exceptions for later @@ -26,17 +29,50 @@ except ImportError: CONTENT_FORMAT = "markdown" +OFFICE_MIME_TYPE_PREFIXES = [ + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "application/vnd.openxmlformats-officedocument.presentationml", + "application/xhtml", + "text/html", +] + +OTHER_MIME_TYPE_PREFIXES = [ + "application/pdf", + "application/x-pdf", + "text/html", + "image/", +] + +OFFICE_FILE_EXTENSIONS = [ + ".docx", + ".xlsx", + ".pptx", + ".html", + ".htm", +] + +OTHER_FILE_EXTENSIONS = [ + ".pdf", + ".jpeg", + ".jpg", + ".png", + ".bmp", + ".tiff", + ".heif", +] + + class DocumentIntelligenceConverter(DocumentConverter): """Specialized DocumentConverter that uses Document Intelligence to extract text from documents.""" def __init__( self, *, - priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT, endpoint: str, api_version: str = "2024-07-31-preview", ): - super().__init__(priority=priority) + super().__init__() # Raise an error if the dependencies are not available. # This is different than other converters since this one isn't even instantiated @@ -44,9 +80,11 @@ class DocumentIntelligenceConverter(DocumentConverter): if _dependency_exc_info is not None: raise MissingDependencyException( "DocumentIntelligenceConverter requires the optional dependency [az-doc-intel] (or [all]) to be installed. E.g., `pip install markitdown[az-doc-intel]`" - ) from _dependency_exc_info[1].with_traceback( + ) from _dependency_exc_info[ + 1 + ].with_traceback( # type: ignore[union-attr] _dependency_exc_info[2] - ) # Restore the original traceback + ) self.endpoint = endpoint self.api_version = api_version @@ -55,55 +93,62 @@ class DocumentIntelligenceConverter(DocumentConverter): api_version=self.api_version, credential=DefaultAzureCredential(), ) - self._priority = priority + + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if extension in OFFICE_FILE_EXTENSIONS + OTHER_FILE_EXTENSIONS: + return True + + for prefix in OFFICE_MIME_TYPE_PREFIXES + OTHER_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False + + def _analysis_features(self, stream_info: StreamInfo) -> List[str]: + """ + Helper needed to determine which analysis features to use. + Certain document analysis features are not availiable for + office filetypes (.xlsx, .pptx, .html, .docx) + """ + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if extension in OFFICE_FILE_EXTENSIONS: + return [] + + for prefix in OFFICE_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return [] + + return [ + DocumentAnalysisFeature.FORMULAS, # enable formula extraction + DocumentAnalysisFeature.OCR_HIGH_RESOLUTION, # enable high resolution OCR + DocumentAnalysisFeature.STYLE_FONT, # enable font style extraction + ] def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if extension is not supported by Document Intelligence - extension = kwargs.get("file_extension", "") - docintel_extensions = [ - ".pdf", - ".docx", - ".xlsx", - ".pptx", - ".html", - ".jpeg", - ".jpg", - ".png", - ".bmp", - ".tiff", - ".heif", - ] - if extension.lower() not in docintel_extensions: - return None - - # Get the bytestring for the local path - with open(local_path, "rb") as f: - file_bytes = f.read() - - # Certain document analysis features are not availiable for office filetypes (.xlsx, .pptx, .html, .docx) - if extension.lower() in [".xlsx", ".pptx", ".html", ".docx"]: - analysis_features = [] - else: - analysis_features = [ - DocumentAnalysisFeature.FORMULAS, # enable formula extraction - DocumentAnalysisFeature.OCR_HIGH_RESOLUTION, # enable high resolution OCR - DocumentAnalysisFeature.STYLE_FONT, # enable font style extraction - ] - + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Extract the text using Azure Document Intelligence poller = self.doc_intel_client.begin_analyze_document( model_id="prebuilt-layout", - body=AnalyzeDocumentRequest(bytes_source=file_bytes), - features=analysis_features, + body=AnalyzeDocumentRequest(bytes_source=file_stream.read()), + features=self._analysis_features(stream_info), output_content_format=CONTENT_FORMAT, # TODO: replace with "ContentFormat.MARKDOWN" when the bug is fixed ) result: AnalyzeResult = poller.result() # remove comments from the markdown content generated by Doc Intelligence and append to markdown string markdown_text = re.sub(r"", "", result.content, flags=re.DOTALL) - return DocumentConverterResult( - title=None, - text_content=markdown_text, - ) + return DocumentConverterResult(markdown=markdown_text) diff --git a/packages/markitdown/src/markitdown/converters/_docx_converter.py b/packages/markitdown/src/markitdown/converters/_docx_converter.py index 0866e59..c568acb 100644 --- a/packages/markitdown/src/markitdown/converters/_docx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_docx_converter.py @@ -1,13 +1,10 @@ import sys -from typing import Union +from typing import BinaryIO, Any -from ._base import ( - DocumentConverterResult, -) - -from ._base import DocumentConverter from ._html_converter import HtmlConverter +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE # Try loading optional (but in this case, required) dependencies @@ -20,22 +17,46 @@ except ImportError: _dependency_exc_info = sys.exc_info() +ACCEPTED_MIME_TYPE_PREFIXES = [ + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", +] + +ACCEPTED_FILE_EXTENSIONS = [".docx"] + + class DocxConverter(HtmlConverter): """ Converts DOCX files to Markdown. Style information (e.g.m headings) and tables are preserved where possible. """ - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def __init__(self): + super().__init__() + self._html_converter = HtmlConverter() - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a DOCX - extension = kwargs.get("file_extension", "") - if extension.lower() != ".docx": - return None + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Check: the dependencies if _dependency_exc_info is not None: raise MissingDependencyException( @@ -44,16 +65,13 @@ class DocxConverter(HtmlConverter): extension=".docx", feature="docx", ) - ) from _dependency_exc_info[1].with_traceback( + ) from _dependency_exc_info[ + 1 + ].with_traceback( # type: ignore[union-attr] _dependency_exc_info[2] - ) # Restore the original traceback + ) - result = None - with open(local_path, "rb") as docx_file: - style_map = kwargs.get("style_map", None) - - result = mammoth.convert_to_html(docx_file, style_map=style_map) - html_content = result.value - result = self._convert(html_content) - - return result + style_map = kwargs.get("style_map", None) + return self._html_converter.convert_string( + mammoth.convert_to_html(file_stream, style_map=style_map).value + ) diff --git a/packages/markitdown/src/markitdown/converters/_exiftool.py b/packages/markitdown/src/markitdown/converters/_exiftool.py new file mode 100644 index 0000000..5a316f0 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_exiftool.py @@ -0,0 +1,44 @@ +import json +import subprocess +import locale +import sys +import shutil +import os +import warnings +from typing import BinaryIO, Optional, Any + + +def exiftool_metadata( + file_stream: BinaryIO, *, exiftool_path: Optional[str] = None +) -> Any: # Need a better type for json data + # Check if we have a valid pointer to exiftool + if not exiftool_path: + which_exiftool = shutil.which("exiftool") + if which_exiftool: + warnings.warn( + f"""Implicit discovery of 'exiftool' is disabled. If you would like to continue to use exiftool in MarkItDown, please set the exiftool_path parameter in the MarkItDown consructor. E.g., + + md = MarkItDown(exiftool_path="{which_exiftool}") + +This warning will be removed in future releases. +""", + DeprecationWarning, + ) + # Nothing to do + return {} + + # Run exiftool + cur_pos = file_stream.tell() + try: + output = subprocess.run( + [exiftool_path, "-json", "-"], + input=file_stream.read(), + capture_output=True, + text=False, + ).stdout + + return json.loads( + output.decode(locale.getpreferredencoding(False)), + )[0] + finally: + file_stream.seek(cur_pos) diff --git a/packages/markitdown/src/markitdown/converters/_html_converter.py b/packages/markitdown/src/markitdown/converters/_html_converter.py index 68c2536..8a8203d 100644 --- a/packages/markitdown/src/markitdown/converters/_html_converter.py +++ b/packages/markitdown/src/markitdown/converters/_html_converter.py @@ -1,37 +1,52 @@ -from typing import Any, Union +import io +from typing import Any, BinaryIO, Optional from bs4 import BeautifulSoup -from ._base import DocumentConverter, DocumentConverterResult +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo from ._markdownify import _CustomMarkdownify +ACCEPTED_MIME_TYPE_PREFIXES = [ + "text/html", + "application/xhtml", +] + +ACCEPTED_FILE_EXTENSIONS = [ + ".html", + ".htm", +] + class HtmlConverter(DocumentConverter): """Anything with content type text/html""" - def __init__( - self, priority: float = DocumentConverter.PRIORITY_GENERIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not html - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".html", ".htm"]: - return None - - result = None - with open(local_path, "rt", encoding="utf-8") as fh: - result = self._convert(fh.read()) - - return result - - def _convert(self, html_content: str) -> Union[None, DocumentConverterResult]: - """Helper function that converts an HTML string.""" - - # Parse the string - soup = BeautifulSoup(html_content, "html.parser") + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: + # Parse the stream + encoding = "utf-8" if stream_info.charset is None else stream_info.charset + soup = BeautifulSoup(file_stream, "html.parser", from_encoding=encoding) # Remove javascript and style blocks for script in soup(["script", "style"]): @@ -51,6 +66,25 @@ class HtmlConverter(DocumentConverter): webpage_text = webpage_text.strip() return DocumentConverterResult( + markdown=webpage_text, title=None if soup.title is None else soup.title.string, - text_content=webpage_text, + ) + + def convert_string( + self, html_content: str, *, url: Optional[str] = None, **kwargs + ) -> DocumentConverterResult: + """ + Non-standard convenience method to convert a string to markdown. + Given that many converters produce HTML as intermediate output, this + allows for easy conversion of HTML to markdown. + """ + return self.convert( + file_stream=io.BytesIO(html_content.encode("utf-8")), + stream_info=StreamInfo( + mimetype="text/html", + extension=".html", + charset="utf-8", + url=url, + ), + **kwargs, ) diff --git a/packages/markitdown/src/markitdown/converters/_image_converter.py b/packages/markitdown/src/markitdown/converters/_image_converter.py index 4eb6155..dd8fbac 100644 --- a/packages/markitdown/src/markitdown/converters/_image_converter.py +++ b/packages/markitdown/src/markitdown/converters/_image_converter.py @@ -1,30 +1,53 @@ -from typing import Union -from ._base import DocumentConverter, DocumentConverterResult -from ._media_converter import MediaConverter +from typing import BinaryIO, Any, Union import base64 import mimetypes +from ._exiftool import exiftool_metadata +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo + +ACCEPTED_MIME_TYPE_PREFIXES = [ + "image/jpeg", + "image/png", +] + +ACCEPTED_FILE_EXTENSIONS = [".jpg", ".jpeg", ".png"] -class ImageConverter(MediaConverter): +class ImageConverter(DocumentConverter): """ Converts images to markdown via extraction of metadata (if `exiftool` is installed), and description via a multimodal LLM (if an llm_client is configured). """ - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not an image - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".jpg", ".jpeg", ".png"]: - return None + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: md_content = "" # Add metadata - metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) + metadata = exiftool_metadata( + file_stream, exiftool_path=kwargs.get("exiftool_path") + ) if metadata: for f in [ @@ -42,39 +65,59 @@ class ImageConverter(MediaConverter): if f in metadata: md_content += f"{f}: {metadata[f]}\n" - # Try describing the image with GPTV + # Try describing the image with GPT llm_client = kwargs.get("llm_client") llm_model = kwargs.get("llm_model") if llm_client is not None and llm_model is not None: - md_content += ( - "\n# Description:\n" - + self._get_llm_description( - local_path, - extension, - llm_client, - llm_model, - prompt=kwargs.get("llm_prompt"), - ).strip() - + "\n" + llm_description = self._get_llm_description( + file_stream, + stream_info, + client=llm_client, + model=llm_model, + prompt=kwargs.get("llm_prompt"), ) + if llm_description is not None: + md_content += "\n# Description:\n" + llm_description.strip() + "\n" + return DocumentConverterResult( - title=None, - text_content=md_content, + markdown=md_content, ) - def _get_llm_description(self, local_path, extension, client, model, prompt=None): + def _get_llm_description( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + *, + client, + model, + prompt=None, + ) -> Union[None, str]: if prompt is None or prompt.strip() == "": prompt = "Write a detailed caption for this image." - data_uri = "" - with open(local_path, "rb") as image_file: - content_type, encoding = mimetypes.guess_type("_dummy" + extension) - if content_type is None: - content_type = "image/jpeg" - image_base64 = base64.b64encode(image_file.read()).decode("utf-8") - data_uri = f"data:{content_type};base64,{image_base64}" + # Get the content type + content_type = stream_info.mimetype + if not content_type: + content_type, _ = mimetypes.guess_type( + "_dummy" + (stream_info.extension or "") + ) + if not content_type: + content_type = "application/octet-stream" + # Convert to base64 + cur_pos = file_stream.tell() + try: + base64_image = base64.b64encode(file_stream.read()).decode("utf-8") + except Exception as e: + return None + finally: + file_stream.seek(cur_pos) + + # Prepare the data-uri + data_uri = f"data:{content_type};base64,{base64_image}" + + # Prepare the OpenAI API request messages = [ { "role": "user", @@ -90,5 +133,6 @@ class ImageConverter(MediaConverter): } ] + # Call the OpenAI API response = client.chat.completions.create(model=model, messages=messages) return response.choices[0].message.content diff --git a/packages/markitdown/src/markitdown/converters/_ipynb_converter.py b/packages/markitdown/src/markitdown/converters/_ipynb_converter.py index b487f41..f8ba193 100644 --- a/packages/markitdown/src/markitdown/converters/_ipynb_converter.py +++ b/packages/markitdown/src/markitdown/converters/_ipynb_converter.py @@ -1,39 +1,62 @@ +from typing import BinaryIO, Any import json -from typing import Any, Union - -from ._base import ( - DocumentConverter, - DocumentConverterResult, -) +from .._base_converter import DocumentConverter, DocumentConverterResult from .._exceptions import FileConversionException +from .._stream_info import StreamInfo + +CANDIDATE_MIME_TYPE_PREFIXES = [ + "application/json", +] + +ACCEPTED_FILE_EXTENSIONS = [".ipynb"] class IpynbConverter(DocumentConverter): """Converts Jupyter Notebook (.ipynb) files to Markdown.""" - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in CANDIDATE_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + # Read further to see if it's a notebook + cur_pos = file_stream.tell() + try: + encoding = stream_info.charset or "utf-8" + notebook_content = file_stream.read().decode(encoding) + return ( + "nbformat" in notebook_content + and "nbformat_minor" in notebook_content + ) + finally: + file_stream.seek(cur_pos) + + return False def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not ipynb - extension = kwargs.get("file_extension", "") - if extension.lower() != ".ipynb": - return None - + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Parse and convert the notebook result = None - with open(local_path, "rt", encoding="utf-8") as fh: - notebook_content = json.load(fh) - result = self._convert(notebook_content) - return result + encoding = stream_info.charset or "utf-8" + notebook_content = file_stream.read().decode(encoding=encoding) + return self._convert(json.loads(notebook_content)) - def _convert(self, notebook_content: dict) -> Union[None, DocumentConverterResult]: + def _convert(self, notebook_content: dict) -> DocumentConverterResult: """Helper function that converts notebook JSON content to Markdown.""" try: md_output = [] @@ -65,8 +88,8 @@ class IpynbConverter(DocumentConverter): title = notebook_content.get("metadata", {}).get("title", title) return DocumentConverterResult( + markdown=md_text, title=title, - text_content=md_text, ) except Exception as e: diff --git a/packages/markitdown/src/markitdown/converters/_llm_caption.py b/packages/markitdown/src/markitdown/converters/_llm_caption.py new file mode 100644 index 0000000..b851dc8 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_llm_caption.py @@ -0,0 +1,50 @@ +from typing import BinaryIO, Any, Union +import base64 +import mimetypes +from .._stream_info import StreamInfo + + +def llm_caption( + file_stream: BinaryIO, stream_info: StreamInfo, *, client, model, prompt=None +) -> Union[None, str]: + if prompt is None or prompt.strip() == "": + prompt = "Write a detailed caption for this image." + + # Get the content type + content_type = stream_info.mimetype + if not content_type: + content_type, _ = mimetypes.guess_type("_dummy" + (stream_info.extension or "")) + if not content_type: + content_type = "application/octet-stream" + + # Convert to base64 + cur_pos = file_stream.tell() + try: + base64_image = base64.b64encode(file_stream.read()).decode("utf-8") + except Exception as e: + return None + finally: + file_stream.seek(cur_pos) + + # Prepare the data-uri + data_uri = f"data:{content_type};base64,{base64_image}" + + # Prepare the OpenAI API request + messages = [ + { + "role": "user", + "content": [ + {"type": "text", "text": prompt}, + { + "type": "image_url", + "image_url": { + "url": data_uri, + }, + }, + ], + } + ] + + # Call the OpenAI API + response = client.chat.completions.create(model=model, messages=messages) + return response.choices[0].message.content diff --git a/packages/markitdown/src/markitdown/converters/_markdownify.py b/packages/markitdown/src/markitdown/converters/_markdownify.py index e15f607..ae99c0b 100644 --- a/packages/markitdown/src/markitdown/converters/_markdownify.py +++ b/packages/markitdown/src/markitdown/converters/_markdownify.py @@ -1,7 +1,7 @@ import re import markdownify -from typing import Any +from typing import Any, Optional from urllib.parse import quote, unquote, urlparse, urlunparse @@ -20,7 +20,14 @@ class _CustomMarkdownify(markdownify.MarkdownConverter): # Explicitly cast options to the expected type if necessary super().__init__(**options) - def convert_hn(self, n: int, el: Any, text: str, convert_as_inline: bool) -> str: + def convert_hn( + self, + n: int, + el: Any, + text: str, + convert_as_inline: Optional[bool] = False, + **kwargs, + ) -> str: """Same as usual, but be sure to start with a new line""" if not convert_as_inline: if not re.search(r"^\n", text): @@ -28,7 +35,13 @@ class _CustomMarkdownify(markdownify.MarkdownConverter): return super().convert_hn(n, el, text, convert_as_inline) # type: ignore - def convert_a(self, el: Any, text: str, convert_as_inline: bool): + def convert_a( + self, + el: Any, + text: str, + convert_as_inline: Optional[bool] = False, + **kwargs, + ): """Same as usual converter, but removes Javascript links and escapes URIs.""" prefix, suffix, text = markdownify.chomp(text) # type: ignore if not text: @@ -68,7 +81,13 @@ class _CustomMarkdownify(markdownify.MarkdownConverter): else text ) - def convert_img(self, el: Any, text: str, convert_as_inline: bool) -> str: + def convert_img( + self, + el: Any, + text: str, + convert_as_inline: Optional[bool] = False, + **kwargs, + ) -> str: """Same as usual converter, but removes data URIs""" alt = el.attrs.get("alt", None) or "" diff --git a/packages/markitdown/src/markitdown/converters/_media_converter.py b/packages/markitdown/src/markitdown/converters/_media_converter.py deleted file mode 100644 index 5c7d82b..0000000 --- a/packages/markitdown/src/markitdown/converters/_media_converter.py +++ /dev/null @@ -1,41 +0,0 @@ -import subprocess -import shutil -import json -from warnings import warn - -from ._base import DocumentConverter - - -class MediaConverter(DocumentConverter): - """ - Abstract class for multi-modal media (e.g., images and audio) - """ - - def __init__( - self, priority: float = DocumentConverter.PRIORITY_GENERIC_FILE_FORMAT - ): - super().__init__(priority=priority) - - def _get_metadata(self, local_path, exiftool_path=None): - if not exiftool_path: - which_exiftool = shutil.which("exiftool") - if which_exiftool: - warn( - f"""Implicit discovery of 'exiftool' is disabled. If you would like to continue to use exiftool in MarkItDown, please set the exiftool_path parameter in the MarkItDown consructor. E.g., - - md = MarkItDown(exiftool_path="{which_exiftool}") - -This warning will be removed in future releases. -""", - DeprecationWarning, - ) - - return None - else: - if True: - result = subprocess.run( - [exiftool_path, "-json", local_path], capture_output=True, text=True - ).stdout - return json.loads(result)[0] - # except Exception: - # return None diff --git a/packages/markitdown/src/markitdown/converters/_mp3_converter.py b/packages/markitdown/src/markitdown/converters/_mp3_converter.py deleted file mode 100644 index 91fd270..0000000 --- a/packages/markitdown/src/markitdown/converters/_mp3_converter.py +++ /dev/null @@ -1,89 +0,0 @@ -import tempfile -from typing import Union -from ._base import DocumentConverter, DocumentConverterResult -from ._wav_converter import WavConverter -from warnings import resetwarnings, catch_warnings - -# Optional Transcription support -IS_AUDIO_TRANSCRIPTION_CAPABLE = False -try: - # Using warnings' catch_warnings to catch - # pydub's warning of ffmpeg or avconv missing - with catch_warnings(record=True) as w: - import pydub - - if w: - raise ModuleNotFoundError - import speech_recognition as sr - - IS_AUDIO_TRANSCRIPTION_CAPABLE = True -except ModuleNotFoundError: - pass -finally: - resetwarnings() - - -class Mp3Converter(WavConverter): - """ - Converts MP3 files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` AND `pydub` are installed). - """ - - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a MP3 - extension = kwargs.get("file_extension", "") - if extension.lower() != ".mp3": - return None - - md_content = "" - - # Add metadata - metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) - if metadata: - for f in [ - "Title", - "Artist", - "Author", - "Band", - "Album", - "Genre", - "Track", - "DateTimeOriginal", - "CreateDate", - "Duration", - ]: - if f in metadata: - md_content += f"{f}: {metadata[f]}\n" - - # Transcribe - if IS_AUDIO_TRANSCRIPTION_CAPABLE: - handle, temp_path = tempfile.mkstemp(suffix=".wav") - os.close(handle) - try: - sound = pydub.AudioSegment.from_mp3(local_path) - sound.export(temp_path, format="wav") - - _args = dict() - _args.update(kwargs) - _args["file_extension"] = ".wav" - - try: - transcript = super()._transcribe_audio(temp_path).strip() - md_content += "\n\n### Audio Transcript:\n" + ( - "[No speech detected]" if transcript == "" else transcript - ) - except Exception: - md_content += "\n\n### Audio Transcript:\nError. Could not transcribe this audio." - - finally: - os.unlink(temp_path) - - # Return the result - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) diff --git a/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py b/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py index eb7a065..8a61b0c 100644 --- a/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py +++ b/packages/markitdown/src/markitdown/converters/_outlook_msg_converter.py @@ -1,6 +1,7 @@ import sys -from typing import Any, Union -from ._base import DocumentConverter, DocumentConverterResult +from typing import Any, Union, BinaryIO +from .._stream_info import StreamInfo +from .._base_converter import DocumentConverter, DocumentConverterResult from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE # Try loading optional (but in this case, required) dependencies @@ -12,6 +13,12 @@ except ImportError: # Preserve the error and stack trace for later _dependency_exc_info = sys.exc_info() +ACCEPTED_MIME_TYPE_PREFIXES = [ + "application/vnd.ms-outlook", +] + +ACCEPTED_FILE_EXTENSIONS = [".msg"] + class OutlookMsgConverter(DocumentConverter): """Converts Outlook .msg files to markdown by extracting email metadata and content. @@ -21,19 +28,52 @@ class OutlookMsgConverter(DocumentConverter): - Email body content """ - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + # Check the extension and mimetype + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + # Brute force, check if we have an OLE file + cur_pos = file_stream.tell() + try: + if not olefile.isOleFile(file_stream): + return False + finally: + file_stream.seek(cur_pos) + + # Brue force, check if it's an Outlook file + try: + msg = olefile.OleFileIO(file_stream) + toc = "\n".join([str(stream) for stream in msg.listdir()]) + return ( + "__properties_version1.0" in toc + and "__recip_version1.0_#00000000" in toc + ) + except Exception as e: + pass + finally: + file_stream.seek(cur_pos) + + return False def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not a MSG file - extension = kwargs.get("file_extension", "") - if extension.lower() != ".msg": - return None - + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Check: the dependencies if _dependency_exc_info is not None: raise MissingDependencyException( @@ -42,44 +82,41 @@ class OutlookMsgConverter(DocumentConverter): extension=".msg", feature="outlook", ) - ) from _dependency_exc_info[1].with_traceback( + ) from _dependency_exc_info[ + 1 + ].with_traceback( # type: ignore[union-attr] _dependency_exc_info[2] - ) # Restore the original traceback - - try: - msg = olefile.OleFileIO(local_path) - # Extract email metadata - md_content = "# Email Message\n\n" - - # Get headers - headers = { - "From": self._get_stream_data(msg, "__substg1.0_0C1F001F"), - "To": self._get_stream_data(msg, "__substg1.0_0E04001F"), - "Subject": self._get_stream_data(msg, "__substg1.0_0037001F"), - } - - # Add headers to markdown - for key, value in headers.items(): - if value: - md_content += f"**{key}:** {value}\n" - - md_content += "\n## Content\n\n" - - # Get email body - body = self._get_stream_data(msg, "__substg1.0_1000001F") - if body: - md_content += body - - msg.close() - - return DocumentConverterResult( - title=headers.get("Subject"), text_content=md_content.strip() ) - except Exception as e: - raise FileConversionException( - f"Could not convert MSG file '{local_path}': {str(e)}" - ) + msg = olefile.OleFileIO(file_stream) + # Extract email metadata + md_content = "# Email Message\n\n" + + # Get headers + headers = { + "From": self._get_stream_data(msg, "__substg1.0_0C1F001F"), + "To": self._get_stream_data(msg, "__substg1.0_0E04001F"), + "Subject": self._get_stream_data(msg, "__substg1.0_0037001F"), + } + + # Add headers to markdown + for key, value in headers.items(): + if value: + md_content += f"**{key}:** {value}\n" + + md_content += "\n## Content\n\n" + + # Get email body + body = self._get_stream_data(msg, "__substg1.0_1000001F") + if body: + md_content += body + + msg.close() + + return DocumentConverterResult( + markdown=md_content.strip(), + title=headers.get("Subject"), + ) def _get_stream_data(self, msg: Any, stream_path: str) -> Union[str, None]: """Helper to safely extract and decode stream data from the MSG file.""" diff --git a/packages/markitdown/src/markitdown/converters/_pdf_converter.py b/packages/markitdown/src/markitdown/converters/_pdf_converter.py index 3c5ecad..4586ef1 100644 --- a/packages/markitdown/src/markitdown/converters/_pdf_converter.py +++ b/packages/markitdown/src/markitdown/converters/_pdf_converter.py @@ -1,8 +1,15 @@ import sys -from typing import Union -from ._base import DocumentConverter, DocumentConverterResult +import io + +from typing import BinaryIO, Any + + +from ._html_converter import HtmlConverter +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE + # Try loading optional (but in this case, required) dependencies # Save reporting of any exceptions for later _dependency_exc_info = None @@ -14,22 +21,43 @@ except ImportError: _dependency_exc_info = sys.exc_info() +ACCEPTED_MIME_TYPE_PREFIXES = [ + "application/pdf", + "application/x-pdf", +] + +ACCEPTED_FILE_EXTENSIONS = [".pdf"] + + class PdfConverter(DocumentConverter): """ Converts PDFs to Markdown. Most style information is ignored, so the results are essentially plain-text. """ - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a PDF - extension = kwargs.get("file_extension", "") - if extension.lower() != ".pdf": - return None + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Check the dependencies if _dependency_exc_info is not None: raise MissingDependencyException( @@ -38,11 +66,13 @@ class PdfConverter(DocumentConverter): extension=".pdf", feature="pdf", ) - ) from _dependency_exc_info[1].with_traceback( + ) from _dependency_exc_info[ + 1 + ].with_traceback( # type: ignore[union-attr] _dependency_exc_info[2] - ) # Restore the original traceback + ) + assert isinstance(file_stream, io.IOBase) # for mypy return DocumentConverterResult( - title=None, - text_content=pdfminer.high_level.extract_text(local_path), + markdown=pdfminer.high_level.extract_text(file_stream), ) diff --git a/packages/markitdown/src/markitdown/converters/_plain_text_converter.py b/packages/markitdown/src/markitdown/converters/_plain_text_converter.py index b4c9282..4a21d3a 100644 --- a/packages/markitdown/src/markitdown/converters/_plain_text_converter.py +++ b/packages/markitdown/src/markitdown/converters/_plain_text_converter.py @@ -1,13 +1,26 @@ -import mimetypes +import sys -from charset_normalizer import from_path -from typing import Any, Union +from typing import BinaryIO, Any +from charset_normalizer import from_bytes +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo -from ._base import DocumentConverter, DocumentConverterResult +# Try loading optional (but in this case, required) dependencies +# Save reporting of any exceptions for later +_dependency_exc_info = None +try: + import mammoth +except ImportError: + # Preserve the error and stack trace for later + _dependency_exc_info = sys.exc_info() +ACCEPTED_MIME_TYPE_PREFIXES = [ + "text/", + "application/json", +] # Mimetypes to ignore (commonly confused extensions) -IGNORE_MIMETYPES = [ +IGNORE_MIME_TYPE_PREFIXES = [ "text/vnd.in3d.spot", # .spo wich is confused with xls, doc, etc. "text/vnd.graphviz", # .dot which is confused with xls, doc, etc. ] @@ -16,34 +29,34 @@ IGNORE_MIMETYPES = [ class PlainTextConverter(DocumentConverter): """Anything with content type text/plain""" - def __init__( - self, priority: float = DocumentConverter.PRIORITY_GENERIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + for prefix in IGNORE_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return False + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Guess the content type from any file extension that might be around - content_type, _ = mimetypes.guess_type( - "__placeholder" + kwargs.get("file_extension", "") - ) + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: + if stream_info.charset: + text_content = file_stream.read().decode(stream_info.charset) + else: + text_content = str(from_bytes(file_stream.read()).best()) - # Ignore common false positives - if content_type in IGNORE_MIMETYPES: - content_type = None - - # Only accept text files - if content_type is None: - return None - elif all( - not content_type.lower().startswith(type_prefix) - for type_prefix in ["text/", "application/json"] - ): - return None - - text_content = str(from_path(local_path).best()) - return DocumentConverterResult( - title=None, - text_content=text_content, - ) + return DocumentConverterResult(markdown=text_content) diff --git a/packages/markitdown/src/markitdown/converters/_pptx_converter.py b/packages/markitdown/src/markitdown/converters/_pptx_converter.py index 431b6a0..bea1226 100644 --- a/packages/markitdown/src/markitdown/converters/_pptx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_pptx_converter.py @@ -1,12 +1,16 @@ +import sys import base64 +import os +import io import re import html -import sys -from typing import Union +from typing import BinaryIO, Any -from ._base import DocumentConverterResult, DocumentConverter from ._html_converter import HtmlConverter +from ._llm_caption import llm_caption +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE # Try loading optional (but in this case, required) dependencies @@ -19,51 +23,46 @@ except ImportError: _dependency_exc_info = sys.exc_info() -class PptxConverter(HtmlConverter): +ACCEPTED_MIME_TYPE_PREFIXES = [ + "application/vnd.openxmlformats-officedocument.presentationml", +] + +ACCEPTED_FILE_EXTENSIONS = [".pptx"] + + +class PptxConverter(DocumentConverter): """ Converts PPTX files to Markdown. Supports heading, tables and images with alt text. """ - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def __init__(self): + super().__init__() + self._html_converter = HtmlConverter() - def _get_llm_description( - self, llm_client, llm_model, image_blob, content_type, prompt=None - ): - if prompt is None or prompt.strip() == "": - prompt = "Write a detailed alt text for this image with less than 50 words." + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() - image_base64 = base64.b64encode(image_blob).decode("utf-8") - data_uri = f"data:{content_type};base64,{image_base64}" + if extension in ACCEPTED_FILE_EXTENSIONS: + return True - messages = [ - { - "role": "user", - "content": [ - { - "type": "image_url", - "image_url": { - "url": data_uri, - }, - }, - {"type": "text", "text": prompt}, - ], - } - ] + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True - response = llm_client.chat.completions.create( - model=llm_model, messages=messages - ) - return response.choices[0].message.content - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a PPTX - extension = kwargs.get("file_extension", "") - if extension.lower() != ".pptx": - return None + return False + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Check the dependencies if _dependency_exc_info is not None: raise MissingDependencyException( @@ -72,11 +71,14 @@ class PptxConverter(HtmlConverter): extension=".pptx", feature="pptx", ) - ) from _dependency_exc_info[1].with_traceback( + ) from _dependency_exc_info[ + 1 + ].with_traceback( # type: ignore[union-attr] _dependency_exc_info[2] - ) # Restore the original traceback + ) - presentation = pptx.Presentation(local_path) + # Perform the conversion + presentation = pptx.Presentation(file_stream) md_content = "" slide_num = 0 for slide in presentation.slides: @@ -92,59 +94,58 @@ class PptxConverter(HtmlConverter): if self._is_picture(shape): # https://github.com/scanny/python-pptx/pull/512#issuecomment-1713100069 - llm_description = None - alt_text = None + llm_description = "" + alt_text = "" + # Potentially generate a description using an LLM llm_client = kwargs.get("llm_client") llm_model = kwargs.get("llm_model") if llm_client is not None and llm_model is not None: + # Prepare a file_stream and stream_info for the image data + image_filename = shape.image.filename + image_extension = None + if image_filename: + image_extension = os.path.splitext(image_filename)[1] + image_stream_info = StreamInfo( + mimetype=shape.image.content_type, + extension=image_extension, + filename=image_filename, + ) + + image_stream = io.BytesIO(shape.image.blob) + + # Caption the image try: - llm_description = self._get_llm_description( - llm_client, - llm_model, - shape.image.blob, - shape.image.content_type, + llm_description = llm_caption( + image_stream, + image_stream_info, + client=llm_client, + model=llm_model, + prompt=kwargs.get("llm_prompt"), ) except Exception: - # Unable to describe with LLM + # Unable to generate a description pass - if not llm_description: - try: - alt_text = shape._element._nvXxPr.cNvPr.attrib.get( - "descr", "" - ) - except Exception: - # Unable to get alt text - pass + # Also grab any description embedded in the deck + try: + alt_text = shape._element._nvXxPr.cNvPr.attrib.get("descr", "") + except Exception: + # Unable to get alt text + pass + + # Prepare the alt, escaping any special characters + alt_text = "\n".join([llm_description, alt_text]) or shape.name + alt_text = re.sub(r"[\r\n\[\]]", " ", alt_text) + alt_text = re.sub(r"\s+", " ", alt_text).strip() # A placeholder name filename = re.sub(r"\W", "", shape.name) + ".jpg" - md_content += ( - "\n![" - + (llm_description or alt_text or shape.name) - + "](" - + filename - + ")\n" - ) + md_content += "\n![" + alt_text + "](" + filename + ")\n" # Tables if self._is_table(shape): - html_table = "" - first_row = True - for row in shape.table.rows: - html_table += "" - for cell in row.cells: - if first_row: - html_table += "" - else: - html_table += "" - html_table += "" - first_row = False - html_table += "
" + html.escape(cell.text) + "" + html.escape(cell.text) + "
" - md_content += ( - "\n" + self._convert(html_table).text_content.strip() + "\n" - ) + md_content += self._convert_table_to_markdown(shape.table) # Charts if shape.has_chart: @@ -174,10 +175,7 @@ class PptxConverter(HtmlConverter): md_content += notes_frame.text md_content = md_content.strip() - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) + return DocumentConverterResult(markdown=md_content.strip()) def _is_picture(self, shape): if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.PICTURE: @@ -192,6 +190,23 @@ class PptxConverter(HtmlConverter): return True return False + def _convert_table_to_markdown(self, table): + # Write the table as HTML, then convert it to Markdown + html_table = "" + first_row = True + for row in table.rows: + html_table += "" + for cell in row.cells: + if first_row: + html_table += "" + else: + html_table += "" + html_table += "" + first_row = False + html_table += "
" + html.escape(cell.text) + "" + html.escape(cell.text) + "
" + + return self._html_converter.convert_string(html_table).markdown.strip() + "\n" + def _convert_chart_to_markdown(self, chart): md = "\n\n### Chart" if chart.has_title: diff --git a/packages/markitdown/src/markitdown/converters/_rss_converter.py b/packages/markitdown/src/markitdown/converters/_rss_converter.py index b279c85..dbafc1b 100644 --- a/packages/markitdown/src/markitdown/converters/_rss_converter.py +++ b/packages/markitdown/src/markitdown/converters/_rss_converter.py @@ -1,128 +1,165 @@ from xml.dom import minidom -from typing import Union +from typing import BinaryIO, Any, Union from bs4 import BeautifulSoup from ._markdownify import _CustomMarkdownify -from ._base import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo +from .._base_converter import DocumentConverter, DocumentConverterResult + +PRECISE_MIME_TYPE_PREFIXES = [ + "application/rss", + "application/atom", +] + +PRECISE_FILE_EXTENSIONS = [".rss", ".atom"] + +CANDIDATE_MIME_TYPE_PREFIXES = [ + "text/xml", + "application/xml", +] + +CANDIDATE_FILE_EXTENSIONS = [ + ".xml", +] class RssConverter(DocumentConverter): """Convert RSS / Atom type to markdown""" - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() - def convert( - self, local_path: str, **kwargs - ) -> Union[None, DocumentConverterResult]: - # Bail if not RSS type - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".xml", ".rss", ".atom"]: - return None + # Check for precise mimetypes and file extensions + if extension in PRECISE_FILE_EXTENSIONS: + return True + + for prefix in PRECISE_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + # Check for precise mimetypes and file extensions + if extension in CANDIDATE_FILE_EXTENSIONS: + return self._check_xml(file_stream) + + for prefix in CANDIDATE_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return self._check_xml(file_stream) + + return False + + def _check_xml(self, file_stream: BinaryIO) -> bool: + cur_pos = file_stream.tell() try: - doc = minidom.parse(local_path) + doc = minidom.parse(file_stream) + return self._feed_type(doc) is not None except BaseException as _: - return None - result = None + pass + finally: + file_stream.seek(cur_pos) + return False + + def _feed_type(self, doc: Any) -> str: if doc.getElementsByTagName("rss"): - # A RSS feed must have a root element of - result = self._parse_rss_type(doc) + return "rss" elif doc.getElementsByTagName("feed"): root = doc.getElementsByTagName("feed")[0] if root.getElementsByTagName("entry"): # An Atom feed must have a root element of and at least one - result = self._parse_atom_type(doc) - else: - return None + return "atom" + return None + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: + doc = minidom.parse(file_stream) + feed_type = self._feed_type(doc) + + if feed_type == "rss": + return self._parse_rss_type(doc) + elif feed_type == "atom": + return self._parse_atom_type(doc) else: - # not rss or atom - return None + raise ValueError("Unknown feed type") - return result - - def _parse_atom_type( - self, doc: minidom.Document - ) -> Union[None, DocumentConverterResult]: + def _parse_atom_type(self, doc: minidom.Document) -> DocumentConverterResult: """Parse the type of an Atom feed. Returns None if the feed type is not recognized or something goes wrong. """ - try: - root = doc.getElementsByTagName("feed")[0] - title = self._get_data_by_tag_name(root, "title") - subtitle = self._get_data_by_tag_name(root, "subtitle") - entries = root.getElementsByTagName("entry") - md_text = f"# {title}\n" - if subtitle: - md_text += f"{subtitle}\n" - for entry in entries: - entry_title = self._get_data_by_tag_name(entry, "title") - entry_summary = self._get_data_by_tag_name(entry, "summary") - entry_updated = self._get_data_by_tag_name(entry, "updated") - entry_content = self._get_data_by_tag_name(entry, "content") + root = doc.getElementsByTagName("feed")[0] + title = self._get_data_by_tag_name(root, "title") + subtitle = self._get_data_by_tag_name(root, "subtitle") + entries = root.getElementsByTagName("entry") + md_text = f"# {title}\n" + if subtitle: + md_text += f"{subtitle}\n" + for entry in entries: + entry_title = self._get_data_by_tag_name(entry, "title") + entry_summary = self._get_data_by_tag_name(entry, "summary") + entry_updated = self._get_data_by_tag_name(entry, "updated") + entry_content = self._get_data_by_tag_name(entry, "content") - if entry_title: - md_text += f"\n## {entry_title}\n" - if entry_updated: - md_text += f"Updated on: {entry_updated}\n" - if entry_summary: - md_text += self._parse_content(entry_summary) - if entry_content: - md_text += self._parse_content(entry_content) + if entry_title: + md_text += f"\n## {entry_title}\n" + if entry_updated: + md_text += f"Updated on: {entry_updated}\n" + if entry_summary: + md_text += self._parse_content(entry_summary) + if entry_content: + md_text += self._parse_content(entry_content) - return DocumentConverterResult( - title=title, - text_content=md_text, - ) - except BaseException as _: - return None + return DocumentConverterResult( + markdown=md_text, + title=title, + ) - def _parse_rss_type( - self, doc: minidom.Document - ) -> Union[None, DocumentConverterResult]: + def _parse_rss_type(self, doc: minidom.Document) -> DocumentConverterResult: """Parse the type of an RSS feed. Returns None if the feed type is not recognized or something goes wrong. """ - try: - root = doc.getElementsByTagName("rss")[0] - channel = root.getElementsByTagName("channel") - if not channel: - return None - channel = channel[0] - channel_title = self._get_data_by_tag_name(channel, "title") - channel_description = self._get_data_by_tag_name(channel, "description") - items = channel.getElementsByTagName("item") - if channel_title: - md_text = f"# {channel_title}\n" - if channel_description: - md_text += f"{channel_description}\n" - if not items: - items = [] - for item in items: - title = self._get_data_by_tag_name(item, "title") - description = self._get_data_by_tag_name(item, "description") - pubDate = self._get_data_by_tag_name(item, "pubDate") - content = self._get_data_by_tag_name(item, "content:encoded") - - if title: - md_text += f"\n## {title}\n" - if pubDate: - md_text += f"Published on: {pubDate}\n" - if description: - md_text += self._parse_content(description) - if content: - md_text += self._parse_content(content) - - return DocumentConverterResult( - title=channel_title, - text_content=md_text, - ) - except BaseException as _: - print(traceback.format_exc()) + root = doc.getElementsByTagName("rss")[0] + channel = root.getElementsByTagName("channel") + if not channel: return None + channel = channel[0] + channel_title = self._get_data_by_tag_name(channel, "title") + channel_description = self._get_data_by_tag_name(channel, "description") + items = channel.getElementsByTagName("item") + if channel_title: + md_text = f"# {channel_title}\n" + if channel_description: + md_text += f"{channel_description}\n" + if not items: + items = [] + for item in items: + title = self._get_data_by_tag_name(item, "title") + description = self._get_data_by_tag_name(item, "description") + pubDate = self._get_data_by_tag_name(item, "pubDate") + content = self._get_data_by_tag_name(item, "content:encoded") + + if title: + md_text += f"\n## {title}\n" + if pubDate: + md_text += f"Published on: {pubDate}\n" + if description: + md_text += self._parse_content(description) + if content: + md_text += self._parse_content(content) + + return DocumentConverterResult( + markdown=md_text, + title=channel_title, + ) def _parse_content(self, content: str) -> str: """Parse the content of an RSS feed item""" diff --git a/packages/markitdown/src/markitdown/converters/_transcribe_audio.py b/packages/markitdown/src/markitdown/converters/_transcribe_audio.py new file mode 100644 index 0000000..3d02173 --- /dev/null +++ b/packages/markitdown/src/markitdown/converters/_transcribe_audio.py @@ -0,0 +1,43 @@ +import io +import sys +from typing import BinaryIO +from .._exceptions import MissingDependencyException + +# Try loading optional (but in this case, required) dependencies +# Save reporting of any exceptions for later +_dependency_exc_info = None +try: + import speech_recognition as sr + import pydub +except ImportError: + # Preserve the error and stack trace for later + _dependency_exc_info = sys.exc_info() + + +def transcribe_audio(file_stream: BinaryIO, *, audio_format: str = "wav") -> str: + # Check for installed dependencies + if _dependency_exc_info is not None: + raise MissingDependencyException( + "Speech transcription requires installing MarkItdown with the [audio-transcription] optional dependencies. E.g., `pip install markitdown[audio-transcription]` or `pip install markitdown[all]`" + ) from _dependency_exc_info[ + 1 + ].with_traceback( # type: ignore[union-attr] + _dependency_exc_info[2] + ) + + if audio_format in ["wav", "aiff", "flac"]: + audio_source = file_stream + elif audio_format in ["mp3", "mp4"]: + audio_segment = pydub.AudioSegment.from_file(file_stream, format=audio_format) + + audio_source = io.BytesIO() + audio_segment.export(audio_source, format="wav") + audio_source.seek(0) + else: + raise ValueError(f"Unsupported audio format: {audio_format}") + + recognizer = sr.Recognizer() + with sr.AudioFile(audio_source) as source: + audio = recognizer.record(source) + transcript = recognizer.recognize_google(audio).strip() + return "[No speech detected]" if transcript == "" else transcript diff --git a/packages/markitdown/src/markitdown/converters/_wav_converter.py b/packages/markitdown/src/markitdown/converters/_wav_converter.py deleted file mode 100644 index 3c8d842..0000000 --- a/packages/markitdown/src/markitdown/converters/_wav_converter.py +++ /dev/null @@ -1,72 +0,0 @@ -from typing import Union -from ._base import DocumentConverter, DocumentConverterResult -from ._media_converter import MediaConverter - -# Optional Transcription support -IS_AUDIO_TRANSCRIPTION_CAPABLE = False -try: - import speech_recognition as sr - - IS_AUDIO_TRANSCRIPTION_CAPABLE = True -except ModuleNotFoundError: - pass - - -class WavConverter(MediaConverter): - """ - Converts WAV files to markdown via extraction of metadata (if `exiftool` is installed), and speech transcription (if `speech_recognition` is installed). - """ - - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) - - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a WAV - extension = kwargs.get("file_extension", "") - if extension.lower() != ".wav": - return None - - md_content = "" - - # Add metadata - metadata = self._get_metadata(local_path, kwargs.get("exiftool_path")) - if metadata: - for f in [ - "Title", - "Artist", - "Author", - "Band", - "Album", - "Genre", - "Track", - "DateTimeOriginal", - "CreateDate", - "Duration", - ]: - if f in metadata: - md_content += f"{f}: {metadata[f]}\n" - - # Transcribe - if IS_AUDIO_TRANSCRIPTION_CAPABLE: - try: - transcript = self._transcribe_audio(local_path) - md_content += "\n\n### Audio Transcript:\n" + ( - "[No speech detected]" if transcript == "" else transcript - ) - except Exception: - md_content += ( - "\n\n### Audio Transcript:\nError. Could not transcribe this audio." - ) - - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) - - def _transcribe_audio(self, local_path) -> str: - recognizer = sr.Recognizer() - with sr.AudioFile(local_path) as source: - audio = recognizer.record(source) - return recognizer.recognize_google(audio).strip() diff --git a/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py b/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py index f27fe23..5b054af 100644 --- a/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py +++ b/packages/markitdown/src/markitdown/converters/_wikipedia_converter.py @@ -1,35 +1,63 @@ +import io import re - -from typing import Any, Union +from typing import Any, BinaryIO, Optional from bs4 import BeautifulSoup -from ._base import DocumentConverter, DocumentConverterResult +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo from ._markdownify import _CustomMarkdownify +ACCEPTED_MIME_TYPE_PREFIXES = [ + "text/html", + "application/xhtml", +] + +ACCEPTED_FILE_EXTENSIONS = [ + ".html", + ".htm", +] + class WikipediaConverter(DocumentConverter): """Handle Wikipedia pages separately, focusing only on the main document content.""" - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + """ + Make sure we're dealing with HTML content *from* Wikipedia. + """ + + url = stream_info.url or "" + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if not re.search(r"^https?:\/\/[a-zA-Z]{2,3}\.wikipedia.org\/", url): + # Not a Wikipedia URL + return False + + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + # Not HTML content + return False def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not Wikipedia - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".html", ".htm"]: - return None - url = kwargs.get("url", "") - if not re.search(r"^https?:\/\/[a-zA-Z]{2,3}\.wikipedia.org\/", url): - return None - - # Parse the file - soup = None - with open(local_path, "rt", encoding="utf-8") as fh: - soup = BeautifulSoup(fh.read(), "html.parser") + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: + # Parse the stream + encoding = "utf-8" if stream_info.charset is None else stream_info.charset + soup = BeautifulSoup(file_stream, "html.parser", from_encoding=encoding) # Remove javascript and style blocks for script in soup(["script", "style"]): @@ -56,6 +84,6 @@ class WikipediaConverter(DocumentConverter): webpage_text = _CustomMarkdownify().convert_soup(soup) return DocumentConverterResult( + markdown=webpage_text, title=main_title, - text_content=webpage_text, ) diff --git a/packages/markitdown/src/markitdown/converters/_xlsx_converter.py b/packages/markitdown/src/markitdown/converters/_xlsx_converter.py index 56398ca..3d0e1ab 100644 --- a/packages/markitdown/src/markitdown/converters/_xlsx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_xlsx_converter.py @@ -1,10 +1,9 @@ import sys - -from typing import Union - -from ._base import DocumentConverter, DocumentConverterResult +from typing import BinaryIO, Any from ._html_converter import HtmlConverter +from .._base_converter import DocumentConverter, DocumentConverterResult from .._exceptions import MissingDependencyException, MISSING_DEPENDENCY_MESSAGE +from .._stream_info import StreamInfo # Try loading optional (but in this case, required) dependencies # Save reporting of any exceptions for later @@ -22,23 +21,51 @@ try: except ImportError: _xls_dependency_exc_info = sys.exc_info() +ACCEPTED_XLSX_MIME_TYPE_PREFIXES = [ + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" +] +ACCEPTED_XLSX_FILE_EXTENSIONS = [".xlsx"] -class XlsxConverter(HtmlConverter): +ACCEPTED_XLS_MIME_TYPE_PREFIXES = [ + "application/vnd.ms-excel", + "application/excel", +] +ACCEPTED_XLS_FILE_EXTENSIONS = [".xls"] + + +class XlsxConverter(DocumentConverter): """ Converts XLSX files to Markdown, with each sheet presented as a separate Markdown table. """ - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def __init__(self): + super().__init__() + self._html_converter = HtmlConverter() - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a XLSX - extension = kwargs.get("file_extension", "") - if extension.lower() != ".xlsx": - return None + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + if extension in ACCEPTED_XLSX_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_XLSX_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Check the dependencies if _xlsx_dependency_exc_info is not None: raise MissingDependencyException( @@ -47,34 +74,58 @@ class XlsxConverter(HtmlConverter): extension=".xlsx", feature="xlsx", ) - ) from _xlsx_dependency_exc_info[1].with_traceback( + ) from _xlsx_dependency_exc_info[ + 1 + ].with_traceback( # type: ignore[union-attr] _xlsx_dependency_exc_info[2] - ) # Restore the original traceback + ) - sheets = pd.read_excel(local_path, sheet_name=None, engine="openpyxl") + sheets = pd.read_excel(file_stream, sheet_name=None, engine="openpyxl") md_content = "" for s in sheets: md_content += f"## {s}\n" html_content = sheets[s].to_html(index=False) - md_content += self._convert(html_content).text_content.strip() + "\n\n" + md_content += ( + self._html_converter.convert_string(html_content).markdown.strip() + + "\n\n" + ) - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) + return DocumentConverterResult(markdown=md_content.strip()) -class XlsConverter(HtmlConverter): +class XlsConverter(DocumentConverter): """ Converts XLS files to Markdown, with each sheet presented as a separate Markdown table. """ - def convert(self, local_path, **kwargs) -> Union[None, DocumentConverterResult]: - # Bail if not a XLS - extension = kwargs.get("file_extension", "") - if extension.lower() != ".xls": - return None + def __init__(self): + super().__init__() + self._html_converter = HtmlConverter() + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if extension in ACCEPTED_XLS_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_XLS_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: # Load the dependencies if _xls_dependency_exc_info is not None: raise MissingDependencyException( @@ -83,18 +134,20 @@ class XlsConverter(HtmlConverter): extension=".xls", feature="xls", ) - ) from _xls_dependency_exc_info[1].with_traceback( + ) from _xls_dependency_exc_info[ + 1 + ].with_traceback( # type: ignore[union-attr] _xls_dependency_exc_info[2] - ) # Restore the original traceback + ) - sheets = pd.read_excel(local_path, sheet_name=None, engine="xlrd") + sheets = pd.read_excel(file_stream, sheet_name=None, engine="xlrd") md_content = "" for s in sheets: md_content += f"## {s}\n" html_content = sheets[s].to_html(index=False) - md_content += self._convert(html_content).text_content.strip() + "\n\n" + md_content += ( + self._html_converter.convert_string(html_content).markdown.strip() + + "\n\n" + ) - return DocumentConverterResult( - title=None, - text_content=md_content.strip(), - ) + return DocumentConverterResult(markdown=md_content.strip()) diff --git a/packages/markitdown/src/markitdown/converters/_youtube_converter.py b/packages/markitdown/src/markitdown/converters/_youtube_converter.py index e61b208..5a158d5 100644 --- a/packages/markitdown/src/markitdown/converters/_youtube_converter.py +++ b/packages/markitdown/src/markitdown/converters/_youtube_converter.py @@ -1,14 +1,15 @@ -import re +import sys import json -import urllib.parse import time - -from typing import Any, Union, Dict, List -from urllib.parse import parse_qs, urlparse +import io +import re +from typing import Any, BinaryIO, Optional, Dict, List, Union +from urllib.parse import parse_qs, urlparse, unquote from bs4 import BeautifulSoup -from ._base import DocumentConverter, DocumentConverterResult - +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo +from ._markdownify import _CustomMarkdownify # Optional YouTube transcription support try: @@ -19,53 +20,59 @@ except ModuleNotFoundError: IS_YOUTUBE_TRANSCRIPT_CAPABLE = False +ACCEPTED_MIME_TYPE_PREFIXES = [ + "text/html", + "application/xhtml", +] + +ACCEPTED_FILE_EXTENSIONS = [ + ".html", + ".htm", +] + + class YouTubeConverter(DocumentConverter): """Handle YouTube specially, focusing on the video title, description, and transcript.""" - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + """ + Make sure we're dealing with HTML content *from* YouTube. + """ + url = stream_info.url or "" + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() - def retry_operation(self, operation, retries=3, delay=2): - """Retries the operation if it fails.""" - attempt = 0 - while attempt < retries: - try: - return operation() # Attempt the operation - except Exception as e: - print(f"Attempt {attempt + 1} failed: {e}") - if attempt < retries - 1: - time.sleep(delay) # Wait before retrying - attempt += 1 - # If all attempts fail, raise the last exception - raise Exception(f"Operation failed after {retries} attempts.") - - def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not YouTube - extension = kwargs.get("file_extension", "") - if extension.lower() not in [".html", ".htm"]: - return None - url = kwargs.get("url", "") - - url = urllib.parse.unquote(url) + url = unquote(url) url = url.replace(r"\?", "?").replace(r"\=", "=") if not url.startswith("https://www.youtube.com/watch?"): - return None + # Not a YouTube URL + return False - # Parse the file with error handling - try: - with open(local_path, "rt", encoding="utf-8") as fh: - soup = BeautifulSoup(fh.read(), "html.parser") - except Exception as e: - print(f"Error reading YouTube page: {e}") - return None + if extension in ACCEPTED_FILE_EXTENSIONS: + return True - if not soup.title or not soup.title.string: - return None + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + # Not HTML content + return False + + def convert( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: + # Parse the stream + encoding = "utf-8" if stream_info.charset is None else stream_info.charset + soup = BeautifulSoup(file_stream, "html.parser", from_encoding=encoding) # Read the meta tags metadata: Dict[str, str] = {"title": soup.title.string} @@ -126,7 +133,7 @@ class YouTubeConverter(DocumentConverter): if IS_YOUTUBE_TRANSCRIPT_CAPABLE: transcript_text = "" - parsed_url = urlparse(url) # type: ignore + parsed_url = urlparse(stream_info.url) # type: ignore params = parse_qs(parsed_url.query) # type: ignore if "v" in params and params["v"][0]: video_id = str(params["v"][0]) @@ -135,7 +142,7 @@ class YouTubeConverter(DocumentConverter): "youtube_transcript_languages", ("en",) ) # Retry the transcript fetching operation - transcript = self.retry_operation( + transcript = self._retry_operation( lambda: YouTubeTranscriptApi.get_transcript( video_id, languages=youtube_transcript_languages ), @@ -158,8 +165,8 @@ class YouTubeConverter(DocumentConverter): assert isinstance(title, str) return DocumentConverterResult( + markdown=webpage_text, title=title, - text_content=webpage_text, ) def _get( @@ -188,3 +195,17 @@ class YouTubeConverter(DocumentConverter): if result := self._findKey(v, key): return result return None + + def _retry_operation(self, operation, retries=3, delay=2): + """Retries the operation if it fails.""" + attempt = 0 + while attempt < retries: + try: + return operation() # Attempt the operation + except Exception as e: + print(f"Attempt {attempt + 1} failed: {e}") + if attempt < retries - 1: + time.sleep(delay) # Wait before retrying + attempt += 1 + # If all attempts fail, raise the last exception + raise Exception(f"Operation failed after {retries} attempts.") diff --git a/packages/markitdown/src/markitdown/converters/_zip_converter.py b/packages/markitdown/src/markitdown/converters/_zip_converter.py index e2b5fe6..cb1a7e6 100644 --- a/packages/markitdown/src/markitdown/converters/_zip_converter.py +++ b/packages/markitdown/src/markitdown/converters/_zip_converter.py @@ -1,9 +1,23 @@ -import os +import sys import zipfile -import shutil -from typing import Any, Union +import io +import os -from ._base import DocumentConverter, DocumentConverterResult +from typing import BinaryIO, Any, TYPE_CHECKING + +from .._base_converter import DocumentConverter, DocumentConverterResult +from .._stream_info import StreamInfo +from .._exceptions import UnsupportedFormatException, FileConversionException + +# Break otherwise circular import for type hinting +if TYPE_CHECKING: + from .._markitdown import MarkItDown + +ACCEPTED_MIME_TYPE_PREFIXES = [ + "application/zip", +] + +ACCEPTED_FILE_EXTENSIONS = [".zip"] class ZipConverter(DocumentConverter): @@ -46,99 +60,58 @@ class ZipConverter(DocumentConverter): """ def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT + self, + *, + markitdown: "MarkItDown", ): - super().__init__(priority=priority) + super().__init__() + self._markitdown = markitdown + + def accepts( + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> bool: + mimetype = (stream_info.mimetype or "").lower() + extension = (stream_info.extension or "").lower() + + if extension in ACCEPTED_FILE_EXTENSIONS: + return True + + for prefix in ACCEPTED_MIME_TYPE_PREFIXES: + if mimetype.startswith(prefix): + return True + + return False def convert( - self, local_path: str, **kwargs: Any - ) -> Union[None, DocumentConverterResult]: - # Bail if not a ZIP - extension = kwargs.get("file_extension", "") - if extension.lower() != ".zip": - return None + self, + file_stream: BinaryIO, + stream_info: StreamInfo, + **kwargs: Any, # Options to pass to the converter + ) -> DocumentConverterResult: + file_path = stream_info.url or stream_info.local_path or stream_info.filename + md_content = f"Content from the zip file `{file_path}`:\n\n" - # Get parent converters list if available - parent_converters = kwargs.get("_parent_converters", []) - if not parent_converters: - return DocumentConverterResult( - title=None, - text_content=f"[ERROR] No converters available to process zip contents from: {local_path}", - ) + with zipfile.ZipFile(file_stream, "r") as zipObj: + for name in zipObj.namelist(): + try: + z_file_stream = io.BytesIO(zipObj.read(name)) + z_file_stream_info = StreamInfo( + extension=os.path.splitext(name)[1], + filename=os.path.basename(name), + ) + result = self._markitdown.convert_stream( + stream=z_file_stream, + stream_info=z_file_stream_info, + ) + if result is not None: + md_content += f"## File: {name}\n\n" + md_content += result.markdown + "\n\n" + except UnsupportedFormatException: + pass + except FileConversionException: + pass - extracted_zip_folder_name = ( - f"extracted_{os.path.basename(local_path).replace('.zip', '_zip')}" - ) - extraction_dir = os.path.normpath( - os.path.join(os.path.dirname(local_path), extracted_zip_folder_name) - ) - md_content = f"Content from the zip file `{os.path.basename(local_path)}`:\n\n" - - try: - # Extract the zip file safely - with zipfile.ZipFile(local_path, "r") as zipObj: - # Bail if we discover it's an Office OOXML file - if "[Content_Types].xml" in zipObj.namelist(): - return None - - # Safeguard against path traversal - for member in zipObj.namelist(): - member_path = os.path.normpath(os.path.join(extraction_dir, member)) - if ( - not os.path.commonprefix([extraction_dir, member_path]) - == extraction_dir - ): - raise ValueError( - f"Path traversal detected in zip file: {member}" - ) - - # Extract all files safely - zipObj.extractall(path=extraction_dir) - - # Process each extracted file - for root, dirs, files in os.walk(extraction_dir): - for name in files: - file_path = os.path.join(root, name) - relative_path = os.path.relpath(file_path, extraction_dir) - - # Get file extension - _, file_extension = os.path.splitext(name) - - # Update kwargs for the file - file_kwargs = kwargs.copy() - file_kwargs["file_extension"] = file_extension - file_kwargs["_parent_converters"] = parent_converters - - # Try converting the file using available converters - for converter in parent_converters: - # Skip the zip converter to avoid infinite recursion - if isinstance(converter, ZipConverter): - continue - - result = converter.convert(file_path, **file_kwargs) - if result is not None: - md_content += f"\n## File: {relative_path}\n\n" - md_content += result.text_content + "\n\n" - break - - # Clean up extracted files if specified - if kwargs.get("cleanup_extracted", True): - shutil.rmtree(extraction_dir) - - return DocumentConverterResult(title=None, text_content=md_content.strip()) - - except zipfile.BadZipFile: - return DocumentConverterResult( - title=None, - text_content=f"[ERROR] Invalid or corrupted zip file: {local_path}", - ) - except ValueError as ve: - return DocumentConverterResult( - title=None, - text_content=f"[ERROR] Security error in zip file {local_path}: {str(ve)}", - ) - except Exception as e: - return DocumentConverterResult( - title=None, - text_content=f"[ERROR] Failed to process zip file {local_path}: {str(e)}", - ) + return DocumentConverterResult(markdown=md_content.strip()) diff --git a/packages/markitdown/tests/test_cli.py b/packages/markitdown/tests/test_cli.py index 1e2b095..7c8afc2 100644 --- a/packages/markitdown/tests/test_cli.py +++ b/packages/markitdown/tests/test_cli.py @@ -7,7 +7,7 @@ from markitdown import __version__ try: from .test_markitdown import TEST_FILES_DIR, DOCX_TEST_STRINGS except ImportError: - from test_markitdown import TEST_FILES_DIR, DOCX_TEST_STRINGS + from test_markitdown import TEST_FILES_DIR, DOCX_TEST_STRINGS # type: ignore @pytest.fixture(scope="session") diff --git a/packages/markitdown/tests/test_files/test.m4a b/packages/markitdown/tests/test_files/test.m4a new file mode 100755 index 0000000000000000000000000000000000000000..7a3b25f85c71f24d4f065752dd3971377377f7fe GIT binary patch literal 165924 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

u70|?mVYVjTs!NVXM8Q&bvqX2MrA#F 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

o*I~b8TR< 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
h1p8^EqMI_>;-aL(5jFxvHd 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�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 literal 0 HcmV?d00001 diff --git a/packages/markitdown/tests/test_files/test.mp3 b/packages/markitdown/tests/test_files/test.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..b13ff887059e8e6f3be8bdd2f41801f33c26b28c GIT binary patch literal 156258 zcmeFYX;f25yXc>U1QNz1%%ce;5FkJTVF;ooAwUuWGAbY{vw(;pqK!7%0Rkk9VIBmT z!YC>rB96@vW>i45o!Vv=5q&|?2Al4__#XTG&xiBBU+!A>!(FGcS9a}PPt~ry_isH< zRXxvU(yhRNodneIVft9^WDEfSsR$d}U=o=eZWe4CMld6V23wi!9EX@$S=)t#k*!F< z;a1@Q9}g$uj=biMJe3^N#06#U2CrP}#H{5shymF(Ic<{5KNb z-cCCbN;?wl;4=}{cILJ==0pNv=iEQ(?>{>K$^QTDnXwTkcM5l!0V)DO!94&eX_%ZM z0;#H@t&7sf7@6QLEJ-$GhrLv~6T{Wr!`t^@z~Q4I;m4w4PR7OmknrP$q?9y4Mz$!w zsIvVhQ}T}ntJlfi(g;QF1&fW`eE(Um(4%^`qr79K8Nn~ znP~N2dxin`{QGdH9}|23JoaCU{wM!`{|W5y69!OP0|26St_=kM6i_>q>}=wl!<{UN z2LOQCR5vH9Z`}F*H|c*{_}|F?&#C{Xp1}X`^Z(TA{J(xP|Hu4L03bjyODc6zN34%d z1ruK-?2@sH0|Maqlv6X2=L{;9m6c^f$eef!!D8=!6auD|ZNQI`YKCp?5wgMUZO?k( za!Enea0BU`nt*A?z0&E`oCWO$gly<7k2VK28R9kvuNdAz?Vb^TD@46oRx0AtN_Jhx0*$BL|lWCooYFJ zRgnyJ^(P$#FbU4?R8XScS`%>hv-TT9Q`cX0>#Gm_N1;^^Wg5Om`dfQ0#>#U1zReE~ ziYd=N`0N^zqRKy`>=gARE^A>CqmI>Ic2^FK&OrKgl`A))5(tKuGAEN3?l^HR6LBOZi>a0d=J_-*?eB0(#FczAEWhGH2xK?>jA_`|zHV>J*lM9n#l` z;0stnT+btTaS?0`6_vVtK>q_W$qkaRn73!o1TA;Ge(63~A+Yrrv|F}rStexsK1_6z zr@|bBIamZW%ftUNoxL=hOy-wq!J%t? z15X#^>B~)1ZW*~JDH_hP!i?(yB6M&xQF>g10y!|PF~;? zPs!#(*FIA`5uz6L;X)P?G1aapkB#i=R|U-Fe+AXoPRv8SxPICh*$jh%UTf$~e8YYd zSeS>twfdt$F>tMkPIg|Q{7kA^xIx-XZgP#=>w8JuIgNEneH*)r9opGelTOUcUpQJ= z|AZEc9?InWwcm)z9;y-ZO*55=wTB{uwVabK=(&gT&-wNxrmH)a{&5m-#1a(k-IKY# zB(%UiZo0YG&^iC^XA8W*Q}%?}z?Rxk&*r|soO4vs0`oM>P`+-&-nD38<9@g1H-4T2 zwhZFzi2sVMyzc<;- zp#Eqn0j`^?J+2@!`)bb+;YrRl7Pa4g#}UYpep zTZXgcxjl5bl}y4GCM@_spBeboOEp7JH{F4WIt#gwrw)(MC-%d7HJOzut?yLDuDB}o z$zulc50Y)d;FEs_lg%YP;|^bNa?cI*$|N&)bW^v}h#9pLZ#7tG72I?S&^!(1wNa^D zkGozV;Z7vDWHP0rl{)hXq|qVjvs`R{(PoJ5n-LB=GY_9oJZYbyzqro-suE3QlJclu zrU?)ENEKb-x`gc&ob&9k+;e#{{d$Jm!;(M$E|~gwQn{|_y|OR$0;;*@?!FRiC%+kN ztaS-Bu$-9t3o9hPC$Mn;;9IP%z)R%^SVwDDL1EKZHOxq?5p&(z!AGLeuIQz*5G!oq zoy#n+yPChigxPz8Vp7cN2YeVVvNJc~;?44g0X$?C7_sz3<#n#{!99tLwtg!J~gsVv5cGUb35P%Xe%3znCcpZn}e+`iOX=C;fj zTB2QU@QQs&2rHyyE`8 zBOH@&$olxg-GA_H@L{z%l^+GsHTKl~hz-}u9l6~y;*lV5%B)1IfI*>8(4>daIImKg zbUg(V!-eM75VDpxz*)V>=w94bN%YRxUlTAaP2oz3bdpf;-X5BS`{ODS3_yVa@_-&Y zWvQ80u85HpWkHCBEhvbsB$z{|l%GK-2T7X;qhwIV-zr-IMe<1~>CN<9|5NtUC;#>L zCa)(=3(|8=f;X6Hl(LfxGUIiD3Ce(BMT!U-)UBLSLwOS^FFO#@?l+%+Q>gM`HDp@}W$!_dkKGVz zKmjO+&&rS8tFRu6l_Hp7H&8V|WjKmYQboOh!EKW_*?e3jyzZ>Yg&~^K#>W~tZ<9h9 zjSqY?n*29@Iy1KvPF^=&J;(WnpQ8H@W!k^Zq5o~aj`TY0nnQu#o`#ABSn0+;;3GZ) ziW+5LR>o3ZZ0WWtE5$m(4`6;0{QhoPh2C~R4t7`RUaV|ZO{{iriz0kFC0-ldEWPYP zCt>vOx(YnEJ8NT(MH~wY{8j5r6N8Dy_9hzi20~`;ORXvQvE@DT^F0*^tiE%b5|UDh z75qUT_;=n#mbN(t(`#7EI_%=nM@nD6;DT#c5Gs;{lhS%MvFfNNN_oNB4Z>jC0L25= zTC=n&52L^*7acvZ{DaKlpj1X_64)x4BpsA1m0-}ffbLJ|E}pigeKC&)oUu!dA_Z&3 zD+)>hL737Rr&3u1Lk+vU@j8zUh^5y^tJc$iNZf-?%1cUbUP{Vk7y(y`Xu zlXuLsisKR#+zMv~? z3!DnGp;x#TbjB%8=XWNlgrP2G-dUsOP9~pB3B=aET5_QFIJ;uR^q&5xc zpD8T9&uiuQvT%{k*lqa_(x^+awAErMKmgu1xwWKX0pQ%X{Z3cVW9jk!7!)mGd3>z6 zUw{ejNfgN-{a)>TF}T|V-><&ntsG;t`sUb(uB(Cm$=Ey=Ge@|4f$F+NF4J?2E(a zz!7!Fwl!Oq=gq`3Y5kh>mO(61103tH#A}NK0Ta|{Y=I7XTVvpsnTa-d!AQol^l)lI zt#836KB{)%h$uQ4!xu!Ibx`a$V79EEkf84(pwc$IdQ{UAAk~)XFhmVg8hX17*Z%ZK z>DU%7DAGcIj_OrAb2t^VlLY1%e4cdg1qH@P4HP?*qAt;4KW4Qrt4T%qO`p%^vhM6j zM=hvR(zIkrOgZaEM009tTU*IvAw64h?M8Xj?8c5trN}4Q84g=vTwIooM$RIMhZP2c zFC9u9Kbpn)^ZL|V{14iC>zl*p98^n2dproJWg%cg(bM6h49ki@_Bw@x{(*ysOo1f_qk2SmO(({2h_>qyG0gAY!hRCQw%vDtD zHTQd^+v=vscPY*EvE&MB1y#im{96xsA!kLYV>57sL3K|$5i36nh$3&~piq;}SLND% zJ)%zaIYX`;&3m07MJh>~8I%SBcPI5Qp&I!mA88xbVEJF<=lqOaF$!)bW3qy9&5)SQ zM%4jj(%1!F{jT z!S9E^>z|z9UK576l1{rnhD zx)AcGcYTh3k(WDWF>*vw{K)=^ui@1^{A>xv!LXyMjM)x&#ONy5n;jMoOy`7V`s$uDzBTbd4pIn(ffcCVr!@q>0l6^BiB8 zORL*|OfBN97F!uBOVu^3X)_&Jh{|9xs~beV_K8z!b?iTnGTq}ZpBWrX-KVfKiB)8! zkeGCd3<8UoD9jWD2)TBFRSpJYQG!Hx*p6+tO97Q)sEWWa49cBXju0U!qi7U9t;s6s zt{K(GY$P~@lvxg*ApcglUu}^1IwrdgL-csOOlCiBJ5k|C^*NpEIoxJ%h+3g73th^c z9gQ)}qGNNBg*7qQ-9X-{>-h!)trx2wSSDobal?>tfqCg$C%km(2M!!!JN0}$=B>1x zhPVkx><+syv~S#L?#c>g)Svio`xVIBvWn~K{nwBG*e|{HzU3u{=l}3?y|Y4}iM*j> zpDhLbsWG*zj6`(rEZwfCv(1gimDjm$)pC?4KcVJyoP$2A)h!<^l5}!vcka91{Bk2> zeqizkd(V{k!dm)poZ_sa9yL*YP{iO%&Ip(a+BJR6yXrQ!$(b*f`vPy(j5IXW!tFne#wg1XIjjM5jYk>dAT1?;k&OTIAA>kqaXp8ylYEUVKX@3^pCQW+uDx5qSp894lSoJ zVRO&K4O-`8Eoi|B!esh~Qi1<)R0?nkjZ~9%81CUxU`zl=?dr)~ec99Mr*PSAYF29# z_L-wh(kTVR+F$`Mv|e?2a+~dO9dIdQ&Vg^5=!#;z7UNc?X+Ulwi zFL>wc@lK)k^2aZSC*Ljr@+}o4A%J$Igswb**{ zz9`ktkE5G4zUiMsyv@^b9ESN zekv#7sGM-Ohvd0as{VwR1te~EL_ycnZaw_!Rb zatoelU2)c_y?>^}$Kk2F zSTL;)+jzEmzq<`Bp~`|mExw@cRcRL}uNs#?o(4;9mK20&?llv9+>R41P$xPrs0k}E zPsJqV^toi~gE6aboeEGh9!9Qb|2lW8s_&VrqLjSfZ=TMiB*Ixt$8*nY3`Ft%G0l`# zq|ETq+l$%V?T+SGPW*ZpkPNzYB*zz5TC$^IvaY9Y{k6v&HYZWCFiDmF%A(aG2EvpTu44!2ESkjoWcfPQR!qEsiwymnPZBoK)q|< z_z4F5o*#Fc`LCdV?3Y2@;P}uz@;~!0{)P6b=2?-fl#A0x%8ElyGI3({6hw$CK?;9) zr=EsWgb=;vR{k#vm_~RF|`z7Zlop`Gba_9V#ch#?M z+spLDKi;n4h0Jdd;6Wy`@q=0(%Qxj;nZr#O>C&jskOOeO9Y7DBA6sK;ltsh`qG z)G>H^N!hW}Pu8*`R!{%+DQF0W3@dZDRYKU3`9!1+f4osUU2wCaFY-b<+SzTWcg}2? z(``iW>9+{00a2$NCobgnzq(f-X+G(z%zuk#SA+sysBLigI<-CL^0}LZW-GNb8{Ou< zCvxOt-QgNo$u{wBt$JfV;XG$wz-MXYlVZhl*7A5ClVbyhbIqYY%gzDp}vZ|J*t(HGted2X| zWDL~k-F5w9`Kw_0d(JOtxwsXf>G9g;Yps69jaHhw<4U9UzpMSF+E5O6v}0-SYKL>@ z)8}KsA$W45*+HTw;d4OCJK}D&+pHV>*m!S9NJI3X>kSBXK-&D=d$hK(s#Is7mi}AY zc(kudwPQy~j)Dj(>2dv9)Kr@`Dg?Ipr47F>#ocdf(vNcLO>sSMsP>JYNZ3|;94S-d z{6FJo{a(q7#(VGo;YaSUQ&B8?V=@H#D_Cp_VXKB59Cf;2g3Y;i@M82}<^-qC5mw=R zP(O))I@UC^TR{GLvc(H_=5ei~`x}QaOF0K4w|DHQNP&#OgCa^gL6>bL+w|1I6)2&> z=~qA=SYZbLXPk3t->TKn@B?ychA}#P-x#cKkK;6hUMP}_OHk97xVuI(RYGs3d*Q4+ zrU=Z;O>q;@z7nw%@*&H)Zmcte5PE4YHBiHaakWysao;qv9A4w_FcYgLsuTZdH12eW z`8vAK!d=F+lP-ADvHgPW(U<7<06iVZFy20C^wQgHFatAA$}F8F(w|ji&-r+k837lf zoD5lY^6@QFFgkoX@^*oD+eIr)qiE3=Yu~=G7wWCaiJ^rUav^_ccNOl5Aq%;8e=YW})|hb}Z{N#bu+jXe1@Wr8+; zdVV*pT>Z%v)08jX1LoG zinIT9{wac}HP1AE$%zuY9vHhSo*kH}l!MMm0R*WaV8tp7IH8aX->0;3JC4Ez_$h-) zD-M}KHsD@pP>@>xMul9;dUv3v$M0CWFBkmDNnB`<_*09?eneZ(Nr>O6rYA6>oL>81 ztya?dv(cCMyFV2Sq}TRHTou3ZvtO|JSDc-c-PwQm(L+m?huZg0 zzS}Q4`i%R-&fZwV+`jE4BST<=A5c$ z-=euj&4lZ|aShFAn_}gQrY{*4!1#*6vcQkhs+drUiGZ6p<#DAUP-!UwV~i|5(4_9w z-m+Ti-Lgl@;GNmvt)d$yIpz(fx}M1*zN+@V#->O7`cYS`PXqnsH5!Z`7Da`V0+dt4 z;a1l>9dETy&U!c-6&((A4?_S^!kNpef*RR@mGpOTe%`Xlk$!j8)Io3oLL*Bs8@2Kj zHsYo(OY<(G`Nv1=rF(mBU;P>%?isn^qO)JMILk4e=Ly>w8lJgcYIqI@=!yDN-r#o_ zR)C{pEDR4Q^0*xOdA+0#C`%!?7j7>?$`&N+TWTcxv)!{6J{M@@2p{D$uWFP|yj?ml z`?!(j6PBk+Sun6;A*wJ1ewIG*?uq$soI>{_ETg?lLy5e~?JJ*`!r$z>MhYLIdDS*$ zh+7p3i}>MAp4dLmkHNUj76qRi%5yMRdQ_-yqTf#bWU#zH(0*@B{&^VYiq00%& zTOCYmDAlkA>e!)?>_$WS6bT=Fjk&ql(LtQ&wSi1oLj&8nt->X=gNdBPek` zn1um>A{7HwgcBxvkl=-(5Di_+a^2ljXVqAuePGa1IX%xVrtCtnrOnG9eRFR4muiq3 z&fqTI4e;tgx{)-KYtILq+uLfH|01??A(exkU=+C7Au4`O>GclhfF?yTKz&-PV|lG# zn4{-6eo_TrqBz}2t8SLx`7xO7TNvL{$@s2+q`zLU(m3-xEG?b%gX4`ox(trwNM!ym+yl^Zk_?E-hZ zFngEMmExx8T{%g5``m%S2C!4Q2{+43=DyyJ&)+BTCtG>U;rAb{kXR!k91TZll2dn% zz+et~V#=ai@5;GXCJ%hyn!3zBzpd_A_lIr;QgIr_%o_6QXaFC-^X{^O^AkmcyVhLD zuKpM{-S3!yb33mu#-}(r=2&U+iwmfsddd{bSI%kcL?J%W%VWZKRlpy1PO62kg$ZI{ z2t*R9t(C1xFoc)xY*>Ug7XREhV$!6ab*tWQpnRZ8wb3-$H0bM^#+0%aEmZ2*c=!7F zL83R%*xPwO>HHa=8**uGZCFovr=SM?9&cTDFU0}x&Nd*jVVc2j) zTzGFC8?vsN(yj`faW=1j_K)yZb*hS8^q+?rniacXAvFV3yO!z^d<4OO9K3MVEZM49 zk6af<5p-%_HB_CT(E)HLU|0}kqWBPR`~gQKcBH};z+g~7o%H@02S)V=>&lHg*@GPh zH?uSejz(fbv@lATDMaX2i3wp3qPAs(Pl^!82Xw389WS>JgC6X=^^KoO*q3)4GVpD< z*LQw2-?lC_5YwRF`FZd>qWibjmQ5vXypfsMf&bT-K}h*uWV!c)9C2|I#S2~h&AlC2 z+})=~dTWA2lzv0g_X;^3?xgQO zK?+ci-*JGG_8?yqvLAf)UE^ov^7_6-6}13V{GA`4K%(bsi&ES&0)2|XL!+V*Wk|M( zYg4%ae$u#*&Js1Ta8Y%#owc09h0>RdeelDNT|34`8uW_FxELo^1B>C05RLRAQ!nxI zBp?{c0vTYJ0#mqpy3?DT=frq96(1Sl7PcR8Ib~>PG+SdgWfKx>8G6O5NM~S{`NEuj zJ>SqpMn)PVd)zBF2H}zH!k_WtWvs~eypR{+LSZ3VXjSY5Wo;mWlQ1VumESyrg1l~{L&qPOom^Li`Wv>{- z2@2RyAK*9v&Onb3u6a zWIXjEt)do*u6==+=rzJr_oe>G+kVLHzGv4 zZ^5kRg|g>cwaLEb;Dn>X$rJEA1-(3&`Zs>20H3p?_IMgwbHDS0o*bNzssFwLXIK_r8;AfC<=kc6b}EPJH%2EvkNPG?ze zpoNbU~MU)_7)`V3h z3t?-OhJI+-n?qkPjY0u9uX?w`g|yBwZTZOmdr><;AmuX2+s z!MA`DPdve#5$xhxuk=@b69|O-0nGb#?=V$EF^#Y-Z4kLC+kbZwA7baAn*tyiqyw^x z`@>$!_4@{*A+wAoc}1HsaWtDFuMoEAgLE89!9}+}16?EE01q}O0YDz<;$;u0ozIV59T`Pi06Mp=25fKa_^TaccYyC7&U>K4X< zZMB|#^l5a&0xXJ2c(jXrFY*4yMgs5 zeMXfvO3WXtpFZ9_^{(R5%Cqvo=b7p5onc!U1$A>HekMjpE}8uI6>DWiA&9LKNq|-( zgH)w3QR@2B%Y}L3Oh6ATsE(S<0vgH+d!6d9TdZVacTVt}cpeZf9Ij0^DIZsS(JUbP zfD=7A6Gl*_^e53+vJRR-bxsg9W$8NR*(z_qi)g$n6BEg#V3Yaf$Y5+9ea?f4YsyHK zdDxiv=8uX4pn!w-2UdyjdF6_SH+H}J*Qt9CKa(Y|PX%XD%=^JP&1J{NkC7@CrHT{_ zcl*5$tylE0!A(fnx!UloZIfmo1an}7{Gw&WLvLety=CF3w?zkCm~X|5x%*p=6tk}f>8nvXAYuy;-LBBHi*rW>h=xN0lc&@u*8v8_?9Rn83i-su zdFr!^>*o&qeJl3R-?4RnEw+7@qWQ;+8{oU45h0q;FtjL*wzDIa4hCzn!i}>cc50*pXV3C}M69P6=4 z7yx+CcR9rm`MkS#?aun0AN6*^XF-lYO@Rk}-XB6o5hdU61xE#3?0i~K8 zDb!8RHAY5Xk6-P4_U?QQvL6y??E`TYos}*mTW4+;jFT<$D%-lQUXFaA8M5qm0vY$W z@jlC;o>BvtUs?Ujv9e;e_FGWGk-MJi-pNU%~3F8V6W_`pD?z>d4e3PVt(RsIT zpl$ioesj@0OeHWg%1;l%Z_Av-+A<gd)M<36zUl;2WN;PN{ ziNk{qH3YwpBvvuJq*@ldnB7Wz{uG-OKis%Sh>e>f}PCw`3 zbt|1g#9em*p-<)q(BDUm$aPo9FU|&)fr}Hd_+hR3Qf=hgmN0xxG28UrnK-W#)orb)l(ziFq?- zy0F5@!hqH ze(No+>lm4I)1lWd_Bd3cR^wmhUCL#c06Z@TJxMP88fLr;@HU}XD#*Mz6zBs*xJn3wI>yj;8Ui&!UYTt|p^&a^`!RY%OGF(P7#mXtJhA5J*8jR#Tj} zYZ*S+Hv3{;vMh|sgq)U0md7WuVaIb7U-ZG>`{REv?&krc>-j4>pllW}K)nfaUC31^YvM~IuqlHoiNbZedZ zIPAEFfnOh)AU>4(!Cjnm7Ui}eTWUaO*hG57S7am5KUDj6Ui4Ov0-X%XPzjtrovD)i z*e>Bd222J#_C(dS<+(MYyX(0tAWm2FjO8oPRB zu@s{9qY>?=_Jq2=*7#N6*5Q+1OYLLKe$r1drfe*8o=yeI0)b6>Uv1Acfq^iOoD=M4 zyT=1u7VE3;63UOC0}D;1?hD_Fo>x8HyJ{=^#?Py)FMBw*U}^jRnZFzTIs5|u|HU7s zRb*e@e?`i&=!h^UESAyn4EftncH?q0fnQ=iIH7KA9F=xa=UvQvDxm_{>3~iuWU~nHtTiXuY!6$$E|w7>d+{&a6Lw($fUi)yu3rlGKpJ%2;sm zHp|HU%AOKX2u7|n= zlNR``$JhJX31@t2Oycai9SPW~oV1kgRkooJoF71=UH>#(Y^!;$F~U`mm771Ms`zO0 ze4roe%#omc@0vZ-l&DwqD&+yB?o+dU_WNoOpVTjxUdnj{L2w=2U5-sbe~q=9=<P7*pK~xWlR|vsXNmviU!2>Bx559!kD<>>UJu!B90i(9!}WkJMRQ;hCVe(*O!^hmGEcVWr@TVQD4^&C{C2Y%1Pw4BK}U z1?xcHUD0d2I@WgkV&?VuGw>ArTU+Q^zkP)Z)A_mHXUP`*i*0{76{sv=ueZy^>*6AQ2)-C`U{|!u zhj5`uP9oKH{e)m|M$HGl^4x*Fuv@k9YQPHDkb1tP(rbR9FKyw+U8}ICUB!;4Io#Dg zi=|NXtMG#4yOR`+xhYqF_v-1~#%RyI2GN^XgsGjzFGj$e^xGayMZ);x${Tq8u4omk z&OSE`ZVKrY))DQ`NK%R*ogWLklqJHa zWSJ%x%7ng`m8hw;e4TtiJFM!x%RNV+qcH4r{6wTy1)8lnP5uML%C2} z%b`N|ZCp2Hj0*ddn%4T0 z{3|Q@X>WyH#`{CVJ~M13`~rgfr(1{Tu3J~}w|l%=jVD=84Yn_7L@#Rcf+|Lz_E&5- z53@)0zg~Um=o)pOA#2(Bji0}Hn-yFesKImK* zeCv_E-f<67nE~&!Hp!y7Y7n;@JQK+{u(o)O4#0RHv?tx#M>wzJ!Pe_ zg_NHS5##Q|{BRk}BGwaH#BGK)zL7reK9aJvESF=>W-rods>Sd;66ZEVAW7-hZ|@Ia zIT7ge@LC_bkU5yaSR}&H*25X9Ae)jnhZKI98Sm#vhy^nIc7|HuLbLh2p=;smM4Com zkXNeLh-}{xUrURxPiUCEF*uKs;jdXDdp~GTp3`-2&rntA&oT<~9?!vWA_X3mRz25m z7|n9!=N$F9YW9+BhzK%^0t#2FaL=_|L7tWq9OM&3=7;SIW75x9lZ6A{!s%5kUZsyKJRf z%TEYU5T|6%h75&S-Xh*zr+#X>->~Lv+Ax;~8Od zKxRcc=8X$zJ0}h1QN)sX7rB>yJ#K1sw|?wxO+9z_l(>)Ebs%6W08}g% z1FE9S+Uy>TDtQTNB!?DtAt{%*FDOG!x5<;9qb(eLI}H=iwje3>=dU9DRO*40JM zvYt5*e$jJw{#ivK1v1CZ#F?D9ba`bO7+_rY6w&i5kWwsTSF7pRUP_V-qc~2Kt`e^R zTjuaAxvY!8flC+m2fVZN^@OUN4p+Y`gnS+ELURe$#Gt5;w@X@H`=UXUdEnt^_^{^V zMe5}9h{FR1=X(7nZ>px^?AbTOz4WF2o7D3i1Fu*^>z8N>+u1!|%=N|EO_Q>sem9Mp z@dX8OX|Jwe;}Aaj(+T^4rzdc8@6LOW?z_@yh7EaFfI&sC0Hr2p|NZ^NJY?$^u9d0A z1!6+ zof@E4-o$cI3bL3;1&C&GhnnD*=e1W)dUoSZcdi-Q2bq4hPLO-ytAG6G=DtD}HQ<`M zAIBug+nT#td;MceuF0#;{Z$u#rL+U8 zruF-ZWrOjnD#oZ-l>gYfob>kg6(?(PQ^kktsvFxKU8a#*owykM=2A2vVFJ)Rf@PqC2xyaputU>@?>rX+8!NBug;YG{M7U zhNNgJ;NeUB`HA|L2e7aRMu{c8hTszvXi0L{l+6HCt5A?&$36~26$9dV0=o4{3@x|_ zmIPnh45RVbOh&Ssscs9A(XNnmNxADJao9&Y>!PNZ`mKg<+p2 z@t4+kezU7T?B0!htSqmKt(q?WDP0;~)%Et`Uz~-mKR>tzvTG$Pe_dYh%%i+rnB4ub zckuvT@c#Uio~yL#iNxb-alLPBjzz$rSxRa~Ru{hMpBsYT`{Hcd-$qP*=SQ<<@HM@D zXZrOY^LHs|DZ%5#rwxNqhoCpQKjZZxbm;efT-DnLOcCWjnV9Jk^@bT9UrqQaO(wgn zswe2eWU_!6{mjlxOmJ}Df1o$H3nr^L{zObTkLJ5X#I-tP&GZ>u|3e2C+5!awoC+bQ z^8!r!0^1s#_~-5N3pl17sWP&f<=@n900BPjc+ns1mb)bg)uoF!$q!Tf+A0QMKjEeQ zu|{rh+8Z3aT|~dq)F!1gx(1Af?EcKjR$I73O(SN$6B?6c)Uv8)kJYmMm_EcK7K=+j zE@GPSnIPk(HEu9)59(Bby>+)r<5+=&^Q${%G`Y;N=5BDcLIFILyh{Sj@G%}{eahQw zIl_G_i#5tpp81Kev#6UmvTuK_d~F2ADFfzV$tlG^2fF}1EXj|E^NXG7QF zLPnmle7OJza_AHFBtk@vDRpUrqcWW4+eJw#>H%SUhV6A~f?8AwX14^8-_EK{`qb$o zk}8Isx|OOgC@AB8E@>-7gc5$%7W1mgp){Q%`!`2maG&}a8|7y8&Z)X z*Ux^aC!?ity2NoY@Pej+1_j?FWB2Ny*oE`wzIsJ2+7x3O~Ep^PQi)%(&aH zYV>INdgDG0q3INjfd`cCU7<53qf)O@gc_KnWCL1|3SmD`0*SkSGzFzV;KFt<0vsh- zM7d}OF0`pk33;T*TGD$ITy4}~$@`$0qT{CN-p&iEt7{hOt6fkBU7#o^!+$Pxlw930 zmI?WCyx$1Q&ZU=>r?xq^IPViMFq0o$6T`UyJb@o&xKTC{NEu3Dx@2aw102$(ujR}! z83*`48Lr|HUrcz=aq*RAXZyXSOa-l71cWKn*nJjcLo)Jfnn-j3$r4NR>0hQt(loK? z;6QyJnx;rLB-j(#k{U^KMX*IJuC@98Y5rYBxw183CgXyVh%|N!dLKC85xXQ$ImC1% ze>T)7Gia*aA8D*#QXdAA>U9{}tF`y#9u2a;RkiF3*J`8Wt6}-jBEqnBsvXNN*Je;k z&XV&(eC23r=JYPknjRkK_eV#w%slSLc zw7+|@DR98-8$ZK>FD`L*?W>F(h4b(42XW1kr}#HO!FPUq9vBMyBJk_|8E#z}(`7AN z4>(Wzb~glY37cp^-A90@fBe0yD`aI|drb$szpjcie6Ct;-hE8fn+B%eHI>i9NmHNL zgtokwfqUGK+`RLQ*3*!G?wa8ZP}e)p+(p=l>TOzS)xKRCLKP_6lEEHNkbDUT)eO456Wwpf^iCffG7UIL)cNe3;V9`+k9UxE|@6!SeYq}eR?RObP4lk7W zO7>T+Hv5?wr;Q{H*i$=hkyl=XeG%j(TjhlKGR z5O2O+rSkI7EuzJ6{28yp@&Zn)gUFvi_{_{qDLYa~)s)NhF_Ur3hvB0X>0VJDLH0tU zPIGmoH0c|Wt=6(c`&y#TO^H|ZuF9hEKP5!`pNq{0kSK$TUEHuENSR5@#!NIMhnd=| zVPb^W;7!6bzG$WI=rDMe49#b;+5wzN{l?Glg3ZryH~W?TGk$)T=HTn}d%6GEFS{eU z(9tZaKoe6Z-3Jr)OptaNaH?akN)59YsWm4bx#X>GZ??w2YXJd36QxSJg~HKc8nIVH zvcU?7hZ*%W6&Yg$F@^F4?g2W7?X_rypz7`Q9zADF(bWU)d>CRfBKYAXy;BH(?zo=Hn*Y@t+Qh>E21r0IBGvL)oM*usS+Dgl#93qVUIG9U2?nIcZ6 zF^c%GFzH8KeI0{(*hH#ceNV0e{0UO^1-}oovj{K4lx8;xp%dEk)kl#}ru@#O79N&q zO;f{~Qq2|7WF7w9b#H?qMj2!sNJb79P#RV8EVW0h3li?+_jVa$aDQP5e4r1)K^ znRH!yuPK$7uQB?B8mHYix?8SnqxRq>{W;VA&f6wWn)?G2go4+*ebd)}&;eyxI)aNF zZC%=~rBg1e*AF_Do)PvGWKdobBP?niG-^4vV^XdkHw@8UmER8L zkqeYw{x8P9Jeuw8eK(09K}aIzDT#!bXGOJ5B1nv(sIiT)=p=@I(H;$g#2E8XT0;y~ zdQe(ad(3kc)m9y+2SsU}9#mWHX?w1o+w=S0`^R1DS}W`G*~{La{r>T+XTN*D@B3^E zTsAq^{D|!9|B-NM{Qv#~^b)}YkeJ(YB*-vIh)d&8vkTxNgUK(e8Dj{jD?1cADUVl^ zf*0u$GkMRGaf1iB7>G)B)1Z<94!d=h4PKWhRYT=US-8kyZVw-fPcPSHmG{-)s;iMB z6d;pWemUA$Llk1wuV01UZz(a<6e+UsJ?QZc*Pn+~t%ZyoOkik7`EEdz@Iz!e$6kqG zL!_P^GtfXl``4xw^g|0u*qqi#a8T-GJ~Ew}UZ6^JVmz;Q#Uh7B5qZkSb`Iq4!ws!Y zXMG>8_=f<(+QKz{Edm07YrX~P0LHd2lbCySlA0K{pL*!6&Ak8KIllX2MrTLc@7 z3I5)Ma{$xP(chb=0gDRxOYj3@H%p8W65`+cg;E7pEQ45~FbPQxBcfz<9X1$!FidzN z3=9ah&^fTbisY-192pO12@C&+3z+_npVg!f&m!&;hN=H^{_HaPSjZsjU;M}uoM65C z8>6YP!PqeXi|#{33y=e`vXVOWr{4b$c>ceoL*PQ@vN9kKqoIgA&R_7T6418aBopVB z=9Qqb3h0#Z$~+?2o_w8Meh0#yaL<8)s*D@0*0T~^{dLV zyhY2*cE7!h4Ex5&fbKUA&R(%i(KT854>K>!rlVF?|E8zlg#>K>Oa$vLZhGhff#jN6cXv+A)_7- zaPU~5fHS=ftfVt5I?=>E4iv7dDs`P}=9|T5Cnlu{3?`8|!!tRA%V#@x4PAjXD;w5; zmmqHyAQCkntxJw*-7$v(zvE{;XWu8%6uR}((hvSocry4xxYdOI!~a1_YN;IL)RA#& zE|Qu4T7xTxu|!z;}l^g?B1fiDR6HA$P^q@(X-yYhClugKN<9 zIzwG@pT)W^!C#8Isz2L+ow5 z%v}sn+{Y=f>?;Zff)2IX6gkv`%N1&x9ia~@ZW3%J1Ki>b%Cl_@5?s}sqj5vW@wCkt zM@)LP!>Phot&4FgQF8eA9g$p{+S3+U8#H5=!E9F;`M@Vo6R5n17!?(?icg$Inagok z2y%*nQWDsi_hws45>}rq7c~X*#e;W30(@!M&J{(P{<{Cf#GEJ9uw;<^wMv0ufz}q z8t#@#nXJHQ%#|)}|2%UuNI_2hxY%QdLc(!%tY6U2C-t;LJ&-Lgwjdsfu(c^7Lll?-HfST=c#2LB$7Nwa^QP>u6KsT%BRoy<6Nq^=#j4N#lEZ3UBmt z=5~pHrl-npi>A9hJW`w;V?RLKT+DZ^N-MxdZZ*!L31f;F3x@{WEn-Y_ex3RktFEFa3)Ot5_DwsTH*D3e`1GB%3o?{(Aw{biOv=LL+pkXI|bGdF>eirSkJpEmh48uFw0= z)u2yIC2md(MmHlzmhUfys zU@$-+(A?ZyPTn}=VI@sFm{sdQa!CZD?3p!{uZ%O39Z>}qll^O*LO@35ld~HPD;3f7A<{y#}_gVX;ujv1eJa&u#+=37^Ky>VmQAzb0w*p9c~ ztcKB3__l9p$SyN26Wk`*ctse@udRH@oK&S*rXN><@(Zx~b5>0$79=$ziaWyXm@^hP} zyt83Abuxe{Heo!y28^~*Eh&Ae;as9MnIV|yV@}W&5dz~*Od0NVE{F~mz7wf)F&JX_+0?i%#{UbESvNaa( z%FQfNqJyky^JxaGd48;~Sfr)D)K)gKvfvqkBH6u6q1MZz%AcA+$Hb6{1s zCyVfzcgrs*JE4>|dB?}&_{qpK1FE~8zs2p_p_{}8^(k9qWC3D=vBB@r)hU3FNSfXj z5=)Q9>uBnorQJbB?qDy#YtFT-%iu54Hmk=h!`BYfs-iT;EBL0*6g{qp?_B)!ZtYhw zT-5tBukOeSuB7_!@q|iJ)P+5f0XThebR9Zr_>6h+j)HM!WhKO4^l&zBPI_nXl&Bp0 zhb7>CKRcpH8%7}@A54k3ZBWGf!*-DenLiY zLD3if&MZ%YJ?r_UtzpqkCUR-(1uO0<1muxcpTn`S(3t)`A-2fL7QxE>j-O9}k4wz% z39&2x#^162gD=#MEd7fgh0Q(OroF=HHoE`K$-Jg*`AvbI$98gR>FmuDFaQf+(>Oyu zTZ87WcGd|uw3-PZ$Yaf+A z<{RuTLAQE0wnnK%Z)5!8H&tWMXZErKiPwC?rOCj@J$deGc$Cg9+ud{IPsjv`mH2gk zv4HrjW3KhCMe@WIoyNgZo%61@CQGl~JydnXo00Q$ZG5>FcGf&2Jj|_Gebn3S0{+*T z#;vO(NJ1-gb3L|d5C;frhNtIRx>kLlW~3KMnX)zU*wR@d*vSq9z=22Iog?UTVJfIT z3u$kOri+v1o6lt4P~Ea?Ma}#&sv3)RuKuy1y$qjds7;^$8B_x~%m~Yb2`{(;6=>Wi z7sR7CpI(>V9X1yLEO|%*q#;Ych#9=G1)6~{k?=%gjPQoWh<7gU7hZ>f8C@ME9DB7O z&Ehg<lXzLE+58-tV=dUN|HXr-ISlFJ>NPezPBKo;UaDXXt5hkYn)5xNNR#bgt~8x zLG~3^_WV(6tH~+{fk`pkdX>4j+$H^&TWmvsLma==f=)z0MbdgCo6nGIo2b@$x>Q{ia>z@45wQyY8*g?0O}swV|dI zWZoJ%;B-%XeV)a+rmu!4N+j%G#Jk#UUyFFKB|SsFGy6zR>TIWj@)$Q~SYRgvY+orR z+#e3w*BoI$l2L-&15(?v!*Cdzr?`C5FtPIth?gfG@#+{Gy^Via*@u38P^OmLUU@J3MLj@Z@$j4 zlH)b&{W(1lW_V%Hah7w-V zUQpE?Bek0H_$g9vbk@7fX_d_+NJRQ4QDb4Ch6==AU27~i`m*DcYS2eFv{U}q6tk*a z;#67(0j1vkhjx}HS}Fb08fDHW3oPWguwAR@Gq(!B-g=^PezyadMla>P>Yd7BECiZ@A?f-9XYj zEyL=5%};Gu_ls_)x|I>mdc&z*WNdS87j3sKYIuU4QR~}it=P1Xv8)e>$9ABRH_d{5^<1@ofV05kH&?s&(U*8S__V57XRMDgJBS5gss{;_A?uNsWqO zFKw|+$NBu_cV%AhHk_Xa+$_lpmocif_z$6QEoI|#{6%Rs|L$fZxP5U%v<)B=A~cv9 zyh3H8^G;~vIeaH8_aJ7{t6$7Wvh1tR?uOX+nd%?*#(ocA=+Kdg%yA68QzExaaIBG(l8&*@^LAY2-5X-FZm zCD9Ip!)F4T8c)z}v3}LTP{_s+Spw(7pm26$M&BJ55o)fDOLK6&{@H=&c{imj67L$b zIbFqvw;kH>MCbtb7st`qW zLfIt7AX;mN+L+MX{#MZju*(f79URd)3dp+AR1W!8o^CN%wA-R)5wE3rSF3QaHUr`F zY`{9q$-e1B&ypu2%f6k`aya{*)O~A7JSKOr#2=tt>BbjAh}{{WNyidcJYJSKwXt+8 zqVf%?yL`iIy+Yna%V^-En=VgrxPoFA02=+!AwY_gj!+vGHEX_R-w zO!vxbA$=j=l1RMtL_wP}ypcXY1EEj34N0z6YB8Rqi1G`Dy7XL#qEFc=V*c8jmF*u| zb{>>eKMlC2@

3wkS=0Vp#C# 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

Y^fqur(hap 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

Xg#7!cD{08z@9bP7FY}pF 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 literal 0 HcmV?d00001 diff --git a/packages/markitdown/tests/test_files/test.pdf b/packages/markitdown/tests/test_files/test.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e82861e7dcc25c24544cf439a5d585236b35ce1b GIT binary patch literal 92971 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 H?%aO>rT}kC literal 0 HcmV?d00001 diff --git a/packages/markitdown/tests/test_files/test.pptx b/packages/markitdown/tests/test_files/test.pptx index e6d16f3cbb7836ff92b701b5fa61d92c165c50ab..fb663021a11a7766e74a83ebe5c7871fd369a760 100644 GIT binary patch delta 146527 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%0D&zLb-v9H3g!oe9_6vD6u?{c!_V?&~dqgve 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

    hvzWHFPqQR8ZS%}qJ- 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

    #yiOmSA!tfw?i;uU%Aal% zt|>97>6BzAKL}qD4ildxXP+L3+dd@V*SlG8L0}B83XTZahMy1qBM=M!LBIwQUq558Z*Y#lz9_sTCXbu08sK)Z zZu_Ge>;A`lugV{4&%oP)cLjWL{6zm5h*{7VejL#0>GS6ae4B%}=2i*4b@@Pf*TFg93($u0>^9IB+fU!; z*#tXo|4lgWSlV+^=ZqPz82`Kvy4^W9|DKj|+Lh|Z*xiHix-a9Bg0UI*V1Dy@Q;E0 zM!vBDy!WhtPeoo_2@ld|$qISr*k{thwdXJX?>l9*MZRcDn@ePEuAgN{#j+D~Yn9~3+?=)IU{^UEfnUzjiPIyUZ`f)56t*u-b@ zw+=oZ_`6w02jn+7&d&Jn;AcV9n+?|dwGC$cwGHk)f4+gjarpVN0iEND0iL^2fYadC z!CwUBw|nk!&kfzcIr&EhbO<^I&?Ox6;o>%&hQH)r9N;k=_rw5ymFpbSPv{@wOb-n1 z9neGc1IADv;LY>*gmKwb17r7H&i;Y>;s?aN*>bd$w>R|@SATIt`P7So-^Q^ zvPV@soUet=z^DJ7z@9vR>+!h(Kcf9w4-M`eh}+*h5NGkt2$}zTLHA_spYKf16^L)y zn|9iOquX9!@fz_i`>b%w7lO|O{A?czJ|5UpP}q~{(a-C)qmfJm)X08oA~Fx z9@wL$ZTsT%#klrOAP&aG{CCE6Kwzv_3a%Nr4}ZJLcTfIyFW!1U@b|$}0-SGu8z0}R z0)9Sr*2jX+1?J8C#kIMy=T}_Ao@;T9%LZ2ux>pN#i6!y>@jvkais!H)*ba1*+74nI zVo9FusT_9pKC@h0etKMeR@=>=?0d$Psv z*qz60{yphWp7P0!XXE*NETCVo^E@*#K=3{So0J_$50QuW1kUlLi1o1*<=+-KR#shY zO10N|Z9^IDw7;G=26e;@_%e-EYOM0?Wyfr0Fn%_E?P=>xT+*6z?`(d05?dV13%k{v zv0bf0^T=7jhUHIY$I>(C7W8p?h-X8`u{N&|SdU$o(yIraxAoZdXRY8$>x@qD&;a-1 zVR`_Ypq$P|z)$3<9i>^47O5-wsX)eiX3J&Kj_N&l`~2qi89r}j|PZ^-{?Y{0f-yWu%8uJRr` zo^5}pfQ^ao#75cI=7Md?Pf%O>EMaptE}mz@N%)E=e>yw{s0P>W5hyTb~elD?z@}Ric z)dDe@iv(n~_!+wc7oHe=D)3+l>Ce z&ucHTdAvp-)+4@RZ;bi2C)xf4F-!h6{b4{d#n}0|WjGzFslM-w5a;o*5x+ZHt|Wp?xzrE;uGQIuJMhY~Y!H zD6rn`>5#J3-x*l{Zx7_16K8hp{1Jg;dJ$iVx}ONNs}IoMw}bBo#$Y`3&(m+l@AzHV z{KkIqz`ckkTrv2A!1}s*zz5JZ=KbaactRkKcX+^uO^>qH_<+S#aa{E%eq?-x=jqS< zM05nthJMYyEkAjV^d)kMJyre1+N1NZq3A($_J;@TRNTaVw8s2>ATp0n7Tz2j5gZx3 zHy{`B6Ofbqw781g{Ce=cfIY>2;7epr?2#WoBY)zKV4nbwk;D52e4FPBa2fC~lGXfd zmkiii{GvFHJiqcL*fIQ#e5>rQKMio6SS8-OO@I&hVDSMzuviltiEV^4?9If9hXmqL ze1-T?%D%#r&a>H^W0L`n6uYw@LySvo4p&O?CcGwS%uXEdrGazGiIu%Qz=yc8 zaYS7BmH=nEu5JC4m&MTKXFEiw}P~;Gee^tdXY&WQ&+GeTPgTOZflEK|Uk;y|sEue%9~TgYFSw zH?SkfTl;mz!{D+?l_z-cQznOY$AYOU=CfE|>Cj0GMffP6LG5ThJ&4C;D z++)uTzngdxoIN0m?ad>X?Ge9BQ2rycuMx2C$nkO=pCcPj{PDg4KEq@DgVSG#Bk&d; zIy8{SEo?6PHE555|7Kg>6>hw;0CeU0{r$iw#n$M(?t zEa*NG`)BMiQQkfh?H?5!6WE(#&kDQJ9!NYWwXeqb@F}h}ejLayWWTy!+*N4_@LPT zAcjD8vHi%#a|i4{I-9*HVmSO1d>4En;_lurb_Q9+=Ab)2Iv}gPi_z*c`3K1`yhVW@+{}P|^NAf+=ALtSE(_;g^MEpk2I3bXFkLj`et~js$ zLwXS%#XCR!+I+qK#sJ?C{fE!+S^+(o?-&>ISMv|>8`ehSW5S94#toUnjwgR`qgWR_ zF%a*1T7V~U5F$*;(Mdrg2R->~`jzwslkgtr853|zyZWLwd@ z-o^9h*xbj2gV@1haK7*0+pUk6O{Tm(Kx|^y&K8_2U?+nz>T2)T1AQo`3>yyg=R6;> zu^Ee>F*^o22|qK?ReJC2dAg0cqwCOlJU7pYjs))t_zA2Tf8&LH2-Y9J6^=4o8ln6 zD#fEX6lc-h%ae3_wt#pYzwDC&am&YUg1_^D!NI{p13u9EZ{j}r+f4Te?isKf`AP2< zhzIiJ@}06NrOt!$%Ce8O`{2NyAgMkc8So3Up}{!#TltIYb3H8IrM)P?;r7MgWI6%e z02kw6F~)K)Tb-W4Hu-MAK4F{SRQuoUsXu=}kHMYz5?A^L3|HbtIuD;AZp43{5$@q9 zrym_0c$PTfi2+XFQ}>+dSDv|jkZi)Ddq%Ab9Ke@py^#NG8yvu{1aT#{jy3g_z#8k` zPHPQE0N-f$=-`U-M!7>A%6g>_N&$~JZw>RWvTL0et5Qy^ujn!R*Y7m>MeLl$zSQnb zwGYTSDO(vo(Lvc}_5~H*9ex?SW#23AV!J{2*LcUO%N`IvBb%IE$IkDb8t)|gogI(s zE*m)Z-2oeaa-a9O`)tH=`6<2Q_6&e`9^}PV`KS5LC&byrUBqB-ABfx5uP)9@mhf>` zrijx3xzboLSu^vk&lU@psx1$@GcbS7v%MCua#pdzm4b5-Zysg+I@+ExOacE#d9@R=Foh4 ze&)N+&2!+N=1)8%us4bBL+7FA*xMv7f=}o;V2=;|g&tF104}NyK~E^?1atwwVQlqj zpR)n+Jl@BD_z=%KkNfR~1-viCpEgReW3$KGlZucvU-&`BlYrajW+ADc)OO zfju|;3v?Fx37rPF;$3`8KjY_c&i%S~Tx%}qd;Iw3Nvv7i`3V7i(H<~5C75G6Cf}{t zkohn7dPbfVJ(a!+o~t!zEdu#KeppXrhJE#nDDsDlBKO2S?H&JGK&Fc2le1(le-io2 z4@^Fj({%Pj19JSa!Q+BQ2EN%M=cVk3+9&K{+;D?Hyaiw24lx)!((kv#nAm5yMx2TL zCS}v{j{!fbm@1nYud@UB(%6MkF(CZKRVeu8?u{DND%~>y1AV-;jp|nS*P}Kk{S{G+!C24t~;(cFC^xB?ae!9lo>PwfZT}E^T+H2i1G3`CO*H?`&HYE@2RR~!L5{p3 zcui0}kIqk~@BvuYQvLyYp}z}5)`*4B73KN7#YgCm{0jVWWD&3#$Rv<29-sd^$2t0E zuaR4hyt$N?)h0nqqnoqLTdZCY6 zTi!o}xv+k|MlV`|xD(u`dZ~D2dc4{1x~dhqIme zU+e{=*O=qEhr>QwoXsyJUgG)CM{zWL)AOTG(j&oh^^84hdK`|nkAqD>K9Nae5sofD zljCe162`mjo%}%HowN45U*bU4BR`sb3)ZRi+V{wM_U`bJDy~llLoA=)K zUTS0ZUfplyhI8`f!Z&*I=ED2#TF<)%JyuRT$|+y8ZK-}i8L9D@WBJat*qyPHJ?_hW zns50Yn}a?FdAb02CY>uOn0wC$^?=#ySm-Xh=2TV($7{lZm;1$e@G=~^=%=Eq$1nVVP7)O>qh z-UsiE_k^#V4(R`Hfco_L`1$hbiU$St;WzF;pDgUn7n=~Hu)k?S?4rm1b_6J=4rrr( zHgSjw3j}cY=!=2e$X=CPDcT zhaD8)H5@s468GUtum{S1sQU!>4elTO-6kH8eYN)5&STe=v!_U`RbA~Bc=s-W{=}n= zp}dN>jSqZ_@+ZOd0{o8WuNqt_aBt$Y?%BQbd(#!n2VeNv0(u1BI-R0>dD+o?_59X+ z_EdL2C z>z-^QH^@2f15Tz(;$<9zOUe;TS>gTio|R9%e^6QBy(A~Z04pOJL#(_YGrZT84deqk z;Qg190qjz?dcm*DUKRJ0XT#QxWzUO=UN3M?+GA;Br@h{~>Osq2=alPg`0%C970TFW z*0vqjewG>!>}+jkS>+u&-+M52=&{s2lY^CoeAbnh(kTns=jILgGWfQ^yz+6d+r>_I zMsRn=U>l1izxlu$L-ouWN2N!RpVh7Kaph=vf62dix4MM&GIf>OC)N`ls-0q;;okag ztiAFrJ+WMi->g&i8PFw{z=a?-Yh9O@aVHLia&tMjcHxp^y&LK+(RP;UDqf!B>6na* zy$SO3xaX7w_t$%!ZK>0HqYLP}Fy7wNyjQve-9nrKx3T?v3sZZ$wmw-wf9EqGKN_## zTc|IN-p@WHci4!06k-W{7wiK*8ulU|2OrHU|4ccOtmC&9+pe#-v2C^_A3omXL-(x} z`63{%F*{=+2!HWm@ z`VyOv?=fEUJ&LsXc|6ZwWb^M0XjdN>4D`2uAjWGf=L(DsFN*QfAH*P}+5Q1@k3T(&mj?D7_~rn2(t$ij&y&q6#%r(n z{R29aXD_~DzXSVKyu>=8V_iGAMnLcS-M|{dpL~MsSo}#(J8QuAwokBE;Aaie^(m*fJg^ zqr2y&-}jVP$@l8tc$MxA_+Y7jSBIXucsUox0^Sk7wzm`Kg8bwu$AGV9zV+s{a$&j7 zaobW(zUAAVR9h20x6>-P>Hmza_JVO6KaMQs{hEt%rL=ZR=c}A4mOpvZJVW`CjWId1 z{)74s=t8wu%bD!v`T^?0vkq#j<4WrTPx2??$Z{jQblRkNk-bt*#0}+?r47oyoN}N3 zS3hliv~)xM*UJ9Ju5p0%j|cb$fnV8s!B2=2pgw5t42}Tr5XkpD-IT9LxVDSX|MTKaY8l_InExk50+fFho}2_ z*h}o;<$g81ZV#P z*p}wVes?@+-f$%!uleM6H^=lObI#`r__KQ(=u(~!pM>WIIF-KTnX*m)IIzzGJache z9BVDui@^6!ca!2>dk%0f*vEl`tu65~aepx}5Etv-0=z7aXKfbND!&Szrb~*Gv3cp2 z)_G%N;uCaG{%Gjl7+enY)W*&1lVKx!r^qex!aL}ltgQ2ndRNH_=e)n<0omw%_Rf== z^k(`qeHwgo$KO}GfNn5lG9AG&`3z)s?HO{sK5_Op`=@pgo7^$^FRfpXe&HOjoxnLM z-YDoFY^~Z@gUMXar_ahWEXrrn<~`q{&wtf%*9GpF<+NSdZf)pS{}aYEc|pG1 zF=Lp$KiurTfsIyMO&<7doO4~;>{$?Jp`|wlk9UTD3PkuxC0C`Hb0vnyIWfv9pDs*23+nt;yue+y#&cLPu`yI%3GG08G z&$4^?rXFEm8ap3H;EJmU)hF0()hYNwagOiG*>%+|>Ibl|i0>3n@d?l~?6Iq^Vb2|2 ztImP%@Sgoi)jg*EfhYM93f#%w1pCPFseNSjIu#EM&&oUBYtHdQfc!jeS?A>GI)(Q2 z1MRcNQsbf{0X{eOf#XmAohkmwKg;&q71*c~_3t`2^DR?*wlQb1#>S_Oqo|!b_s$qUxF34V((a}E(1(_B zSb7Itite%0JIrr=qUAu(VcNvyvdLqf--PE{yAE&Re$RgLR`myIb%olUGwu3mdd!9v zy7S-Kf>LLeddE%;<`@4Ohw&8ixNEZGuI_=C%hT08+&kd&>KpjJuzt;1b&2}VtIyRB zM$ap%|2meZ3l^SJ*L(f=);)NZMbFJ=JD>4vxBW@=xl_~L`HpoBR4>|U4VW9xzR%n| znpd-4{lxQG`o`%TwbRKHa)q2BZ*V(p7xUx1mUc`xb1;5~%+Tjo1{M#P(`}#i$?cM4gYPRXLy=!+L zp74o*_#R03{n3w3N}sh(8#~5(Y-4&h`9zkHbL<*6i+6*JAP>k>F(&WUv}wica93^F@>PA| zxQYDl9u!=JOYB488?_IGueAG*#2dT6h+p-PP4KgdPuA}${#@TVpDgVBBJ>ykif=Z? z>1>bZxnGpt`7J3weB+_r8>ZjJMvbTYmF!RISo!tENcn!3`;;0h#h19UvC?&M(p7wD zej6iQav&M#nN;r8)?Ugz&k_gVgxb^iV#+*g01sIYUM4kFIFU zVEpa_YCpQq+MD%Z*Y{oD_4HADzsw_;)9M2F1ZayXr) zD2L;9c|6YEmp0$yot}W5*J}4SRaYC@)lY5yxpr#j8?*7dkFK9%qR+TryvcU2f4ghN zT$$)=tDY%&dB@*T2EaV1-nZL#D@Hs{p?{z|qBTLw?|+c7c3>AUXtVB|6z zi@n88EI+dG_*}&($#=fkejmeM%YR$HG=DT+7%Y68kg~x8z)XHua(pA8SZzFbOAbn`!^5xjNQsk<)qP-9(YgiAAJ%BR{y2n(pBlNY`E^pB&*pk_3f4u z*>BTsV-M9#?!(1T>$hMuSAI{DDEC&wzotc~jYWO+G{f6;p4Q^W~m7`@86^D77O&DAGI z7i(U*pIZU4kg$hrF8*abl6o8XTFvasN9sgF)fhOW4T>&myjRJ-JA z{e4aAui?8fE+B{bZW_<&_fGDsKAXmL8rP}+ral~UzWz*ls<|_V<>>OU`JJ3xUM@G| zlA^wy@-x0!#-ZshQ-2{Fl$lT;&zI{R&vQGy%irISG1fu#9Al+J7(3mTrTz%Ple%~IiOIMY_ zJ>c5J^n)6M?_mmK#8t)&y$AQzZ?oCj?tA)4&5bz{E5~c~lQvdbUuk)+F;maObMbsU ztG<8UalGf5_I>Mn=Gj{V)`Itp94Qxix9CjXDSpxUK3Rj-qqXVXv0l9=)^pzt`YS!H zx+;EL>Zfc4b_37@>4j6z#F1=|B}bCMwKT}W#Sj8FLS0_`AKWPX}@+H4hQ4txTNK&`Z>#2^>y;^;w|@H`;IL= z`K!LL>E~kSndkbq@EN@wr_ovHF7;{A(ec{!Y1O{-jB#A!Y}L~nU#qTOd(PTfC)>#G z%C*L-tVJA1u34XrMNR&zAI!QIhXU)oa;|)cZ-C4zFM3ZJms)aSxv>1!W9j5V{76m~ zja{ruTTZ zdy;pry>DsPmUUGA>3T88%QfSr3fO89cP+pKY z$d`xa`QDpy?tS{N>Q`FMqxme%bK#u4XTay=xs=(~C*9@g3kwGD9M(hjip*dM#H1EznIox>iey;!@T9O}LBjx6m1?+|#O3ig6`ZOYOq zL;G%$n^R8iWZRv8Q^UKxlXZ9gOJ;(1zj9Mr4zArnPOL&X$+gOp%9kl?@S5W#T6S4? z)p5%%+i=|StHwCbwGF9y(bVr<>jj%%zCTFu{_s% zbiVh|x$xZj?8=MPCAto*iLMXnTsP&2>Jrx8T#NF!Ve)_d1CuAZ&gqWc0q;V61>N`I zU8(QSyX05@!Om#H&VSiItN3I356U04`ImNo{Rrh1a)HgX^!t+`D{%r z%0rb?P06n9g3QBR)$f~MrjzGdcAjJRE$eg)Ew@Z(JIcD=Iz8?=_gYjI_n1sBFFPmS zdFs5)wDVirrSX@_a;bAb59l+K?(_ov;@`%z>JReFm#FNgYjn-Xcir@SIYBykfelsg zY0+nvU}J$b+qEm5{6RNbqHDkB9rx$mz%}KYo!ZvUy@kztm&!xU&$QfB`wmBWC%v0} zKOOfyt!~%%wQ1|MtW^DS9sRKH{IcD)J?pey_db#twK=C8ac-9BwWj!#3|jJOWtFsc z%Bpj%p3^<_hZx zy4EJoc%Qsq-o?I~d~4A6b{s(>C`KmCnG9D zDr=;bLzP`yrBlvTmNl&o+_dMXjH_&0_CJq}v14t%_fYxn{+F2YzVc6*&RKP7vd-LA z&UMb4_FB`PpUzYx3mw1bt%_D&Lpa`u<3lx>0qgW$GR5Z{wxRKh?t~U*L?w`#e$JD3?sV zaPkQKk-V5PqsQf!a!mEoa!vghP06ToPGwe)C+C!RD)Z>u6V=0K>iRq;N2|*>t(=`{ zuQi?WxA|V1_2hfL<@DciRz}wzkoJC7r7gFV>E;e^o72v#@wdybBo36)sUS8R*$DJ(ozyAh#d8+Gt+AWj2 z`hN6W%XyEMc1qtv@1*y2)w?_2d9s5nD94dCQ})P{VH1^YP075e^Ox($SF*Uiw94t3 zP8nbMUarFlqr7gR2;l9|p`-bz;; zFVD67y7t=Nx|DpLC~uX|mh!hU*nM|SW@>IKhbvz@x8$n%?z5P(vRv+2_L(-{XKsyb zESAlGwvuyQpIvj(sjGA?cWux0UfpP>z25TMNoSq*H`6(unV)5r`T6ekJ?eW`8>Yv7 z4_B32zIW!f^DOOe&iBmsx>Wh)GwXZXa;>Z1J~!j+@l2InSFd&Fz0GIbe6M#dR;4W? zZM~+wHtXrzZ;rM3mRq*vxYwj@W22$*&$1n5JBFrhr)5X=|CM#UW!p~gOS)`tmTlY1 zde)t_xSe%B%k&+PR-dTdTwAAh&boA|dsP2uiU(_BHC=M$k{4&2?YHM<*=4?ET4!my z)gGJo*fQnd&PnIVy!QQ{&#C$4^YV=Po9~}@ZlXHmGOesFUsgx0T%O#x%ugM8sVA2^ z$^CNYvb)4ZOydTmg!O!s8e~cl}wo2Wv$QSuJ>jAz8lN5?@H6z zmVDcr<7%0$>bRFx_dDl!=9lxi>RnvLhh0mn(ylLQ*Oj#P;#|w}UAsNs|vGv>YZ~UYmWay0$#m zemm~vJ-YXKu5+#%FJ>v^WjweH$>%D3K3=X*5I%lF!RKj%B!^F7z{GhMdX<5l-F zul0VU=BDrCx_Mll@4U|Qo{#6``SqDL?Q`$(y0qoGcDmlW2AAu0)$x2Uy8invl{cj2 zlBTQ9m3LO9<)&r2EW5nEJjQv;bB^0i$0wcRU*>y{O?&S%opaN<>)dv(rSo0xGnwgp zem&oFeSiDz&i8h%7x}KE<@%fFn_s@e%j1??moCfqc$S~zo8xZ2*Ly7OIjQ5`_e?t{ zO?$1!O*@CnIqh-NmYZp>HSIgpXW6vRxyRD^Q-2;eKg-LvomJ^9yXyM7bF0>3&vm^v z?ON{fsj-w!V6+?t8Y^GEHas`JDQUn|2-aSlV;eR@a+! z-P&EQ<8|fc`_gwvIyq(LXPK??tuwi6nQxh*i%y zuE#CEYTo;N=Cziesp~B(ozGal&%SA|w@%yd@vO6*_i%Da`;c~hcKuq<%XRMk=$dc3 zZtb@n>1=D3cfRH3x}W2cU*2QK+H##E>F)kIpH2I$`plPU*OGMAT3dH+)|>fRey;yr zy#vc}?dsTlt@~{?XLD{l-<|(mrG2(t16>DQJC(Pq(w5m(y4|{S-E~}Z{q@`&tLsIt z&wK9Lob$J8zLaadWgXANv+47jYeU}ouE|x;uh&-9pKD9L?X~QxRGC%vR*h>_{pGps z^f~LapH*X6b#ANn*R?g)2HSN0V zI$y5wc`Uz9PV^n>JJqy2vo4)7pzr%UC*Si;mpa}&o<0lbTW7YpZY=B0_gF zcV3$I`b>MRbJ{s?+Gip4eEREkY0ow7bL@Mz)$?!J-A&t^YX>C1e} zEYnqOEP10oy`I@@=neNtg9{t!3LrpSiT> zl(bVf_MSTLO?!SjY3ua4tV>&NrmM<&&P(3tao2!!Ro(5L>ljwu->Ugp zRnED#BW)S=*Uf#;&puY=TTa?_F;nMP)mxrZ&TrOTwT9H|_-8uX+u71D{_VAvHwWwH zzw^|xyGmPrrn64_-YT8tm-*KF#oesVwVbqVbWA;N87(a5c^%DJj=i=0)bFJ*E{wzCXz^?MM-gffFvFiTjz0Q2cJ?ogK z&ROSvroFbSv~~Ji%LhIFzmXb4*U;>*W7#Tg`QFE_?zh)lex|+Fbh#FLyj41%(W?Ab zbzNIkr_X-y>SW!kpq`E_kGIdI(&e>v$F0-;mT9lAYja+ob^BaarL){JKigZCUzXqMxb@fF`|^C}v~#?? zK9AeBbdI6tXW8c4eveyr*+%EA?Y5kH@~z+FUT^u`P1|2NVDd)KHEr2dY0J#|>+&tz zbX9xK_4@9l>)P7gc~O4dZ#!+xy7QT>%FnX1?Vg`?x;~fbETi5$mY?NU$)jFh)>|Gc z*ZSqS9!r<)^d45FZM${Wr7b62Rc7|T%rDE&wwiC5W!-r{Ez>$p=Y92D%g**XSJHWY zRUfPBw@$A$ZJ*1u*QKr7wAWh4J{ji$)^gHWf40#wyVF+dtV&n4Gs`W< zF^`p-_4`~_rL&xT`&gcLygR?SM&v6aD?jJ)^8Hv>xAIoHmHcnH_R-^}+o{{K%XHRV z=f|IQI)-)WEW0Y-ddoTKaj$QcwrtZ~J;#w0UttUvoSo_Q?a@~yv2 zdwr(s+L&dQ`DLBicgxPcd#-8gFXwc5Pc6Tlv~6ycuIjJnX1!&9TiuJYzv|zz|5bf- z+`F50tm@7DJns2rx~i|`yS6N&jpaGVTh*KW&bjFM+1_lY=ap-{`RtbYmYMTA&n?R@ zk6X6m>alc|oqY7G;K|v~cJp&QGe7J1KBS$?WxAa*tuvp^x_ssQs_Sh>I{TgZS!Pv! z*>3x5Iyp?f=a==i)An}itZHYToA$tz!#(dVz&+Dfq-+q?qY^!}q=i1xd z{A}k}k)LB+mEYYye%1H0YE0|SZD*|O>TdV^R?k=)%P}nHV_u(qF57iHuWyxK)}3pA zUR$7Z@G2psy?=JZnmfV zJeJ>88_V)N-l|^9{IcnCp5{9|^UHGc*cj&VFO#2r%CBo{S#Ei}thcLqT9#iPFYEu` zcs8@o*)V4kA$uIj@-rMr}^0;j*+nvYr-sbsbTifk>wsC6m%YN4#uX?7+ zo|@lQeJt;L9xvFF&tJXSvpuuIguAU*=~!yPIFOweEP??yCD)b#7U2UHiK_zielD zysrMLxm=!GS9jURs^eLAwmap@I@zZDc7MC-TRZFepXb|O+gm=fo|m@lR&6iubE|t@ zb-(SW{mwpTzsr7>{_q|z%dNWiWgpAqS!Z2-+0XKLUA<*r^H`nj{yJZ$Hl6*f8|(6X z>-;MEY+JjNp4xs}Z+H6IowD0`ZXLrfo30yI$IxfCuG~ET%Z_E%pY3)GyGm!B=4YGB ze9LSn-BsWJUtV7~e)qfT+IHt*t9#l`yGt(E>UcS(9@v44)nZ9Pf&CmX}lW)D5E;(m;+_JO%b@yh@m%mw0zU|FapN`x2yw?0|XW7TD zj%VFvUi*ISr^m~3|9?K-)&1}4`d0VWx?7d`Rb6Xe+f7&XJD=lL`BinDTi5sQ$P;bM z_Lt-6I^R_~>&^DIo1gW!lizN;Ew`@C-MKGq%-@{uY!Gcl_(p&cUkd?Q1*t_Q(%f8x= zwC~?c>(^*HugSN5+nx8e)f~7sf34s4Wqt9p>Fj%}{H$|o z@>{jNyw>*TnB{vfGhLQ(-1^dG+m8E8S6!QRSGC=9E!Q^MrgYW2(Q~t0>$a`7EuHtc zDnHAr-?pT)k5&0uR(^MW%et%D@3~oa*~c9JcJi}++igEvr7bI+zuD)i`CWBx)@fU_ z{pC33wU(E*omG9TJJ&kW*_Qn5XLs_;b{x-smicvKTb^ImYd@>TwwyD^tID;FrprE7 z9k*=LRqd`i*YZtg+sk`h9?!C^-*oo1>b{rv-g>jm?c`hU)TGPym-n|kp5^toJNMY} zwT-sD&iJ$FQrkb=LJY z`(5_gy0ec}_cqVXvaP?}zB`s#zHQ8QXMfGl>#fsv+U~lv<)q8sY0g%rUi}b!q!=I@@TwGo9C4r)~FM z`<%CvwvIO1Ui)ajz0amS-?ZghU)nKA+s9VvEZ_WWZ|2+IcGA{UcHM7PJH5B2z4ujV z%SdNi?XUOKblp7k`b^u#R_QFiY%&T_3Q z_0xX)>p14K=sUSgXPMTMwymaf{PMkrrpxP&TX&|jkLKs~w$pZ-&ih@LZ&_*ESvQW^ zXY;Ky+i72O?w8MH9?x>kw~eN={q{N2j%Qcttke8#dsV*Wmg%~_`ixektLiM#d`H+gsJw@|?2$wT;>C>~H30nbvDN>-z8cQ`=|z z*LQzg^*Loh^Yi{Y9&NO}-dFpYX|J_^_1cDZ^-+0L-F@nr^IXeyO>|D?ING=Oaq5^e z-*>fTJI1!N9OJzIWxn^)v8da2)}_kyH|sCkp2xGCx^25-@4fWimT9jqpMyU73_9=g z|3I1fb-I4Xqiy}P?>Xnq_nLCs8B6HM|4bong0rq-pNS=XAnerAJR;V_A-Q-5fhVe{E;>vmDEI=eKRmboMp#vyA-gf2;hm-fVL_`B{HmKkk3swOM~V z{k6=jw`_Yk->dp>{kA9F>KQMu&3bKXrpqxoUiF*ptjn*ex2pYB=VsluKkucotMYVJ z+A`AC)mGcq@0|0wzL)t~uH$Vx(vESv>8!im{C3-Jx!G>VywyF=d+ge48*Q`mD4p}W zD&MlL+qOEE+23-$9nb5n(>B^>`u;GZ z=RkeG@<^cHZYY=(W~4HS;p(W~*nS?e-&W-@8g@9r^yu zmtXI{^YQ<%cPH?kj`jb?=gi1jw5Mb*AtjVG`@U1Q2!kxi7P6H!S|ufwvP;&IEKxDG zN{i4!$*wHPTC&cZ|ND97e15L(-#Ig9R6ooA`+YqgbMM!6-Pe8HpY^)W4E5})&)Q|3 zU)N78?O9z~^-ivR?eV&%ZKw8D*|n@Xr({{z*0TCxB+I(Sa!Tr~bKC3N`r7-oK3rea zd39~K9rY~g`E#k?o zKIc~MRr{(>yY;vAwi>YZx9xCk)nDbRzgu^^UF~yz{glyd$54GxZRqw#+ZWXyWw&jr zdTUw7+IG0c_4TWA+qPBzYhSGow`{K;$$Hh>U24}ze%RAo7Y|pD}tGsUALp`55r>?0os@%5DcKlB2T~d~E+xqH#sbzc2x%E?j zx9)DewXJP+uIt)*tDg2cwn7)jk# zf7|a>N4IXn*Fy$t~M!hFh9$9?RflD_9qlpe?XSve+f?-owQSFC%jwoJsqOZjrDu1|TombaZc~yRU zkJibIc3+)W*9}#7>5ie6)vmT3%Bpg!PW4v2s=F*X=3LkLRXdbl^_G4s`^vKRIj3!l z>y^{CqixGj{os5*_flmkR~>DgZM?YJP;GRb>)ZOf^|trl-uu6M|J4U={qCpR2kL35 zd}3LET^5-&J4rRaaAsa z%(;Hm50=U*s*a(Sbxtj-jEN=w?|<8Rt#^NQecOg^y>;*1W%s;llV$zd`l>DV)%xVx z)V52x-8$Rt?pUc~ZM)jGDZ6c7cYUa~Ij8Qemfi9v)y|>L?Y61Pwd}TOO19f_+V$bu zFuDD08AGiP*S31rj*p~I+ji75tmUM}U|m;jtM*j=^)60oS?9X8%Bga-p{>6wC+b+W zwXRc6+m^Qel2hGfozu2wxHeUN!;OE(+qQJuQ*~6G-DMrOY=6~1mQ}uGwWnRS$E~-& zwoL17eeHVpJlkzK)~lX&z4q0zdri08w$4edcdu*9t-40CY_DtAyX6npmhO4&c3WPp zkEBh`nbO}#%k7@mt*34OaO>S`YP(x@ZMS1_sP#IpyR33+Ib3@tx4*8hWw)Lw*{(8% zTTZSmLmeNktZG*s?{3%r$t~46xpSV&@uBWzsC^?TyY8)BPVTy)>Ke(u$(1{jmS_IJx~@7a3$j&zT;+ud?(PpaObj&;ju%Wv05+9uZw^&6`0?!KX}t9@--rewXY zZiBbQ zLtEyQmf`tM={5hU^M@N-LzUm&<4D)L<+SycY#eUco@>1=t6P67kGkvKbK7#-I)-b< zQ2X2K+VX0>TW5E>&g(AgKHKt#Tkl@`-`uV?sH4^`+d8}3?Xh;f+ZR)^-Ig=ldfUF? z)`z>cyMH8YbB*(+^jB?jU9JB+%PFmYO3xo@+a^`+NcwZQb0$@89UDm->)hd%RsV3u zU#$CUjMnl$bsyDV!!5h@OiBGiJbhEvq>Q%yDOn$` z?6$urw?0%EQ__a+xkHs_U)zrEcK6tDW&9`hck61mt^X(Ln9?$yk9w=lT25)3|5N9y zzy1BE%6%b}gSOxpG)~8xn@#zkL3F2 zdd{Tkb?o{0wQYJn>hIOr>w)Lm10&JFlR9Ul^-jsVslFinUW?fW^B^`Xj` z)V^xRq|WIb>-9j}15@%owAa1V*S$+G^?Q6F++SA?K3{FBc2xb{?b`ohS$4bw#Vm^m?Gz1HB%2A@#uX6&o%;;rXin zh4c)1ZJB%zbZzaj!zZ_#e965tdOh&c=z*bR>Wf9bcHi%p#uMq?MXv{XJ<#ic|JxpT zvB>=Y+g|C_*6V>@5A=GV*8{yC==DIa2YNlw>w#Vm^m?Gz1HB&T^+2x&dOgtVfnE>v zdfpw|Oa)&o76K4tyYJG<8d zy&mZGK(7aSJ<#icUJvwopw|Oa(gW=6|29+7p5D3ty9avlhyUFty*<4i==DIa2YNlw z>wzilfwFg|h-{L?SY|UP($r|uI2Zx>-E5Ys|R}e;=k3iFYR*w8}hBntmTyU z;B&ohO6%#J|NQho<@icwwcEq3YiWC|ZF#%DyWXDHTYu^H0GZ+UVz@(NwD;@vK(7aS zJ<#icUJvwopw|Pv9_aNzuLpWP(CdL-5A=GV*8{yC==DIa2YNlw>w#Vm^m?Gz1HB&T z^+2x&dOgtVfnE>vdZ5<>y&mZGK(7a0Iz7^MWYj4>D)jrFi<_!;ZUR^WXu}ST(Yil{&xpn;cTn_il?Dy-oZK!?Sb9&n^oE{i> zh(kQb7fuVG|CV?^U#P#K+BTd#nUZt=o%^l&yY+SVcejVDb10co-_2?+qFKaWqVz%54Rku&T3!xnxW3Eb0*cEI_BJ3 zx9tA9`?~d2yW0Ij?Ne@hPPfk59zAOGzqF_JciYi!xAoQfg#L-twq?7o?z8q=*1m3A z+x^}4wA*c)YJYoecU_&s{j}Au+R|=UJ#}qcS6yRY^<{hBm{DT}_E))<&O^JeuCIN{ zsC|~Ut4+4io@>4KRlm3UhPuAacWh#b|N5`%{o1_~_e}h^_S;g1W$m-{tNqnC?LOZ|Q2XlKI@Y$)K0oKwy-nQnug|o~sPk&9 z)U|EjSZ{yMspni}+aBLg$7{c3_qu9>{nqO~w7c4FscqFh%c%ybeM4Q>mOW5$^N)5u zGl=zSt9?%g%eK9BPPMTu+j`r^>MLz~S;HtNXBYy>hB-$NlupQ$c$McH|%H_SOEXr}n$Xxpm)FuJiN}s_m9j zhiO9foqf)+zsjgO9J8)W_4%pGw)S|Q_S>%K+wODB{-xOir;P5o>S*^nUhTA;Sn9<3C*I+|j(_{yPqkH9)@#3Q zW!R@LoLl>*9N~j&%U;;0|z_*3{*b&k3-de+ST@{cGy>aSpDB_S6QxeTzTr( zF59qP?Q*{B{oDuq>U#Ta*L~TK`qg%ot$o!-`y97jW5IRytFxYo?e#lKpVlO-^gR0IN6Rz>oj=GmR=GxkC zUzJsDR@TIpKKo9qTN|qnZC4xZt9!9t?_-tWJo~HN+U0uN>eSEG4#%vQ%+faPsr~g# zTwi54ZoTTMr8?2wu6^3Fbx-cYudc0gt8eZ1vt8#_-BpHT z&Z)k%->=TAw%D$FvaIv%uVeQ4Rhjl{pT32k&bRSAFi@th=vzkL#Fibnm}pY4vfH ztv>tePO5Enp6%)@=h$|w@~f{cl}~3s5iF}6kM}>`|Ic8*bKsa|-A65zTkTPQ{jBT5 zdLOH;?bxx;PZ@Px^-Nd&MBuo#!6tqFPsm zHmjrhQ@!ff4(d=1uQ~j#l)#iu$AMSs!;eq~VvEOm`;e7Yu+PW9_QTI@N zt^caOwM+ZlkG5%}dxHJ8-LE#grfs)2>t}6NpZcq<_xIo5|JOn8?Z3DG?(pYeY5Trl z=^S_CI&JsN>KQ0s|7dUZy>@DocDH@6uRR0%9Cw~}dtRh(<9 zvFLu#?$btNqQ-@BqA!(IZT2kd{nGa8N6Q*_mbHIkZ%-T(uG79+Dy#hsR5JLFI$N}( z(1*~z7Wb;{HGXT|eZhWMulufj6YqNBwf5;VA z{SLKkk6Um1QNLC{>+AM?tmjnE$8tD4JJ&0(P*2s}K7;D3TGrU9w!6=^E$VFL9646{ zyL}JZea`Woz?iT0xmWE|hc;=0=ULCami5eQ+jDlFwpJf1OMe-|SIX8$>g!VNsdvb-`=050@}_J(avQeERg~VR2TB)^rA5hB+t$k-aBh38b>)_P ztM|G3s-AT{=hC&FiRVrJdS3O+JpZC(Zfk?-Ge6HjUl?ENE`6b$?8P^RS;CvctYNk= z`ykd~zjN@W@PfUPn>TmVd7-*lF^%@7p0&EwK*ZXV<{iM8lj`dvYzDno1 z$9j(S47IKH)q3|i)L2$ewND><9>!z6d##DRPtaaDAZ*<4JzCrbK_3y-^=3)YI{9n_gH;ZeQBvLhU%~C>$=X; zI3W{^LuF62%qGf)8ejUynA0B1>MzHKYg^fC)fUg5e64X;?_T?U8D}Nq$N>x|_nd2- z)|fR0OI8?z#%QFD)aOL%LrENs`l_I&Hgm}8K3-9FoB%bjP`Jfr3f^M?h(f?=WX z?yy)`Dl8M03oC|I!fP~f zc{jWh#=LitZ18^G9_n4cq5p>d>%*_YFT&5lmEqFx!*F5ve)w)UGkiOo5>5=qhOdXC z!%^YL@P+WX@Yz8=-T&$S!@{A#vR(gF|EF?vBF_JOI3j#0d^srdYvG&W_@K^jh10`X zL7UDE=Z7DJABW4r<>89(({OcgU%w33gzLh!!P0&Iw!t=j(@^KT_SeBuUnvjDR!8yk z{+|!@p?c48B|2+fu;C{vp@}vGA^Q{u+o8S{jPW0d*r?LPJ7q9bL#}}v3GOJ zux;2W>=8a54hf$LM}}j2!7oyU2JX_q@m6G4B*vLarI#WYPX%xA38`QCK~^H!K+D z3a<;(h6(xoJ=_~^4ZjP&3|ED5;o@*!_+I#K_)a)0oE>bR8!iYx3Ri@mhwH*k;m_fr z@Kl((f9n2MhuOm0!{TA3uzuJw>=gD6-di&C8-YCdPVjD$=OhjJMdtk>&;fJ-+pYZK z)_!dLXXofQ*RTOy|NB5*lBccyAj8N3bzTz4t&0P>bwMDn$u6>+?9lhxNsf^xM}hPlHV!%ShSpilMfU&5cl_2KH^ znf)M~6HX5&g>QzhhA)RB!r|fb;d9}$!SV~?$Z%BndN?ke63z^sv2k#DFgAW4j1^tlT%8#umu-|l_82G@N! zY#X);TZ9jWO~QuZePO+@PFORn7FG|ItA+vkRJ!r9^U;JV|(*TRwEv*D1SPj(6J zSG%-xrLaU;Aj}qC6=>-?5_S*!g#E*z!Mp2yJ~5mT z&JSeowSg?~UOpaP*8j5p*9Nj<;h??V$FYID`9xqFv9-(nf8~!f;k&Qzy z@t^oG^M!W>e#+9pdsz0&>Z2w?2bN#qdGIUvGoH&Lfga>P(0%kC8;ZW8>-e_(a(a$U zN)D5^WQJ#=-3Nr-1G)Kuuy$~d?+NnZ)pPevxNksqkzr(+e!D2t^EqL{2?Kpg z9)2?D^S#5aVf(OU*feYq)(NYH6~fYC$?%@AU|1l`ALb2j33G+HgC*t+mTwKtd3$(g zSR^bFmJ6!}b!-&23dV%7a!??{j|ry*`uEB}2iy@J4SoH6{jUn-@j_vR;Ms2-J{s7{ zUkt|uz6cwF-YXeQpNegf!Td7*xOa#D#+UQF_;%$_TawSHn4{bM`x z^(s!U9?zX^ZE2ei$o8rDg*GUMudjaNrpDsJqZS^uWZ);S71&|?-tEF}Vc)=RJ3Jg6 z$d7LawkR8vE@1zWGi*-!;J(0aWLFxP(}WoVy)bKdOL%)&BrFwH2xKsMO@5CJWII_) z{*!;74_^t#1#*?_yd?ZA{3hHQ{u=%n#*7{_`c+}J@b<7oST$@Ewh6n3L&BHB@!{<7 zqww=^L%1tE6rK!IjhSl9E5d8TEMcxNPk39HH(0(U%n{xcULB?l<42DlDC73gw~xLy z{5YH*jtcvSZNr*jq40+Abl=l`w}mSMJ@AF#{^?6He)d4N)3v_~Y=6&zZ^PI5a3I6^ zMPd(hy|Lw)iwzkQ>|izmTdw3bxkYaC_1Ry1ZMHC5i?6tEAoI2g8-_K)(t)iqdtjT6 z3G5kmEBWw~aAEL{v5DA8A`OV zwkx^#sc>Lu<@Od6wiuA3Yfo5v!b;)2!LuQE$>BGKSB2?AUwCT#Q{(>;9t`(|KZo1H zt>Kn%^B~sm2#((yod3@dGhqD7CcJFIj6vD+1hRekK&EdV==%c#UBlkyTe08iaectP zAJsoD&hTs-^3o_=j{{pyJ(d7mGL2VBDTfv@Gj7s*6r)YyId#6bzoo@ z>=)SUo+Ev+Yw-T?)39@}ZNKAeBW-YPwS(QHz7qm}h)uIG(L9>9}5SC&xfyulfv17ZFofxKlnqqGw}JJ4pa9{-S_Iiz9h333+zrd z@|J-ePDXzwd^MaL*tD02Ux%B+{o$!F{pjgO&m7(s77Z(gb;1Y3j$!Zc$?(PSjqt7T zy+Af!6|M>7^R3~Y@Id%Scslfr=^HamczJkbAg^B^W)9@`n+LJ}#$f;J!mEO7rVjn1 z`$s-rwn$#*fut%Cf(MuCsSZx-ig z!?VTNQtAJWUuCo*w`7fV_TW{3GN47VZgT`JLgmK)!>#|5LC|58M_068;(<4rKl_VX6sJ zO?X96&+LH@K+h}_)(qOXb>L692k{ra+{wZH8lT3}Z-W>Mf5lkxo2Gx7f$_xG)ThS2 z*w7+@eW1_T`Qk3Cg*5}+%Wh!%(-{z75)<5{VblIi`#%`A2%aN9fvrKmd?b+bbb&ET zN6;0S z!(w6iuzFZOY!b$X9m1|*ufX;t<3AgY3||Y!g;T;A;hbt_P_Plit)W(?#yTl_VFE+FeI?RVUHt;}cdD_0%A4wr@R2kk1EztiZQMt>lz z92N|3415iJqJJ(8-wt04Wd7Kof5pJ~J^Ubkk^I0%{J&xAw6LBadT9v5q2I~Mk_`<>%l?<`qFCW#l&Bka*120lZ@zuB^U zaW)*;Cw@CmAQ#=kx?%I+{USrjQt#98fs7SrmOm4h;^**p=uELuwmu)3Z%kI}*EU}+ zcfeM+-_N_pZg-v7irBcgmpHiiw`VXeu+P|O^swikJz~|~dG;V(yiFi4$P{vB*+Blh zE4V+ls#q}JMcm(W`Db__(8-=n#b3mf#g_G-e)MeE@%or;yk`*iAm8~-WIJDqfAzLN zroS?fyKHu{`0hYf|2F(GTp4~8E(qs@Gs9`&lyFiwaS-d@3XYu>z85YGmxP~$Yr`J{ z{qRsA@28tE-GtW%F&?@`+=dR~Z_rKRd+tT7Mm(PHaz)_R=!cT;f-J@`JLb*dErHEI zwzK)gwa9gTt8qh)ZyeYXWH!InbK!H*#hw$tfXw#Xyhn0E;+V#n9Fh1BU!axWp1nAr zc$=8KJSaQ;_Q2;eevBn!O)N;RldW!E0DoPK&wK*0c=iTaAP#?UsMyPi$zQS)<^SaU z#Ng%N?g-?&xbIYbQ}w+vkT+y}+3V}~tv?VW->Gk>zWqYk>*CGq^>N{v@TYKJ_(x!* zlJRd2Z1zRMazWfeEQM_UaM&{(5Iz&g%CCo$!dcJ2p;n*1#8_2VNG$ zc=!=~3UdF_@SSjMpriOCVn*wRCBr;HY>7Yf=WuPfIMA13RCK7E!772R|E7>`?2{+< ztl0YUy7V+#f4jh@6oV7f6|W(0*s*L!IW#^Xc_MCWjIuwBY4J%igNzglU>C9p#m>o8 za{KteE@%7g6~xHJMA=ho2eFl<0$WQQmCfg!oGrX5%pBej*k!K`mfl;|2Ov}4 z5tO4m<*pSr3}jHnU=N;f@PPi1Tk~Fv6Nyo>=iWnXze`O1d} za+dAnz2h5`$8wZpG`mTRly5BdDF(womd{{A@d?D@>DWTN#+(Cr5AWt2!Fwt$#J{E+ z#9!%Qy5O!LmZRRX@y|>ilOCdn`SbjHvc)qagUBTMm#iY^$uIE=aSL&1GVc394w0@E zlc7&P96lI4vt4>92<)!)L=M!~S9Kut(T6 z>=Zs6w(qdR_#MXY7>p!>EGNg!fg!)e zSB?wxwK%@`=S6`or_(E6-p*rTdl^@rzxX=)pknJ}y7^jSuEvdb*?8i2*4z~`UQEXO z&X*Kt7gIE6MQnyV_*D2}Fkj_c!MqP~b~!wARLoBiUzcwsS7r)gGjf3J`BlS4L7q@P z_29rBl~a^s{9*Wc5Tp1@_kr%DW6jD;;O{xWBnH@q{vJ1iNN4J(G#0-3&E*dS~aJ`gqwA8goS z%obxd5B6;uHVGSs_XYBQ^{`SX*}veJ1qb5xvyGW;z!#Wq%yeV;4fM}ng1C}<_(3== zd^H>z-1ioNPxGEIN0=@=()UQ;P2tLLR*?TKn_sTm^LS05lWz@I2D+Qv-#d8r@_xpM ze2?)&=8FrnU&#=DqB#y@gZKy8F>f&D*@xbPyTc8G`BMJ>Ie|~iH|F!pm9opdTm1cs z=dL$ly@8mzm@Xf?V(?|Z8S?1%1S@AGfWZ96fDpNs#HzicjcIl0W%7l+ZW zbO8UE45tUYr)>^SKFoVdKghw6_ul6jg7;e+&O3L%a8USkI3gS! zjtk!oY<)gL+4=kju^_rgK0wS!o7o5Cz41ogZyDJ6d_;L1XV(jm z%n-z0*xhB*FFa=90lCkfC#Tu#Y=m{O zYlL@)*@IY{d6c&Yb3o-;%%h^;#e3NPp8GO^4QhOlH+)5YBfHXEy0ZgY*I1Qbl1F0O zkc(oM;~f z7>DPk-}Is9rEkUE$jqGrT~3d)p%)G2!|>V2+|l8miLKus#NB@%#B}J09|ku1>EYx+ zmVYgLDbN*s1G4_Gz`j2u92_id+yANH9JW85@Z~@+d?OqmP6^7Vi})WG1-{5t;TPe$ zpiT6JoB_W@Y>3_vkD@!|8r%!NlMb0PxJUMh`xVckPu2)@iupxb2fmWI2F9-OY;22- ziILHujSmh-1o0C7z=ff7f&3{sOBaZ(+m*5MC1u2_u5Jy@pEE4zybi~|2%t`D?Y>0m#r$C4C z5$+4Oh2IA{o7_xp8M<(Cp+ad1I zF0DI93~TeiKBWtkr(7`$b@6xDv)Vy7@Pp((=m&XBIRUvEIzpcFcftL$nc2?t1RqNb z<-o8c_lqTw^W;6< z@s&Ua&>`YWu#VCV&U3yvQR#>_XK?=b^T%Ht#szxf=i%BQhICU9N4h6G5VZBlAnsLq zLTr+r5RY_!eAISMsQdzditnLM=m_@A!GVr2znJY}tQp(J*yYXKed9{M>wn{kALqGv zXXG8;89X~VDmvacF*eLukWXmiPv&Zz9M}x!g-Zf^f)9IRlQ;N#=6moX*oFL8eyh3s zr7M=rJOp`QbI;84`Eb}X92h|*kboHN%_tVHgY4ZTnJbdcvgHOQ%woqUCx!@WVAh^!SO zB7f-yaewletX?6o?a6d9p8dad*e>iCb_pL1dxVdLy~93Xzd`mL^DK_-74{6fhuy-? zK{?xpZ2~_-T#25cOZX)fPvWoeE%+~Q5Aq58i#G(iZJI!MJ|5^j`p1b1-02bXc8v-1d5shEe76tclHyVe1-itTW2>-<+0Xpm3j^O+4$NF5HW1lI zmKpnOcXQ|E2 z;>c`6c}y|z=>l0Wb&%H_6WGC)<`mlRIC&=y&9;1XAUBjHCpt$En>G)f{9tFA^T@_t zJ+QaQ5b-T@S+$ppWs|!HdQ85BE<7QaXK8*SeMxW9SNtIHY;n6=0$+&j$sb~WJ{kP@ z17r+al+Ge+^eI0H;vk^M#00IgSzi@=@8lZS`tC`d;i>RgkZ zFFhg#?_TI{_a}xZrngzp4=V-oRo=)vA$=$|rN5sT|HMGdUwn$}X7B$j&?Og!?*zF5 zzQo!je@bNU--m)Gd@}y$NEL)QRriH z8t9Fh(=bc_ECc#|@#qV=JoyUmkT?~e(Hu~|1pUB|;Kzz>vgza>=mYbClkneq!*Rj|=8^${)x@vMHzSo3`)u!F>FM!ZLx}Fdyhc!FO4{bMlRoIYGw< zeuBC8KMwSO{3n0m_8@QkXpkEno!|69u9R*NH|Il`CnS!(RFGq!E96!;4CaAu9X=d( z4Ic~SA|Hc{{6a8){+J;4^zC5ozPXv=_Lqb!137EX{qF)FgxxMCCErXYi~q3eYu*sQ zguPGykm2SH(L?+c`3imk8BZ_G75EC`SVQ5MbL2RjKYMV!a?CrWC(K1shq}}$@2w4D zW%4C_CG%Pz4)Q4Gy2_W!t;kczv+zO8iFMEBOMN%UTj&?L3w`y;p#OFY+lEbpSe}^H zVqyLu=To}n;l76lbjx*p*A2`E;F}y9#JBbi#>Bc|$?&%D>R?Wp?~AVu@>Hh;`ecv5 zcU>`vZ5gZV7;zW5H96bk1HYLsvPqyj*x=+DTb=#x-QjbHTal;c9+_`M?p8ij{(^4k z%Am)`KRzIX?#{fH+k-gyZ^EyF+$7spJcPaZ<3J8TJiCR=x;$JNej3=N%BUEIa&HND z4#qL$IxCJ5)j6KtAs6Wyxpa2796KE&Utap9;uz#>=@#>N+%Fl-HzHq3udq>lvpO!w zA($J(2NFBFGm!Cg3b{iEvsuX>dWBx*PwkEN@ z!*7vSIXlo{mj$sbxpvQA49j!(%x9P|!+>4ERuQiw>{<{+3_@OEo*<6IM_4h4Q*0R6n`DD;0d^0*2RJYs7RU~^ zsc*NA333nS%J3!52xQE;fnOp1M6Za8Tp4`ZCC=_U0^fL-3HnF(8 zd8uq>TKw147MbqHj(KbPZWs`R?mR zUpM*>;r2kcn2-8YAjjnz$apfJ4&W#77ZwVOh9#Svx7ZZ_M&6pQA#TOjkqd!!*zdTQ zmiU-B*@{ENw8YfJwCEwar+gE7hM%R4bf7u3cLjQdfAWiPd7w+_6ZdQ`m-wEX4_{9I zj16Lds|ItT%13$S=vQVYLEk`b-1Dgz*E#vV*>g8PYM)?k!u!Iq!8avu2rd-2^!{ackc$p1dpjmb?~QC&T#;?82wVKRy1j@Nl?4&@*?1+Xm;qi*3^lH-_Ig zh-cKcIE&-#PUn(+w+8x3S?p&r@vlMLLtW&gdc{AU3FM9T@NxJ+d?7v&--u0KevNyW zHx+Yeex)z?mExd$HgQ=xnSPc( zqBHn_a%t=-u}m>c@hEXfu_*6J`532X4jrHVif~=HIouom5xi&h9nIYN&gGq9iLg>w zH~5C8%~|t1*ni^F^{p`fZg!XSuL);HQuw8wdJl>#)P%-)Im=Cua@_z8yB#)!%6Na**pFi%t%FneT@4!^L4- z;M14~`@3K+?47}P#a+MVHKSiMU^~x~`Ji-)xEH&cJ`wxk$LtjL4)Owr2eS0!K#!2I z@+7`(kcVd9lgDCVj9;>v{_ssPIZk(ohtV6$ht&doAwDG!A||$F5Et7v><~U2#I*|B z_KTZ2Z;N1Fm7EFvLZ`^Zw{xcCXy_36^BDsDA+}}C?43c|eIqBPM>keJ#J3%EhWr0W z*dq8QWTim=mhVAF6aJ6&JvI*hJ>(v60wH59Pc4TZ4R^obDMxoYp)MIcG6_xj*?5 z`M|k@cnh0ZT!n7oukiUV32b8e#he~;QC?lFXoujvHZPwX6O*TB*ok6K`~z~E3@6VS zHRJ`EPmYlxbOW1{-e7-W%9_T;1lg<-= zq36Vr=r_8JUZa2YjXomp`4N0SJ_TK%FINuwRlHvxi`U72=<~5*o4_aW9OyK2qRmC3 z+vpoUOYzYOAN`+o`y6+k^T7|TzdJ%sD^qTPzNE9%MSrsS)eZRvx~$NyT5p%mb)7Pl zrA+0kPaCw2UXa7!BhnB2MEaEOl|vK5J2CJt#P!Y(KMMRd<5cWVTvjZQ{&+aBlgzae zJETYCH|7fS2jiYTVOy;o_#$%Q{1JZq-hpoUOpp&hW^ir>`|SJShe1BlJH~dqC75Sn z&eY?9zL_qVFJl=`eNQ)B}Gr=goa@9*AcwobR-j4yy(8rnU(F4h4Nem&lcqMf8WiLBVe^hw7@p zN4YU{<6wLdaWMK~mM~YCFDw+q_m>S~{q%;ozZebsdix+BAfH?@F#ZTz{ODk=5?$hN zO890@-rYQ=ihuD<$mUyv*caU*kNwXuK8(qaj`1xV+0IW9@c|%a}nts-w$jP#D`1oco*dYyrYliJGr}pc~#zNHla9-`~#g+bA`wp zvXEWL=6^>Jn-Gs;E3-u_UiRmFr^OE;lg$|t`(oG9C2Za{Zcpyh1L7nHg^I`2{8BL$ zvH7jS7D3EK>_sf*{bBvEURXD*6V@JNt??7FZNKBrbgrs4x2!HhrP}Ry(y5p?1sM$&Q)N)%hUKV1g8q(a{O1kJjm-{#zE|xA&}Q% zd2&W=3{QE=6;G1;xj)#DgK?pNIp1aU<%Np01Bajsc{Sl0r zd^vn`aNgB-G9Ua0;j(ab_)RcxPu%%|@L2HkEsr_gZ*1mX$)hYC#L3FH**f`@od&

    Test

    " + result = markitdown.convert_stream(io.BytesIO(input_data)) + assert "# Test" in result.text_content + # Test input with leading blank characters input_data = b" \n\n\n

    Test

    " result = markitdown.convert_stream(io.BytesIO(input_data)) assert "# Test" in result.text_content +def test_markitdown_streams() -> None: + markitdown = MarkItDown() + + # Test PDF processing + with open(os.path.join(TEST_FILES_DIR, "test.pdf"), "rb") as f: + result = markitdown.convert(f, file_extension=".pdf") + validate_strings(result, PDF_TEST_STRINGS) + + # Test XLSX processing + with open(os.path.join(TEST_FILES_DIR, "test.xlsx"), "rb") as f: + result = markitdown.convert(f, file_extension=".xlsx") + validate_strings(result, XLSX_TEST_STRINGS) + + # Test XLS processing + with open(os.path.join(TEST_FILES_DIR, "test.xls"), "rb") as f: + result = markitdown.convert(f, file_extension=".xls") + for test_string in XLS_TEST_STRINGS: + text_content = result.text_content.replace("\\", "") + assert test_string in text_content + + # Test DOCX processing + with open(os.path.join(TEST_FILES_DIR, "test.docx"), "rb") as f: + result = markitdown.convert(f, file_extension=".docx") + validate_strings(result, DOCX_TEST_STRINGS) + + # Test DOCX processing, with comments + with open(os.path.join(TEST_FILES_DIR, "test_with_comment.docx"), "rb") as f: + result = markitdown.convert( + f, + file_extension=".docx", + style_map="comment-reference => ", + ) + validate_strings(result, DOCX_COMMENT_TEST_STRINGS) + + # Test DOCX processing, with comments and setting style_map on init + markitdown_with_style_map = MarkItDown(style_map="comment-reference => ") + with open(os.path.join(TEST_FILES_DIR, "test_with_comment.docx"), "rb") as f: + result = markitdown_with_style_map.convert(f, file_extension=".docx") + validate_strings(result, DOCX_COMMENT_TEST_STRINGS) + + # Test PPTX processing + with open(os.path.join(TEST_FILES_DIR, "test.pptx"), "rb") as f: + result = markitdown.convert(f, file_extension=".pptx") + validate_strings(result, PPTX_TEST_STRINGS) + + # Test HTML processing + with open(os.path.join(TEST_FILES_DIR, "test_blog.html"), "rb") as f: + result = markitdown.convert(f, file_extension=".html", url=BLOG_TEST_URL) + validate_strings(result, BLOG_TEST_STRINGS) + + # Test Wikipedia processing + with open(os.path.join(TEST_FILES_DIR, "test_wikipedia.html"), "rb") as f: + result = markitdown.convert(f, file_extension=".html", url=WIKIPEDIA_TEST_URL) + text_content = result.text_content.replace("\\", "") + validate_strings(result, WIKIPEDIA_TEST_STRINGS, WIKIPEDIA_TEST_EXCLUDES) + + # Test Bing processing + with open(os.path.join(TEST_FILES_DIR, "test_serp.html"), "rb") as f: + result = markitdown.convert(f, file_extension=".html", url=SERP_TEST_URL) + text_content = result.text_content.replace("\\", "") + validate_strings(result, SERP_TEST_STRINGS, SERP_TEST_EXCLUDES) + + # Test RSS processing + with open(os.path.join(TEST_FILES_DIR, "test_rss.xml"), "rb") as f: + result = markitdown.convert(f, file_extension=".xml") + text_content = result.text_content.replace("\\", "") + for test_string in RSS_TEST_STRINGS: + assert test_string in text_content + + # Test MSG (Outlook email) processing + with open(os.path.join(TEST_FILES_DIR, "test_outlook_msg.msg"), "rb") as f: + result = markitdown.convert(f, file_extension=".msg") + validate_strings(result, MSG_TEST_STRINGS) + + # Test JSON processing + with open(os.path.join(TEST_FILES_DIR, "test.json"), "rb") as f: + result = markitdown.convert(f, file_extension=".json") + validate_strings(result, JSON_TEST_STRINGS) + + +@pytest.mark.skipif( + skip_remote, + reason="do not run remotely run speech transcription tests", +) +def test_speech_transcription() -> None: + markitdown = MarkItDown() + + # Test WAV files, MP3 and M4A files + for file_name in ["test.wav", "test.mp3", "test.m4a"]: + result = markitdown.convert(os.path.join(TEST_FILES_DIR, file_name)) + result_lower = result.text_content.lower() + assert ( + ("1" in result_lower or "one" in result_lower) + and ("2" in result_lower or "two" in result_lower) + and ("3" in result_lower or "three" in result_lower) + and ("4" in result_lower or "four" in result_lower) + and ("5" in result_lower or "five" in result_lower) + ) + + def test_exceptions() -> None: # Check that an exception is raised when trying to convert an unsupported format markitdown = MarkItDown() @@ -295,17 +520,20 @@ def test_markitdown_exiftool() -> None: # Test the automatic discovery of exiftool throws a warning # and is disabled try: - with catch_warnings(record=True) as w: + warnings.simplefilter("default") + with warnings.catch_warnings(record=True) as w: markitdown = MarkItDown() result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test.jpg")) assert len(w) == 1 assert w[0].category is DeprecationWarning assert result.text_content.strip() == "" finally: - resetwarnings() + warnings.resetwarnings() + + which_exiftool = shutil.which("exiftool") + assert which_exiftool is not None # Test explicitly setting the location of exiftool - which_exiftool = shutil.which("exiftool") markitdown = MarkItDown(exiftool_path=which_exiftool) result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test.jpg")) for key in JPG_TEST_EXIFTOOL: @@ -320,6 +548,12 @@ def test_markitdown_exiftool() -> None: target = f"{key}: {JPG_TEST_EXIFTOOL[key]}" assert target in result.text_content + # Test some other media types + result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test.mp3")) + for key in MP3_TEST_EXIFTOOL: + target = f"{key}: {MP3_TEST_EXIFTOOL[key]}" + assert target in result.text_content + @pytest.mark.skipif( skip_llm, @@ -330,7 +564,6 @@ def test_markitdown_llm() -> None: markitdown = MarkItDown(llm_client=client, llm_model="gpt-4o") result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test_llm.jpg")) - for test_string in LLM_TEST_STRINGS: assert test_string in result.text_content @@ -339,12 +572,24 @@ def test_markitdown_llm() -> None: for test_string in ["red", "circle", "blue", "square"]: assert test_string in result.text_content.lower() + # Images embedded in PPTX files + result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test.pptx")) + # LLM Captions are included + for test_string in LLM_TEST_STRINGS: + assert test_string in result.text_content + # Standard alt text is included + validate_strings(result, PPTX_TEST_STRINGS) + if __name__ == "__main__": """Runs this file's tests from the command line.""" + test_stream_info_operations() + test_stream_info_guesses() test_markitdown_remote() test_markitdown_local() + test_markitdown_streams() + test_speech_transcription() test_exceptions() test_markitdown_exiftool() - # test_markitdown_llm() + test_markitdown_llm() print("All tests passed!") From 70e9f8c3c041e35574dab45c648e655bd363bb75 Mon Sep 17 00:00:00 2001 From: afourney Date: Wed, 5 Mar 2025 21:26:06 -0800 Subject: [PATCH 25/33] Bump version. (#1094) --- packages/markitdown-sample-plugin/pyproject.toml | 2 +- .../src/markitdown_sample_plugin/_plugin.py | 5 ----- packages/markitdown/src/markitdown/__about__.py | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/markitdown-sample-plugin/pyproject.toml b/packages/markitdown-sample-plugin/pyproject.toml index d8668aa..a12b9aa 100644 --- a/packages/markitdown-sample-plugin/pyproject.toml +++ b/packages/markitdown-sample-plugin/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ "Programming Language :: Python :: Implementation :: PyPy", ] dependencies = [ - "markitdown>=0.0.2a2", + "markitdown>=0.2.0a1", "striprtf", ] diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py index 1362818..1ca00cc 100644 --- a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py @@ -36,11 +36,6 @@ class RtfConverter(DocumentConverter): Converts an RTF file to in the simplest possible way. """ - def __init__( - self, priority: float = DocumentConverter.PRIORITY_SPECIFIC_FILE_FORMAT - ): - super().__init__(priority=priority) - def accepts( self, file_stream: BinaryIO, diff --git a/packages/markitdown/src/markitdown/__about__.py b/packages/markitdown/src/markitdown/__about__.py index 4ebb498..ca1bba5 100644 --- a/packages/markitdown/src/markitdown/__about__.py +++ b/packages/markitdown/src/markitdown/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.0.2a2" +__version__ = "0.2.0a1" From 784c293579fc72203cdfabeeb6b54139fd22a89d Mon Sep 17 00:00:00 2001 From: Adam Fourney Date: Wed, 5 Mar 2025 21:55:20 -0800 Subject: [PATCH 26/33] Bump plugin version. --- .../src/markitdown_sample_plugin/__about__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py index a365900..ca1bba5 100644 --- a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.0.1a3" +__version__ = "0.2.0a1" From 9380112892770f61402e4b539749e0fea03b985e Mon Sep 17 00:00:00 2001 From: afourney Date: Wed, 5 Mar 2025 22:24:08 -0800 Subject: [PATCH 27/33] Fixed loading of plugins. (#1096) --- packages/markitdown-sample-plugin/pyproject.toml | 2 +- .../src/markitdown_sample_plugin/__about__.py | 2 +- packages/markitdown/src/markitdown/__about__.py | 2 +- packages/markitdown/src/markitdown/_markitdown.py | 8 +++++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/markitdown-sample-plugin/pyproject.toml b/packages/markitdown-sample-plugin/pyproject.toml index a12b9aa..400cc4f 100644 --- a/packages/markitdown-sample-plugin/pyproject.toml +++ b/packages/markitdown-sample-plugin/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ "Programming Language :: Python :: Implementation :: PyPy", ] dependencies = [ - "markitdown>=0.2.0a1", + "markitdown>=0.2.0a2", "striprtf", ] diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py index ca1bba5..f691daf 100644 --- a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.2.0a1" +__version__ = "0.2.0a2" diff --git a/packages/markitdown/src/markitdown/__about__.py b/packages/markitdown/src/markitdown/__about__.py index ca1bba5..f691daf 100644 --- a/packages/markitdown/src/markitdown/__about__.py +++ b/packages/markitdown/src/markitdown/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.2.0a1" +__version__ = "0.2.0a2" diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index 6086eb9..d88bb73 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -58,10 +58,10 @@ PRIORITY_GENERIC_FILE_FORMAT = ( ) -_plugins: List[Any] = [] +_plugins: Union[None, List[Any]] = None # If None, plugins have not been loaded yet. -def _load_plugins() -> List[Any]: +def _load_plugins() -> Union[None, List[Any]]: """Lazy load plugins, exiting early if already loaded.""" global _plugins @@ -186,7 +186,9 @@ class MarkItDown: """ if not self._plugins_enabled: # Load plugins - for plugin in _load_plugins(): + plugins = _load_plugins() + assert plugins is not None + for plugin in plugins: try: plugin.register_converters(self, **kwargs) except Exception: From 6bedf6d950719a7432ba6b7c34c946ba70ddfb76 Mon Sep 17 00:00:00 2001 From: afourney Date: Wed, 5 Mar 2025 22:52:52 -0800 Subject: [PATCH 28/33] Fixed version. (#1097) --- packages/markitdown-sample-plugin/pyproject.toml | 2 +- .../src/markitdown_sample_plugin/__about__.py | 2 +- packages/markitdown/src/markitdown/__about__.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/markitdown-sample-plugin/pyproject.toml b/packages/markitdown-sample-plugin/pyproject.toml index 400cc4f..4721036 100644 --- a/packages/markitdown-sample-plugin/pyproject.toml +++ b/packages/markitdown-sample-plugin/pyproject.toml @@ -24,7 +24,7 @@ classifiers = [ "Programming Language :: Python :: Implementation :: PyPy", ] dependencies = [ - "markitdown>=0.2.0a2", + "markitdown>=0.1.0a1", "striprtf", ] diff --git a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py index f691daf..91bf07b 100644 --- a/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py +++ b/packages/markitdown-sample-plugin/src/markitdown_sample_plugin/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.2.0a2" +__version__ = "0.1.0a1" diff --git a/packages/markitdown/src/markitdown/__about__.py b/packages/markitdown/src/markitdown/__about__.py index f691daf..91bf07b 100644 --- a/packages/markitdown/src/markitdown/__about__.py +++ b/packages/markitdown/src/markitdown/__about__.py @@ -1,4 +1,4 @@ # SPDX-FileCopyrightText: 2024-present Adam Fourney # # SPDX-License-Identifier: MIT -__version__ = "0.2.0a2" +__version__ = "0.1.0a1" From 00a65e8f8bea17727cecf10eb7525ba69f48dc81 Mon Sep 17 00:00:00 2001 From: Adam Fourney Date: Wed, 5 Mar 2025 23:10:21 -0800 Subject: [PATCH 29/33] Fixed version in README. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f9ef70..ac61512 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Built by AutoGen Team](https://img.shields.io/badge/Built%20by-AutoGen%20Team-blue)](https://github.com/microsoft/autogen) > [!IMPORTANT] -> Breaking changes between 0.0.1 to 0.0.2: +> Breaking changes between 0.0.1 to 0.1.0: > * Dependencies are now organized into optional feature-groups (further details below). Use `pip install markitdown[all]` to have backward-compatible behavior. > * The DocumentConverter class interface has changed to read from file-like streams rather than file paths. *No temporary files are created anymore*. If you are the maintainer of a plugin, or custom DocumentConverter, you likely need to update your code. Otherwise, if only using the MarkItDown class or CLI (as in these examples), you should not need to change anything. From 80baa5db18e6133965dc9ac47bbebf734808ed7e Mon Sep 17 00:00:00 2001 From: Andrea Pietrobon <32714047+Piero24@users.noreply.github.com> Date: Thu, 6 Mar 2025 08:21:10 +0100 Subject: [PATCH 30/33] fix(README): correct pip install command formatting (#1090) Added missing quotes around `markitdown[all]` in the installation command to ensure proper package resolution by pip. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ac61512..0aa788c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ > [!IMPORTANT] > Breaking changes between 0.0.1 to 0.1.0: -> * Dependencies are now organized into optional feature-groups (further details below). Use `pip install markitdown[all]` to have backward-compatible behavior. +> * Dependencies are now organized into optional feature-groups (further details below). Use `pip install 'markitdown[all]~=0.1.0a1'` to have backward-compatible behavior. > * The DocumentConverter class interface has changed to read from file-like streams rather than file paths. *No temporary files are created anymore*. If you are the maintainer of a plugin, or custom DocumentConverter, you likely need to update your code. Otherwise, if only using the MarkItDown class or CLI (as in these examples), you should not need to change anything. MarkItDown is a lightweight Python utility for converting various files to Markdown for use with LLMs and related text analysis pipelines. To this end, it is most comparable to [textract](https://github.com/deanmalmgren/textract), but with a focus on preserving important document structure and content as Markdown (including: headings, lists, tables, links, etc.) While the output is often reasonably presentable and human-friendly, it is meant to be consumed by text analysis tools -- and may not be the best option for high-fidelity document conversions for human consumption. @@ -36,7 +36,7 @@ are also highly token-efficient. ## Installation -To install MarkItDown, use pip: `pip install markitdown[all]`. Alternatively, you can install it from the source: +To install MarkItDown, use pip: `pip install 'markitdown[all]~=0.1.0a1'`. Alternatively, you can install it from the source: ```bash git clone git@github.com:microsoft/markitdown.git From 36c4bc9ec321f176fdd1ffeeb6e37e98b367cc46 Mon Sep 17 00:00:00 2001 From: scalabreseGD <47219719+scalabreseGD@users.noreply.github.com> Date: Thu, 6 Mar 2025 08:25:37 +0100 Subject: [PATCH 31/33] Fixed deepcopy failure when passing llm_client (#1089) Co-authored-by: afourney --- packages/markitdown/src/markitdown/_markitdown.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index d88bb73..fd2b85f 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -455,7 +455,7 @@ class MarkItDown: cur_pos == file_stream.tell() ), f"File stream position should NOT change between guess iterations" - _kwargs = copy.deepcopy(kwargs) + _kwargs = {k:v for k,v in kwargs.items()} # Copy any additional global options if "llm_client" not in _kwargs and self._llm_client is not None: From 82d84e3edd6ecf319e83362729f68d4a4e511a3c Mon Sep 17 00:00:00 2001 From: afourney Date: Wed, 5 Mar 2025 23:30:29 -0800 Subject: [PATCH 32/33] Fixed formatting. (#1098) --- packages/markitdown/src/markitdown/_markitdown.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/markitdown/src/markitdown/_markitdown.py b/packages/markitdown/src/markitdown/_markitdown.py index fd2b85f..f32b236 100644 --- a/packages/markitdown/src/markitdown/_markitdown.py +++ b/packages/markitdown/src/markitdown/_markitdown.py @@ -455,7 +455,7 @@ class MarkItDown: cur_pos == file_stream.tell() ), f"File stream position should NOT change between guess iterations" - _kwargs = {k:v for k,v in kwargs.items()} + _kwargs = {k: v for k, v in kwargs.items()} # Copy any additional global options if "llm_client" not in _kwargs and self._llm_client is not None: From 0229ff6cb75aa63e5ba6582766d0e5b9cba1fdfa Mon Sep 17 00:00:00 2001 From: Richard Ye <33409792+richardye101@users.noreply.github.com> Date: Fri, 7 Mar 2025 18:45:14 -0500 Subject: [PATCH 33/33] feat: sort pptx shapes to be parsed in top-to-bottom, left-to-right order (#1104) * Sort PPTX shapes to be read in top-to-bottom, left-to-right order Referenced from https://github.com/ssine/pptx2md/blob/39bef65b312035baeade932aad8d221e37daae5f/pptx2md/parser.py#L249 * Update README.md * Fixed formatting. * Added missing import --- README.md | 2 +- .../src/markitdown/converters/_pptx_converter.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0aa788c..40f4b82 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ MarkItDown is a lightweight Python utility for converting various files to Markd At present, MarkItDown supports: - PDF -- PowerPoint +- PowerPoint (reading in top-to-bottom, left-to-right order) - Word - Excel - Images (EXIF metadata and OCR) diff --git a/packages/markitdown/src/markitdown/converters/_pptx_converter.py b/packages/markitdown/src/markitdown/converters/_pptx_converter.py index bea1226..bcde6c9 100644 --- a/packages/markitdown/src/markitdown/converters/_pptx_converter.py +++ b/packages/markitdown/src/markitdown/converters/_pptx_converter.py @@ -6,6 +6,7 @@ import re import html from typing import BinaryIO, Any +from operator import attrgetter from ._html_converter import HtmlConverter from ._llm_caption import llm_caption @@ -160,10 +161,12 @@ class PptxConverter(DocumentConverter): # Group Shapes if shape.shape_type == pptx.enum.shapes.MSO_SHAPE_TYPE.GROUP: - for subshape in shape.shapes: + sorted_shapes = sorted(shape.shapes, key=attrgetter("top", "left")) + for subshape in sorted_shapes: get_shape_content(subshape, **kwargs) - for shape in slide.shapes: + sorted_shapes = sorted(slide.shapes, key=attrgetter("top", "left")) + for shape in sorted_shapes: get_shape_content(shape, **kwargs) md_content = md_content.strip()

    W=>v3T&vY5%Zy%Tz{Xx<^cn-Ql1?!fiCz)o z+A`2D^2~gc7W*7$t2@`XAFkuih>Y*d_h4>VIgT7rL$U*6|S%TQ$jA7cq2a&h( zJ&c&5Ia=b3zYlafzmQKNM#(SXJDwEG-C`5)FAoju1iIy;K|GXx;h*wT*AM&_dS=rNRRSrO$P%O&4Rrf7d&NrbqyDALp8fVg+{j#}&4bt~KbTBjGssCS7x)F*uwdXTkmIw3nFBw9j5lToMmmZ7r;qLn z@*TGYy6A>rJh^v13O#aFpo`?X=otElzA0?mPxm;F?lPx=uI1yfNdK{$o(}XY zU26UWyNcd1#`U58Gtb^UU;h6g;fvw8;2pUru-SeW?g-)sa-95^Hw5q5LV-^4mmU3W zy{&?H_P)Vf-XnrIx4h|hf^P&a3%(a%U-DW09Q@t4e+2nfw&=?PIUz4YZp<6#m-hs5 zkrf92rrz3pYY+G`a{3h~+rDr60of$Kzh@w?J{}GXY-6z&F*EUc_OkqqzhfkRM%IC@ z>SDihz7(AAI@c>ldFGLQGWaHuoK&Z}eKRd@v}^EvI-g4$$xb?Q%iwRjveVtiMuGn1 zqlp2Mt1b39wn1>NYh3I8#|Gt!BdLp=7FW`igMv0ztWdt{gy3&_(8=codik;-H&t;$ zF{|5x?v!Q4I1!E-gAgFm}t(6{uGoPPN}^wE4__P}nThXnoTAh9)L zQS6rfxhlx{8@DG1xx~+gkB41?vHt$BQsBSO6MTC&b@*rIu>2*60bCWt22Kn|1oP?1 z9dgF^A7T!3hM5Apn5`_{O*XJQ&kW)mWGJ1(78i5zw?^6N^v*&-d|jMfyq#Tdo|61Y z8&_lh%e~wj#MZ>_`37?R@&#g5a{v4yxnGd~ux`KO&UKAzM1RO>%pJtK+z03a1AC zENtWCa6&jX921TXM~1_LGRawEz;`ork$S~m&7C$T%rjgo45xSK!#Tp6!yALSa`cb! zLvQk<+%vz5uS6$V+J4(m-Z2Nj9AUcWwjfVqj*qy9e2uvQUF>I{im#bt%1#xBCo7c2 zH!}ZB`RvxqgF49%_4A{&g&ix7LLZvD#?KN{p(D*@K03%Pv2*>sJl|8pdTm=e?mXv{ zOJ5Jl@ZF5^l*?W|A*ko1K!&OJTS4Dwhd3g%>#QK3pq+AB+AQvKexSF17~B*6tuK9( zBM;%;{eKW*M*8Ny=I`Ss<<&P`cvYaw-x}T-77ylFtP|+3Z317>JS_T?P9@jrC-W%2 zAH=%M3I2I7hl}r0y6LXIy9RWI_!u4aw+7qh?$KZJU38i2%J;cC-vnI|%*`-Q!<-HA zwBy3jp?sgxE&Lws-7L_>YXtVll7W7avw2I9w=w_lm0|io&#-U&Z3F&}F-6}PM|>Xr z_^aUm(ij(v9nav*;JJCGp0`{N+v*d+T=*>-*um;jAEbPmc2q%>5EqqVM<%=7Wjz%dfXNb$NCAPz=z#)K3Mu0UR1W zImjV{U*w2e)w-o~oa;Kdd1Z)eDVJ`M$5*d5XbYduyw}si*?}K;L13S=$HkM_^X{1) z&fcfT`2g(jZVX6njcnDQ{_epFVfDc0;M1_n=_I}hKZTyCzop7&Js`+K&{Lk*CmZY| zf3bgXzPtq+e~+Lne>24MCce&5cDl7WzZHxT}9pjqa7(r&G=j=LB}v z1woAL;_%}zF3>eU31VjA0Opa2o!t<;3%7>5f>^b`ePe!^*foELE)q+4MR-jRQ=4P( zZ=lHC&`XPlWy8v0jX*znA2$nI4*m_!9r8Cfy{q(<*o8Ty-d}O_y$7-Wv0%S*b`AU~ zadxqevEhTkd?E9pz3=p)*!xm}9lBtcFYwQ14{r+MA+HKA57UO11%|iZgiM}ypHB~B z-99+(ys3ig$dQ@Cs{Qd)Bf*inNL3{Mciea^&t@?${to?Fa`e%#azQiKw z^X-CfHQcj&wmuW1)NlG@x1evT@96&h0(mG;CO2X3pLrTb1~QXQqyy~W5qSu z1N1oE#Sb+vklx~hlHdH#w}(Z8`5EN>24Rc9kJ~Nq^9~B)oL>lh#hQyD=6OmmCy=kj zZ-H(5#o6c@{urN=Uuj+;UzN_`Khllnm8p|&$nWLTEEBYgPMs&1Q!;aSbHox(s z#*Z=w<*^`kE6?*#;PaT5=DuOwKKjYL6+XFZ^a&s7sUS~8k111-%M$iE?mXA2LwW3` zJAyu@<9->g2lpO8+Y$IPFix9Cv%O1*O8;zvIX{3E{QUxL^ay-hdq1H`fDCHKBqSU!k~Ug z`Au)oBm5USNB@c$k!GWc42sBeU? z2RcAK{4xHNdiiI34EjP_=ng&>-{Y`ApOkJi4nWV)jdUpe=w9eZ7$^J}`jT#Lb1oom$w2V{o2pTuZkrPxeP?y1MT3K%3JGC@lWl% zFYr;>(Pbadk)Z=1zhB)W$Xj zDrQ&lPjSwQb++pj_cT{d>{I+y{F8nh+d&)<_B*HItm=4Qpi9lUq}%y$3y1j!=SR^0 z^r!@yzSigZ-ZStl`1bs0{&&R&*=uYX@5S=LGdB-!=3spA!yXO%Fk_4UGUkmz)vK<9hM=@L4IEucTk7x11#Uc)|q z0)N4|bP#<-_s~1!3Oz&i>U;Ij7xV);t$wnb3@6h)gZkSCbS3*jUdl6pb^G8rzj|!o z7r7t$fnK0Tlu5VHG3w~j>K^B-Um42M26gBse}94QE+3AqQ@$I$Uf5UuoAKj1WhhJ8 z>NDQxCc0C9(7pPIT-D!XseTnt;A34E$WC&dF8XVbKcbJ=ZhQGb1k{696lOZOwW1v-5-J&ymySx_wzu;o1@1sq+^T&?PrhBF((Fk z!rbI(p6^LfQamJ3S+v1K_nF?|=_SU1iq{^~q& z6*idsqHjBtX)dDYqdwzI8`uc!96FCqG=`0Ba)b?Vd(bapsrqroK=1R@_^dS-guhC6 z)8q6yxkV50y~z2J)Bumb2kU$>YegiT%k-{UC_X{VIsrng3?Kh`8Rv!Q5)Oqo=~t!P2(O;=9qJwOUKDS z?i-ZDpQD4tHsufbh+hlzG5^o~YC{X(P>zc(6%W-m@ko6n$4Hl|OIzqd@l_HxtAILZ3^NDx=KA78gX*e(Ni^Uh&8~!GrSUSI&ugw=98~EyMK6Cxpdg6@Bge8Nx zgTMLb`z3iWaYu1`F#`6GxBP;O zM}AAq&yWKbhdXa@e&E;hw{_^H0|TGxBSFs0Jn0R>dcpUaYlSrjv2Fi`VY9GRkayy5 z?Gp|TbQ*moPI+cHKgi3M9uxb!J3JU33-V9$FXjgDALVM~Y`o`kIQ&cRyL*yvp`$_X z*;o4=gKhH;ES)ExC635vBQJbI$%i#pVc9@-m@83nMY^cX*YJtyGd>SLhTdQ4mBRPs_g*-qO3xxjy9Tb0jBkDb(D z4BE#Aa}Iw(JfZ9Xwiunj9uQMiN5xa=;j+hklSBt=&-xwg(^vGZ=TbUXKWew~*m(7f z=pXgzclY8M6t>wzo}+u^v$~e9(jH~kb1^177w?kiVyw|s?K~EFLhqM+v}YrR4eRwR z%q_0$OPd=s&yn7e zqY=j=YK)|ivK1zhH>FXf!^ek(QoGRgMUV+g8wJibyl!+ z%sH-cE%2{ zu-|vh&UYOhO|R3_HwU`D^)t0Yo3z{f#M0MvskrNbL4WIa`k9|sb3epM<>tglMR~}bv^73GO@av2rV~RgsaY=TP7{6S!G0MjmTW4p93(#w9Fm|T-?qUwc zz47ne^lp0>YrZ>q&OY?Mi6_dR@rkYs7ldyIc__L^tWWH3`>=U1KZ5>RIV=~822fra&A#*EM59phL9!n zQ_UR^OXP>Lk;xvuDW8K*A_K`twr$Bj@`^uHz7YR|zeT3eRr-*eBL@!%(S3O$xBCx`hb^fCRTul4iTK+ou7{Xlk#wv$FCU)H73ak9fgXl+)G_C|#`WGW<*GxS+TeXFJzdY<_%V)3 zU(-!uDBj76(OTCp_S3=DH~K|?7*p=oeQCe;c*nmRyzl(Vc5Xg-AkN8e^^-@FLlX~@ zJCiqKJIk4|r^_dkClha#Ka>*_SK1?(Tgexr^9~R6ow*+;g!048+mK&j-`Bhs{+Pd^ zDi34M0YAW;7daX_PR>T2M}8-!)+qB8$VhYi&66WD&6)E(nVc9|%Eu5dGuL~$uxcQ4 z#qh-2_(FUqJ`n$h?^5$Rd^&kIaY@hc zjzEW97w9qZNpp6L1$Ga8W*&)LsJtk9$^XZ3NRU6J-}wD}J>yPXTK>(LuHpNc%MLQzd~EBEk>C6pI>bxH{}Bf=_l};S zH~De=H~teFnr_mEWRd2k;5&2KY@s-4w=neD3 z+4b5fhv|8Y3-s2>!874Y%Q2dNxkuPJ>=4)u+YVygH^PqX9`+3f1u^03^KT{oOApG6 zvTxM&hhW~izS57z23TPehkg?3f%kj^&fZGud(11aZWh!yVz?Af73f;XM$iG)F{ypDifvA^$U5 zkhk{U$N|W?L5u|UiIq4{j?8s(bjqoC$&-nBvMa?-IV39C2^4L)VJm(p}2@RZxezy17Jlu6T}oo_nOj+*8f{;IqjAE*JQ2Vnx2s z;lr&P)(_&1FvmrEUKgeb z=9uu!^{;uie6|Y$Jy$wTe42eEUd>h#yFNIuoel_mI=T<`7xp{HI5XbpMYb0kOrF;G zmAjSWX1kdK<$Yk^c~|6(y_0g*>_he<`Ad$I>E=_D_3U?gK;F%KN&dqnf!sYcn8R^& zI6Tl>;*a8)d_Z!Te5EHp5e^9C^P$0<68SeioLD9KeM~U-jrxN=;w$nI`C@Wr zWI6rC$79p8^Z5YsH0A}cx5bSw4RShc5Z_xAo`X4nWSe}TT-Awzee#9i+0YMkt9YS$ z=@+_2Y*o9&xA?boB>hcK^2cru^d*}Co*{dN{lGV52heBrJ)5{EAB|s0ztds--z|ds zq}%xye5=m~zD(&S{*g8p{3plhe|o<4bMzNqj^Dz!b8k>b`O@m*3+q?cD~sb4BF1y%S<`as}ownuq6I^1gZR$ZGGDSe@e^4P|GN`}6`m zL2sDnB}YZC(4*><|5HC*E9Xb=iWh2^Jc4!m%_n&(Fw*EK*D8abB}PNn%1`jM77gYn z(o@TZ<%4{NrEUAQhuv!)i|br3r@{V})8NNxn>y)dZIOedqi-3^Ki(L-*t{0DLt)=d z!8vS+npfg}lp|;79?GU5ThzxcP`5mu=b$a@h8Fw4mT-=9-M^(iEgW+l+k@_w6V&(a z*S(hyN=JLX^e`Rl`L({Me32L#-_txk{--#rIqQXOzK3JZkuP-3*8<=5i-9h0<#a2P zts6^x73Vp>d|t6#->H8u@OQ;>eV1UKVSSH4U(?<6xCcgmnA0(1pnv7Zz^Ag!*Y$V0 z*Z|I_YaR;be%vwWWBKmEcOGmFInT3$d(sPv}x zi;-(v=}qr0Jt^KG*6zJE2IxZba=r5f-3a4kn?cOyWyi7U#7s8~-trKII37O9U^AM-;oRYY+!qs&q7bqfnri*5&1+`>1P96 z&V_s_*+O=d93dyjkMc=8AN~$G#Rnq8jG??b8BjLqr2BlA8zIFDTpf-Ot_iQ9NL$zkWZhL6N=;#ZYzsvgf#tkI8-WS?pu|4y6P zMaBoaNM25#vak4wmbQ%{c7fcy`*+XmgYt{{iTcyHqW|s>bh6lxaZ)^*IdAsSbNWWy zi2n0DJS*eK_ke6SeX4);xp!Y1w8?W9<1hxqKg#Yg&WsO!KCHL-Y__B8`1SN(HaFa`_T_Iob+ z&U@L~GUCPT0I>k}jBilP=NgjL!~W##-MwGbw9_Pqs?p#<&gnw zggJsat7Q|&b+OUv+ZOU%E|$FaeMZ@Sd?xz3<_MLZW*^WmYy!Gk?v>8-9e{5z=u^Hr zKU(gUo}~lnT(M2M(02=Tn0P0>$cN^i^W)v9U&XAa%RD2wT6&&Ne{C@Di2men)1h;Q z(xdYZ{Dpye2XyHIiD~n9VV(cm?xSz%UeLR)rFX$cwY1Oic3)kiPC8osvj(~3($(w^ z_rm57E0BZMCv^3=AePI{Fz-qqv#I66=~{AxZuP9_RW_@*ljli(8$0CC)Pa3$4Agk2 z@xjh6jA5}Su&vAXHb&X3#xPkz=8?POg1L0wEwY1;;=MaCkl*}|ErS>&InNhfHqd)? zp1E^;V_3J(F*;HXi_YLfE2I1+Ws?KmZT<^6VIChDU9y?1D&MgDL$XhM#rViTvOwIg zN%c|%@QZb^K#g>Od3s#i=+{E(bfKRHQvC|^Bf8aYEZnOjcQ(NQ3KEbVuk4Af5g zj2u)BIjG#4pD6F8f90U)S$a`lkb5-;gpbD$G=D_ClRpUSaE!g+**KS7<=R$$lB?pT zkYiOxVV~pVta@R7N};Tx=B>Df&#k@MEe5L(jTiAq_5-=^nU!3oAB;CT#W*x(%QqtL z$i2e&Cbzvr>=ZsD8O&Cplm8g>HT|cL)l=~SV;9DPWyKae1JBTyq4PW+*Yl5!eRy`Z z*{jZRu5y*(p4^-9TqX>4H6q0NPhA$eZ-N_eH(rffW63k9+=1AGcS`y6Yd!a&p0|4_om>x+v4a9NGagxiov~53|nr%)Fxn2%IAG;_0 zDqgP7*a)6)8w;Uh*#&F@@d`eS__x@CctK%)2s!LHKij!{Zdfnho4n=^RZN8~$IoKp z@gMn$z6Yl#=|*~xexpCcjh7APews(y=3EcVoES0H!-9CQrR{@)JgB*?y9e=B*NNkb zJIg!z-a;-{oOsnB4r^{HeDA*8AhsP_CCF7e-*v9{orZZhV!7tzh(U{It5ew9z4~PFuu!1G>EgM!>xg;qsoC>#82n^^yF%Pc zj>KGS<71A%mSoG3VdNZnNA9tejX!p>u}H=km*kZ9+`H^OCQrS$-XU_|Tn2uWIHUK2 z-$l%8ZWD(s#|Fp7*{wY00R<$|4s230KqI8`oU+D+>#4~U%eWI=ASMj^e0rI@q zUywspzUOD0cz&)oe&_(tMBlKH=r%SVACCRVS0KN{f>#af&#^&lNY2D}1N>8nAMp|R zsm>8sbd4A*`6%Wb+oZ(bL`){wclBjwrv& zlFuq0LVvS0=xjD4U1#MNxuZydC77iE(%-V@J*O~eio%jUcC?>)b1;!pBPjgN{mi+g~+6pN-i`6GN0 zF9bO!EJQ3mvjpkS|?7(1Uc~p5YUr z@}%?{eJ2+xU+SBW6B|y-TqfK0A2*2ed^_Tr(vkF}oU8JV4D_jaMdmQk|E=z)J3kiW zhUsK~*T(ml<{hyEwhU|m`CV)h=yQMjKwg%frRUcU=039n=-efPxk_{{eaq(-hZawl zN3R&Pe&hR_gRSp954i!cb8&Oup@{j*AJLtb;$HUgeZ|9^CkG*}E}u|;1F7;0p7#;K z`3D7Zhzyd`sP8k`YILvo2fxCY;%|@*~Baa3-#@oV;L7e;7L980rgzLf$ z;g%+D{dn?`V&vo!{jOZPi;pcHOApX9-v3sI)2Z}0xl_8BuBChFAO0kLQ~o_UMt_lQ zzA+G=*M9YinbU!C-+vDeg})8XlagDtZr?wG`Bn0#<^z$T!@jm{1#Wu@#7DFsQ%)OF(=El;I;tgUGWPJG%>IIoEHcw{L|N4yFR6l)T9C+4b zqq(2*d2Bkd7;#^EkNy+$H5SEh#BeRe(!|u{Ow5&GAMz>4PV!Q0MvRgjDCQzYZJZgG z?or+DvwUg#%z0!qKbT!f25X1$FXk*>C!Qo1CC0>dHFxFqP;*?wpvtBtGx;R+yZo)3 zq4*NLP3LM0d&w9!2KZg(n0em!gLb{DT&qmTm+UVKWT&T73-KA~wEBOGy^XK z7oTSz8{6JXcAPfzVZFoV4_2Gyr5+pnZc2apTYu)!`NqJz$aXQ#*#r8)_#o%hXN-#Z z%1d~z#-jKlc`N@w)`Hw6kI7PFRnFnPL4MpA75CP5Hkh$VKC(sF?Ve}Ztz-uq)4l0C z_v-nINt+v|pXhFKosPII(5?Kmr2-wqr{w>AJeYSxrT*-8?wZGsZr>&&Q+d<%;=(^d7y)hvwJvPx-NQ^9iAJ zw|TyFGk;f`cMh8eJ~O?^zcj~M&Q_e;{A}-{_^*1!0K|a3tLD4Oeao*~w~ro`Pu5@N z|JFB6%J43Wr^{t)yBK=S^EMZaeujP$K$9ymH3sl&SB|&sP~qw=3Ow~z2+K-eJHQylhEDdl%@G4d`_bGmBadf z?A-^rW>;B0{3$`I^ezxOND-tXEr6gDK`DZ$Bs4*~AP5SCAO;WxDN=jaXX(Ora>b(R;y$i*;(-m+kg-BQ%o}TkNh6n&JMCG{G?W0fNe5Ac_tgq zW~l}6%W`V5kuk;c;(hxI>bPpjN@&$S+o)v>05qO7P@!gSllbthvF(&(`{>nazXXO2O*}u=UzGQ`;!fW^WS2YQ8 z%#O=x<>h#RcWO=iy6?x1A3y6(huK;@RWqwC zlXtOm`~aSl2j5=uSNsJ%mf6$$TMu#AmWc>>0WAynNW6nf(F2oLN`F@SH4UK_+#GzkXyPV zX5;hxU97dnTi-8{S@PRj<>9G2v#qxZ>;cQ?#drFZx3Fhw2#ue_#N<dySLQ7Gq(Ti-_oOlbdgPv$NIOP*fBm5kI~)wZ}(}*4%>)l?#Ut8A@5il zxznci2I3^~lDz;BkGL+Tx_uy@zhYqT+~0)R zcko?3zK8++EgFCA`+hYSc89#P;~+k#*L2l)1MIh0%Qpe+qkKXI&)& z_6^h<)EDqxJ>i@IUW!9}>y3|iAg*Ai+3dFke6F}$P0QX+b5TAL$Y%3LdQLXPsQdt5 zA&+5C=`H`nR$B-9q}F6z)VkC{#TViM@qt<-{pK_IJ-%Kp$)2#?)e&(!$YPFV{Rw=v-i=S3yY9aHjSuB} z`G0+}QSxl{OZ#_hCpnj&voY$3zCq>JSFRZHiz9XFR_v} z6!)oHsQZXX{kt6hmA}V&Yw+CQ@Zg@oZG)QzhwO#p+XQzH>O;Nr*}&g6n3s97{l*}3 z>JM@|`<(O^PyOv7{^2eEfui9z@su^Zm0Q`xiP1Jw{-8$2U;bnw979>HA$ zG(RYKY+xR54ERsEvbc(#kry&aSI8DyWv$tNv6K3*@05J&>-${xPi}?BYL57B9`ax7 zE#FY5us6X5h?&%i{CyvK@kT6X>u2D+ifaf3h&jGYqy zb&pEy;y(Y*m(m~d$@lV8*w!Tb{c#0SW!<-l@Q z{HANMzaQn_!SHv>@_4kHi$26KY82?@iys}>>&0hu%X@ui&nMEq?o-Hd z=%xC$_)C7x*UHW9OTjnvVBnCKnByMyuXi;v0QQHz zwQs-G2-Gv=2x5Kl7`pJ5ud{}1GXF-V>7acYzK<>DZ`mF`ovyGi>&)*HuaduO_q0S&i!yEJG=fw!(NOY*JsaK29 zUmD1D{9TrRZ;D-n`v$K4aUdsoOYpHkywCspdn5U}{FtA#=P9P3?C@w_X;#g-i<2<;TP>W(LHvZ%~$7p zQ9!O+BUB5N*O5(n;`>Okl)mx8o~t;LALXOO9Q-+&$g0{gy6poW9PsyO{rSK*{OIND z$t^ixxAf08%XRt9>jmm$Y$4h7eR#jIRfp)lm$(Ga`33qdUodZaAO;jm8i(x`8>7iy z%m;%v1oB~jZzzA~Pwx_F?-%%+!>0tV4EQqpH1yB%?+w9yw6EdqKcPsAKxK z=jfedy2c)xk6N<&ofwmBiA(4_IaC|_+u(`8y@Fc?R|_r~TsXLR;NJyMdqD4z0U!Ih z!1opCQx7{Pz*D;9-#K8X`9`#;llog>f8WanvkS)td>DR;4a`Z6UcFC!kl)caxwKcM zKKIVx)xnE{qk1f8KfWKs+Y zaxpT@4vRs_shEHc@^|Lh+L#!dJ(nj~BXv>nin#aKpx-)@J^Mz@HRujsKz`I#*-}1@ zZS=hd-l!??EAl#io3CNt&l6lU;3Iz~xMFbGfc-y5;HSpSFNs&gu-4?Tz})dbY{njT zUzYD@C-F+Hj!bud>!QgQ=(o6-t&wY5N4}mv<%{I!zZ*P0u>KrC^` z;IKd*ZZH1M0Uz%BI)A5qu|Qt$-)ylj=Q}gDifv`j(1dSjLIazso*;+g*X_>$pH2_h zG5H>S6(gaakLPpbG3s6Rgw*rJbZVIN!1~~^7)LzGmV;yV$zFi?z_a9p?Zhknp^ZHv zOLPfcWL`cg)~BOtvFsop&~KgPPx1+H%nylIqsg2H|J@=(HLDTKQu-p>O+VEYs)U+D;e~6qt0oiu$xYwNb8SyN?-yc0-2g#gR1K+_~ z^E=?Yy5U*xi*KqQVlpupc`QdjX<2Kw&mMGIih;3I2G^7H~w_5 zSuP?5K%-XdC>J10Y!UvGar+VWJk-0z`uevA_RakJIv)=BS2VsUcwK;=V}lO{Ukt>! zzQe;`epjw*FQRqe)_(BMzP#8;uET!Wb0Wj!)_w9xzW5&dfb>Y6OU=%F#Rlqt_G<9J zn%Tb>?}^J@7lWy5po3krN9MaAxh;L=i}^dgx_ge+h>r4mAWm$n&ca{IdDV)@GMS?r za-z0tJ@}LR1#G-HPJBj}$vb_er(}&z(I0kRIYo=#-m_Imssb!A9T*-$>T^E&72b zHkPkrdw}nw>u41}(kU{^?&Bf(v4+-^pAtutdvTRD6XO`Su@2b;uyUdOyw<>|3HWD^6WDf zM=9Yw&*>mPqLnvTcWaJDbbF7y;5XZbUvdz9Qm-KUe7XHctz3a$ANgXv$%^&F zlgb@GO5e#FUuAsuKwEo&R?mrD(T|_{5Vw;F^31l80c#A_{+IyG)`DFmv*u!Ke5Xfb zUaT!PW8cO1>;_xNcCq_>KmF6PC*pTDP5sWd2Hs(B%oXSr|6E-Y zruoi41JIR+Cr}>85n(b$!*<1EZyvx6`#q0%}%{CX#`Fi)nG@j*Gy~`JgNe&70 zZJzd_%nu*<7%i}mXmJl8 z>l4h;xtPQl=4KrEw|B*J`VnX76Y9HM2Q+!sds7}6)3vcLeV|u-Bz{oSV5fZ(td6P< zDQ;8mEBJKR?LV>WwdvwZG~>TD#B;F{|7-oph@X6cf8&GL2YNXAJNijx$Q&889%3`` zA-C3;4e=oTBm&aqLo<6~^m+8O=Q z51A&*two3r$Q<8G{`h5a13%0^(l5D&xRq{-1^6hr5Pysox{VG#$KE4*#NP0GY!aI( zA7P`xdFv;hvxmlCs!i}q>Mo7l%+Y+<4L*s@lDn!OvL9k6d=Yb5A2tcBk+ou9e51hk zqgRfKW`2u}D&6cm8(p7+zCD$mJ^$s$`E&l8Pemhsn>)JHJ=j9=C7aHcu{rFgH5ALR zBV+_Gr?y=jWv$pzHdOA#KO2kRK?Pf0+s^OR_t{5AAKE?dJ-*c(`3m`&^%A!=7h?y> ztoWR)i}@U*x$(Sb*?GLgXLcU%tpVRp2KiUCipltKvdEWwxa9l z8F8RFc-Q#W$@pZCPMW(ohE1g(>=B>KKa)Q?!9MZ-@&+xq*1Uv_lH2<8u^z_`%eM=* z3Y;5{T$6itjLhqsKC*}Gwm3tK!H=?u>|uSnIx?SKpHx4m%n&Mhxj8F@t(Qqhky5t1)s+Ms+IWuL!Rt!9QqAN zzXP$?Ca?FL=ha*IMf1ZmK1ZB~C)S*NutEF{xusWZERZSk%chYjYj0h}Yu!7*NB)d| z7pqt+F^3qZ@s1ckOvLwENAtpW>(2+13GzW!$eP@?Hj!UpgV-7RPjA>7?bJu1oz96R z$iKLg?Bg?8Z;VMU`2EIr)Yb*mG1HxBmMZzPT;pWh}Ub^%%^b8z1kLQ#ICT-Y(Z&Z-`N(n%GhiSIIbT+FJ7{Z z?CNMojA5>1!@R5CaudAJ(s#Nqm-Z~%gDx=wdnX=XAN9{xSu^v-EA8la(C&Hfd7u3@ z*V;1Ujk!8GWYfU0b#@yZXZpbm;$q$Jw_(Q&F^jG2!;JaLR-*e(X z@A04d8tWg^7z7Ur^G8o*r!fXyqFcuV`Zr!{9DKU?j9&-wgt~`#$upkyPGerWV!r0i z)-=8td5d>=jDKW=tc)^_MlqXtp$mV^y}1LL(4a+!m<=6#zUS#Gov;SRH-%o_x(_H0+ zYAfi&qyAl-aqX?k<;4=F_pLqIV4v7oeULMLkZ%;jSU0hQwM28*xOpr;E_NXs_+q~1&hD{!WX@Q|rSIgO zJ)ysid&Rzv*$Fx^#@T3Psp$n9hgS0xFOUoJV$9}%e7$4yASZMOJ#@(rP4(k!F#F2J z@QHMIv~}pI?Q-3Hx{i-*H=nXdU+XI>pZID0fgV-nD?j24zJlJ#Z|OgK!w%6=8&-V>-eG{^F>2-gqw^=%wqPl6`=IU9xNDuYVxTrLZIUZW%{o(??viloqulyG9 zZ$+=U&)<8V59Hsv7c!j}n_gRrhUNkn-SGMs-Iy~w%Qxadd4@K08N;}T1og9gtU7}I zQ~9zz+(JC#o@eTV)l|BlpB(HtIj7K7{Q0@eAahO!FONoXm@NrhbgC zE$AOKr=l;_4gSVY|D$h1CwdkEedZ$`s*j`B^>3vMO=w`R`3G?9+UQ@s=Y9R@o8DVD z`e4oYax!R5tPy!54#kp~_j$a~ zhrXsVS6fS#$W(oC^RQ_y#_!Z0iTylB4l0k+_zDg5W|Tj=QJrud-F|4p3$*CdIDBDq z1ip#S8uNaBSl(V=%pce1y3X&mu2g@||MKhl;`i$7>lfYQ@72r1)6M7g+kI{Egg8Xb zKJIzQp_@mKdmv(vasLCI=u`J<&1;NB>Wjq(z$dE#jBw38aZ+noor}3Ob}?Ul;~SV) z(QEE|PCVyb{peHw%VGg*PhRLg8$qVYZ)LY~yGZsbciyeck+m_d*;D=6^WQP27;7KK zr7wQujE?gg><#^9-|HvnINPJ;H){WLdnOjK55QmZhx|C-&Oa9F*8FY#yJx*4hG8S8afbB==*E>(^*w_q@$vudFf!sN-j9P=nTlEKMqQj#f8|Q&<-XRP6qgU2; zkzQ4&)S!H$BW~3m61YdVx+g~`^`Wn^&d?a6^pTfhoOfdhvQ5rLn&^_a+*tI)xJC7b ze#-%>-;ImeDEz`#@?#CVX4bkfMc1h7T6y z-TL}5m!JCi&SRvbxxF}{xxMi}6{s1sX4iVd7}r??>tS6NVY*gbvuQi_QM<)=*T&So zRCdR>mrWyYP}@cifGn~bKsU)}?Op9}Z7|tqKj`%`xDTEkZ8jS)+JVtlp#xno(&@bP zl{S4;57EGOR2OS6r}0W-mN9Ojr=D-@Qku=#SZMOY$EjVfy}P%Df+(mrgJhE>p_;L z@yxsH}VBR>OeWf>ai9U;+`Iq`wl_$^+R-U5jsxefQ~iB0iTMGtAFKFN1yASSV7Ey7Vqn8)O)>8)H$Hl5OUN`CAN7_kp@*yNNPUa<>5cx(RsUqS`eB75~KV_TUtNAvTm z&nVwJx7tp0k6?dFzh}t}Jx3FM>D!p(VUcdPMpNCPyY<`NL8Ez?mpPhu?I3=Qc95+b zX~SpNrZnO$I=lAeU)R2To9bYFe{G5RK;?R>cjc-6ty$?_X1~!pl@0SVPcl*7j(TVe z@`~ohW!AjMu6KQ>@@xM3#E-7C@vJ9VhUu~U^}Ur-eVE%a`6N^QZ3tQZgO*k3bKdhl z9@fv0FED25?;P-I3UhFkv8;^P5qTV{DAVNZTZyk ztIysC^o;1-$7|zp-Rq~4eM7r` zVJbhP9IeuUWpb#$(rg@KE~34@xc-=Zn!-Ks>^PtD9<6@XuX0E}3TrWyXKO^3Du3S9 zN9R-er*kO(#ugp0hm$A#w>)iIo^G}6dnfd`=cr?k{HzS%Q)8OZ7c9#K$DFV++Ze0q zLx0w!YhbK#9ZFAmP`W!$=RIy)KKFcCyGr(^?-*y~RoA8Tm0xss)N6AodQV$@8Run8 zH2IMkKYCiZtIZ={m9bIIYTvwH9*lGwYor$qQ@TeQOLyDqfAz|`P31v6AU>!}Sa&ha zh^@%NDmj?Wqx`O%mab7or*yPdQCiU4SjL>lV`=DGS^rVqM)|3{l;2bNDBpWst3U7g zSvzaVuCOQd>$U5ROT;51rtwI9k3RG@%EumwI^n;gY>ngcDSU{&$NakSyxc=RF~T)* zzGoW4dABiC{iOMTF^XO@rsu}F>I1~F)A)9bb$h?hcU*nJ9#4Hjj?pno!>YE=qHmNPfvC znWy)3fG$+0#$2{>f3JipmTRzKSQ-@AKai|MuTynVN=&FUP?qZsdb zUO&bib+UR%TSog^KI32c-DB;z9<|qP^;7g(+rBsUHC;<@^R z-l(JA^FGwhpr`hxHl^1*1EVfihxI*zz6OMms}H_E0pu1r)8oRbx@W}WcJ56$Su=aH7i45gud7k}t7T`3LL zLtj&Uo$5yQqA_FjpfuHY;8po#j${OVm4%Vt#x)mnGH>#3TzV%~RUcF7BLeSEFn8M}7Md>g-yIbCf;ZIySX<5eH=)co*f5!~|(o%2rV zs$HlY)DCDX3uvzm(8tLC>gXb$)0l76(fShWX8o*-{z_MQHPU0wFw*2X^C&%JyR_6+ z7=QG6bg~$IUUjr~q%^WUfYuScPQE+~#_YJ2!P=^xyWi)%+rH6V&@2iM&U6oPvl}6)0*Hepz1Hm|#_S615p7HS*(6tPGru3FR zW0arPvTICls%vy<5k~zYqm>2y`RTiKYfF3E-t(N_p0`erIr>z3^pB>(*dvzFH$LOI z?^mZvbLD8HyL969o|Qg<*X4V!Z^qY=esrv&7mej7x<;BxOV^vO(3{F?Wmj8$AFuUz znOrZE?eap~b(^kfX)AB0vRFGaZTs9Pqa!~%_Bbwi8P9v%XU7&@=mHNI$U;Tg0{=@|J@*=Soi z>N+o*t1*hsebHFc^*1-@oO^CfDr;z1Hhy{Av8HpIj@R|9u8(rINXEQx{6+lkJjb?l z;8Xc(9-U*yWjm%eu(oiKjYH=m`tbyc_M-7?hihYNf5%q5J)ZYj?UY{g zn%c(FZ~V@qYoYD>x2+tkYWuAB+wZuZrJ=kY&-+|yF-~Q!@>W^5zGRy|jd^bKTG!n3 zob~V8TMPZ7&v;#LJS#6pzPfHL(1|YZT1Rq3uJzyCU)~~rkew&$Z^%x>IXUo<$p)x<(^^ zHWn)XF-O0i8+Xd<&Urfilm_P=f050a^2C_NCNERC?&q12rs+DEU)NyTc0D@(j$b*| zzj4QPsoh>=%iUYFUi$Gvs~>u&aNRSD#;cvGT-IhRvRSS{ZB}Ksw2g99no5g#7rllq zzpc<#`slOqr*IuSSGvq?q-_y>#xFhE(zvJ{pX;&r$Dg_E>u-F&$L)WlgAT0%8LOPF zdTuNC+E?4!y0PuOw(WPMx${`nj?X)8KW*Fp*!EuA_Awo&{G7JqbA7jcjpK~Rz3+MN z`&sL$UR9^q^+j?!%4%)@D5tf>`Yzogy*(bsFAZ#jz829i)tR18>6y|r+8sKy2z|!b z9e+y0$cu5zJsNw0ADrs#GJZ_gt?M(keWq*Hbt_--c-61ZwJq-#wS7k0KCMgF#ynuk zzh3XN-fdsTL3`&k%Hybuj(e}qE}FBxJ5Jl__`R+jf2CyrM&5LtD%aJk%6Hq|x27W>%QyXZta1GDxc5s->1coY?l>KHYm#&SM^PjFkdDONvPFwdY z(|vZccG}1Eyz@IL+v%94x$_@+iAUwv*iPlG=i@Wuae1vRzuR`)MeUTf@tMBgzB?XT zs*j_Nj(*VfKI3`smNsMJ(I}If**MR7$Gd*|Djmi$wtNrdty44?ERARzX)^C+bX7;R zqn?x=@0KQgE~2ZswA{40YmeKOW;B-0DesoiS-Qq{MMw4)r3H1-+q6z!|)Z;X!D@wKH(yA`_ip|8zkK)s^% zO!blxz1|uQnZWzbN#DjnADXQ3s5|v3+R?967QE-DAH1>dmCZ$Up4N6+-|-CEM!N9T zuQZWCW1~T?A=hdBqOEK0mCovxIaL<)xrmpQReTxYI#d?S4{iGB&)mngU9_&f*7f&1 z__d$XrT?k?m5#9;X)0YKZ5y5EKOL)MmzHVU`_s1XZ?&Die<0^m8p#}tHfgk_mD}mH z@%i?l@6y(_7}vwPSd%HbUYqf^2JI-Os z=bn$x^xgKS|3&*@w;0XSLq#4_&3ZJnLF^4W?_nh`;*LXX!IeX{s%o zw!OcMrjee?!YF&wr(^40{ha5?z_|YU)qm&RamTjzO2;Bv z^jmrBcx`)q9KSS_cjmU}*ZZA!=RS_t{yW~-_Fl&xbwFRmIL>(7``W&{XzY$NKGS#g z*B{>bRTkQgJnpr&d)_!9w$ax}8CV}^o%r2dC~JevxvTtMq_lmWo_p((o%XlPRG?&4wkj!vwgp9>7BOa z@7PYCS$5vO$9AM))p6(0c`bT&?6=3uXqjH`^JBYcj9wd`>+!VD>3N?U+xFMC^IX;T zS#5vgSmWAEkH_bF+&p3))9{r6p7{B(s_I=v+zGu-^x=LI7?%c<= z_q68GpFZ@}`FD)z*gfz4K3_Vfw2ZtO$L?|Ok8NpM)Q-=!kG9L^>3-iE`$TJhUE{Is zJ+1fJ$8@}9HoI#*uD3q=({INsAD6X#uC$b%k(MbPquf>Y`b>G%_dBcAU-H@txArcI@Brs^9e4p0}@kY5VT}w&?WkqTeEZx@LV>{ib~_qOEgWbg%Ds zjLMUCnasI9KIh%`(=j^cvbN9lJ$@6L1N{i5SO*Y`Sh$DG=l+Pu;3Oy!_-=(}rPzc%J^J?_0x9=z)}(lgRhI>xp% zZAMRNsw|G<_nK!$-jt4UJ&aQryT@(I!>*A&{K{)>$5_<%xjk>4@Za{gmG*?U_8hg( z{b}{!y|&Bxn9gO9+>Lx*biaL!W9*s13ICnW|Aady9F6ZgZojMA@tqTTI>8e}@E@qE#E zy*56#sQ>bJRlDfDvEOCKi{9JpTKg*fZCA)rOV6FJq7VSVTwrYTwJ~81MI;aV}%um_ebLyPU0c=PR_<-q|El|y$x$A9+;-LbtL|-u_LKUV&DQe7yuaC8I+o{p zysE9enYOFmac_Tq)^X8$n~k;Ec&p@NvwKr|wnEFYXQq7}=y~Tow#&vIpIJ8UB3@Mg z#&*$j(>|wk)R#=JkLP0_;~3-ETR9%zZJ*;frDdz__-^~tj^m8Si)bA0FFGFk?eRG7 z{vNllv0XI2Ya`vuo^gHbYY|<`_&R-d>}MQrq@%}UEYsuOYdiKa_U(8&_Nw#gyJNqO zjn}qgkL||I75|y`zm;?J?(1*W9QXC!W@C4{n>{z)-&Yzodw%SDe~vfnpImSD%y@r) zXjt{m*!O`RuNr5wdtK`TX*U~V+58s0H>G3L#jPAq-|rYx8W!2L=`($I+UJ4Lq0i|! zi)dMNZTep6o3>MW_w{_*pY!S1<9T&yq?0$MHDER*t9dJ6|+T=~;Adytb&neZ4mJx7qQszPB=W&rE;Q@jCBS?ev}Y zIi+EdY)qdSX==Z##-85mJKEBr?Kq2QSahw=kMy*^ag5E5`%c@j->n|^-L{*JIo|I( z({|O^p55xa@!xN{4!yn^EnA^uUuc=qF^)eTPx&#Pcf66d@&2k~W4PaT)wAQhajfa_ z_}u;;Py5{LeAPH3A2&N*)z7}(+ia}y{-VA&oAXxgFY0%z*S6CCqG$BK==zCuZ590^ zPgfnU>SL>PuIl5&xVMN7{r38@F?#=`YL|_>*>&{z9VlJP##y!Ai|#G!XRFs2^|>$C zwmQzfJhzqcx6oiS%&I=OdT&v``*Urpvk>x|mRc;4f=ojGu7YdR8vE2X?##=R&x+PQk2d?{L){)qO4}-0`^>)5KFi|1a%_Hn zs~o7jZuR;3xtRkq2WAe;9GE#Ub70>&AeQs%o8$4SYrQwOrwtA)l8bTX?)T?^~n*Yj4)>ubOv# zLZ9vVs(0plGY3u$95^M~()xmBZP%r98=rHp=Y4K&XAaC9m^m&dXL|p% z&f|IhGY4i4%p90GFmvEX$${o)i*mOgB^~ovGY4i4%p90GFmvG4#DV(PQ`4O0xy&4x zIdID0K?wEcX3A#{oLC&F9ndcNofzZj zcdPwOpPim>wV(O9nFBKiW)938m^mE$GY5V& z9GLe!e>8laN0~V=b71Dc%z>E$GY4i4%p6$Gfzx_SxlbQpKVYJ18jM@GUq>uUCnFBKiW)938IAwF- zJkvm4uPwDOG zo0lD*(&sqSKXYK_z)8=6+Qzmq22?}7C+zddtc z=DmV#C5IDNM7oY?J;YMc|B?zz9211DDw zRHxdWTdTIqY{jFZ;MC3mwW=vj?Q@>zH*;X-z|4V@D+lKNgOlsZ%yi8hSk8gwU~QK_ zIp3K%Fmqt$z|4V}12YF^4$K@lxpQF5$;RXTrCW?R{`R+@ALo11y5atuFQWfI`HQcM z`kk-M99YGH>f@?sP6_v>^O&BGbC}*+cHZl4^)Vi|&+(e$Mb~@nq;ALYjWwQ6kH_G`5}ru~lN_PEcC=c|r8PT%YK*e<%)KKoqH`)tpr_nr5d-don3 zF?zrErtS1SGt*<|oBc}Hs^|25QvN!&F?y_> zp7-8(-SPOtr}E16@qF2F-|u@J+x3n)UE{5sPv337z20%#E~2m3)^@M`@4R}g?`hj- z+tTOUF}*2vZrizW-0S0cuZ{1I<2W{c>CqOucJD#Y$9AN-G%lhIjp#XO1>7Ied1?Jd zdPiD&Jko_?=cP|O{z_xp(${tso$gKPEMK*L<5(jNrM1_lG*0Q%&qjxP|1(|3(otTG z=Z<@QY^StNX`Y^UKBc2`Yd^i-bFJ~F=i{}~(`S2cysqD|kB&2KOV6~O^0GW1pPN22 z?c4cC!}PfHE~3BJrtfroeLF5)i`r49D=TgLeEZYt({DPa^O4q(wqEzl^rz2`)3!7@ zACG&k9e-n=BOR61v8~>X*QWH1eH*{_>G<8p@BZO{@9*A&AMF0W7@w(~C{NK^8qrXC zPPgrJ+fF~h8Mf^~um8lhJ@9O8MER`W^2eB^wUm`s?e_w0@1fW8ooD%5T1PrjPeIs3G+;#$b9j&F)yNmd^ipKxh z{XhT9$I@9odavtEmZs~yipJ7cetH(h^)4^8LKDe|n6@ z(&;_Fk=Bu3V*(nADIfccITj;N^=*vOSz1fS*!EuO@}8gmiYa~QLR0B0?@Fih9{0I% zPL9#7-=broy+7Ah{q|6Lg0FGj=X-D3jy&n{B7ThP)#ut*$7qYraUPDB&2OAj`_sSi zrm{53e~-tOtX1AhqZVDI2_5Bq*JP>#wR*KBZO66Khk5B2&_0ei(q8!=uZ{flZt2tK zNMC6yO=sG+2WQ^42R(1=xkdDr)~=B;M;@1VV~gHJbXLdEi6_Q0E*emEmf$CYvo3-A zBmLgj&&bo#haPLpSMVL*-HYRPAGiBE1HQd`4_x=m=x5kVeV9+zNdF_xJEyj2aqQ<= zKkuSPe*j;;LRW7a5xYpMBY{A)sa|Guc;2hi|3!b&^<9b(j%yGKT z_|bK3i%+H38kna!>&Keu+Zbp%S8(3o0>MuO7YQyFTq3yS1g^Q~nF|HpIbWa;w3BVR zXbeB};w^rm2VK^&KyPXFjJe?_I{67a#1H&APjJD&*cS~h9$Y%O>;kxscF$cnK&SWd z7>(A)TA|Ncql1i*xi1Ev4?Z`+fA9Y9jeBI&v*<=Mdg%b3;=#ECTyU8Hf6;3_%-I^@r7_THT)Kk3PX!+fJ`#K=_+apX;9mo+YyTd6H2BZp zvw^wMDf1;4WJ3S=jCSjI{(u~yMN z(D8`?O&{M2$Da&J;}>>+VZ&xs9#+vwCeT#*rAK5K9OEy#$vB;2BdSv)e=D!n5s%2_ ze+6hlTj?#W`0t)M;cIEeTl2PFWPvXD(F?ja`qZi4tZnkFb*WvV4`gdf8yfJiGGM*Q zz`ra(W!N+1gN&08^4@uUX7^_{=1mvOiENX(`VBN#7qU3|9oNj=eb3ToeDpqE;!)SX z{4}od(Si0+*UaJl!TTm~%{_B55ARgY7tN#grM?h-^?hg_G1BjO^y5M8)=2*-!^VY0 z@?3tR15ZZzpx1u%hFs8jwv@~HOOKK1>pf$@xelK?%}3Gjg3zhdyy z0h?djTKkHp>=s*4o8cZiajAemxl(`!=70U*#=$QHw+MbExI=)B-we=ow*Zaz47BFl z_O9FRy6rat@7yl<RLL;9+7R0OU1lvGH3burgX-q_Rpz$xe ztPd@)dwdJosts)4Q#;6hk$tjDuGtED_|D*M!QTe230@JrBsePgi{LrIGlQoGPuYv7 z?%o5}{ycEsbI%Ws4*oKDY4GykZ-Unb`hQdK=HRV?F^>t34YaQPUGSFRjlt`JR|npI zW$>~9UHX5)UX;e??tbnDt;ToFGoCg6tAf`D`h7?6o`9XK zcdhYS{h@c+6MeCHBTwJ3`whGQI{2#q&FI9drv*?(2fT3I1R3!r-~Vvx27we;Pb4cx>>P04ozOknH}1)mAN5gZ@<#P*-qey-qR!4-pR1vd$96C4`c zD|kTg@ZiYc$-&ctrw7jp{vvo@@SNb!1NR>v93DIaZB5u?rbyBg9Z_CSOl}*$BQ}yeaqKYxo)dyFQkT zI3_dvJHJJyjOTrQ>7R_#QF2Qc?-krGxPEZC-~z!JgI(*p*1r>cCHQ>sx!?=I*Mk2E zw(s7)`>er5f~y3-5d3;Tr;iNi47>4 z;_WG~@v=UZ-$TD2J*Ly_58uHC{87M$8RxperGj$=+k$Vbe`EdA!H0wQ1@GO9_piTy z{e!_Lf-eWh2S2&{CwCtl;O#F4hX!oop9JhP|2Fa#E#koD=6K0(i2ud?;#GNwwRm^H zX0xMwD4)R2J|w`Ky9B=xSkGSz?iAcPzvgTD-p4qh1iRq*QItpUD% zJosinmM;-pFSujyJAwJK({zFE(J|}E4vU+_P^}5jF~{t(xX;?l_q`)_|L1^=ia+>< zM+e5Zdq4(m9*|Y@L4)>2fi?Z*0FUvUPvqzLYyN{@L?gGX@6*I|9G8ZEG8L ze%H2L8^v(roh2~lMFL}9JNSj*cER0(2M2!`u<f)oZFb*g_YH!}2j>kA3ckPo{q=7J zd;@$va87T}u=@wr3k%9jCceJrj`~rW*$BG-&JIRGLm*2`+@m6f1hQLqo5p1K_ zUu^rB;NAfq@S#@^E)!fZV4wM2;IsJQ^91raUNaEG z=vyvgjf`n*a*94Vj#vS2fX|at%0tKldc^?zqIbm@e1Wy*L)m*{&>!oLH&+eBG1gIw z4n6{(ZyDS^I5fb2{$CCy7Lu#sjraxMeii%`pZiY%87Z8LW9XGQ zvH1$QW)JvBF&bH6E7VEkAGZnAD(WAewCzb7@$ZYay=dEC2X6}A5s2624<89W7Kq#V zjjsgX42}!JbQoo;3osVKwQtxpFg;8AjZE$aH)XrU|ac-s|42!t{?C-{7u0x z+&uWD;FiJ7f?o_=*ShB#+#b#f;$9v4(<`$H+V?EzCSKt>*Wov4Bis(1OFU+ zH28Y3Bfql-dE1ErZ(zhX(f#9uhn__?^J<9|VsG9u~NMzu>OH?Sfwn4hgOn z@KOFlJhn=A7YzJGe4#DQoXSpK(;>Q=N%i%Mf)XEL%sQcDX9!b~b3i$VX0efW%LSL&i=STq>GdlI*9&eP+#}#az01%3XJBsPZM?HqVp@KL zEn-XL0QOJh!(vWxDET7;>K0;7vOpf$8FLi>^7&*<&cb)dv2GjuTyU`fKfk^H?e)(D z?7ke}AA+|9e-~)U$GZdm^rL~CR!%10vQ~VT_2ZANC)+IlVwc4)R}A`%zu)Kl?7Zb!#J zyyRToC$FM2bP=!kQoc(KRg8pZd`;aV3XC9*ykq( z=-@+M5%3}Z6tLs}x)&eb{^1ROBF~V!d??VqFW_(9z87*EzUTeHzXkspd@lG>@Xg@( z;B-4qx8aZEGFJ+27~Cefd%)K`C3r>fkHIH{aBT3h;OW5wgBu0s4ZgAc8yoZDm(2g?0)G7q+rF^v)q(n-yvIHao5q*W zdwK9b1mZ99BbGiUsH~9(&(RM#gj$35*%)?2eN^6SFGzlMcp%r}|J3T#7}X|SljGhe zV29Wzv9el~xR@-9x6}{VXmKrD!H&xp#G35ji-JE5{vi0B;NHPqf;$Aa4YbZ(e?aii z;12_N$e#z#5B@q}v)BxHXYh{!yYhzMRRKT8zx`35pF;z-`xXHk{jveWVbHBENd_-x>>1f4ItC6DtRg?N{rQcHhm@UTFA z<@W>iYxV3u3CIyS7Td_*<=OTY2T)V$ z9xQ!PPge7k7xFoBTk(fJ_;Wdknw4CMU$|#rP37V0v*IIbE0^Iz)ZXqKs4I$bz_D7R zoK9_*z2^h?7U3n7e`;>@ zfz*BFyXx)TqvvbMEPu+L$bTIB*^dKpvRH<#QDYa6;g#5RjLCYemZ2`M-g1M0T&S_B z#fgR4CBEx0=bm2_4$Wg69Np3H~McNbu3%Gr^~WcLvW0 zeml5+a8U539dFvm%YJ&tPw!AGG~X)+_QT}6)|4!%3yBTcP4(v|1nm1QgPR3xGJADI zaCE?qtMjPulYg}ZzD{k94S8RnMkr>n#zzP52|g33HEQ{PKHt3u2Vx8F$m`@;_I&6B zJ!Dte7QW}8;LU4qUVCV8&EO2dH+Fqv*M9{c+l#O4`pT{|uAOo1D#5*izX^5)H(kH! zhF@c!)lKL#{St4=JIM7t1NM-QWh41gGR`lEQ~7E-$}XuLijUd!p9#LY_SLml1rHBy z6r45q(ylM<`j6nF!54z#gY&MPckOz?{ezbTY#|%ScZ$Ui*?q`H+(@_8H0jrigMSZV zGPhkMwPLz-?Z7_XrGs+@>JV=Y9u@Fq_N&CV?AeZhFFGtZSMc7o_pbeM@GHT=!S{B3 zZ`UV-4+m)da)5_;e81qYf-eSFTff>y%~3r{u4zw2JgiQKM`BoUiTzY{lFtR=*#8XF zPu?7eSv;pMEaqX`*vl&f@>%}!*8@KPYinOy`{&?o!7%~4KNFm8{d5~~fY^h~S_}Cs zn=YPb@6lr);n*N9V?*}UO@1S=kIL@QPq7@m_}aFwZTrhWO^E!-59AQ$dbhwjJvz8z z@WowU-1XPNBZ4~yHw>;3TraqNa76ItfZ*MH?dEGo2RqkyZp1nAwnLN0kUO~|d#N^b z|KLr5n*K$0Tx28eywi?5?YLX;o59V4O9$?&kI*e^|H*Bi-0<6cp*<;nMP6@@ldP*7 z93J4QxJnEq7ruHx$N6kJ?>YIUeN#ETS|UFwXTeW#1fQ#JX75Jr#a_I<@n-~24jvuY zuQ@dEt&sXXU(NsUQ}Qf)HsuuD`yGBllIZY?e>Amwt6605(|-4wpKnR{}w~wp)v80zWMe79RFq@A7(qq zgf)6JegH`H>os{e|ZT zd_4QkwtjT&qie4Yo*Fzdcwlhv;J(4bf+qzp4c-%cKM?cZGeFZvf^+Xa_ePyYe2X4> zD$kOa(ox?x@~`5?`dBeLKdg2y$3Uap>PxAQzBFK`)bGBx_Pw>Y2WWdhaJzs%y+Ux= z;7S2r-Yod-;90@@0``~vdt~sAKcaM=>~qWQ#rro2>??h8{gWH{AKUvY!4-q^24@UTAMnHS+nWdX4dgz2jhsq;Ax}_; zBAeoFd*#L@`(Fys^~2!Xf&JL827IpXm&AAK(c&_72RRCVZC~zb!65;E_Lsr$2DcCJ z?BL)W!8wCV1~&;F9K164MsTh5Yi;D~YLxsn`Tl00KHe;(}^SO_4&3ztwem{p1nl1K2RH`OTL}p z*XS2NDW|gki~n+N-#5sO_@b8w{0ckH2jLmJPTqXOW_>*?ZV@BhI#3@}8>i3qYSq%; z7T9MLd#jQ94yNDo$(8L(iyuE1$N}xE^V@vmUj-iwQtI9&FH#d!BjktVBWi8xY`!a4 z3j`7t!nLmi>U!#Ya<+Q}e4rYoeJ{Ss{M4f8lG*|K)uH5%zC{w#s=bIM?B$CW%o`tk z3n#w4c_2r7ZSX$0r>0o!N~gbm>X`8VHbvITVNy7`vH znu$FwzT@H>I{CC6Pur-K$~Rvd92MZPJwEl;=LPD-;voBA?2))ooX%$PNBq-I1h3om zx?T4TE*X68_|F~x+TiKIk-?LKR|j7UuDh!+ujWtGN!bcE_*VluFOR@KLHHYjhXhv-cIEe>;BCPhgJXja z2HyFvS!*3Y*wPkEjk!~T;!obLtK-FDp#ALhGGGQ?k?k6hvRzXh)j)YjCb z)LraRTNg2}{$8{GnvL9oPgf^e73+o1KRQQ&jY>&Pt}Fgme}BD2I6q` z(;Bg-;w*b{Vh}NwZ&&2jVhgoMc9UJQ2Pj@YXKK;%Y&7}4md^VIOWex8s^i#4my59_ z=#g8fM~ctv7x^wkUVES5szE*xTz^l%f2y0R6NqEZ6Nt0^C-6JV`dKz=$v0WQ$wm$K zS^1_$omLDa&#*3Rt9>bU*Ehy;Rj&%y zpUk%SZdhJvkJ`6`_<=9xV6RavWj#OpaQ_m#J>bj!CV1K2{a`f^$F8GWob}nj9-w_> z{J(HO_vOO)e`sI~HAz0p9Qg|T6EoXmJ2v1e)DOG=aQ1wUC9jfGs_Wp#odUYnzh4o% z$@l&^@ZE&kk9i&ui0vK_c;0*RT=5@2l;zs^E|9+@r(#xgJtE+1`DQf>-xsO>h^NH2 zVtex;gW?YRi}XqSuWm^n#gc4=_?<5~-}duutc5jU`>fI10((oJ4t#IG-^qu>A@2?T zHc-D~_irEgF5|2LnN-{IU5GllTDmo5v&~KX*l%qwwfFC6#I*8Y`ot%S&3uC{uk$?v z-+8aVHyC`(M*{v%4e|=X^#k?CTLf~mn+4YiE*k6%)DF$%&B2QT{X8O&Oa5}8Mr41F zf4)HAdqcGlzF)nK?)whqrh)pyp9jYTUkxt2b< zf?Ec1yYmJ7;%5W?gnv`BFqaRfzG}bn#(^KbS3eL7)F%3FR_sfj>A|N1^$YbKd*5QY zbL~FYhHas*>IcsY_#|BVE)Yx5UHq{AM+a)Y)>pmx_kzQMp9}oNVPYiT zaoC>|hudH0ORf`qVC@4NImZRpF1W^LJUh5oaQ)zd!S>(>$N%8?ox67K`l;YL!QF%B z1)mM%C;ZUA1!{imwr?tYD=jz& zf9x*b_xj+sgG&Y9UiY_SoPF!PA152mcYAdHu}mKNra3AYG`~D?RceJ16TaG&g&kpRf@jv!$^e;B{EyhuSZ?e=!edi>meMj(L zfyFsvzI#1OKzGPE+wFT-`{ZIn`NyZXeR?CV5HI^XZ1zda!>{??gr8AImCxbX@oUGg z{U8vhojXulyHS9TWXPJBuUfZj&c#@4j(rCHO)exqeS2UpPyCNh zTJ;C+vCMWhV@LPdvY76%1_|7W@7Z1)Fd~5r+Hum}6o_#0r8@m917l_|n z<44~V_$K9J0skrwQgi=)aHbt++UU=Bi#H5@IZ&JTU87dsDNns)!1rA{u$OqY;5*yD zv;70X%LDtIcMbR*cK!3)KEJVNLf^=NSmxm1i~$?e+PS!m&Wo4G`y&H2wxa`f&|b>h z0&*qJwD+y1W-nYU=Q{`axW5SzPm5h{5V&SMHd}nn2GG^J2I}x+moFyUY>XJ1PO1t0 zdvI)URB%LKZ%)ln9`l^w^@03U{C$nUcMs1D^yj-ZwSK-F{pxUh%=H6&u$LvrW7o+m zJr--qAJ}`}YN)r+Q?aBy0^gI%L)dEi=UW!F!&?Nt3A}J{)&M;}708>-=Z?Vx1HMVV zN56e1$8MwV&jNfAulSyZjkLFMu>c)->^pTiw|b!Oe#F=Q=81jsy_%Y|ZyUrjFA5$X z$fMam@c{l@GvJ5Wy4wW4X?$Gp{{lSYL+#gE8{Z7rN4ikzP4-;qx46N+_q77C%^wAP zoLY()Q~q*PU=Lc1duZTUHlAG++p>Y=MqVIK@%@854^R1DHkj|eK=8x0A8y!d{zWXI zE^N*D?(YT{U%&YJF9(kfd|&ka;OhB4&vzG33FPeL8{d3$Yh524*jr)`UUJiSJ~E49vih;M@B zDdHI4U9n-}0x>iDtA=!gz_-`h%LaIEk4S7Q2jNT9z38Dn#ggX_!~^oUhX>^DY=QcR znmeEOrQo=Lkvw~F>EOn}0|GLj_NgEH#P(m=0yU%02lgFq6p#hu+t1L-$Nn%7pW&tZ zbl>y#27KQnCw)Qi@IbDmzUv!hzS_Pt9|m9C3*Y^)3v$<=3DDy^OTGXOF<_9VX* z_$FFjsSc?eh`zEfzSlLj{FUG0)8y;?=(&SS1=k5~6Wlpquk988c5t`gR|D%$clcuO zs9&hT^L1*x;tg>Jzsj%I@2U%V#9$A<=w z3?3HTJK%HFC;2=%7k|gs+2dAEl|!hpsA-^!U6rHLH~i%j$SWTqU-un`b>PR@1v%pl zQxTQN$y0rQd01c{@N2=fc3x}eV}thx=Q!vb2i+vNXK+ODj6iMlkAp*lO9h|Y`N^F} z2A2rlx#OK1bw@ep8@9h;gRh@WjgKwj3;6|hl#YKZ-zut`(O))FTzIj7T~|kA<9$!( zyFzxh`#eWw@7Q+=z7>-r>R%l7Yk_ZA{cWA^P5EiOK7FA6{pmogD@TwgvjO&v@l8Em z-X*?2Hs3b-9)Z1~$IlGz7+fMqX?*RtUB~VEVQ}WPGjHs(TzBod8{byEaqW$3av=7~ zo&|r)rm4rM->Dmr6ZL{y2kKD%w)^RUoYvm%uLtBXWN#Ncs!i|-z5!HIQJ;HzYD(&3 z;%xEtvxB<@*9zpbX9|2z1Z|K!O z)fL&q%LVMEJzI6#{|M}#+2g=JxvQERAEUOT?k#_1lb;+|N8bqYBcBaE61+Q*8_H?S z!|xL7m)P(zk4gQTk5LPiAKp3ey^h?2?#rF*Rf#K}7tm3AA!?0s0kN_g4VjnEvYG59 zT_A_&4}4E&kCI(sbJSbaBYb;*T)v_DWbmQjeF2&9UF!3K=LUTK>jF7}8ppQ--#2N$ z6YxXbueQ&{#`<1_-z6Jg4pL&-*vsZa)eY45_)&Yi;y(6P>u;m%ONoovN%F+U{ve=F z>?a?pZp9wki?Pqh2dmR=56rdDulb5))EMojtJlDJ0`$^NaTA)&$2C5gkFa+q|KTgh zxbG*$n0$`7iruzX>6jC1z`X@1rILn-^lePO~U=00{H4x{y=Q;B1J!@+m@r8WSaqGHoOCCV~)d}=v z&q7XXedPk;ezje?YmY^2*FQSTA_Zt(EHURU!*dFAB-wIMeD*udX4_|D@B0Us^C^Y3KH zMbrz#4`LYeI5ZHih+)L8auu{1 zL$NaW+Y&JZTWhVvA96hQ$C`>2`FMM5zWZPY)qLL?$T^-693I?15WoLsAYYRkv9Ij@ ze+F!h{OC4;Sd?zif$s+wOpRDfPwv&XtegE&Ye)~oKyq%f$Ih@(>>S%GXO+ju9mVRe z3LYQaJ-AtLoxt~!HxBL+JT`b?@J|85e*N|9Z`8VuSwChYCXo-Yr*z!6*T$!NYB%aQ zzH3(75u>P+@Tq?MD?i0IiS_w4HpZTaxSg-Jhje7{3jzOW4;0O>37!$i%^w%21wT1> zQSj#Ap9A0Le>L!(iod~7bH(@P2X78O8c2?;(ai%k*!NUN1WydqBYeBUuCs&vPC<>r z9wJ}G->YMoe{DNk&vw#%eo1bk4(D5Q|7MtPDd?DdOg?w<*)J=@HdNen_kfQ2H(2;IIUav6mlfCCDiG)VWPon< z7vIQ=H*XO9dLXA%d;C;jFMxmLBgCn4FL^yZRwwZ9CaLw2rT$w)zI~wI=+=4V;o@g^H+Y9JV>LWv|Bh_n`n94nx( zAwfixXn`28HU~l}jif3QWHgiwhzJbR1JVkiVS@z9Sixb`9x!B0MxaJTTc8|5vOr9V zEvFHJ1PRmY^FHslxqW6A`&=`7{}1>1aQ%MQb>IJYVU?e6nQ#m?7kkv6ID6=t5&jCg ziVutpM#tojwv@RyPe2;VsU+FD(+_Lli z*7bAd^WX?QdCdsh@Pu!iu(RjnEF&A(y5oo2J7*5zIc&ly@KEc9j>av_DcATM+XTOJ zCimqd=DK;$-f=F-I)3?xJ*x+g{N?Ps!76)N?;WAD*@W&r|I&y(ut$&BuhSmq+kr7V zM7`*699h}?LdJ=n;fvyXWT%?rVGaGsf91zVNcXTM>}eru_Jb}T;j81b(=VTz?-lsR z-#K#S$ZJL}9eLr%{*l*?@R_Q+y|4Rz@fu3fs>ND5@>-aj@c-lp`^3lL=V}gsZx%j7iZ>G-L>kJAG zz(!%4d}@Rrjh!LHpNMPw!Sn_nihVHak-nriaZmG*Ptn|De>v-fv#`RU$ssKRt5XoXuvZ!ewWG-Zk>k5x!pE zczk8#>mz&SchrbyH;lYzIbCydwm(R_W@#(ps`ZyFz-vkCmAz8SF3b)OMuJNTFF(c$Cl z0$9hFhdc5w@xj1TdV%lO`e(<%<|{@%GIGq($L#zqHhaT(!#zi|QCr_OVvm6@g`Ldq zu~z9xbDB+TPt(5T4defO-N;XjoHlZokw2Sn4nHySk&zFL+%SSj^7FoE^5hYi z&CmTUBW##^kDNMU&+{LS{LBa&TRI#bC#L)80PCKg7&hSCbfvirkF7OamF>=E)c5o> zdvgB>-GW2YTe!Y68vF*zRJJ`}=T5#d=S203Gc&i3u$l25=X`!_iuaGZ&?M=7MU%>y`Q9l;w|gP-6j`j>B( zFBaBox6s)F^A2V@Ysx>Nd^|yaun%Dser7&6A2gp#?BEPr?lU8>1J1yd_l#UUg7e=n z^2HIDlHj}Q`hXE_g7Nkj{JjPB_I;$iR_7c%cYYX-Y8Pyk{!8O~XFq;;L|Jh8l_U0; zoHuy($TLUyvz&|IC&Jy&9>JBLJL3GHHMxJ}wIjX{efJ1VWS?5&6rFGE;H&)zb+z93 z7I7B+t8aWO!+tS$a6=eQoM*vR`1a{d_v~YFlJ1>B4DVq+$=784nTL3rwE>H*C3t*~ z@pPrw~jbB%9dhJ9vFG`2rOe$ z*#~~`$UR4Vm&K>!?@Y5t*`|0NEWp$00saqbf$(qeb65|2%by;(>rr>z`L593RASC@k$zK^9N>>1;&{4|KvsdH8mmtj}xk84Kw+V{@cWaqG6KJu24_lInXTJN)_xpFBUnZAaa<^S2a?2j7ML1n158 zq}T(v4IO9=vZ?W6^U&UpHDzs?|FHQlN31FOflcY`3{Gi{JLdvR`0jl(oISzc&zF6{ z$j^`9Y&h6Yjktc{$a6-{9Qn2pb~s-IU$Xqzv~0_lj93@Shqbt}HT6$M;35okj+C4{ z@~{zSYplzQNBF*BB72$-la66O;VQ6zE^>wgzdv@qF*$yO9pRqO33p&qu<5KJHa?wk z(uloBocC8p=!PF2!ExBlu#dR5zYYiS9)4522+wDi>uY*P8`*f)IQzvOqq@K(eB!K; z?6-e5f6w>A5w^B>{I>9q?aAikL*#>_1KI01IQ?_kh;y~}h52RGi;eA^%sof&3qDfs z=rVf+_L1o=de}atdBXOjFX(r6FN}hF)+VfECz}84Hs7YeC+ouAg|%Uh@Soz2Fjjlm z()^R!f_v+Cb~-L%jLZc-MB~85GI#MN?PkmKBhpd)hw_7Y{k>w?O_x}U>IN72XW8>G z+dhgtGb$8i9+qkDn2TF{kX=!XEpi_ZwkbI#+~mUN-{E%_lx5 zenI+*56<~s3m121lRRX^d6^#?@pl&f!H7LU9Gj2VIT&ri1?;E(pZOa#>UZIYdN~&c zTk!5zjKC@1^6)?5X~eibX#{tJQ%I?HjQ!;2OOFqt%Ds7#2GBrd)eZ=Zu(R{O;!D3rEDea^#v3Hsha<`1TZ+HJ{n1 z_^divyZDB+qF(Cc{3g7EYjFyADn0uZuSmD4o4o<{_nSs=XL7{||DkgS|7C>F%b7Er zfNs=3#+W~W-{2J^dYL=Q$&0{m9?C zffTdx2+kJ>KuE z2_FqVBmK)~2Y22z!aqoF@q6$!IA_N_IBZwg2%}*72k!X5&OY$V?s(Z9&mB2y>ECD`hracW9#{>MG z1vUd*&;~#I5AedCC*86L+f{WaLke{)TLs*5&iD?aPY!~dAS!AI}o zNY5Vex4ZNqKBWI}CExr!apc00*Nngi{-l%VeAWdc@Q_|MhByTs#7}^G(?RyM@!ww< z;Vb;55%vQcz`oOuk9^O_-9~UHYZtG!XY%FwdsOBOKFoK`Da9VXd<2eLFOM0)hw(V) z4}AA!4e`IJJ3Cd~UpB(uj4!}^XTIR8^DD3u-rG;W@6A1WcF*uUJO^VQt#QP2N9@nC!>s}Q(R#rTa3<>nuCj&I1Bc>!ux7>QBWAOk>+E-RguDENLOuv* z>)FblxhCGRq1pGoft6Msr;p_O7s}f+96>sqhkjIdxQ=J=Bk|wZTWcS{el#41uXF@o z6@0~E@lV%;Z%ybuZfjo9J?1mq*0;{iISZ-Jt!@4gI^vQMdd9rs$J0KdPoFd59sc3l z1chxM`d2% zDDt|wV!Q%lFP)t!%UZqz!pW{;n99H)%n0#6=+Dg3>B18n%G zjW`eGTT~qRAtS!&^0QZ+ePPY;vBG_}H~%l*4|CZZxCQ^6cUO<_|HEti#yLDTD?a}4 z5g2vRh;{m_BmZgS_eMT2@}Utp>zijhz%%cDdj!wHeej@vz56{ed_QMI+a5dOJR6@0 zU{rs)syg!z(;4^|e}TU{0LO8!M~~1EzB~Dq5#J5kGxv8zU@sp(-2H)(vqqjif*0T} z1gG$x59HVp-)FsVgkPO)e)3|o!Qg1^mOz+hYwkQXA99&>|?r^yd?yd}zct*|%Wt5^Z5m(If1s-xz_} zeCPHk@HFjo&XKNyd5qxD`JOJBWU|{|KFw&CkPm+s?03eE4yOBvYdV~GM;|8UD{(I#ooODj zt<=+;hJkD@^TGZv9Mq@!6W1{(^qF;`f1EwyZ#RB)H@vl1%YOD=U+G`|Tv)G<^pClx zJp9ml&@O-9Nn6=E_VO3TyER=f3Pa^H=jx zvCVM?zJmvi;E(taj^W&#=iWQx$lt&(_xh3F8sXc*jW|2MW5n5V{QmqA-*M9!_6?k8 zG?&z;^Nr?>zT&5AKN?;?c!ZCIPXNE>d$IP}G5nS4kH-<$H;s7zg^}Aw@bTkEzI{YK zc#pM(2k>j*3iiHn2WJ%V3z+My**PPgi^CU$E7L#n!2fU?>s1-rjNjnqbPU@-s2=!^ zwJnbL_QB-ACZjXX8^MRo2YteyXH8qf)`>CXPcUcgGnwaju`}owj5r6$#>d002Rsz_ z6~~-;$_PG>kC^jt8s@We@DlrP=5_c_-{E<) z(Zdm7Eg!>=jPSKTV+6P0d*HXYaO8q5IdAs0J>#1eK5N9j20mb)f?fUi5j@0xJKO&e zBYYwc9l;&&7|;2?A2uRX7wKU5X(PVxdEkhBfRjexu6+xB7B-A?1$?J`ruJFz6#f`I z!FM+}4PTAxcn;sDXSj~NNqh&F@XeaPA&V#Zo6Obc8KV z@6)F+3eTV$`26S%`okU_o0lKXdTuRQbM5&#OJ<$o@$3*dMu*a$=KOkoLqF+Pea#nZ z?id3Lm_6y6EB2*6Z{5-r_890D^`%?wtI!d!+%vj^eqn#o zb8yr?%)t?u$hV6(@q?>3n*lE3?$+wx9$|x7m$(Vt@WBzd3bXMueHS-lSCjoC_zm5H zJMbT~+2B5|K)>Mb_#WM&uW&W%&pzBcM$9#H&|K7a&S{!oxHP}Ee!}tfl{HTn=r3(x z8?Yhl_1m|!53c=u*nBi>G~?&o5nWF&Iu9Y_i!ul3YFv#zW&>%Dv(xN(c+2MwgY7%B zNAii%S=m0?2TO@-eM_IwZ}c2n7v}!?2>$~PsDI%)T;}`6iTH8YZ2Hn%!%JZ~T!nGw z1B{3Du*_Ue!hico<|>$;N{N`bS^IpXx*YD!v{* zSn=3}?;9~5IF0r>rv~eATlIYP$OR*hA904{wmCcU!I9q?dB@0ABUg;Papb_r+edzD z{e`$p^q`nv<~8PO)be)GioVxt%@cDD6u?Wn)KA~^Wu5q1f@BJk1N z$NNqiu^!Ba{2Z{@dbh^3?Ik0|5U(+I<}hBsH%M36bHq3J*Zev zYj%VF!bR{O^T=ApqxlK=3$(}Fw5GHPmg9x|<<=cMwb#VPa;6nF(06QK*x=e)wvP`> z?2+;3S?By#a2Kb;mVle2c^$AoP|#;B(;rBhJncc;ifwcSO| zLfV1vsGoBc_9poz=v00QI0Tc9AMtGryk5USxbK{eJ7MIQ5k7hQ3j7H$i|>PN?QD{E z;(|{bv7f>wvVLoqy>H`VuJcD*D=^4#H0m#V!u)3Dh`x?D89Q8r?MPR^6K9<068OmmWBcGr^bcRF za|ied-OmR~*T5xz7YBc+UFJ59VZO5;&3XMo2bt?I5r1L(^L;26Ueot<9-ek+#6HEf zyTW(PPP6v_gXruBjlgyosb3F{SUcvOF=0zs)5eLuGG@NLvX{YTvoj!S=k=@3%+n1MsW!CH>nGdr5B`furvnv1bNDZyaIcX(Roe&wAhN z^}z7#N4TzUaYKG9I6=2-D_ipMBXAz?;q!(c#)Qqwe~!;et8e+H%{#nl9mtl|Mv&IvSQRvQsI+OQ5 zNAwx)aotG%EWRy1tq+gzd3|xjkG(4o=TdwFuYKkU-oej}C*Vyu9sdzttew^#%;mSh z!OT0H#9A}&wHYs=lVB5_#OG}6;TPQp8`zXWx(Y_Nx6GE-2Xr2tjV~x$os5O`!av8q z_=_Xwj@WCt_sG}o_}U#ekKiuXkGy|Z{%HPY`o~8;KXU9hj@|iR6rVC@1o>629KqT6 zT<~0TLwWcXTLsRrso|VD^M~?{vX%H{@o?Yy(e3uh;h41nC;55!`uU?^k#9)xZ2JV} zkojgTPa5Gz!6k8~n?`U#V`^QhpD{Ggjj=QS&Sc=6_Bf@pZtxrH);u^Y}<$tTI}+I4m9kxA`CSF`aD8 z)xYyFbcFQ`7w~a&n{Sfd;3t;mb0aWb8_gfO1J|-f)Ym*?+c~#D*RqS*%dqHyBaa-} zH^SG#Pr_gFW4n7euKmFq_ADcM`H$AlN$JYt{c^CP#8*n<+!Hy(JzYetlzPW(^z7{LYo-9h%a{-OWP zU0lvNbNVJ3m$IH4eMsD9*x8qSN4M7|Di(AI{*x z4)Yy1r!(N3^^Aw}cha@W5wcD2UF+Wd310#~l(W|QVgCsIW}k?Dp+^X;cMsRYGJbu1 zYTrX1_E~Tz-y6Uh+#7#3PuVoMIbBES4)^-kIy`ga5hHxH)~NckC*U!Be;j%jjo&Nc18-NH4-S->={y{re+uDsCP>cYo7}xq&lT1JbFZvl7~4tnqFf4X1tO$a6=2aKyJ!_Zc~6Y;_~7< zXJQ=mo&JPV`dGfWjxyLQ%EJZuhWKglFB}m^(ms2i>ZqOjN7NaI#<6@$LfT8hs|k+d zECN~YJ%^uo2I1TAjGxRt6gyMj;3Ir${4TK2_YC%Le7nl_A9v-BALnj!w(DDW#r3fx zcNxJmOd>uK`w{F}ejK>?yCb*>pNewvM(yIaf*013_8SlS5+}76_oE~DsCC8;!gZYA zbFR!jk-tr?oX)=RE!j7F;s{=b*IYL8+L5b9?CCf!f|Go1}7UV z-{rvu*Zj*c3f{55*fg+~uC%v~3(yhl0s9x$qVo7b@cncby+dcwx%3ZxXzg0Juo}Oh zWAGUJOY8`okRB4!NuIIMogGmgy#=4?FggkMp_lk6taD=TiYO1aqz~{k{h>^KVjqGp z!k(406EGfz!B*I)f9$X6AA5kf3ykGkAD6=*?d?091TTSi_T6zC@A<;=zr%aD;w%tO z#8$+UV2Yx_akrJX|DVW$%FuWQ18p`HF_inQ{;E%cpy+iSp|wbhm&SIy7(y!e$|LGAm%Dt14qRh@Kge? zjkP|o9@NXVxYFpK{Uh=a@)>z1BiH zK46Z(PwPQH+MlHtv{T;Bqr@xCQ|sS&Hm3ZC{A&2B@svit@NZa4=9xLmcCZ$$du5uZ zxV1AK>8ldU>mM-)cn}xd=e{3|vVW1b19H7VgBK z2^(QIf4)4N4aP_Do%NeN@9m9AXP*pCUpB(GmOmHI;r}6cpz$+~_>%g_S3B*WSp4`7 zKgF{~_-}9>do6Dm@y#;dioYT9o?UV689&W|5k4Efo0pDAFP}3<9x?KFNAMN>hub;t z;*1g>iSLA*Rnn*4i}&D>?;GJ8;U}>lmS5;C^M4b)bHv`&)g$Wj?vc*esIN0NxRbQ< zc=!na8BWO$geUPEo9B3-JzX4#J!Ze#{4>w!Cj8o5#FcO-{mD;jUFdtt9XepmB%09F)!M4OuxILxHxagu=i*35=gFIn(l$079hq*U)97hjhpo@oq%HKg^Fq#qu-*A2_-yu$ z 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≫36(kU0_%e!+U+KH1HKX`$Mzyr9Q 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 literal 0 HcmV?d00001 diff --git a/packages/markitdown/tests/test_files/test_notebook.ipynb b/packages/markitdown/tests/test_files/test_notebook.ipynb index 62db0fa..28a546f 100644 --- a/packages/markitdown/tests/test_files/test_notebook.ipynb +++ b/packages/markitdown/tests/test_files/test_notebook.ipynb @@ -1,89 +1,89 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "0f61db80", - "metadata": {}, - "source": [ - "# Test Notebook" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "3f2a5bbd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "markitdown\n" - ] - } - ], - "source": [ - "print('markitdown')" - ] - }, - { - "cell_type": "markdown", - "id": "9b9c0468", - "metadata": {}, - "source": [ - "## Code Cell Below" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "37d8088a", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "42\n" - ] - } - ], - "source": [ - "# comment in code\n", - "print(42)" - ] - }, - { - "cell_type": "markdown", - "id": "2e3177bd", - "metadata": {}, - "source": [ - "End\n", - "\n", - "---" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.8" - }, - "title": "Test Notebook Title" - }, - "nbformat": 4, - "nbformat_minor": 5 + "cells": [ + { + "cell_type": "markdown", + "id": "0f61db80", + "metadata": {}, + "source": [ + "# Test Notebook" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "3f2a5bbd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "markitdown\n" + ] + } + ], + "source": [ + "print(\"markitdown\")" + ] + }, + { + "cell_type": "markdown", + "id": "9b9c0468", + "metadata": {}, + "source": [ + "## Code Cell Below" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "37d8088a", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "42\n" + ] + } + ], + "source": [ + "# comment in code\n", + "print(42)" + ] + }, + { + "cell_type": "markdown", + "id": "2e3177bd", + "metadata": {}, + "source": [ + "End\n", + "\n", + "---" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + }, + "title": "Test Notebook Title" + }, + "nbformat": 4, + "nbformat_minor": 5 } diff --git a/packages/markitdown/tests/test_markitdown.py b/packages/markitdown/tests/test_markitdown.py index 0a3b56e..8c34da0 100644 --- a/packages/markitdown/tests/test_markitdown.py +++ b/packages/markitdown/tests/test_markitdown.py @@ -2,13 +2,20 @@ import io import os import shutil +import openai import pytest import requests -from warnings import catch_warnings, resetwarnings +import warnings -from markitdown import MarkItDown, UnsupportedFormatException, FileConversionException +from markitdown import ( + MarkItDown, + UnsupportedFormatException, + FileConversionException, + StreamInfo, +) +from markitdown._stream_info import _guess_stream_info_from_stream skip_remote = ( True if os.environ.get("GITHUB_ACTIONS") else False @@ -35,6 +42,13 @@ JPG_TEST_EXIFTOOL = { "DateTimeOriginal": "2024:03:14 22:10:00", } +MP3_TEST_EXIFTOOL = { + "Title": "f67a499e-a7d0-4ca3-a49b-358bd934ae3e", + "Artist": "Artist Name Test String", + "Album": "Album Name Test String", + "SampleRate": "48000", +} + PDF_TEST_URL = "https://arxiv.org/pdf/2308.08155v2.pdf" PDF_TEST_STRINGS = [ "While there is contemporaneous exploration of multi-agent approaches" @@ -162,6 +176,107 @@ def validate_strings(result, expected_strings, exclude_strings=None): assert string not in text_content +def test_stream_info_operations() -> None: + """Test operations performed on StreamInfo objects.""" + + stream_info_original = StreamInfo( + mimetype="mimetype.1", + extension="extension.1", + charset="charset.1", + filename="filename.1", + local_path="local_path.1", + url="url.1", + ) + + # Check updating all attributes by keyword + keywords = ["mimetype", "extension", "charset", "filename", "local_path", "url"] + for keyword in keywords: + updated_stream_info = stream_info_original.copy_and_update( + **{keyword: f"{keyword}.2"} + ) + + # Make sure the targted attribute is updated + assert getattr(updated_stream_info, keyword) == f"{keyword}.2" + + # Make sure the other attributes are unchanged + for k in keywords: + if k != keyword: + assert getattr(stream_info_original, k) == getattr( + updated_stream_info, k + ) + + # Check updating all attributes by passing a new StreamInfo object + keywords = ["mimetype", "extension", "charset", "filename", "local_path", "url"] + for keyword in keywords: + updated_stream_info = stream_info_original.copy_and_update( + StreamInfo(**{keyword: f"{keyword}.2"}) + ) + + # Make sure the targted attribute is updated + assert getattr(updated_stream_info, keyword) == f"{keyword}.2" + + # Make sure the other attributes are unchanged + for k in keywords: + if k != keyword: + assert getattr(stream_info_original, k) == getattr( + updated_stream_info, k + ) + + # Check mixing and matching + updated_stream_info = stream_info_original.copy_and_update( + StreamInfo(extension="extension.2", filename="filename.2"), + mimetype="mimetype.3", + charset="charset.3", + ) + assert updated_stream_info.extension == "extension.2" + assert updated_stream_info.filename == "filename.2" + assert updated_stream_info.mimetype == "mimetype.3" + assert updated_stream_info.charset == "charset.3" + assert updated_stream_info.local_path == "local_path.1" + assert updated_stream_info.url == "url.1" + + # Check multiple StreamInfo objects + updated_stream_info = stream_info_original.copy_and_update( + StreamInfo(extension="extension.4", filename="filename.5"), + StreamInfo(mimetype="mimetype.6", charset="charset.7"), + ) + assert updated_stream_info.extension == "extension.4" + assert updated_stream_info.filename == "filename.5" + assert updated_stream_info.mimetype == "mimetype.6" + assert updated_stream_info.charset == "charset.7" + assert updated_stream_info.local_path == "local_path.1" + assert updated_stream_info.url == "url.1" + + +def test_stream_info_guesses() -> None: + """Test StreamInfo guesses based on stream content.""" + + test_tuples = [ + ( + os.path.join(TEST_FILES_DIR, "test.xlsx"), + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ), + ( + os.path.join(TEST_FILES_DIR, "test.docx"), + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ), + ( + os.path.join(TEST_FILES_DIR, "test.pptx"), + "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ), + (os.path.join(TEST_FILES_DIR, "test.xls"), "application/vnd.ms-excel"), + ] + + for file_path, expected_mimetype in test_tuples: + with open(file_path, "rb") as f: + guesses = _guess_stream_info_from_stream( + f, filename_hint=os.path.basename(file_path) + ) + assert len(guesses) > 0 + assert guesses[0].mimetype == expected_mimetype + assert guesses[0].extension == os.path.splitext(file_path)[1] + + @pytest.mark.skipif( skip_remote, reason="do not run tests that query external urls", @@ -183,7 +298,6 @@ def test_markitdown_remote() -> None: assert test_string in result.text_content # Youtube - # TODO: This test randomly fails for some reason. Haven't been able to repro it yet. Disabling until I can debug the issue result = markitdown.convert(YOUTUBE_TEST_URL) for test_string in YOUTUBE_TEST_STRINGS: assert test_string in result.text_content @@ -192,6 +306,10 @@ def test_markitdown_remote() -> None: def test_markitdown_local() -> None: markitdown = MarkItDown() + # Test PDF processing + result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test.pdf")) + validate_strings(result, PDF_TEST_STRINGS) + # Test XLSX processing result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test.xlsx")) validate_strings(result, XLSX_TEST_STRINGS) @@ -230,10 +348,6 @@ def test_markitdown_local() -> None: ) validate_strings(result, BLOG_TEST_STRINGS) - # Test ZIP file processing - result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test_files.zip")) - validate_strings(result, XLSX_TEST_STRINGS) - # Test Wikipedia processing result = markitdown.convert( os.path.join(TEST_FILES_DIR, "test_wikipedia.html"), url=WIKIPEDIA_TEST_URL @@ -254,24 +368,135 @@ def test_markitdown_local() -> None: for test_string in RSS_TEST_STRINGS: assert test_string in text_content - ## Test non-UTF-8 encoding - result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test_mskanji.csv")) - validate_strings(result, CSV_CP932_TEST_STRINGS) - # Test MSG (Outlook email) processing result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test_outlook_msg.msg")) validate_strings(result, MSG_TEST_STRINGS) + # Test non-UTF-8 encoding + result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test_mskanji.csv")) + validate_strings(result, CSV_CP932_TEST_STRINGS) + # Test JSON processing result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test.json")) validate_strings(result, JSON_TEST_STRINGS) + # # Test ZIP file processing + result = markitdown.convert(os.path.join(TEST_FILES_DIR, "test_files.zip")) + validate_strings(result, DOCX_TEST_STRINGS) + validate_strings(result, XLSX_TEST_STRINGS) + validate_strings(result, BLOG_TEST_STRINGS) + + # Test input from a stream + input_data = b"

    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 G1N&c;K{7W0 delta 13265 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 diff --git a/packages/markitdown/tests/test_files/test.wav b/packages/markitdown/tests/test_files/test.wav new file mode 100644 index 0000000000000000000000000000000000000000..e872f106f0a6cbae805b5b0fc9d3adc4f4cb2602 GIT binary patch literal 1237070 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