wang.lingxiao commited on
Commit
bffa120
·
1 Parent(s): 1c196a0
Files changed (1) hide show
  1. app.py +388 -1
app.py CHANGED
@@ -1 +1,388 @@
1
- import gradio as grimport refrom typing import Dict, Any, Optionalimport osfrom pathlib import Path# Import dependencies for PDF and DOCX processingtry: import docx DOCX_AVAILABLE = Trueexcept ImportError: DOCX_AVAILABLE = Falsetry: import fitz # PyMuPDF PDF_AVAILABLE = Trueexcept ImportError: PDF_AVAILABLE = Falseclass DocumentToMarkdownConverter: def __init__(self): self.elements = [] def extract_from_docx(self, docx_path: str) -> str: """Extract content from DOCX and convert to Markdown""" if not DOCX_AVAILABLE: raise ImportError("python-docx not installed. Run: pip install python-docx") doc = docx.Document(docx_path) markdown_content = [] # Process paragraphs for paragraph in doc.paragraphs: if paragraph.text.strip(): md_text = self._convert_paragraph_to_markdown(paragraph) if md_text: markdown_content.append(md_text) # Process tables for table in doc.tables: md_table = self._convert_table_to_markdown(table) if md_table: markdown_content.append(md_table) return '\n\n'.join(markdown_content) def extract_from_pdf(self, pdf_path: str) -> str: """Extract content from PDF and convert to Markdown""" if not PDF_AVAILABLE: raise ImportError("PyMuPDF not installed. Run: pip install PyMuPDF") doc = fitz.open(pdf_path) markdown_content = [] for page_num in range(len(doc)): page = doc.load_page(page_num) # Extract text blocks with formatting blocks = page.get_text("dict") page_markdown = self._convert_pdf_blocks_to_markdown(blocks) if page_markdown.strip(): markdown_content.append(f"## Page {page_num + 1}\n\n{page_markdown}") doc.close() return '\n\n---\n\n'.join(markdown_content) def _convert_paragraph_to_markdown(self, paragraph) -> str: """Convert DOCX paragraph to Markdown""" text = paragraph.text.strip() if not text: return "" style_name = paragraph.style.name if paragraph.style else "Normal" # Check if paragraph has bold formatting is_bold = any(run.bold for run in paragraph.runs if run.bold) # Check font size for heading detection font_size = 12 if paragraph.runs: first_run = paragraph.runs[0] if first_run.font.size: font_size = first_run.font.size.pt # Convert based on style and formatting if "Title" in style_name or (is_bold and font_size >= 18): return f"# {text}" elif "Heading 1" in style_name or (is_bold and font_size >= 16): return f"# {text}" elif "Heading 2" in style_name or (is_bold and font_size >= 14): return f"## {text}" elif "Heading 3" in style_name or (is_bold and font_size >= 13): return f"### {text}" elif "Heading 4" in style_name: return f"#### {text}" elif "Heading 5" in style_name: return f"##### {text}" elif "Heading 6" in style_name: return f"###### {text}" elif re.match(r"^[\d\w]\.\s|^[•\-\*]\s|^\d+\)\s", text): # List items if text.startswith(('1.', '2.', '3.', '4.', '5.', '6.', '7.', '8.', '9.')): return f"1. {text[2:].strip()}" else: return f"- {text[1:].strip() if text[0] in '•-*' else text}" else: # Regular paragraph formatted_text = self._apply_inline_formatting(paragraph) return formatted_text def _apply_inline_formatting(self, paragraph) -> str: """Apply inline formatting (bold, italic) to text""" result = "" for run in paragraph.runs: text = run.text if run.bold and run.italic: text = f"***{text}***" elif run.bold: text = f"**{text}**" elif run.italic: text = f"*{text}*" result += text return result def _convert_table_to_markdown(self, table) -> str: """Convert DOCX table to Markdown table""" if not table.rows: return "" markdown_rows = [] # Process header row header_cells = [cell.text.strip() for cell in table.rows[0].cells] markdown_rows.append("| " + " | ".join(header_cells) + " |") markdown_rows.append("| " + " | ".join(["---"] * len(header_cells)) + " |") # Process data rows for row in table.rows[1:]: cells = [cell.text.strip() for cell in row.cells] markdown_rows.append("| " + " | ".join(cells) + " |") return "\n".join(markdown_rows) def _convert_pdf_blocks_to_markdown(self, blocks_dict) -> str: """Convert PDF text blocks to Markdown""" markdown_lines = [] for block in blocks_dict.get("blocks", []): if block.get("type") == 0: # Text block for line in block.get("lines", []): line_text = "" for span in line.get("spans", []): text = span.get("text", "").strip() if text: # Check formatting font_size = span.get("size", 12) flags = span.get("flags", 0) # Bold = flags & 16, Italic = flags & 2 is_bold = bool(flags & 16) is_italic = bool(flags & 2) # Apply formatting if is_bold and is_italic: text = f"***{text}***" elif is_bold: text = f"**{text}**" elif is_italic: text = f"*{text}*" # Check if it's a heading based on font size if font_size >= 18: text = f"# {text}" elif font_size >= 16: text = f"## {text}" elif font_size >= 14: text = f"### {text}" line_text += text + " " if line_text.strip(): markdown_lines.append(line_text.strip()) return "\n\n".join(markdown_lines) def analyze_markdown_structure(self, markdown_text: str) -> Dict[str, Any]: """Analyze the structure of extracted Markdown""" lines = markdown_text.split('\n') structure = { "headings": {"h1": 0, "h2": 0, "h3": 0, "h4": 0, "h5": 0, "h6": 0}, "lists": {"ordered": 0, "unordered": 0}, "tables": 0, "paragraphs": 0, "bold_text": 0, "italic_text": 0, "total_lines": len(lines), "word_count": len(markdown_text.split()), "character_count": len(markdown_text) } in_table = False for line in lines: line = line.strip() if not line: continue # Count headings if line.startswith('#'): level = len(line) - len(line.lstrip('#')) if level <= 6: structure["headings"][f"h{level}"] += 1 # Count lists elif re.match(r'^\d+\.\s', line): structure["lists"]["ordered"] += 1 elif re.match(r'^[\-\*\+]\s', line): structure["lists"]["unordered"] += 1 # Count tables elif '|' in line and not in_table: structure["tables"] += 1 in_table = True elif '|' not in line: in_table = False if line and not line.startswith('#') and not re.match(r'^[\-\*\+\d]', line): structure["paragraphs"] += 1 # Count formatting structure["bold_text"] += len(re.findall(r'\*\*[^*]+\*\*', line)) structure["italic_text"] += len(re.findall(r'\*[^*]+\*', line)) return structuredef extract_document_to_markdown(file_path: str) -> Dict[str, Any]: """ Extract document content and convert to Markdown format Args: file_path: Path to PDF or DOCX file Returns: Dictionary containing markdown content and structure analysis """ if not file_path or not os.path.exists(file_path): return {"error": "File not found", "markdown": "", "structure": {}} converter = DocumentToMarkdownConverter() file_extension = Path(file_path).suffix.lower() try: if file_extension == ".docx": if not DOCX_AVAILABLE: return { "error": "python-docx not installed. Run: pip install python-docx", "markdown": "", "structure": {} } markdown_content = converter.extract_from_docx(file_path) elif file_extension == ".pdf": if not PDF_AVAILABLE: return { "error": "PyMuPDF not installed. Run: pip install PyMuPDF", "markdown": "", "structure": {} } markdown_content = converter.extract_from_pdf(file_path) else: return { "error": f"Unsupported file type: {file_extension}. Only PDF and DOCX files are supported.", "markdown": "", "structure": {} } # Analyze markdown structure structure = converter.analyze_markdown_structure(markdown_content) return { "success": True, "file_info": { "name": Path(file_path).name, "type": file_extension.upper()[1:], "size_kb": round(os.path.getsize(file_path) / 1024, 2) }, "markdown": markdown_content, "structure": structure, "preview": markdown_content[:500] + "..." if len(markdown_content) > 500 else markdown_content } except Exception as e: return { "error": f"Error processing file: {str(e)}", "markdown": "", "structure": {} }# Create Gradio interfacedef create_interface(): with gr.Blocks(title="Document to Markdown Converter") as demo: gr.Markdown("# 📄 Document to Markdown Converter") gr.Markdown("Upload PDF or DOCX files to extract content and convert to Markdown format") missing_deps = [] if not DOCX_AVAILABLE: missing_deps.append("python-docx") if not PDF_AVAILABLE: missing_deps.append("PyMuPDF") if missing_deps: gr.Markdown( f"⚠️ **Missing dependencies**: Run `pip install {' '.join(missing_deps)}` to enable full support" ) with gr.Row(): with gr.Column(scale=1): file_input = gr.File( label="Upload Document", file_types=[".pdf", ".docx"], type="filepath" ) extract_btn = gr.Button("Extract to Markdown", variant="primary") with gr.Accordion("Output Options", open=False): show_structure = gr.Checkbox(label="Show Structure Analysis", value=True) show_preview = gr.Checkbox(label="Show Preview Only", value=False) with gr.Column(scale=2): with gr.Tabs(): with gr.TabItem("Markdown Output"): markdown_output = gr.Textbox( label="Extracted Markdown", lines=20, max_lines=30, show_copy_button=True ) with gr.TabItem("Structure Analysis"): structure_output = gr.JSON(label="Document Structure") with gr.TabItem("File Info"): info_output = gr.JSON(label="File Information") def process_document(file_path, show_struct, show_prev): if not file_path: return "No file uploaded", {}, {} result = extract_document_to_markdown(file_path) if "error" in result: return f"Error: {result['error']}", {}, {} markdown_text = result["preview"] if show_prev else result["markdown"] structure = result["structure"] if show_struct else {} file_info = result["file_info"] return markdown_text, structure, file_info extract_btn.click( fn=process_document, inputs=[file_input, show_structure, show_preview], outputs=[markdown_output, structure_output, info_output] ) return demoif __name__ == "__main__": demo = create_interface() demo.launch(mcp_server=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import re
3
+ from typing import Dict, Any, Optional
4
+ import os
5
+ from pathlib import Path
6
+
7
+ # Import dependencies for PDF and DOCX processing
8
+ try:
9
+ import docx
10
+
11
+ DOCX_AVAILABLE = True
12
+ except ImportError:
13
+ DOCX_AVAILABLE = False
14
+
15
+ try:
16
+ import fitz # PyMuPDF
17
+
18
+ PDF_AVAILABLE = True
19
+ except ImportError:
20
+ PDF_AVAILABLE = False
21
+
22
+
23
+ class DocumentToMarkdownConverter:
24
+ def __init__(self):
25
+ self.elements = []
26
+
27
+ def extract_from_docx(self, docx_path: str) -> str:
28
+ """Extract content from DOCX and convert to Markdown"""
29
+ if not DOCX_AVAILABLE:
30
+ raise ImportError("python-docx not installed. Run: pip install python-docx")
31
+
32
+ doc = docx.Document(docx_path)
33
+ markdown_content = []
34
+
35
+ # Process paragraphs
36
+ for paragraph in doc.paragraphs:
37
+ if paragraph.text.strip():
38
+ md_text = self._convert_paragraph_to_markdown(paragraph)
39
+ if md_text:
40
+ markdown_content.append(md_text)
41
+
42
+ # Process tables
43
+ for table in doc.tables:
44
+ md_table = self._convert_table_to_markdown(table)
45
+ if md_table:
46
+ markdown_content.append(md_table)
47
+
48
+ return "\n\n".join(markdown_content)
49
+
50
+ def extract_from_pdf(self, pdf_path: str) -> str:
51
+ """Extract content from PDF and convert to Markdown"""
52
+ if not PDF_AVAILABLE:
53
+ raise ImportError("PyMuPDF not installed. Run: pip install PyMuPDF")
54
+
55
+ doc = fitz.open(pdf_path)
56
+ markdown_content = []
57
+
58
+ for page_num in range(len(doc)):
59
+ page = doc.load_page(page_num)
60
+
61
+ # Extract text blocks with formatting
62
+ blocks = page.get_text("dict")
63
+ page_markdown = self._convert_pdf_blocks_to_markdown(blocks)
64
+
65
+ if page_markdown.strip():
66
+ markdown_content.append(f"## Page {page_num + 1}\n\n{page_markdown}")
67
+
68
+ doc.close()
69
+ return "\n\n---\n\n".join(markdown_content)
70
+
71
+ def _convert_paragraph_to_markdown(self, paragraph) -> str:
72
+ """Convert DOCX paragraph to Markdown"""
73
+ text = paragraph.text.strip()
74
+ if not text:
75
+ return ""
76
+
77
+ style_name = paragraph.style.name if paragraph.style else "Normal"
78
+
79
+ # Check if paragraph has bold formatting
80
+ is_bold = any(run.bold for run in paragraph.runs if run.bold)
81
+
82
+ # Check font size for heading detection
83
+ font_size = 12
84
+ if paragraph.runs:
85
+ first_run = paragraph.runs[0]
86
+ if first_run.font.size:
87
+ font_size = first_run.font.size.pt
88
+
89
+ # Convert based on style and formatting
90
+ if "Title" in style_name or (is_bold and font_size >= 18):
91
+ return f"# {text}"
92
+ elif "Heading 1" in style_name or (is_bold and font_size >= 16):
93
+ return f"# {text}"
94
+ elif "Heading 2" in style_name or (is_bold and font_size >= 14):
95
+ return f"## {text}"
96
+ elif "Heading 3" in style_name or (is_bold and font_size >= 13):
97
+ return f"### {text}"
98
+ elif "Heading 4" in style_name:
99
+ return f"#### {text}"
100
+ elif "Heading 5" in style_name:
101
+ return f"##### {text}"
102
+ elif "Heading 6" in style_name:
103
+ return f"###### {text}"
104
+ elif re.match(r"^[\d\w]\.\s|^[•\-\*]\s|^\d+\)\s", text):
105
+ # List items
106
+ if text.startswith(("1.", "2.", "3.", "4.", "5.", "6.", "7.", "8.", "9.")):
107
+ return f"1. {text[2:].strip()}"
108
+ else:
109
+ return f"- {text[1:].strip() if text[0] in '•-*' else text}"
110
+ else:
111
+ # Regular paragraph
112
+ formatted_text = self._apply_inline_formatting(paragraph)
113
+ return formatted_text
114
+
115
+ def _apply_inline_formatting(self, paragraph) -> str:
116
+ """Apply inline formatting (bold, italic) to text"""
117
+ result = ""
118
+ for run in paragraph.runs:
119
+ text = run.text
120
+ if run.bold and run.italic:
121
+ text = f"***{text}***"
122
+ elif run.bold:
123
+ text = f"**{text}**"
124
+ elif run.italic:
125
+ text = f"*{text}*"
126
+ result += text
127
+ return result
128
+
129
+ def _convert_table_to_markdown(self, table) -> str:
130
+ """Convert DOCX table to Markdown table"""
131
+ if not table.rows:
132
+ return ""
133
+
134
+ markdown_rows = []
135
+
136
+ # Process header row
137
+ header_cells = [cell.text.strip() for cell in table.rows[0].cells]
138
+ markdown_rows.append("| " + " | ".join(header_cells) + " |")
139
+ markdown_rows.append("| " + " | ".join(["---"] * len(header_cells)) + " |")
140
+
141
+ # Process data rows
142
+ for row in table.rows[1:]:
143
+ cells = [cell.text.strip() for cell in row.cells]
144
+ markdown_rows.append("| " + " | ".join(cells) + " |")
145
+
146
+ return "\n".join(markdown_rows)
147
+
148
+ def _convert_pdf_blocks_to_markdown(self, blocks_dict) -> str:
149
+ """Convert PDF text blocks to Markdown"""
150
+ markdown_lines = []
151
+
152
+ for block in blocks_dict.get("blocks", []):
153
+ if block.get("type") == 0: # Text block
154
+ for line in block.get("lines", []):
155
+ line_text = ""
156
+ for span in line.get("spans", []):
157
+ text = span.get("text", "").strip()
158
+ if text:
159
+ # Check formatting
160
+ font_size = span.get("size", 12)
161
+ flags = span.get("flags", 0)
162
+
163
+ # Bold = flags & 16, Italic = flags & 2
164
+ is_bold = bool(flags & 16)
165
+ is_italic = bool(flags & 2)
166
+
167
+ # Apply formatting
168
+ if is_bold and is_italic:
169
+ text = f"***{text}***"
170
+ elif is_bold:
171
+ text = f"**{text}**"
172
+ elif is_italic:
173
+ text = f"*{text}*"
174
+
175
+ # Check if it's a heading based on font size
176
+ if font_size >= 18:
177
+ text = f"# {text}"
178
+ elif font_size >= 16:
179
+ text = f"## {text}"
180
+ elif font_size >= 14:
181
+ text = f"### {text}"
182
+
183
+ line_text += text + " "
184
+
185
+ if line_text.strip():
186
+ markdown_lines.append(line_text.strip())
187
+
188
+ return "\n\n".join(markdown_lines)
189
+
190
+ def analyze_markdown_structure(self, markdown_text: str) -> Dict[str, Any]:
191
+ """Analyze the structure of extracted Markdown"""
192
+ lines = markdown_text.split("\n")
193
+ structure = {
194
+ "headings": {"h1": 0, "h2": 0, "h3": 0, "h4": 0, "h5": 0, "h6": 0},
195
+ "lists": {"ordered": 0, "unordered": 0},
196
+ "tables": 0,
197
+ "paragraphs": 0,
198
+ "bold_text": 0,
199
+ "italic_text": 0,
200
+ "total_lines": len(lines),
201
+ "word_count": len(markdown_text.split()),
202
+ "character_count": len(markdown_text),
203
+ }
204
+
205
+ in_table = False
206
+
207
+ for line in lines:
208
+ line = line.strip()
209
+ if not line:
210
+ continue
211
+
212
+ # Count headings
213
+ if line.startswith("#"):
214
+ level = len(line) - len(line.lstrip("#"))
215
+ if level <= 6:
216
+ structure["headings"][f"h{level}"] += 1
217
+
218
+ # Count lists
219
+ elif re.match(r"^\d+\.\s", line):
220
+ structure["lists"]["ordered"] += 1
221
+ elif re.match(r"^[\-\*\+]\s", line):
222
+ structure["lists"]["unordered"] += 1
223
+
224
+ # Count tables
225
+ elif "|" in line and not in_table:
226
+ structure["tables"] += 1
227
+ in_table = True
228
+ elif "|" not in line:
229
+ in_table = False
230
+ if (
231
+ line
232
+ and not line.startswith("#")
233
+ and not re.match(r"^[\-\*\+\d]", line)
234
+ ):
235
+ structure["paragraphs"] += 1
236
+
237
+ # Count formatting
238
+ structure["bold_text"] += len(re.findall(r"\*\*[^*]+\*\*", line))
239
+ structure["italic_text"] += len(re.findall(r"\*[^*]+\*", line))
240
+
241
+ return structure
242
+
243
+
244
+ def extract_document_to_markdown(file_path: str) -> Dict[str, Any]:
245
+ """
246
+ Extract document content and convert to Markdown format
247
+
248
+ Args:
249
+ file_path: Path to PDF or DOCX file
250
+
251
+ Returns:
252
+ Dictionary containing markdown content and structure analysis
253
+ """
254
+
255
+ if not file_path or not os.path.exists(file_path):
256
+ return {"error": "File not found", "markdown": "", "structure": {}}
257
+
258
+ converter = DocumentToMarkdownConverter()
259
+ file_extension = Path(file_path).suffix.lower()
260
+
261
+ try:
262
+ if file_extension == ".docx":
263
+ if not DOCX_AVAILABLE:
264
+ return {
265
+ "error": "python-docx not installed. Run: pip install python-docx",
266
+ "markdown": "",
267
+ "structure": {},
268
+ }
269
+ markdown_content = converter.extract_from_docx(file_path)
270
+
271
+ elif file_extension == ".pdf":
272
+ if not PDF_AVAILABLE:
273
+ return {
274
+ "error": "PyMuPDF not installed. Run: pip install PyMuPDF",
275
+ "markdown": "",
276
+ "structure": {},
277
+ }
278
+ markdown_content = converter.extract_from_pdf(file_path)
279
+
280
+ else:
281
+ return {
282
+ "error": f"Unsupported file type: {file_extension}. Only PDF and DOCX files are supported.",
283
+ "markdown": "",
284
+ "structure": {},
285
+ }
286
+
287
+ # Analyze markdown structure
288
+ structure = converter.analyze_markdown_structure(markdown_content)
289
+
290
+ return {
291
+ "success": True,
292
+ "file_info": {
293
+ "name": Path(file_path).name,
294
+ "type": file_extension.upper()[1:],
295
+ "size_kb": round(os.path.getsize(file_path) / 1024, 2),
296
+ },
297
+ "markdown": markdown_content,
298
+ "structure": structure,
299
+ "preview": markdown_content[:500] + "..."
300
+ if len(markdown_content) > 500
301
+ else markdown_content,
302
+ }
303
+
304
+ except Exception as e:
305
+ return {
306
+ "error": f"Error processing file: {str(e)}",
307
+ "markdown": "",
308
+ "structure": {},
309
+ }
310
+
311
+
312
+ # Create Gradio interface
313
+ def create_interface():
314
+ with gr.Blocks(title="Document to Markdown Converter") as demo:
315
+ gr.Markdown("# 📄 Document to Markdown Converter")
316
+ gr.Markdown(
317
+ "Upload PDF or DOCX files to extract content and convert to Markdown format"
318
+ )
319
+
320
+ missing_deps = []
321
+ if not DOCX_AVAILABLE:
322
+ missing_deps.append("python-docx")
323
+ if not PDF_AVAILABLE:
324
+ missing_deps.append("PyMuPDF")
325
+
326
+ if missing_deps:
327
+ gr.Markdown(
328
+ f"⚠️ **Missing dependencies**: Run `pip install {' '.join(missing_deps)}` to enable full support"
329
+ )
330
+
331
+ with gr.Row():
332
+ with gr.Column(scale=1):
333
+ file_input = gr.File(
334
+ label="Upload Document",
335
+ file_types=[".pdf", ".docx"],
336
+ type="filepath",
337
+ )
338
+ extract_btn = gr.Button("Extract to Markdown", variant="primary")
339
+
340
+ with gr.Accordion("Output Options", open=False):
341
+ show_structure = gr.Checkbox(
342
+ label="Show Structure Analysis", value=True
343
+ )
344
+ show_preview = gr.Checkbox(label="Show Preview Only", value=False)
345
+
346
+ with gr.Column(scale=2):
347
+ with gr.Tabs():
348
+ with gr.TabItem("Markdown Output"):
349
+ markdown_output = gr.Textbox(
350
+ label="Extracted Markdown",
351
+ lines=20,
352
+ max_lines=30,
353
+ show_copy_button=True,
354
+ )
355
+
356
+ with gr.TabItem("Structure Analysis"):
357
+ structure_output = gr.JSON(label="Document Structure")
358
+
359
+ with gr.TabItem("File Info"):
360
+ info_output = gr.JSON(label="File Information")
361
+
362
+ def process_document(file_path, show_struct, show_prev):
363
+ if not file_path:
364
+ return "No file uploaded", {}, {}
365
+
366
+ result = extract_document_to_markdown(file_path)
367
+
368
+ if "error" in result:
369
+ return f"Error: {result['error']}", {}, {}
370
+
371
+ markdown_text = result["preview"] if show_prev else result["markdown"]
372
+ structure = result["structure"] if show_struct else {}
373
+ file_info = result["file_info"]
374
+
375
+ return markdown_text, structure, file_info
376
+
377
+ extract_btn.click(
378
+ fn=process_document,
379
+ inputs=[file_input, show_structure, show_preview],
380
+ outputs=[markdown_output, structure_output, info_output],
381
+ )
382
+
383
+ return demo
384
+
385
+
386
+ if __name__ == "__main__":
387
+ demo = create_interface()
388
+ demo.launch(mcp_server=True)