docs: 250916 트러블슈팅 및 아이디어 문서 정리
- ChromaDB 메타데이터 손상 문제 문서화 - CompanyX 뉴스 검증 로직 현황 수정 - 4개 아이디어 문서에 프로젝트 구현 상태 추가 - HWP-PDF 변환: skill-rag-file 미지원 - 네이버웍스 캘린더: OAuth2/서비스 미구현 - 감정 분석: ONNX 미통합, API 미구현 - 슬랙 캔버스: API 전체 미사용
This commit is contained in:
parent
7fabe113b7
commit
8f62e9c4d4
277
ideas/250916_HWP-PDF_변환_전략_분석.md
Normal file
277
ideas/250916_HWP-PDF_변환_전략_분석.md
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
# 파이썬 기반 HWP-PDF 변환 방법론에 대한 전략적 분석
|
||||||
|
|
||||||
|
## 1. Executive Summary
|
||||||
|
|
||||||
|
본 보고서는 파이썬(Python) 환경에서 한글(HWP) 문서를 PDF로 변환하는 다양한 기술적 접근법을 심층적으로 분석하고, 각 방법론의 장단점과 비용 구조를 비교하여 최적의 솔루션 선택을 위한 전략적 가이드라인을 제공한다. 분석 결과, 높은 완성도를 보장하는 순수 파이썬 오픈소스 라이브러리는 현재 존재하지 않는다는 결론에 도달했다.
|
||||||
|
|
||||||
|
**[현재 프로젝트 상태]** skill-rag-file은 HWP 파일을 지원하지 않음 (app/core/config.py의 ALLOWED_EXTENSIONS에 .hwp 누락, TextExtractor에 HWP 처리 로직 없음, Dockerfile에 LibreOffice 미설치).
|
||||||
|
|
||||||
|
HWP 파일 변환의 핵심 과제는 한글과컴퓨터(Hancom Inc.)가 개발한 HWP 포맷의 독점적(proprietary) 특성에서 비롯된다. 공개된 명세가 없는 이 기술적 장벽은 외부 애플리케이션이나 서비스를 활용하는 간접적인 해결책을 강제한다. 따라서 개발자는 단순히 '라이브러리'를 찾는 것이 아니라, 주어진 요구사항에 가장 적합한 '기술적 가교'를 선택하는 문제에 직면하게 된다.
|
||||||
|
|
||||||
|
본 보고서는 실질적으로 구현 가능한 세 가지 핵심 전략을 제시하고 분석한다.
|
||||||
|
|
||||||
|
* **COM 자동화 (COM Automation):** `pywin32` 라이브러리를 사용하여 윈도우(Windows)에 설치된 한컴오피스를 프로그래밍 방식으로 제어한다. 원본과 동일한, 완벽한 품질의 변환을 보장한다.
|
||||||
|
* **클라우드 기반 REST API:** 외부 전문 변환 서비스(예: CloudConvert)에 HWP 파일을 전송하여 PDF 결과물을 받는 방식이다. 플랫폼에 독립적이며 확장성이 뛰어나다.
|
||||||
|
* **명령줄 인터페이스(CLI) 래퍼:** 파이썬 스크립트 내에서 리브레오피스(LibreOffice)와 같은 외부 커맨드라인 도구를 호출하여 변환을 수행한다. 무료이며 여러 운영체제에서 사용 가능하지만, 변환 품질의 일관성은 보장되지 않는다.
|
||||||
|
|
||||||
|
최종적으로, 각 전략은 특정 사용 사례에 맞춰 권장된다. 높은 보안이 요구되는 기업 환경에서는 COM 자동화가, 다양한 플랫폼을 지원해야 하는 웹 애플리케이션에는 클라우드 API가, 그리고 비용 제약이 있는 내부 프로젝트에는 CLI 래퍼 방식이 가장 적합한 솔루션으로 평가된다.
|
||||||
|
|
||||||
|
## 2. HWP 변환의 기술적 과제: 근본 원인 분석
|
||||||
|
|
||||||
|
파이썬 생태계에서 HWP를 PDF로 직접 변환하는 라이브러리를 찾기 어려운 이유는 파이썬 언어의 한계가 아닌, HWP 포맷 자체의 본질적인 특성에 기인한다.
|
||||||
|
|
||||||
|
### 2.1. 독점적 파일 포맷의 장벽
|
||||||
|
|
||||||
|
HWP는 한글과컴퓨터가 개발하고 소유한 독점적 파일 포맷이다. DOCX나 ODT와 같이 공개된 표준과 달리, HWP 파일의 내부 구조와 데이터 명세는 외부에 공개되어 있지 않다.¹ 이로 인해 제3자 개발자들이 HWP 파일의 내용을 정확하게 해석하고 시각적으로 재현(rendering)하는 파서(parser)를 만드는 것은 기술적으로 매우 어렵다.
|
||||||
|
|
||||||
|
### 2.2. 파이썬 생태계에 미치는 영향
|
||||||
|
|
||||||
|
이러한 독점적 특성은 파이썬 오픈소스 커뮤니티에서 HWP 지원 라이브러리가 발전하지 못하는 직접적인 원인이 되었다. 파이썬은 `pypdf`³, `PyMuPDF`⁴, `pikepdf`⁵ 등 PDF 문서를 생성하고 조작하는 강력한 라이브러리들을 다수 보유하고 있다. 하지만 이 라이브러리들은 이미 구조화된 PDF를 다루는 데 특화되어 있을 뿐, HWP 파일의 원시 데이터를 읽어 들여 해석하는 기능은 전무하다.
|
||||||
|
|
||||||
|
결과적으로, HWP를 PDF로 변환하려는 개발자는 HWP 포맷을 공식적으로 지원하는 외부 소프트웨어에 의존하는 우회적인 방법을 선택할 수밖에 없다.
|
||||||
|
* `pywin32`는 한컴오피스로의 '가교' 역할을 하고,⁶
|
||||||
|
* HTTP 요청은 클라우드 API 서버로의 '가교' 역할을 하며,¹
|
||||||
|
* `subprocess` 모듈은 리브레오피스라는 외부 프로그램으로의 '가교' 역할을 하는 것이 바로 그 증거이다.
|
||||||
|
|
||||||
|
> 즉, 문제는 PDF 생성이 아니라 HWP 해석에 있다.
|
||||||
|
|
||||||
|
### 2.3. 텍스트 추출과 완전한 변환의 차이
|
||||||
|
|
||||||
|
일부 라이브러리는 HWP 파일에서 텍스트를 '추출'하는 기능을 제공하지만, 이는 완전한 '변환'과는 명백히 다르다. 예를 들어, `olefile` 라이브러리는 HWP 파일이 사용하는 OLE(Object Linking and Embedding) 컨테이너 구조를 분석하여 `PrvText`(미리보기 텍스트)나 `BodyText`(본문 텍스트)와 같은 원시 텍스트 스트림을 읽어올 수 있다.⁷
|
||||||
|
|
||||||
|
그러나 이 방식은 글꼴, 서식, 이미지, 표, 차트 등 문서의 시각적 레이아웃 정보를 전혀 해석하지 못한다. 따라서 단순한 텍스트 마이닝이나 데이터 분석 목적을 넘어, 원본 문서의 시각적 형태를 그대로 보존해야 하는 PDF 변환 요구사항은 충족시킬 수 없다.
|
||||||
|
|
||||||
|
## 3. COM 자동화를 통한 고품질 변환 (Windows 환경)
|
||||||
|
|
||||||
|
Windows 환경에서 가장 안정적이고 높은 품질의 변환 결과를 얻을 수 있는 방법은 COM(Component Object Model) 자동화를 통해 로컬에 설치된 한컴오피스를 직접 제어하는 것이다.
|
||||||
|
|
||||||
|
### 3.1. 메커니즘 및 아키텍처
|
||||||
|
|
||||||
|
COM은 마이크로소프트 윈도우의 핵심 기술로, 서로 다른 애플리케이션 간의 상호 운용성을 지원하는 표준 인터페이스이다. 한컴오피스는 외부 프로그램이 자신을 제어할 수 있도록 COM 인터페이스를 제공한다. 파이썬의 `pywin32` 라이브러리(win32com으로도 알려짐)는 이 COM 인터페이스에 접근할 수 있는 다리 역할을 수행한다.⁶
|
||||||
|
|
||||||
|
변환 프로세스는 다음과 같은 순서로 진행된다.
|
||||||
|
1. 파이썬 스크립트가 `win32.gencache.EnsureDispatch("HWPFrame.HwpObject")` 코드를 통해 한컴오피스 애플리케이션 객체를 생성한다.⁶
|
||||||
|
2. 생성된 객체의 `Open` 메서드를 호출하여 대상 HWP 파일을 연다.
|
||||||
|
3. `SaveAs` 메서드를 호출하면서 두 번째 인자로 `"PDF"`를 지정하여 문서를 PDF 포맷으로 저장한다.⁶
|
||||||
|
4. 변환이 완료되면 `Quit` 메서드를 호출하여 한컴오피스 애플리케이션을 종료한다.
|
||||||
|
|
||||||
|
### 3.2. 구현 가이드
|
||||||
|
|
||||||
|
**사전 요구사항:**
|
||||||
|
* Windows 운영체제
|
||||||
|
* 한컴오피스 소프트웨어 설치 및 정품 라이선스
|
||||||
|
* `pywin32` 라이브러리 설치 (`pip install pywin32`)⁸
|
||||||
|
|
||||||
|
**코드 예제:**
|
||||||
|
```python
|
||||||
|
import os
|
||||||
|
import win32com.client as win32
|
||||||
|
|
||||||
|
def convert_hwp_to_pdf_com(hwp_path, pdf_path):
|
||||||
|
"""
|
||||||
|
COM 자동화를 사용하여 HWP 파일을 PDF로 변환합니다.
|
||||||
|
:param hwp_path: 원본 HWP 파일의 전체 경로
|
||||||
|
:param pdf_path: 저장할 PDF 파일의 전체 경로
|
||||||
|
"""
|
||||||
|
hwp = None
|
||||||
|
try:
|
||||||
|
hwp = win32.gencache.EnsureDispatch("HWPFrame.HwpObject")
|
||||||
|
hwp.RegisterModule("FilePathCheckDLL", "SecurityModule") # 보안 모듈 등록
|
||||||
|
|
||||||
|
hwp.Open(hwp_path)
|
||||||
|
|
||||||
|
# PDF 저장 설정 (필요시 사용)
|
||||||
|
# 예: hwp.HAction.GetDefault("FileSaveAsPdf", hwp.HParameterSet.HFileOpenSave.HSet)
|
||||||
|
# hwp.HParameterSet.HFileOpenSave.filename = pdf_path
|
||||||
|
# hwp.HParameterSet.HFileOpenSave.Format = "PDF"
|
||||||
|
# hwp.HAction.Execute("FileSaveAsPdf", hwp.HParameterSet.HFileOpenSave.HSet)
|
||||||
|
|
||||||
|
hwp.SaveAs(pdf_path, "PDF")
|
||||||
|
print(f"'{hwp_path}' -> '{pdf_path}' 변환 성공")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"변환 중 오류 발생: {e}")
|
||||||
|
finally:
|
||||||
|
if hwp:
|
||||||
|
hwp.Quit()
|
||||||
|
|
||||||
|
# 사용 예시
|
||||||
|
# hwp_file = "C:\path\to\document.hwp"
|
||||||
|
# pdf_file = "C:\path\to\document.pdf"
|
||||||
|
# convert_hwp_to_pdf_com(hwp_file, pdf_file)
|
||||||
|
```
|
||||||
|
|
||||||
|
> **중요 고려사항: 보안 승인 모듈**
|
||||||
|
> 자동화 스크립트로 한컴오피스를 제어할 때, "한글을 이용하여 위 파일에 접근하려는 시도가 있습니다"와 같은 보안 경고 팝업이 발생할 수 있다.⁶ 완전한 자동화를 위해서는 이 팝업을 비활성화해야 한다. 이를 위해 한컴에서 제공하는 보안 승인 모듈을 다운로드하고 레지스트리에 등록하는 과정이 필요하다.⁹ 이는 무인 환경에서 스크립트가 중단 없이 실행되기 위한 필수적인 절차이다.
|
||||||
|
|
||||||
|
### 3.3. 장점 및 단점 분석
|
||||||
|
|
||||||
|
* **장점:**
|
||||||
|
* **최상의 변환 품질:** HWP 문서를 만든 네이티브 애플리케이션이 직접 변환을 수행하므로, 모든 요소가 원본과 동일하게 보존된다.
|
||||||
|
* **세부적인 제어 기능:** PDF의 세부 속성을 프로그래밍 방식으로 제어할 수 있다.¹⁰
|
||||||
|
* **높은 보안성:** 모든 변환 과정이 로컬에서 이루어져 데이터 유출 위험이 없다.
|
||||||
|
|
||||||
|
* **단점:**
|
||||||
|
* **플랫폼 종속성:** 오직 윈도우 운영체제에서만 작동한다.
|
||||||
|
* **소프트웨어 의존성:** 한컴오피스 전체 버전이 설치되어 있어야 한다.
|
||||||
|
* **자원 소모 및 프로세스 관리:** 상당한 시스템 자원을 소모하며, 견고한 예외 처리가 필요하다.
|
||||||
|
|
||||||
|
### 3.4. 비용 구조 분석
|
||||||
|
|
||||||
|
이 솔루션은 한컴오피스 소프트웨어 라이선스 구매 비용이 발생한다.
|
||||||
|
* **구독형 모델:** '한컴독스' 기업용 플랜은 1인당 월 8,250원¹⁷ 또는 월 7.00 달러¹⁹ 수준이다.
|
||||||
|
* **영구 라이선스:** '한컴오피스 2024 기업용'은 약 46만 원 ~ 51만 원.²⁰
|
||||||
|
* **볼륨 라이선스 (ALA):** 다수 사용자 대상 연간 계약.²⁰
|
||||||
|
|
||||||
|
총 소유 비용(TCO)에는 윈도우 서버 라이선스 및 유지보수 비용도 포함되어야 한다.
|
||||||
|
|
||||||
|
## 4. 클라우드 기반 REST API를 이용한 플랫폼 독립적 변환
|
||||||
|
|
||||||
|
운영체제에 구애받지 않고 유연하게 HWP 변환 기능을 구현해야 할 경우, 외부 전문 서비스를 활용하는 클라우드 기반 REST API가 효과적인 대안이 될 수 있다.
|
||||||
|
|
||||||
|
### 4.1. 메커니즘 및 아키텍처
|
||||||
|
|
||||||
|
클라이언트(파이썬 스크립트)가 HTTP 요청으로 HWP 파일을 API 서버에 전송하면, 서버가 PDF로 변환하여 결과를 응답으로 돌려주는 방식이다.
|
||||||
|
|
||||||
|
### 4.2. 주요 서비스 제공업체 및 구현
|
||||||
|
|
||||||
|
* **CloudConvert:** HWP to PDF 변환을 지원하는 대표적인 서비스.¹ `requests` 라이브러리로 연동 가능하다.
|
||||||
|
* **CoolUtils:** 온라인 변환 서비스 및 데스크톱/서버용 소프트웨어 판매.²⁴
|
||||||
|
* **기타 서비스:** Allinpdf,²⁶ FreeConvert²⁸ 등.
|
||||||
|
|
||||||
|
### 4.3. 장점 및 단점 분석
|
||||||
|
|
||||||
|
* **장점:**
|
||||||
|
* **크로스 플랫폼 호환성:** 모든 OS에서 작동한다.
|
||||||
|
* **로컬 의존성 없음:** 별도 소프트웨어 설치가 불필요하다.
|
||||||
|
* **높은 확장성:** 인프라 관리가 필요 없다.
|
||||||
|
|
||||||
|
* **단점:**
|
||||||
|
* **데이터 프라이버시 및 보안:** 민감 정보를 외부 서버에 업로드해야 한다.
|
||||||
|
* **지속적인 운영 비용:** 사용량 기반 또는 구독 모델로 비용이 계속 발생한다.
|
||||||
|
* **네트워크 의존성 및 지연 시간:** 인터넷 연결이 필수이며, 속도 저하가 발생할 수 있다.
|
||||||
|
* **제한적인 제어:** API가 제공하는 범위 내로 기능이 한정된다.
|
||||||
|
|
||||||
|
### 4.4. 비용 구조 분석
|
||||||
|
|
||||||
|
* **CloudConvert:** '변환 크레딧'이라는 과금 체계를 사용한다.¹
|
||||||
|
* **CoolUtils:** 주로 소프트웨어 라이선스 형태로 판매 (서버 라이선 $750).²⁵
|
||||||
|
|
||||||
|
> 클라우드 API 선택은 리스크 관리 및 규정 준수(compliance)에 대한 결정이기도 하다. 서비스 제공업체의 보안 정책, ISO 27001 인증¹, 데이터 처리 계약(DPA) 등을 검토하는 '신뢰 비용(Trust Tax)'이 발생할 수 있다.
|
||||||
|
|
||||||
|
## 5. 오픈소스 대안: CLI 도구 활용
|
||||||
|
|
||||||
|
비용을 최소화하면서 크로스 플랫폼을 지원해야 하는 경우, 파이썬에서 외부 명령줄 인터페이스(CLI) 도구를 호출하는 방식이 대안이 될 수 있다.
|
||||||
|
|
||||||
|
### 5.1. 메커니즘 및 아키텍처
|
||||||
|
|
||||||
|
파이썬의 `subprocess` 모듈을 사용하여 리브레오피스(LibreOffice)와 같은 외부 프로그램을 실행하고 파일 변환을 오케스트레이션한다.
|
||||||
|
|
||||||
|
### 5.2. 주요 도구: 리브레오피스 (LibreOffice)
|
||||||
|
|
||||||
|
리브레오피스는 HWP 파일 가져오기 기능을 일부 지원한다. 아래 명령어로 변환을 수행할 수 있다.
|
||||||
|
```bash
|
||||||
|
soffice --headless --convert-to pdf <입력파일.hwp> --outdir <출력경로>
|
||||||
|
```
|
||||||
|
`--headless` 플래그는 GUI 없이 백그라운드에서 작업을 수행하게 한다.³⁰
|
||||||
|
|
||||||
|
**파이썬 코드 예제:**
|
||||||
|
```python
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
def convert_hwp_to_pdf_libreoffice(hwp_path, output_dir):
|
||||||
|
"""
|
||||||
|
LibreOffice CLI를 사용하여 HWP 파일을 PDF로 변환합니다.
|
||||||
|
:param hwp_path: 원본 HWP 파일의 경로
|
||||||
|
:param output_dir: PDF 파일을 저장할 디렉토리
|
||||||
|
"""
|
||||||
|
if not os.path.exists(hwp_path):
|
||||||
|
print(f"오류: 파일이 존재하지 않습니다 - {hwp_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# OS별 soffice 경로
|
||||||
|
# Windows: "C:\Program Files\LibreOffice\program\soffice.exe"
|
||||||
|
# Linux: "libreoffice" or "soffice"
|
||||||
|
# macOS: "/Applications/LibreOffice.app/Contents/MacOS/soffice"
|
||||||
|
soffice_path = "soffice" # 시스템 PATH에 등록되어 있다고 가정
|
||||||
|
|
||||||
|
command = [
|
||||||
|
soffice_path,
|
||||||
|
"--headless",
|
||||||
|
"--convert-to", "pdf",
|
||||||
|
hwp_path,
|
||||||
|
"--outdir", output_dir
|
||||||
|
]
|
||||||
|
|
||||||
|
result = subprocess.run(command, check=True, capture_output=True, text=True)
|
||||||
|
print(f"LibreOffice 변환 성공. 출력:
|
||||||
|
{result.stdout}")
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("오류: 'soffice' 명령을 찾을 수 없습니다. LibreOffice가 설치되어 있고 PATH에 등록되었는지 확인하세요.")
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"LibreOffice 변환 실패. 오류:
|
||||||
|
{e.stderr}")
|
||||||
|
|
||||||
|
# 사용 예시
|
||||||
|
# hwp_file_path = "/path/to/document.hwp"
|
||||||
|
# pdf_output_dir = "/path/to/output"
|
||||||
|
# convert_hwp_to_pdf_libreoffice(hwp_file_path, pdf_output_dir)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.3. 장점 및 단점 분석
|
||||||
|
|
||||||
|
* **장점:**
|
||||||
|
* **무료:** 소프트웨어 라이선스 비용이 없다.
|
||||||
|
* **크로스 플랫폼:** Windows, Linux, macOS를 모두 지원한다.
|
||||||
|
* **일괄 처리 지원:** 스크립트를 통한 대량 변환에 용이하다.³²
|
||||||
|
|
||||||
|
* **단점:**
|
||||||
|
* **가변적인 변환 품질:** 가장 결정적인 약점. 리버스 엔지니어링 기반이므로 레이아웃이 깨질 수 있다.
|
||||||
|
* **무거운 의존성:** 리브레오피스 스위트 전체를 서버에 설치해야 한다.
|
||||||
|
* **성능:** 프로세스를 새로 시작해야 하므로 속도가 느릴 수 있다.
|
||||||
|
|
||||||
|
> 이 접근법은 '품질 대 자유(Fidelity vs. Freedom)'의 트레이드오프를 보여준다. 공식 문서보다는 내용 확인이나 미리보기 생성 등 비핵심 업무에 적합하다.
|
||||||
|
|
||||||
|
## 6. 고려하지 않아야 할 접근법 및 흔한 함정
|
||||||
|
|
||||||
|
* **`olefile`은 텍스트 추출 전용:** 시각적 구조 렌더링 기능이 없다.⁷
|
||||||
|
* **유지보수가 중단된 라이브러리 (`hwp2pdf`):** GitHub 저장소에 'unmaintained'로 명시되어 있으며,³³ 프로덕션 사용은 심각한 리스크를 초래한다.
|
||||||
|
* **범용 PDF 처리 라이브러리 (`PyMuPDF`, `pypdf` 등):** HWP 소스 파일을 해석하는 기능이 없다.³
|
||||||
|
|
||||||
|
## 7. 솔루션 선택을 위한 비교 프레임워크
|
||||||
|
|
||||||
|
최적의 솔루션은 프로젝트의 운영 환경, 예산, 보안 요구사항, 품질 허용 범위에 따라 달라진다.
|
||||||
|
|
||||||
|
**HWP-PDF 변환 방법론 비교 매트릭스**
|
||||||
|
|
||||||
|
| 기능 | COM 자동화 (pywin32) | 클라우드 API (예: CloudConvert) | CLI 래퍼 (LibreOffice) |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **OS 호환성** | Windows 전용 | Windows, macOS, Linux | Windows, macOS, Linux |
|
||||||
|
| **주요 의존성** | 한컴오피스 라이선스 | 인터넷 연결, API 구독 | 리브레오피스 스위트 설치 |
|
||||||
|
| **변환 품질** | 매우 높음 (네이티브) | 높음 ~ 매우 높음 (독자적 엔진) | 중간 ~ 높음 (리버스 엔지니어링) |
|
||||||
|
| **비용 모델** | 자본/운영 비용 | 운영 비용 (사용량 기반) | 무료 (숨겨진 유지보수 비용) |
|
||||||
|
| **성능** | 높음 (로컬 처리) | 네트워크에 의존 | 중간 (프로세스 오버헤드) |
|
||||||
|
| **보안/프라이버시**| 매우 높음 (On-Premise) | 낮음 ~ 중간 (외부 업로드) | 매우 높음 (On-Premise) |
|
||||||
|
| **설정 난이도** | 중간 | 쉬움 | 중간 |
|
||||||
|
| **이상적인 사용 사례**| 보안이 중요한 기업 백오피스 | 대국민 웹/모바일 서비스 | 예산 제한적인 내부 도구 |
|
||||||
|
|
||||||
|
## 8. 전략적 권장사항 및 최종 결론
|
||||||
|
|
||||||
|
### 8.1. 시나리오 1: Windows 기반의 기업 환경
|
||||||
|
* **권장 솔루션:** **COM 자동화 (pywin32)**
|
||||||
|
* **근거:** 최고의 변환 품질과 완벽한 데이터 보안을 보장한다.
|
||||||
|
|
||||||
|
### 8.2. 시나리오 2: 크로스 플랫폼 웹 또는 모바일 애플리케이션
|
||||||
|
* **권장 솔루션:** **신뢰할 수 있는 클라우드 API (예: CloudConvert)**
|
||||||
|
* **근거:** 플랫폼 독립성과 확장성을 제공하는 가장 현실적인 해결책이다. 단, 제공업체에 대한 보안 검토가 필수적이다.
|
||||||
|
|
||||||
|
### 8.3. 시나리오 3: 예산이 제한적이거나 Linux 중심의 개발 환경
|
||||||
|
* **권장 솔루션:** **리브레오피스 CLI 래퍼 (주의하여 사용)**
|
||||||
|
* **근거:** 무료로 사용할 수 있는 유일한 크로스 플랫폼 방법이다. 단, 도입 전 충분한 품질 테스트가 반드시 필요하다.
|
||||||
|
|
||||||
|
### 8.4. 최종 결론
|
||||||
|
|
||||||
|
> HWP를 PDF로 변환하는 '최고의' 단일 방법은 존재하지 않는다. 최적의 선택은 전적으로 주어진 프로젝트의 기술적 아키텍처, 비즈니스 요구사항, 그리고 리스크 허용 범위에 달려있다. 본 보고서는 각 접근법의 전략적 트레이드오프를 명확히 제시함으로써, 개발자와 의사결정권자가 자신의 상황에 가장 부합하는 현명한 결정을 내릴 수 있도록 필요한 분석적 토대를 제공한다.
|
||||||
104
ideas/250916_네이버웍스_캘린더_API_연동_가이드.md
Normal file
104
ideas/250916_네이버웍스_캘린더_API_연동_가이드.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# 네이버웍스 캘린더 API 연동 가이드
|
||||||
|
|
||||||
|
## 핵심 요약
|
||||||
|
|
||||||
|
> 네이버웍스 캘린더는 별도의 '에이전트' 개념보다는 **API(Application Programming Interface)**를 통해 외부 애플리케이션이나 봇이 캘린더 데이터를 읽고 수정하도록 허용합니다. 즉, 에이전트 역할을 하는 프로그램이 이 API를 호출하여 기능을 수행하게 됩니다.
|
||||||
|
|
||||||
|
**[현재 프로젝트 상태]** 네이버웍스 캘린더 API 연동 미구현 (OAuth2 토큰 관리 로직 없음, skill-calendar 서비스 미존재, auth-server에 Works API 인증 미탑재).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 네이버웍스 캘린더 API 개요
|
||||||
|
|
||||||
|
네이버웍스(NAVER WORKS)는 개발자가 자사의 다양한 기능과 리소스에 접근할 수 있도록 **NAVER WORKS API**를 제공합니다. 캘린더 기능 역시 이 API에 포함되어 있으며, 다음 기능을 수행할 수 있습니다.
|
||||||
|
|
||||||
|
* **일정 조회 (View):** 특정 사용자의 기본 캘린더나 공유 캘린더의 일정을 조회합니다.
|
||||||
|
* **일정 생성 (Create):** 새로운 일정을 생성하고 참석자, 시간, 장소 등을 설정합니다.
|
||||||
|
* **일정 수정 (Modify):** 기존 일정의 정보를 업데이트합니다.
|
||||||
|
* **일정 삭제 (Delete):** 일정을 삭제합니다.
|
||||||
|
* **캘린더 관리 (Manage):** 캘린더 자체를 생성, 수정, 삭제하고 공유 속성을 관리합니다.
|
||||||
|
|
||||||
|
## 2. 에이전트(봇) 구현을 위한 필수 절차
|
||||||
|
|
||||||
|
에이전트(봇)가 캘린더 API를 사용하려면 다음 절차를 따라야 합니다.
|
||||||
|
|
||||||
|
1. **개발자 콘솔에서 앱 생성:** [네이버웍스 개발자 콘솔](https://dev.worksmobile.com)에 관리자 계정으로 로그인하여 캘린더 API를 사용할 앱을 생성해야 합니다.
|
||||||
|
2. **Access Token 발급:** API 호출을 위해서는 인증(Authentication) 절차를 거쳐 `Access Token`을 발급받아야 합니다. 이 토큰은 API 요청에 대한 권한을 부여하는 역할을 합니다.
|
||||||
|
3. **API 스코프(Scope) 설정:** 앱이 캘린더에 접근할 수 있도록 API 권한 관리에서 `calendar` 또는 `calendar.read`와 같은 스코프를 설정해야 합니다.
|
||||||
|
* `calendar.read`: 읽기 전용 권한
|
||||||
|
* `calendar`: 읽기, 쓰기, 수정, 삭제 등 모든 권한
|
||||||
|
4. **API 호출:** 발급받은 `Access Token`을 사용하여 HTTP 요청을 보냅니다. API 호출 방식은 일반적으로 RESTful API 형태로 제공되며, `GET`, `POST`, `PUT`, `DELETE` 등의 HTTP 메서드를 사용합니다.
|
||||||
|
|
||||||
|
## 3. API 사용 예시 (영문 문서 기반)
|
||||||
|
|
||||||
|
네이버웍스 개발자 문서는 영어로도 제공되며, 다음은 주요 API 호출 예시입니다.
|
||||||
|
|
||||||
|
### A. 일정 목록 조회 (GET)
|
||||||
|
|
||||||
|
특정 사용자의 기본 캘린더 일정을 조회하는 API입니다.
|
||||||
|
|
||||||
|
* **HTTP Request:** `GET /users/{userId}/calendar/events`
|
||||||
|
* **Description:** Retrieves a list of events from the default calendar of the target user.
|
||||||
|
* **Authorization:** `Bearer {token}` (요청 헤더에 Access Token 포함)
|
||||||
|
|
||||||
|
### B. 일정 생성 (POST)
|
||||||
|
|
||||||
|
사용자의 기본 캘린더에 새로운 일정을 생성하는 API입니다.
|
||||||
|
|
||||||
|
* **HTTP Request:** `POST /users/{userId}/calendar/events`
|
||||||
|
* **Description:** Creates a new event in the target user's default calendar.
|
||||||
|
* **Request Body (JSON):** 일정의 제목, 시작/종료 시간, 참석자 등 상세 정보를 JSON 형식으로 담아 보냅니다.
|
||||||
|
|
||||||
|
**Request URL:**
|
||||||
|
`POST https://www.worksapis.com/v1.0/users/{userId}/calendar/events`
|
||||||
|
|
||||||
|
**JSON Example:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"subject": "Team Meeting",
|
||||||
|
"start": {
|
||||||
|
"date": "2025-09-12",
|
||||||
|
"time": "10:00:00"
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"date": "2025-09-12",
|
||||||
|
"time": "11:00:00"
|
||||||
|
},
|
||||||
|
"attendees": [
|
||||||
|
{
|
||||||
|
"email": "member1@example.com",
|
||||||
|
"isOptional": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### C. 일정 수정 (PUT)
|
||||||
|
|
||||||
|
기존 일정의 내용을 수정하는 API입니다.
|
||||||
|
|
||||||
|
* **HTTP Request:** `PUT /users/{userId}/calendar/events/{eventId}`
|
||||||
|
* **Description:** Updates an event in the target user's default calendar.
|
||||||
|
* **Authorization:** `Bearer {token}`
|
||||||
|
* **Request Body (JSON):** 수정할 내용이 포함된 JSON 데이터를 보냅니다.
|
||||||
|
|
||||||
|
## 4. 에이전트 구현 시 고려사항
|
||||||
|
|
||||||
|
* **인증 (OAuth 2.0):** 네이버웍스 API는 OAuth 2.0 기반 인증을 사용합니다. 에이전트는 이 인증 흐름을 이해하고 Access Token을 관리해야 합니다.
|
||||||
|
* **권한 (Scope):** 에이전트의 역할에 따라 필요한 최소한의 권한(예: 읽기 전용)을 설정하여 보안을 강화하는 것이 중요합니다.
|
||||||
|
* **사용자 관리:** 봇이 특정 사용자의 캘린더에 접근하려면 해당 사용자의 `userId`를 알아야 합니다.
|
||||||
|
* **오류 처리:** API 호출 시 발생할 수 있는 오류(예: `403 Forbidden`, `404 Not Found`)를 적절히 처리하도록 로직을 구현해야 합니다.
|
||||||
|
|
||||||
|
## 5. 참고 자료 및 결론
|
||||||
|
|
||||||
|
네이버웍스 캘린더 API는 주로 기업 내부 시스템 통합이나 업무 자동화 봇 개발에 사용되므로, 일반 네이버 캘린더 API와 달리 대외적으로 공개된 영상이나 블로그 튜토리얼이 많지 않습니다.
|
||||||
|
|
||||||
|
따라서 캘린더 제어 프로그램을 만들고자 한다면, 아래 공식 개발자 문서를 중심으로 학습하는 것이 가장 정확하고 효율적인 방법입니다.
|
||||||
|
|
||||||
|
* **네이버웍스 개발자 센터 (공식 문서):** [developers.worksmobile.com](https://developers.worksmobile.com)
|
||||||
|
* [한국어 캘린더 API 문서](https://developers.worksmobile.com/kr/document/10070?lang=ko)
|
||||||
|
* [영문 캘린더 API 문서](https://developers.worksmobile.com/document/10070?lang=en)
|
||||||
|
* **네이버 개발자 포럼:** API 관련 실제 질의응답을 참고할 수 있습니다.
|
||||||
|
* **유튜브 튜토리얼:** "네이버웍스 봇 개발"로 검색하면 API 사용의 기본적인 흐름과 인증 절차에 대한 이해를 돕는 영상을 찾을 수 있습니다.
|
||||||
|
|
||||||
|
> **결론:** 공식 문서의 예제 코드를 기반으로 직접 코드를 작성하며 기능을 구현하는 것을 추천합니다.
|
||||||
95
ideas/250916_로빙_감정_분석_시스템_구현_계획.md
Normal file
95
ideas/250916_로빙_감정_분석_시스템_구현_계획.md
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
# 로빙 감정 분석 시스템 구현 계획
|
||||||
|
|
||||||
|
> 사용자의 사양(7개 감정, klue/bert-base, Temperature Scaling, ONNX 추론)을 전제로, 로빙이 감정 그래프를 생성하고 제공하기 위한 구현 순서와 운영 항목을 정리한 문서입니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 목표와 범위
|
||||||
|
|
||||||
|
로빙은 한국어 텍스트 입력을 받아 7개 감정(fear, surprise, anger, sadness, neutral, happiness, disgust) 확률을 산출하고, 보정된 확률 기반의 시계열 그래프와 요약 리포트를 제공합니다. 실시간 대화형(배치 1)과 비동기 배치(8–32) 처리를 모두 지원합니다.
|
||||||
|
|
||||||
|
**[현재 프로젝트 상태]** app/core/emotion/base.py에 9개 감정 임시 균등값만 존재. EMOTION_TEMPERATURE 변수 있으나 스케일링 미적용. ONNX 추론 미통합. emotion_readings 테이블 없음. /v1/emotion/* API 엔드포인트 미구현 (test_endpoint.py의 /emotion만 존재).
|
||||||
|
|
||||||
|
## 2. 모델 파이프라인
|
||||||
|
|
||||||
|
* **입력 전처리:** `klue/bert-base` 토크나이저 사용, 최대 길이 128로 고정, 잘림 규칙 명시.
|
||||||
|
* **추론 모델:** 7개 클래스 단일 라벨 분류기. 원시 로짓(logits)을 산출.
|
||||||
|
* **확률 보정:** Temperature Scaling `Softmax(z/T)`으로 확률 보정.
|
||||||
|
* **후처리:**
|
||||||
|
* 최댓값 확률과 엔트로피 계산.
|
||||||
|
* 임계값(기본 τ=0.45) 미만은 `unknown`으로 강등.
|
||||||
|
* **버저닝:** `model_version`과 `temperature` 값을 쌍으로 관리. 모델 교체 시 T를 반드시 재추정.
|
||||||
|
|
||||||
|
## 3. Temperature Scaling 운용
|
||||||
|
|
||||||
|
* **학습:** 검증 세트(validation set)로만 T 값을 추정 (L-BFGS-B 알고리즘, 목적 함수 NLL, 보조 지표 ECE).
|
||||||
|
* **관리:** 배포 구성 파일에 모델 버전별 T 값을 기록. 모델 교체 시 재보정 필수.
|
||||||
|
* **품질 기준:** 보정 전 대비 NLL 및 ECE 감소를 최소 기준으로 삼음.
|
||||||
|
|
||||||
|
## 4. ONNX 변환 및 추론 최적화
|
||||||
|
|
||||||
|
* **변환:** `transformers optimum` 또는 `onnx export` 사용 (opset 17, 동적 축 지정).
|
||||||
|
* **실행:** ONNX Runtime, 그래프 최적화 `ORT_ENABLE_ALL`, 스레드 수 고정.
|
||||||
|
* **양자화 (선택):** 동적 양자화 적용 후 정밀도, 지연, ECE 재점검.
|
||||||
|
* **지연 관리:** 실시간 p95 지연 목표 수립 (예: 40–80ms on CPU, 10–20ms on GPU).
|
||||||
|
|
||||||
|
## 5. 저장 스키마
|
||||||
|
|
||||||
|
`emotion_readings` 테이블에 다음 항목을 저장합니다.
|
||||||
|
|
||||||
|
* `user_id`, `source`, `ts`, `text_hash`
|
||||||
|
* `model_version`, `temperature`
|
||||||
|
* `logits[7]`, `probs[7]`
|
||||||
|
* `top_label`, `top_p`, `entropy`, `meta`
|
||||||
|
|
||||||
|
**주요 인덱스:**
|
||||||
|
* `(user_id, ts)` 복합 인덱스
|
||||||
|
* `meta` GIN 인덱스
|
||||||
|
|
||||||
|
> **참고:** 원문 텍스트는 별도 저장소에 암호화하여 저장하고, 본 테이블에는 해시값만 유지합니다.
|
||||||
|
|
||||||
|
## 6. 서비스 API
|
||||||
|
|
||||||
|
* `POST /v1/emotion/infer`: 단건 추론. 보정 확률, 라벨, 엔트로피, `top_p`, `model_version`, `temperature`, `ts` 반환.
|
||||||
|
* `POST /v1/emotion/infer:batch`: 최대 128건 배치 처리. 서버 내부에서 마이크로배칭 및 캐시 적용.
|
||||||
|
* `GET /v1/emotion/timeseries`: 기간 및 빈도(`bin=1h` 등)별 평균 확률, 지배 라벨, 평균 엔트로피 반환.
|
||||||
|
|
||||||
|
## 7. 시각화 설계
|
||||||
|
|
||||||
|
* **지배 라벨 타임라인:** 시간축에 최댓값 라벨을 색상 구간으로 표시. EMA(α=0.2) 또는 이동평균을 적용하여 진동 완화.
|
||||||
|
* **확률 시계열:** 7개 라벨의 확률을 선 그래프로 표시. 기본적으로 상위 2–3개만 강조하고 나머지는 토글로 제어.
|
||||||
|
* **분포 그래프:** 일/시간대별 스택 영역 차트로 감정 비중 요약.
|
||||||
|
* **불확실성 표현:** 엔트로피가 높을수록 그래프의 음영 또는 투명도를 조절하여 시각적으로 표현.
|
||||||
|
* **Slack 연동:** 최근 24시간 요약 텍스트(상위 라벨, 평균 엔트로피 등)와 함께 정적 PNG 그래프 또는 대시보드 링크를 제공.
|
||||||
|
|
||||||
|
## 8. 운영 및 모니터링
|
||||||
|
|
||||||
|
* **모델 건전성:** 주간 혼동 행렬, 라벨별 평균 확률, ECE, NLL 트래킹.
|
||||||
|
* **데이터 분포:** 사용자별 라벨 분포가 전체 대비 과도하게 치우치면 점검 알림.
|
||||||
|
* **성능:** p95 추론 지연, 큐 대기 시간, 배치 처리량 모니터링.
|
||||||
|
* **알림 정책:** 부정 라벨 비중이 지속적으로 상승하거나 엔트로피가 급증하는 구간을 탐지. 단, 알림은 사용자 동의 범위 내에서만 제안형으로 표시.
|
||||||
|
|
||||||
|
## 9. 보안과 프라이버시
|
||||||
|
|
||||||
|
* **원문 보호:** 원문은 암호화하여 저장하거나 비식별화 처리 후 해시만 유지.
|
||||||
|
* **삭제 권리:** 사용자가 기간을 지정하여 데이터를 삭제할 수 있는 API 지원.
|
||||||
|
* **접근 제어:** 본인과 관리자만 열람 가능하도록 스코프 분리. 감사 로그는 최소한으로 기록.
|
||||||
|
|
||||||
|
## 10. 배포 체크리스트
|
||||||
|
|
||||||
|
- [ ] 검증 세트 분리 및 T 추정 완료
|
||||||
|
- [ ] ONNX와 PyTorch 결과의 최대 오차 검증
|
||||||
|
- [ ] 보정 전후 NLL·ECE 비교 리포트 산출
|
||||||
|
- [ ] 지연 시간 목표(p95) 만족 여부 확인
|
||||||
|
- [ ] Slack 메시지 규격 및 이미지 렌더러 동작 확인
|
||||||
|
- [ ] 모델 버전, T, 임계값 τ 설정이 구성 서버에 반영되었는지 점검
|
||||||
|
|
||||||
|
## 11. 1주 구현 순서 (예시)
|
||||||
|
|
||||||
|
* **1일차:** 모델 가중치 확정, 검증 세트 준비, T 추정.
|
||||||
|
* **2일차:** ONNX 변환 및 추론 엔진 래퍼, 단건 API 구현.
|
||||||
|
* **3일차:** 배치 API, 저장 스키마 및 리포지토리 구현.
|
||||||
|
* **4일차:** 시계열 집계 로직, EMA 적용, 그래프 렌더러 구현.
|
||||||
|
* **5일차:** Slack 요약 카드, PNG 업로드, 권한 및 로깅 적용.
|
||||||
|
* **6일차:** 품질 대시보드 구축 (ECE, NLL, 혼동 행렬).
|
||||||
|
* **7일차:** 부하/지연 테스트, 문서화 및 운영 기준 수립.
|
||||||
110
ideas/250916_슬랙_캔버스_API_활용_방안.md
Normal file
110
ideas/250916_슬랙_캔버스_API_활용_방안.md
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# 로빙(RO-BEING)의 슬랙 캔버스(Canvas) 활용 방안
|
||||||
|
|
||||||
|
> Slack API 문서를 기반으로, 로빙이 캔버스를 읽고 쓰기 위해 필요한 스코프, 구현 흐름, 제약 사항을 3가지 시나리오로 나누어 구체적으로 정리한 문서입니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 공통 이해 요약
|
||||||
|
|
||||||
|
**[현재 프로젝트 상태]** 캔버스 API 미사용 (canvases.create/edit/sections.lookup 호출 없음). canvases:read/write 스코프 미설정. files.list?types=canvas 탐색 미구현. canvases.access.set/delete 권한 관리 없음.
|
||||||
|
|
||||||
|
* **캔버스 종류:** 독립 문서(standalone) 또는 채널에 붙은 문서(channel canvas)로 존재합니다.
|
||||||
|
* **주요 API:**
|
||||||
|
* 생성: `canvases.create`
|
||||||
|
* 수정: `canvases.edit`
|
||||||
|
* 섹션 조회: `canvases.sections.lookup`
|
||||||
|
* 접근 권한: `canvases.access.set` / `delete`
|
||||||
|
* **콘텐츠 포맷:** `document_content` 객체에 `type: "markdown"`과 `markdown` 문자열만 지원합니다. **Block Kit은 지원하지 않습니다.**
|
||||||
|
* **탐색 및 읽기:** `files.list` API에 `types=canvas` 파라미터를 주어 검색하고, 반환된 파일 객체의 `url_private`를 `Authorization: Bearer <token>` 헤더와 함께 호출하여 본문을 다운로드합니다.
|
||||||
|
* **필수 권한 (스코프):**
|
||||||
|
* `canvases:write`: 생성/편집/삭제/공유
|
||||||
|
* `canvases:read`: 섹션 조회 등 읽기 작업
|
||||||
|
* `files:read`: 파일/캔버스 목록 조회 및 다운로드
|
||||||
|
* **제약 사항:**
|
||||||
|
* **유료 플랜 전용:** 캔버스 관련 API는 유료 플랜에서만 사용할 수 있습니다.
|
||||||
|
* **DM/다인 DM 공유:** 채널 ID가 아닌 사용자 ID(`user_ids`) 기준으로만 공유 가능하며, 사전에 해당 사용자에게 캔버스 링크가 공유된 이력이 있어야 합니다.
|
||||||
|
* **전용 마크다운:** 사용자(``), 채널(``) 멘션 문법이 일반 메시지와 다릅니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 시나리오 1: 프로젝트별 위키 (독립 캔버스)
|
||||||
|
|
||||||
|
**목표:** 프로젝트 시작 시 독립적인 위키 캔버스를 만들고, 섹션별로 내용을 추가/교체하며, 필요시 특정 인원이나 채널에 공유합니다.
|
||||||
|
|
||||||
|
#### 필요 스코프
|
||||||
|
* **필수:** `canvases:write`, `canvases:read`, `files:read`
|
||||||
|
* **선택:** `conversations:read` (채널 ID 탐색용), `chat:write` (안내 메시지 전송용)
|
||||||
|
|
||||||
|
#### 구현 흐름
|
||||||
|
1. **생성:** `canvases.create`를 호출하여 `title`과 `document_content` (markdown)를 포함한 캔버스를 생성하고, 반환된 `canvas_id`를 저장합니다.
|
||||||
|
2. **공유 (선택):** `canvases.access.set`을 사용하여 `user_ids` 또는 `channel_ids`로 접근 권한을 부여합니다.
|
||||||
|
3. **편집:**
|
||||||
|
* **문단 추가:** `canvases.edit`의 `changes` 배열에 `{operation: "insert_at_end", ...}`를 포함하여 호출합니다.
|
||||||
|
* **특정 위치 삽입:** `canvases.sections.lookup`으로 `section_id`를 찾은 뒤, `insert_after` / `insert_before` / `replace` operation을 사용합니다.
|
||||||
|
4. **목록화/탐색:** `files.list?types=canvas`로 워크스페이스의 캔버스 목록을 조회하고, `url_private`로 본문을 다운로드합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 시나리오 2: 채널 온보딩/FAQ 자동화 (채널 캔버스)
|
||||||
|
|
||||||
|
**목표:** 새 채널이 생성되거나 로빙이 채널에 초대될 때, 해당 채널의 캔버스 탭에 "가이드/FAQ" 문서를 자동으로 생성하고 주기적으로 갱신합니다.
|
||||||
|
|
||||||
|
#### 필요 스코프
|
||||||
|
* **필수:** `canvases:write`, `canvases:read`
|
||||||
|
* **선택:** `conversations:read` (채널 ID 탐색), `chat:write` (갱신 알림), `files:read` (내부 파일/이미지 링크 삽입)
|
||||||
|
|
||||||
|
#### 구현 흐름
|
||||||
|
1. **채널 식별:** `conversations.list` 또는 채널 생성 이벤트를 통해 `channel_id`를 확보합니다.
|
||||||
|
2. **채널 탭에 캔버스 생성:** `canvases.create` 호출 시 `channel_id`를 함께 전달하면 해당 채널 탭에 캔버스가 자동으로 추가됩니다.
|
||||||
|
3. **접근 제어:** `canvases.access.set`으로 채널 단위 접근 권한을 설정합니다.
|
||||||
|
4. **주기적 갱신:** 캔버스 내 헤더(예: `## FAQ`)를 앵커로 삼아 `canvases.sections.lookup`으로 위치를 찾고, `canvases.edit`으로 해당 섹션만 교체합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 시나리오 3: 회의록/인시던트 문서화
|
||||||
|
|
||||||
|
**목표:** 회의나 인시던트 종료 후, 대화 요약본을 캔버스의 정해진 서식(체크리스트, 테이블 등)에 맞춰 구조화하여 반영하고 관련 스크린샷을 첨부합니다.
|
||||||
|
|
||||||
|
#### 필요 스코프
|
||||||
|
* **필수:** `canvases:write`, `canvases:read`
|
||||||
|
* **선택:** `files:read` (이미지 퍼멀링크 조회), `chat:write` (완료 알림), `conversations:read` (관련 채널 탐색)
|
||||||
|
|
||||||
|
#### 구현 흐름
|
||||||
|
1. **서식 정의:** 캔버스 내에 헤더(예: `# Summary`, `## Action items`)를 앵커로 미리 정의합니다.
|
||||||
|
2. **섹션 위치 탐색:** `canvases.sections.lookup`에 `section_types:["h1","h2"]`와 `contains_text:"Action items"` 같은 조건을 주어 삽입할 위치의 `section_id`를 찾습니다.
|
||||||
|
3. **내용 반영:** `canvases.edit`을 사용하여 `insert_after` 또는 `replace` operation을 수행합니다. 체크리스트(`- [ ]`), 테이블(파이프 `|` 문법) 등 캔버스 전용 마크다운을 사용합니다.
|
||||||
|
4. **이미지 삽입:** 슬랙에 업로드된 파일은 `files.info`로 `permalink`를 얻은 뒤, 마크다운 `` 형식으로 본문에 삽입합니다.
|
||||||
|
5. **완료 알림 (선택):** `chat.postMessage`를 통해 관련 채널에 캔버스 링크와 변경 요약 내용을 알립니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 앱 매니페스트 및 스코프 설정 (예시)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
display_information:
|
||||||
|
name: RO-BEING
|
||||||
|
features:
|
||||||
|
bot_user:
|
||||||
|
display_name: RO-BEING
|
||||||
|
always_online: true
|
||||||
|
oauth_config:
|
||||||
|
scopes:
|
||||||
|
bot:
|
||||||
|
- canvases:write
|
||||||
|
- canvases:read
|
||||||
|
- files:read
|
||||||
|
- conversations:read # 채널 탐색/확인 용도
|
||||||
|
- chat:write # 안내/알림 메시지 포스팅 시
|
||||||
|
settings:
|
||||||
|
interactivity:
|
||||||
|
is_enabled: true
|
||||||
|
```
|
||||||
|
> **중요:** 스코프 추가 후에는 앱을 워크스페이스에 재설치해야 합니다.
|
||||||
|
|
||||||
|
## 최소 구현 체크리스트
|
||||||
|
|
||||||
|
- [ ] **스코프 추가:** 매니페스트에 `canvases:write`, `canvases:read`, `files:read` 추가 후 앱 재설치.
|
||||||
|
- [ ] **생성:** `canvases.create`로 캔버스 생성 및 `canvas_id` 저장. (채널 탭 연동 시 `channel_id` 포함)
|
||||||
|
- [ ] **편집:** `canvases.sections.lookup` → `canvases.edit` 조합으로 위치 기반 편집 구현.
|
||||||
|
- [ ] **공유:** `canvases.access.set`으로 채널/사용자 접근 수준 설정. (DM/MPDM 제약 준수)
|
||||||
|
- [ ] **탐색:** `files.list?types=canvas`로 캔버스 검색 및 `url_private`로 본문 다운로드.
|
||||||
@ -12,9 +12,9 @@
|
|||||||
|
|
||||||
### 검증 과정 분석
|
### 검증 과정 분석
|
||||||
```
|
```
|
||||||
현재 검색: "컴퍼니 엑스" → 부분 매칭 발생
|
현재 검색: COMPANY_X_SEARCH_KEYWORD='"컴퍼니 엑스"' (따옴표 포함)
|
||||||
수집 결과: 보링컴퍼니, DHX컴퍼니, 엑스붐 버즈 등
|
수집 결과: 보링컴퍼니, DHX컴퍼니, 엑스붐 버즈 등
|
||||||
검증 로직: 없음 (수집된 모든 기사를 그대로 전송)
|
검증 로직: 없음 (companyx_news_collector.py에 검증 코드 없음)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 추가 문제
|
### 추가 문제
|
||||||
@ -29,29 +29,21 @@ docker logs robeing-skill-news | grep "컴퍼니엑스"
|
|||||||
# 결과: "머스크의 보링컴퍼니", "엔티엑스(NTX)" 등 수집
|
# 결과: "머스크의 보링컴퍼니", "엔티엑스(NTX)" 등 수집
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. 슬랙 메시지 수정
|
### 2. 슬랙 메시지 처리 방안
|
||||||
```bash
|
- chat_update API로 메시지 수정 가능
|
||||||
docker exec rb8001 python -c "
|
- 채널: C09C98KK2TT, ts: 1757984471.889439
|
||||||
client.chat_update(channel='C09C98KK2TT', ts='1757984471.889439',
|
|
||||||
text='잘못된 기사 송출로 삭제합니다. 검증 과정을 보완하겠습니다.')
|
|
||||||
"
|
|
||||||
```
|
|
||||||
|
|
||||||
## 검증 과정 보완책
|
## 필요한 개선사항
|
||||||
### 1. 수집 단계 검증
|
### 1. 수집 단계 검증 필요
|
||||||
- 정확한 회사명 "CompanyX" 사용 (따옴표 포함)
|
- 제목/URL에서 회사명 정확히 포함 여부 확인 로직 추가
|
||||||
- 검색 결과 제목/URL에서 회사명 정확히 포함 여부 확인
|
- 부분 매칭 제외 로직 구현
|
||||||
- 부분 매칭 제외 로직: `if "CompanyX" not in title: skip`
|
|
||||||
|
|
||||||
### 2. 처리 단계 검증
|
### 2. 처리 단계 검증 필요
|
||||||
- 본문 스크래핑 후 CompanyX 언급 횟수 카운트
|
- 본문 스크래핑 후 관련성 검증 로직 추가
|
||||||
- 최소 언급 횟수(예: 3회) 미달 시 제외
|
|
||||||
- 관련성 점수 계산: 제목(50%) + 본문(50%)
|
|
||||||
|
|
||||||
### 3. 전송 전 최종 검증
|
### 3. 전송 전 검증 필요
|
||||||
- summarized 상태 기사만 전송
|
- summarized 상태 기사만 전송하도록 필터링
|
||||||
- 검증된 기사 0개일 때 전송 중단
|
- 검증된 기사 0개일 때 전송 중단 로직
|
||||||
- 이전 캐시 데이터 사용 금지
|
|
||||||
|
|
||||||
## 교훈
|
## 교훈
|
||||||
- 검색어 설정과 검증은 별개 프로세스로 관리 필요
|
- 검색어 설정과 검증은 별개 프로세스로 관리 필요
|
||||||
|
|||||||
@ -0,0 +1,83 @@
|
|||||||
|
# rb8001 ChromaDB 메타데이터 손상 문제
|
||||||
|
|
||||||
|
## 배경
|
||||||
|
- **날짜**: 2025-09-16
|
||||||
|
- **작성자**: happybell80
|
||||||
|
- **문제**: ChromaDB 메타데이터 BLOB/INTEGER 타입 불일치로 서비스 전면 마비
|
||||||
|
|
||||||
|
## 문제 상황
|
||||||
|
|
||||||
|
### 핵심 문제
|
||||||
|
- **증상**: 10:22부터 모든 사용자 요청에서 ChromaDB 오류 발생
|
||||||
|
- **오류**: `BLOB column can't be cast to INTEGER (u64)`
|
||||||
|
- **영향**: 대화 맥락 유지 및 개인화 기능 전면 마비
|
||||||
|
|
||||||
|
### 오류 메시지
|
||||||
|
```
|
||||||
|
chromadb.errors.InvalidCollectionException:
|
||||||
|
Collection with name rb8001_rag already exists
|
||||||
|
```
|
||||||
|
|
||||||
|
### 근본 원인
|
||||||
|
- ChromaDB 내부 메타데이터 컬럼이 BLOB으로 저장됨
|
||||||
|
- 시스템이 INTEGER(u64)로 읽으려 시도
|
||||||
|
- 데이터베이스 마이그레이션이나 버전 업그레이드 중 스키마 불일치 발생 추정
|
||||||
|
|
||||||
|
## 부가 문제
|
||||||
|
|
||||||
|
### 1. 스케줄러 user_id 처리
|
||||||
|
- 시스템 작업 시 더미 user_id 필요
|
||||||
|
- 현재 스케줄러가 user_id 없이 호출하여 오류 발생
|
||||||
|
|
||||||
|
### 2. 파일 중복 체크
|
||||||
|
- 해시 기반 중복 검사 로직은 정상 작동 중
|
||||||
|
- ChromaDB 문제와는 별개
|
||||||
|
|
||||||
|
### 3. 이메일 서비스 불안정
|
||||||
|
- skill_email 서비스 헬스체크는 정상
|
||||||
|
- 실제 이메일 API 호출 시 500 에러 발생
|
||||||
|
|
||||||
|
## 현재 상태
|
||||||
|
- PostgreSQL: 정상 작동
|
||||||
|
- 기본 대화: 가능 (품질 저하)
|
||||||
|
- ChromaDB 의존 기능: 전면 마비
|
||||||
|
- 대화 맥락 유지 불가
|
||||||
|
- 개인화 기능 불가
|
||||||
|
- RAG 검색 불가
|
||||||
|
|
||||||
|
## 해결 방향 (코드 수정 없이)
|
||||||
|
|
||||||
|
### 옵션 1: ChromaDB 컬렉션 재생성
|
||||||
|
```bash
|
||||||
|
# ChromaDB 데이터 백업
|
||||||
|
cp -r /mnt/hdd/chromadb_data /mnt/hdd/chromadb_backup_20250916
|
||||||
|
|
||||||
|
# 컬렉션 삭제 및 재생성
|
||||||
|
docker exec rb8001 python -c "
|
||||||
|
import chromadb
|
||||||
|
client = chromadb.PersistentClient(path='/mnt/hdd/chromadb_data')
|
||||||
|
client.delete_collection('rb8001_rag')
|
||||||
|
"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 옵션 2: ChromaDB 초기화
|
||||||
|
```bash
|
||||||
|
# 전체 ChromaDB 데이터 초기화
|
||||||
|
mv /mnt/hdd/chromadb_data /mnt/hdd/chromadb_data_old
|
||||||
|
mkdir /mnt/hdd/chromadb_data
|
||||||
|
docker restart rb8001
|
||||||
|
```
|
||||||
|
|
||||||
|
### 옵션 3: 메타데이터 재인덱싱
|
||||||
|
- 기존 벡터 데이터를 새 컬렉션으로 마이그레이션
|
||||||
|
- 메타데이터 타입 명시적 지정 필요
|
||||||
|
|
||||||
|
## 영향 범위
|
||||||
|
- 모든 사용자 대화 영향
|
||||||
|
- 10:22부터 지속적 발생
|
||||||
|
- skill-rag-file 등 연계 서비스도 영향 받음
|
||||||
|
|
||||||
|
## 교훈
|
||||||
|
- ChromaDB 버전 업그레이드 전 스키마 호환성 검증 필수
|
||||||
|
- 백업 없이 마이그레이션 진행 금지
|
||||||
|
- 메타데이터 타입 변경 시 명시적 타입 캐스팅 필요
|
||||||
Loading…
x
Reference in New Issue
Block a user