人工智能AI 应用MCP 服务【免费下载链接】markitdownPython tool for converting files and office documents to Markdown.项目地址https://gitcode.com/GitHub_Trending/ma/markitdown点击查看免费下载导读MarkItDown 是微软推出的文件/Office 文档转 Markdown的 Python 工具其核心转换逻辑由一系列DocumentConverter组成。但当内置转换器无法覆盖你所需的文件格式如 RTF时该怎么办本文以仓库中的 markitdown-sample-plugin 为骨架完整讲解插件接口协议 → 自定义转换器实现 → pyproject.toml 入口点声明 → 安装验证 → CLI/Python 两种启用方式 → 优先级机制 → 测试的全链路开发流程。读完本文你将能独立为 MarkItDown 编写一个可被markitdown --use-plugins或MarkItDown(enable_pluginsTrue)自动发现与调用的第三方转换插件。一、插件机制概览MarkItDown 如何发现第三方转换器MarkItDown 本身内置了 Docx、Xlsx、Pptx、Pdf、Html、Csv 等二十余种转换器但插件机制允许外部包在不修改核心库的情况下扩展新的文件格式支持。整套插件协议由三块拼图组成对应 sample plugin 的实现一个自定义的DocumentConverter子类实现accepts()与convert()两个方法两个模块级导出__plugin_interface_version__接口版本号与register_converters(markitdown, **kwargs)注册回调pyproject.toml中的入口点声明[project.entry-points.markitdown.plugin]。MarkItDown 侧通过importlib.metadata.entry_points(groupmarkitdown.plugin)枚举并懒加载所有已安装插件的入口点然后逐个调用其register_converters将转换器注册进MarkItDown实例。相关实现位于 packages/markitdown/src/markitdown/_markitdown.py_load_plugins与 同文件 enable_plugins 方法。二、实现自定义 DocumentConverteraccepts 与 convert 双方法协议插件最核心的部分是转换器本身。Sample Plugin 以 RTF 转换器为例展示了最小可用的DocumentConverter骨架from typing import BinaryIO, Any from markitdown import MarkItDown, DocumentConverter, DocumentConverterResult, StreamInfo, PRIORITY_SPECIFIC_FILE_FORMAT class RtfConverter(DocumentConverter): def __init__( self, priority: float PRIORITY_SPECIFIC_FILE_FORMAT ): super().__init__(prioritypriority) 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()2.1 基类契约来自源码的事实根据 packages/markitdown/src/markitdown/_base_converter.py 中DocumentConverter的基类定义协议细节如下accepts()依据stream_info典型是mimetype、extension必要时也可参考url、filename快速判断是否应由本转换器尝试转换返回布尔值。其签名与convert()保持一致以保障accepts 为 True 时 convert 必能处理。重要约束若在accepts()中读取了文件流如file_stream.read(...)返回前必须把流位置复位file_stream.seek(cur_pos)因为convert()会紧接着以原位置读取。convert()真正把文件流转换为 Markdown返回DocumentConverterResult。失败时可抛出FileConversionExceptionmimetype 已识别但转换失败或MissingDependencyException缺少依赖。DocumentConverterResult构造参数为markdown必填与title可选text_content是其软弃用别名源码中注明新代码应迁移到markdown或__str__。StreamInfo字段包括mimetype、extension、charset、filename、local_path、url均可为 None见 packages/markitdown/src/markitdown/_stream_info.py。2.2 真实可运行的 RTF 实现仓库源码Sample Plugin 实际交付的 RtfConverter 并未停留在NotImplementedError骨架而是给出了完整实现是编写自有转换器的最佳模板import locale from typing import BinaryIO, Any from striprtf.striprtf import rtf_to_text from markitdown import ( MarkItDown, DocumentConverter, DocumentConverterResult, StreamInfo, ) ACCEPTED_MIME_TYPE_PREFIXES [ text/rtf, application/rtf, ] ACCEPTED_FILE_EXTENSIONS [.rtf] class RtfConverter(DocumentConverter): Converts an RTF file in the simplest possible way. 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 a str using the 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( titleNone, markdownrtf_to_text(stream_data), )几个值得注意的实现细节匹配策略accepts()先比对扩展名.rtf再按 MIME 前缀text/rtf、application/rtf做宽松匹配startswith大小写归一化后比较覆盖面更稳编码处理convert()优先使用stream_info.charset缺失时回退到locale.getpreferredencoding()再对二进制流解码兼顾了 HTTP 响应中携带 charset 与本地文件两种场景文本转换调用第三方库striprtf的rtf_to_text完成 RTF 语法剥离title传None表示不提供文档标题。三、声明插件协议导出接口版本号与注册回调实现转换器之后插件包还必须导出以下两个模块级对象源码见 packages/markitdown-sample-plugin/src/markitdown_sample_plugin/_plugin.py# 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())__plugin_interface_version__当前协议版本号唯一受支持的值是1register_converters(markitdown, **kwargs)每次创建MarkItDown实例并启用插件时都会被调用。其中markitdown是刚构造的实例kwargs透传构造参数。回调内部只需markitdown.register_converter(...)即可完成注册示例中把RtfConverter的一个实例直接挂上。插件包的__init__.pypackages/markitdown-sample-plugin/src/markitdown_sample_plugin/init.py会再导出__version__、__plugin_interface_version__、register_converters、RtfConverter四个符号方便测试与使用者直接from markitdown_sample_plugin import RtfConverter。四、在 pyproject.toml 中声明插件入口点register_converters只是模块内函数MarkItDown 要发现它靠的是打包元数据中的 entry point。在插件的 pyproject.toml 中声明[project.entry-points.markitdown.plugin] sample_plugin markitdown_sample_plugin语义说明键sample_plugin可以是任意字符串但最好与插件名一致--list-plugins输出中会显示它值markitdown_sample_plugin是实现插件的包的全限定名即register_converters所在模块MarkItDown 加载入口点后直接调用该模块的register_converters入口点分组名markitdown.plugin是固定的协议字符串与 _markitdown.py 中entry_points(groupmarkitdown.plugin)一一对应写错分组名将导致插件无法被发现。该 pyproject.toml 还给出了可参考的完整打包配置requires-python 3.10、依赖markitdown0.1.0a1与striprtf、采用 hatchling 构建。若插件还需转换其他格式只需在dependencies中追加对应解析库即可。五、安装与验证从 pip 安装到插件列表确认5.1 安装插件在插件包目录下执行此处指仓库中的 packages/markitdown-sample-plugin 目录pip install -e .-eeditable模式会以可编辑方式安装当前目录的包开发调试时改动源码无需重装。5.2 验证插件已被 MarkItDown 识别markitdown --list-plugins该命令的输出逻辑在 packages/markitdown/src/markitdown/main.py它会枚举entry_points(groupmarkitdown.plugin)打印形如* sample_plugin (package: markitdown_sample_plugin)的条目若没有任何插件则提示 No 3rd-party plugins installed.。注意插件只有在使用-p/--use-plugins时才真正加载见 5.3 与 6.1--list-plugins只是列出已安装的入口点。六、启用插件CLI 与 Python 两种方式6.1 CLI 方式使用--use-plugins简写-p标志启用全部已安装插件例如转换一个 RTF 文件markitdown --use-plugins path-to-file.rtf在main.py 中该标志被透传为MarkItDown(enable_pluginsargs.use_plugins)从而在实例构造阶段触发插件注册。6.2 Python 方式在 Python 中通过enable_pluginsTrue构造MarkItDownfrom markitdown import MarkItDown md MarkItDown(enable_pluginsTrue) result md.convert(path-to-file.rtf) print(result.text_content)结合 _markitdown.py 可知enable_plugins默认是None等效关闭仅当显式传True时才调用enable_plugins()内置转换器默认开启enable_builtins默认True插件转换器与内置转换器共存于同一注册表。七、优先级机制插件转换器如何插队到内置转换器之前注册时通过register_converter(converter, priority...)指定优先级其语义在 _markitdown.py 的 docstring 中有权威说明两个内置常量PRIORITY_SPECIFIC_FILE_FORMAT 0.0如 docx、pdf、xlsx 这类精确格式定义见此处与PRIORITY_GENERIC_FILE_FORMAT 10.0text/*等接近兜底的通用转换器如 PlainTextConverter、HtmlConverter、ZipConverter数值越小越先尝试每次_convert前对注册表按 priority 做稳定排序sorted(self._converters, keylambda x: x.priority)见实现同优先级的转换器保持注册顺序且越晚注册的越靠前插件的插队空间插件可用任意优先级控制出场顺序。例如 priority 为 9 的插件会排在PRIORITY_GENERIC_FILE_FORMAT10的 PlainTextConverter 之前但排在大多数内置精确格式0之后想让插件优先于一切内置转换器则可用小于 0 的数值兜底保障每个StreamInfo猜测含magika内容识别的猜测与空StreamInfo()兜底都会依次过一遍排序后的转换器直到某个accepts()返回 True 且convert()成功为止全部失败时若存在异常记录则抛FileConversionException否则抛UnsupportedFormatException。Sample Plugin 的RtfConverter默认使用PRIORITY_SPECIFIC_FILE_FORMAT0.0与 Docx、Pdf 等内置精确格式同优先级依靠后注册者优先的稳定排序规则排在它们之前保证 RTF 输入能命中插件自身。八、用测试验证插件直接调用与端到端两条路径仓库自带测试 packages/markitdown-sample-plugin/tests/test_sample_plugin.py给出了两条验证思路from markitdown import MarkItDown, StreamInfo from markitdown_sample_plugin import RtfConverter 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 directly. with open(os.path.join(TEST_FILES_DIR, test.rtf), rb) as file_stream: converter RtfConverter() result converter.convert( file_streamfile_stream, stream_infoStreamInfo( mimetypetext/rtf, extension.rtf, filenametest.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(enable_pluginsTrue) 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单元级跳过插件加载链路直接构造RtfConverter并手工传入StreamInfo(mimetypetext/rtf, extension.rtf, filenametest.rtf)验证convert()输出包含预期文本集成级MarkItDown(enable_pluginsTrue)convert()端到端验证入口点发现、register_converters回调、路由匹配accepts与转换convert全链路。测试样本为仓库内的 test.rtf。九、完整插件清单可复制的开发模板综合上述各节一个完整、可直接运行的 MarkItDown 插件包由以下四部分构成文件组织方式参照 markitdown-sample-plugin1. 转换器与注册回调src/your_plugin/_plugin.py__plugin_interface_version__ 1register_converters(markitdown) 自定义DocumentConverter子类accepts判格式、convert转 Markdown返回DocumentConverterResult(markdown..., title...)。2. 包导出src/your_plugin/__init__.pyre-export__plugin_interface_version__、register_converters与转换器类方便测试与用户直接引用。3. 入口点声明pyproject.toml[project.entry-points.markitdown.plugin] sample_plugin markitdown_sample_plugin4. 安装与使用pip install -e . markitdown --list-plugins # 确认入口点可见 markitdown --use-plugins file.rtf # CLI 启用插件转换from markitdown import MarkItDown md MarkItDown(enable_pluginsTrue) result md.convert(file.rtf) print(result.text_content) # 或 result.markdown从接口版本号、注册回调到入口点声明、优先级数值每一步都有明确的源码与测试佐证读者可对照仓库中的 sample plugin 源码、核心注册逻辑 与 基类协议 逐行核验并据此为自己的专属格式编写转换插件。赞分享人工智能AI 应用MCP 服务【免费下载链接】markitdownPython tool for converting files and office documents to Markdown.项目地址https://gitcode.com/GitHub_Trending/ma/markitdown点击查看免费下载相关推荐F3D 插件开发实战基于 libf3d Plugin SDK 编写自定义三维格式读取插件F3D 插件开发实战基于 libf3d Plugin SDK 编写自定义三维格式读取插件 F3D 的插件机制允许开发者在不修改主程序的前提下通过 Plugi3D渲染图形学桌面应用在 AntV G6 中编写自定义插件Custom Plugin从注册、配置到生命周期实战在 AntV G6 中编写自定义插件Custom Plugin从注册、配置到生命周期实战 导读 插件Plugin是 G6 antv/g6 中扩展数据可视化前端图表库Apache Airflow 插件开发实战从零编写一个自定义 Plugin 视图Apache Airflow 插件开发实战从零编写一个自定义 Plugin 视图 导读 Apache Airflow 提供了强大的插件Plugin机制允后端任务调度工作流自动化数据编排批处理数据工程流程编排创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考