SynaptechX commited on
Commit
b90b5f2
·
verified ·
1 Parent(s): a859786

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +277 -22
app.py CHANGED
@@ -5,6 +5,8 @@ from transformers import AutoModel, AutoTokenizer
5
  import warnings
6
  import os
7
  import spaces
 
 
8
 
9
  # 禁用警告信息
10
  warnings.filterwarnings("ignore")
@@ -136,6 +138,199 @@ def clean_text_output(text):
136
 
137
  return '\n'.join(text_lines)
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  @spaces.GPU
140
  def parse_image(image, parse_type):
141
  """解析图片内容为指定格式"""
@@ -175,24 +370,36 @@ def parse_image(image, parse_type):
175
  for new_text in res:
176
  generated_text += new_text
177
 
178
- # 根据类型清理输出
179
  if parse_type == "表格解析":
180
- result = clean_markdown_output(generated_text)
181
- output_format = "Markdown"
 
 
182
  elif parse_type == "公式解析":
183
- result = clean_formula_output(generated_text)
184
- output_format = "LaTeX"
 
 
185
  elif parse_type == "文本解析":
186
- result = clean_text_output(generated_text)
187
- output_format = "纯文本"
 
 
 
 
 
 
 
 
188
  else:
189
  result = generated_text.strip()
190
  output_format = "原始输出"
191
-
192
- return result, f"解析完成 - 输出格式: {output_format}"
193
 
194
  except Exception as e:
195
- return f"解析失败: {str(e)}", "错误"
 
196
 
197
  def create_interface():
198
  """创建Gradio界面"""
@@ -206,9 +413,50 @@ def create_interface():
206
  font-family: 'Courier New', monospace;
207
  font-size: 14px;
208
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
209
  """
210
 
211
- with gr.Blocks(css=css, title="MiniCPM 多模态内容解析工具", analytics_enabled=False) as interface:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
212
  gr.Markdown("""
213
  # 🚀 MiniCPM 多模态内容解析工具
214
 
@@ -217,12 +465,12 @@ def create_interface():
217
  ## 📋 使用说明
218
  1. **上传图片**: 支持 PNG、JPG、JPEG 等格式
219
  2. **选择解析类型**: 根据图片内容选择相应的解析模式
220
- 3. **获取结果**: 自动清理输出,获得纯净的解析结果
221
 
222
  ## 🎯 解析类型说明
223
- - **📊 表格解析**: 将表格图片转换为Markdown格式
224
- - **🧮 公式解析**: 识别数学公式并输出LaTeX格式
225
- - **📝 文本解析**: 提取图片中的所有文字内容
226
  """)
227
 
228
  with gr.Row():
@@ -255,14 +503,20 @@ def create_interface():
255
  interactive=False
256
  )
257
 
258
- result_output = gr.Textbox(
259
- label="📄 解析结果",
260
- lines=20,
261
- max_lines=30,
 
 
 
 
 
 
262
  show_copy_button=True,
263
  elem_classes=["output-text"],
264
- placeholder="解析结果将在这里显示...",
265
- interactive=True
266
  )
267
 
268
  # 示例图片
@@ -283,7 +537,7 @@ def create_interface():
283
  parse_button.click(
284
  fn=parse_image,
285
  inputs=[image_input, parse_type],
286
- outputs=[result_output, status_output]
287
  )
288
 
289
  # 添加页脚信息
@@ -294,6 +548,7 @@ def create_interface():
294
  - 复杂表格建议分段处理
295
  - 公式图片建议使用高分辨率
296
  - 文字图片避免模糊、倾斜或光线不足
 
297
 
298
  ### 🔧 技术支持
299
  - 模型: MiniCPM-o-2.6
 
5
  import warnings
6
  import os
7
  import spaces
8
+ import markdown
9
+ import re
10
 
11
  # 禁用警告信息
12
  warnings.filterwarnings("ignore")
 
138
 
139
  return '\n'.join(text_lines)
140
 
141
+ def detect_content_types(text):
142
+ """检测文本中包含的内容类型"""
143
+ content_types = set()
144
+
145
+ # 检测表格(Markdown格式)
146
+ if '|' in text and any(line.count('|') >= 2 for line in text.split('\n')):
147
+ content_types.add('table')
148
+
149
+ # 检测公式(LaTeX格式)
150
+ formula_indicators = ['$', '\\frac', '\\sum', '\\int', '\\sqrt', '\\alpha', '\\beta', '\\gamma', '\\delta',
151
+ '\\theta', '\\pi', '\\sigma', '\\omega', '\\infty', '\\partial', '\\nabla']
152
+ if any(indicator in text for indicator in formula_indicators) or \
153
+ (any(symbol in text for symbol in ['{', '}', '^', '_']) and any(char.isdigit() for char in text)):
154
+ content_types.add('formula')
155
+
156
+ # 总是包含文本
157
+ content_types.add('text')
158
+
159
+ return content_types
160
+
161
+ def render_mixed_content(text):
162
+ """渲染混合内容(文本+表格+公式)"""
163
+ if not text.strip():
164
+ return text
165
+
166
+ # 检测内容类型
167
+ content_types = detect_content_types(text)
168
+
169
+ # 如果只有纯文本,简单处理
170
+ if content_types == {'text'}:
171
+ return f"<div style='padding: 15px; white-space: pre-wrap; font-family: Arial, sans-serif; line-height: 1.6;'>{text}</div>"
172
+
173
+ # 处理混合内容
174
+ lines = text.split('\n')
175
+ rendered_parts = []
176
+ current_block = []
177
+ current_type = 'text'
178
+
179
+ i = 0
180
+ while i < len(lines):
181
+ line = lines[i].strip()
182
+
183
+ # 检测表格开始
184
+ if '|' in line and line.count('|') >= 2:
185
+ # 先处理之前累积的文本块
186
+ if current_block and current_type == 'text':
187
+ text_content = '\n'.join(current_block)
188
+ if text_content.strip():
189
+ rendered_parts.append(f"<div style='padding: 10px 0; white-space: pre-wrap; font-family: Arial, sans-serif; line-height: 1.6;'>{text_content}</div>")
190
+ current_block = []
191
+
192
+ # 收集表格行
193
+ table_lines = []
194
+ while i < len(lines) and '|' in lines[i]:
195
+ table_lines.append(lines[i])
196
+ i += 1
197
+
198
+ # 渲染表格
199
+ if table_lines:
200
+ table_markdown = '\n'.join(table_lines)
201
+ table_html = render_markdown_table(table_markdown)
202
+ rendered_parts.append(table_html)
203
+
204
+ current_type = 'text'
205
+ continue
206
+
207
+ # 检测公式(简单检测包含LaTeX符号的行)
208
+ elif any(symbol in line for symbol in ['$', '\\frac', '\\sum', '\\int', '\\sqrt']) and current_type != 'formula':
209
+ # 先处理之前累积的文本块
210
+ if current_block and current_type == 'text':
211
+ text_content = '\n'.join(current_block)
212
+ if text_content.strip():
213
+ rendered_parts.append(f"<div style='padding: 10px 0; white-space: pre-wrap; font-family: Arial, sans-serif; line-height: 1.6;'>{text_content}</div>")
214
+ current_block = []
215
+
216
+ # 收集公式行
217
+ formula_lines = [line]
218
+ i += 1
219
+ while i < len(lines):
220
+ next_line = lines[i].strip()
221
+ if any(symbol in next_line for symbol in ['$', '\\', '{', '}', '^', '_']) or \
222
+ any(char.isdigit() or char in '+-*/=()[]{}^_' for char in next_line):
223
+ formula_lines.append(next_line)
224
+ i += 1
225
+ else:
226
+ break
227
+
228
+ # 渲染公式
229
+ if formula_lines:
230
+ formula_text = '\n'.join(formula_lines)
231
+ formula_html = render_latex_formula(formula_text)
232
+ rendered_parts.append(formula_html)
233
+
234
+ current_type = 'text'
235
+ continue
236
+
237
+ # 普通文本行
238
+ else:
239
+ current_block.append(lines[i])
240
+ current_type = 'text'
241
+ i += 1
242
+
243
+ # 处理最后剩余的文本块
244
+ if current_block:
245
+ text_content = '\n'.join(current_block)
246
+ if text_content.strip():
247
+ rendered_parts.append(f"<div style='padding: 10px 0; white-space: pre-wrap; font-family: Arial, sans-serif; line-height: 1.6;'>{text_content}</div>")
248
+
249
+ # 合并所有渲染部分
250
+ if rendered_parts:
251
+ return '<div style="padding: 5px;">' + ''.join(rendered_parts) + '</div>'
252
+ else:
253
+ return f"<div style='padding: 15px; white-space: pre-wrap; font-family: Arial, sans-serif; line-height: 1.6;'>{text}</div>"
254
+
255
+ def render_markdown_table(markdown_text):
256
+ """将Markdown表格转换为HTML渲染格式"""
257
+ if not markdown_text.strip():
258
+ return markdown_text
259
+
260
+ # 使用markdown库转换为HTML
261
+ html_content = markdown.markdown(markdown_text, extensions=['tables'])
262
+
263
+ # 添加表格样式
264
+ styled_html = f"""
265
+ <div style="overflow-x: auto; margin: 10px 0;">
266
+ <style>
267
+ table {{
268
+ border-collapse: collapse;
269
+ width: 100%;
270
+ margin: 10px 0;
271
+ font-family: Arial, sans-serif;
272
+ }}
273
+ th, td {{
274
+ border: 1px solid #ddd;
275
+ padding: 8px 12px;
276
+ text-align: left;
277
+ }}
278
+ th {{
279
+ background-color: #f2f2f2;
280
+ font-weight: bold;
281
+ }}
282
+ tr:nth-child(even) {{
283
+ background-color: #f9f9f9;
284
+ }}
285
+ tr:hover {{
286
+ background-color: #f5f5f5;
287
+ }}
288
+ </style>
289
+ {html_content}
290
+ </div>
291
+ """
292
+
293
+ return styled_html
294
+
295
+ def render_latex_formula(latex_text):
296
+ """将LaTeX公式转换为可渲染的HTML格式"""
297
+ if not latex_text.strip():
298
+ return latex_text
299
+
300
+ # 处理LaTeX公式,确保正确的MathJax格式
301
+ lines = latex_text.strip().split('\n')
302
+ processed_lines = []
303
+
304
+ for line in lines:
305
+ line = line.strip()
306
+ if line:
307
+ # 检查是否已经有$符号包围
308
+ if not (line.startswith('$') and line.endswith('$')):
309
+ # 如果是单行公式,用$$包围(块级公式)
310
+ if '=' in line or any(symbol in line for symbol in ['\\', '{', '}', '^', '_']):
311
+ line = f"$${line}$$"
312
+ else:
313
+ line = f"${line}$"
314
+ processed_lines.append(line)
315
+
316
+ formula_html = '<br>'.join(processed_lines)
317
+
318
+ # 添加MathJax支持的HTML
319
+ html_content = f"""
320
+ <div style="margin: 10px 0; padding: 15px; background-color: #f8f9fa; border-left: 4px solid #007bff; border-radius: 4px;">
321
+ <div style="font-family: 'Times New Roman', serif; font-size: 16px; line-height: 1.6;">
322
+ {formula_html}
323
+ </div>
324
+ </div>
325
+ <script>
326
+ if (typeof MathJax !== 'undefined') {{
327
+ MathJax.typesetPromise();
328
+ }}
329
+ </script>
330
+ """
331
+
332
+ return html_content
333
+
334
  @spaces.GPU
335
  def parse_image(image, parse_type):
336
  """解析图片内容为指定格式"""
 
370
  for new_text in res:
371
  generated_text += new_text
372
 
373
+ # 根据类型清理输出并渲染
374
  if parse_type == "表格解析":
375
+ cleaned_result = clean_markdown_output(generated_text)
376
+ rendered_result = render_markdown_table(cleaned_result)
377
+ output_format = "Markdown表格"
378
+ return rendered_result, cleaned_result, f"解析完成 - 输出格式: {output_format}"
379
  elif parse_type == "公式解析":
380
+ cleaned_result = clean_formula_output(generated_text)
381
+ rendered_result = render_latex_formula(cleaned_result)
382
+ output_format = "LaTeX公式"
383
+ return rendered_result, cleaned_result, f"解析完成 - 输出格式: {output_format}"
384
  elif parse_type == "文本解析":
385
+ cleaned_result = clean_text_output(generated_text)
386
+ # 检测是否包含表格或公式,智能渲染
387
+ content_types = detect_content_types(cleaned_result)
388
+ if len(content_types) > 1: # 包含多种内容类型
389
+ rendered_result = render_mixed_content(cleaned_result)
390
+ output_format = "混合内容(文本+表格+公式)"
391
+ else:
392
+ rendered_result = f"<div style='padding: 15px; white-space: pre-wrap; font-family: Arial, sans-serif; line-height: 1.6;'>{cleaned_result}</div>"
393
+ output_format = "纯文本"
394
+ return rendered_result, cleaned_result, f"解析完成 - 输出格式: {output_format}"
395
  else:
396
  result = generated_text.strip()
397
  output_format = "原始输出"
398
+ return f"<div style='padding: 15px; white-space: pre-wrap; font-family: monospace;'>{result}</div>", result, f"解析完成 - 输出格式: {output_format}"
 
399
 
400
  except Exception as e:
401
+ error_html = f"<div style='color: red; padding: 15px; border: 1px solid red; border-radius: 4px;'>解析失败: {str(e)}</div>"
402
+ return error_html, str(e), "错误"
403
 
404
  def create_interface():
405
  """创建Gradio界面"""
 
413
  font-family: 'Courier New', monospace;
414
  font-size: 14px;
415
  }
416
+ .rendered-output {
417
+ font-family: Arial, sans-serif;
418
+ line-height: 1.6;
419
+ }
420
+ .rendered-output table {
421
+ border-collapse: collapse;
422
+ width: 100%;
423
+ margin: 10px 0;
424
+ }
425
+ .rendered-output th, .rendered-output td {
426
+ border: 1px solid #ddd;
427
+ padding: 8px 12px;
428
+ text-align: left;
429
+ }
430
+ .rendered-output th {
431
+ background-color: #f2f2f2;
432
+ font-weight: bold;
433
+ }
434
+ .rendered-output tr:nth-child(even) {
435
+ background-color: #f9f9f9;
436
+ }
437
  """
438
 
439
+ # MathJax配置
440
+ mathjax_config = """
441
+ <script>
442
+ window.MathJax = {
443
+ tex: {
444
+ inlineMath: [['$', '$'], ['\\(', '\\)']],
445
+ displayMath: [['$$', '$$'], ['\\[', '\\]']],
446
+ processEscapes: true,
447
+ processEnvironments: true
448
+ },
449
+ options: {
450
+ ignoreHtmlClass: 'tex2jax_ignore',
451
+ processHtmlClass: 'tex2jax_process'
452
+ }
453
+ };
454
+ </script>
455
+ <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
456
+ <script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
457
+ """
458
+
459
+ with gr.Blocks(css=css, title="MiniCPM 多模态内容解析工具", analytics_enabled=False, head=mathjax_config) as interface:
460
  gr.Markdown("""
461
  # 🚀 MiniCPM 多模态内容解析工具
462
 
 
465
  ## 📋 使用说明
466
  1. **上传图片**: 支持 PNG、JPG、JPEG 等格式
467
  2. **选择解析类型**: 根据图片内容选择相应的解析模式
468
+ 3. **获取结果**: 自动渲染显示,表格和公式直接可视化
469
 
470
  ## 🎯 解析类型说明
471
+ - **📊 表格解析**: 将表格图片转换为可视化表格
472
+ - **🧮 公式解析**: 识别数学公式并渲染显示
473
+ - **📝 文本解析**: 提取图片中的所有文字内容,智能识别并渲染其中的表格和公式
474
  """)
475
 
476
  with gr.Row():
 
503
  interactive=False
504
  )
505
 
506
+ result_output = gr.HTML(
507
+ label="📄 解析结果(渲染视图)",
508
+ value="<p style='color: #666; text-align: center; padding: 20px;'>解析结果将在这里显示...</p>",
509
+ elem_classes=["rendered-output"]
510
+ )
511
+
512
+ raw_output = gr.Textbox(
513
+ label="📝 原始代码(可复制)",
514
+ lines=8,
515
+ max_lines=15,
516
  show_copy_button=True,
517
  elem_classes=["output-text"],
518
+ placeholder="原始Markdown/LaTeX代码将在这里显示...",
519
+ visible=False
520
  )
521
 
522
  # 示例图片
 
537
  parse_button.click(
538
  fn=parse_image,
539
  inputs=[image_input, parse_type],
540
+ outputs=[result_output, raw_output, status_output]
541
  )
542
 
543
  # 添加页脚信息
 
548
  - 复杂表格建议分段处理
549
  - 公式图片建议使用高分辨率
550
  - 文字图片避免模糊、倾斜或光线不足
551
+ - **文本解析**现在支持智能识别:如果文本中包含表格或公式,会自动渲染显示
552
 
553
  ### 🔧 技术支持
554
  - 模型: MiniCPM-o-2.6