Skip to content

Latest commit

 

History

History
358 lines (299 loc) · 17.4 KB

File metadata and controls

358 lines (299 loc) · 17.4 KB

Second Brain — 디렉토리 감시 기반 자동 수집 시스템 구현 계획

폴더에 파일을 넣기만 하면 자동으로 감지 → 추출 → LLM 분류 → 임베딩 → Teradata Vector Store 저장 → 웹 채팅에서 검색되는 "자동 수집형 개인 지식 플랫폼".


1. 목표와 범위

핵심 사용자 시나리오

  1. 사용자가 /second-brain/inbox에 파일을 복사한다.
  2. 시스템이 자동 감지 → 처리 → 검색 가능 상태로 전환한다.
  3. 사용자는 웹 UI에서 질문하면 관련 지식을 근거와 함께 받는다.

MVP 범위 (In)

  • 디렉토리 감시 + 파이프라인 (inbox → processing → archive/failed)
  • 파일 유형: 1순위 .txt/.md, 2순위 .pdf, 3순위 .docx/.pptx (.xlsx/이미지/음성은 확장 단계)
  • LLM 자동 분류/요약/메타데이터 생성 (Ollama)
  • 청킹 + bge-m3 임베딩 + Teradata Vector Store 저장
  • 파일 해시 기반 중복 제거
  • 웹 UI: Chat / Documents / Inbox Monitor / Categories / Failed Files (실시간 상태)
  • RAG 채팅 (출처 인용 포함)

범위 외 (Out, 추후)

  • 이미지 OCR / 음성 STT, .xlsx 표 의미화
  • 멀티 사용자/권한, 클라우드 동기화
  • 모바일 앱

2. 기술 스택 (greenfield 결정)

영역 선택 근거
Backend API FastAPI (Python 3.11+) 비동기, 자동 OpenAPI 문서, 워커와 코드 공유
Watcher/Worker watchdog + 내부 큐(asyncio.Queue → 추후 Redis/RQ) 단순·안정, 단일 머신 MVP에 충분
LLM Ollama (예: qwen2.5, llama3.1) 로컬, 분류/요약/RAG 답변
Embedding bge-m3 (Ollama 또는 sentence-transformers) 다국어(한국어) 강함, 1024-dim
Vector Store / DB Teradata Vector Store 요구사항. 메타데이터·청크·벡터 통합 저장
문서 파싱 pypdf/pdfplumber, python-docx, python-pptx, markdown-it, trafilatura(html/url) 유형별 추출
Frontend Next.js 14 (App Router) + TypeScript SSR/스트리밍, 라우팅, DX
UI 시스템 Tailwind CSS + shadcn/ui + Radix + Framer Motion + lucide-react 세련된 현대적 UX, 접근성, 애니메이션
실시간 SSE (Server-Sent Events) Ingestion 상태/채팅 토큰 스트리밍
상태관리 TanStack Query + Zustand 서버 캐시 + 경량 클라 상태
패키지/런타임 uv(py) / pnpm(js), Docker Compose 재현 가능한 개발 환경

3. 전체 아키텍처

[Local Directory]              [Web UI - Next.js]
 /second-brain/inbox             Chat / Documents / Inbox Monitor
        │                              ▲   │
        ▼                              │SSE│ REST
[Directory Watcher (watchdog)]         │   ▼
        │ enqueue                 ┌──────────────┐
        ▼                         │  FastAPI App │
[Ingestion Queue]  ───────────────▶  REST + SSE  │
        │                         └──────┬───────┘
        ▼                                │
[Ingestion Worker]                       │ RAG 검색
  1 hash/중복체크                          │
  2 parse(추출)        ┌──────────────────┴──────────────┐
  3 LLM 분류/메타       │            Teradata             │
  4 chunk              │  SB_Document / SB_DocumentChunk  │
  5 embed(bge-m3)      │  SB_IngestionFile / Log          │
  6 save  ────────────▶│  SB_DocumentCategory / Vector    │
                       └─────────────────────────────────┘
        │
        ▼ 성공: archive / 실패: failed

상태 머신:

DETECTED → PROCESSING → COMPLETED
                     └→ FAILED (사유 기록)
DETECTED → DUPLICATED (해시 중복)
DETECTED → SKIPPED (미지원 확장자)

4. 프로젝트 구조

second-brain-agents/
├─ docs/
│  └─ IMPLEMENTATION_PLAN.md
├─ backend/
│  ├─ app/
│  │  ├─ main.py                # FastAPI 엔트리, 라우터 등록, 워커 기동
│  │  ├─ config.py              # 환경설정 (pydantic-settings)
│  │  ├─ db/
│  │  │  ├─ teradata.py         # 커넥션 풀, 세션
│  │  │  └─ ddl/                # 테이블 생성 SQL
│  │  ├─ ingestion/
│  │  │  ├─ watcher.py          # watchdog 핸들러
│  │  │  ├─ queue.py            # 인제스천 큐
│  │  │  ├─ worker.py           # 파이프라인 오케스트레이션
│  │  │  ├─ hashing.py          # SHA256
│  │  │  ├─ parsers/            # txt/md/pdf/docx/pptx/html
│  │  │  ├─ chunking.py
│  │  │  └─ pipeline.py         # process_file()
│  │  ├─ llm/
│  │  │  ├─ ollama_client.py
│  │  │  ├─ classifier.py       # 분류/메타데이터 프롬프트
│  │  │  └─ rag.py              # 검색+답변 생성
│  │  ├─ embeddings/
│  │  │  └─ bge_m3.py
│  │  ├─ repositories/          # SB_* CRUD
│  │  ├─ api/
│  │  │  ├─ documents.py
│  │  │  ├─ ingestion.py        # 모니터/재처리
│  │  │  ├─ categories.py
│  │  │  ├─ chat.py             # SSE 스트리밍
│  │  │  └─ events.py           # SSE 상태 피드
│  │  └─ schemas/               # pydantic 모델
│  ├─ tests/
│  ├─ pyproject.toml
│  └─ .env.example
├─ frontend/
│  ├─ app/
│  │  ├─ (dashboard)/
│  │  │  ├─ chat/page.tsx
│  │  │  ├─ documents/page.tsx
│  │  │  ├─ inbox/page.tsx
│  │  │  ├─ categories/page.tsx
│  │  │  └─ failed/page.tsx
│  │  ├─ layout.tsx
│  │  └─ globals.css
│  ├─ components/
│  │  ├─ ui/                    # shadcn 컴포넌트
│  │  ├─ chat/
│  │  ├─ ingestion/            # 상태 타임라인, 라이브 피드
│  │  └─ layout/               # Sidebar, CommandPalette, ThemeToggle
│  ├─ lib/                      # api client, sse hooks, query
│  └─ package.json
├─ second-brain/                # 감시 디렉토리 (gitignore)
│  ├─ inbox/  processing/  archive/  failed/  logs/
├─ docker-compose.yml           # teradata(or 외부), ollama, backend, frontend
└─ README.md

5. 데이터 모델 (Teradata)

기존 SB_Document, SB_DocumentChunk에 더해 자동 수집용 테이블 추가.

SB_IngestionFile (파일 단위 추적)

CREATE MULTISET TABLE SB_IngestionFile (
    FileId           BIGINT GENERATED ALWAYS AS IDENTITY,
    OriginalFileName VARCHAR(500)  CHARACTER SET UNICODE,
    FilePath         VARCHAR(1000) CHARACTER SET UNICODE,
    FileHash         VARCHAR(128)  CHARACTER SET UNICODE,
    FileExtension    VARCHAR(20)   CHARACTER SET UNICODE,
    FileSizeBytes    BIGINT,
    WatchDirectory   VARCHAR(1000) CHARACTER SET UNICODE,
    IngestionStatus  VARCHAR(30)   CHARACTER SET UNICODE,  -- DETECTED/PROCESSING/COMPLETED/FAILED/DUPLICATED/SKIPPED
    DetectedAt       TIMESTAMP(6),
    StartedAt        TIMESTAMP(6),
    CompletedAt      TIMESTAMP(6),
    ErrorMessage     VARCHAR(4000) CHARACTER SET UNICODE
) PRIMARY INDEX (FileId);
-- 중복 조회 최적화: FileHash 보조 인덱스

SB_DocumentCategory (계층형 분류)

CREATE MULTISET TABLE SB_DocumentCategory (
    CategoryId       INTEGER GENERATED ALWAYS AS IDENTITY,
    CategoryName     VARCHAR(200) CHARACTER SET UNICODE,
    ParentCategoryId INTEGER,
    Description      VARCHAR(1000) CHARACTER SET UNICODE,
    IsActive         BYTEINT DEFAULT 1
) PRIMARY INDEX (CategoryId);

시드: AI Architecture / Data Platform / Teradata / MCP / Second Brain / Customer Project / Technical Troubleshooting / Personal Notes / Meeting Notes / Research

SB_IngestionLog (단계별 로그 — 실패 원인 추적)

CREATE MULTISET TABLE SB_IngestionLog (
    LogId      BIGINT GENERATED ALWAYS AS IDENTITY,
    FileId     BIGINT,
    StepName   VARCHAR(100) CHARACTER SET UNICODE,   -- hash/parse/classify/chunk/embed/save
    StepStatus VARCHAR(30)  CHARACTER SET UNICODE,
    LogMessage VARCHAR(4000) CHARACTER SET UNICODE,
    CreatedAt  TIMESTAMP(6)
) PRIMARY INDEX (FileId);

SB_Document / SB_DocumentChunk (요지)

  • SB_Document: DocumentId, FileId(FK), Title, Category, SubCategory, Summary, Keywords(JSON), Entities(JSON), DocumentType, Importance, Language, Status, CreatedAt
  • SB_DocumentChunk: ChunkId, DocumentId(FK), ChunkIndex, ChunkText, Embedding(VECTOR/Float[]), TokenCount

6. 인제스천 파이프라인 (백엔드 핵심)

Watcher → Queue

  • watchdog on_created/on_moved 감지. 파일 쓰기 완료 안정성을 위해 폴링(크기 안정화) 또는 일정 시간 후 처리(예: 2s 후 mtime 재확인).
  • 감지 즉시 inbox → processing 이동, SB_IngestionFileDETECTED → PROCESSING 기록, 큐에 적재.
  • 미지원 확장자는 SKIPPED로 기록 후 통과.

process_file() 단계 (각 단계마다 SB_IngestionLog 기록)

def process_file(file_path):
    file_hash = calculate_file_hash(file_path)        # 1 SHA256
    if is_duplicate(file_hash):                       # 2 중복
        mark_as_duplicate(file_path); return
    text = extract_text(file_path)                    # 3 유형별 추출
    metadata = classify_with_llm(text)                # 4 분류/요약/메타
    chunks = split_into_chunks(text)                  # 5 청킹(겹침 포함)
    for i, chunk in enumerate(chunks):                # 6 임베딩+저장
        emb = create_embedding(chunk)                 #   bge-m3
        save_chunk_to_teradata(metadata, i, chunk, emb)
    finalize_document(metadata, status="indexed")
  • 성공 시 processing → archive, COMPLETED 기록.
  • 예외 시 processing → failed, FAILED + ErrorMessage 기록 (단계별 로그로 원인 특정).

LLM 분류 (classifier.py)

  • 프롬프트: "JSON만 반환" 강제 + format=json(Ollama) / 스키마 검증(pydantic) + 재시도.
  • 산출: title, category, sub_category, summary, keywords[], entities[], document_type, importance(1-5), language.
  • 긴 문서는 요약 후 분류(맵-리듀스) 또는 앞부분+목차 기반.

청킹 / 임베딩

  • 토큰 기준 분할(예: 512800 토큰, 1015% overlap), 코드/표 경계 보존.
  • bge-m3 1024-dim. 배치 임베딩으로 처리량 확보.

중복 처리

  • 파일 내용 SHA256 → SB_IngestionFile.FileHash 조회 → 존재 시 DUPLICATED.

7. API 설계 (FastAPI)

Method Path 설명
GET /api/ingestion/files 수집 파일 목록(상태/카테고리/시간 필터·페이징)
GET /api/ingestion/files/{id} 파일 상세 + 단계 로그
POST /api/ingestion/files/{id}/retry 실패 파일 재처리
GET /api/ingestion/stream SSE 실시간 상태 피드
GET /api/documents 문서 목록(검색/필터)
GET /api/documents/{id} 문서 상세 + 청크/메타
GET/POST/PATCH /api/categories 카테고리 관리
POST /api/chat SSE RAG 답변 토큰 스트리밍
GET /api/stats 대시보드 지표

8. UI/UX 설계 — 세련되고 현대적인 인터페이스

디자인 컨셉: "Calm, focused knowledge workspace" — Linear/Vercel/Raycast 류의 절제된 미니멀 + 다크 우선 + 정보 밀도 높은 데이터 화면 + 부드러운 마이크로 인터랙션.

8.1 디자인 시스템

  • 테마: 다크 우선 + 라이트 토글. CSS 변수 토큰(색/간격/반경/그림자). next-themes.
  • 컬러: 뉴트럴 그레이 베이스 + 단일 액센트(예: indigo/violet). 상태색 — COMPLETED(emerald), PROCESSING(amber, 펄스), FAILED(rose), DUPLICATED(slate), DETECTED(sky).
  • 타이포: Inter / Geist (UI), 본문 한글 Pretendard. 명확한 타입 스케일.
  • 표면: 은은한 글래스/보더(1px hairline) + 소프트 섀도. 과한 글래스모피즘 지양.
  • 모션: Framer Motion — 페이지 전환 fade/slide, 리스트 stagger, 상태 변경 시 layout 애니메이션. 200~300ms, ease-out. prefers-reduced-motion 존중.
  • 접근성: Radix 기반 키보드 내비/포커스 링/ARIA, 명도 대비 AA.

8.2 레이아웃 / 내비게이션

  • 좌측 사이드바(접이식): Chat / Documents / Inbox Monitor / Categories / Failed Files + 하단 상태 인디케이터("Watcher: ● live", 큐 N건).
  • 상단 바: 글로벌 검색, 테마 토글, 처리 중 카운트 배지.
  • ⌘K Command Palette: 문서 검색·페이지 이동·"실패 파일 재처리" 등 액션. Raycast 스타일.
  • 반응형: 데스크톱 우선, 태블릿까지 대응.

8.3 화면별 설계

① Chat (지식 질의응답)

  • 중앙 정렬 대화 캔버스, 토큰 스트리밍(타이핑 효과) + 스켈레톤.
  • 답변 하단 출처 카드(문서 제목/카테고리/관련 청크 발췌) → 클릭 시 문서 상세 슬라이드오버.
  • 입력창: 멀티라인, ⌘↵ 전송, 카테고리 필터 칩으로 검색 범위 좁히기.
  • 빈 상태: 추천 질문 칩, 최근 인덱싱 문서 미리보기.

② Documents (문서 목록)

  • 그리드/리스트 토글. 카드: 제목, 카테고리·서브카테고리 칩, 중요도(별), 요약 2줄, 키워드 태그, 언어 배지.
  • 좌측 패싯 필터(카테고리/유형/중요도/기간/언어) + 정렬. 디바운스 검색.
  • 카드 클릭 → 슬라이드오버 상세: 요약, 엔티티/키워드, 청크 뷰어, 원본 메타.

③ Inbox Monitor (자동 수집 상태) — 핵심 화면

  • 상단 KPI 카드: 오늘 수집 수, 처리 중, 완료, 실패율(스파크라인).
  • 라이브 피드: SSE로 상태가 실시간 갱신되는 테이블/타임라인.
    • 컬럼: 파일명 | 상태(컬러 배지+PROCESSING 펄스) | 카테고리 | 감지시간 | 처리시간 | 오류.
    • 새 항목 등장 시 하이라이트 후 페이드.
  • 단계 진행 표시: 행 확장 시 hash→parse→classify→chunk→embed→save 6단계 progress stepper(현재 단계 강조, 실패 단계 적색).
  • 예시:
    mcp_hub_note.md   ● COMPLETED  AI Architecture  08:31  2.3s   —
    sales_report.pdf  ● FAILED     —                08:35   —     PDF text extraction failed
    meeting.docx      ◐ PROCESSING Meeting Notes    08:36   …      embedding 3/8
    

④ Categories (자동 분류 결과 관리)

  • 좌: 계층 트리(드래그로 부모 변경, 활성/비활성 토글).
  • 우: 선택 카테고리의 문서 수·중요도 분포·최근 문서. 카테고리 분포 도넛/바 차트.

⑤ Failed Files (실패 파일 재처리)

  • 실패 목록 + 오류 메시지 + 마지막 실패 단계.
  • 재처리 버튼(단건/일괄), 재처리 시 낙관적 업데이트 + 진행 표시.
  • 오류 상세 모달: 단계별 로그 타임라인.

8.4 마이크로 인터랙션 / 디테일

  • 토스트 알림(수집 완료/실패), 스켈레톤 로딩, 낙관적 업데이트.
  • 숫자 카운트업 애니메이션(KPI), 상태 배지 펄스, 호버 시 카드 살짝 부상.
  • 빈 상태/에러 상태 일러스트와 명확한 다음 행동 제시.

9. 구현 로드맵 (마일스톤)

M0 — 환경 셋업 (0.5주)

  • 모노레포 스캐폴딩, Docker Compose(Ollama·backend·frontend), Teradata 연결, .env.

M1 — 데이터 계층 (0.5주)

  • DDL 적용(SB_* 테이블), 리포지토리 + 시드 카테고리, 연결 스모크 테스트.

M2 — 인제스천 파이프라인 코어 (1.5주)

  • watchdog watcher + 폴더 이동 흐름, 큐/워커, 해시·중복.
  • 파서(txt/md → pdf → docx/pptx), 청킹.
  • 단계별 로그 기록. CLI로 end-to-end 검증(파일 넣으면 archive까지).

M3 — LLM & 임베딩 (1주)

  • Ollama 분류기(JSON 강제+검증+재시도), bge-m3 임베딩, Teradata 청크/벡터 저장.
  • 벡터 검색 쿼리 + RAG 답변 파이프라인.

M4 — API & SSE (0.5주)

  • documents/ingestion/categories/chat 엔드포인트, SSE 상태/채팅 스트림.

M5 — 프론트엔드 (2주)

  • 디자인 시스템·레이아웃·⌘K → Inbox Monitor(라이브) → Chat(스트리밍+출처) → Documents → Categories → Failed Files.

M6 — 마감 (0.5주)

  • 에러 처리/리트라이/관측(로그·지표), 접근성·반응형 점검, README/운영 문서, 데모 시드.

대략 6.5~7주 (1인 기준, 순차). 병렬 시 단축.


10. 리스크 & 대응

리스크 대응
파일 쓰기 미완료 상태 감지 크기/mtime 안정화 폴링 후 처리
LLM JSON 비정형 응답 format=json + pydantic 검증 + 재시도/폴백 기본값
대용량 문서 분류 비용 요약 후 분류(맵-리듀스), 토큰 상한
Teradata 벡터 검색 성능 인덱싱/배치 임베딩, 청크 크기 튜닝
워커 단일 장애 상태 기반 복구(PROCESSING 잔여 재큐), 추후 Redis/RQ 멀티 워커
중복/재처리 정합성 해시 유니크 + 재처리 시 기존 문서/청크 정리 후 재생성

11. 확장 로드맵

  • 이미지 OCR / 음성 STT, .xlsx 표 의미화, .url 크롤링 강화
  • 하이브리드 검색(키워드+벡터), 재랭킹
  • 멀티 워커 큐(Redis/RQ/Celery), 알림(Slack/메일)
  • 지식 그래프(엔티티 관계), 자동 태깅 피드백 루프