Files
ai-server/README.md
Hyungi Ahn e102ce6db9 feat: AI 서버 관리 페이지 Phase 1 구현
- 웹 기반 관리 대시보드 추가 (/admin)
- 시스템 상태 모니터링 (AI 서버, Ollama, 활성 모델, API 호출)
- 모델 관리 기능 (목록 조회, 테스트, 새로고침)
- API 키 관리 시스템 (생성, 조회, 삭제)
- 반응형 UI/UX 디자인 (모바일 지원)
- 테스트 모드 서버 (test_admin.py) 추가
- 보안: API 키 기반 인증, 키 마스킹
- 실시간 업데이트 (30초 자동 새로고침)

구현 파일:
- templates/admin.html: 관리 페이지 HTML
- static/admin.css: 관리 페이지 스타일
- static/admin.js: 관리 페이지 JavaScript
- server/main.py: 관리 API 엔드포인트 추가
- test_admin.py: 맥북프로 테스트용 서버
- README.md: 관리 페이지 문서 업데이트
2025-08-18 13:33:39 +09:00

374 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
### 로컬 AI 서버 (Mac mini M4 Pro 64GB)
이 저장소는 Apple Silicon(M4 Pro, RAM 64GB) 환경에서 로컬 AI 모델을 실행해 API 서버로 활용하기 위한 기본 구성과 가이드를 제공합니다.
## 현재 설치 상태
- **러너**: Ollama 0.11.4 확인됨
- **Ollama 로컬 모델**:
- qwen2.5:1.5b
- mistral:7b
- **LM Studio 로컬 모델**:
- gemma-3-4b-it
## 하드웨어 요약 (권장 기준)
- **칩셋**: Apple M4 Pro (Metal/ANE 가속 활용 가능)
- **메모리**: 64GB 통합 메모리
- **권장 동시성**: 13 세션(프롬프트 길이에 따라 조절)
## 권장 모델 (M4 Pro 64GB)
- **일반 대화/업무**
- Llama 3.1 8B Instruct: 품질·속도 밸런스 좋음, 긴 문서 요약/대화에 적합
- Qwen2.5 7B Instruct: 정보 회수/한글 대응 우수, 속도 양호
- Mistral 7B Instruct: 경량/속도 지향, 기본 품질 안정적
- Gemma 2 9B IT: 간결한 답변과 대화 품질 균형
- **코딩 보조**
- Qwen2.5-Coder 7B: 코드 생성/수정/해설에 실용적, 메모리 요구도 낮음
- DeepSeek-Coder 6.7B 또는 16B(Lite): 코드 품질 강점, 16B는 속도·메모리 여유 필요
- **초경량**
- Phi-3.5/3.1 Mini(34B): 간단 질의응답/요약, 서버 부하가 낮음
- 참고: 1432B급도 구동 가능하나(예: Qwen2.5 14B/32B), 긴 컨텍스트/동시성 시 메모리 여유가 적어질 수 있음. 70B급은 64GB 환경에서 가능하더라도 속도·안정성 상 비권장.
## 설치 (Ollama)
아래 명령으로 권장 모델을 내려받을 수 있습니다. 태그는 상황에 따라 업데이트될 수 있으니 `ollama run <model>` 시 안내를 확인하세요.
```bash
# 일반 대화
ollama pull llama3.1:8b-instruct
ollama pull qwen2.5:7b-instruct
ollama pull mistral:7b
ollama pull gemma2:9b-instruct
# 코딩 보조
ollama pull qwen2.5-coder:7b
ollama pull deepseek-coder:6.7b
# 초경량
ollama pull phi3:mini
```
이미 설치된 모델 확인:
```bash
ollama list
```
모델 실행(대화형 테스트):
```bash
ollama run qwen2.5:7b-instruct
```
## REST API로 바로 쓰기 (Ollama 내장 서버)
Ollama는 기본적으로 `http://localhost:11434`에서 API를 제공합니다.
```bash
# 단발성 텍스트 생성
curl http://localhost:11434/api/generate \
-H "Content-Type: application/json" \
-d '{
"model": "qwen2.5:7b-instruct",
"prompt": "한국어로 이 모델의 장점을 3가지로 요약해줘",
"stream": false
}'
# Chat 형식
curl http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
"model": "llama3.1:8b-instruct",
"messages": [
{"role": "user", "content": "로컬 LLM 서버 운영 팁을 알려줘"}
],
"stream": false
}'
```
TIP: 긴 문서를 다루려면 `num_ctx`(컨텍스트 길이)와 `num_thread`를 모델/하드웨어에 맞춰 조정하세요. 과도하게 늘리면 속도와 메모리 사용량이 크게 증가합니다.
## 포트 정책
- **AI 서버 표준 포트**: 26000 이상 사용 권장 (예: 26000)
- 환경 변수 `AI_SERVER_PORT`로 조정 가능. 기본값 26000.
개발 서버 실행 스크립트(`scripts/dev_server.sh`)는 위 정책을 따릅니다.
## 레포지토리/데이터 정책
- **커밋 제외**: 문서 원본(PDF 등)과 런타임 산출물(추출 텍스트/인덱스)은 저장소에 커밋하지 않습니다.
- `.gitignore`: `data/`, `*.pdf` 적용됨
- **재현 방법(로컬에서 데이터 생성)**:
- PDF → 텍스트/토큰 산출: `scripts/venv_setup.sh``source .venv/bin/activate``python scripts/pdf_stats.py`
- 텍스트 임베딩/인덱스 생성: Ollama 실행 후 `python scripts/embed_ollama.py`
- 서버 기동: `scripts/dev_server.sh` (기본 포트 26000)
## 운영 워크플로(요약)
- **모델 정책(24/7 + 부스팅)**
- 기본 상시: `BASE_MODEL`(권장: `qwen2.5:7b-instruct` 또는 `llama3.1:8b-instruct`)
- 필요 시 부스팅: `BOOST_MODEL`(권장: `qwen2.5:14b-instruct`)으로 자동/강제 전환
- 장문은 32k 컨텍스트 + RAG(인덱스 Top-k 주입)로 처리
- **Paperless 연동**
- 문서 처리 완료 시(웹훅/잡) → 본문 텍스트 추출 → `/index/upsert`로 인덱스 갱신
- 선택적으로 `/paperless/hook`에 문서 ID를 통지 후 서버가 Paperless API로 조회하도록 확장 가능
- **시놀로지 메일/오피스 연동**
- 본문/첨부 텍스트를 `/index/upsert`로 누적(사전 색인)
- 사용자 질의는 `/chat` 호출(`use_rag=true`, 필요 시 `force_boost=true`)
- 자동 라우팅 규칙(기본):
- 영어 비율이 높으면 `ENGLISH_MODEL`(기본 `llama3:8b-instruct`)
- 그 외는 길이/강제 부스팅 기준으로 `BASE_MODEL`(7B) 또는 `BOOST_MODEL`(14B)
## API 개요(요약)
- 헬스: `GET /health`
- 검색: `POST /search` `{ query, top_k }`
- 챗: `POST /chat` `{ messages, use_rag, top_k, force_boost, options }`
- 인덱스 업서트: `POST /index/upsert` `{ rows:[{id,text,source}], embed }`
- 인덱스 리로드: `POST /index/reload`
- Paperless 훅 자리표시자: `POST /paperless/hook`
## API 개요 (Paperless/시놀로지 연동)
- 기본 베이스 모델(24/7): `BASE_MODEL` (기본: `qwen2.5:7b-instruct`)
- 온디맨드 부스팅 모델: `BOOST_MODEL` (기본: `qwen2.5:14b-instruct`)
- 임베딩(RAG): `EMBEDDING_MODEL` (기본: `nomic-embed-text`), 인덱스 파일 `INDEX_PATH` (기본: `data/index.jsonl`)
- 문서화: `http://localhost:26000/docs` (FastAPI 자동 문서)
### 헬스체크
```bash
curl -s http://localhost:26000/health
```
### 검색(Search, RAG용)
```bash
curl -s -X POST http://localhost:26000/search \
-H 'Content-Type: application/json' \
-d '{
"query": "질문 내용",
"top_k": 5
}'
```
### 채팅(Chat, RAG/부스팅 자동)
```bash
curl -s -X POST http://localhost:26000/chat \
-H 'Content-Type: application/json' \
-d '{
"messages": [
{"role": "user", "content": "문서 내용 기반으로 요약해줘"}
],
"use_rag": true,
"top_k": 5,
"force_boost": false,
"options": {"num_ctx": 32768, "temperature": 0.3}
}'
```
필드 설명:
- `use_rag`: 인덱스(`INDEX_PATH`)에서 상위 청크를 검색해 시스템 프롬프트로 주입
- `force_boost`: 강제로 부스팅 모델 사용(고난도/장문)
- `options`: Ollama 옵션(예: `num_ctx`, `temperature` 등)
### 인덱스 갱신(Upsert)
Paperless/시놀로지에서 추출한 본문 텍스트를 직접 인덱스에 추가합니다.
```bash
curl -s -X POST http://localhost:26000/index/upsert \
-H 'Content-Type: application/json' \
-d '{
"rows": [
{"id": "paperless:123", "text": "문서 본문 텍스트", "source": "paperless"}
],
"embed": true
}'
```
### 인덱스 리로드
```bash
curl -s -X POST http://localhost:26000/index/reload
```
### Paperless 훅(Webhook) 자리표시자
```bash
curl -s -X POST http://localhost:26000/paperless/hook \
-H 'Content-Type: application/json' \
-d '{"document_id": 123, "title": "문서제목", "tags": ["finance"]}'
```
해당 훅은 문서 도착을 통지받는 용도로 제공됩니다. 실제 본문 텍스트는 Paperless API로 조회해 `/index/upsert`로 추가하세요.
### Paperless 배치 동기화(`/paperless/sync`)
### 문서 파이프라인(`/pipeline/ingest`)
첨부 문서(텍스트가 준비된 상태: OCR/추출 선행) → (옵션)요약 → (옵션)번역 → 임베딩 → HTML 생성까지 처리합니다.
```bash
curl -s -X POST http://localhost:26000/pipeline/ingest \
-H 'Content-Type: application/json' -H 'X-API-Key: <키>' \
-d '{
"doc_id": "doc-2025-08-13-001",
"text": "(여기에 문서 텍스트)",
"generate_html": true,
"translate": true,
"target_language": "ko",
"summarize": false,
"summary_sentences": 5,
"summary_language": null
}'
```
응답에 `html_path`가 포함됩니다.
- 요약 켜짐(`summarize=true`): 청크별 요약 후 통합 요약을 생성해 사용(기본 5문장). `summary_language`로 요약 언어 선택 가능(기본 번역 언어와 동일, 번역 off면 ko).
- 번역 켜짐(`translate=true`): 최종 텍스트를 대상 언어로 번역해 HTML+인덱스화.
- 번역 꺼짐(`translate=false`): 최종 텍스트(요약 또는 원문)로 HTML+인덱스화.
파일 업로드 버전(`/pipeline/ingest_file`): `.txt`/`.pdf` 지원
```bash
curl -s -X POST http://localhost:26000/pipeline/ingest_file \
-H 'X-API-Key: <키>' \
-F 'file=@/path/to/file.pdf' \
-F 'doc_id=doc-001' \
-F 'generate_html=true' \
-F 'translate=false' \
-F 'target_language=ko'
```
Paperless에서 다수 문서를 일괄 인덱싱합니다.
```bash
curl -s -X POST http://localhost:26000/paperless/sync \
-H 'Content-Type: application/json' -H 'X-API-Key: <키>' \
-d '{
"page_size": 50,
"ordering": "-created",
"tags": null,
"query": null,
"limit": 200
}'
```
## 시놀로지 메일/오피스 연동 가이드(요약)
- **검색/QA 호출 엔드포인트**: `http://<AI서버IP>:26000/search`, `http://<AI서버IP>:26000/chat`
- **권장 흐름**:
- 메일/문서 본문 → `/index/upsert`로 인덱스 추가(임베딩 생성)
- 사용자 질의 → `/chat` 호출(`use_rag=true`) → 관련 청크 Top-k 주입 후 응답
- **모델 라우팅**:
- 기본: 베이스 모델(7B/8B)
- 장문/고난도: `force_boost=true` 또는 메시지 길이에 따라 자동 부스팅(14B)
## 환경 변수
- `AI_SERVER_PORT`(기본 26000): 서버 포트
- `OLLAMA_HOST`(기본 `http://localhost:11434`): Ollama API 호스트
- `BASE_MODEL`(기본 `qwen2.5:7b-instruct`)
- `BOOST_MODEL`(기본 `qwen2.5:14b-instruct`)
- `ENGLISH_MODEL`(기본 `llama3:8b-instruct`): 영어 감지 시 라우팅 대상
- `ENGLISH_RATIO_THRESHOLD`(기본 `0.65`): 영어 비율 임계값(초과 시 영어 모델)
- `EMBEDDING_MODEL`(기본 `nomic-embed-text`)
- `INDEX_PATH`(기본 `data/index.jsonl`)
- `PAPERLESS_BASE_URL`, `PAPERLESS_TOKEN`(선택): Paperless API 연동 시 사용
- `PAPERLESS_VERIFY_SSL`(기본 `true`): Paperless HTTPS 검증 비활성화는 `false`
- `PAPERLESS_CA_BUNDLE`(선택): 신뢰할 CA 번들 경로 지정 시 해당 번들로 검증
- `OUTPUT_DIR`(기본 `outputs`): 파이프라인 산출물(HTML) 저장 루트
- `EXPORT_HTML_DIR`(선택): HTML 산출물 사본을 내보낼 디렉터리(예: 시놀로지 공유 폴더)
- `EXPORT_UPLOAD_DIR`(선택): 업로드 원본 파일 보관 디렉터리
- `API_KEY`(선택): 설정 시 모든 민감 엔드포인트 호출에 `X-API-Key` 헤더 필요
- `CORS_ORIGINS`(선택): CORS 허용 오리진(쉼표 구분), 미설정 시 `*`
`.env` 예시:
```bash
AI_SERVER_PORT=26000
OLLAMA_HOST=http://localhost:11434
BASE_MODEL=qwen2.5:7b-instruct
BOOST_MODEL=qwen2.5:14b-instruct
EMBEDDING_MODEL=nomic-embed-text
INDEX_PATH=data/index.jsonl
API_KEY=changeme
CORS_ORIGINS=http://localhost:5173,http://synology.local
```
OpenAI 호환 호출 예시:
```bash
curl -s -X POST http://localhost:26000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "X-API-Key: changeme" \
-d '{
"model":"qwen2.5:14b-instruct",
"messages":[{"role":"user","content":"이 서버 기능을 한 줄로 설명"}],
"temperature":0.3
}'
```
## AI 서버 관리 페이지 (Admin Dashboard)
AI 서버의 효율적인 관리를 위한 웹 기반 관리 페이지를 제공합니다.
### 관리 페이지 접근
- **URL**: `http://localhost:26000/admin`
- **인증**: API 키 기반 (환경변수 `API_KEY` 설정 필요)
### 주요 기능
#### Phase 1: 기본 관리 기능 ✅
- **시스템 상태 대시보드**: 서버/Ollama/모델 상태 실시간 모니터링
- **모델 관리**: 설치된 모델 목록, 활성 모델 현황, 모델별 사용 통계
- **API 키 관리**: 키 생성/조회/삭제, 사용량 모니터링
#### Phase 2: 고급 기능 (계획)
- **모델 다운로드/삭제**: Ollama 모델 원격 관리
- **실시간 모니터링**: CPU/메모리/GPU 사용률, API 호출 통계
- **설정 관리**: 환경변수 편집, Paperless 연동 설정
#### Phase 3: 보안 강화 (계획)
- **인증 시스템**: JWT 기반 로그인, 2FA 지원
- **접근 제어**: IP 화이트리스트, 권한 관리
- **감사 로그**: 모든 관리 작업 기록 및 추적
### 보안 고려사항
- **API 키 암호화**: AES-256 암호화 저장
- **HTTPS 강제**: SSL/TLS 인증서 필수
- **접근 로그**: 모든 관리 페이지 접근 기록
- **민감 정보 보호**: 로그에서 API 키 자동 마스킹
### 사용 예시
```bash
# API 키 설정
export API_KEY=your-secure-api-key
# 서버 실행
python -m server.main
# 관리 페이지 접근
curl -H "X-API-Key: your-secure-api-key" http://localhost:26000/admin
```
## 이 저장소 사용 계획
1) ✅ Ollama API를 감싸는 경량 서버(FastAPI) 구현 완료
2) ✅ 표준화된 엔드포인트(`/v1/chat/completions`, `/v1/completions`) 제공
3) ✅ 헬스체크/모델 선택/리밋/로깅 옵션 제공
4) 🚧 웹 기반 관리 페이지 구현 중 (Phase 1)
우선 본 문서로 설치/선택 가이드를 정리했으며, 현재 관리 페이지와 고급 기능들을 단계적으로 추가하고 있습니다.