コンテンツにスキップ

TableSematicParserSchema

Bases: BaseSchema

Source code in src/yomitoku/schemas/table_semantic_parser.py
class TableSemanticParserSchema(BaseSchema):
    tables: List[TableSemanticContentsSchema] = Field(
        ...,
        description="List of tables with semantic information",
    )

    paragraphs: List[Element] = Field(
        ...,
        description="List of recognized paragraphs in the document",
    )

    words: List[WordPrediction] = Field(
        ...,
        description="List of recognized words in the document",
    )

    def search_words_by_position(self, bbox) -> str:
        """
        Search for words by their bounding box.
        位置情報(bounding box)に対応する文字列を返す

        Args:
            box (List[int]): 検索するバウンディングボックス [x1, y1, x2, y2]
        """
        words = []
        for word in self.words:
            word_box = quad_to_xyxy(word.points)
            if is_contained(bbox, word_box, threshold=0.5):
                word = ParagraphSchema(
                    box=word_box,
                    contents=word.content,
                    direction=word.direction,
                    role=None,
                    order=None,
                    indent_level=None,
                )

                words.append(word)

        word_direction = [word.direction for word in words]
        cnt_horizontal = word_direction.count("horizontal")
        cnt_vertical = word_direction.count("vertical")

        element_direction = (
            "horizontal" if cnt_horizontal > cnt_vertical else "vertical"
        )
        order = "left2right" if element_direction == "horizontal" else "right2left"
        words = prediction_reading_order(words, order)
        words = sorted(words, key=lambda x: x.order)

        return "".join([word.contents for word in words])

    @classmethod
    def load_json(self, json_path: str) -> "TableSemanticParserSchema":
        with open(json_path, "r", encoding="utf-8") as f:
            data = json.load(f)
        return TableSemanticParserSchema.model_validate(data)

    def to_csv(self, outdir):
        for table in self.tables:
            table.export.grids_to_csv(
                out_path=f"{outdir}/table_{table.id}.csv",
            )

    def to_dict(self, separator="\n"):
        """テーブルIDごとの構造化情報 (kv_items / grids) を dict で返す。

        kv_items は to_simple と同じく、キーセルの入れ子構造を保った
        階層dictになる (kv_items_to_nested を参照)。同一キーセル列の
        複数 value は separator で結合される。
        """
        results = {}
        for table in self.tables:
            result = {
                "kv_items": table.view.kv_items_to_nested(separator=separator),
                "grids": table.view.grids_to_dict(),
            }
            results[table.id] = result

        return results

    def to_structured(self, separator="\n") -> StructuredDocumentSchema:
        """ドキュメント全体を、テキストとセル座標を解決した構造化形に変換する。

        to_dict のkey-value構造に加えて、各エントリに由来セルのIDと座標
        (key_cells / value_cells) を埋め込み、paragraphs も含める。
        """
        tables = []
        for table in self.tables:
            tables.append(
                StructuredTableSchema(
                    id=table.id,
                    box=table.box,
                    style=table.style,
                    kv_items=table.view.kv_items_to_structured(separator=separator),
                    grids=table.view.grids_to_structured(),
                )
            )

        return StructuredDocumentSchema(tables=tables, paragraphs=self.paragraphs)

    def to_simple(self, separator="\n") -> SimpleDocumentSchema:
        """座標などのメタ情報を持たないテキストのみの構造化形に変換する。

        to_structured からセル参照・座標・スコア類を落とした形。
        kv_items はキーセルの入れ子構造を保った階層dictになる
        (kv_items_to_nested を参照)。同一キーの結合挙動は to_structured と
        同一。grid の行内でヘッダテキストが重複する場合は _0/_1 の
        インデックスを付与して値の消失を防ぐ。
        """
        doc = self.to_structured(separator=separator)

        tables = []
        for src_table, table in zip(self.tables, doc.tables):
            grids = []
            for grid in table.grids:
                rows = []
                for row in grid.rows:
                    keys = make_unique_all([list(e.key) for e in row.cells])
                    rows.append(
                        {
                            "_".join(map(str, k)): e.value
                            for k, e in zip(keys, row.cells)
                        }
                    )
                grids.append(SimpleGridSchema(id=grid.id, rows=rows))

            tables.append(
                SimpleTableSchema(
                    id=table.id,
                    kv_items=src_table.view.kv_items_to_nested(separator=separator),
                    grids=grids,
                )
            )

        return SimpleDocumentSchema(
            tables=tables,
            paragraphs=[p.contents for p in doc.paragraphs],
        )

    def find_table_by_id(
        self, table_id: str
    ) -> Union[TableSemanticContentsSchema, None]:
        """
        Search for a table by its ID.
        テーブルIDに対応するテーブルを返す

        Args:
            table_id (str): 検索するテーブルID
        """
        for table in self.tables:
            if table.id == str(table_id):
                return table

    def find_table_by_position(
        self, box: List[int]
    ) -> Union[TableSemanticContentsSchema, None]:
        """
        Search for a table by its bounding box.
        テーブルの位置情報(bounding box)に対応するテーブルを返す

        Args:
            box (List[int]): 検索するバウンディングボックス [x1, y1, x2, y2]
        """
        ratios = []
        for table in self.tables:
            overlap_ratio = calc_overlap_ratio(box, table.box)[0]
            ratios.append(overlap_ratio)

        if not ratios:
            return None

        max_idx = ratios.index(max(ratios))
        return self.tables[max_idx] if ratios[max_idx] > 0.5 else None

    def search_kv_items_by_key(self, key: str) -> List[dict]:
        """
        search for key-value items or grid cells where the key matches the query string.
        クエリーに部分一致するキーを持つKVアイテムおよびグリッドセルを返す

        Args:
            key (str): 検索するクエリ文字列. キー部分に部分一致するものを検索
        """

        results: List[dict] = []
        for table in self.tables:
            table_results = table.search_kv_items_by_key(key)
            results.extend(table_results)

        return results

    def load_template_json(self, template_path: str) -> "TableSemanticParserSchema":
        with open(template_path, "r", encoding="utf-8") as f:
            data = json.load(f)
        template = TableSemanticParserTemplateSchema.model_validate(data)
        return apply_table_template(self, template)

    def save_template_json(
        self, out_path: str, include_kv: bool = True, include_grids: bool = True
    ):
        template_tables: List[TableSemanticContentsTemplateSchema] = []

        for t in self.tables:
            tmp_cells: Dict[str, CellTemplateSchema] = {}
            for cid, c in t.cells.items():
                if c.role == "group":
                    continue

                tmp_cells[str(cid)] = CellTemplateSchema(
                    id=str(c.id) if c.id is not None else str(cid),
                    box=list(c.box) if c.box is not None else None,
                    role=c.role,
                    contents=c.contents,
                )

            template_tables.append(
                TableSemanticContentsTemplateSchema(
                    id=t.id,
                    style=t.style,
                    box=list(t.box),
                    cells=tmp_cells,
                    kv_items=t.kv_items if include_kv else None,
                    grids=t.grids if include_grids else None,
                )
            )

        template = TableSemanticParserTemplateSchema(
            meta=TemplateMetaSchema(),
            tables=template_tables,
        )

        with open(out_path, "w", encoding="utf-8") as f:
            json.dump(
                template.model_dump(exclude_none=True), f, ensure_ascii=False, indent=4
            )

find_table_by_id(table_id)

Search for a table by its ID. テーブルIDに対応するテーブルを返す

Parameters:

Name Type Description Default
table_id str

検索するテーブルID

required
Source code in src/yomitoku/schemas/table_semantic_parser.py
def find_table_by_id(
    self, table_id: str
) -> Union[TableSemanticContentsSchema, None]:
    """
    Search for a table by its ID.
    テーブルIDに対応するテーブルを返す

    Args:
        table_id (str): 検索するテーブルID
    """
    for table in self.tables:
        if table.id == str(table_id):
            return table

find_table_by_position(box)

Search for a table by its bounding box. テーブルの位置情報(bounding box)に対応するテーブルを返す

Parameters:

Name Type Description Default
box List[int]

検索するバウンディングボックス [x1, y1, x2, y2]

required
Source code in src/yomitoku/schemas/table_semantic_parser.py
def find_table_by_position(
    self, box: List[int]
) -> Union[TableSemanticContentsSchema, None]:
    """
    Search for a table by its bounding box.
    テーブルの位置情報(bounding box)に対応するテーブルを返す

    Args:
        box (List[int]): 検索するバウンディングボックス [x1, y1, x2, y2]
    """
    ratios = []
    for table in self.tables:
        overlap_ratio = calc_overlap_ratio(box, table.box)[0]
        ratios.append(overlap_ratio)

    if not ratios:
        return None

    max_idx = ratios.index(max(ratios))
    return self.tables[max_idx] if ratios[max_idx] > 0.5 else None

search_kv_items_by_key(key)

search for key-value items or grid cells where the key matches the query string. クエリーに部分一致するキーを持つKVアイテムおよびグリッドセルを返す

Parameters:

Name Type Description Default
key str

検索するクエリ文字列. キー部分に部分一致するものを検索

required
Source code in src/yomitoku/schemas/table_semantic_parser.py
def search_kv_items_by_key(self, key: str) -> List[dict]:
    """
    search for key-value items or grid cells where the key matches the query string.
    クエリーに部分一致するキーを持つKVアイテムおよびグリッドセルを返す

    Args:
        key (str): 検索するクエリ文字列. キー部分に部分一致するものを検索
    """

    results: List[dict] = []
    for table in self.tables:
        table_results = table.search_kv_items_by_key(key)
        results.extend(table_results)

    return results

search_words_by_position(bbox)

Search for words by their bounding box. 位置情報(bounding box)に対応する文字列を返す

Parameters:

Name Type Description Default
box List[int]

検索するバウンディングボックス [x1, y1, x2, y2]

required
Source code in src/yomitoku/schemas/table_semantic_parser.py
def search_words_by_position(self, bbox) -> str:
    """
    Search for words by their bounding box.
    位置情報(bounding box)に対応する文字列を返す

    Args:
        box (List[int]): 検索するバウンディングボックス [x1, y1, x2, y2]
    """
    words = []
    for word in self.words:
        word_box = quad_to_xyxy(word.points)
        if is_contained(bbox, word_box, threshold=0.5):
            word = ParagraphSchema(
                box=word_box,
                contents=word.content,
                direction=word.direction,
                role=None,
                order=None,
                indent_level=None,
            )

            words.append(word)

    word_direction = [word.direction for word in words]
    cnt_horizontal = word_direction.count("horizontal")
    cnt_vertical = word_direction.count("vertical")

    element_direction = (
        "horizontal" if cnt_horizontal > cnt_vertical else "vertical"
    )
    order = "left2right" if element_direction == "horizontal" else "right2left"
    words = prediction_reading_order(words, order)
    words = sorted(words, key=lambda x: x.order)

    return "".join([word.contents for word in words])

to_dict(separator='\n')

テーブルIDごとの構造化情報 (kv_items / grids) を dict で返す。

kv_items は to_simple と同じく、キーセルの入れ子構造を保った 階層dictになる (kv_items_to_nested を参照)。同一キーセル列の 複数 value は separator で結合される。

Source code in src/yomitoku/schemas/table_semantic_parser.py
def to_dict(self, separator="\n"):
    """テーブルIDごとの構造化情報 (kv_items / grids) を dict で返す。

    kv_items は to_simple と同じく、キーセルの入れ子構造を保った
    階層dictになる (kv_items_to_nested を参照)。同一キーセル列の
    複数 value は separator で結合される。
    """
    results = {}
    for table in self.tables:
        result = {
            "kv_items": table.view.kv_items_to_nested(separator=separator),
            "grids": table.view.grids_to_dict(),
        }
        results[table.id] = result

    return results

to_simple(separator='\n')

座標などのメタ情報を持たないテキストのみの構造化形に変換する。

to_structured からセル参照・座標・スコア類を落とした形。 kv_items はキーセルの入れ子構造を保った階層dictになる (kv_items_to_nested を参照)。同一キーの結合挙動は to_structured と 同一。grid の行内でヘッダテキストが重複する場合は _0/_1 の インデックスを付与して値の消失を防ぐ。

Source code in src/yomitoku/schemas/table_semantic_parser.py
def to_simple(self, separator="\n") -> SimpleDocumentSchema:
    """座標などのメタ情報を持たないテキストのみの構造化形に変換する。

    to_structured からセル参照・座標・スコア類を落とした形。
    kv_items はキーセルの入れ子構造を保った階層dictになる
    (kv_items_to_nested を参照)。同一キーの結合挙動は to_structured と
    同一。grid の行内でヘッダテキストが重複する場合は _0/_1 の
    インデックスを付与して値の消失を防ぐ。
    """
    doc = self.to_structured(separator=separator)

    tables = []
    for src_table, table in zip(self.tables, doc.tables):
        grids = []
        for grid in table.grids:
            rows = []
            for row in grid.rows:
                keys = make_unique_all([list(e.key) for e in row.cells])
                rows.append(
                    {
                        "_".join(map(str, k)): e.value
                        for k, e in zip(keys, row.cells)
                    }
                )
            grids.append(SimpleGridSchema(id=grid.id, rows=rows))

        tables.append(
            SimpleTableSchema(
                id=table.id,
                kv_items=src_table.view.kv_items_to_nested(separator=separator),
                grids=grids,
            )
        )

    return SimpleDocumentSchema(
        tables=tables,
        paragraphs=[p.contents for p in doc.paragraphs],
    )

to_structured(separator='\n')

ドキュメント全体を、テキストとセル座標を解決した構造化形に変換する。

to_dict のkey-value構造に加えて、各エントリに由来セルのIDと座標 (key_cells / value_cells) を埋め込み、paragraphs も含める。

Source code in src/yomitoku/schemas/table_semantic_parser.py
def to_structured(self, separator="\n") -> StructuredDocumentSchema:
    """ドキュメント全体を、テキストとセル座標を解決した構造化形に変換する。

    to_dict のkey-value構造に加えて、各エントリに由来セルのIDと座標
    (key_cells / value_cells) を埋め込み、paragraphs も含める。
    """
    tables = []
    for table in self.tables:
        tables.append(
            StructuredTableSchema(
                id=table.id,
                box=table.box,
                style=table.style,
                kv_items=table.view.kv_items_to_structured(separator=separator),
                grids=table.view.grids_to_structured(),
            )
        )

    return StructuredDocumentSchema(tables=tables, paragraphs=self.paragraphs)