Skip to content

Upstage-Ambassador-1th-Team1/Embedding_chatBot

Repository files navigation

공공임대주택 상담 AI 챗봇

Python 기반 공공임대주택 상담 AI 챗봇 시스템입니다.

📋 목차

🎯 기능

  • Upstage Solar LLM 기반 대화형 AI
  • PostgreSQL pgvector를 활용한 RAG (Retrieval-Augmented Generation)
  • Redis 기반 세션 메모리 관리
  • 하이브리드 검색 (벡터 유사도 + 키워드 매칭)
  • FastAPI 기반 REST API
  • 대화 컨텍스트 유지 (세션별 대화 히스토리 관리)
  • 실시간 스트리밍 응답 (Server-Sent Events) ✨
  • 엄격한 범위 제한 (공공임대주택 전용, 범위 외 질문 자동 거부)

🏗️ 아키텍처

┌─────────────────┐
│   사용자 요청    │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│   FastAPI       │
│   (api/routes)  │
└────────┬────────┘
         │
         ▼
┌─────────────────┐      ┌──────────────┐
│   QA Chain      │◄─────│ Redis        │
│   (chains/)     │      │ (세션 메모리) │
└────────┬────────┘      └──────────────┘
         │
         ├─────────────────┐
         │                 │
         ▼                 ▼
┌─────────────────┐ ┌──────────────┐
│ Retrieval       │ │ LLM Service  │
│ Service         │ │ (Upstage)    │
│ (RAG 검색)      │ └──────────────┘
└────────┬────────┘
         │
         ├─────────────────┐
         │                 │
         ▼                 ▼
┌─────────────────┐ ┌──────────────┐
│ Vector Store    │ │ Embeddings   │
│ (pgvector)      │ │ (Upstage)    │
└─────────────────┘ └──────────────┘
         │
         ▼
┌─────────────────┐
│  PostgreSQL DB  │
│  - embeddings   │
└─────────────────┘

📦 설치 방법

두 가지 실행 방법을 제공합니다:

  1. 🐳 Docker로 실행 (권장) - 빠르고 쉬운 설정
  2. 💻 로컬 실행 - 개발 및 디버깅용

🐳 Docker로 실행하기 (권장)

1. 필수 요구사항

  • Docker 20.10 이상
  • Docker Compose 2.0 이상

2. 환경 설정

# .env 파일 생성
cp .env.example .env

# .env 파일 수정
nano .env

.env 파일에서 다음 항목들을 설정하세요:

# LLM (필수!)
UPSTAGE_API_KEY=up_xxxxxxxxxxxxxxxxxxxxx

# Database
DB_HOST=postgres
DB_PORT=5432
DB_NAME=housing_db
DB_USER=postgres
DB_PASSWORD=your_strong_password

# Redis
REDIS_HOST=redis
REDIS_PORT=6379

3. Docker Compose로 실행

프로덕션 환경

# 이미지 빌드 및 컨테이너 시작
docker-compose up -d

# 로그 확인
docker-compose logs -f

# 특정 서비스 로그만 확인
docker-compose logs -f app
docker-compose logs -f postgres
docker-compose logs -f redis

개발 환경 (코드 자동 리로드)

# 개발 모드로 실행
docker-compose -f docker-compose.dev.yml up -d

# pgAdmin 포함 (데이터베이스 관리 도구)
# 접속: http://localhost:5050
# Email: admin@example.com
# Password: admin

4. API 접속

브라우저에서 접속:

5. Docker 컨테이너 관리

# 컨테이너 상태 확인
docker-compose ps

# 컨테이너 중지
docker-compose down

# 컨테이너 재시작
docker-compose restart

# 특정 서비스만 재시작
docker-compose restart app

# 로그 실시간 확인
docker-compose logs -f --tail=100

# 볼륨 포함 완전 삭제 (데이터 삭제됨!)
docker-compose down -v

6. 데이터베이스 접속

# PostgreSQL 컨테이너 접속
docker-compose exec postgres psql -U postgres -d housing_db

# SQL 쿼리 실행
SELECT COUNT(*) FROM announcement_program_embeddings;

# 테이블 구조 확인
\d announcement_program_embeddings

# 종료
\q

7. 컨테이너 내부 접속

# 앱 컨테이너 접속
docker-compose exec app bash

# Python 인터프리터 실행
docker-compose exec app python

# 특정 스크립트 실행
docker-compose exec app python -c "from services.embeddings import embeddings_service; print('OK')"

8. 트러블슈팅

포트 충돌

# 포트 변경 (docker-compose.yml 수정)
ports:
  - "8001:8000"  # 8000 대신 8001 사용

데이터베이스 초기화

# 볼륨 삭제 후 재시작
docker-compose down -v
docker-compose up -d

# 초기화 스크립트 재실행
docker-compose exec postgres psql -U postgres -d housing_db -f /docker-entrypoint-initdb.d/init-db.sql

이미지 재빌드

# 캐시 없이 재빌드
docker-compose build --no-cache
docker-compose up -d

💻 로컬 실행 (Docker 없이)

1. 필수 요구사항

  • Python 3.11 이상
  • PostgreSQL 14+ (pgvector 확장 포함)
  • Redis 6+
  • Upstage API Key

2. 프로젝트 구조

housing-chatbot/
├── config/
│   ├── settings.py          # 환경 설정
│   └── prompts.py           # 시스템 프롬프트
├── models/
│   ├── schemas.py           # Pydantic 스키마
│   └── database.py          # DB 모델
├── services/
│   ├── embeddings.py        # Upstage 임베딩 서비스
│   ├── vector_store.py      # pgvector 검색
│   ├── llm_service.py       # LLM 인터페이스
│   ├── memory_service.py    # Redis 메모리
│   └── retrieval_service.py # RAG 검색
├── chains/
│   └── qa_chain.py          # QA 체인 (메인 로직)
├── api/
│   └── routes.py            # FastAPI 라우트
├── main.py                  # 앱 진입점
├── requirements.txt         # 의존성
├── .env.example             # 환경 변수 예시
├── docker-compose.yml       # Docker Compose 설정
└── Dockerfile               # Docker 이미지 설정

3. 의존성 설치

# 가상환경 생성
python -m venv venv

# 가상환경 활성화
# macOS/Linux:
source venv/bin/activate
# Windows:
# venv\Scripts\activate

# 의존성 설치
pip install -r requirements.txt

4. PostgreSQL 설치 및 설정

macOS (Homebrew)

# PostgreSQL 설치
brew install postgresql@14

# pgvector 설치
brew install pgvector

# PostgreSQL 시작
brew services start postgresql@14

# 데이터베이스 생성
createdb housing_db

Ubuntu/Debian

# PostgreSQL 설치
sudo apt-get update
sudo apt-get install postgresql postgresql-contrib

# pgvector 설치
sudo apt-get install postgresql-14-pgvector

# PostgreSQL 서비스 시작
sudo systemctl start postgresql
sudo systemctl enable postgresql

PostgreSQL 데이터베이스 설정

PostgreSQL 콘솔에서:

-- PostgreSQL 접속
psql postgres

-- 데이터베이스 생성
CREATE DATABASE housing_db;

-- 데이터베이스 연결
\c housing_db

-- pgvector 확장 설치
CREATE EXTENSION IF NOT EXISTS vector;

-- 테이블 생성
CREATE TABLE announcement_program_embeddings (
    announcement_id SERIAL PRIMARY KEY,
    embedding_text TEXT NOT NULL,
    embedding_vector vector(4096),  -- Upstage embedding dimension
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 벡터 인덱스 생성 (성능 향상)
CREATE INDEX ON announcement_program_embeddings 
USING ivfflat (embedding_vector vector_cosine_ops)
WITH (lists = 100);

-- 종료
\q

5. Redis 설치 및 실행

macOS (Homebrew)

# Redis 설치
brew install redis

# Redis 시작
brew services start redis

# 또는 포그라운드 실행
redis-server

Ubuntu/Debian

# Redis 설치
sudo apt-get install redis-server

# Redis 시작
sudo systemctl start redis
sudo systemctl enable redis

# Redis 연결 테스트
redis-cli ping
# 응답: PONG

6. 환경 변수 설정

# .env 파일 생성
cp .env.example .env

.env 파일을 편집하여 다음 값들을 입력:

# LLM
UPSTAGE_API_KEY=up_xxxxxxxxxxxxxxxxxxxxx  # Upstage API 키
LLM_MODEL=solar-pro
TEMPERATURE=0.3
STREAMING=True

# Database
DB_HOST=localhost
DB_PORT=5432
DB_USER=postgres
DB_PASSWORD=your_password  # PostgreSQL 비밀번호
DB_NAME=housing_db

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB=0
SESSION_TTL=1800

# RAG
RETRIEVER_TOP_K=10
CONTEXT_WINDOW_LENGTH=15
VECTOR_STORE_TABLE=announcement_program_embeddings
VECTOR_COLUMN=embedding_vector
CONTENT_COLUMN=embedding_text
ID_COLUMN=announcement_id

# API
API_HOST=0.0.0.0
API_PORT=8000
API_ALLOW_ORIGINS=*

7. 실행

# 서버 시작
python main.py

서버가 성공적으로 시작되면:

INFO:     Started server process [xxxxx]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

⚙️ 설정

환경 변수 상세 설명

.env 파일의 각 설정 항목:

# LLM 설정
UPSTAGE_API_KEY=up_xxxxx        # Upstage API 키 (필수)
LLM_MODEL=solar-pro             # 사용할 LLM 모델
TEMPERATURE=0.3                 # 응답 창의성 (0.0~1.0)
STREAMING=True                  # 스트리밍 응답 사용 여부

# Database 설정
DB_HOST=localhost               # PostgreSQL 호스트
DB_PORT=5432                    # PostgreSQL 포트
DB_USER=postgres                # DB 사용자명
DB_PASSWORD=your_password       # DB 비밀번호
DB_NAME=housing_db              # DB 이름

# Redis 설정
REDIS_HOST=localhost            # Redis 호스트
REDIS_PORT=6379                 # Redis 포트
REDIS_DB=0                      # Redis DB 번호
SESSION_TTL=1800                # 세션 유지 시간 (초)

# RAG 설정
RETRIEVER_TOP_K=10              # 검색할 문서 개수
CONTEXT_WINDOW_LENGTH=15        # 컨텍스트 윈도우 길이
VECTOR_STORE_TABLE=announcement_program_embeddings  # 벡터 테이블명
VECTOR_COLUMN=embedding_vector  # 벡터 컬럼명
CONTENT_COLUMN=embedding_text   # 텍스트 컬럼명
ID_COLUMN=announcement_id       # ID 컬럼명

# API 설정
API_HOST=0.0.0.0                # API 서버 호스트
API_PORT=8000                   # API 서버 포트
API_ALLOW_ORIGINS=*             # CORS 허용 도메인

🚀 사용법

1. API 테스트

헬스 체크

curl http://localhost:8000/health

응답:

{"status": "healthy"}

채팅 요청 (일반)

curl -X POST "http://localhost:8000/chat" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "청년이 신청할 수 있는 공공임대주택 알려줘",
    "session_id": "test_session_001"
  }'

응답 예시:

{
  "response": "청년을 위한 공공임대주택으로는...",
  "sources": [
    {
      "content": "청년 대상 공공임대주택 공고...",
      "score": 0.85,
      "announcement_id": 123
    }
  ],
  "session_id": "test_session_001",
  "timestamp": "2024-11-10T12:34:56"
}

채팅 요청 (스트리밍) ✨

curl -N -X POST "http://localhost:8000/chat/stream" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "청년이 신청할 수 있는 공공임대주택 알려줘",
    "session_id": "test_session_001"
  }'

스트리밍 응답 예시 (Server-Sent Events):

data: {"type":"sources","data":[...],"session_id":"test_session_001"}

data: {"type":"content","data":"청년을","session_id":"test_session_001"}

data: {"type":"content","data":" 위한","session_id":"test_session_001"}

data: {"type":"content","data":" 공공임대주택으로는...","session_id":"test_session_001"}

data: {"type":"done","session_id":"test_session_001"}

data: [DONE]

세션 삭제

curl -X POST "http://localhost:8000/clear-session?session_id=test_session_001"

API 문서 확인

브라우저에서 접속:

2. 스트리밍 클라이언트 예시

HTML 클라이언트 (브라우저)

examples/streaming_client.html 파일을 브라우저에서 열면 실시간 스트리밍 채팅을 테스트할 수 있습니다.

# 서버 실행 후
open examples/streaming_client.html

주요 기능:

  • 실시간 텍스트 스트리밍
  • 타이핑 인디케이터
  • 출처 정보 표시
  • 세션 유지

Python 클라이언트

# 스트리밍 테스트
python examples/streaming_client.py
# 선택: 1

# 일반 채팅 테스트
python examples/streaming_client.py
# 선택: 2

3. Python 코드 예시

일반 채팅

import httpx
import asyncio

async def chat_example():
    async with httpx.AsyncClient() as client:
        # 채팅 요청
        response = await client.post(
            "http://localhost:8000/chat",
            json={
                "content": "청년이 신청할 수 있는 공공임대주택 알려줘",
                "session_id": "user_123"
            }
        )
        
        result = response.json()
        print(f"응답: {result['response']}")
        print(f"출처 개수: {len(result['sources'])}")

asyncio.run(chat_example())

스트리밍 채팅

import httpx
import json
import asyncio

async def chat_streaming():
    url = "http://localhost:8000/chat/stream"
    payload = {
        "content": "청년이 신청할 수 있는 공공임대주택 알려줘",
        "session_id": "user_123"
    }
    
    async with httpx.AsyncClient(timeout=60.0) as client:
        async with client.stream("POST", url, json=payload) as response:
            async for line in response.aiter_lines():
                if line.startswith("data: "):
                    data_str = line[6:].strip()
                    
                    if data_str == "[DONE]":
                        break
                    
                    try:
                        data = json.loads(data_str)
                        
                        if data["type"] == "sources":
                            print(f"📚 출처 {len(data['data'])}개 발견")
                        
                        elif data["type"] == "content":
                            # 실시간으로 텍스트 출력
                            print(data["data"], end="", flush=True)
                        
                        elif data["type"] == "done":
                            print("\n✅ 응답 완료")
                    
                    except json.JSONDecodeError:
                        continue

asyncio.run(chat_streaming())

4. 세션 관리

세션 ID를 통해 대화 컨텍스트를 유지합니다:

# 같은 session_id로 연속 대화
session_id = "user_123"

# 첫 번째 질문
response1 = await client.post("/chat", json={
    "content": "청년 임대주택 알려줘",
    "session_id": session_id
})

# 두 번째 질문 (이전 대화 기억)
response2 = await client.post("/chat", json={
    "content": "신청 자격은 어떻게 되나요?",
    "session_id": session_id
})

# 세션 삭제
await client.post(f"/clear-session?session_id={session_id}")

🗄️ 데이터베이스 스키마

announcement_program_embeddings 테이블

CREATE TABLE announcement_program_embeddings (
    announcement_id SERIAL PRIMARY KEY,
    embedding_text TEXT NOT NULL,
    embedding_vector vector(4096),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 인덱스
CREATE INDEX ON announcement_program_embeddings 
USING ivfflat (embedding_vector vector_cosine_ops)
WITH (lists = 100);

데이터 조회 예시

-- 전체 데이터 개수
SELECT COUNT(*) FROM announcement_program_embeddings;

-- 최근 데이터 조회
SELECT announcement_id, 
       LEFT(embedding_text, 100) as preview,
       created_at
FROM announcement_program_embeddings
ORDER BY created_at DESC
LIMIT 10;

-- 특정 키워드 검색
SELECT announcement_id, embedding_text
FROM announcement_program_embeddings
WHERE embedding_text ILIKE '%청년%'
LIMIT 5;

📊 데이터 임베딩 (초기 데이터 준비)

공고 데이터를 벡터 데이터베이스에 저장하기 위해 임베딩을 생성해야 합니다.

n8n 워크플로우로 임베딩 생성 (권장) 🔄

n8n을 사용하여 자동화된 임베딩 파이프라인을 실행할 수 있습니다.

1. n8n 설치

# npm으로 설치
npm install n8n -g

# 또는 Docker로 실행
docker run -it --rm \
  --name n8n \
  -p 5678:5678 \
  -v ~/.n8n:/home/node/.n8n \
  n8nio/n8n

2. n8n 워크플로우 임포트

  1. n8n 웹 인터페이스 접속: http://localhost:5678
  2. 좌측 메뉴에서 "Workflows" 클릭
  3. "Import from File" 선택
  4. embedding_announcements/RAG ChatBot - Embedding.json 파일 선택
  5. 워크플로우가 임포트됨

3. 데이터베이스 연결 설정

워크플로우에서 PostgreSQL 노드의 Credentials 설정:

Host: localhost (또는 DB 호스트)
Database: housing_db
User: postgres
Password: your_password
Port: 5432
SSL: Disable (로컬) / Enable (프로덕션)

4. Upstage API 설정

Embeddings 노드에서 Upstage API 키 설정:

API Key: your_upstage_api_key
Model: solar-embedding-1-large-passage

5. 워크플로우 실행

수동 실행:

  • 워크플로우 화면에서 "Execute Workflow" 버튼 클릭

자동 실행 (스케줄):

  • Schedule Trigger 노드가 매일 오전 10시에 자동 실행
  • 스케줄 변경: Schedule Trigger 노드 설정에서 시간 조정

6. 워크플로우 구조

┌─────────────────────┐
│ Schedule Trigger    │ ← 매일 오전 10시 실행
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ PostgreSQL          │ ← 임베딩 안 된 프로그램 조회
│ Get Programs        │    (program_embedding_source)
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ Loop Over Programs  │ ← 각 프로그램 순회
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ Upstage Embeddings  │ ← 임베딩 생성
│ API Call            │    (embedding_text → vector)
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ Code - Format Data  │ ← 데이터 포맷팅
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│ PostgreSQL          │ ← DB에 저장 (Upsert)
│ Save Embeddings     │    (announcement_program_embeddings)
└─────────────────────┘

7. 워크플로우 특징

  • 자동 중복 방지: 이미 임베딩된 데이터는 자동으로 스킵
  • 배치 처리: 여러 프로그램을 순차적으로 처리
  • 에러 핸들링: 실패한 항목은 로그에 기록
  • 스케줄링: 매일 자동으로 신규 데이터 임베딩
  • 시각적 모니터링: n8n UI에서 실행 상태 확인

8. 실행 결과 확인

n8n 웹 인터페이스에서:

  • "Executions" 탭에서 실행 히스토리 확인
  • 각 노드의 입출력 데이터 확인
  • 에러 발생 시 상세 로그 확인

Python 스크립트로 임베딩 생성 (대안)

n8n을 사용하지 않는 경우, Python 스크립트로도 임베딩을 생성할 수 있습니다.

# embedding_announcements/manual_embed.py
import asyncio
from services.embeddings import embeddings_service
import psycopg2
import json

async def embed_announcements():
    conn = psycopg2.connect(
        host="localhost",
        database="housing_db",
        user="postgres",
        password="your_password"
    )
    cur = conn.cursor()
    
    # 임베딩 안 된 프로그램 조회
    cur.execute("""
        SELECT 
            p.announcement_id,
            p.subscription_type,
            p.title,
            p.published_date,
            p.embedding_text
        FROM program_embedding_source p
        WHERE NOT EXISTS (
            SELECT 1 
            FROM announcement_program_embeddings e 
            WHERE e.announcement_id = p.announcement_id
        )
        ORDER BY p.published_date DESC;
    """)
    
    programs = cur.fetchall()
    print(f"임베딩할 프로그램: {len(programs)}개")
    
    for i, (ann_id, sub_type, title, pub_date, emb_text) in enumerate(programs, 1):
        print(f"[{i}/{len(programs)}] 처리 중: {title[:50]}...")
        
        # 임베딩 생성
        embedding = await embeddings_service.embed_text(emb_text)
        embedding_json = json.dumps(embedding)
        
        # DB 저장
        cur.execute("""
            INSERT INTO announcement_program_embeddings 
            (announcement_id, subscription_type, title, published_date, 
             embedding_text, embedding_vector)
            VALUES (%s, %s, %s, %s, %s, %s)
            ON CONFLICT (announcement_id) DO UPDATE
            SET embedding_vector = EXCLUDED.embedding_vector,
                updated_at = NOW();
        """, (ann_id, sub_type, title, pub_date, emb_text, embedding_json))
        
        conn.commit()
    
    cur.close()
    conn.close()
    print(f"✅ 완료: {len(programs)}개 임베딩 생성")

if __name__ == "__main__":
    asyncio.run(embed_announcements())

임베딩 상태 확인

# SQL로 확인
psql -U postgres -d housing_db -c "
SELECT 
    COUNT(*) as total,
    COUNT(CASE WHEN embedding_vector IS NOT NULL THEN 1 END) as embedded,
    COUNT(CASE WHEN embedding_vector IS NULL THEN 1 END) as not_embedded
FROM announcement_program_embeddings;
"

출력 예시:

 total | embedded | not_embedded 
-------+----------+--------------
    25 |       25 |            0

� API 엔드포인트

메서드 경로 설명 요청 본문 응답
POST /chat 채팅 메시지 전송 (일반) {"content": "질문", "session_id": "세션ID"} {"response": "답변", "sources": [...], "session_id": "세션ID"}
POST /chat/stream 채팅 메시지 전송 (스트리밍) ✨ {"content": "질문", "session_id": "세션ID"} Server-Sent Events 스트림
POST /clear-session 세션 삭제 Query: session_id {"status": "ok"}
GET /health 헬스 체크 - {"status": "healthy"}
GET /docs API 문서 (Swagger) - HTML
GET /redoc API 문서 (ReDoc) - HTML

스트리밍 응답 형식

/chat/stream 엔드포인트는 Server-Sent Events (SSE) 형식으로 응답합니다:

// 1. 출처 정보
{"type": "sources", "data": [...], "session_id": "..."}

// 2. 텍스트 청크 (실시간)
{"type": "content", "data": "텍스트 조각", "session_id": "..."}

// 3. 완료 신호
{"type": "done", "session_id": "..."}

// 4. 에러 (발생 시)
{"type": "error", "data": "에러 메시지", "session_id": "..."}

범위 제한

챗봇은 공공임대주택 입주자 모집공고에 관한 질문만 답변합니다:

답변 가능:

  • 청년/신혼부부/다자녀 등 대상별 임대주택 검색
  • 특정 지역의 공공임대주택 공고 찾기
  • 신청자격, 소득기준, 임대조건 확인
  • 신청방법, 일정, 제출서류 안내
  • 공고 비교 및 추천

답변 불가 (자동 거부):

  • 음악, 영화, 음식, 날씨 등 일반 주제
  • 프로그래밍, 수학, 과학 문제
  • 의료, 법률, 금융 자문 (임대주택 무관)
  • 기타 공공임대주택과 무관한 모든 질문

범위 외 질문 시 응답 예시:

죄송합니다. 저는 공공임대주택(LH, SH 등) 입주자 모집공고 정보 제공에 특화된 챗봇이에요. 😅
말씀하신 내용은 제 전문 분야가 아니라 답변을 드릴 수 없습니다.
공공임대주택 관련해서 궁금하신 점이 있으시면 언제든 물어봐 주세요! 🏠

🔧 개발

코드 포맷팅

# Black 포맷터 실행
black .

# 특정 파일만 포맷팅
black services/llm_service.py

테스트

# 전체 테스트 실행
pytest

# 특정 테스트 파일 실행
pytest tests/test_retrieval.py

# 커버리지 포함
pytest --cov=services --cov-report=html

로그 확인

로그는 콘솔에 출력됩니다. 파일로 저장하려면:

# 로그 파일로 저장
python main.py > app.log 2>&1

# 실시간 로그 확인
tail -f app.log

개발 서버 실행 (자동 재시작)

# uvicorn으로 개발 모드 실행
uvicorn api.routes:app --reload --host 0.0.0.0 --port 8000

🐛 문제 해결

Docker 관련

1. 포트 충돌 오류

Error: port is already allocated

해결방법:

# docker-compose.yml에서 포트 변경
ports:
  - "8081:8000"  # 8080 대신 8081 사용

2. 권한 오류

PermissionError: [Errno 13] Permission denied

해결방법:

# 폴더 권한 수정
sudo chown -R $(id -u):$(id -g) .

3. 이미지 빌드 실패

해결방법:

# 캐시 없이 다시 빌드
docker-compose build --no-cache

# 이전 이미지 삭제
docker-compose down --rmi all
docker-compose up -d --build

4. 볼륨 초기화

해결방법:

# 볼륨 삭제 후 재시작 (데이터 삭제됨!)
docker-compose down -v
docker-compose up -d

로컬 실행 관련

1. PostgreSQL 연결 오류

sqlalchemy.exc.OperationalError: could not connect to server

해결방법:

# PostgreSQL 상태 확인
# macOS
brew services list
brew services restart postgresql@14

# Ubuntu
sudo systemctl status postgresql
sudo systemctl restart postgresql

# 연결 테스트
psql -U postgres -d housing_db -c "SELECT 1;"

2. pgvector 확장 오류

ERROR: extension "vector" is not available

해결방법:

# macOS
brew install pgvector

# Ubuntu
sudo apt-get install postgresql-14-pgvector

# PostgreSQL에서 확장 활성화
psql housing_db -c "CREATE EXTENSION IF NOT EXISTS vector;"

3. Redis 연결 오류

redis.exceptions.ConnectionError: Error connecting to Redis

해결방법:

# Redis 상태 확인
redis-cli ping
# 응답: PONG

# Redis 재시작
# macOS
brew services restart redis

# Ubuntu
sudo systemctl restart redis

4. Upstage API 오류

openai.error.AuthenticationError: Incorrect API key provided

해결방법:

  • .env 파일의 UPSTAGE_API_KEY 확인
  • API 키가 유효한지 확인
  • API 사용량 초과 여부 확인

5. Python 캐시 문제

해결방법:

# 캐시 삭제
find . -type d -name "__pycache__" -exec rm -rf {} +
find . -name "*.pyc" -delete

# 서버 재시작
python main.py

6. 임베딩 차원 불일치 오류

ERROR: dimension mismatch

해결방법:

-- 테이블 재생성 (데이터 삭제됨!)
DROP TABLE announcement_program_embeddings;

CREATE TABLE announcement_program_embeddings (
    announcement_id SERIAL PRIMARY KEY,
    embedding_text TEXT NOT NULL,
    embedding_vector vector(4096),  -- Upstage는 4096 차원
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

📚 추가 문서

프로젝트의 상세한 가이드:

  • 빠른 시작 가이드: 5분 안에 실행하기
  • Docker 설정 가이드: Docker 상세 설명 및 문제 해결
  • API 사용 가이드: API 상세 설명 및 예제
  • 프로젝트 구조: 디렉토리 구조 및 파일 설명

🔐 보안

  • .env 파일은 절대 Git에 커밋하지 마세요 (.gitignore에 포함됨)
  • 프로덕션 환경에서는 API_ALLOW_ORIGINS를 특정 도메인으로 제한하세요
  • PostgreSQL과 Redis는 방화벽으로 보호하세요
  • API 키는 환경 변수로만 관리하세요

👥 기여

이슈 및 풀 리퀘스트는 언제나 환영합니다!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Commit Message')
  4. Push to the Branch (`git push origin feature/)
  5. Open a Pull Request

📧 문의

문제가 있거나 질문이 있으시면 이슈를 등록해주세요.


📄 라이선스

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published