Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Versioning:
## [Unreleased]

### Added
- **`get_form_fields()` + inspect 중복 라벨 힌트** — 라벨 후보와 *중복(dot-path 필요)*
여부를 미리 보여준다. `inspect_document` 응답에 `duplicate_labels` + 힌트를 추가해
LLM 이 fill_form 전에 dot-path 필요를 인지(ambiguous 재시도 라운드 절감).
- **`diff_documents(path_a, path_b)`** — 편집 전/후 문서를 셀 단위로 비교해 변경된
셀의 before/after 와 overflow_risk 를 반환하는 **검증 도구**(MCP 도구 → 총 12 개).
fill 후 원본과 diff 해 "무엇이 어디서 바뀌었고 깨짐 위험은 없나" 를 LLM 이 스스로
Expand Down
33 changes: 33 additions & 0 deletions document_adapter/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,39 @@ def get_schema(self) -> DocumentSchema:
tables=self.get_tables(),
)

def get_form_fields(self) -> list[dict[str, Any]]:
"""표 셀 텍스트에서 라벨 후보와 **중복 여부(dot-path 필요)**를 미리 보여준다.

fill_form 호출 *전에* LLM 이 "어떤 라벨이 여러 곳에 있어 dot-path 로 구분해야
하는지" 를 알 수 있게 한다 — ambiguous 응답을 받고 재시도하는 라운드를 줄인다.

각 항목: {label, normalized, ambiguous, occurrences:[{table_index,row,col}]}.
(라벨로 보이는 비어있지 않은 anchor 셀 기준 — 빈 양식에서 가장 유용.)
"""
index: dict[str, list[dict[str, Any]]] = {}
labels: dict[str, str] = {}
for t in self.get_tables(preview_rows=10_000, max_cell_len=200):
for r, row in enumerate(t.preview):
for c, val in enumerate(row):
if not val:
continue
norm = _normalize_label(val)
if not norm:
continue
index.setdefault(norm, []).append(
{"table_index": t.index, "row": r, "col": c})
labels.setdefault(norm, val)
fields = [
{
"label": labels[norm],
"normalized": norm,
"ambiguous": len(occ) > 1,
"occurrences": occ,
}
for norm, occ in index.items()
]
return sorted(fields, key=lambda f: f["label"])

# ---- editing ----
@abstractmethod
def render_template(self, context: dict[str, Any], *,
Expand Down
15 changes: 15 additions & 0 deletions document_adapter/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,21 @@ def inspect_document(path: str, min_rows: int = 1, min_cols: int = 1) -> dict[st
except NotImplementedError:
pass # DOCX / HWPX 는 shape 개념 약함 — skip
result["tables"] = [t.to_dict() for t in filtered]

# 중복 라벨 힌트: 여러 곳에 같은 라벨이 있으면 fill_form 에서 ambiguous
# 가 되므로, 미리 dot-path 를 쓰라고 신호한다 (재시도 라운드 절감).
dups = [f for f in doc.get_form_fields() if f["ambiguous"]]
if dups:
result["duplicate_labels"] = [
{"label": f["label"],
"count": len(f["occurrences"]),
"locations": f["occurrences"]}
for f in dups
]
result["duplicate_labels_hint"] = (
"같은 라벨이 여러 곳에 있습니다. fill_form 에서 이 라벨들은 "
"dot-path(예: '피해자.금액')로 섹션을 구분해 채우세요."
)
return result
finally:
doc.close()
Expand Down
21 changes: 21 additions & 0 deletions tests/test_scenarios.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,27 @@ def test_pptx_notes_placeholders_and_render(tmp_path: Path) -> None:
assert any("확인됨" in n for n in notes)


def test_get_form_fields_and_duplicate_hint(tmp_path: Path) -> None:
"""get_form_fields 가 중복 라벨을 ambiguous 로 표시하고, inspect_document 가
duplicate_labels 힌트를 미리 제공해야 한다 (dot-path 재시도 절감)."""
from document_adapter.tools import call_tool

src = tmp_path / "dup.hwpx"
_make_form_hwpx(src, [("피해자정보", ""), ("금액", ""),
("지급정지", ""), ("금액", "")])
ad = load(src)
fields = {f["label"]: f for f in ad.get_form_fields()}
ad.close()
assert fields["금액"]["ambiguous"] is True
assert len(fields["금액"]["occurrences"]) == 2
assert fields["지급정지"]["ambiguous"] is False

r = call_tool("inspect_document", {"path": str(src)})
dups = {d["label"]: d for d in r.get("duplicate_labels", [])}
assert "금액" in dups and dups["금액"]["count"] == 2
assert "duplicate_labels_hint" in r


def test_diff_documents(tmp_path: Path) -> None:
"""diff_documents: 편집 전/후 변경 셀을 before/after + overflow 로 반환."""
import shutil
Expand Down
Loading