mdengine 0.2.2__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. {mdengine-0.2.2/src/mdengine.egg-info → mdengine-0.3.0}/PKG-INFO +131 -5
  2. {mdengine-0.2.2 → mdengine-0.3.0}/README.md +123 -3
  3. {mdengine-0.2.2 → mdengine-0.3.0}/pyproject.toml +14 -2
  4. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/__init__.py +1 -1
  5. mdengine-0.3.0/src/md_generator/media/__init__.py +21 -0
  6. mdengine-0.3.0/src/md_generator/media/audio/__init__.py +18 -0
  7. mdengine-0.3.0/src/md_generator/media/audio/api/__init__.py +1 -0
  8. mdengine-0.3.0/src/md_generator/media/audio/api/main.py +175 -0
  9. mdengine-0.3.0/src/md_generator/media/audio/api/mcp_server.py +38 -0
  10. mdengine-0.3.0/src/md_generator/media/audio/api/mcp_setup.py +84 -0
  11. mdengine-0.3.0/src/md_generator/media/audio/api/run.py +30 -0
  12. mdengine-0.3.0/src/md_generator/media/audio/api/settings.py +26 -0
  13. mdengine-0.3.0/src/md_generator/media/audio/converter.py +178 -0
  14. mdengine-0.3.0/src/md_generator/media/audio/formatter.py +70 -0
  15. mdengine-0.3.0/src/md_generator/media/audio/service.py +52 -0
  16. mdengine-0.3.0/src/md_generator/media/document_converter.py +239 -0
  17. mdengine-0.3.0/src/md_generator/media/job_store.py +94 -0
  18. mdengine-0.3.0/src/md_generator/media/video/__init__.py +9 -0
  19. mdengine-0.3.0/src/md_generator/media/video/api/__init__.py +1 -0
  20. mdengine-0.3.0/src/md_generator/media/video/api/main.py +174 -0
  21. mdengine-0.3.0/src/md_generator/media/video/api/mcp_server.py +38 -0
  22. mdengine-0.3.0/src/md_generator/media/video/api/mcp_setup.py +84 -0
  23. mdengine-0.3.0/src/md_generator/media/video/api/run.py +30 -0
  24. mdengine-0.3.0/src/md_generator/media/video/api/settings.py +26 -0
  25. mdengine-0.3.0/src/md_generator/media/video/converter.py +111 -0
  26. mdengine-0.3.0/src/md_generator/media/video/formatter.py +81 -0
  27. mdengine-0.3.0/src/md_generator/media/video/service.py +79 -0
  28. mdengine-0.3.0/src/md_generator/media/whisper_language.py +78 -0
  29. {mdengine-0.2.2 → mdengine-0.3.0/src/mdengine.egg-info}/PKG-INFO +131 -5
  30. {mdengine-0.2.2 → mdengine-0.3.0}/src/mdengine.egg-info/SOURCES.txt +24 -0
  31. {mdengine-0.2.2 → mdengine-0.3.0}/src/mdengine.egg-info/entry_points.txt +6 -0
  32. {mdengine-0.2.2 → mdengine-0.3.0}/src/mdengine.egg-info/requires.txt +8 -0
  33. {mdengine-0.2.2 → mdengine-0.3.0}/LICENSE +0 -0
  34. {mdengine-0.2.2 → mdengine-0.3.0}/setup.cfg +0 -0
  35. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/__init__.py +0 -0
  36. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/api/__init__.py +0 -0
  37. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/api/convert_runner.py +0 -0
  38. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/api/jobs.py +0 -0
  39. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/api/main.py +0 -0
  40. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/api/mcp_server.py +0 -0
  41. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/api/mcp_setup.py +0 -0
  42. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/api/query_options.py +0 -0
  43. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/api/settings.py +0 -0
  44. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/convert_impl.py +0 -0
  45. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/converter.py +0 -0
  46. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/archive/options.py +0 -0
  47. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/__init__.py +0 -0
  48. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/api/__init__.py +0 -0
  49. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/api/main.py +0 -0
  50. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/api/mcp_server.py +0 -0
  51. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/api/query_options.py +0 -0
  52. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/api/settings.py +0 -0
  53. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/api/staging.py +0 -0
  54. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/api/zip_bundle.py +0 -0
  55. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/backends/__init__.py +0 -0
  56. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/backends/base.py +0 -0
  57. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/backends/easy.py +0 -0
  58. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/backends/paddle.py +0 -0
  59. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/backends/tesseract.py +0 -0
  60. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/convert_impl.py +0 -0
  61. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/converter.py +0 -0
  62. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/emit.py +0 -0
  63. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/io_util.py +0 -0
  64. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/image/utils.py +0 -0
  65. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/__init__.py +0 -0
  66. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/api/__init__.py +0 -0
  67. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/api/main.py +0 -0
  68. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/api/mcp_server.py +0 -0
  69. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/api/settings.py +0 -0
  70. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/api/zip_bundle.py +0 -0
  71. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/converter.py +0 -0
  72. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/md_emit.py +0 -0
  73. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/pdf_extract.py +0 -0
  74. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/pdf/utils.py +0 -0
  75. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/__init__.py +0 -0
  76. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/api/__init__.py +0 -0
  77. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/api/convert_runner.py +0 -0
  78. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/api/jobs.py +0 -0
  79. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/api/main.py +0 -0
  80. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/api/mcp_server.py +0 -0
  81. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/api/mcp_setup.py +0 -0
  82. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/api/query_options.py +0 -0
  83. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/api/settings.py +0 -0
  84. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/convert_impl.py +0 -0
  85. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/converter.py +0 -0
  86. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/embedded_extract.py +0 -0
  87. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/ooxml_media.py +0 -0
  88. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/options.py +0 -0
  89. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/post_assets.py +0 -0
  90. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/text_formatting.py +0 -0
  91. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/vendor_pdf_md/__init__.py +0 -0
  92. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/vendor_pdf_md/convert.py +0 -0
  93. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/vendor_word_md/__init__.py +0 -0
  94. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/vendor_word_md/convert.py +0 -0
  95. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/ppt/zip_deep.py +0 -0
  96. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/__init__.py +0 -0
  97. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/api/__init__.py +0 -0
  98. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/api/convert_runner.py +0 -0
  99. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/api/jobs.py +0 -0
  100. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/api/main.py +0 -0
  101. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/api/mcp_server.py +0 -0
  102. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/api/mcp_setup.py +0 -0
  103. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/api/query_options.py +0 -0
  104. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/api/settings.py +0 -0
  105. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/convert_impl.py +0 -0
  106. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/converter.py +0 -0
  107. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/format_detect.py +0 -0
  108. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/md_emit_json.py +0 -0
  109. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/md_emit_txt.py +0 -0
  110. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/md_emit_xml.py +0 -0
  111. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/text/options.py +0 -0
  112. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/__init__.py +0 -0
  113. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/api/__init__.py +0 -0
  114. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/api/convert_runner.py +0 -0
  115. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/api/jobs.py +0 -0
  116. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/api/main.py +0 -0
  117. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/api/mcp_server.py +0 -0
  118. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/api/mcp_setup.py +0 -0
  119. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/api/query_options.py +0 -0
  120. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/api/settings.py +0 -0
  121. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/assets.py +0 -0
  122. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/convert_impl.py +0 -0
  123. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/converter.py +0 -0
  124. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/crawl.py +0 -0
  125. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/extract.py +0 -0
  126. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/fetch.py +0 -0
  127. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/html_to_md.py +0 -0
  128. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/options.py +0 -0
  129. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/page_convert.py +0 -0
  130. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/post_convert_assets.py +0 -0
  131. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/url/robots_util.py +0 -0
  132. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/__init__.py +0 -0
  133. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/api/__init__.py +0 -0
  134. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/api/convert_util.py +0 -0
  135. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/api/jobs.py +0 -0
  136. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/api/main.py +0 -0
  137. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/api/mcp_server.py +0 -0
  138. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/artifact.py +0 -0
  139. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/converter.py +0 -0
  140. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/word/settings.py +0 -0
  141. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/__init__.py +0 -0
  142. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/api/__init__.py +0 -0
  143. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/api/app.py +0 -0
  144. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/convert_config.py +0 -0
  145. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/converter.py +0 -0
  146. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/converter_core.py +0 -0
  147. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/excel_reader.py +0 -0
  148. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/markdown_emitter.py +0 -0
  149. {mdengine-0.2.2 → mdengine-0.3.0}/src/md_generator/xlsx/mcp_server.py +0 -0
  150. {mdengine-0.2.2 → mdengine-0.3.0}/src/mdengine.egg-info/dependency_links.txt +0 -0
  151. {mdengine-0.2.2 → mdengine-0.3.0}/src/mdengine.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mdengine
3
- Version: 0.2.2
4
- Summary: Convert PDF, Office, images, text/JSON/XML, ZIP archives, and web URLs to Markdown.
3
+ Version: 0.3.0
4
+ Summary: Convert PDF, Office, images, audio, video, text/JSON/XML, ZIP archives, and web URLs to Markdown.
5
5
  Author: mdengine contributors
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://github.com/vishal7090/md-generator
@@ -68,6 +68,12 @@ Requires-Dist: Pillow>=10.0.0; extra == "url-full"
68
68
  Requires-Dist: olefile>=0.47; extra == "url-full"
69
69
  Requires-Dist: openpyxl>=3.1.0; extra == "url-full"
70
70
  Requires-Dist: pytesseract>=0.3.10; extra == "url-full"
71
+ Provides-Extra: audio
72
+ Requires-Dist: openai-whisper>=20231117; extra == "audio"
73
+ Requires-Dist: imageio-ffmpeg>=0.5.1; extra == "audio"
74
+ Provides-Extra: video
75
+ Requires-Dist: openai-whisper>=20231117; extra == "video"
76
+ Requires-Dist: imageio-ffmpeg>=0.5.1; extra == "video"
71
77
  Provides-Extra: api
72
78
  Requires-Dist: fastapi>=0.115.0; extra == "api"
73
79
  Requires-Dist: uvicorn[standard]>=0.32.0; extra == "api"
@@ -112,14 +118,14 @@ Dynamic: license-file
112
118
 
113
119
  # mdengine
114
120
 
115
- Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**, and **ZIP archives** into **Markdown** (and related assets). Install only the extras you need; everything imports under the **`md_generator`** package.
121
+ Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**, **ZIP archives**, and **audio / video** (Whisper transcription → Markdown) into **Markdown** (and related assets). Install only the extras you need; everything imports under the **`md_generator`** package.
116
122
 
117
123
  - **PyPI name:** `mdengine` (import package: `md_generator`)
118
124
  - **Source:** [github.com/vishal7090/md-generator](https://github.com/vishal7090/md-generator)
119
125
  - **Python:** 3.10+
120
126
  - **License:** [MIT](LICENSE)
121
127
 
122
- **Quick links:** [On a new computer](#on-a-new-computer) · [Command-line execution](#command-line-execution) · [Python library](#python-library) · [HTTP API](#http-api-fastapi) · [MCP](#mcp-model-context-protocol) · [Development](#development) · [Code of Conduct](CODE_OF_CONDUCT.md)
128
+ **Quick links:** [On a new computer](#on-a-new-computer) · [Command-line execution](#command-line-execution) · [Python library](#python-library) · [Audio and video](#audio-and-video-to-markdown) · [HTTP API](#http-api-fastapi) · [MCP](#mcp-model-context-protocol) · [Development](#development) · [Code of Conduct](CODE_OF_CONDUCT.md)
123
129
 
124
130
  ---
125
131
 
@@ -186,6 +192,8 @@ pip install "mdengine[all]"
186
192
  | `archive` | ZIP → Markdown layout (Pillow; optional tesseract for inline image OCR) |
187
193
  | `url` | HTTP(S) HTML → Markdown (httpx, readability-lxml, markdownify, BeautifulSoup, lxml) |
188
194
  | `url-full` | `url` plus PDF/Word/PPTX/XLSX/archive stack for **post-converting** downloaded linked files to Markdown |
195
+ | `audio` | **Audio → Markdown** via Whisper (`openai-whisper`); ships `imageio-ffmpeg` for a bundled **ffmpeg** when none is on `PATH` |
196
+ | `video` | **Video → Markdown** (ffmpeg extracts mono 16 kHz WAV, then same Whisper stack as `audio`) |
189
197
  | `api` | FastAPI, uvicorn, httpx, pydantic-settings |
190
198
  | `mcp` | MCP servers (`mcp`, `fastmcp` where used) |
191
199
  | `dev` | pytest + API/MCP test helpers |
@@ -228,6 +236,12 @@ If the shell reports “command not found”, ensure the Python **Scripts** dire
228
236
  | `md-text` | `md_generator.text.converter:main` | `md-text config.xml out.md` |
229
237
  | `md-zip` | `md_generator.archive.converter:main` | `md-zip bundle.zip ./zip-out` |
230
238
  | `md-url` | `md_generator.url.converter:main` | `md-url https://example.com/doc ./web-out --artifact-layout` |
239
+ | `md-audio` | `md_generator.media.audio.converter:main` | `md-audio clip.mp3 transcript.md --model base` |
240
+ | `md-video` | `md_generator.media.video.converter:main` | `md-video clip.mp4 transcript.md --model base` |
241
+ | `md-audio-api` | `md_generator.media.audio.api.run:main` | REST + MCP on port **8011** (see [Audio and video to Markdown](#audio-and-video-to-markdown)) |
242
+ | `md-video-api` | `md_generator.media.video.api.run:main` | REST + MCP on port **8012** |
243
+ | `md-audio-mcp` | `md_generator.media.audio.api.mcp_server:main` | Standalone MCP (`--transport stdio` \| `sse` \| `streamable-http`) |
244
+ | `md-video-mcp` | `md_generator.media.video.api.mcp_server:main` | Same for video |
231
245
 
232
246
  Every command accepts **`-h` / `--help`** for full flags (artifact layout, OCR, ZIP options, etc.).
233
247
 
@@ -245,6 +259,8 @@ md-image ./photos ocr.md --engines tess --strategy best
245
259
  md-text data.json data.md
246
260
  md-zip archive.zip ./unzipped-md
247
261
  md-url https://example.com/page ./page-bundle --artifact-layout
262
+ md-audio ./voice.mp3 ./voice.md --model tiny
263
+ md-video ./screen.mp4 ./screen.md --model base
248
264
  ```
249
265
 
250
266
  **Windows PowerShell** (same commands; use backslashes for paths if you prefer)
@@ -253,6 +269,8 @@ md-url https://example.com/page ./page-bundle --artifact-layout
253
269
  md-pdf .\manual.pdf .\out\doc.md
254
270
  md-zip .\archive.zip .\zip-out
255
271
  md-url https://example.com/page .\page-bundle --artifact-layout
272
+ md-audio .\voice.mp3 .\voice.md --model tiny
273
+ md-video .\screen.mp4 .\screen.md --model base
256
274
  ```
257
275
 
258
276
  **Windows CMD**
@@ -422,6 +440,106 @@ convert_zip(
422
440
 
423
441
  ---
424
442
 
443
+ ## Audio and video to Markdown
444
+
445
+ Library code lives under **`md_generator.media`**: shared probing in [`document_converter.py`](src/md_generator/media/document_converter.py), **audio** in [`media/audio/`](src/md_generator/media/audio/) (Whisper + ffprobe / ffmpeg metadata), **video** in [`media/video/`](src/md_generator/media/video/) (ffmpeg extracts audio only; transcription always goes through the audio service—no duplicate Whisper path in video).
446
+
447
+ ### System requirements
448
+
449
+ - **ffmpeg** (and **ffprobe** when available) on `PATH` for metadata and for **video** demux. If `ffprobe` is missing or misbehaving, metadata falls back to parsing `ffmpeg -i` stderr.
450
+ - Optional **`FFMPEG`** environment variable: absolute path to an `ffmpeg` executable (see [`resolve_ffmpeg_executable()`](src/md_generator/media/document_converter.py)).
451
+ - **GPU** is optional; Whisper runs on CPU if needed (may log FP16→FP32 on CPU).
452
+
453
+ ### Install
454
+
455
+ ```bash
456
+ pip install "mdengine[audio,api,mcp]" # audio CLI + HTTP + MCP
457
+ pip install "mdengine[video,api,mcp]" # video CLI + HTTP + MCP (same ML stack as audio)
458
+ ```
459
+
460
+ ### Python library
461
+
462
+ **Audio** — structured result + Markdown:
463
+
464
+ ```python
465
+ from pathlib import Path
466
+ from md_generator.media.audio import AudioToMarkdownService, AudioConverter
467
+
468
+ svc = AudioToMarkdownService(whisper_model="base") # language omitted → Whisper auto-detect; pass e.g. language="en" to force
469
+ text = svc.to_markdown(Path("input.mp3"), title="My title")
470
+ svc.write_markdown(Path("input.mp3"), Path("out/transcript.md"))
471
+
472
+ result = svc.transcribe(Path("input.wav")) # metadata + segments + plain_text
473
+ ```
474
+
475
+ **Video** — extract → transcribe (via audio) → Markdown:
476
+
477
+ ```python
478
+ from pathlib import Path
479
+ from md_generator.media.video import VideoToMarkdownService
480
+
481
+ svc = VideoToMarkdownService(whisper_model="base") # transcription language omitted → auto-detect
482
+ md = svc.to_markdown(Path("input.mp4"), title=None)
483
+ svc.write_markdown(Path("input.mp4"), Path("out/transcript.md"))
484
+ ```
485
+
486
+ Public symbols are also re-exported from [`md_generator.media`](src/md_generator/media/__init__.py) for ffprobe helpers (`ffprobe_json`, `VideoProbeResult`, …).
487
+
488
+ ### REST API (FastAPI)
489
+
490
+ Each service exposes the same job pattern as other converters:
491
+
492
+ | Endpoint | Description |
493
+ |----------|-------------|
494
+ | `POST /convert/sync` | Multipart field **`file`**; returns **Markdown** body. Query: `whisper_model`, `language` (omit or `auto` for detection; pass a code to force), `title`. |
495
+ | `POST /convert/jobs` | Async upload; returns `{ "job_id", "status" }`. |
496
+ | `GET /convert/jobs/{job_id}` | Status JSON. |
497
+ | `GET /convert/jobs/{job_id}/download` | Markdown when `done`; workspace removed after download. |
498
+
499
+ **Audio** defaults: `MD_AUDIO_MAX_UPLOAD_MB=200`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB=40`, `MD_AUDIO_API_PORT=8011`.
500
+ **Video** defaults: `MD_VIDEO_MAX_UPLOAD_MB=500`, `MD_VIDEO_MAX_SYNC_UPLOAD_MB=80`, `MD_VIDEO_API_PORT=8012`.
501
+
502
+ Run with the bundled runners (each call builds the app with **`factory=True`** for a clean MCP session manager):
503
+
504
+ ```bash
505
+ md-audio-api --host 127.0.0.1 --port 8011
506
+ md-video-api --host 127.0.0.1 --port 8012
507
+ ```
508
+
509
+ Or with Uvicorn directly (the ASGI app is built by **`create_app()`** so each worker gets its own MCP session manager):
510
+
511
+ ```bash
512
+ uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
513
+ uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
514
+ ```
515
+
516
+ The module also defines **`app = create_app()`** for a single-process target: `uvicorn md_generator.media.audio.api.main:app` (no `--factory`).
517
+
518
+ Swagger is at **`/docs`** when the app is running.
519
+
520
+ ### MCP (stdio, SSE, streamable HTTP)
521
+
522
+ 1. **With FastAPI** — start `md-audio-api` or `md-video-api`; mount Streamable HTTP MCP at **`http://<host>:<port>/mcp`** (same host as REST).
523
+ 2. **Standalone** — process speaks MCP only:
524
+
525
+ ```bash
526
+ md-audio-mcp --transport stdio
527
+ md-audio-mcp --transport sse
528
+ md-audio-mcp --transport streamable-http
529
+ md-video-mcp --transport stdio
530
+ ```
531
+
532
+ **Audio MCP tools:** `transcribe_audio_path`, `transcribe_audio_base64`.
533
+ **Video MCP tools:** `transcribe_video_path`, `transcribe_video_base64`.
534
+
535
+ Equivalent modules: `python -m md_generator.media.audio.api.mcp_server`, `python -m md_generator.media.video.api.mcp_server`.
536
+
537
+ ### Thin shims (repo clone)
538
+
539
+ [`audio-to-md/converter.py`](audio-to-md/converter.py) and [`video-to-md/converter.py`](video-to-md/converter.py) delegate to the same `main` as `md-audio` / `md-video`. Tests and `pytest.ini` live under `audio-to-md/tests/` and `video-to-md/tests/`.
540
+
541
+ ---
542
+
425
543
  ## HTTP API (FastAPI)
426
544
 
427
545
  All format APIs follow a similar pattern:
@@ -447,6 +565,8 @@ Install `mdengine[api]` plus the format extra(s), then run the **`app`** object
447
565
  | Text/JSON/XML | `md_generator.text.api.main:app` | `text`, `api`, `mcp` |
448
566
  | ZIP | `md_generator.archive.api.main:app` | `archive`, `api`, `mcp` (+ extras for nested office/PDF) |
449
567
  | URL / HTML | `md_generator.url.api.main:app` | `url`, `api`, `mcp` |
568
+ | Audio (Whisper) | `md_generator.media.audio.api.main:create_app` (use **`--factory`**) or `…main:app` | `audio`, `api`, `mcp` |
569
+ | Video (Whisper) | `md_generator.media.video.api.main:create_app` (use **`--factory`**) or `…main:app` | `video`, `api`, `mcp` |
450
570
 
451
571
  Examples:
452
572
 
@@ -455,6 +575,8 @@ uvicorn md_generator.pdf.api.main:app --host 127.0.0.1 --port 8001
455
575
  uvicorn md_generator.word.api.main:app --host 127.0.0.1 --port 8002
456
576
  uvicorn md_generator.archive.api.main:app --host 127.0.0.1 --port 8010
457
577
  uvicorn md_generator.url.api.main:app --host 127.0.0.1 --port 8011
578
+ uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
579
+ uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
458
580
  ```
459
581
 
460
582
  ### MCP over HTTP on the same server
@@ -474,6 +596,8 @@ Prefixes differ per service (often read from a `.env` file next to the process):
474
596
  | Text | `TXT_JSON_XML_TO_MD_` | same pattern |
475
597
  | XLSX | `XLSX_TO_MD_` | `XLSX_TO_MD_TEMP_DIR`, `XLSX_TO_MD_CORS_ORIGINS`, etc. (see `md_generator.xlsx.api.app`) |
476
598
  | URL | `URL_TO_MD_` | `URL_TO_MD_MAX_SYNC_URLS`, `URL_TO_MD_MAX_SYNC_CRAWL_PAGES`, `URL_TO_MD_MAX_JOB_URLS`, `URL_TO_MD_JOB_TTL_SECONDS`, `URL_TO_MD_TEMP_DIR`, `URL_TO_MD_CORS_ORIGINS` |
599
+ | Audio API | `MD_AUDIO_` | `MD_AUDIO_MAX_UPLOAD_MB`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB`, `MD_AUDIO_JOB_TTL_SECONDS`, `MD_AUDIO_TEMP_DIR`, `MD_AUDIO_CORS_ORIGINS`, `MD_AUDIO_API_HOST`, `MD_AUDIO_API_PORT` |
600
+ | Video API | `MD_VIDEO_` | Same pattern as audio with `MD_VIDEO_*` (defaults: larger upload/sync caps, port **8012**) |
477
601
 
478
602
  Exact variable names match the `ApiSettings` / helper functions in each `api/settings` or `api/app` module.
479
603
 
@@ -497,6 +621,8 @@ Two usage patterns:
497
621
  | PPTX | `python -m md_generator.ppt.api.mcp_server` (see module docstring for flags) |
498
622
  | Image | `python -m md_generator.image.api.mcp_server` (see module for CLI) |
499
623
  | URL / HTML | `python -m md_generator.url.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
624
+ | Audio | `md-audio-mcp` or `python -m md_generator.media.audio.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
625
+ | Video | `md-video-mcp` or `python -m md_generator.media.video.api.mcp_server` — same transports |
500
626
 
501
627
  **Word** and **XLSX** also ship a small runner script in the repo:
502
628
 
@@ -531,7 +657,7 @@ Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/test
531
657
  |------|------|
532
658
  | `LICENSE` | MIT license text |
533
659
  | `CODE_OF_CONDUCT.md` | [Contributor Covenant](https://www.contributor-covenant.org/) 2.1 |
534
- | `src/md_generator/` | **Library source** (all formats + `api` subpackages) |
660
+ | `src/md_generator/` | **Library source** (all formats + `api` subpackages); **audio/video** under [`media/audio/`](src/md_generator/media/audio/) and [`media/video/`](src/md_generator/media/video/) |
535
661
  | `pyproject.toml` | Packaging, extras, CLI entry points, pytest |
536
662
  | `*-to-md/` | **Docs, tests, fixtures**, thin `converter.py` shims, some `run.py` helpers |
537
663
  | `README.md` | This document |
@@ -1,13 +1,13 @@
1
1
  # mdengine
2
2
 
3
- Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**, and **ZIP archives** into **Markdown** (and related assets). Install only the extras you need; everything imports under the **`md_generator`** package.
3
+ Single Python distribution for converting **PDF**, **Word (.docx)**, **PowerPoint (.pptx)**, **Excel (.xlsx/.xlsm)**, **images** (OCR), **plain text / JSON / XML**, **ZIP archives**, and **audio / video** (Whisper transcription → Markdown) into **Markdown** (and related assets). Install only the extras you need; everything imports under the **`md_generator`** package.
4
4
 
5
5
  - **PyPI name:** `mdengine` (import package: `md_generator`)
6
6
  - **Source:** [github.com/vishal7090/md-generator](https://github.com/vishal7090/md-generator)
7
7
  - **Python:** 3.10+
8
8
  - **License:** [MIT](LICENSE)
9
9
 
10
- **Quick links:** [On a new computer](#on-a-new-computer) · [Command-line execution](#command-line-execution) · [Python library](#python-library) · [HTTP API](#http-api-fastapi) · [MCP](#mcp-model-context-protocol) · [Development](#development) · [Code of Conduct](CODE_OF_CONDUCT.md)
10
+ **Quick links:** [On a new computer](#on-a-new-computer) · [Command-line execution](#command-line-execution) · [Python library](#python-library) · [Audio and video](#audio-and-video-to-markdown) · [HTTP API](#http-api-fastapi) · [MCP](#mcp-model-context-protocol) · [Development](#development) · [Code of Conduct](CODE_OF_CONDUCT.md)
11
11
 
12
12
  ---
13
13
 
@@ -74,6 +74,8 @@ pip install "mdengine[all]"
74
74
  | `archive` | ZIP → Markdown layout (Pillow; optional tesseract for inline image OCR) |
75
75
  | `url` | HTTP(S) HTML → Markdown (httpx, readability-lxml, markdownify, BeautifulSoup, lxml) |
76
76
  | `url-full` | `url` plus PDF/Word/PPTX/XLSX/archive stack for **post-converting** downloaded linked files to Markdown |
77
+ | `audio` | **Audio → Markdown** via Whisper (`openai-whisper`); ships `imageio-ffmpeg` for a bundled **ffmpeg** when none is on `PATH` |
78
+ | `video` | **Video → Markdown** (ffmpeg extracts mono 16 kHz WAV, then same Whisper stack as `audio`) |
77
79
  | `api` | FastAPI, uvicorn, httpx, pydantic-settings |
78
80
  | `mcp` | MCP servers (`mcp`, `fastmcp` where used) |
79
81
  | `dev` | pytest + API/MCP test helpers |
@@ -116,6 +118,12 @@ If the shell reports “command not found”, ensure the Python **Scripts** dire
116
118
  | `md-text` | `md_generator.text.converter:main` | `md-text config.xml out.md` |
117
119
  | `md-zip` | `md_generator.archive.converter:main` | `md-zip bundle.zip ./zip-out` |
118
120
  | `md-url` | `md_generator.url.converter:main` | `md-url https://example.com/doc ./web-out --artifact-layout` |
121
+ | `md-audio` | `md_generator.media.audio.converter:main` | `md-audio clip.mp3 transcript.md --model base` |
122
+ | `md-video` | `md_generator.media.video.converter:main` | `md-video clip.mp4 transcript.md --model base` |
123
+ | `md-audio-api` | `md_generator.media.audio.api.run:main` | REST + MCP on port **8011** (see [Audio and video to Markdown](#audio-and-video-to-markdown)) |
124
+ | `md-video-api` | `md_generator.media.video.api.run:main` | REST + MCP on port **8012** |
125
+ | `md-audio-mcp` | `md_generator.media.audio.api.mcp_server:main` | Standalone MCP (`--transport stdio` \| `sse` \| `streamable-http`) |
126
+ | `md-video-mcp` | `md_generator.media.video.api.mcp_server:main` | Same for video |
119
127
 
120
128
  Every command accepts **`-h` / `--help`** for full flags (artifact layout, OCR, ZIP options, etc.).
121
129
 
@@ -133,6 +141,8 @@ md-image ./photos ocr.md --engines tess --strategy best
133
141
  md-text data.json data.md
134
142
  md-zip archive.zip ./unzipped-md
135
143
  md-url https://example.com/page ./page-bundle --artifact-layout
144
+ md-audio ./voice.mp3 ./voice.md --model tiny
145
+ md-video ./screen.mp4 ./screen.md --model base
136
146
  ```
137
147
 
138
148
  **Windows PowerShell** (same commands; use backslashes for paths if you prefer)
@@ -141,6 +151,8 @@ md-url https://example.com/page ./page-bundle --artifact-layout
141
151
  md-pdf .\manual.pdf .\out\doc.md
142
152
  md-zip .\archive.zip .\zip-out
143
153
  md-url https://example.com/page .\page-bundle --artifact-layout
154
+ md-audio .\voice.mp3 .\voice.md --model tiny
155
+ md-video .\screen.mp4 .\screen.md --model base
144
156
  ```
145
157
 
146
158
  **Windows CMD**
@@ -310,6 +322,106 @@ convert_zip(
310
322
 
311
323
  ---
312
324
 
325
+ ## Audio and video to Markdown
326
+
327
+ Library code lives under **`md_generator.media`**: shared probing in [`document_converter.py`](src/md_generator/media/document_converter.py), **audio** in [`media/audio/`](src/md_generator/media/audio/) (Whisper + ffprobe / ffmpeg metadata), **video** in [`media/video/`](src/md_generator/media/video/) (ffmpeg extracts audio only; transcription always goes through the audio service—no duplicate Whisper path in video).
328
+
329
+ ### System requirements
330
+
331
+ - **ffmpeg** (and **ffprobe** when available) on `PATH` for metadata and for **video** demux. If `ffprobe` is missing or misbehaving, metadata falls back to parsing `ffmpeg -i` stderr.
332
+ - Optional **`FFMPEG`** environment variable: absolute path to an `ffmpeg` executable (see [`resolve_ffmpeg_executable()`](src/md_generator/media/document_converter.py)).
333
+ - **GPU** is optional; Whisper runs on CPU if needed (may log FP16→FP32 on CPU).
334
+
335
+ ### Install
336
+
337
+ ```bash
338
+ pip install "mdengine[audio,api,mcp]" # audio CLI + HTTP + MCP
339
+ pip install "mdengine[video,api,mcp]" # video CLI + HTTP + MCP (same ML stack as audio)
340
+ ```
341
+
342
+ ### Python library
343
+
344
+ **Audio** — structured result + Markdown:
345
+
346
+ ```python
347
+ from pathlib import Path
348
+ from md_generator.media.audio import AudioToMarkdownService, AudioConverter
349
+
350
+ svc = AudioToMarkdownService(whisper_model="base") # language omitted → Whisper auto-detect; pass e.g. language="en" to force
351
+ text = svc.to_markdown(Path("input.mp3"), title="My title")
352
+ svc.write_markdown(Path("input.mp3"), Path("out/transcript.md"))
353
+
354
+ result = svc.transcribe(Path("input.wav")) # metadata + segments + plain_text
355
+ ```
356
+
357
+ **Video** — extract → transcribe (via audio) → Markdown:
358
+
359
+ ```python
360
+ from pathlib import Path
361
+ from md_generator.media.video import VideoToMarkdownService
362
+
363
+ svc = VideoToMarkdownService(whisper_model="base") # transcription language omitted → auto-detect
364
+ md = svc.to_markdown(Path("input.mp4"), title=None)
365
+ svc.write_markdown(Path("input.mp4"), Path("out/transcript.md"))
366
+ ```
367
+
368
+ Public symbols are also re-exported from [`md_generator.media`](src/md_generator/media/__init__.py) for ffprobe helpers (`ffprobe_json`, `VideoProbeResult`, …).
369
+
370
+ ### REST API (FastAPI)
371
+
372
+ Each service exposes the same job pattern as other converters:
373
+
374
+ | Endpoint | Description |
375
+ |----------|-------------|
376
+ | `POST /convert/sync` | Multipart field **`file`**; returns **Markdown** body. Query: `whisper_model`, `language` (omit or `auto` for detection; pass a code to force), `title`. |
377
+ | `POST /convert/jobs` | Async upload; returns `{ "job_id", "status" }`. |
378
+ | `GET /convert/jobs/{job_id}` | Status JSON. |
379
+ | `GET /convert/jobs/{job_id}/download` | Markdown when `done`; workspace removed after download. |
380
+
381
+ **Audio** defaults: `MD_AUDIO_MAX_UPLOAD_MB=200`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB=40`, `MD_AUDIO_API_PORT=8011`.
382
+ **Video** defaults: `MD_VIDEO_MAX_UPLOAD_MB=500`, `MD_VIDEO_MAX_SYNC_UPLOAD_MB=80`, `MD_VIDEO_API_PORT=8012`.
383
+
384
+ Run with the bundled runners (each call builds the app with **`factory=True`** for a clean MCP session manager):
385
+
386
+ ```bash
387
+ md-audio-api --host 127.0.0.1 --port 8011
388
+ md-video-api --host 127.0.0.1 --port 8012
389
+ ```
390
+
391
+ Or with Uvicorn directly (the ASGI app is built by **`create_app()`** so each worker gets its own MCP session manager):
392
+
393
+ ```bash
394
+ uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
395
+ uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
396
+ ```
397
+
398
+ The module also defines **`app = create_app()`** for a single-process target: `uvicorn md_generator.media.audio.api.main:app` (no `--factory`).
399
+
400
+ Swagger is at **`/docs`** when the app is running.
401
+
402
+ ### MCP (stdio, SSE, streamable HTTP)
403
+
404
+ 1. **With FastAPI** — start `md-audio-api` or `md-video-api`; mount Streamable HTTP MCP at **`http://<host>:<port>/mcp`** (same host as REST).
405
+ 2. **Standalone** — process speaks MCP only:
406
+
407
+ ```bash
408
+ md-audio-mcp --transport stdio
409
+ md-audio-mcp --transport sse
410
+ md-audio-mcp --transport streamable-http
411
+ md-video-mcp --transport stdio
412
+ ```
413
+
414
+ **Audio MCP tools:** `transcribe_audio_path`, `transcribe_audio_base64`.
415
+ **Video MCP tools:** `transcribe_video_path`, `transcribe_video_base64`.
416
+
417
+ Equivalent modules: `python -m md_generator.media.audio.api.mcp_server`, `python -m md_generator.media.video.api.mcp_server`.
418
+
419
+ ### Thin shims (repo clone)
420
+
421
+ [`audio-to-md/converter.py`](audio-to-md/converter.py) and [`video-to-md/converter.py`](video-to-md/converter.py) delegate to the same `main` as `md-audio` / `md-video`. Tests and `pytest.ini` live under `audio-to-md/tests/` and `video-to-md/tests/`.
422
+
423
+ ---
424
+
313
425
  ## HTTP API (FastAPI)
314
426
 
315
427
  All format APIs follow a similar pattern:
@@ -335,6 +447,8 @@ Install `mdengine[api]` plus the format extra(s), then run the **`app`** object
335
447
  | Text/JSON/XML | `md_generator.text.api.main:app` | `text`, `api`, `mcp` |
336
448
  | ZIP | `md_generator.archive.api.main:app` | `archive`, `api`, `mcp` (+ extras for nested office/PDF) |
337
449
  | URL / HTML | `md_generator.url.api.main:app` | `url`, `api`, `mcp` |
450
+ | Audio (Whisper) | `md_generator.media.audio.api.main:create_app` (use **`--factory`**) or `…main:app` | `audio`, `api`, `mcp` |
451
+ | Video (Whisper) | `md_generator.media.video.api.main:create_app` (use **`--factory`**) or `…main:app` | `video`, `api`, `mcp` |
338
452
 
339
453
  Examples:
340
454
 
@@ -343,6 +457,8 @@ uvicorn md_generator.pdf.api.main:app --host 127.0.0.1 --port 8001
343
457
  uvicorn md_generator.word.api.main:app --host 127.0.0.1 --port 8002
344
458
  uvicorn md_generator.archive.api.main:app --host 127.0.0.1 --port 8010
345
459
  uvicorn md_generator.url.api.main:app --host 127.0.0.1 --port 8011
460
+ uvicorn md_generator.media.audio.api.main:create_app --factory --host 127.0.0.1 --port 8011
461
+ uvicorn md_generator.media.video.api.main:create_app --factory --host 127.0.0.1 --port 8012
346
462
  ```
347
463
 
348
464
  ### MCP over HTTP on the same server
@@ -362,6 +478,8 @@ Prefixes differ per service (often read from a `.env` file next to the process):
362
478
  | Text | `TXT_JSON_XML_TO_MD_` | same pattern |
363
479
  | XLSX | `XLSX_TO_MD_` | `XLSX_TO_MD_TEMP_DIR`, `XLSX_TO_MD_CORS_ORIGINS`, etc. (see `md_generator.xlsx.api.app`) |
364
480
  | URL | `URL_TO_MD_` | `URL_TO_MD_MAX_SYNC_URLS`, `URL_TO_MD_MAX_SYNC_CRAWL_PAGES`, `URL_TO_MD_MAX_JOB_URLS`, `URL_TO_MD_JOB_TTL_SECONDS`, `URL_TO_MD_TEMP_DIR`, `URL_TO_MD_CORS_ORIGINS` |
481
+ | Audio API | `MD_AUDIO_` | `MD_AUDIO_MAX_UPLOAD_MB`, `MD_AUDIO_MAX_SYNC_UPLOAD_MB`, `MD_AUDIO_JOB_TTL_SECONDS`, `MD_AUDIO_TEMP_DIR`, `MD_AUDIO_CORS_ORIGINS`, `MD_AUDIO_API_HOST`, `MD_AUDIO_API_PORT` |
482
+ | Video API | `MD_VIDEO_` | Same pattern as audio with `MD_VIDEO_*` (defaults: larger upload/sync caps, port **8012**) |
365
483
 
366
484
  Exact variable names match the `ApiSettings` / helper functions in each `api/settings` or `api/app` module.
367
485
 
@@ -385,6 +503,8 @@ Two usage patterns:
385
503
  | PPTX | `python -m md_generator.ppt.api.mcp_server` (see module docstring for flags) |
386
504
  | Image | `python -m md_generator.image.api.mcp_server` (see module for CLI) |
387
505
  | URL / HTML | `python -m md_generator.url.api.mcp_server` / `--transport sse` / `--transport streamable-http` |
506
+ | Audio | `md-audio-mcp` or `python -m md_generator.media.audio.api.mcp_server` — `--transport stdio` (default), `sse`, `streamable-http` |
507
+ | Video | `md-video-mcp` or `python -m md_generator.media.video.api.mcp_server` — same transports |
388
508
 
389
509
  **Word** and **XLSX** also ship a small runner script in the repo:
390
510
 
@@ -419,7 +539,7 @@ Tests live under each legacy folder’s `tests/` directory (e.g. `pdf-to-md/test
419
539
  |------|------|
420
540
  | `LICENSE` | MIT license text |
421
541
  | `CODE_OF_CONDUCT.md` | [Contributor Covenant](https://www.contributor-covenant.org/) 2.1 |
422
- | `src/md_generator/` | **Library source** (all formats + `api` subpackages) |
542
+ | `src/md_generator/` | **Library source** (all formats + `api` subpackages); **audio/video** under [`media/audio/`](src/md_generator/media/audio/) and [`media/video/`](src/md_generator/media/video/) |
423
543
  | `pyproject.toml` | Packaging, extras, CLI entry points, pytest |
424
544
  | `*-to-md/` | **Docs, tests, fixtures**, thin `converter.py` shims, some `run.py` helpers |
425
545
  | `README.md` | This document |
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mdengine"
7
- version = "0.2.2"
8
- description = "Convert PDF, Office, images, text/JSON/XML, ZIP archives, and web URLs to Markdown."
7
+ version = "0.3.0"
8
+ description = "Convert PDF, Office, images, audio, video, text/JSON/XML, ZIP archives, and web URLs to Markdown."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
11
11
  license = "MIT"
@@ -72,6 +72,10 @@ url-full = [
72
72
  "openpyxl>=3.1.0",
73
73
  "pytesseract>=0.3.10",
74
74
  ]
75
+ # Whisper + PyTorch; metadata uses ffprobe when available, else ``ffmpeg -i`` (see imageio-ffmpeg).
76
+ audio = ["openai-whisper>=20231117", "imageio-ffmpeg>=0.5.1"]
77
+ # Same ML stack as audio; ships a bundled ``ffmpeg`` binary when the system has none.
78
+ video = ["openai-whisper>=20231117", "imageio-ffmpeg>=0.5.1"]
75
79
  api = [
76
80
  "fastapi>=0.115.0",
77
81
  "uvicorn[standard]>=0.32.0",
@@ -128,6 +132,12 @@ md-image = "md_generator.image.converter:main"
128
132
  md-text = "md_generator.text.converter:main"
129
133
  md-zip = "md_generator.archive.converter:main"
130
134
  md-url = "md_generator.url.converter:main"
135
+ md-audio = "md_generator.media.audio.converter:main"
136
+ md-video = "md_generator.media.video.converter:main"
137
+ md-audio-api = "md_generator.media.audio.api.run:main"
138
+ md-video-api = "md_generator.media.video.api.run:main"
139
+ md-audio-mcp = "md_generator.media.audio.api.mcp_server:main"
140
+ md-video-mcp = "md_generator.media.video.api.mcp_server:main"
131
141
 
132
142
  [tool.setuptools.packages.find]
133
143
  where = ["src"]
@@ -143,5 +153,7 @@ testpaths = [
143
153
  "txt-json-xml-to-md/tests",
144
154
  "zip-to-md/tests",
145
155
  "url-to-md/tests",
156
+ "audio-to-md/tests",
157
+ "video-to-md/tests",
146
158
  ]
147
159
  markers = ["integration: optional dependency or slower checks"]
@@ -1,5 +1,5 @@
1
1
  """md_generator: PDF, Office, image, text, and ZIP to Markdown conversion."""
2
2
 
3
- __version__ = "0.2.2"
3
+ __version__ = "0.3.0"
4
4
 
5
5
  __all__ = ["__version__"]
@@ -0,0 +1,21 @@
1
+ """Media helpers: document probing (ffprobe/ffmpeg) and audio/video to Markdown."""
2
+
3
+ from md_generator.media.document_converter import (
4
+ DocumentConverter,
5
+ MediaToolsError,
6
+ VideoProbeResult,
7
+ ffprobe_json,
8
+ require_ffmpeg_tools,
9
+ resolve_ffmpeg_executable,
10
+ video_probe_from_ffprobe,
11
+ )
12
+
13
+ __all__ = [
14
+ "DocumentConverter",
15
+ "MediaToolsError",
16
+ "VideoProbeResult",
17
+ "ffprobe_json",
18
+ "require_ffmpeg_tools",
19
+ "resolve_ffmpeg_executable",
20
+ "video_probe_from_ffprobe",
21
+ ]
@@ -0,0 +1,18 @@
1
+ from md_generator.media.audio.converter import (
2
+ AudioConverter,
3
+ MediaMetadata,
4
+ TranscriptSegment,
5
+ TranscriptionResult,
6
+ )
7
+ from md_generator.media.audio.formatter import AudioMarkdownFormatter, format_timestamped_transcript
8
+ from md_generator.media.audio.service import AudioToMarkdownService
9
+
10
+ __all__ = [
11
+ "AudioConverter",
12
+ "AudioMarkdownFormatter",
13
+ "AudioToMarkdownService",
14
+ "MediaMetadata",
15
+ "TranscriptSegment",
16
+ "TranscriptionResult",
17
+ "format_timestamped_transcript",
18
+ ]
@@ -0,0 +1 @@
1
+ """REST + MCP (Streamable HTTP under ``/mcp``) for audio-to-Markdown."""