From a9cc3c9b9004a5f3fdb0fa5126329f4caed12cb0 Mon Sep 17 00:00:00 2001 From: lhl Date: Sun, 9 Aug 2026 03:09:42 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20FreeTextExtractor=EF=BC=88=E6=96=87?= =?UTF-8?q?=E6=9C=AC=E5=88=86=E6=AE=B5=20+=20=E5=8D=A0=E4=BD=8D=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E5=8C=96=E8=A1=A8=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/genesis/parsers/free_text_extractor.py | 51 ++++++++++++++++++++++ tests/test_free_text_extractor.py | 17 ++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/genesis/parsers/free_text_extractor.py create mode 100644 tests/test_free_text_extractor.py diff --git a/src/genesis/parsers/free_text_extractor.py b/src/genesis/parsers/free_text_extractor.py new file mode 100644 index 0000000..4b3eb90 --- /dev/null +++ b/src/genesis/parsers/free_text_extractor.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +from typing import Any + +from genesis.data_models import CellValue, ExcelTable, Provenance, SheetType + + +def extract_text_blocks(matrix: list[list[Any]]) -> list[str]: + """按全空行分段;行内非空单元格以「 」连接。""" + blocks: list[str] = [] + current: list[str] = [] + for row in matrix: + cells = [str(c).strip() for c in row if c is not None and str(c).strip() != ""] + if not cells: + if current: + blocks.append(" ".join(current)) + current = [] + continue + current.append(" ".join(cells)) + if current: + blocks.append(" ".join(current)) + return blocks + + +def build_free_text_table( + sheet_name: str, + blocks: list[str], + file_name: str, + detected_type: SheetType = SheetType.GENERIC, +) -> ExcelTable: + rows = [] + for i, text in enumerate(blocks, start=1): + rows.append({ + "text": CellValue( + value=text, + provenance=Provenance( + file_name=file_name, + sheet_name=sheet_name, + row=i, + column="A", + column_header="text", + ), + ), + }) + return ExcelTable( + name=sheet_name, + detected_type=detected_type, + extraction_method="llm_from_free_text", + headers=["text"], + rows=rows, + ) \ No newline at end of file diff --git a/tests/test_free_text_extractor.py b/tests/test_free_text_extractor.py new file mode 100644 index 0000000..fe1f9f0 --- /dev/null +++ b/tests/test_free_text_extractor.py @@ -0,0 +1,17 @@ +from genesis.data_models import CellValue, ExcelTable, SheetType +from genesis.parsers.free_text_extractor import build_free_text_table, extract_text_blocks + + +def test_extract_blocks_splits_on_empty_rows(): + m = [["新入社員を登録。"], [], ["テスト要件:入力。"], [], []] + assert extract_text_blocks(m) == ["新入社員を登録。", "テスト要件:入力。"] + + +def test_build_free_text_table(): + table = build_free_text_table("機能要件", ["A", "B"], "f.xlsx", SheetType.FUNCTION) + assert isinstance(table, ExcelTable) + assert table.detected_type == SheetType.FUNCTION + assert table.extraction_method == "llm_from_free_text" + assert len(table.rows) == 2 + assert isinstance(table.rows[0]["text"], CellValue) + assert table.rows[0]["text"].value == "A"