Metadata-Version: 2.4
Name: qc-structure
Version: 0.2.0
Summary: 入試問題構造情報ライブラリ - WordファイルとJSON構造データを統合処理
Author-email: kamarume <akamarume@icloud.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/AI-Part-A/auto_structuring
Project-URL: Repository, https://github.com/AI-Part-A/auto_structuring
Project-URL: Issues, https://github.com/AI-Part-A/auto_structuring/issues
Keywords: word,docx,structure,exam,質保証,QC
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing
Requires-Python: >=3.7
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-docx>=0.8.11
Dynamic: license-file

# qc-structure

`qc-structure` は、Word の段落と `structure.json` を結びつけて、品質管理コードを書きやすくするための Python ライブラリです。

このライブラリ自身は「連番チェック」や「太字チェック」を実装しません。代わりに、異常判定に必要な情報を段落オブジェクトへ付与します。

## 想定用途

- 異常がある段落の `index` を返す
- `role` や `label_text` を使って番号・体裁チェックを書く
- `ancestors` や `structure_by_id` を使って親子関係を辿る
- 必要に応じて `para_id` を使って Word XML にコメントを付ける

## インストール

```bash
pip install qc-structure
```

または:

```bash
pip install git+https://github.com/AI-Part-A/auto_structuring.git#subdirectory=qc_structure
```

## 基本方針

`qc_structure` では、3 種類の ID を役割分担して扱います。

- `index`: Word 内の段落順を表す番号。異常出力の主キー
- `pid`: `structure.json` 側の論理段落 ID
- `para_id`: Word XML (`w14:paraId`) の内部段落 ID

通常の品質管理コードでは `index` を主に使い、Word へ直接コメントを打ちたいときだけ `para_id` を使います。

## 最小利用例

```python
from qc_structure import load_exam_document

doc = load_exam_document("exam.docx", "structure.json")

findings = []
for p in doc.paragraphs:
    if p.role == "小問" and p.label_text is None:
        findings.append(
            {
                "index": p.index,
                "pid": p.pid,
                "para_id": p.para_id,
                "reason": "小問ラベルがありません",
            }
        )

print(findings)
```

## 使い方

```python
from qc_structure import load_exam_document

doc = load_exam_document("exam.docx", "structure.json")

for p in doc.paragraphs:
    print(
        p.index,
        p.pid,
        p.role,
        p.label_text,
        [node.id for node in p.ancestors],
        p.text[:40],
    )
```

親子関係を直接見たい場合:

```python
node = doc.structure_by_id["q1-1"]

print(node.id)
print(node.parent.id if node.parent else None)
print([child.id for child in node.children])
print(node.paragraph_indexes)
```

## 主な API

### `load_exam_document(docx_path, structure_json_path) -> ExamDocument`

`.docx` と `structure.json` を読み込みます。

### `ExamDocument`

- `paragraphs`: `list[EnhancedParagraph]`
- `structure_by_id`: `dict[str, StructureNode]`
- `root_nodes`: ルート構造ノード一覧
- `structure_nodes`: 全構造ノード一覧

### `EnhancedParagraph`

- `index`: 段落順の番号
- `pid`: 論理段落 ID
- `para_id`: Word 内部段落 ID
- `role`: 構造上の役割
- `id`: 構造 ID
- `parent_id`: 親構造 ID
- `label_text`: 見出しラベル
- `structure`: 生の構造 dict
- `node`: 対応する `StructureNode`
- `parent`: 親ノード
- `children`: 子ノード一覧
- `ancestors`: 祖先ノード一覧
- `structure_path`: root -> self のノード列
- `text`, `runs`, `style`: `python-docx` の段落 API

### `StructureNode`

- `id`
- `parent`
- `children`
- `role`
- `label_text`
- `start_pid`
- `end_pid`
- `paragraphs`
- `paragraph_indexes`
- `ancestors`
- `structure`

## `structure.json` の前提

`structure.json` には少なくとも次が必要です。

- `questions`
- `paragraph_mapping`

`paragraph_mapping` の最低要件:

```json
{
  "p0001": {
    "index": 0,
    "para_id": "00000001"
  }
}
```

- `index` は必須
- `para_id` は任意

`questions` はツリー形式に対応します。

```json
{
  "questions": [
    {
      "id": "q1",
      "role": "大問",
      "start_pid": "p0001",
      "end_pid": "p0037",
      "label_text": "I",
      "children": [
        {
          "id": "q1-1",
          "role": "小問",
          "parent_id": "q1",
          "start_pid": "p0002",
          "end_pid": "p0004",
          "label_text": "(1)",
          "children": []
        }
      ]
    }
  ],
  "paragraph_mapping": {
    "p0001": {"index": 0, "para_id": "00000001"},
    "p0002": {"index": 1, "para_id": "00000002"}
  }
}
```

## マッピング仕様

- 構造ノードは `start_pid` から `end_pid` の範囲で段落に対応します
- 段落解決は `index` を優先します
- `index` が使えない場合のみ `para_id` にフォールバックします
- 親子範囲が重なるときは、より深い子ノードが親ノードを上書きします

## ライセンス

MIT
