smart-docgen 0.1.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.
- smart_docgen-0.1.0/.claude/skills/docpilot-tools/SKILL.md +80 -0
- smart_docgen-0.1.0/.claude/skills/docpilot-tools/docpilot_cli.py +150 -0
- smart_docgen-0.1.0/.env.example +29 -0
- smart_docgen-0.1.0/.github/workflows/publish.yml +42 -0
- smart_docgen-0.1.0/.gitignore +56 -0
- smart_docgen-0.1.0/LICENSE +21 -0
- smart_docgen-0.1.0/PKG-INFO +1269 -0
- smart_docgen-0.1.0/README.md +1203 -0
- smart_docgen-0.1.0/docpilot/__init__.py +1499 -0
- smart_docgen-0.1.0/docpilot/builder/__init__.py +12 -0
- smart_docgen-0.1.0/docpilot/builder/base.py +50 -0
- smart_docgen-0.1.0/docpilot/builder/docx_analyzer.py +208 -0
- smart_docgen-0.1.0/docpilot/builder/docx_builder.py +266 -0
- smart_docgen-0.1.0/docpilot/builder/html_blocks.py +174 -0
- smart_docgen-0.1.0/docpilot/builder/html_table.py +269 -0
- smart_docgen-0.1.0/docpilot/builder/hwp_convert.py +104 -0
- smart_docgen-0.1.0/docpilot/builder/hwpx_analyzer.py +190 -0
- smart_docgen-0.1.0/docpilot/builder/hwpx_auto_builder.py +314 -0
- smart_docgen-0.1.0/docpilot/builder/hwpx_builder.py +301 -0
- smart_docgen-0.1.0/docpilot/builder/hwpx_bullets.py +164 -0
- smart_docgen-0.1.0/docpilot/builder/hwpx_dynamic_builder.py +361 -0
- smart_docgen-0.1.0/docpilot/builder/hwpx_section_generator.py +130 -0
- smart_docgen-0.1.0/docpilot/builder/hwpx_style_extractor.py +128 -0
- smart_docgen-0.1.0/docpilot/builder/pdf_builder.py +100 -0
- smart_docgen-0.1.0/docpilot/db/__init__.py +4 -0
- smart_docgen-0.1.0/docpilot/db/client.py +155 -0
- smart_docgen-0.1.0/docpilot/db/indexer.py +355 -0
- smart_docgen-0.1.0/docpilot/db/schema.py +94 -0
- smart_docgen-0.1.0/docpilot/db/template_store.py +412 -0
- smart_docgen-0.1.0/docpilot/exceptions.py +34 -0
- smart_docgen-0.1.0/docpilot/ingestion/__init__.py +48 -0
- smart_docgen-0.1.0/docpilot/ingestion/docx.py +78 -0
- smart_docgen-0.1.0/docpilot/ingestion/hwp.py +77 -0
- smart_docgen-0.1.0/docpilot/ingestion/hwpx.py +91 -0
- smart_docgen-0.1.0/docpilot/ingestion/models.py +12 -0
- smart_docgen-0.1.0/docpilot/ingestion/pdf.py +125 -0
- smart_docgen-0.1.0/docpilot/ingestion/text.py +35 -0
- smart_docgen-0.1.0/docpilot/mapping/__init__.py +24 -0
- smart_docgen-0.1.0/docpilot/mapping/base.py +184 -0
- smart_docgen-0.1.0/docpilot/mapping/benchmark.py +103 -0
- smart_docgen-0.1.0/docpilot/mapping/claude.py +93 -0
- smart_docgen-0.1.0/docpilot/mapping/gemini.py +79 -0
- smart_docgen-0.1.0/docpilot/mapping/openai.py +78 -0
- smart_docgen-0.1.0/docpilot/mapping/openai_compat.py +106 -0
- smart_docgen-0.1.0/docpilot/mapping/rag.py +157 -0
- smart_docgen-0.1.0/docpilot/mapping/sidecar.py +107 -0
- smart_docgen-0.1.0/docpilot/mcp_server.py +282 -0
- smart_docgen-0.1.0/docpilot/search/__init__.py +64 -0
- smart_docgen-0.1.0/docpilot/search/_filter.py +77 -0
- smart_docgen-0.1.0/docpilot/search/embedding.py +268 -0
- smart_docgen-0.1.0/docpilot/search/eval.py +86 -0
- smart_docgen-0.1.0/docpilot/search/exact.py +50 -0
- smart_docgen-0.1.0/docpilot/search/highlight.py +73 -0
- smart_docgen-0.1.0/docpilot/search/hybrid.py +92 -0
- smart_docgen-0.1.0/docpilot/search/models.py +44 -0
- smart_docgen-0.1.0/docpilot/search/morpheme.py +132 -0
- smart_docgen-0.1.0/docpilot/search/reranker.py +44 -0
- smart_docgen-0.1.0/docpilot/template_generator/__init__.py +4 -0
- smart_docgen-0.1.0/docpilot/template_generator/analyzer.py +100 -0
- smart_docgen-0.1.0/docpilot/template_generator/docx_extractor.py +71 -0
- smart_docgen-0.1.0/docpilot/template_generator/extractor.py +131 -0
- smart_docgen-0.1.0/docpilot/template_generator/generator.py +331 -0
- smart_docgen-0.1.0/docpilot/templates/base/Contents/content.hpf +24 -0
- smart_docgen-0.1.0/docpilot/templates/base/Contents/header.xml +821 -0
- smart_docgen-0.1.0/docpilot/templates/base/Contents/section0.xml +48 -0
- smart_docgen-0.1.0/docpilot/templates/base/META-INF/container.rdf +1 -0
- smart_docgen-0.1.0/docpilot/templates/base/META-INF/container.xml +8 -0
- smart_docgen-0.1.0/docpilot/templates/base/META-INF/manifest.xml +2 -0
- smart_docgen-0.1.0/docpilot/templates/base/Preview/PrvImage.png +0 -0
- smart_docgen-0.1.0/docpilot/templates/base/Preview/PrvText.txt +1 -0
- smart_docgen-0.1.0/docpilot/templates/base/mimetype +1 -0
- smart_docgen-0.1.0/docpilot/templates/base/settings.xml +4 -0
- smart_docgen-0.1.0/docpilot/templates/base/version.xml +2 -0
- smart_docgen-0.1.0/docpilot/templates/gonmun/header.xml +976 -0
- smart_docgen-0.1.0/docpilot/templates/gonmun/section0.xml +197 -0
- smart_docgen-0.1.0/docpilot/templates/gonmun/sidecar.json +24 -0
- smart_docgen-0.1.0/docpilot/templates/minutes/header.xml +965 -0
- smart_docgen-0.1.0/docpilot/templates/minutes/section0.xml +346 -0
- smart_docgen-0.1.0/docpilot/templates/minutes/sidecar.json +17 -0
- smart_docgen-0.1.0/docpilot/templates/proposal/header.xml +1040 -0
- smart_docgen-0.1.0/docpilot/templates/proposal/section0.xml +242 -0
- smart_docgen-0.1.0/docpilot/templates/proposal/sidecar.json +11 -0
- smart_docgen-0.1.0/docpilot/templates/report/header.xml +1202 -0
- smart_docgen-0.1.0/docpilot/templates/report/section0.xml +201 -0
- smart_docgen-0.1.0/docpilot/templates/report/sidecar.json +18 -0
- smart_docgen-0.1.0/example/run.py +75 -0
- smart_docgen-0.1.0/pyproject.toml +92 -0
- smart_docgen-0.1.0/scripts/chunk_size_compare.py +137 -0
- smart_docgen-0.1.0/scripts/gen_/355/225/231/355/232/214/353/263/264/352/263/240/354/204/234.py +78 -0
- smart_docgen-0.1.0/scripts/gen_/355/225/231/355/232/214/353/263/264/352/263/240/354/204/234_hwpx_from_docx.py +104 -0
- smart_docgen-0.1.0/scripts/inspect_index.py +136 -0
- smart_docgen-0.1.0/scripts/make_ebs_template.py +122 -0
- smart_docgen-0.1.0/scripts/test_docgen.py +203 -0
- smart_docgen-0.1.0/scripts/test_folder_search.py +119 -0
- smart_docgen-0.1.0/scripts/test_hwpx_to_docx.py +53 -0
- smart_docgen-0.1.0/scripts/test_mapping.py +188 -0
- smart_docgen-0.1.0/scripts/test_quality.py +260 -0
- smart_docgen-0.1.0/scripts/test_real.py +57 -0
- smart_docgen-0.1.0/scripts/verify_html_render.py +88 -0
- smart_docgen-0.1.0/setup.cfg +4 -0
- smart_docgen-0.1.0/smart_docgen.egg-info/PKG-INFO +1269 -0
- smart_docgen-0.1.0/smart_docgen.egg-info/SOURCES.txt +127 -0
- smart_docgen-0.1.0/smart_docgen.egg-info/dependency_links.txt +1 -0
- smart_docgen-0.1.0/smart_docgen.egg-info/entry_points.txt +2 -0
- smart_docgen-0.1.0/smart_docgen.egg-info/requires.txt +52 -0
- smart_docgen-0.1.0/smart_docgen.egg-info/scm_file_list.json +123 -0
- smart_docgen-0.1.0/smart_docgen.egg-info/scm_version.json +8 -0
- smart_docgen-0.1.0/smart_docgen.egg-info/top_level.txt +1 -0
- smart_docgen-0.1.0/tests/__init__.py +5 -0
- smart_docgen-0.1.0/tests/conftest.py +221 -0
- smart_docgen-0.1.0/tests/mocks/__init__.py +0 -0
- smart_docgen-0.1.0/tests/mocks/db_mock.py +27 -0
- smart_docgen-0.1.0/tests/mocks/llm_mock.py +30 -0
- smart_docgen-0.1.0/tests/test_analyzers.py +194 -0
- smart_docgen-0.1.0/tests/test_builder.py +129 -0
- smart_docgen-0.1.0/tests/test_embed_batch_bench.py +97 -0
- smart_docgen-0.1.0/tests/test_embed_model_bench.py +226 -0
- smart_docgen-0.1.0/tests/test_embedding.py +104 -0
- smart_docgen-0.1.0/tests/test_generate_from_content.py +401 -0
- smart_docgen-0.1.0/tests/test_hwp_ingestion.py +132 -0
- smart_docgen-0.1.0/tests/test_index_perf.py +94 -0
- smart_docgen-0.1.0/tests/test_indexer.py +67 -0
- smart_docgen-0.1.0/tests/test_ingestion.py +69 -0
- smart_docgen-0.1.0/tests/test_mapping.py +342 -0
- smart_docgen-0.1.0/tests/test_mcp_server.py +279 -0
- smart_docgen-0.1.0/tests/test_search.py +402 -0
- smart_docgen-0.1.0/tests/test_search_quality.py +189 -0
- smart_docgen-0.1.0/tests/test_template_generator.py +101 -0
- smart_docgen-0.1.0/uv.lock +5521 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: docpilot-tools
|
|
3
|
+
description: docpilot 라이브러리를 이용한 문서 포맷 변환(hwp/hwpx/docx) 및 플레이스홀더 템플릿 기반 문서 생성. "hwp를 docx로 바꿔줘", "hwpx로 변환해줘", "이 데이터로 이 템플릿 채워서 문서 만들어줘" 같은 요청에 사용.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
이 스킬은 `docpilot` 파이썬 라이브러리를 감싼 CLI(`docpilot_cli.py`, 이 스킬과 같은 폴더에 있음)를 실행해서
|
|
7
|
+
두 가지 작업을 수행한다. 직접 `import docpilot`을 시도하지 말고, 반드시 아래 CLI를 Bash로 실행할 것.
|
|
8
|
+
|
|
9
|
+
## 실행 환경 — 어떤 python을 쓸지 먼저 판단할 것
|
|
10
|
+
|
|
11
|
+
`docpilot`이 import 가능한 인터프리터를 찾아야 한다. 이 스킬 폴더 자체는 어느 프로젝트에 복사돼도 동작해야
|
|
12
|
+
하므로 경로를 하드코딩하지 말고 아래 순서로 판단한다:
|
|
13
|
+
|
|
14
|
+
1. **이 스킬이 docpilot 레포 자체 안에 있는 경우** (`docpilot/` 소스와 `.venv/`가 현재 프로젝트 루트에 있음):
|
|
15
|
+
프로젝트 루트의 `.venv/Scripts/python.exe`(Windows) 또는 `.venv/bin/python`(macOS/Linux)를 쓴다.
|
|
16
|
+
2. **그 외의 경우** (다른 프로젝트에 `pip install git+https://github.com/pjkwon/docpilot.git`로
|
|
17
|
+
설치해서 이 스킬 폴더만 복사해온 경우): 그 프로젝트에서 활성화된/기본 `python`을 쓴다.
|
|
18
|
+
3. 실행 전에 `<python> -c "import docpilot"`으로 import 가능 여부를 먼저 확인한다. 실패하면
|
|
19
|
+
`pip install git+https://github.com/pjkwon/docpilot.git`로 설치가 필요하다고 사용자에게 안내하고 멈출 것 — 임의로 설치를 진행하지 말 것.
|
|
20
|
+
|
|
21
|
+
찾은 인터프리터로 이렇게 실행한다 (`<python>`, `<skill_dir>`은 위에서 판단한 값):
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
<python> <skill_dir>/docpilot_cli.py <command> ...
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## API 키 — `generate`에만 필요
|
|
28
|
+
|
|
29
|
+
`convert`는 LLM을 쓰지 않으므로 `ANTHROPIC_API_KEY`/`.env` 없이도 동작한다.
|
|
30
|
+
|
|
31
|
+
`generate`는 `ANTHROPIC_API_KEY`가 필요하다 (실제 LLM API 호출 발생, 과금됨). 우선순위:
|
|
32
|
+
1. CLI 실행 시점의 현재 작업 디렉터리(=사용자 프로젝트 루트)와 그 상위 폴더의 `.env` 파일 (`docpilot` import 시 자동 로드됨, `docpilot` 소스 위치와 무관 — CWD 기준)
|
|
33
|
+
2. 셸에 이미 export된 OS 환경변수
|
|
34
|
+
|
|
35
|
+
`generate` 실행 전, `.env`와 OS 환경변수 둘 다 없으면 **직접 `.env`를 만들거나 키를 추측하지 말고** 사용자에게
|
|
36
|
+
어떻게 설정할지 물어볼 것. 확인은 존재 여부만 하고 키 값 자체를 출력하지 말 것.
|
|
37
|
+
|
|
38
|
+
## 1. 문서 포맷 변환 — `convert`
|
|
39
|
+
|
|
40
|
+
한컴오피스 COM 자동화로 파일 포맷을 바꾼다. LLM 호출 없음, Windows + 한컴오피스 설치 환경 전용.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
<python> <skill_dir>/docpilot_cli.py convert <source> [--output PATH]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
지원 방향:
|
|
47
|
+
- `.hwp` / `.hwpx` → `.docx`
|
|
48
|
+
- `.hwp` → `.hwpx`
|
|
49
|
+
|
|
50
|
+
**미지원**: `.docx` → `.hwpx`. 일부 한컴오피스 설치 환경에서 COM `Open()`이 DOCX를 가져오지 못하는 문제가 재현되어 보류 중이다 (원인 불명, 레포 README의 "알려진 이슈" 참고). 이 조합을 요청받으면 스크립트가 시도 없이 바로 실패 메시지를 낸다 — 사용자에게 한글 GUI에서 파일 > 열기로 직접 열어 다른 이름으로 저장하라고 안내할 것.
|
|
51
|
+
|
|
52
|
+
`--output` 생략 시 같은 폴더에 같은 이름으로, 기본 반대 포맷(`.hwp`/`.hwpx`→`.docx`, `.hwp`→`.hwpx`)으로 저장된다.
|
|
53
|
+
|
|
54
|
+
## 2. 템플릿 기반 문서 생성 — `generate`
|
|
55
|
+
|
|
56
|
+
데이터 폴더의 내용을 RAG로 검색해 템플릿의 `{{플레이스홀더}}`를 LLM으로 채운다.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
<python> <skill_dir>/docpilot_cli.py generate --data <데이터폴더> --template <템플릿경로또는이름> [--output <출력경로>] \
|
|
60
|
+
[--reindex] [--extra-instructions "지침"] [--instructions-doc <경로>] [--top-k 10]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `--template`: `.hwpx`/`.docx`/`.pdf` 파일 경로, 또는 내장 템플릿 이름(`report`/`gonmun`/`minutes`/`proposal`, 전부 HWPX)
|
|
64
|
+
- `--output`: 확장자가 출력 형식을 결정 (`.hwpx`/`.docx`/`.pdf`). 템플릿이 `.docx`이고 `--output`이 `.hwpx`면 내부적으로 자동 변환 후 진행한다 (Windows + 한컴오피스 필요, 위 "미지원" 이슈가 있으면 여기서도 실패할 수 있음). **생략 시** `~/Documents/docpilot_YYYYMMDD_HHMMSS.<ext>`에 저장 (ext는 템플릿이 `.docx`/`.pdf`면 그것을 따르고, 그 외(내장 템플릿 포함)는 `.hwpx`).
|
|
65
|
+
- 템플릿에 `{{플레이스홀더}}`가 하나도 없으면 Reference Mode로 동작 — LLM이 문서 구조를 추론해서 임시 템플릿을 만든 뒤 생성한다.
|
|
66
|
+
- 데이터 폴더는 매 호출 시 자동 인덱싱된다 (변경분만, `--reindex`로 강제 가능).
|
|
67
|
+
- `--top-k`: RAG로 가져올 청크 수 (기본 10). 공문·회의록처럼 짧은 문서는 낮게(5 안팎), 보고서·제안서처럼 긴 문서는 높게(15~20) 설정.
|
|
68
|
+
|
|
69
|
+
**⚠️ 인덱스가 프로젝트별로 분리되지 않는다.** `generate`는 기본적으로 `~/docpilot.db` 하나를 모든 프로젝트가
|
|
70
|
+
공유하고, 검색도 방금 인덱싱한 `--data` 폴더로 제한되지 않는다 — RAG 검색이 이 DB에 지금까지 인덱싱된
|
|
71
|
+
**모든** 문서를 대상으로 실행되므로, 다른 프로젝트에서 이 스킬로 인덱싱해둔 문서 내용이 이번 생성 결과에
|
|
72
|
+
섞여 들어올 수 있다. 여러 프로젝트에서 이 스킬을 반복 사용한다면:
|
|
73
|
+
- 프로젝트별로 `DOCPILOT_DATABASE_URL` 환경변수를 다르게 지정해 DB를 분리하거나,
|
|
74
|
+
- 생성 결과에 낯선/무관한 내용이 섞여 있는지 사용자에게 확인을 권할 것.
|
|
75
|
+
|
|
76
|
+
## 주의사항
|
|
77
|
+
|
|
78
|
+
- `convert`는 LLM을 쓰지 않고, `generate`만 API 비용이 발생한다. 사용자가 비용에 민감해 보이면 먼저 언급할 것.
|
|
79
|
+
- 두 서브커맨드 모두 실패 시 exit code 1과 `[오류]`/`[실패]`/`[미지원]` 접두사가 붙은 메시지를 stdout에 출력한다. 그대로 사용자에게 전달하면 된다.
|
|
80
|
+
- 이 스킬은 `docpilot` 패키지에 종속적이다 — 실행할 환경에 `docpilot`이 import 가능해야 한다(이 레포 자체의 `.venv`이거나, `pip install git+https://github.com/pjkwon/docpilot.git`로 설치한 다른 환경).
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""docpilot 라이브러리를 감싸는 CLI — 문서 포맷 변환 및 플레이스홀더 템플릿 문서 생성.
|
|
2
|
+
|
|
3
|
+
사용법:
|
|
4
|
+
python docpilot_cli.py convert <source> [--output PATH]
|
|
5
|
+
python docpilot_cli.py generate --data FOLDER --template PATH_OR_NAME [--output PATH]
|
|
6
|
+
[--reindex] [--extra-instructions TEXT]
|
|
7
|
+
[--instructions-doc PATH] [--top-k N]
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import sys
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
if hasattr(sys.stdout, "reconfigure"):
|
|
16
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
17
|
+
if hasattr(sys.stderr, "reconfigure"):
|
|
18
|
+
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
|
19
|
+
|
|
20
|
+
_CONVERSIONS = {
|
|
21
|
+
(".hwp", ".docx"): "docx",
|
|
22
|
+
(".hwpx", ".docx"): "docx",
|
|
23
|
+
(".hwp", ".hwpx"): "hwpx",
|
|
24
|
+
}
|
|
25
|
+
_DEFAULT_OUTPUT_EXT = {".hwp": ".docx", ".hwpx": ".docx", ".docx": ".hwpx"}
|
|
26
|
+
# 알려진 이슈: 일부 한컴오피스 설치 환경에서 COM을 통한 DOCX 가져오기(Open)가 실패한다.
|
|
27
|
+
# docpilot README의 "알려진 이슈" 참고. 원인 불명이라 보류 중.
|
|
28
|
+
_KNOWN_UNSUPPORTED = {(".docx", ".hwpx")}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _default_generate_output(template: str) -> str:
|
|
32
|
+
"""MCP generate_document의 _default_output()과 동일한 규칙: 미지정 시
|
|
33
|
+
~/Documents/docpilot_YYYYMMDD_HHMMSS.<ext>에 저장 (ext는 템플릿이 .docx/.pdf면
|
|
34
|
+
그것을 따르고, 그 외(내장 템플릿 이름 포함)엔 .hwpx)."""
|
|
35
|
+
from datetime import datetime
|
|
36
|
+
|
|
37
|
+
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
38
|
+
ext = ".hwpx"
|
|
39
|
+
tpl_ext = Path(template).suffix.lower()
|
|
40
|
+
if tpl_ext in (".docx", ".pdf"):
|
|
41
|
+
ext = tpl_ext
|
|
42
|
+
docs = Path.home() / "Documents"
|
|
43
|
+
docs.mkdir(exist_ok=True)
|
|
44
|
+
return str(docs / f"docpilot_{ts}{ext}")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def cmd_convert(args: argparse.Namespace) -> int:
|
|
48
|
+
from docpilot.builder.hwp_convert import convert_to_docx, convert_to_hwpx
|
|
49
|
+
from docpilot.exceptions import DocPilotError
|
|
50
|
+
|
|
51
|
+
src = Path(args.source)
|
|
52
|
+
if not src.exists():
|
|
53
|
+
print(f"[오류] 파일을 찾을 수 없습니다: {src}")
|
|
54
|
+
return 1
|
|
55
|
+
|
|
56
|
+
src_ext = src.suffix.lower()
|
|
57
|
+
if src_ext not in _DEFAULT_OUTPUT_EXT:
|
|
58
|
+
print(f"[오류] 지원하지 않는 입력 형식입니다: {src_ext} (.hwp, .hwpx, .docx만 가능)")
|
|
59
|
+
return 1
|
|
60
|
+
|
|
61
|
+
out = Path(args.output) if args.output else src.with_suffix(_DEFAULT_OUTPUT_EXT[src_ext])
|
|
62
|
+
out_ext = out.suffix.lower()
|
|
63
|
+
|
|
64
|
+
if (src_ext, out_ext) in _KNOWN_UNSUPPORTED:
|
|
65
|
+
print(
|
|
66
|
+
f"[미지원] {src_ext} → {out_ext} 변환은 현재 지원하지 않습니다 (알려진 이슈).\n"
|
|
67
|
+
"일부 한컴오피스 설치 환경에서 COM을 통한 DOCX 가져오기(Open) 자체가 실패하는 "
|
|
68
|
+
"문제가 재현되어 보류 중입니다. 한/글에서 파일 > 열기로 수동으로 열어 "
|
|
69
|
+
"다른 이름으로 저장(hwpx)하세요."
|
|
70
|
+
)
|
|
71
|
+
return 1
|
|
72
|
+
|
|
73
|
+
target = _CONVERSIONS.get((src_ext, out_ext))
|
|
74
|
+
if target is None:
|
|
75
|
+
print(f"[오류] 지원하지 않는 변환입니다: {src_ext} → {out_ext}")
|
|
76
|
+
return 1
|
|
77
|
+
|
|
78
|
+
convert_fn = convert_to_docx if target == "docx" else convert_to_hwpx
|
|
79
|
+
try:
|
|
80
|
+
result = convert_fn(src, out)
|
|
81
|
+
except DocPilotError as e:
|
|
82
|
+
print(f"[실패] {e}")
|
|
83
|
+
return 1
|
|
84
|
+
|
|
85
|
+
print(f"변환 완료: {result}")
|
|
86
|
+
return 0
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def cmd_generate(args: argparse.Namespace) -> int:
|
|
90
|
+
import os
|
|
91
|
+
import docpilot
|
|
92
|
+
|
|
93
|
+
api_key = os.environ.get("ANTHROPIC_API_KEY")
|
|
94
|
+
if not api_key:
|
|
95
|
+
print("[오류] ANTHROPIC_API_KEY 환경변수가 필요합니다.")
|
|
96
|
+
return 1
|
|
97
|
+
|
|
98
|
+
pilot = docpilot.DocPilot(llm="claude", api_key=api_key)
|
|
99
|
+
|
|
100
|
+
output = args.output or _default_generate_output(args.template)
|
|
101
|
+
if not args.output:
|
|
102
|
+
print(f"(output 미지정 — 기본 경로 사용: {output})")
|
|
103
|
+
|
|
104
|
+
try:
|
|
105
|
+
result = pilot.generate(
|
|
106
|
+
data_folder=args.data,
|
|
107
|
+
template=args.template,
|
|
108
|
+
output=output,
|
|
109
|
+
reindex=args.reindex,
|
|
110
|
+
extra_instructions=args.extra_instructions,
|
|
111
|
+
instructions_doc=args.instructions_doc,
|
|
112
|
+
top_k=args.top_k,
|
|
113
|
+
)
|
|
114
|
+
except Exception as e:
|
|
115
|
+
print(f"[실패] {e}")
|
|
116
|
+
return 1
|
|
117
|
+
|
|
118
|
+
print(f"문서 생성 완료: {result.path}")
|
|
119
|
+
print(
|
|
120
|
+
f"모델: {result.model} | 입력 {result.input_tokens:,} + 출력 {result.output_tokens:,} 토큰"
|
|
121
|
+
f" | {result.elapsed_seconds:.1f}초"
|
|
122
|
+
)
|
|
123
|
+
return 0
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def main() -> None:
|
|
127
|
+
parser = argparse.ArgumentParser(description="docpilot CLI — 문서 변환 및 템플릿 기반 문서 생성")
|
|
128
|
+
sub = parser.add_subparsers(dest="cmd", required=True)
|
|
129
|
+
|
|
130
|
+
p_convert = sub.add_parser("convert", help="hwp/hwpx/docx 파일 포맷 변환")
|
|
131
|
+
p_convert.add_argument("source", help="변환할 파일 경로")
|
|
132
|
+
p_convert.add_argument("--output", help="출력 파일 경로 (미지정 시 기본 반대 포맷으로 같은 폴더에 저장)")
|
|
133
|
+
p_convert.set_defaults(func=cmd_convert)
|
|
134
|
+
|
|
135
|
+
p_generate = sub.add_parser("generate", help="데이터 폴더 + 플레이스홀더 템플릿으로 문서 생성")
|
|
136
|
+
p_generate.add_argument("--data", required=True, help="데이터 폴더 경로")
|
|
137
|
+
p_generate.add_argument("--template", required=True, help="템플릿 파일 경로(.hwpx/.docx/.pdf) 또는 내장 템플릿 이름")
|
|
138
|
+
p_generate.add_argument("--output", help="출력 파일 경로 (미지정 시 ~/Documents/docpilot_YYYYMMDD_HHMMSS.<ext>에 저장)")
|
|
139
|
+
p_generate.add_argument("--reindex", action="store_true", help="데이터 폴더 강제 재인덱싱")
|
|
140
|
+
p_generate.add_argument("--extra-instructions", default=None, help="추가 작성 지침 문자열")
|
|
141
|
+
p_generate.add_argument("--instructions-doc", default=None, help="작성 지침으로 쓸 파일 경로 (RFP 등)")
|
|
142
|
+
p_generate.add_argument("--top-k", type=int, default=10, help="RAG 검색 청크 수 (기본 10)")
|
|
143
|
+
p_generate.set_defaults(func=cmd_generate)
|
|
144
|
+
|
|
145
|
+
args = parser.parse_args()
|
|
146
|
+
sys.exit(args.func(args))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
if __name__ == "__main__":
|
|
150
|
+
main()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# ─── LLM ────────────────────────────────────────────────────────────────────
|
|
2
|
+
# 사용할 LLM 제공자. 코드에서 DocPilot(llm="...") 로 전달하면 이 값보다 우선합니다.
|
|
3
|
+
# 지원값: claude (기본값) | openai | gemini | grok | ollama
|
|
4
|
+
DOCPILOT_LLM=claude
|
|
5
|
+
|
|
6
|
+
# Anthropic API 키 (llm=claude 일 때 필수)
|
|
7
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
8
|
+
|
|
9
|
+
# OpenAI API 키 (llm=openai, grok 또는 임베딩 검색 사용 시 필요)
|
|
10
|
+
OPENAI_API_KEY=sk-...
|
|
11
|
+
|
|
12
|
+
# Google Gemini API 키 (llm=gemini 일 때 필수)
|
|
13
|
+
GEMINI_API_KEY=AIza...
|
|
14
|
+
|
|
15
|
+
# xAI API 키 (llm=grok 일 때 필수)
|
|
16
|
+
XAI_API_KEY=xai-...
|
|
17
|
+
|
|
18
|
+
# Ollama 서버 주소 (llm=ollama 일 때. 기본값: localhost)
|
|
19
|
+
# OLLAMA_BASE_URL=http://localhost:11434/v1
|
|
20
|
+
|
|
21
|
+
# ─── Database ────────────────────────────────────────────────────────────────
|
|
22
|
+
# 미설정 시 홈 디렉토리(~/docpilot.db)에 SQLite 파일이 자동 생성됩니다.
|
|
23
|
+
#
|
|
24
|
+
# SQLite — MCP 서버는 cwd가 고정되지 않으므로 절대 경로를 권장합니다.
|
|
25
|
+
# DOCPILOT_DATABASE_URL=sqlite:////home/yourname/docpilot.db # Linux/macOS
|
|
26
|
+
# DOCPILOT_DATABASE_URL=sqlite:////Users/yourname/docpilot.db # macOS
|
|
27
|
+
#
|
|
28
|
+
# PostgreSQL (대용량, pip install "docpilot[postgres]" 필요):
|
|
29
|
+
# DOCPILOT_DATABASE_URL=postgresql://user:password@localhost:5432/docpilot
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
with:
|
|
14
|
+
fetch-depth: 0 # full history + tags, required for setuptools-scm to compute the version
|
|
15
|
+
|
|
16
|
+
- name: Install uv
|
|
17
|
+
uses: astral-sh/setup-uv@v3
|
|
18
|
+
|
|
19
|
+
- name: Build package
|
|
20
|
+
run: uv build
|
|
21
|
+
|
|
22
|
+
- name: Upload build artifacts
|
|
23
|
+
uses: actions/upload-artifact@v4
|
|
24
|
+
with:
|
|
25
|
+
name: dist
|
|
26
|
+
path: dist/
|
|
27
|
+
|
|
28
|
+
publish:
|
|
29
|
+
needs: build
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
environment: pypi
|
|
32
|
+
permissions:
|
|
33
|
+
id-token: write # required for PyPI trusted publishing (OIDC) — no token/secret needed
|
|
34
|
+
steps:
|
|
35
|
+
- name: Download build artifacts
|
|
36
|
+
uses: actions/download-artifact@v4
|
|
37
|
+
with:
|
|
38
|
+
name: dist
|
|
39
|
+
path: dist/
|
|
40
|
+
|
|
41
|
+
- name: Publish to PyPI
|
|
42
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.pyo
|
|
5
|
+
*.pyd
|
|
6
|
+
.Python
|
|
7
|
+
|
|
8
|
+
# Distribution / packaging
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
wheels/
|
|
14
|
+
|
|
15
|
+
# Virtual environments
|
|
16
|
+
.venv/
|
|
17
|
+
venv/
|
|
18
|
+
env/
|
|
19
|
+
|
|
20
|
+
# Environment variables
|
|
21
|
+
.env
|
|
22
|
+
.env.local
|
|
23
|
+
|
|
24
|
+
# Testing
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.coverage
|
|
27
|
+
htmlcov/
|
|
28
|
+
|
|
29
|
+
# IDE
|
|
30
|
+
.vscode/
|
|
31
|
+
.idea/
|
|
32
|
+
|
|
33
|
+
# Internal docs
|
|
34
|
+
*.md
|
|
35
|
+
!README.md
|
|
36
|
+
!.claude/skills/**/*.md
|
|
37
|
+
|
|
38
|
+
# Test artifacts
|
|
39
|
+
test-data/
|
|
40
|
+
test-output/
|
|
41
|
+
*.hwpx
|
|
42
|
+
hwpxskill/
|
|
43
|
+
data/
|
|
44
|
+
samples/
|
|
45
|
+
output/
|
|
46
|
+
|
|
47
|
+
# Runtime database
|
|
48
|
+
*.db
|
|
49
|
+
*.db-journal
|
|
50
|
+
|
|
51
|
+
# Windows Zone.Identifier (인터넷 다운로드 파일 메타데이터, WSL 복사 시 생성)
|
|
52
|
+
*:Zone.Identifier
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# legacy data
|
|
56
|
+
data_legacy/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 pjkwon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|