document-adapter 0.7.1__tar.gz → 0.7.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {document_adapter-0.7.1/document_adapter.egg-info → document_adapter-0.7.2}/PKG-INFO +65 -20
- {document_adapter-0.7.1 → document_adapter-0.7.2}/README.md +64 -19
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/tools.py +19 -5
- {document_adapter-0.7.1 → document_adapter-0.7.2/document_adapter.egg-info}/PKG-INFO +65 -20
- {document_adapter-0.7.1 → document_adapter-0.7.2}/pyproject.toml +1 -1
- {document_adapter-0.7.1 → document_adapter-0.7.2}/LICENSE +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/NOTICE +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/__init__.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/base.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/docx_adapter.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/hwpx_adapter.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/hwpx_core/__init__.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/hwpx_core/constants.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/hwpx_core/grid.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/hwpx_core/package.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/hwpx_core/paragraph.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/mcp_server.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter/pptx_adapter.py +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter.egg-info/SOURCES.txt +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter.egg-info/dependency_links.txt +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter.egg-info/entry_points.txt +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter.egg-info/requires.txt +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter.egg-info/top_level.txt +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/setup.cfg +0 -0
- {document_adapter-0.7.1 → document_adapter-0.7.2}/tests/test_smoke.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: document-adapter
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: LLM-friendly document template editing (DOCX/PPTX/HWPX) with MCP server and Claude API tool-use support
|
|
5
5
|
Author-email: Son Seongjun <sonsj97@plateer.com>
|
|
6
6
|
License: MIT
|
|
@@ -127,13 +127,46 @@ doc.append_to_cell(table_index=2, row=0, col=0, value="홍길동")
|
|
|
127
127
|
cell = doc.get_cell(table_index=1, row=3, col=2)
|
|
128
128
|
print(cell.text, cell.is_anchor, cell.span, cell.nested_table_indices)
|
|
129
129
|
|
|
130
|
-
# DOCX/HWPX
|
|
130
|
+
# DOCX/PPTX/HWPX 전부 행 추가 지원 (v0.5+)
|
|
131
131
|
doc.append_row(1, ["새 항목", "값"])
|
|
132
132
|
|
|
133
133
|
doc.save("checklist_filled.docx")
|
|
134
134
|
doc.close()
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
### 라벨 기반 일괄 채우기 (v0.7+)
|
|
138
|
+
|
|
139
|
+
LLM 이 좌표 `(table_index, row, col)` 를 직접 계산하지 않고 "접수번호", "성명" 같은 사람이 읽는 라벨 key-value 로 양식을 채울 수 있습니다.
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
doc = load("form.hwpx")
|
|
143
|
+
result = doc.fill_form({
|
|
144
|
+
"접수번호": "2026-0001",
|
|
145
|
+
"성 명": "홍길동",
|
|
146
|
+
"주 소": "서울시 강남구",
|
|
147
|
+
"금융회사": "국민은행",
|
|
148
|
+
})
|
|
149
|
+
# → {"filled": [...], "not_found": [...], "ambiguous": [...]}
|
|
150
|
+
doc.save()
|
|
151
|
+
doc.close()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
- `auto` (기본): 라벨 셀 오른쪽 → 아래 → 같은 셀 순으로 값 셀 탐색. 보수적이라 기존 값 있는 셀은 다른 라벨로 간주하고 skip.
|
|
155
|
+
- `direction="right"` 명시: 라벨 오른쪽 셀을 **덮어쓰기** (예시값 있는 PPTX 템플릿 등).
|
|
156
|
+
- **Dot-path 섹션 지정**: 동일 라벨이 여러 섹션에 있으면 `"피해자.금액"`, `"지급정지요청계좌.금액"` 처럼 섹션 힌트 부여. `ambiguous` 반환 시 `hint` 필드에 예시 제공.
|
|
157
|
+
- **팁**: 한 양식의 관련 라벨을 한 번에 dict 로 넘기면 라벨끼리 서로 보호되어 오염을 방지합니다.
|
|
158
|
+
|
|
159
|
+
### 셀 크기 메타 (v0.6+)
|
|
160
|
+
|
|
161
|
+
`get_tables()`가 `column_widths_cm` / `row_heights_cm` 를, `get_cell()`이 `width_cm` / `height_cm` / `char_count` 를 반환해 LLM이 **좁은 셀에 긴 텍스트를 넣어 오버플로 되는 것을 사전에 판단**할 수 있습니다.
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
cell = doc.get_cell(table_index=0, row=0, col=0)
|
|
165
|
+
print(cell.width_cm, cell.char_count) # 1.7cm, 4자 — 작은 배지
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
DOCX/PPTX는 EMU → cm, HWPX는 HU → cm 자동 환산 (1자리 반올림).
|
|
169
|
+
|
|
137
170
|
확장자로 자동 분기되므로 `.pptx` / `.hwpx`도 동일한 API를 사용합니다.
|
|
138
171
|
|
|
139
172
|
### 병합 셀 인지 동작 (v0.2+)
|
|
@@ -185,7 +218,7 @@ document-adapter-mcp
|
|
|
185
218
|
}
|
|
186
219
|
```
|
|
187
220
|
|
|
188
|
-
재시작하면 Claude Desktop에서 아래
|
|
221
|
+
재시작하면 Claude Desktop에서 아래 7개 도구를 사용할 수 있습니다.
|
|
189
222
|
|
|
190
223
|
### Claude Code 설정
|
|
191
224
|
|
|
@@ -227,12 +260,13 @@ resp = client.messages.create(
|
|
|
227
260
|
|
|
228
261
|
| 도구 | 설명 |
|
|
229
262
|
|---|---|
|
|
230
|
-
| `inspect_document` | 문서 구조(placeholders, tables)를 JSON으로 반환. **항상 첫 호출로 사용** |
|
|
263
|
+
| `inspect_document` | 문서 구조(placeholders, tables + `column_widths_cm`/`row_heights_cm`)를 JSON으로 반환. **항상 첫 호출로 사용** |
|
|
231
264
|
| `render_template` | `{{key}}`를 context dict 값으로 치환해 새 파일 저장 |
|
|
232
|
-
| `get_cell` | 셀 전체 텍스트 + 병합/중첩 메타
|
|
265
|
+
| `get_cell` | 셀 전체 텍스트 + 병합/중첩 메타 + `width_cm`/`height_cm`/`char_count` 반환 |
|
|
233
266
|
| `set_cell` | 특정 표의 `(row, col)` 셀 값 교체 (병합 anchor만) |
|
|
234
267
|
| `append_to_cell` | 기존 텍스트 뒤에 값 덧붙임 (라벨 유지용, 예: `"성 명"` → `"성 명 홍길동"`) |
|
|
235
|
-
| `
|
|
268
|
+
| `fill_form` (v0.7+) | **라벨 이름**으로 일괄 채우기. 좌표 계산 없이 `{"접수번호": "...", "성명": "..."}` dict. dot-path 섹션 해소 지원 |
|
|
269
|
+
| `append_row` | 표 끝에 새 행 추가 (DOCX/PPTX/HWPX 전부 지원, v0.5+) |
|
|
236
270
|
|
|
237
271
|
### `inspect_document` 반환 예시 (v0.2+)
|
|
238
272
|
|
|
@@ -294,13 +328,12 @@ LLM은 이 preview를 보고 **"빈 셀이 어디 있는지 / 어떤 값을 넣
|
|
|
294
328
|
|
|
295
329
|
loop / if / filter는 지원하지 않습니다. PPTX는 placeholder가 여러 `run`으로 쪼개질 수 있어, 어댑터가 paragraph 전체 텍스트를 재조립한 뒤 첫 `run`에 다시 담는 방식으로 처리합니다 (서식 일부 손실 가능).
|
|
296
330
|
|
|
297
|
-
## 내장된 버그 회피
|
|
331
|
+
## 내장된 버그 회피 / 백엔드 선택
|
|
298
332
|
|
|
299
333
|
| 포맷 | 문제 | 어댑터의 처리 |
|
|
300
334
|
|---|---|---|
|
|
301
|
-
| HWPX | `python-hwpx
|
|
302
|
-
|
|
|
303
|
-
| HWPX | `manifest fallback` 경고 로그가 과도하게 출력됨 | `logging.getLogger("hwpx")` 레벨을 `ERROR`로 조정 |
|
|
335
|
+
| HWPX | `python-hwpx` 가 Non-Commercial License → 상용 배포 블로커 | **v0.4.0 부터 자체 `hwpx_core` 모듈** (zipfile + lxml) 로 교체. 런타임에 `python-hwpx` 불필요. 테스트 fixture 생성에만 사용 (dev extras) |
|
|
336
|
+
| PPTX | `python-pptx` 에 공식 `add_row` API 없음 (issue #86, 2014년부터 open) | **v0.5.0 부터 자체 lxml 구현** (`<a:tr>` deepcopy 패턴) |
|
|
304
337
|
| PPTX | placeholder가 여러 `run`으로 쪼개져 단순 `run.text` 치환이 실패 | paragraph 전체 재조립 |
|
|
305
338
|
| DOCX | `docxtpl`의 `{%tr%}`를 같은 행에 두면 파싱 에러 | README에 배치 규칙 명시 |
|
|
306
339
|
|
|
@@ -309,15 +342,20 @@ loop / if / filter는 지원하지 않습니다. PPTX는 placeholder가 여러 `
|
|
|
309
342
|
```
|
|
310
343
|
document_adapter/
|
|
311
344
|
├── __init__.py # load() dispatcher
|
|
312
|
-
├── base.py # DocumentAdapter ABC
|
|
345
|
+
├── base.py # DocumentAdapter ABC + fill_form + dataclasses
|
|
313
346
|
├── docx_adapter.py # DocxAdapter
|
|
314
|
-
├── pptx_adapter.py # PptxAdapter
|
|
315
|
-
├── hwpx_adapter.py # HwpxAdapter (
|
|
316
|
-
├──
|
|
347
|
+
├── pptx_adapter.py # PptxAdapter (append_row 자체 구현 포함)
|
|
348
|
+
├── hwpx_adapter.py # HwpxAdapter (hwpx_core 기반)
|
|
349
|
+
├── hwpx_core/ # 자체 HWPX 패키지 (v0.4+)
|
|
350
|
+
│ ├── constants.py
|
|
351
|
+
│ ├── package.py # ZIP + dirty XML 관리
|
|
352
|
+
│ ├── grid.py # iter_grid, table_shape
|
|
353
|
+
│ └── paragraph.py # run-level 편집 헬퍼
|
|
354
|
+
├── tools.py # 7개 MCP 도구 정의 + call_tool dispatcher
|
|
317
355
|
└── mcp_server.py # MCP stdio server
|
|
318
356
|
|
|
319
357
|
examples/
|
|
320
|
-
└── claude_api_example.py
|
|
358
|
+
└── claude_api_example.py # Claude API Tool Use 에이전트 루프
|
|
321
359
|
```
|
|
322
360
|
|
|
323
361
|
## 라이선스
|
|
@@ -326,8 +364,15 @@ MIT
|
|
|
326
364
|
|
|
327
365
|
## Credits
|
|
328
366
|
|
|
329
|
-
|
|
330
|
-
- [`
|
|
331
|
-
- [`
|
|
332
|
-
- [`python-
|
|
333
|
-
- [`
|
|
367
|
+
**런타임 의존성** (전부 허용형 OSS):
|
|
368
|
+
- [`python-docx`](https://github.com/python-openxml/python-docx) — MIT
|
|
369
|
+
- [`docxtpl`](https://github.com/elapouya/python-docx-template) — LGPL-2.1
|
|
370
|
+
- [`python-pptx`](https://github.com/scanny/python-pptx) — MIT
|
|
371
|
+
- [`lxml`](https://lxml.de/) — BSD
|
|
372
|
+
- [`mcp`](https://github.com/modelcontextprotocol/python-sdk) — MIT
|
|
373
|
+
|
|
374
|
+
**코드 참조**:
|
|
375
|
+
- [`xgen-doc2chunk`](https://github.com/PlateerLab/xgen-doc2chunk) (Apache-2.0) — HWPX table grid 파싱 로직 차용 (`NOTICE` 참조)
|
|
376
|
+
|
|
377
|
+
**Dev 전용** (fixture 생성에만 사용):
|
|
378
|
+
- [`python-hwpx`](https://github.com/airmang/python-hwpx) — Non-Commercial License (v0.4.0 부터 런타임 의존성 제거)
|
|
@@ -86,13 +86,46 @@ doc.append_to_cell(table_index=2, row=0, col=0, value="홍길동")
|
|
|
86
86
|
cell = doc.get_cell(table_index=1, row=3, col=2)
|
|
87
87
|
print(cell.text, cell.is_anchor, cell.span, cell.nested_table_indices)
|
|
88
88
|
|
|
89
|
-
# DOCX/HWPX
|
|
89
|
+
# DOCX/PPTX/HWPX 전부 행 추가 지원 (v0.5+)
|
|
90
90
|
doc.append_row(1, ["새 항목", "값"])
|
|
91
91
|
|
|
92
92
|
doc.save("checklist_filled.docx")
|
|
93
93
|
doc.close()
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
### 라벨 기반 일괄 채우기 (v0.7+)
|
|
97
|
+
|
|
98
|
+
LLM 이 좌표 `(table_index, row, col)` 를 직접 계산하지 않고 "접수번호", "성명" 같은 사람이 읽는 라벨 key-value 로 양식을 채울 수 있습니다.
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
doc = load("form.hwpx")
|
|
102
|
+
result = doc.fill_form({
|
|
103
|
+
"접수번호": "2026-0001",
|
|
104
|
+
"성 명": "홍길동",
|
|
105
|
+
"주 소": "서울시 강남구",
|
|
106
|
+
"금융회사": "국민은행",
|
|
107
|
+
})
|
|
108
|
+
# → {"filled": [...], "not_found": [...], "ambiguous": [...]}
|
|
109
|
+
doc.save()
|
|
110
|
+
doc.close()
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
- `auto` (기본): 라벨 셀 오른쪽 → 아래 → 같은 셀 순으로 값 셀 탐색. 보수적이라 기존 값 있는 셀은 다른 라벨로 간주하고 skip.
|
|
114
|
+
- `direction="right"` 명시: 라벨 오른쪽 셀을 **덮어쓰기** (예시값 있는 PPTX 템플릿 등).
|
|
115
|
+
- **Dot-path 섹션 지정**: 동일 라벨이 여러 섹션에 있으면 `"피해자.금액"`, `"지급정지요청계좌.금액"` 처럼 섹션 힌트 부여. `ambiguous` 반환 시 `hint` 필드에 예시 제공.
|
|
116
|
+
- **팁**: 한 양식의 관련 라벨을 한 번에 dict 로 넘기면 라벨끼리 서로 보호되어 오염을 방지합니다.
|
|
117
|
+
|
|
118
|
+
### 셀 크기 메타 (v0.6+)
|
|
119
|
+
|
|
120
|
+
`get_tables()`가 `column_widths_cm` / `row_heights_cm` 를, `get_cell()`이 `width_cm` / `height_cm` / `char_count` 를 반환해 LLM이 **좁은 셀에 긴 텍스트를 넣어 오버플로 되는 것을 사전에 판단**할 수 있습니다.
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
cell = doc.get_cell(table_index=0, row=0, col=0)
|
|
124
|
+
print(cell.width_cm, cell.char_count) # 1.7cm, 4자 — 작은 배지
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
DOCX/PPTX는 EMU → cm, HWPX는 HU → cm 자동 환산 (1자리 반올림).
|
|
128
|
+
|
|
96
129
|
확장자로 자동 분기되므로 `.pptx` / `.hwpx`도 동일한 API를 사용합니다.
|
|
97
130
|
|
|
98
131
|
### 병합 셀 인지 동작 (v0.2+)
|
|
@@ -144,7 +177,7 @@ document-adapter-mcp
|
|
|
144
177
|
}
|
|
145
178
|
```
|
|
146
179
|
|
|
147
|
-
재시작하면 Claude Desktop에서 아래
|
|
180
|
+
재시작하면 Claude Desktop에서 아래 7개 도구를 사용할 수 있습니다.
|
|
148
181
|
|
|
149
182
|
### Claude Code 설정
|
|
150
183
|
|
|
@@ -186,12 +219,13 @@ resp = client.messages.create(
|
|
|
186
219
|
|
|
187
220
|
| 도구 | 설명 |
|
|
188
221
|
|---|---|
|
|
189
|
-
| `inspect_document` | 문서 구조(placeholders, tables)를 JSON으로 반환. **항상 첫 호출로 사용** |
|
|
222
|
+
| `inspect_document` | 문서 구조(placeholders, tables + `column_widths_cm`/`row_heights_cm`)를 JSON으로 반환. **항상 첫 호출로 사용** |
|
|
190
223
|
| `render_template` | `{{key}}`를 context dict 값으로 치환해 새 파일 저장 |
|
|
191
|
-
| `get_cell` | 셀 전체 텍스트 + 병합/중첩 메타
|
|
224
|
+
| `get_cell` | 셀 전체 텍스트 + 병합/중첩 메타 + `width_cm`/`height_cm`/`char_count` 반환 |
|
|
192
225
|
| `set_cell` | 특정 표의 `(row, col)` 셀 값 교체 (병합 anchor만) |
|
|
193
226
|
| `append_to_cell` | 기존 텍스트 뒤에 값 덧붙임 (라벨 유지용, 예: `"성 명"` → `"성 명 홍길동"`) |
|
|
194
|
-
| `
|
|
227
|
+
| `fill_form` (v0.7+) | **라벨 이름**으로 일괄 채우기. 좌표 계산 없이 `{"접수번호": "...", "성명": "..."}` dict. dot-path 섹션 해소 지원 |
|
|
228
|
+
| `append_row` | 표 끝에 새 행 추가 (DOCX/PPTX/HWPX 전부 지원, v0.5+) |
|
|
195
229
|
|
|
196
230
|
### `inspect_document` 반환 예시 (v0.2+)
|
|
197
231
|
|
|
@@ -253,13 +287,12 @@ LLM은 이 preview를 보고 **"빈 셀이 어디 있는지 / 어떤 값을 넣
|
|
|
253
287
|
|
|
254
288
|
loop / if / filter는 지원하지 않습니다. PPTX는 placeholder가 여러 `run`으로 쪼개질 수 있어, 어댑터가 paragraph 전체 텍스트를 재조립한 뒤 첫 `run`에 다시 담는 방식으로 처리합니다 (서식 일부 손실 가능).
|
|
255
289
|
|
|
256
|
-
## 내장된 버그 회피
|
|
290
|
+
## 내장된 버그 회피 / 백엔드 선택
|
|
257
291
|
|
|
258
292
|
| 포맷 | 문제 | 어댑터의 처리 |
|
|
259
293
|
|---|---|---|
|
|
260
|
-
| HWPX | `python-hwpx
|
|
261
|
-
|
|
|
262
|
-
| HWPX | `manifest fallback` 경고 로그가 과도하게 출력됨 | `logging.getLogger("hwpx")` 레벨을 `ERROR`로 조정 |
|
|
294
|
+
| HWPX | `python-hwpx` 가 Non-Commercial License → 상용 배포 블로커 | **v0.4.0 부터 자체 `hwpx_core` 모듈** (zipfile + lxml) 로 교체. 런타임에 `python-hwpx` 불필요. 테스트 fixture 생성에만 사용 (dev extras) |
|
|
295
|
+
| PPTX | `python-pptx` 에 공식 `add_row` API 없음 (issue #86, 2014년부터 open) | **v0.5.0 부터 자체 lxml 구현** (`<a:tr>` deepcopy 패턴) |
|
|
263
296
|
| PPTX | placeholder가 여러 `run`으로 쪼개져 단순 `run.text` 치환이 실패 | paragraph 전체 재조립 |
|
|
264
297
|
| DOCX | `docxtpl`의 `{%tr%}`를 같은 행에 두면 파싱 에러 | README에 배치 규칙 명시 |
|
|
265
298
|
|
|
@@ -268,15 +301,20 @@ loop / if / filter는 지원하지 않습니다. PPTX는 placeholder가 여러 `
|
|
|
268
301
|
```
|
|
269
302
|
document_adapter/
|
|
270
303
|
├── __init__.py # load() dispatcher
|
|
271
|
-
├── base.py # DocumentAdapter ABC
|
|
304
|
+
├── base.py # DocumentAdapter ABC + fill_form + dataclasses
|
|
272
305
|
├── docx_adapter.py # DocxAdapter
|
|
273
|
-
├── pptx_adapter.py # PptxAdapter
|
|
274
|
-
├── hwpx_adapter.py # HwpxAdapter (
|
|
275
|
-
├──
|
|
306
|
+
├── pptx_adapter.py # PptxAdapter (append_row 자체 구현 포함)
|
|
307
|
+
├── hwpx_adapter.py # HwpxAdapter (hwpx_core 기반)
|
|
308
|
+
├── hwpx_core/ # 자체 HWPX 패키지 (v0.4+)
|
|
309
|
+
│ ├── constants.py
|
|
310
|
+
│ ├── package.py # ZIP + dirty XML 관리
|
|
311
|
+
│ ├── grid.py # iter_grid, table_shape
|
|
312
|
+
│ └── paragraph.py # run-level 편집 헬퍼
|
|
313
|
+
├── tools.py # 7개 MCP 도구 정의 + call_tool dispatcher
|
|
276
314
|
└── mcp_server.py # MCP stdio server
|
|
277
315
|
|
|
278
316
|
examples/
|
|
279
|
-
└── claude_api_example.py
|
|
317
|
+
└── claude_api_example.py # Claude API Tool Use 에이전트 루프
|
|
280
318
|
```
|
|
281
319
|
|
|
282
320
|
## 라이선스
|
|
@@ -285,8 +323,15 @@ MIT
|
|
|
285
323
|
|
|
286
324
|
## Credits
|
|
287
325
|
|
|
288
|
-
|
|
289
|
-
- [`
|
|
290
|
-
- [`
|
|
291
|
-
- [`python-
|
|
292
|
-
- [`
|
|
326
|
+
**런타임 의존성** (전부 허용형 OSS):
|
|
327
|
+
- [`python-docx`](https://github.com/python-openxml/python-docx) — MIT
|
|
328
|
+
- [`docxtpl`](https://github.com/elapouya/python-docx-template) — LGPL-2.1
|
|
329
|
+
- [`python-pptx`](https://github.com/scanny/python-pptx) — MIT
|
|
330
|
+
- [`lxml`](https://lxml.de/) — BSD
|
|
331
|
+
- [`mcp`](https://github.com/modelcontextprotocol/python-sdk) — MIT
|
|
332
|
+
|
|
333
|
+
**코드 참조**:
|
|
334
|
+
- [`xgen-doc2chunk`](https://github.com/PlateerLab/xgen-doc2chunk) (Apache-2.0) — HWPX table grid 파싱 로직 차용 (`NOTICE` 참조)
|
|
335
|
+
|
|
336
|
+
**Dev 전용** (fixture 생성에만 사용):
|
|
337
|
+
- [`python-hwpx`](https://github.com/airmang/python-hwpx) — Non-Commercial License (v0.4.0 부터 런타임 의존성 제거)
|
|
@@ -177,11 +177,25 @@ TOOL_DEFINITIONS: list[dict[str, Any]] = [
|
|
|
177
177
|
"description": (
|
|
178
178
|
"라벨 이름으로 값 셀을 자동 탐지해 **일괄 채우기**. 좌표 (table_index, row, col) "
|
|
179
179
|
"계산 없이 '접수번호', '성명' 같은 라벨 key-value dict 로 양식 채움. "
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
180
|
+
"\n"
|
|
181
|
+
"**direction 선택 기준 (중요)**: "
|
|
182
|
+
"(a) `auto` (기본, 보수적): 기존 값이 있는 셀은 다른 라벨로 간주하고 skip → 같은 "
|
|
183
|
+
"셀에 append_to_cell. **값 셀이 비어있는 양식**에 적합 (HWPX 공공 서식 등). "
|
|
184
|
+
"(b) `right` / `below` (명시): 라벨 오른쪽/아래 셀을 **덮어쓰기**. **기존에 "
|
|
185
|
+
"예시값이 채워져 있는 양식**(PPTX 템플릿 등) 에는 반드시 direction='right' 명시. "
|
|
186
|
+
"\n"
|
|
187
|
+
"**Dot-path 섹션 지정**: 같은 라벨이 여러 섹션에 있어 ambiguous 로 반환되면 "
|
|
188
|
+
"`{'피해자.금액': '...', '지급정지요청계좌.금액': '...'}` 처럼 섹션힌트.라벨 "
|
|
189
|
+
"형태로 재호출. ambiguous 반환의 hint 필드에 예시 제공됨. "
|
|
190
|
+
"\n"
|
|
191
|
+
"**output_path**: 생략 시 **원본 파일에 덮어쓰기** (대부분의 경우 생략 권장). "
|
|
192
|
+
"다른 위치에 저장이 필요할 때만 지정. "
|
|
193
|
+
"\n"
|
|
194
|
+
"**팁**: 한 양식의 관련 라벨을 **한 번에 dict 로** 넘기면 라벨끼리 서로 보호되어 "
|
|
195
|
+
"인접 라벨 오염이 방지됩니다. "
|
|
196
|
+
"\n"
|
|
197
|
+
"반환: `{filled: [...], not_found: [...], ambiguous: [...]}`. "
|
|
198
|
+
"ambiguous candidates 각각에 `context` 필드 포함 (어느 섹션인지 확인)."
|
|
185
199
|
),
|
|
186
200
|
"input_schema": {
|
|
187
201
|
"type": "object",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: document-adapter
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.2
|
|
4
4
|
Summary: LLM-friendly document template editing (DOCX/PPTX/HWPX) with MCP server and Claude API tool-use support
|
|
5
5
|
Author-email: Son Seongjun <sonsj97@plateer.com>
|
|
6
6
|
License: MIT
|
|
@@ -127,13 +127,46 @@ doc.append_to_cell(table_index=2, row=0, col=0, value="홍길동")
|
|
|
127
127
|
cell = doc.get_cell(table_index=1, row=3, col=2)
|
|
128
128
|
print(cell.text, cell.is_anchor, cell.span, cell.nested_table_indices)
|
|
129
129
|
|
|
130
|
-
# DOCX/HWPX
|
|
130
|
+
# DOCX/PPTX/HWPX 전부 행 추가 지원 (v0.5+)
|
|
131
131
|
doc.append_row(1, ["새 항목", "값"])
|
|
132
132
|
|
|
133
133
|
doc.save("checklist_filled.docx")
|
|
134
134
|
doc.close()
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
+
### 라벨 기반 일괄 채우기 (v0.7+)
|
|
138
|
+
|
|
139
|
+
LLM 이 좌표 `(table_index, row, col)` 를 직접 계산하지 않고 "접수번호", "성명" 같은 사람이 읽는 라벨 key-value 로 양식을 채울 수 있습니다.
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
doc = load("form.hwpx")
|
|
143
|
+
result = doc.fill_form({
|
|
144
|
+
"접수번호": "2026-0001",
|
|
145
|
+
"성 명": "홍길동",
|
|
146
|
+
"주 소": "서울시 강남구",
|
|
147
|
+
"금융회사": "국민은행",
|
|
148
|
+
})
|
|
149
|
+
# → {"filled": [...], "not_found": [...], "ambiguous": [...]}
|
|
150
|
+
doc.save()
|
|
151
|
+
doc.close()
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
- `auto` (기본): 라벨 셀 오른쪽 → 아래 → 같은 셀 순으로 값 셀 탐색. 보수적이라 기존 값 있는 셀은 다른 라벨로 간주하고 skip.
|
|
155
|
+
- `direction="right"` 명시: 라벨 오른쪽 셀을 **덮어쓰기** (예시값 있는 PPTX 템플릿 등).
|
|
156
|
+
- **Dot-path 섹션 지정**: 동일 라벨이 여러 섹션에 있으면 `"피해자.금액"`, `"지급정지요청계좌.금액"` 처럼 섹션 힌트 부여. `ambiguous` 반환 시 `hint` 필드에 예시 제공.
|
|
157
|
+
- **팁**: 한 양식의 관련 라벨을 한 번에 dict 로 넘기면 라벨끼리 서로 보호되어 오염을 방지합니다.
|
|
158
|
+
|
|
159
|
+
### 셀 크기 메타 (v0.6+)
|
|
160
|
+
|
|
161
|
+
`get_tables()`가 `column_widths_cm` / `row_heights_cm` 를, `get_cell()`이 `width_cm` / `height_cm` / `char_count` 를 반환해 LLM이 **좁은 셀에 긴 텍스트를 넣어 오버플로 되는 것을 사전에 판단**할 수 있습니다.
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
cell = doc.get_cell(table_index=0, row=0, col=0)
|
|
165
|
+
print(cell.width_cm, cell.char_count) # 1.7cm, 4자 — 작은 배지
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
DOCX/PPTX는 EMU → cm, HWPX는 HU → cm 자동 환산 (1자리 반올림).
|
|
169
|
+
|
|
137
170
|
확장자로 자동 분기되므로 `.pptx` / `.hwpx`도 동일한 API를 사용합니다.
|
|
138
171
|
|
|
139
172
|
### 병합 셀 인지 동작 (v0.2+)
|
|
@@ -185,7 +218,7 @@ document-adapter-mcp
|
|
|
185
218
|
}
|
|
186
219
|
```
|
|
187
220
|
|
|
188
|
-
재시작하면 Claude Desktop에서 아래
|
|
221
|
+
재시작하면 Claude Desktop에서 아래 7개 도구를 사용할 수 있습니다.
|
|
189
222
|
|
|
190
223
|
### Claude Code 설정
|
|
191
224
|
|
|
@@ -227,12 +260,13 @@ resp = client.messages.create(
|
|
|
227
260
|
|
|
228
261
|
| 도구 | 설명 |
|
|
229
262
|
|---|---|
|
|
230
|
-
| `inspect_document` | 문서 구조(placeholders, tables)를 JSON으로 반환. **항상 첫 호출로 사용** |
|
|
263
|
+
| `inspect_document` | 문서 구조(placeholders, tables + `column_widths_cm`/`row_heights_cm`)를 JSON으로 반환. **항상 첫 호출로 사용** |
|
|
231
264
|
| `render_template` | `{{key}}`를 context dict 값으로 치환해 새 파일 저장 |
|
|
232
|
-
| `get_cell` | 셀 전체 텍스트 + 병합/중첩 메타
|
|
265
|
+
| `get_cell` | 셀 전체 텍스트 + 병합/중첩 메타 + `width_cm`/`height_cm`/`char_count` 반환 |
|
|
233
266
|
| `set_cell` | 특정 표의 `(row, col)` 셀 값 교체 (병합 anchor만) |
|
|
234
267
|
| `append_to_cell` | 기존 텍스트 뒤에 값 덧붙임 (라벨 유지용, 예: `"성 명"` → `"성 명 홍길동"`) |
|
|
235
|
-
| `
|
|
268
|
+
| `fill_form` (v0.7+) | **라벨 이름**으로 일괄 채우기. 좌표 계산 없이 `{"접수번호": "...", "성명": "..."}` dict. dot-path 섹션 해소 지원 |
|
|
269
|
+
| `append_row` | 표 끝에 새 행 추가 (DOCX/PPTX/HWPX 전부 지원, v0.5+) |
|
|
236
270
|
|
|
237
271
|
### `inspect_document` 반환 예시 (v0.2+)
|
|
238
272
|
|
|
@@ -294,13 +328,12 @@ LLM은 이 preview를 보고 **"빈 셀이 어디 있는지 / 어떤 값을 넣
|
|
|
294
328
|
|
|
295
329
|
loop / if / filter는 지원하지 않습니다. PPTX는 placeholder가 여러 `run`으로 쪼개질 수 있어, 어댑터가 paragraph 전체 텍스트를 재조립한 뒤 첫 `run`에 다시 담는 방식으로 처리합니다 (서식 일부 손실 가능).
|
|
296
330
|
|
|
297
|
-
## 내장된 버그 회피
|
|
331
|
+
## 내장된 버그 회피 / 백엔드 선택
|
|
298
332
|
|
|
299
333
|
| 포맷 | 문제 | 어댑터의 처리 |
|
|
300
334
|
|---|---|---|
|
|
301
|
-
| HWPX | `python-hwpx
|
|
302
|
-
|
|
|
303
|
-
| HWPX | `manifest fallback` 경고 로그가 과도하게 출력됨 | `logging.getLogger("hwpx")` 레벨을 `ERROR`로 조정 |
|
|
335
|
+
| HWPX | `python-hwpx` 가 Non-Commercial License → 상용 배포 블로커 | **v0.4.0 부터 자체 `hwpx_core` 모듈** (zipfile + lxml) 로 교체. 런타임에 `python-hwpx` 불필요. 테스트 fixture 생성에만 사용 (dev extras) |
|
|
336
|
+
| PPTX | `python-pptx` 에 공식 `add_row` API 없음 (issue #86, 2014년부터 open) | **v0.5.0 부터 자체 lxml 구현** (`<a:tr>` deepcopy 패턴) |
|
|
304
337
|
| PPTX | placeholder가 여러 `run`으로 쪼개져 단순 `run.text` 치환이 실패 | paragraph 전체 재조립 |
|
|
305
338
|
| DOCX | `docxtpl`의 `{%tr%}`를 같은 행에 두면 파싱 에러 | README에 배치 규칙 명시 |
|
|
306
339
|
|
|
@@ -309,15 +342,20 @@ loop / if / filter는 지원하지 않습니다. PPTX는 placeholder가 여러 `
|
|
|
309
342
|
```
|
|
310
343
|
document_adapter/
|
|
311
344
|
├── __init__.py # load() dispatcher
|
|
312
|
-
├── base.py # DocumentAdapter ABC
|
|
345
|
+
├── base.py # DocumentAdapter ABC + fill_form + dataclasses
|
|
313
346
|
├── docx_adapter.py # DocxAdapter
|
|
314
|
-
├── pptx_adapter.py # PptxAdapter
|
|
315
|
-
├── hwpx_adapter.py # HwpxAdapter (
|
|
316
|
-
├──
|
|
347
|
+
├── pptx_adapter.py # PptxAdapter (append_row 자체 구현 포함)
|
|
348
|
+
├── hwpx_adapter.py # HwpxAdapter (hwpx_core 기반)
|
|
349
|
+
├── hwpx_core/ # 자체 HWPX 패키지 (v0.4+)
|
|
350
|
+
│ ├── constants.py
|
|
351
|
+
│ ├── package.py # ZIP + dirty XML 관리
|
|
352
|
+
│ ├── grid.py # iter_grid, table_shape
|
|
353
|
+
│ └── paragraph.py # run-level 편집 헬퍼
|
|
354
|
+
├── tools.py # 7개 MCP 도구 정의 + call_tool dispatcher
|
|
317
355
|
└── mcp_server.py # MCP stdio server
|
|
318
356
|
|
|
319
357
|
examples/
|
|
320
|
-
└── claude_api_example.py
|
|
358
|
+
└── claude_api_example.py # Claude API Tool Use 에이전트 루프
|
|
321
359
|
```
|
|
322
360
|
|
|
323
361
|
## 라이선스
|
|
@@ -326,8 +364,15 @@ MIT
|
|
|
326
364
|
|
|
327
365
|
## Credits
|
|
328
366
|
|
|
329
|
-
|
|
330
|
-
- [`
|
|
331
|
-
- [`
|
|
332
|
-
- [`python-
|
|
333
|
-
- [`
|
|
367
|
+
**런타임 의존성** (전부 허용형 OSS):
|
|
368
|
+
- [`python-docx`](https://github.com/python-openxml/python-docx) — MIT
|
|
369
|
+
- [`docxtpl`](https://github.com/elapouya/python-docx-template) — LGPL-2.1
|
|
370
|
+
- [`python-pptx`](https://github.com/scanny/python-pptx) — MIT
|
|
371
|
+
- [`lxml`](https://lxml.de/) — BSD
|
|
372
|
+
- [`mcp`](https://github.com/modelcontextprotocol/python-sdk) — MIT
|
|
373
|
+
|
|
374
|
+
**코드 참조**:
|
|
375
|
+
- [`xgen-doc2chunk`](https://github.com/PlateerLab/xgen-doc2chunk) (Apache-2.0) — HWPX table grid 파싱 로직 차용 (`NOTICE` 참조)
|
|
376
|
+
|
|
377
|
+
**Dev 전용** (fixture 생성에만 사용):
|
|
378
|
+
- [`python-hwpx`](https://github.com/airmang/python-hwpx) — Non-Commercial License (v0.4.0 부터 런타임 의존성 제거)
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "document-adapter"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.2"
|
|
8
8
|
description = "LLM-friendly document template editing (DOCX/PPTX/HWPX) with MCP server and Claude API tool-use support"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{document_adapter-0.7.1 → document_adapter-0.7.2}/document_adapter.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|