common.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import os
  2. import click
  3. import fitz
  4. from loguru import logger
  5. import magic_pdf.model as model_config
  6. from magic_pdf.config.enums import SupportedPdfParseMethod
  7. from magic_pdf.config.make_content_config import DropMode, MakeMode
  8. from magic_pdf.data.data_reader_writer import FileBasedDataWriter
  9. from magic_pdf.data.dataset import PymuDocDataset
  10. from magic_pdf.model.doc_analyze_by_custom_model import doc_analyze
  11. from magic_pdf.model.operators import InferenceResult
  12. # from io import BytesIO
  13. # from pypdf import PdfReader, PdfWriter
  14. def prepare_env(output_dir, pdf_file_name, method):
  15. local_parent_dir = os.path.join(output_dir, pdf_file_name, method)
  16. local_image_dir = os.path.join(str(local_parent_dir), 'images')
  17. local_md_dir = local_parent_dir
  18. os.makedirs(local_image_dir, exist_ok=True)
  19. os.makedirs(local_md_dir, exist_ok=True)
  20. return local_image_dir, local_md_dir
  21. # def convert_pdf_bytes_to_bytes_by_pypdf(pdf_bytes, start_page_id=0, end_page_id=None):
  22. # # 将字节数据包装在 BytesIO 对象中
  23. # pdf_file = BytesIO(pdf_bytes)
  24. # # 读取 PDF 的字节数据
  25. # reader = PdfReader(pdf_file)
  26. # # 创建一个新的 PDF 写入器
  27. # writer = PdfWriter()
  28. # # 将所有页面添加到新的 PDF 写入器中
  29. # end_page_id = end_page_id if end_page_id is not None and end_page_id >= 0 else len(reader.pages) - 1
  30. # if end_page_id > len(reader.pages) - 1:
  31. # logger.warning("end_page_id is out of range, use pdf_docs length")
  32. # end_page_id = len(reader.pages) - 1
  33. # for i, page in enumerate(reader.pages):
  34. # if start_page_id <= i <= end_page_id:
  35. # writer.add_page(page)
  36. # # 创建一个字节缓冲区来存储输出的 PDF 数据
  37. # output_buffer = BytesIO()
  38. # # 将 PDF 写入字节缓冲区
  39. # writer.write(output_buffer)
  40. # # 获取字节缓冲区的内容
  41. # converted_pdf_bytes = output_buffer.getvalue()
  42. # return converted_pdf_bytes
  43. def convert_pdf_bytes_to_bytes_by_pymupdf(pdf_bytes, start_page_id=0, end_page_id=None):
  44. document = fitz.open('pdf', pdf_bytes)
  45. output_document = fitz.open()
  46. end_page_id = (
  47. end_page_id
  48. if end_page_id is not None and end_page_id >= 0
  49. else len(document) - 1
  50. )
  51. if end_page_id > len(document) - 1:
  52. logger.warning('end_page_id is out of range, use pdf_docs length')
  53. end_page_id = len(document) - 1
  54. output_document.insert_pdf(document, from_page=start_page_id, to_page=end_page_id)
  55. output_bytes = output_document.tobytes()
  56. return output_bytes
  57. def do_parse(
  58. output_dir,
  59. pdf_file_name,
  60. pdf_bytes,
  61. model_list,
  62. parse_method,
  63. debug_able,
  64. f_draw_span_bbox=True,
  65. f_draw_layout_bbox=True,
  66. f_dump_md=True,
  67. f_dump_middle_json=True,
  68. f_dump_model_json=True,
  69. f_dump_orig_pdf=True,
  70. f_dump_content_list=True,
  71. f_make_md_mode=MakeMode.MM_MD,
  72. f_draw_model_bbox=False,
  73. f_draw_line_sort_bbox=False,
  74. start_page_id=0,
  75. end_page_id=None,
  76. lang=None,
  77. layout_model=None,
  78. formula_enable=None,
  79. table_enable=None,
  80. ):
  81. if debug_able:
  82. logger.warning('debug mode is on')
  83. f_draw_model_bbox = True
  84. f_draw_line_sort_bbox = True
  85. pdf_bytes = convert_pdf_bytes_to_bytes_by_pymupdf(
  86. pdf_bytes, start_page_id, end_page_id
  87. )
  88. local_image_dir, local_md_dir = prepare_env(output_dir, pdf_file_name, parse_method)
  89. image_writer, md_writer = FileBasedDataWriter(local_image_dir), FileBasedDataWriter(
  90. local_md_dir
  91. )
  92. image_dir = str(os.path.basename(local_image_dir))
  93. ds = PymuDocDataset(pdf_bytes, lang=lang)
  94. if len(model_list) == 0:
  95. if model_config.__use_inside_model__:
  96. if parse_method == 'auto':
  97. if ds.classify() == SupportedPdfParseMethod.TXT:
  98. infer_result = ds.apply(
  99. doc_analyze,
  100. ocr=False,
  101. lang=ds._lang,
  102. layout_model=layout_model,
  103. formula_enable=formula_enable,
  104. table_enable=table_enable,
  105. )
  106. pipe_result = infer_result.pipe_txt_mode(
  107. image_writer, debug_mode=True, lang=ds._lang
  108. )
  109. else:
  110. infer_result = ds.apply(
  111. doc_analyze,
  112. ocr=True,
  113. lang=ds._lang,
  114. layout_model=layout_model,
  115. formula_enable=formula_enable,
  116. table_enable=table_enable,
  117. )
  118. pipe_result = infer_result.pipe_ocr_mode(
  119. image_writer, debug_mode=True, lang=ds._lang
  120. )
  121. elif parse_method == 'txt':
  122. infer_result = ds.apply(
  123. doc_analyze,
  124. ocr=False,
  125. lang=ds._lang,
  126. layout_model=layout_model,
  127. formula_enable=formula_enable,
  128. table_enable=table_enable,
  129. )
  130. pipe_result = infer_result.pipe_txt_mode(
  131. image_writer, debug_mode=True, lang=ds._lang
  132. )
  133. elif parse_method == 'ocr':
  134. infer_result = ds.apply(
  135. doc_analyze,
  136. ocr=True,
  137. lang=ds._lang,
  138. layout_model=layout_model,
  139. formula_enable=formula_enable,
  140. table_enable=table_enable,
  141. )
  142. pipe_result = infer_result.pipe_ocr_mode(
  143. image_writer, debug_mode=True, lang=ds._lang
  144. )
  145. else:
  146. logger.error('unknown parse method')
  147. exit(1)
  148. else:
  149. logger.error('need model list input')
  150. exit(2)
  151. else:
  152. infer_result = InferenceResult(model_list, ds)
  153. if parse_method == 'ocr':
  154. pipe_result = infer_result.pipe_ocr_mode(
  155. image_writer, debug_mode=True, lang=ds._lang
  156. )
  157. elif parse_method == 'txt':
  158. pipe_result = infer_result.pipe_txt_mode(
  159. image_writer, debug_mode=True, lang=ds._lang
  160. )
  161. else:
  162. if ds.classify() == SupportedPdfParseMethod.TXT:
  163. pipe_result = infer_result.pipe_txt_mode(
  164. image_writer, debug_mode=True, lang=ds._lang
  165. )
  166. else:
  167. pipe_result = infer_result.pipe_ocr_mode(
  168. image_writer, debug_mode=True, lang=ds._lang
  169. )
  170. if f_draw_model_bbox:
  171. infer_result.draw_model(
  172. os.path.join(local_md_dir, f'{pdf_file_name}_model.pdf')
  173. )
  174. if f_draw_layout_bbox:
  175. pipe_result.draw_layout(
  176. os.path.join(local_md_dir, f'{pdf_file_name}_layout.pdf')
  177. )
  178. if f_draw_span_bbox:
  179. pipe_result.draw_span(os.path.join(local_md_dir, f'{pdf_file_name}_spans.pdf'))
  180. if f_draw_line_sort_bbox:
  181. pipe_result.draw_line_sort(
  182. os.path.join(local_md_dir, f'{pdf_file_name}_line_sort.pdf')
  183. )
  184. if f_dump_md:
  185. pipe_result.dump_md(
  186. md_writer,
  187. f'{pdf_file_name}.md',
  188. image_dir,
  189. drop_mode=DropMode.NONE,
  190. md_make_mode=f_make_md_mode,
  191. )
  192. if f_dump_middle_json:
  193. pipe_result.dump_middle_json(md_writer, f'{pdf_file_name}_middle.json')
  194. if f_dump_model_json:
  195. infer_result.dump_model(md_writer, f'{pdf_file_name}_model.json')
  196. if f_dump_orig_pdf:
  197. md_writer.write(
  198. f'{pdf_file_name}_origin.pdf',
  199. pdf_bytes,
  200. )
  201. if f_dump_content_list:
  202. pipe_result.dump_content_list(
  203. md_writer,
  204. f'{pdf_file_name}_content_list.json',
  205. image_dir
  206. )
  207. logger.info(f'local output dir is {local_md_dir}')
  208. parse_pdf_methods = click.Choice(['ocr', 'txt', 'auto'])