document-adapter 0.2.0__tar.gz → 0.3.0__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.2.0 → document_adapter-0.3.0}/PKG-INFO +63 -20
- {document_adapter-0.2.0 → document_adapter-0.3.0}/README.md +62 -19
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter/base.py +64 -1
- document_adapter-0.3.0/document_adapter/docx_adapter.py +352 -0
- document_adapter-0.3.0/document_adapter/hwpx_adapter.py +389 -0
- document_adapter-0.3.0/document_adapter/pptx_adapter.py +354 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter/tools.py +106 -17
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter.egg-info/PKG-INFO +63 -20
- {document_adapter-0.2.0 → document_adapter-0.3.0}/pyproject.toml +1 -1
- {document_adapter-0.2.0 → document_adapter-0.3.0}/tests/test_smoke.py +325 -0
- document_adapter-0.2.0/document_adapter/docx_adapter.py +0 -133
- document_adapter-0.2.0/document_adapter/hwpx_adapter.py +0 -246
- document_adapter-0.2.0/document_adapter/pptx_adapter.py +0 -178
- {document_adapter-0.2.0 → document_adapter-0.3.0}/LICENSE +0 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter/__init__.py +0 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter/mcp_server.py +0 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter.egg-info/SOURCES.txt +0 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter.egg-info/dependency_links.txt +0 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter.egg-info/entry_points.txt +0 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter.egg-info/requires.txt +0 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/document_adapter.egg-info/top_level.txt +0 -0
- {document_adapter-0.2.0 → document_adapter-0.3.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: document-adapter
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
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
|
|
@@ -53,14 +53,15 @@ Dynamic: license-file
|
|
|
53
53
|
|
|
54
54
|
## 지원 포맷
|
|
55
55
|
|
|
56
|
-
| 포맷 | 백엔드 | 템플릿 렌더 | 표 읽기 | 셀 수정 | 행 추가 |
|
|
57
|
-
|
|
58
|
-
| `.docx` | `docxtpl` + `python-docx` | Jinja2 (`{%tr%}` loop 포함) | ✅ | ✅ | ✅ |
|
|
59
|
-
| `.pptx` | `python-pptx` | `{{key}}` 치환 | ✅ (슬라이드 위치 포함) | ✅ | ❌ (미지원) |
|
|
60
|
-
| `.hwpx` | `python-hwpx` (Pure Python) | `{{key}}` 치환 | ✅ | ✅ |
|
|
56
|
+
| 포맷 | 백엔드 | 템플릿 렌더 | 표 읽기 | 병합 셀 인지 | 중첩 테이블 | 셀 수정 | 행 추가 |
|
|
57
|
+
|---|---|---|---|---|---|---|---|
|
|
58
|
+
| `.docx` | `docxtpl` + `python-docx` | Jinja2 (`{%tr%}` loop 포함) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
59
|
+
| `.pptx` | `python-pptx` | `{{key}}` 치환 | ✅ (슬라이드 위치 포함) | ✅ | — (포맷 미지원) | ✅ | ❌ (미지원) |
|
|
60
|
+
| `.hwpx` | `python-hwpx` (Pure Python) | `{{key}}` 치환 | ✅ | ✅ | ✅ | ✅ | ✅ (v0.3+) |
|
|
61
61
|
|
|
62
62
|
- HWPX는 한컴오피스 설치가 **불필요**합니다 (macOS/Linux 서버에서 그대로 동작).
|
|
63
63
|
- 구버전 `.hwp`(바이너리 포맷)는 지원하지 않습니다 — `.hwpx`로 변환 후 사용하세요.
|
|
64
|
+
- 병합 셀: 3개 포맷 모두 preview에 `null` 슬롯 + `merges` 메타로 구조 노출. non-anchor 좌표에 쓰기는 `MergedCellWriteError`로 거부.
|
|
64
65
|
|
|
65
66
|
## 설치
|
|
66
67
|
|
|
@@ -106,14 +107,50 @@ doc.save("report_filled.docx")
|
|
|
106
107
|
|
|
107
108
|
# 3. 기존 양식 파일의 표 셀 수정
|
|
108
109
|
doc = load("checklist.docx")
|
|
110
|
+
|
|
111
|
+
# 빈 셀 값 교체
|
|
109
112
|
old = doc.set_cell(table_index=1, row=1, col=1, value="○○전자")
|
|
110
|
-
|
|
113
|
+
|
|
114
|
+
# 라벨이 있는 셀 ("성 명")에 값 추가 → "성 명 홍길동"
|
|
115
|
+
doc.append_to_cell(table_index=2, row=0, col=0, value="홍길동")
|
|
116
|
+
|
|
117
|
+
# 셀 전체 텍스트 + 병합 메타 조회 (preview의 40자 잘림 없이)
|
|
118
|
+
cell = doc.get_cell(table_index=1, row=3, col=2)
|
|
119
|
+
print(cell.text, cell.is_anchor, cell.span, cell.nested_table_indices)
|
|
120
|
+
|
|
121
|
+
# DOCX/HWPX는 행 추가 지원
|
|
122
|
+
doc.append_row(1, ["새 항목", "값"])
|
|
123
|
+
|
|
111
124
|
doc.save("checklist_filled.docx")
|
|
112
125
|
doc.close()
|
|
113
126
|
```
|
|
114
127
|
|
|
115
128
|
확장자로 자동 분기되므로 `.pptx` / `.hwpx`도 동일한 API를 사용합니다.
|
|
116
129
|
|
|
130
|
+
### 병합 셀 인지 동작 (v0.2+)
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
schema = doc.get_schema()
|
|
134
|
+
t = schema.tables[0]
|
|
135
|
+
|
|
136
|
+
# preview는 logical grid. 병합된 non-anchor 슬롯은 None.
|
|
137
|
+
# [['HEADER', None, None], ['A1', 'A2', 'A3']]
|
|
138
|
+
print(t.preview)
|
|
139
|
+
|
|
140
|
+
# merges는 span>1x1인 anchor 목록
|
|
141
|
+
# [MergeInfo(anchor=(0,0), span=(1,3))]
|
|
142
|
+
print(t.merges)
|
|
143
|
+
|
|
144
|
+
# non-anchor에 쓰기 시도하면 MergedCellWriteError (ValueError 서브클래스)
|
|
145
|
+
try:
|
|
146
|
+
doc.set_cell(0, 0, 2, "X")
|
|
147
|
+
except ValueError as e:
|
|
148
|
+
print(e) # "cell (0,2) is part of a merged region anchored at (0,0)..."
|
|
149
|
+
|
|
150
|
+
# 의도적으로 앵커로 리디렉트하고 싶다면
|
|
151
|
+
doc.set_cell(0, 0, 2, "X", allow_merge_redirect=True) # 경고 + 실제로 (0,0) 수정
|
|
152
|
+
```
|
|
153
|
+
|
|
117
154
|
## MCP 서버로 사용 — Claude Desktop / Claude Code
|
|
118
155
|
|
|
119
156
|
### 실행
|
|
@@ -177,39 +214,45 @@ resp = client.messages.create(
|
|
|
177
214
|
|
|
178
215
|
전체 agent loop 예시는 [`examples/claude_api_example.py`](examples/claude_api_example.py) 참고.
|
|
179
216
|
|
|
180
|
-
## 노출되는
|
|
217
|
+
## 노출되는 도구
|
|
181
218
|
|
|
182
219
|
| 도구 | 설명 |
|
|
183
220
|
|---|---|
|
|
184
221
|
| `inspect_document` | 문서 구조(placeholders, tables)를 JSON으로 반환. **항상 첫 호출로 사용** |
|
|
185
222
|
| `render_template` | `{{key}}`를 context dict 값으로 치환해 새 파일 저장 |
|
|
186
|
-
| `
|
|
187
|
-
| `
|
|
223
|
+
| `get_cell` | 셀 전체 텍스트 + 병합/중첩 메타 반환 (preview의 40자 잘림 없이) |
|
|
224
|
+
| `set_cell` | 특정 표의 `(row, col)` 셀 값 교체 (병합 anchor만) |
|
|
225
|
+
| `append_to_cell` | 기존 텍스트 뒤에 값 덧붙임 (라벨 유지용, 예: `"성 명"` → `"성 명 홍길동"`) |
|
|
226
|
+
| `append_row` | 표 끝에 새 행 추가 (DOCX/HWPX 지원) |
|
|
188
227
|
|
|
189
|
-
### `inspect_document` 반환 예시
|
|
228
|
+
### `inspect_document` 반환 예시 (v0.2+)
|
|
190
229
|
|
|
191
230
|
```json
|
|
192
231
|
{
|
|
193
|
-
"format": "
|
|
194
|
-
"source": "/path/to/
|
|
232
|
+
"format": "hwpx",
|
|
233
|
+
"source": "/path/to/form.hwpx",
|
|
195
234
|
"placeholders": [],
|
|
196
235
|
"tables": [
|
|
197
236
|
{
|
|
198
|
-
"index":
|
|
199
|
-
"rows":
|
|
200
|
-
"cols":
|
|
237
|
+
"index": 0,
|
|
238
|
+
"rows": 28,
|
|
239
|
+
"cols": 16,
|
|
201
240
|
"location": null,
|
|
241
|
+
"parent_path": null,
|
|
202
242
|
"preview": [
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
243
|
+
["포상금 지급신청서", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
|
|
244
|
+
["접수번호", null, null, "", "접수일자", null, null, "", ...]
|
|
245
|
+
],
|
|
246
|
+
"merges": [
|
|
247
|
+
{"anchor": [0, 0], "span": [1, 16]},
|
|
248
|
+
{"anchor": [1, 0], "span": [1, 3]}
|
|
206
249
|
]
|
|
207
250
|
}
|
|
208
251
|
]
|
|
209
252
|
}
|
|
210
253
|
```
|
|
211
254
|
|
|
212
|
-
LLM은 이 preview를 보고 **"빈 셀이 어디 있는지 / 어떤 값을 넣어야 하는지"** 를 판단하여 `set_cell`을 호출합니다.
|
|
255
|
+
LLM은 이 preview를 보고 **"빈 셀이 어디 있는지 / 어떤 값을 넣어야 하는지"** 를 판단하여 `set_cell` / `append_to_cell`을 호출합니다. `null` 슬롯은 병합된 영역이며 `merges`의 anchor 좌표로만 쓸 수 있습니다.
|
|
213
256
|
|
|
214
257
|
## 템플릿 작성 규칙
|
|
215
258
|
|
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
|
|
15
15
|
## 지원 포맷
|
|
16
16
|
|
|
17
|
-
| 포맷 | 백엔드 | 템플릿 렌더 | 표 읽기 | 셀 수정 | 행 추가 |
|
|
18
|
-
|
|
19
|
-
| `.docx` | `docxtpl` + `python-docx` | Jinja2 (`{%tr%}` loop 포함) | ✅ | ✅ | ✅ |
|
|
20
|
-
| `.pptx` | `python-pptx` | `{{key}}` 치환 | ✅ (슬라이드 위치 포함) | ✅ | ❌ (미지원) |
|
|
21
|
-
| `.hwpx` | `python-hwpx` (Pure Python) | `{{key}}` 치환 | ✅ | ✅ |
|
|
17
|
+
| 포맷 | 백엔드 | 템플릿 렌더 | 표 읽기 | 병합 셀 인지 | 중첩 테이블 | 셀 수정 | 행 추가 |
|
|
18
|
+
|---|---|---|---|---|---|---|---|
|
|
19
|
+
| `.docx` | `docxtpl` + `python-docx` | Jinja2 (`{%tr%}` loop 포함) | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
20
|
+
| `.pptx` | `python-pptx` | `{{key}}` 치환 | ✅ (슬라이드 위치 포함) | ✅ | — (포맷 미지원) | ✅ | ❌ (미지원) |
|
|
21
|
+
| `.hwpx` | `python-hwpx` (Pure Python) | `{{key}}` 치환 | ✅ | ✅ | ✅ | ✅ | ✅ (v0.3+) |
|
|
22
22
|
|
|
23
23
|
- HWPX는 한컴오피스 설치가 **불필요**합니다 (macOS/Linux 서버에서 그대로 동작).
|
|
24
24
|
- 구버전 `.hwp`(바이너리 포맷)는 지원하지 않습니다 — `.hwpx`로 변환 후 사용하세요.
|
|
25
|
+
- 병합 셀: 3개 포맷 모두 preview에 `null` 슬롯 + `merges` 메타로 구조 노출. non-anchor 좌표에 쓰기는 `MergedCellWriteError`로 거부.
|
|
25
26
|
|
|
26
27
|
## 설치
|
|
27
28
|
|
|
@@ -67,14 +68,50 @@ doc.save("report_filled.docx")
|
|
|
67
68
|
|
|
68
69
|
# 3. 기존 양식 파일의 표 셀 수정
|
|
69
70
|
doc = load("checklist.docx")
|
|
71
|
+
|
|
72
|
+
# 빈 셀 값 교체
|
|
70
73
|
old = doc.set_cell(table_index=1, row=1, col=1, value="○○전자")
|
|
71
|
-
|
|
74
|
+
|
|
75
|
+
# 라벨이 있는 셀 ("성 명")에 값 추가 → "성 명 홍길동"
|
|
76
|
+
doc.append_to_cell(table_index=2, row=0, col=0, value="홍길동")
|
|
77
|
+
|
|
78
|
+
# 셀 전체 텍스트 + 병합 메타 조회 (preview의 40자 잘림 없이)
|
|
79
|
+
cell = doc.get_cell(table_index=1, row=3, col=2)
|
|
80
|
+
print(cell.text, cell.is_anchor, cell.span, cell.nested_table_indices)
|
|
81
|
+
|
|
82
|
+
# DOCX/HWPX는 행 추가 지원
|
|
83
|
+
doc.append_row(1, ["새 항목", "값"])
|
|
84
|
+
|
|
72
85
|
doc.save("checklist_filled.docx")
|
|
73
86
|
doc.close()
|
|
74
87
|
```
|
|
75
88
|
|
|
76
89
|
확장자로 자동 분기되므로 `.pptx` / `.hwpx`도 동일한 API를 사용합니다.
|
|
77
90
|
|
|
91
|
+
### 병합 셀 인지 동작 (v0.2+)
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
schema = doc.get_schema()
|
|
95
|
+
t = schema.tables[0]
|
|
96
|
+
|
|
97
|
+
# preview는 logical grid. 병합된 non-anchor 슬롯은 None.
|
|
98
|
+
# [['HEADER', None, None], ['A1', 'A2', 'A3']]
|
|
99
|
+
print(t.preview)
|
|
100
|
+
|
|
101
|
+
# merges는 span>1x1인 anchor 목록
|
|
102
|
+
# [MergeInfo(anchor=(0,0), span=(1,3))]
|
|
103
|
+
print(t.merges)
|
|
104
|
+
|
|
105
|
+
# non-anchor에 쓰기 시도하면 MergedCellWriteError (ValueError 서브클래스)
|
|
106
|
+
try:
|
|
107
|
+
doc.set_cell(0, 0, 2, "X")
|
|
108
|
+
except ValueError as e:
|
|
109
|
+
print(e) # "cell (0,2) is part of a merged region anchored at (0,0)..."
|
|
110
|
+
|
|
111
|
+
# 의도적으로 앵커로 리디렉트하고 싶다면
|
|
112
|
+
doc.set_cell(0, 0, 2, "X", allow_merge_redirect=True) # 경고 + 실제로 (0,0) 수정
|
|
113
|
+
```
|
|
114
|
+
|
|
78
115
|
## MCP 서버로 사용 — Claude Desktop / Claude Code
|
|
79
116
|
|
|
80
117
|
### 실행
|
|
@@ -138,39 +175,45 @@ resp = client.messages.create(
|
|
|
138
175
|
|
|
139
176
|
전체 agent loop 예시는 [`examples/claude_api_example.py`](examples/claude_api_example.py) 참고.
|
|
140
177
|
|
|
141
|
-
## 노출되는
|
|
178
|
+
## 노출되는 도구
|
|
142
179
|
|
|
143
180
|
| 도구 | 설명 |
|
|
144
181
|
|---|---|
|
|
145
182
|
| `inspect_document` | 문서 구조(placeholders, tables)를 JSON으로 반환. **항상 첫 호출로 사용** |
|
|
146
183
|
| `render_template` | `{{key}}`를 context dict 값으로 치환해 새 파일 저장 |
|
|
147
|
-
| `
|
|
148
|
-
| `
|
|
184
|
+
| `get_cell` | 셀 전체 텍스트 + 병합/중첩 메타 반환 (preview의 40자 잘림 없이) |
|
|
185
|
+
| `set_cell` | 특정 표의 `(row, col)` 셀 값 교체 (병합 anchor만) |
|
|
186
|
+
| `append_to_cell` | 기존 텍스트 뒤에 값 덧붙임 (라벨 유지용, 예: `"성 명"` → `"성 명 홍길동"`) |
|
|
187
|
+
| `append_row` | 표 끝에 새 행 추가 (DOCX/HWPX 지원) |
|
|
149
188
|
|
|
150
|
-
### `inspect_document` 반환 예시
|
|
189
|
+
### `inspect_document` 반환 예시 (v0.2+)
|
|
151
190
|
|
|
152
191
|
```json
|
|
153
192
|
{
|
|
154
|
-
"format": "
|
|
155
|
-
"source": "/path/to/
|
|
193
|
+
"format": "hwpx",
|
|
194
|
+
"source": "/path/to/form.hwpx",
|
|
156
195
|
"placeholders": [],
|
|
157
196
|
"tables": [
|
|
158
197
|
{
|
|
159
|
-
"index":
|
|
160
|
-
"rows":
|
|
161
|
-
"cols":
|
|
198
|
+
"index": 0,
|
|
199
|
+
"rows": 28,
|
|
200
|
+
"cols": 16,
|
|
162
201
|
"location": null,
|
|
202
|
+
"parent_path": null,
|
|
163
203
|
"preview": [
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
204
|
+
["포상금 지급신청서", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null],
|
|
205
|
+
["접수번호", null, null, "", "접수일자", null, null, "", ...]
|
|
206
|
+
],
|
|
207
|
+
"merges": [
|
|
208
|
+
{"anchor": [0, 0], "span": [1, 16]},
|
|
209
|
+
{"anchor": [1, 0], "span": [1, 3]}
|
|
167
210
|
]
|
|
168
211
|
}
|
|
169
212
|
]
|
|
170
213
|
}
|
|
171
214
|
```
|
|
172
215
|
|
|
173
|
-
LLM은 이 preview를 보고 **"빈 셀이 어디 있는지 / 어떤 값을 넣어야 하는지"** 를 판단하여 `set_cell`을 호출합니다.
|
|
216
|
+
LLM은 이 preview를 보고 **"빈 셀이 어디 있는지 / 어떤 값을 넣어야 하는지"** 를 판단하여 `set_cell` / `append_to_cell`을 호출합니다. `null` 슬롯은 병합된 영역이며 `merges`의 anchor 좌표로만 쓸 수 있습니다.
|
|
174
217
|
|
|
175
218
|
## 템플릿 작성 규칙
|
|
176
219
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
세 포맷(DOCX/PPTX/HWPX)의 공통 작업을 추상화:
|
|
4
4
|
- 템플릿 렌더링 ({{key}} 치환)
|
|
5
5
|
- 표 스키마 추출 (LLM 입력용)
|
|
6
|
-
- 셀 수정 / 행 추가
|
|
6
|
+
- 셀 수정 / 값 추가 / 행 추가
|
|
7
7
|
"""
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
@@ -13,6 +13,28 @@ from pathlib import Path
|
|
|
13
13
|
from typing import Any
|
|
14
14
|
|
|
15
15
|
|
|
16
|
+
# ---- custom exceptions -----------------------------------------------------
|
|
17
|
+
# 표준 예외를 상속해 기존 ``except ValueError/IndexError`` 흐름과 호환.
|
|
18
|
+
|
|
19
|
+
class MergedCellWriteError(ValueError):
|
|
20
|
+
"""병합 영역의 non-anchor 좌표에 쓰기를 시도했을 때."""
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CellOutOfBoundsError(IndexError):
|
|
24
|
+
"""(row, col)이 표 경계를 벗어남."""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class TableIndexError(IndexError):
|
|
28
|
+
"""table_index로 표를 찾지 못함."""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class NotImplementedForFormat(NotImplementedError):
|
|
32
|
+
"""특정 포맷이 지원하지 않는 연산."""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# ---- dataclasses -----------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
|
|
16
38
|
@dataclass
|
|
17
39
|
class MergeInfo:
|
|
18
40
|
"""병합 셀 정보. anchor=(row,col)에서 span=(rows,cols)만큼 병합."""
|
|
@@ -51,6 +73,34 @@ class TableSchema:
|
|
|
51
73
|
}
|
|
52
74
|
|
|
53
75
|
|
|
76
|
+
@dataclass
|
|
77
|
+
class CellContent:
|
|
78
|
+
"""단일 셀의 전체 내용 + 병합/중첩 메타.
|
|
79
|
+
|
|
80
|
+
프리뷰가 max_cell_len으로 잘리는 것과 달리 ``text``는 전체 본문을 보유.
|
|
81
|
+
"""
|
|
82
|
+
row: int
|
|
83
|
+
col: int
|
|
84
|
+
text: str # 셀 전체 평문 (자르지 않음)
|
|
85
|
+
paragraphs: list[str] # paragraph 단위 분리
|
|
86
|
+
is_anchor: bool # (row,col)이 병합 앵커인지
|
|
87
|
+
anchor: tuple[int, int] # 이 logical 위치의 앵커 좌표
|
|
88
|
+
span: tuple[int, int] # (row_span, col_span)
|
|
89
|
+
nested_table_indices: list[int] = field(default_factory=list)
|
|
90
|
+
|
|
91
|
+
def to_dict(self) -> dict[str, Any]:
|
|
92
|
+
return {
|
|
93
|
+
"row": self.row,
|
|
94
|
+
"col": self.col,
|
|
95
|
+
"text": self.text,
|
|
96
|
+
"paragraphs": self.paragraphs,
|
|
97
|
+
"is_anchor": self.is_anchor,
|
|
98
|
+
"anchor": list(self.anchor),
|
|
99
|
+
"span": list(self.span),
|
|
100
|
+
"nested_table_indices": self.nested_table_indices,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
54
104
|
@dataclass
|
|
55
105
|
class DocumentSchema:
|
|
56
106
|
"""문서 전체 스키마."""
|
|
@@ -98,6 +148,10 @@ class DocumentAdapter(ABC):
|
|
|
98
148
|
preview_rows: int = 4, max_cell_len: int = 40) -> list[TableSchema]:
|
|
99
149
|
"""필터 조건을 만족하는 표 스키마 목록."""
|
|
100
150
|
|
|
151
|
+
@abstractmethod
|
|
152
|
+
def get_cell(self, table_index: int, row: int, col: int) -> CellContent:
|
|
153
|
+
"""셀 단건 조회. preview로 잘린 전체 텍스트와 병합/중첩 메타 반환."""
|
|
154
|
+
|
|
101
155
|
def get_schema(self) -> DocumentSchema:
|
|
102
156
|
return DocumentSchema(
|
|
103
157
|
format=self.format,
|
|
@@ -115,6 +169,15 @@ class DocumentAdapter(ABC):
|
|
|
115
169
|
def set_cell(self, table_index: int, row: int, col: int, value: str) -> str:
|
|
116
170
|
"""셀 값 교체. 원래 값 반환."""
|
|
117
171
|
|
|
172
|
+
@abstractmethod
|
|
173
|
+
def append_to_cell(self, table_index: int, row: int, col: int, value: str,
|
|
174
|
+
separator: str = " ") -> str:
|
|
175
|
+
"""기존 셀 텍스트 뒤에 ``separator + value``를 덧붙임.
|
|
176
|
+
|
|
177
|
+
라벨(예: "성 명")을 유지한 채 사용자 입력을 추가하는 용도.
|
|
178
|
+
빈 셀이면 separator 없이 value만 기록. 원래 값 반환.
|
|
179
|
+
"""
|
|
180
|
+
|
|
118
181
|
@abstractmethod
|
|
119
182
|
def append_row(self, table_index: int, values: list[str]) -> None:
|
|
120
183
|
"""표 끝에 새 행 추가."""
|