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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -277
app.py CHANGED
@@ -5,8 +5,6 @@ from transformers import AutoModel, AutoTokenizer
5
  import warnings
6
  import os
7
  import spaces
8
- import markdown
9
- import re
10
 
11
  # 禁用警告信息
12
  warnings.filterwarnings("ignore")
@@ -138,199 +136,6 @@ def clean_text_output(text):
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,36 +175,24 @@ def parse_image(image, parse_type):
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,50 +206,9 @@ def create_interface():
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,12 +217,12 @@ def create_interface():
465
  ## 📋 使用说明
466
  1. **上传图片**: 支持 PNG、JPG、JPEG 等格式
467
  2. **选择解析类型**: 根据图片内容选择相应的解析模式
468
- 3. **获取结果**: 自动渲染显示,表格和公式直接可视化
469
 
470
  ## 🎯 解析类型说明
471
- - **📊 表格解析**: 将表格图片转换为可视化表格
472
- - **🧮 公式解析**: 识别数学公式并渲染显示
473
- - **📝 文本解析**: 提取图片中的所有文字内容,智能识别并渲染其中的表格和公式
474
  """)
475
 
476
  with gr.Row():
@@ -503,20 +255,14 @@ def create_interface():
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,7 +283,7 @@ def create_interface():
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,7 +294,6 @@ def create_interface():
548
  - 复杂表格建议分段处理
549
  - 公式图片建议使用高分辨率
550
  - 文字图片避免模糊、倾斜或光线不足
551
- - **文本解析**现在支持智能识别:如果文本中包含表格或公式,会自动渲染显示
552
 
553
  ### 🔧 技术支持
554
  - 模型: MiniCPM-o-2.6
 
5
  import warnings
6
  import os
7
  import spaces
 
 
8
 
9
  # 禁用警告信息
10
  warnings.filterwarnings("ignore")
 
136
 
137
  return '\n'.join(text_lines)
138
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  @spaces.GPU
140
  def parse_image(image, parse_type):
141
  """解析图片内容为指定格式"""
 
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
  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
  ## 📋 使用说明
218
  1. **上传图片**: 支持 PNG、JPG、JPEG 等格式
219
  2. **选择解析类型**: 根据图片内容选择相应的解析模式
220
+ 3. **获取结果**: 自动清理输出,获得纯净的解析结果
221
 
222
  ## 🎯 解析类型说明
223
+ - **📊 表格解析**: 将表格图片转换为Markdown格式
224
+ - **🧮 公式解析**: 识别数学公式并输出LaTeX格式
225
+ - **📝 文本解析**: 提取图片中的所有文字内容
226
  """)
227
 
228
  with gr.Row():
 
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
  parse_button.click(
284
  fn=parse_image,
285
  inputs=[image_input, parse_type],
286
+ outputs=[result_output, status_output]
287
  )
288
 
289
  # 添加页脚信息
 
294
  - 复杂表格建议分段处理
295
  - 公式图片建议使用高分辨率
296
  - 文字图片避免模糊、倾斜或光线不足
 
297
 
298
  ### 🔧 技术支持
299
  - 模型: MiniCPM-o-2.6