| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import logging |
| import sys |
| from io import BytesIO |
|
|
| import pandas as pd |
| from openpyxl import Workbook, load_workbook |
|
|
| from rag.nlp import find_codec |
|
|
|
|
| class RAGFlowExcelParser: |
|
|
| @staticmethod |
| def _load_excel_to_workbook(file_like_object): |
| if isinstance(file_like_object, bytes): |
| file_like_object = BytesIO(file_like_object) |
|
|
| |
| file_like_object.seek(0) |
| file_head = file_like_object.read(4) |
| file_like_object.seek(0) |
|
|
| if not (file_head.startswith(b'PK\x03\x04') or file_head.startswith(b'\xD0\xCF\x11\xE0')): |
| logging.info("****wxy: Not an Excel file, converting CSV to Excel Workbook") |
|
|
| try: |
| file_like_object.seek(0) |
| df = pd.read_csv(file_like_object) |
| return RAGFlowExcelParser._dataframe_to_workbook(df) |
|
|
| except Exception as e_csv: |
| raise Exception(f"****wxy: Failed to parse CSV and convert to Excel Workbook: {e_csv}") |
|
|
| try: |
| return load_workbook(file_like_object) |
| except Exception as e: |
| logging.info(f"****wxy: openpyxl load error: {e}, try pandas instead") |
| try: |
| file_like_object.seek(0) |
| df = pd.read_excel(file_like_object) |
| return RAGFlowExcelParser._dataframe_to_workbook(df) |
| except Exception as e_pandas: |
| raise Exception(f"****wxy: pandas.read_excel error: {e_pandas}, original openpyxl error: {e}") |
|
|
| @staticmethod |
| def _dataframe_to_workbook(df): |
| wb = Workbook() |
| ws = wb.active |
| ws.title = "Data" |
|
|
| for col_num, column_name in enumerate(df.columns, 1): |
| ws.cell(row=1, column=col_num, value=column_name) |
|
|
| for row_num, row in enumerate(df.values, 2): |
| for col_num, value in enumerate(row, 1): |
| ws.cell(row=row_num, column=col_num, value=value) |
|
|
| return wb |
|
|
| def html(self, fnm, chunk_rows=256): |
| file_like_object = BytesIO(fnm) if not isinstance(fnm, str) else fnm |
| wb = RAGFlowExcelParser._load_excel_to_workbook(file_like_object) |
| tb_chunks = [] |
| for sheetname in wb.sheetnames: |
| ws = wb[sheetname] |
| rows = list(ws.rows) |
| if not rows: |
| continue |
|
|
| tb_rows_0 = "<tr>" |
| for t in list(rows[0]): |
| tb_rows_0 += f"<th>{t.value}</th>" |
| tb_rows_0 += "</tr>" |
|
|
| for chunk_i in range((len(rows) - 1) // chunk_rows + 1): |
| tb = "" |
| tb += f"<table><caption>{sheetname}</caption>" |
| tb += tb_rows_0 |
| for r in list( |
| rows[1 + chunk_i * chunk_rows: 1 + (chunk_i + 1) * chunk_rows] |
| ): |
| tb += "<tr>" |
| for i, c in enumerate(r): |
| if c.value is None: |
| tb += "<td></td>" |
| else: |
| tb += f"<td>{c.value}</td>" |
| tb += "</tr>" |
| tb += "</table>\n" |
| tb_chunks.append(tb) |
|
|
| return tb_chunks |
|
|
| def __call__(self, fnm): |
| file_like_object = BytesIO(fnm) if not isinstance(fnm, str) else fnm |
| wb = RAGFlowExcelParser._load_excel_to_workbook(file_like_object) |
|
|
| res = [] |
| for sheetname in wb.sheetnames: |
| ws = wb[sheetname] |
| rows = list(ws.rows) |
| if not rows: |
| continue |
| ti = list(rows[0]) |
| for r in list(rows[1:]): |
| fields = [] |
| for i, c in enumerate(r): |
| if not c.value: |
| continue |
| t = str(ti[i].value) if i < len(ti) else "" |
| t += (":" if t else "") + str(c.value) |
| fields.append(t) |
| line = "; ".join(fields) |
| if sheetname.lower().find("sheet") < 0: |
| line += " ——" + sheetname |
| res.append(line) |
| return res |
|
|
| @staticmethod |
| def row_number(fnm, binary): |
| if fnm.split(".")[-1].lower().find("xls") >= 0: |
| wb = RAGFlowExcelParser._load_excel_to_workbook(BytesIO(binary)) |
| total = 0 |
| for sheetname in wb.sheetnames: |
| ws = wb[sheetname] |
| total += len(list(ws.rows)) |
| return total |
|
|
| if fnm.split(".")[-1].lower() in ["csv", "txt"]: |
| encoding = find_codec(binary) |
| txt = binary.decode(encoding, errors="ignore") |
| return len(txt.split("\n")) |
|
|
|
|
| if __name__ == "__main__": |
| psr = RAGFlowExcelParser() |
| psr(sys.argv[1]) |
|
|