Deploy: GitHub submodule sync 2026-07-23 12:46:52
This commit is contained in:
+11
-8
@@ -1,7 +1,7 @@
|
||||
# 로컬 개발 — exdev AI 연동
|
||||
|
||||
로컬에서 **chatbotApi · chatbotApp · exAiChatBot · kakaoChatbotSkill · Qdrant · MongoDB** 를 실행하고,
|
||||
**LLM / Embedding / Reranker** 만 `chatbot.exdev.co.kr` Mac Studio 호스트 AI를 SSH 터널로 사용합니다.
|
||||
로컬에서 **chatbotApi · chatbotApp · exAiChatBot · kakaoChatbotSkill** 을 실행하고,
|
||||
**LLM / Embedding / Reranker** 는 SSH 터널로, **MongoDB / Qdrant** 는 `stock.exdev.co.kr` 원격 인스턴스를 사용합니다.
|
||||
|
||||
## exdev AI 구조
|
||||
|
||||
@@ -26,11 +26,12 @@ chmod +x local-dev/*.sh
|
||||
./local-dev/start-all.sh --skip-java # Docker(RAG + chatbotApp)만
|
||||
./local-dev/start-all.sh --no-build # RAG 이미지 빌드 생략
|
||||
|
||||
./local-dev/stop-all.sh --mongo --tunnel # Mongo·SSH 터널까지 종료
|
||||
./local-dev/stop-all.sh --tunnel # SSH 터널까지 종료
|
||||
```
|
||||
|
||||
- RAG는 **`docker-compose.local.yml`** 사용 (Mac Docker `:28012` 포트 바인딩)
|
||||
- Qdrant 호스트 포트 **`6335`** (다른 프로젝트 `:6333` 과 충돌 방지)
|
||||
- Mongo: `stock.exdev.co.kr:27017` / Qdrant: `http://stock.exdev.co.kr:6333/dashboard`
|
||||
- 로컬 Mongo·Qdrant 컨테이너는 기동하지 않습니다
|
||||
|
||||
기동 후 UI: `http://localhost:8089/chatbot/app/`
|
||||
|
||||
@@ -66,17 +67,19 @@ curl -s -X POST http://127.0.0.1:16002/rerank \
|
||||
|
||||
```bash
|
||||
cp local-dev/env.exdev-ai.template exAiChatBot-chatbot2.0-agent/.env
|
||||
cd exAiChatBot-chatbot2.0-agent
|
||||
docker compose -f docker-compose-slim.yml up -d
|
||||
curl -s http://localhost:28012/health
|
||||
./local-dev/start-all.sh --skip-java --no-build # RAG만 (원격 Mongo/Qdrant)
|
||||
curl -s http://127.0.0.1:28012/health
|
||||
```
|
||||
|
||||
RAG 컨테이너는 `.env` 의 `MONGO_HOST` / `QDRANT_HOST` (= `stock.exdev.co.kr`) 로 원격 DB에 접속합니다.
|
||||
|
||||
## 4. Java 서비스 + chatbotApp
|
||||
|
||||
```bash
|
||||
# WAS
|
||||
# WAS (Mongo → stock.exdev.co.kr)
|
||||
cd chatbotApi-chatbot2.0-agent
|
||||
export INTERNAL_TOOL_API_KEY=local-dev-key
|
||||
export MONGODB_URI='mongodb://exDev:ehfhrhdtk!!@stock.exdev.co.kr:27017/chatbot?authSource=chatbot'
|
||||
export SKILL_INTERNAL_BASE_URL=http://127.0.0.1:8083
|
||||
./gradlew bootRun
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# 로컬 Mac 개발용 (start-all.sh / stop-all.sh)
|
||||
# - network_mode:host 미사용 → :28012 / :28013 호스트 바인딩
|
||||
# - Mongo / Qdrant 는 stock.exdev.co.kr (로컬 컨테이너 미기동)
|
||||
# - AI 는 host.docker.internal 경유 SSH 터널 (.env)
|
||||
name: exchatbot-local
|
||||
|
||||
services:
|
||||
api:
|
||||
image: ${RAG_API_IMAGE:-rag-api-slim:latest}
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/service-slim.Dockerfile
|
||||
ports:
|
||||
- "${RAG_API_PORT:-28012}:28012"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
UVICORN_WORKERS: "${UVICORN_WORKERS:-2}"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./scripts:/app/scripts
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-sf", "http://localhost:28012/health"]
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 12
|
||||
start_period: 45s
|
||||
|
||||
admin:
|
||||
image: ${RAG_API_IMAGE:-rag-api-slim:latest}
|
||||
ports:
|
||||
- "${ADMIN_PORT:-28013}:28013"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
command:
|
||||
- python
|
||||
- -m
|
||||
- uvicorn
|
||||
- scripts.admin_service:app
|
||||
- --host
|
||||
- 0.0.0.0
|
||||
- --port
|
||||
- "28013"
|
||||
working_dir: /app
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./scripts:/app/scripts
|
||||
restart: unless-stopped
|
||||
@@ -27,9 +27,9 @@ API_TIMEOUT=120
|
||||
# 게이트웨이 키 불필요 (exdev 호스트 AI는 Bearer 없음)
|
||||
MODEL_API_KEY=
|
||||
|
||||
# ── 로컬 MongoDB / Qdrant ──
|
||||
# start-all.sh(docker-compose.local.yml) 사용 시 컨테이너→호스트는 host.docker.internal
|
||||
MONGO_HOST=host.docker.internal
|
||||
# ── exdev MongoDB / Qdrant (stock.exdev.co.kr, 로컬 미기동) ──
|
||||
EXDEV_DATA_HOST=stock.exdev.co.kr
|
||||
MONGO_HOST=stock.exdev.co.kr
|
||||
MONGO_PORT=27017
|
||||
MONGO_USER=
|
||||
MONGO_PASSWORD=
|
||||
@@ -37,10 +37,15 @@ MONGO_DATABASE=chat_history
|
||||
MONGO_COLLECTION=rag_conversations
|
||||
|
||||
VECTOR_STORE=qdrant
|
||||
QDRANT_HOST=127.0.0.1
|
||||
QDRANT_HOST=stock.exdev.co.kr
|
||||
QDRANT_PORT=6333
|
||||
# stock.exdev.co.kr 운영 컬렉션 (8488 vectors, 2026-07)
|
||||
QDRANT_COLLECTION=qa_vectors
|
||||
|
||||
# chatbotApi (WAS) — stock MongoDB chatbot DB
|
||||
MONGODB_URI=mongodb://exDev:ehfhrhdtk!!@stock.exdev.co.kr:27017/chatbot?authSource=chatbot&heartbeatFrequencyMS=30000&minPoolSize=3&maxIdleTimeMS=1800000
|
||||
|
||||
|
||||
# ── 로컬 WAS / Skill 연동 ──
|
||||
CHATBOT_API_BASE_URL=http://127.0.0.1:8086/api
|
||||
INTERNAL_TOOL_API_KEY=local-dev-key
|
||||
|
||||
+46
-36
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# 로컬 전체 스택 기동 (exdev AI SSH 터널 + Mongo + RAG + WAS + Skill + chatbotApp)
|
||||
# 로컬 전체 스택 기동 (exdev AI SSH 터널 + 원격 Mongo/Qdrant + RAG + WAS + Skill + chatbotApp)
|
||||
# Mongo/Qdrant 는 stock.exdev.co.kr 를 사용 (로컬 컨테이너 미기동)
|
||||
#
|
||||
# ./local-dev/start-all.sh
|
||||
# ./local-dev/start-all.sh --no-tunnel
|
||||
@@ -23,8 +24,9 @@ ENV_TEMPLATE="${LOCAL_DEV_DIR}/env.exdev-ai.template"
|
||||
RAG_ENV="${RAG_DIR}/.env"
|
||||
COMPOSE_LOCAL="${RAG_DIR}/docker-compose.local.yml"
|
||||
|
||||
MONGO_CONTAINER="${MONGO_CONTAINER:-ex-chatbot-mongo-local}"
|
||||
EXDEV_DATA_HOST="${EXDEV_DATA_HOST:-stock.exdev.co.kr}"
|
||||
INTERNAL_TOOL_API_KEY="${INTERNAL_TOOL_API_KEY:-local-dev-key}"
|
||||
MONGODB_URI="${MONGODB_URI:-mongodb://exDev:ehfhrhdtk!!@${EXDEV_DATA_HOST}:27017/chatbot?authSource=chatbot&heartbeatFrequencyMS=30000&minPoolSize=3&maxIdleTimeMS=1800000}"
|
||||
|
||||
LLM_PORT="${LLM_PORT:-16000}"
|
||||
EMBED_PORT="${EMBED_PORT:-16001}"
|
||||
@@ -34,18 +36,21 @@ ADMIN_PORT="${ADMIN_PORT:-28013}"
|
||||
WAS_PORT="${CHATBOT_API_PORT:-8086}"
|
||||
SKILL_PORT="${KAKAO_SKILL_PORT:-8083}"
|
||||
APP_PORT="${CHATBOT_APP_PORT:-8089}"
|
||||
MONGO_PORT="${MONGO_PORT:-27017}"
|
||||
QDRANT_PORT="${QDRANT_PORT:-6333}"
|
||||
|
||||
SKIP_TUNNEL=false
|
||||
SKIP_JAVA=false
|
||||
NO_BUILD=false
|
||||
SYNC_QDRANT=false
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--no-tunnel) SKIP_TUNNEL=true ;;
|
||||
--skip-java) SKIP_JAVA=true ;;
|
||||
--no-build) NO_BUILD=true ;;
|
||||
--sync-qdrant) SYNC_QDRANT=true ;;
|
||||
--sync-qdrant)
|
||||
echo "경고: 원격 Qdrant 사용 중이라 --sync-qdrant 는 무시됩니다."
|
||||
;;
|
||||
-h|--help)
|
||||
sed -n '2,12p' "$0"
|
||||
exit 0
|
||||
@@ -148,43 +153,52 @@ ensure_rag_env() {
|
||||
cp "${ENV_TEMPLATE}" "${RAG_ENV}"
|
||||
fi
|
||||
|
||||
# Docker 컨테이너 → Mac 호스트 접근
|
||||
# Docker 컨테이너 → Mac 호스트(SSH 터널) 접근
|
||||
patch_env "LLM_BASE_URL" "http://host.docker.internal:${LLM_PORT}"
|
||||
patch_env "TEI_EMBED_URL" "http://host.docker.internal:${EMBED_PORT}"
|
||||
patch_env "TEI_RERANK_URL" "http://host.docker.internal:${RERANK_PORT}"
|
||||
patch_env "EMBED_API_STYLE" "tei"
|
||||
patch_env "RERANK_API_STYLE" "legacy"
|
||||
patch_env "MONGO_HOST" "host.docker.internal"
|
||||
patch_env "CHATBOT_API_BASE_URL" "http://host.docker.internal:${WAS_PORT}/api"
|
||||
patch_env "INTERNAL_TOOL_API_KEY" "${INTERNAL_TOOL_API_KEY}"
|
||||
|
||||
# 로컬 Mongo 무인증
|
||||
# Mongo / Qdrant → stock.exdev.co.kr (원격)
|
||||
patch_env "EXDEV_DATA_HOST" "${EXDEV_DATA_HOST}"
|
||||
patch_env "MONGO_HOST" "${EXDEV_DATA_HOST}"
|
||||
patch_env "MONGO_PORT" "${MONGO_PORT}"
|
||||
patch_env "MONGO_USER" ""
|
||||
patch_env "MONGO_PASSWORD" ""
|
||||
patch_env "MONGO_DATABASE" "chat_history"
|
||||
patch_env "QDRANT_HOST" "${EXDEV_DATA_HOST}"
|
||||
patch_env "QDRANT_PORT" "${QDRANT_PORT}"
|
||||
patch_env "QDRANT_COLLECTION" "qa_vectors"
|
||||
}
|
||||
|
||||
ensure_mongo() {
|
||||
if docker ps --format '{{.Names}}' | grep -qx "${MONGO_CONTAINER}"; then
|
||||
docker start "${MONGO_CONTAINER}" >/dev/null 2>&1 || true
|
||||
log "MongoDB 재사용: ${MONGO_CONTAINER}"
|
||||
wait_port 27017 "MongoDB" 20 || true
|
||||
return 0
|
||||
fi
|
||||
ensure_remote_data() {
|
||||
log "원격 데이터 확인: ${EXDEV_DATA_HOST} (Mongo :${MONGO_PORT}, Qdrant :${QDRANT_PORT})"
|
||||
|
||||
if lsof -iTCP:27017 -sTCP:LISTEN >/dev/null 2>&1; then
|
||||
log "MongoDB :27017 이미 사용 중 (외부 인스턴스)"
|
||||
return 0
|
||||
if ! curl -sf --max-time 5 "http://${EXDEV_DATA_HOST}:${QDRANT_PORT}/collections" >/dev/null 2>&1; then
|
||||
fail "원격 Qdrant 접속 실패 — http://${EXDEV_DATA_HOST}:${QDRANT_PORT}"
|
||||
fi
|
||||
log "✅ 원격 Qdrant (${EXDEV_DATA_HOST}:${QDRANT_PORT})"
|
||||
|
||||
log "MongoDB 컨테이너 생성: ${MONGO_CONTAINER}"
|
||||
docker run -d --name "${MONGO_CONTAINER}" \
|
||||
-p 27017:27017 \
|
||||
mongo:7 >/dev/null
|
||||
wait_port 27017 "MongoDB" 30 || true
|
||||
if command -v nc >/dev/null 2>&1; then
|
||||
if ! nc -z -w 5 "${EXDEV_DATA_HOST}" "${MONGO_PORT}" >/dev/null 2>&1; then
|
||||
fail "원격 MongoDB 접속 실패 — ${EXDEV_DATA_HOST}:${MONGO_PORT}"
|
||||
fi
|
||||
fi
|
||||
log "✅ 원격 MongoDB (${EXDEV_DATA_HOST}:${MONGO_PORT})"
|
||||
}
|
||||
|
||||
ensure_rag_compose() {
|
||||
local template="${LOCAL_DEV_DIR}/docker-compose.rag.local.yml"
|
||||
[[ -f "${template}" ]] || fail "local-dev/docker-compose.rag.local.yml 없음"
|
||||
cp "${template}" "${COMPOSE_LOCAL}"
|
||||
}
|
||||
|
||||
start_rag() {
|
||||
ensure_rag_env
|
||||
ensure_rag_compose
|
||||
[[ -f "${COMPOSE_LOCAL}" ]] || fail "docker-compose.local.yml 없음"
|
||||
|
||||
cd "${RAG_DIR}"
|
||||
@@ -199,23 +213,17 @@ start_rag() {
|
||||
# 이전 slim/legacy 잔여 정리
|
||||
docker compose -f docker-compose-slim.yml down --remove-orphans 2>/dev/null || true
|
||||
|
||||
log "RAG 스택 기동 (docker-compose.local.yml)..."
|
||||
# 로컬 Qdrant 잔여 컨테이너 정리 (원격 사용)
|
||||
docker compose -f docker-compose.local.yml stop qdrant 2>/dev/null || true
|
||||
docker compose -f docker-compose.local.yml rm -f qdrant 2>/dev/null || true
|
||||
|
||||
log "RAG 스택 기동 (docker-compose.local.yml, 원격 Mongo/Qdrant)..."
|
||||
docker compose -f docker-compose.local.yml up "${up_flags[@]}"
|
||||
|
||||
wait_http "http://127.0.0.1:6335/readyz" "Qdrant" 30 || \
|
||||
wait_http "http://127.0.0.1:6335/collections" "Qdrant" 30 || true
|
||||
wait_http "http://${EXDEV_DATA_HOST}:${QDRANT_PORT}/collections" "원격 Qdrant" 30 || true
|
||||
wait_http "http://127.0.0.1:${RAG_PORT}/health" "RAG API" 120
|
||||
wait_http "http://127.0.0.1:${ADMIN_PORT}/api/stats" "Vector Admin" 60 || \
|
||||
wait_port "${ADMIN_PORT}" "Vector Admin" 30 || true
|
||||
|
||||
local vc
|
||||
vc="$(curl -sf "http://127.0.0.1:${RAG_PORT}/health" 2>/dev/null \
|
||||
| python3 -c "import sys,json; print(json.load(sys.stdin).get('vector_count',0))" 2>/dev/null || echo 0)"
|
||||
if $SYNC_QDRANT || [[ "${vc}" == "0" ]]; then
|
||||
log "Qdrant 데이터 exdev 동기화 (vector_count=${vc})..."
|
||||
chmod +x "${LOCAL_DEV_DIR}/sync-qdrant-from-exdev.sh"
|
||||
"${LOCAL_DEV_DIR}/sync-qdrant-from-exdev.sh" || log "⚠️ Qdrant 동기화 실패 — 수동: ./local-dev/sync-qdrant-from-exdev.sh"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_java() {
|
||||
@@ -305,7 +313,7 @@ else
|
||||
ai_tunnel_ready || fail "--no-tunnel 이지만 :${LLM_PORT}~:${RERANK_PORT} AI 미응답"
|
||||
fi
|
||||
|
||||
ensure_mongo
|
||||
ensure_remote_data
|
||||
start_rag
|
||||
|
||||
if ! $SKIP_JAVA; then
|
||||
@@ -313,6 +321,7 @@ if ! $SKIP_JAVA; then
|
||||
start_java_service "chatbotApi" "${API_DIR}" \
|
||||
"${RUN_DIR}/chatbot-api.pid" "${LOG_DIR}/chatbot-api.log" \
|
||||
"INTERNAL_TOOL_API_KEY=${INTERNAL_TOOL_API_KEY}" \
|
||||
"MONGODB_URI=${MONGODB_URI}" \
|
||||
"SKILL_INTERNAL_BASE_URL=http://127.0.0.1:${SKILL_PORT}" \
|
||||
"RAG_SERVER_HOST=127.0.0.1" \
|
||||
"RAG_SERVER_PORT=${RAG_PORT}"
|
||||
@@ -345,7 +354,8 @@ log "기동 완료"
|
||||
log " UI http://127.0.0.1:${APP_PORT}/chatbot/app/"
|
||||
log " RAG http://127.0.0.1:${RAG_PORT}/health"
|
||||
log " Admin http://127.0.0.1:${ADMIN_PORT}/"
|
||||
log " Qdrant http://127.0.0.1:6335/ (호스트 포트)"
|
||||
log " Mongo ${EXDEV_DATA_HOST}:${MONGO_PORT} (원격, RAG+WAS)"
|
||||
log " Qdrant http://${EXDEV_DATA_HOST}:${QDRANT_PORT}/dashboard (원격)"
|
||||
log " WAS http://127.0.0.1:${WAS_PORT}/"
|
||||
log " Skill http://127.0.0.1:${SKILL_PORT}/web/ask"
|
||||
log " exdev AI tunnel :${LLM_PORT} ~ :${RERANK_PORT}"
|
||||
|
||||
@@ -72,7 +72,7 @@ fi
|
||||
|
||||
if [[ -f "${COMPOSE_LOCAL}" ]]; then
|
||||
(cd "${RAG_DIR}" && docker compose -f docker-compose.local.yml down --remove-orphans 2>/dev/null) || true
|
||||
log "RAG/Qdrant/Admin 중지 (exchatbot-local)"
|
||||
log "RAG/Admin 중지 (exchatbot-local, 원격 Mongo/Qdrant는 유지)"
|
||||
fi
|
||||
|
||||
# legacy slim compose 잔여 컨테이너 정리
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
# exdev Qdrant qa_vectors 스냅샷 → 로컬 Qdrant(:6335) 복원
|
||||
# (레거시) stock.exdev.co.kr Qdrant 스냅샷 → 로컬 Qdrant 복원
|
||||
# 로컬 start-all.sh 는 원격 Qdrant(stock.exdev.co.kr) 를 직접 사용하므로 보통 불필요
|
||||
#
|
||||
# ./local-dev/sync-qdrant-from-exdev.sh
|
||||
# ./local-dev/sync-qdrant-from-exdev.sh --force
|
||||
@@ -11,9 +12,9 @@ SNAP_DIR="${RUN_DIR}/qdrant-snapshots"
|
||||
|
||||
EXDEV_USER="${EXDEV_USER:-aidev}"
|
||||
EXDEV_HOST="${EXDEV_HOST:-chatbot.exdev.co.kr}"
|
||||
REMOTE_QDRANT="${REMOTE_QDRANT:-http://127.0.0.1:6333}"
|
||||
REMOTE_QDRANT="${REMOTE_QDRANT:-http://stock.exdev.co.kr:6333}"
|
||||
LOCAL_QDRANT="${LOCAL_QDRANT:-http://127.0.0.1:6335}"
|
||||
COLLECTION="${QDRANT_COLLECTION:-qa_vectors}"
|
||||
COLLECTION="${QDRANT_COLLECTION:-qa_vectors_v2}"
|
||||
|
||||
FORCE=false
|
||||
for arg in "$@"; do
|
||||
|
||||
Reference in New Issue
Block a user