diff --git a/README.md b/README.md index f7df946..be7326e 100644 --- a/README.md +++ b/README.md @@ -96,13 +96,15 @@ Streamlit 웹 인터페이스 실행: lang2sql run-streamlit ``` -사용자 정의 포트 및 DataHub 서버와 함께: +사용자 정의 포트로 실행: ```bash -lang2sql --datahub_server http://your-datahub-server:8080 run-streamlit -p 8888 +lang2sql run-streamlit -p 8888 ``` -참고: Streamlit 서버는 `0.0.0.0` 으로 바인딩되어 외부에서 접속 가능합니다. +**참고**: +- Streamlit 서버는 `0.0.0.0` 으로 바인딩되어 외부에서 접속 가능합니다. +- `--datahub_server` 옵션은 더 이상 사용되지 않습니다(deprecated). DataHub 설정은 UI의 설정 > 데이터 소스 탭에서 관리하세요. ### Graph Builder 페이지 @@ -116,21 +118,23 @@ Streamlit 앱은 멀티 페이지 구조입니다. 좌측 네비게이션에서 ### VectorDB 선택 -FAISS(로컬) 또는 pgvector(PostgreSQL) 중 선택: +**참고**: CLI 레벨의 `--vectordb-type` 및 `--vectordb-location` 옵션은 더 이상 사용되지 않습니다(deprecated). Streamlit 실행 시 VectorDB 설정은 UI의 설정 > 데이터 소스 탭에서 관리하세요. + +`query` 명령어에서는 VectorDB 옵션을 사용할 수 있습니다: ```bash # FAISS 사용 (기본값) -lang2sql --vectordb-type faiss run-streamlit +lang2sql query "질문" --vectordb-type faiss # pgvector 사용 -lang2sql --vectordb-type pgvector run-streamlit +lang2sql query "질문" --vectordb-type pgvector # 위치 지정 예시 # FAISS: 인덱스 디렉토리 경로 지정 -lang2sql --vectordb-type faiss --vectordb-location ./dev/table_info_db run-streamlit +lang2sql query "질문" --vectordb-type faiss --vectordb-location ./dev/table_info_db # pgvector: 연결 문자열 지정 -lang2sql --vectordb-type pgvector --vectordb-location "postgresql://user:pass@host:5432/db" run-streamlit +lang2sql query "질문" --vectordb-type pgvector --vectordb-location "postgresql://user:pass@host:5432/db" ``` 참고: DataHub 없이도 미리 준비된 VectorDB(FAISS 디렉토리 혹은 pgvector 컬렉션)를 바로 사용할 수 있습니다. 자세한 준비 방법은 [DataHub 없이 시작하기](docs/tutorials/getting-started-without-datahub.md)를 참고하세요. @@ -144,20 +148,41 @@ lang2sql --vectordb-type pgvector --vectordb-location "postgresql://user:pass@ho ### 자연어 쿼리 실행 ```bash -# 기본 FAISS 사용 +# 기본 사용 (FAISS, clickhouse, 기본 검색기) lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" -# pgvector 사용 -lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" --vectordb-type pgvector --vectordb-location "postgresql://postgres:postgres@localhost:5432/postgres" +# 옵션 사용 예시 +lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" \ + --database-env clickhouse \ + --retriever-name 기본 \ + --top-n 5 \ + --device cpu \ + --use-enriched-graph \ + --vectordb-type faiss \ + --vectordb-location ./dev/table_info_db + +# pgvector 사용 예시 +lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" \ + --vectordb-type pgvector \ + --vectordb-location "postgresql://postgres:postgres@localhost:5432/postgres" ``` +**주요 옵션 설명:** +- `--database-env`: 사용할 데이터베이스 환경 (기본값: clickhouse) +- `--retriever-name`: 테이블 검색기 이름 (기본값: 기본) +- `--top-n`: 검색된 상위 테이블 수 제한 (기본값: 5) +- `--device`: LLM 실행에 사용할 디바이스 (기본값: cpu) +- `--use-enriched-graph`: 확장된 그래프(프로파일 추출 + 컨텍스트 보강) 사용 여부 +- `--vectordb-type`: 벡터 데이터베이스 타입 ("faiss" 또는 "pgvector", 기본값: faiss) +- `--vectordb-location`: VectorDB 위치 (FAISS: 디렉토리 경로, pgvector: 연결 문자열) + ### 환경 설정 - `.env` 파일을 생성하여 설정을 관리합니다. (예시 파일이 있다면 참조) - 또는 CLI 옵션으로 환경을 지정할 수 있습니다: - `--env-file-path`: 환경 변수 파일 경로 지정 - `--prompt-dir-path`: 프롬프트 템플릿(.md) 디렉토리 지정 - - `--datahub_server`: DataHub GMS 서버 URL 지정 + - `--datahub_server`: [Deprecated] DataHub GMS 서버 URL 지정. 이제는 UI의 설정 > 데이터 소스 탭에서 관리하세요. ## 🏗️ 아키텍처 diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 0000000..012d1eb --- /dev/null +++ b/cli/README.md @@ -0,0 +1,270 @@ +# CLI 모듈 + +Lang2SQL 프로젝트의 CLI(Command Line Interface) 모듈입니다. 자연어 질문을 SQL 쿼리로 변환하고, Streamlit 웹 애플리케이션을 실행하는 기능을 제공합니다. + +## 디렉토리 구조 + +``` +cli/ +├── __init__.py # CLI 진입점 및 메인 그룹 정의 +├── __pycache__/ # Python 캐시 디렉토리 +├── commands/ # CLI 명령어 정의 모듈 +│ ├── __pycache__/ +│ ├── quary.py # 자연어 질문을 SQL로 변환하는 명령어 +│ ├── run_streamlit.py # Streamlit 실행 명령어 +│ └── README.md # Commands 모듈 문서 +├── core/ # CLI 핵심 기능 모듈 +│ ├── __pycache__/ +│ ├── environment.py # 환경 변수 초기화 모듈 +│ ├── streamlit_runner.py # Streamlit 실행 유틸리티 +│ └── README.md # Core 모듈 문서 +├── utils/ # CLI 유틸리티 모듈 +│ ├── __pycache__/ +│ ├── env_loader.py # 환경 변수 로드 유틸리티 +│ ├── logger.py # 로깅 설정 유틸리티 +│ └── README.md # Utils 모듈 문서 +└── README.md # 이 파일 +``` + +## 모듈 개요 + +### `__init__.py` + +CLI 프로그램의 진입점입니다. Click 프레임워크를 사용하여 명령어 그룹과 옵션을 정의합니다. + +**주요 구성 요소:** + +#### CLI 그룹 정의 +- **함수**: `cli(ctx, datahub_server, run_streamlit, port, env_file_path, prompt_dir_path, vectordb_type, vectordb_location)` +- **데코레이터**: `@click.group()` +- **역할**: Lang2SQL CLI의 최상위 명령어 그룹 + +#### 주요 옵션 + +1. **`--version` / `-v`**: 버전 정보 출력 +2. **`--datahub_server`** (Deprecated): DataHub GMS URL 설정 - 더 이상 사용되지 않음 +3. **`--run-streamlit`**: CLI 실행 시 Streamlit 애플리케이션을 바로 실행하는 플래그 +4. **`-p, --port`**: Streamlit 서버 포트 번호 (기본값: 8501) +5. **`--env-file-path`**: 환경 변수를 로드할 .env 파일 경로 +6. **`--prompt-dir-path`**: 프롬프트 템플릿 디렉토리 경로 +7. **`--vectordb-type`** (Deprecated): VectorDB 타입 - 더 이상 사용되지 않음 +8. **`--vectordb-location`** (Deprecated): VectorDB 위치 - 더 이상 사용되지 않음 + +#### 주요 동작 + +1. **환경 변수 초기화**: `initialize_environment()` 호출로 환경 변수 설정 +2. **Deprecated 옵션 경고**: 사용되지 않는 옵션 사용 시 경고 메시지 출력 +3. **Streamlit 자동 실행**: `--run-streamlit` 플래그가 설정된 경우 Streamlit 실행 + +#### 등록된 명령어 + +- `run-streamlit`: Streamlit 애플리케이션 실행 (`cli/commands/run_streamlit.py`) +- `query`: 자연어 질문을 SQL 쿼리로 변환 (`cli/commands/quary.py`) + +#### Import 관계 + +**Import하는 모듈:** +- `cli.commands.quary.query_command`: query 명령어 +- `cli.commands.run_streamlit.run_streamlit_cli_command`: run-streamlit 명령어 +- `cli.core.environment.initialize_environment`: 환경 변수 초기화 +- `cli.core.streamlit_runner.run_streamlit_command`: Streamlit 실행 함수 +- `cli.utils.logger.configure_logging`: 로깅 설정 +- `version.__version__`: 버전 정보 + +**사용 위치:** +- CLI 진입점: `pyproject.toml`의 `[project.scripts]` 섹션에 정의됨 + ```toml + [project.scripts] + lang2sql = "cli.__init__:cli" + ``` +- 사용 방법: 패키지 설치 후 `lang2sql` 명령어로 실행 + ```bash + lang2sql --help + lang2sql --version + lang2sql --run-streamlit + lang2sql query "질문" + lang2sql run-streamlit + ``` + +#### 코드 예시 + +```python +from cli import cli + +# CLI 그룹 자동 등록 +# lang2sql 명령어로 실행 가능 +``` + +### 하위 모듈 + +#### `commands/` 모듈 + +CLI 명령어를 정의하는 모듈입니다. 자연어 질문을 SQL로 변환하는 `query` 명령어와 Streamlit을 실행하는 `run-streamlit` 명령어를 제공합니다. + +자세한 내용은 [`commands/README.md`](commands/README.md)를 참고하세요. + +**주요 파일:** +- `quary.py`: `query_command` - 자연어를 SQL로 변환하는 명령어 +- `run_streamlit.py`: `run_streamlit_cli_command` - Streamlit 실행 명령어 + +**사용 위치:** +- `cli/__init__.py` (10-11, 116-117번 라인): CLI 그룹에 명령어 등록 + ```python + from cli.commands.quary import query_command + from cli.commands.run_streamlit import run_streamlit_cli_command + + cli.add_command(run_streamlit_cli_command) + cli.add_command(query_command) + ``` + +#### `core/` 모듈 + +CLI의 핵심 기능을 제공하는 모듈입니다. 환경 변수 초기화와 Streamlit 실행 기능을 담당합니다. + +자세한 내용은 [`core/README.md`](core/README.md)를 참고하세요. + +**주요 파일:** +- `environment.py`: `initialize_environment` - 환경 변수 초기화 함수 +- `streamlit_runner.py`: `run_streamlit_command` - Streamlit 실행 함수 + +**사용 위치:** +- `cli/__init__.py` (12-13, 85, 113번 라인): + ```python + from cli.core.environment import initialize_environment + from cli.core.streamlit_runner import run_streamlit_command + + # 환경 변수 초기화 + initialize_environment( + env_file_path=env_file_path, + prompt_dir_path=prompt_dir_path + ) + + # Streamlit 실행 + if run_streamlit: + run_streamlit_command(port) + ``` + +#### `utils/` 모듈 + +CLI 애플리케이션에서 사용되는 유틸리티 함수들을 제공하는 모듈입니다. + +자세한 내용은 [`utils/README.md`](utils/README.md)를 참고하세요. + +**주요 파일:** +- `env_loader.py`: 환경 변수 로드 및 설정 함수들 + - `load_env`: .env 파일 로드 + - `set_prompt_dir`: 프롬프트 디렉토리 설정 + - `set_vectordb`: VectorDB 설정 +- `logger.py`: `configure_logging` - CLI 전용 로깅 설정 + +**사용 위치:** +- `cli/__init__.py` (14, 18번 라인): 로깅 설정 + ```python + from cli.utils.logger import configure_logging + + logger = configure_logging() + ``` +- `cli/core/environment.py`: 환경 변수 로드 +- `cli/core/streamlit_runner.py`: 로깅 설정 +- `cli/commands/quary.py`: 로깅 설정 +- `cli/commands/run_streamlit.py`: 로깅 설정 + +## CLI 사용 방법 + +### 기본 사용법 + +```bash +# 도움말 보기 +lang2sql --help + +# 버전 확인 +lang2sql --version + +# Streamlit 바로 실행 +lang2sql --run-streamlit + +# 환경 변수 파일 지정하여 실행 +lang2sql --env-file-path /path/to/.env --run-streamlit +``` + +### 명령어 + +#### `query` 명령어 + +자연어 질문을 SQL 쿼리로 변환합니다. + +```bash +# 기본 사용 +lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" + +# 옵션과 함께 사용 +lang2sql query "질문" \ + --database-env clickhouse \ + --retriever-name 기본 \ + --top-n 5 \ + --device cpu \ + --use-enriched-graph \ + --vectordb-type faiss \ + --vectordb-location ./dev/table_info_db +``` + +#### `run-streamlit` 명령어 + +Streamlit 웹 애플리케이션을 실행합니다. + +```bash +# 기본 포트(8501)로 실행 +lang2sql run-streamlit + +# 특정 포트로 실행 +lang2sql run-streamlit -p 9000 +``` + +자세한 사용법은 [`commands/README.md`](commands/README.md)를 참고하세요. + +## 의존성 + +### 내부 의존성 + +- `cli.commands.*`: CLI 명령어 정의 +- `cli.core.*`: 핵심 기능 모듈 +- `cli.utils.*`: 유틸리티 함수 +- `version`: 버전 정보 + +### 외부 의존성 + +- `click`: CLI 프레임워크 +- `subprocess`: Streamlit 프로세스 실행 (core 모듈) +- `python-dotenv`: 환경 변수 파일 로드 (utils 모듈) +- `streamlit`: Streamlit 웹 애플리케이션 프레임워크 + +## 모듈 간 관계도 + +``` +cli/__init__.py (진입점) +├── commands/ +│ ├── quary.py → engine.query_executor +│ └── run_streamlit.py → core/streamlit_runner.py +├── core/ +│ ├── environment.py → utils/env_loader.py +│ └── streamlit_runner.py → utils/logger.py +└── utils/ + ├── env_loader.py (독립적) + └── logger.py (독립적) +``` + +## 주요 특징 + +1. **모듈화된 구조**: 명령어, 핵심 기능, 유틸리티가 명확히 분리됨 +2. **확장 가능성**: 새로운 명령어를 쉽게 추가할 수 있는 구조 +3. **환경 관리**: 일관된 환경 변수 초기화 보장 +4. **UI 중심 설계**: VectorDB 및 DataHub 설정은 UI에서 관리 +5. **로깅 지원**: 모든 모듈에서 일관된 로깅 사용 +6. **Deprecated 옵션 처리**: 사용되지 않는 옵션에 대한 명확한 경고 + +## 참고 문서 + +- [`commands/README.md`](commands/README.md): 명령어 모듈 상세 문서 +- [`core/README.md`](core/README.md): 핵심 기능 모듈 상세 문서 +- [`utils/README.md`](utils/README.md): 유틸리티 모듈 상세 문서 + diff --git a/cli/commands/README.md b/cli/commands/README.md new file mode 100644 index 0000000..520e8d6 --- /dev/null +++ b/cli/commands/README.md @@ -0,0 +1,232 @@ +# CLI Commands 모듈 + +Lang2SQL CLI 애플리케이션에서 사용되는 명령어 정의 모듈입니다. + +이 모듈은 사용자가 CLI를 통해 Lang2SQL 기능을 사용할 수 있도록 다양한 명령어를 제공합니다. + +## 디렉토리 구조 + +``` +cli/commands/ +├── __pycache__/ # Python 캐시 디렉토리 +├── quary.py # 자연어 질문을 SQL로 변환하는 명령어 +├── run_streamlit.py # Streamlit 실행 명령어 +└── README.md # 이 파일 +``` + +## 모듈 개요 + +### `quary.py` +- **위치**: `cli/commands/quary.py` +- **설명**: 자연어 질문을 SQL 쿼리로 변환하는 CLI 명령어 정의 모듈 +- **주요 기능**: + - 사용자가 입력한 자연어 질문을 SQL 쿼리로 변환 + - 다양한 옵션을 통한 쿼리 실행 파라미터 설정 + - SQL 쿼리 결과 출력 + +#### 주요 함수 + +##### `query_command()` +자연어 질문을 SQL 쿼리로 변환하여 출력합니다. + +**매개변수:** +- `question` (str): SQL로 변환할 자연어 질문 +- `database_env` (str, optional): 사용할 데이터베이스 환경 (기본값: "clickhouse") +- `retriever_name` (str, optional): 테이블 검색기 이름 (기본값: "기본") +- `top_n` (int, optional): 검색된 상위 테이블 수 제한 (기본값: 5) +- `device` (str, optional): LLM 실행에 사용할 디바이스 (기본값: "cpu") +- `use_enriched_graph` (bool, optional): 확장된 그래프(프로파일 추출 + 컨텍스트 보강) 사용 여부 +- `vectordb_type` (str, optional): 사용할 벡터 데이터베이스 타입 ("faiss" 또는 "pgvector", 기본값: "faiss") +- `vectordb_location` (str, optional): VectorDB 위치 설정 + - FAISS: 디렉토리 경로 (예: ./my_vectordb) + - pgvector: 연결 문자열 (예: postgresql://user:pass@host:port/db) + - 기본값: FAISS는 './dev/table_info_db', pgvector는 환경변수 사용 + +**동작 방식:** +1. 환경 변수 설정 (VECTORDB_TYPE, VECTORDB_LOCATION) +2. `engine.query_executor.execute_query()` 호출하여 쿼리 실행 +3. `extract_sql_from_result()`로 SQL 추출 +4. 추출 실패 시 전체 generated_query 출력 +5. 성공 시 SQL 쿼리 출력 + +**사용 예제:** +```bash +# 기본 사용 +lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" + +# 옵션 사용 +lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" \ + --database-env clickhouse \ + --retriever-name 기본 \ + --top-n 5 \ + --device cpu \ + --use-enriched-graph + +# VectorDB 지정 +lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" \ + --vectordb-type pgvector \ + --vectordb-location postgresql://user:pass@localhost:5432/db +``` + +### `run_streamlit.py` +- **위치**: `cli/commands/run_streamlit.py` +- **설명**: Streamlit 실행 CLI 명령어 모듈 +- **주요 기능**: + - CLI 명령어로 Streamlit 애플리케이션 실행 + - 포트 번호 지정 가능 + +#### 주요 함수 + +##### `run_streamlit_cli_command()` +CLI 명령어로 Streamlit 애플리케이션을 실행합니다. + +**매개변수:** +- `port` (int, optional): Streamlit 서버가 바인딩될 포트 번호 (기본값: 8501) + +**동작 방식:** +1. 로깅을 통해 실행 시작 로그 기록 +2. `cli.core.streamlit_runner.run_streamlit_command()` 호출하여 Streamlit 실행 + +**사용 예제:** +```bash +# 기본 포트(8501)로 실행 +lang2sql run-streamlit + +# 사용자 지정 포트로 실행 +lang2sql run-streamlit -p 9000 + +# 또는 +lang2sql run-streamlit --port 9000 +``` + +## 의존성 + +### 내부 모듈 +- `cli.utils.logger.configure_logging`: CLI 전용 로깅 유틸리티 +- `cli.core.streamlit_runner.run_streamlit_command`: Streamlit 실행 유틸리티 +- `engine.query_executor.execute_query`: 쿼리 실행 공용 함수 +- `engine.query_executor.extract_sql_from_result`: SQL 추출 함수 + +### 외부 라이브러리 +- `click`: CLI 프레임워크 +- `os`: 환경 변수 설정을 위한 표준 라이브러리 + +## 사용 위치 + +### 1. CLI 메인 모듈 (`cli/__init__.py`) +CLI 메인 모듈에서 두 명령어를 등록합니다. + +```python +from cli.commands.quary import query_command +from cli.commands.run_streamlit import run_streamlit_cli_command + +# CLI 그룹에 명령어 추가 +cli.add_command(run_streamlit_cli_command) +cli.add_command(query_command) +``` + +## CLI 사용 방법 + +### `query` 명령어 + +자연어 질문을 SQL 쿼리로 변환하는 명령어입니다. + +**기본 사용법:** +```bash +lang2sql query "<자연어 질문>" +``` + +**모든 옵션:** +```bash +lang2sql query "<자연어 질문>" \ + --database-env <데이터베이스 환경> \ + --retriever-name <검색기 이름> \ + --top-n <테이블 수> \ + --device \ + --use-enriched-graph \ + --vectordb-type \ + --vectordb-location <경로 또는 연결 문자열> +``` + +**실제 사용 예:** +```bash +# 간단한 쿼리 +lang2sql query "사용자 수를 확인하는 쿼리" + +# 옵션을 사용한 쿼리 +lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" \ + --database-env clickhouse \ + --top-n 10 \ + --use-enriched-graph +``` + +### `run-streamlit` 명령어 + +Streamlit 웹 인터페이스를 실행하는 명령어입니다. + +**기본 사용법:** +```bash +lang2sql run-streamlit +``` + +**포트 지정:** +```bash +lang2sql run-streamlit -p 9000 +``` + +**실제 사용 예:** +```bash +# 기본 포트로 실행 +lang2sql run-streamlit + +# 다른 포트로 실행 +lang2sql run-streamlit --port 9000 + +# 브라우저에서 http://localhost:9000 접속 +``` + +## 워크플로우 + +### `query` 명령어 워크플로우 +1. 사용자가 자연어 질문과 옵션을 CLI로 입력 +2. VectorDB 타입과 위치 환경 변수 설정 +3. `engine.query_executor.execute_query()` 호출 +4. Lang2SQL 파이프라인 실행 +5. SQL 추출 및 출력 + +### `run-streamlit` 명령어 워크플로우 +1. 사용자가 명령어 실행 +2. `cli.core.streamlit_runner.run_streamlit_command()` 호출 +3. Streamlit 서브프로세스 실행 +4. 웹 브라우저에서 접속 가능 + +## 환경 변수 + +### `query` 명령어에서 설정되는 환경 변수 +- `VECTORDB_TYPE`: 벡터 데이터베이스 타입 ("faiss" 또는 "pgvector") +- `VECTORDB_LOCATION`: 벡터 데이터베이스 위치 (FAISS: 디렉토리 경로, pgvector: 연결 문자열) + +## 로깅 + +모든 명령어는 `cli.utils.logger.configure_logging()`을 사용하여 로그를 기록합니다: + +- `query` 명령어: 쿼리 처리 중 오류 발생 시 에러 로그 +- `run-streamlit` 명령어: 실행 시작 로그 + +## 에러 처리 + +### `query` 명령어 +- `Exception` 발생 시 에러 로그 기록 및 예외 재발생 +- SQL 추출 실패 시 전체 generated_query 출력 시도 + +### `run-streamlit` 명령어 +- `subprocess.CalledProcessError` 발생 시 에러 로그 기록 및 예외 재발생 + +## 주의사항 + +1. `query` 명령어는 SQL 쿼리만 출력하며 결과는 실행하지 않습니다 +2. `vectordb_location`을 지정하지 않으면 기본값 또는 환경변수 사용 +3. `run-streamlit` 명령어는 서브프로세스로 Streamlit을 실행하므로 프로세스가 종료될 때까지 대기합니다 +4. 기본 포트(8501)가 이미 사용 중이면 포트 변경 필요 +5. `use_enriched_graph` 옵션 사용 시 더 많은 리소스 소모 가능 + diff --git a/cli/core/README.md b/cli/core/README.md new file mode 100644 index 0000000..925c522 --- /dev/null +++ b/cli/core/README.md @@ -0,0 +1,147 @@ +# CLI Core 모듈 + +Lang2SQL CLI의 핵심 기능을 제공하는 모듈입니다. + +## 디렉토리 구조 + +``` +cli/core/ +├── environment.py # 환경 변수 초기화 모듈 +└── streamlit_runner.py # Streamlit 실행 유틸리티 모듈 +``` + +## 모듈 설명 + +### 1. environment.py + +환경 변수 초기화를 담당하는 모듈입니다. VectorDB 설정은 UI에서 관리합니다. + +#### 주요 기능 + +- `initialize_environment()`: 환경 변수를 초기화하는 함수 + +#### 함수 상세 + +##### `initialize_environment(env_file_path, prompt_dir_path)` + +환경 변수를 초기화합니다. VectorDB 설정은 UI에서 관리합니다. + +**매개변수:** +- `env_file_path` (Optional[str]): 로드할 .env 파일 경로. None이면 기본값 사용. +- `prompt_dir_path` (Optional[str]): 프롬프트 템플릿 디렉토리 경로. None이면 설정하지 않음. + +**예외:** +- `Exception`: 초기화 과정에서 오류가 발생한 경우. + +**내부 동작:** +- `cli.utils.env_loader.load_env()`: .env 파일을 로드합니다. +- `cli.utils.env_loader.set_prompt_dir()`: 프롬프트 템플릿 디렉토리 경로를 환경 변수로 설정합니다. + +#### 사용 예시 + +```python +from cli.core.environment import initialize_environment + +# 기본 경로로 초기화 +initialize_environment(env_file_path=None, prompt_dir_path=None) + +# 사용자 정의 경로로 초기화 +initialize_environment( + env_file_path="/path/to/.env", + prompt_dir_path="/path/to/prompts" +) +``` + +#### import 및 사용 위치 + +이 모듈의 `initialize_environment` 함수는 다음과 같이 사용됩니다: + +- **`cli/__init__.py`** (85-90번째 줄): CLI 진입점에서 환경 초기화 시 호출 + ```python + from cli.core.environment import initialize_environment + + initialize_environment( + env_file_path=env_file_path, + prompt_dir_path=prompt_dir_path + ) + ``` + +### 2. streamlit_runner.py + +Streamlit 애플리케이션 실행을 담당하는 유틸리티 모듈입니다. + +#### 주요 기능 + +- `run_streamlit_command()`: 지정된 포트에서 Streamlit 애플리케이션을 실행하는 함수 + +#### 함수 상세 + +##### `run_streamlit_command(port)` + +지정된 포트에서 Streamlit 애플리케이션을 실행합니다. + +**매개변수:** +- `port` (int): 바인딩할 포트 번호. + +**예외:** +- `subprocess.CalledProcessError`: 실행 실패 시 발생. + +**내부 동작:** +- `subprocess.run()`을 사용하여 `streamlit run` 명령을 실행합니다. +- 실행 대상: `interface/streamlit_app.py` +- 서버 주소: `0.0.0.0` +- 포트: 사용자 지정 값 (기본값: 8501) +- 로깅: `cli.utils.logger.configure_logging()`을 통해 로그 출력 + +#### 사용 예시 + +```python +from cli.core.streamlit_runner import run_streamlit_command + +# 기본 포트(8501)로 실행 +run_streamlit_command(port=8501) + +# 사용자 정의 포트로 실행 +run_streamlit_command(port=8080) +``` + +#### import 및 사용 위치 + +이 모듈의 `run_streamlit_command` 함수는 다음과 같이 사용됩니다: + +1. **`cli/__init__.py`** (113번째 줄): CLI의 `--run-streamlit` 옵션이 활성화된 경우 호출 + ```python + from cli.core.streamlit_runner import run_streamlit_command + + if run_streamlit: + run_streamlit_command(port) + ``` + +2. **`cli/commands/run_streamlit.py`** (29번째 줄): `run-streamlit` CLI 명령 실행 시 호출 + ```python + from cli.core.streamlit_runner import run_streamlit_command + + @click.command(name="run-streamlit") + def run_streamlit_cli_command(port: int): + logger.info("Executing 'run-streamlit' command on port %d...", port) + run_streamlit_command(port) + ``` + +## 의존성 + +### 내부 의존성 + +- `cli.utils.env_loader`: 환경 변수 로드 및 프롬프트 디렉토리 설정 +- `cli.utils.logger`: 로깅 설정 + +### 외부 의존성 + +- `subprocess`: 프로세스 실행 (streamlit_runner.py) + +## 주요 특징 + +1. **환경 관리**: CLI 진입점에서 일관된 환경 변수 초기화 보장 +2. **UI 중심 설계**: VectorDB 설정은 UI에서 관리하여 사용자 편의성 향상 +3. **유연한 실행**: 다양한 포트에서 Streamlit 애플리케이션 실행 지원 +4. **로깅 지원**: 실행 상태 및 오류 추적 가능 + diff --git a/cli/utils/README.md b/cli/utils/README.md new file mode 100644 index 0000000..d6a3012 --- /dev/null +++ b/cli/utils/README.md @@ -0,0 +1,187 @@ +# CLI Utils 모듈 + +CLI 애플리케이션에서 사용되는 유틸리티 함수들을 제공하는 모듈입니다. + +## 디렉토리 구조 + +``` +cli/utils/ +├── __pycache__/ +├── env_loader.py +├── logger.py +└── README.md +``` + +## 파일 목록 및 설명 + +### env_loader.py + +환경 변수 유틸리티 모듈입니다. `.env` 파일 로드, 프롬프트 디렉토리 설정, VectorDB 타입 및 위치 설정을 제공합니다. + +**주요 함수:** + +#### `load_env(env_file_path: Optional[str] = None) -> None` +환경 변수 파일(.env)을 로드합니다. + +**파라미터:** +- `env_file_path` (Optional[str]): .env 파일 경로. None이면 기본 경로 사용. + +**동작:** +- 지정된 경로의 `.env` 파일을 로드하거나, 경로가 없으면 기본 경로의 `.env` 파일을 로드합니다. +- 성공/실패 메시지를 컬러로 출력합니다. +- 로드 실패 시 예외를 발생시킵니다. + +**사용 예시:** +```python +from cli.utils.env_loader import load_env + +# 기본 .env 파일 로드 +load_env() + +# 특정 경로의 .env 파일 로드 +load_env(env_file_path="/path/to/.env") +``` + +#### `set_prompt_dir(prompt_dir_path: Optional[str]) -> None` +프롬프트 템플릿 디렉토리 경로를 환경 변수로 설정합니다. + +**파라미터:** +- `prompt_dir_path` (Optional[str]): 디렉토리 경로. None이면 설정하지 않음. + +**환경 변수:** +- `PROMPT_TEMPLATES_DIR`: 설정된 프롬프트 디렉토리 경로 + +**Raises:** +- `ValueError`: 경로가 유효하지 않을 경우 + +**사용 예시:** +```python +from cli.utils.env_loader import set_prompt_dir + +set_prompt_dir(prompt_dir_path="/path/to/prompt/templates") +``` + +#### `set_vectordb(vectordb_type: str, vectordb_location: Optional[str] = None) -> None` +VectorDB 타입과 위치를 환경 변수로 설정합니다. + +**파라미터:** +- `vectordb_type` (str): VectorDB 타입 ("faiss" 또는 "pgvector") +- `vectordb_location` (Optional[str]): 경로 또는 연결 URL + +**환경 변수:** +- `VECTORDB_TYPE`: 설정된 VectorDB 타입 +- `VECTORDB_LOCATION`: 설정된 VectorDB 경로 또는 연결 URL (지정된 경우) + +**Raises:** +- `ValueError`: 잘못된 타입이나 경로/URL일 경우 + +**사용 예시:** +```python +from cli.utils.env_loader import set_vectordb + +# FAISS 설정 +set_vectordb(vectordb_type="faiss", vectordb_location="/path/to/faiss/db") + +# pgvector 설정 +set_vectordb( + vectordb_type="pgvector", + vectordb_location="postgresql://user:pass@host:port/db" +) +``` + +**사용처:** +- `cli/core/environment.py` (5번 라인): `load_env`, `set_prompt_dir` 함수를 import하여 사용 + - `initialize_environment` 함수에서 환경 변수 초기화 시 사용 + ```python + from cli.utils.env_loader import load_env, set_prompt_dir + + def initialize_environment( + *, + env_file_path: Optional[str], + prompt_dir_path: Optional[str], + ) -> None: + load_env(env_file_path=env_file_path) + set_prompt_dir(prompt_dir_path=prompt_dir_path) + ``` + +### logger.py + +CLI 전용 로깅 유틸리티 모듈입니다. 로깅 설정을 구성하고 기본 로거 인스턴스를 반환합니다. + +**주요 함수:** + +#### `configure_logging(level: int = logging.INFO) -> logging.Logger` +로깅을 설정하고 기본 로거를 반환합니다. + +**파라미터:** +- `level` (int, optional): 로깅 레벨. 기본값은 `logging.INFO`. + +**반환값:** +- `logging.Logger`: 설정된 로거 인스턴스. 로거 이름은 "cli"입니다. + +**로깅 설정:** +- 레벨: 지정된 레벨 (기본값: `INFO`) +- 포맷: `%(asctime)s [%(levelname)s] %(message)s` +- 날짜 포맷: `%Y-%m-%d %H:%M:%S` + +**사용 예시:** +```python +from cli.utils.logger import configure_logging + +# 기본 설정으로 로거 생성 +logger = configure_logging() + +# DEBUG 레벨로 로거 생성 +logger = configure_logging(level=logging.DEBUG) + +# 로깅 사용 +logger.info("Information message") +logger.error("Error message") +``` + +**사용처:** + +1. **`cli/__init__.py`** (14번 라인) + - CLI 진입점에서 로거 초기화 + ```python + from cli.utils.logger import configure_logging + + logger = configure_logging() + ``` + - 사용 위치: 18번 라인에서 로거 인스턴스 생성, 89번, 92번 라인에서 에러 및 정보 로깅 + +2. **`cli/commands/quary.py`** (11번 라인) + - query 명령어 실행 시 로거 초기화 + ```python + from cli.utils.logger import configure_logging + + logger = configure_logging() + ``` + - 사용 위치: 13번 라인에서 로거 인스턴스 생성, 112번 라인에서 에러 로깅 + +3. **`cli/core/streamlit_runner.py`** (5번 라인) + - Streamlit 실행 모듈에서 로거 초기화 + ```python + from cli.utils.logger import configure_logging + + logger = configure_logging() + ``` + - 사용 위치: 7번 라인에서 로거 인스턴스 생성, 19번, 33번, 35번 라인에서 정보 및 에러 로깅 + +4. **`cli/commands/run_streamlit.py`** (6번 라인) + - run-streamlit 명령어 실행 시 로거 초기화 + ```python + from cli.utils.logger import configure_logging + + logger = configure_logging() + ``` + - 사용 위치: 8번 라인에서 로거 인스턴스 생성, 28번 라인에서 정보 로깅 + +## 의존성 + +- `click`: CLI 출력 및 메시지 표시 +- `dotenv`: `.env` 파일 로드 +- `logging`: 로깅 기능 (Python 표준 라이브러리) +- `pathlib.Path`: 경로 처리 +- `os`: 환경 변수 설정 + diff --git a/engine/README.md b/engine/README.md new file mode 100644 index 0000000..b8b4445 --- /dev/null +++ b/engine/README.md @@ -0,0 +1,215 @@ +# engine 모듈 + +Lang2SQL 쿼리 실행을 위한 공용 모듈입니다. + +이 모듈은 CLI와 Streamlit 인터페이스에서 공통으로 사용할 수 있는 쿼리 실행 함수를 제공합니다. + +## 디렉토리 구조 + +``` +engine/ +├── __init__.py # 패키지 초기화 모듈 +├── query_executor.py # 쿼리 실행 공용 함수 +└── README.md # 이 파일 +``` + +## 모듈 개요 + +### `__init__.py` +- **위치**: `engine/__init__.py` +- **설명**: Lang2SQL Data Processing 진입점 패키지 +- **내용**: 패키지 초기화 모듈 + +### `query_executor.py` +- **위치**: `engine/query_executor.py` +- **설명**: Lang2SQL 쿼리 실행을 위한 공용 모듈 +- **주요 기능**: + - `execute_query()`: 자연어 쿼리를 SQL로 변환하고 실행 결과를 반환 + - `extract_sql_from_result()`: Lang2SQL 실행 결과에서 SQL 쿼리 추출 + +#### 주요 함수 + +##### `execute_query()` +자연어 쿼리를 SQL로 변환하고 실행 결과를 반환하는 공용 함수입니다. + +**매개변수:** +- `query` (str): 사용자가 입력한 자연어 기반 질문 +- `database_env` (str): 사용할 데이터베이스 환경 이름 또는 키 (예: "dev", "prod") +- `retriever_name` (str, optional): 테이블 검색기 이름. 기본값은 "기본" +- `top_n` (int, optional): 검색된 상위 테이블 수 제한. 기본값은 5 +- `device` (str, optional): LLM 실행에 사용할 디바이스 ("cpu" 또는 "cuda"). 기본값은 "cpu" +- `use_enriched_graph` (bool, optional): 확장된 그래프 사용 여부. 기본값은 False +- `session_state` (Optional[Union[Dict[str, Any], Any]], optional): Streamlit 세션 상태 (Streamlit에서만 사용) + +**반환값:** +- `Dict[str, Any]`: 다음 정보를 포함한 Lang2SQL 실행 결과 딕셔너리: + - `"generated_query"`: 생성된 SQL 쿼리 (`AIMessage`) + - `"messages"`: 전체 LLM 응답 메시지 목록 + - `"searched_tables"`: 참조된 테이블 목록 등 추가 정보 + +**동작 방식:** +1. 사용자가 지정한 옵션에 따라 기본 그래프 또는 확장 그래프를 선택 +2. Streamlit 환경에서는 세션 상태에서 그래프 재사용, CLI 환경에서는 매번 새로운 그래프 컴파일 +3. 선택된 그래프를 컴파일하고 invoke하여 결과 반환 + +**사용 예제:** +```python +from engine.query_executor import execute_query + +# CLI 환경에서 사용 +result = execute_query( + query="고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리", + database_env="clickhouse", + retriever_name="기본", + top_n=5, + device="cpu", + use_enriched_graph=False +) + +# Streamlit 환경에서 사용 +result = execute_query( + query="고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리", + database_env="clickhouse", + retriever_name="기본", + top_n=5, + device="cpu", + use_enriched_graph=False, + session_state=st.session_state # Streamlit 세션 상태 전달 +) +``` + +##### `extract_sql_from_result()` +Lang2SQL 실행 결과에서 SQL 쿼리를 추출합니다. + +**매개변수:** +- `res` (Dict[str, Any]): `execute_query()` 함수의 반환 결과 + +**반환값:** +- `Optional[str]`: 추출된 SQL 쿼리 문자열. 추출 실패 시 None + +**동작 방식:** +1. `generated_query` 필드에서 쿼리 메시지 추출 +2. `LLMResponseParser.extract_sql()`을 사용하여 SQL 쿼리 문자열 추출 +3. 추출 실패 시 None 반환 + +**사용 예제:** +```python +from engine.query_executor import execute_query, extract_sql_from_result + +result = execute_query( + query="고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리", + database_env="clickhouse" +) + +sql = extract_sql_from_result(result) +if sql: + print(sql) +``` + +## 의존성 + +### 내부 모듈 +- `utils.llm.graph_utils.basic_graph.builder`: 기본 그래프 빌더 +- `utils.llm.graph_utils.enriched_graph.builder`: 확장 그래프 빌더 +- `utils.llm.llm_response_parser.LLMResponseParser`: LLM 응답 파서 + +### 외부 라이브러리 +- `langchain_core.messages.HumanMessage`: LangChain 메시지 클래스 + +## 사용 위치 + +### 1. CLI 명령어 (`cli/commands/quary.py`) +CLI 환경에서 `query` 명령어 실행 시 사용됩니다. + +```python +from engine.query_executor import execute_query, extract_sql_from_result + +# CLI 명령어에서 사용 +res = execute_query( + query=question, + database_env=database_env, + retriever_name=retriever_name, + top_n=top_n, + device=device, + use_enriched_graph=use_enriched_graph, +) + +sql = extract_sql_from_result(res) +``` + +### 2. Streamlit 인터페이스 (`interface/core/lang2sql_runner.py`) +Streamlit 인터페이스에서 Lang2SQL 실행을 위해 사용됩니다. + +```python +from engine.query_executor import execute_query as execute_query_common + +# Streamlit 러너에서 사용 +def run_lang2sql(query, database_env, retriever_name, top_n, device): + return execute_query_common( + query=query, + database_env=database_env, + retriever_name=retriever_name, + top_n=top_n, + device=device, + ) +``` + +### 3. Streamlit 메인 페이지 (`interface/app_pages/lang2sql.py`) +Streamlit 메인 페이지에서 `lang2sql_runner.run_lang2sql()`을 호출하여 사용됩니다. + +```python +from interface.core.lang2sql_runner import run_lang2sql + +# 메인 페이지에서 사용 +if st.button("쿼리 실행"): + res = run_lang2sql( + query=user_query, + database_env=user_database_env, + retriever_name=user_retriever, + top_n=user_top_n, + device=device, + ) + display_result(res=res) +``` + +## 워크플로우 + +### 기본 워크플로우 +1. 사용자가 자연어 질문 입력 +2. `execute_query()` 호출 +3. 기본 그래프 빌더 선택 및 컴파일 +4. 그래프 실행하여 SQL 쿼리 생성 +5. 결과 딕셔너리 반환 + +### 확장 워크플로우 (프로파일 추출 + 컨텍스트 보강) +1. 사용자가 자연어 질문 입력 +2. `execute_query(use_enriched_graph=True)` 호출 +3. 확장 그래프 빌더 선택 및 컴파일 +4. 그래프 실행하여 SQL 쿼리 생성 +5. 결과 딕셔너리 반환 + +## 환경별 동작 + +### CLI 환경 +- 세션 상태 없이 매번 새로운 그래프 컴파일 +- 중간 결과 저장/재사용 불가 + +### Streamlit 환경 +- 세션 상태를 통해 그래프 재사용 가능 +- 중간 결과 저장/재사용 가능 +- 다이얼렉트 정보 주입 지원 + +## 로깅 + +이 모듈은 `logging` 모듈을 사용하여 로그를 기록합니다: +- 처리 중인 쿼리 로그 +- 사용 중인 그래프 유형 로그 +- SQL 추출 실패 시 에러 로그 + +## 주의사항 + +1. `session_state` 파라미터는 Streamlit 환경에서만 유효합니다 +2. `use_enriched_graph=True`로 설정하면 더 많은 리소스가 소모될 수 있습니다 +3. `database_env`는 유효한 데이터베이스 환경 이름이어야 합니다 +4. 그래프 컴파일은 처음 실행 시 시간이 걸릴 수 있습니다 + diff --git a/infra/db/__init__.py b/infra/db/__init__.py deleted file mode 100644 index 628fb1b..0000000 --- a/infra/db/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""DB 접근 계층 패키지""" diff --git a/infra/db/connect_db.py b/infra/db/connect_db.py deleted file mode 100644 index 992e1b7..0000000 --- a/infra/db/connect_db.py +++ /dev/null @@ -1,120 +0,0 @@ -""" -ClickHouse 데이터베이스에 연결하고 SQL 쿼리를 실행하여 결과를 pandas DataFrame으로 반환하는 모듈입니다. - -구성 요소: -- 환경 변수에서 접속 정보를 불러옵니다. -- ClickHouse에 지연 연결(lazy connection)을 수행합니다. -- SQL 쿼리를 실행하고 결과를 pandas DataFrame으로 반환합니다. -- 연결 실패 및 쿼리 오류에 대해 로깅을 통해 디버깅을 지원합니다. -""" - -import logging -import os -from typing import Optional - -import pandas as pd -from clickhouse_driver import Client - -logging.basicConfig( - level=logging.INFO, - format="%(asctime)s [%(levelname)s] %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", -) -logger = logging.getLogger(__name__) - - -class ConnectDB: - """ - ClickHouse 데이터베이스에 연결하고 SQL 쿼리를 실행하는 클래스입니다. - - 환경 변수에서 접속 정보를 읽어들이며, 실제 연결은 SQL 실행 시점에 수행됩니다. - 연결된 클라이언트를 통해 SQL 쿼리를 실행하고, 결과를 pandas DataFrame으로 반환합니다. - """ - - def __init__(self): - """ - ConnectDB 클래스의 인스턴스를 초기화합니다. - - 환경 변수에서 ClickHouse 접속 정보를 불러오며, 연결은 즉시 수행하지 않습니다. - """ - - self.client: Optional[Client] = None - self.is_connected: bool = False - - self.host = self._get_env_or_raise("CLICKHOUSE_HOST") - self.dbname = self._get_env_or_raise("CLICKHOUSE_DATABASE") - self.user = self._get_env_or_raise("CLICKHOUSE_USER") - self.password = os.getenv("CLICKHOUSE_PASSWORD", "") - self.port = int(self._get_env_or_raise("CLICKHOUSE_PORT")) - - def _get_env_or_raise(self, var_name: str) -> str: - """ - 주어진 환경변수를 읽고, 값이 없으면 예외를 발생시킵니다. - - Parameters: - var_name (str): 환경 변수 이름 - - Returns: - str: 환경 변수의 값 - - Raises: - ValueError: 값이 없을 경우 - """ - - value = os.getenv(var_name) - if not value: - logger.error("Environment variable '%s' is not set.", var_name) - raise ValueError(f"Environment variable '{var_name}' is not set.") - return value - - def connect_to_clickhouse(self) -> None: - """ - ClickHouse 서버에 연결을 시도합니다. - - 연결 성공 시 client가 초기화되며, 실패 시 로그를 남기고 예외를 발생시킵니다. - """ - - try: - self.client = Client( - host=self.host, - port=self.port, - user=self.user, - password=self.password, - database=self.dbname, - ) - self.is_connected = True - logger.info("Successfully connected to ClickHouse.") - except Exception as e: - self.is_connected = False - logger.error("Failed to connect to ClickHouse: %s", e) - raise - - def run_sql(self, sql: str) -> pd.DataFrame: - """ - 주어진 SQL 쿼리를 실행하고 결과를 pandas DataFrame으로 반환합니다. - - 연결이 설정되지 않은 경우 자동으로 연결을 시도합니다. - - Parameters: - sql (str): 실행할 SQL 쿼리 문자열 - - Returns: - pd.DataFrame: 쿼리 결과를 포함한 DataFrame - - Raises: - Exception: SQL 실행 중 오류가 발생한 경우 예외를 발생시킵니다. - """ - - if not self.is_connected or not self.client: - logger.warning("ClickHouse client not connected. Attempting to connect...") - self.connect_to_clickhouse() - - try: - result = self.client.execute(sql, with_column_types=True) - rows, columns = result - column_names = [col[0] for col in columns] - df = pd.DataFrame(rows, columns=column_names) - return df - except Exception as e: - logger.exception("An error occurred while executing SQL: %s", e) - raise diff --git a/infra/monitoring/README.md b/infra/monitoring/README.md new file mode 100644 index 0000000..f14d82a --- /dev/null +++ b/infra/monitoring/README.md @@ -0,0 +1,148 @@ +# infra/monitoring 패키지 + +서버 상태 확인 및 헬스 체크 기능을 제공하는 모니터링 패키지입니다. + +## 디렉토리 구조 + +``` +infra/monitoring/ +├── __init__.py +├── __pycache__/ +└── check_server.py +``` + +## 파일 설명 + +### `__init__.py` + +모니터링/헬스체크 패키지의 초기화 파일입니다. + +**내용:** +- 패키지 문서화 문자열: "모니터링/헬스체크 패키지" + +**역할:** +- `infra.monitoring` 패키지를 Python 패키지로 인식시키는 초기화 파일 + +--- + +### `check_server.py` + +서버 상태 확인 및 연결 관련 기능을 제공하는 유틸리티 클래스입니다. + +**주요 구성 요소:** + +1. **HTTP 기반 서버 헬스 체크** + - `/health` 엔드포인트를 통한 서버 상태 확인 + - 향후 서버 연결 또는 상태 점검 기능 확장 가능한 구조 + +2. **예외 처리 및 로깅** + - 요청 실패, 타임아웃, 연결 오류 등의 다양한 예외 상황 처리 + - 로깅을 통해 상세한 실패 원인 기록 + - 결과를 boolean 값으로 반환 + +**주요 클래스:** + +#### `CheckServer` + +서버의 상태를 확인하거나 연결을 테스트하는 유틸리티 메서드를 제공하는 클래스입니다. + +현재는 GMS 서버의 `/health` 엔드포인트에 대한 헬스 체크 기능을 포함하고 있으며, 향후에는 다양한 서버 연결 확인 및 상태 점검 기능이 추가될 수 있도록 확장 가능한 구조로 설계되었습니다. + +**메서드:** + +- `is_gms_server_healthy(*, url: str) -> bool` (정적 메서드): + - 지정된 GMS 서버의 `/health` 엔드포인트에 요청을 보내 상태를 확인합니다. + - Parameters: + - `url` (str): 헬스 체크를 수행할 GMS 서버의 기본 URL (예: "http://localhost:8080") + - Returns: + - `bool`: 서버가 정상적으로 응답하면 `True`, 예외 발생 시 `False` + - 기능: + - 서버 URL과 `/health` 경로를 결합하여 헬스 체크 엔드포인트 생성 + - 3초 타임아웃으로 GET 요청 수행 + - HTTP 200 응답 시 `True` 반환 + - 다음 예외 상황 처리: + - `ConnectTimeout`, `ReadTimeout`: 타임아웃 오류 로깅 + - `ConnectionError`: 연결 실패 로깅 + - `HTTPError`: HTTP 오류 로깅 + - `RequestException`: 기타 요청 예외 로깅 + - 예외 발생 시 `False` 반환 + +**의존성:** +- `requests`: HTTP 요청 수행 +- `urllib.parse.urljoin`: URL 경로 결합 +- `logging`: 로깅 기능 + +**사용 예시:** + +```python +from infra.monitoring.check_server import CheckServer + +# GMS 서버 헬스 체크 +is_healthy = CheckServer.is_gms_server_healthy(url="http://localhost:8080") + +if is_healthy: + print("서버가 정상입니다.") +else: + print("서버 연결에 문제가 있습니다.") +``` + +## Import 및 사용 현황 + +### 사용 위치 + +**`interface/app_pages/settings_sections/data_source_section.py`** + +이 모듈에서 `CheckServer` 클래스를 import하여 사용합니다. + +**Import:** +```python +from infra.monitoring.check_server import CheckServer +``` + +**사용 방법:** + +1. **DataHub 편집 시 헬스 체크** (117번째 줄) + ```python + if st.button("헬스 체크", key="dh_edit_health"): + ok = CheckServer.is_gms_server_healthy(url=new_url) + st.session_state["datahub_last_health"] = bool(ok) + if ok: + st.success("GMS 서버가 정상입니다.") + else: + st.error("GMS 서버 헬스 체크 실패. URL과 네트워크를 확인하세요.") + ``` + +2. **DataHub 추가 시 헬스 체크** (160번째 줄) + ```python + if st.button("헬스 체크", key="dh_health_new"): + ok = CheckServer.is_gms_server_healthy(url=dh_url) + st.session_state["datahub_last_health"] = bool(ok) + if ok: + st.success("GMS 서버가 정상입니다.") + else: + st.error("GMS 서버 헬스 체크 실패. URL과 네트워크를 확인하세요.") + ``` + +**사용 목적:** +- Streamlit UI에서 DataHub 서버 설정 시, 사용자가 입력한 URL이 유효한지 확인 +- 헬스 체크 결과를 세션 상태에 저장하여 상태 배너에 표시 +- 서버 연결 성공/실패에 따라 사용자에게 적절한 피드백 제공 + +## 로깅 + +모듈은 Python의 `logging` 모듈을 사용하여 다음 정보를 로깅합니다: +- 서버가 정상일 때: INFO 레벨로 성공 메시지 +- 타임아웃 발생 시: ERROR 레벨로 타임아웃 오류 메시지 +- 연결 실패 시: ERROR 레벨로 연결 오류 메시지 +- HTTP 오류 발생 시: ERROR 레벨로 HTTP 오류 메시지 +- 기타 요청 예외 발생 시: ERROR 레벨로 예외 정보 로깅 + +로깅 레벨은 `INFO`로 설정되어 있으며, 타임스탬프와 로그 레벨 정보가 포함됩니다. + +**로깅 포맷:** +``` +%(asctime)s [%(levelname)s] %(message)s +``` + +날짜 형식: `%Y-%m-%d %H:%M:%S` + diff --git a/infra/observability/README.md b/infra/observability/README.md new file mode 100644 index 0000000..85f6a2e --- /dev/null +++ b/infra/observability/README.md @@ -0,0 +1,98 @@ +# observability + +LLM 응답 메시지에서 토큰 사용량을 집계하고 관찰(observability)하기 위한 유틸리티 모듈을 제공하는 디렉토리입니다. + +## 디렉토리 구조 + +``` +observability/ +├── __pycache__/ +└── token_usage.py +``` + +## 파일 설명 + +### token_usage.py + +LLM 응답 메시지에서 토큰 사용량을 집계하기 위한 유틸리티 모듈입니다. + +#### 주요 내용 + +- **TokenUtils 클래스**: LLM 토큰 사용량 집계 유틸리티 클래스 + - `get_token_usage_summary()`: 메시지 데이터에서 input/output/total 토큰 사용량을 각각 집계하는 정적 메서드 + - `usage_metadata` 필드를 기반으로 입력 토큰, 출력 토큰, 총 토큰 사용량을 계산 + - Streamlit, LangChain 등 LLM 응답을 다루는 애플리케이션에서 비용 분석, 사용량 추적 등에 활용 가능 + +#### 반환 형식 + +```python +{ + "input_tokens": int, + "output_tokens": int, + "total_tokens": int +} +``` + +## 사용 방법 + +### Import + +이 모듈은 다음과 같이 import되어 사용됩니다: + +```python +from infra.observability.token_usage import TokenUtils +``` + +### 실제 사용 예시 + +#### 1. interface/core/result_renderer.py + +`TokenUtils`는 Lang2SQL 결과 표시 모듈에서 토큰 사용량을 계산하고 Streamlit UI에 표시하는 데 사용됩니다. + +```75:85:interface/core/result_renderer.py + if should_show("show_token_usage"): + st.markdown("---") + token_summary = TokenUtils.get_token_usage_summary(data=res["messages"]) + st.write("**토큰 사용량:**") + st.markdown( + f""" + - Input tokens: `{token_summary['input_tokens']}` + - Output tokens: `{token_summary['output_tokens']}` + - Total tokens: `{token_summary['total_tokens']}` + """ + ) +``` + +**사용 컨텍스트**: +- `display_result()` 함수 내에서 LLM 실행 결과(`res`)의 `messages` 리스트를 전달받아 토큰 사용량을 집계 +- Streamlit UI에서 토큰 사용량 정보를 마크다운 형식으로 표시 +- 사용자가 설정에서 토큰 사용량 표시 옵션(`show_token_usage`)을 활성화한 경우에만 표시 + +**입력 데이터 형식**: +- `data` 파라미터는 각 항목이 `usage_metadata` 속성을 포함할 수 있는 객체 리스트입니다 +- 예: LangChain의 `AIMessage` 객체 리스트 + +#### 사용 패턴 + +```python +# 기본 사용법 +token_summary = TokenUtils.get_token_usage_summary(data=messages) + +# 반환된 딕셔너리 접근 +input_tokens = token_summary["input_tokens"] +output_tokens = token_summary["output_tokens"] +total_tokens = token_summary["total_tokens"] +``` + +## 로깅 + +이 모듈은 Python 표준 `logging` 모듈을 사용하여 토큰 사용량 정보를 기록합니다: + +- **DEBUG 레벨**: 각 메시지별 토큰 사용량 상세 정보 +- **INFO 레벨**: 전체 토큰 사용량 요약 정보 + +## 참고사항 + +- `usage_metadata` 필드가 없는 객체는 토큰 사용량이 0으로 처리됩니다 +- 각 메시지의 토큰 사용량은 누적되어 최종 합계를 반환합니다 + diff --git a/interface/README.md b/interface/README.md new file mode 100644 index 0000000..d90fc49 --- /dev/null +++ b/interface/README.md @@ -0,0 +1,742 @@ +# interface + +Streamlit 기반 Lang2SQL 데이터 분석 도구의 사용자 인터페이스 레이어입니다. + +## 디렉토리 구조 + +``` +interface/ +├── app_pages/ # Streamlit 페이지들 +│ ├── __init__.py +│ ├── chatbot.py # AI ChatBot 페이지 +│ ├── graph_builder.py # LangGraph 구성 페이지 +│ ├── home.py # 홈 페이지 +│ ├── lang2sql.py # Lang2SQL 메인 페이지 +│ ├── settings.py # 설정 페이지 (탭 구성) +│ ├── sidebar_components/ # 사이드바 UI 컴포넌트 +│ │ ├── __init__.py +│ │ ├── chatbot_session_controller.py +│ │ ├── data_source_selector.py +│ │ ├── db_selector.py +│ │ ├── embedding_selector.py +│ │ ├── llm_selector.py +│ │ └── README.md +│ └── settings_sections/ # 설정 페이지 섹션들 +│ ├── __init__.py +│ ├── data_source_section.py +│ ├── db_section.py +│ ├── llm_section.py +│ └── README.md +├── core/ # 핵심 인터페이스 로직 +│ ├── config/ # 설정 관리 +│ │ ├── __init__.py +│ │ ├── models.py # 설정 데이터 모델 +│ │ ├── paths.py # 파일 경로 관리 +│ │ ├── persist.py # 디스크 저장/로드 +│ │ ├── registry_data_sources.py +│ │ ├── registry_db.py +│ │ ├── registry_llm.py +│ │ └── settings.py # 설정 업데이트 API +│ ├── dialects.py # SQL 다이얼렉트 프리셋 +│ ├── lang2sql_runner.py # Lang2SQL 실행 래퍼 +│ ├── result_renderer.py # 결과 시각화 +│ └── session_utils.py # 세션 관리 +├── pages_config.py # 페이지 구성 +└── streamlit_app.py # 메인 진입점 +``` + +## 아키텍처 개요 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ streamlit_app.py │ +│ (메인 진입점, 페이지 네비게이션) │ +└────────────────────────────┬────────────────────────────────────┘ + │ + ┌────────┴─────────┐ + │ pages_config.py │ + │ (페이지 설정) │ + └────────┬─────────┘ + │ + ┌────────────────────┼────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ +│ home.py │ │ lang2sql.py │ │ chatbot.py │ +│ (홈/소개) │ │ (메인 기능) │ │ (AI 채팅) │ +└───────────────┘ └───────┬───────┘ └───────────────┘ + │ │ + │ ┌────────┴────────┐ + │ │ │ + ▼ ▼ ▼ +┌───────────────┐ ┌───────────────┐ ┌───────────────┐ +│graph_builder.py│ │ settings.py │ │sidebar_components│ +│ (그래프 구성) │ │ (설정) │ │ (사이드바) │ +└───────────────┘ └───────┬───────┘ └───────┬───────┘ + │ │ + ▼ ▼ + ┌────────────────┐ ┌────────────────┐ + │settings_sections│ │ core/config/ │ + │ (설정 UI) │ │ (설정 관리) │ + └────────────────┘ └────────┬───────┘ + │ + ▼ + ┌──────────────────┐ + │ core/ │ + │ - dialects.py │ + │ - lang2sql_runner│ + │ - result_renderer│ + │ - session_utils │ + └──────────────────┘ +``` + +## 주요 컴포넌트 + +### 1. streamlit_app.py + +Streamlit 애플리케이션의 메인 진입점입니다. + +**역할:** +- 애플리케이션 전역 설정 초기화 (제목, 아이콘, 레이아웃) +- 페이지 네비게이션 구성 및 실행 + +**주요 함수:** +- `configure_app()`: Streamlit 전역 설정 +- `main()`: 애플리케이션 진입점 + +**사용 예시:** +```python +# streamlit run interface/streamlit_app.py +``` + +**의존성:** +- `interface.pages_config.PAGES`: 페이지 목록 + +--- + +### 2. pages_config.py + +Streamlit 페이지 구성 정의 모듈입니다. + +**역할:** +- 각 페이지의 경로와 제목 정의 +- 네비게이션에 사용되는 페이지 리스트 제공 + +**내용:** +- `PAGES`: 5개 페이지 정의 + - 홈 (home.py) + - Lang2SQL (lang2sql.py) + - 그래프 빌더 (graph_builder.py) + - ChatBot (chatbot.py) + - 설정 (settings.py) + +**사용처:** +- `streamlit_app.py` (line 9, 37) + +--- + +### 3. app_pages/ + +Streamlit 애플리케이션의 각 페이지 모듈들입니다. + +#### 3.1. home.py + +홈 페이지로 Lang2SQL 도구 소개 및 사용 방법 안내를 제공합니다. + +**주요 내용:** +- 도구 소개 및 환영 메시지 +- 사용 방법 가이드 +- 주요 기능 링크 안내 + +**사용처:** +- `pages_config.py` (line 18) + +--- + +#### 3.2. lang2sql.py + +Lang2SQL 메인 페이지로 자연어 질의를 SQL 쿼리로 변환하고 결과를 시각화합니다. + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 🔍 Lang2SQL │ +├──────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────────┐ ┌───────────────────────┐ │ +│ │ Sidebar │ │ Main Area │ │ +│ │ │ │ │ │ +│ │ ┌──────────────┐ │ │ ┌───────────────────┐ │ │ +│ │ │Data Source │ │ │ │쿼리 입력 영역 │ │ │ +│ │ │Selector │ │ │ │ │ │ │ +│ │ └──────────────┘ │ │ │"고객 데이터를..." │ │ │ +│ │ ──────────────── │ │ └───────────────────┘ │ │ +│ │ ┌──────────────┐ │ │ │ │ +│ │ │LLM Selector │ │ │ ┌───────────────────┐ │ │ +│ │ └──────────────┘ │ │ │DB 선택 및 관리 │ │ │ +│ │ ──────────────── │ │ └───────────────────┘ │ │ +│ │ ┌──────────────┐ │ │ │ │ +│ │ │Embedding Sel.│ │ │ [검색기 유형] │ │ +│ │ └──────────────┘ │ │ [Top-N 개수] │ │ +│ │ ──────────────── │ │ [모델 실행 장치] │ │ +│ │ ┌──────────────┐ │ │ │ │ +│ │ │DB Selector │ │ │ [쿼리 실행] │ │ +│ │ └──────────────┘ │ │ │ │ +│ │ ──────────────── │ │ ┌───────────────────┐ │ │ +│ │ Output Settings │ │ │ 결과 표시 영역 │ │ │ +│ │ □ Token Usage │ │ │ - SQL 쿼리 │ │ │ +│ │ □ Result Desc │ │ │ - 결과 테이블 │ │ │ +│ │ □ Show SQL │ │ │ - 차트 │ │ │ +│ │ ... │ │ └───────────────────┘ │ │ +│ │ ──────────────── │ │ │ │ +│ │ 워크플로우 선택 │ └───────────────────────┘ │ +│ │ ○ 기본 │ │ +│ │ ○ 확장 │ │ +│ └──────────────────┘ │ +└──────────────────────────────────────────────────────────────┘ +``` + +**주요 기능:** +- 사이드바 설정: 데이터 소스, LLM, Embedding, DB 선택 +- 출력 옵션 설정 (토큰 사용량, SQL 표시, 차트 등) +- 워크플로우 선택 (기본/확장) +- 자연어 질의 입력 및 SQL 변환 실행 +- DB 다이얼렉트 선택 및 편집 +- 검색기 유형 및 Top-N 설정 +- 결과 시각화 (테이블, 차트) + +**주요 함수:** +- 페이지 레벨에서 직접 실행되는 Streamlit UI 코드 + +**사용 모듈:** +- `interface.core.dialects`: 다이얼렉트 프리셋 +- `interface.core.lang2sql_runner`: Lang2SQL 실행 +- `interface.core.result_renderer`: 결과 시각화 +- `interface.core.session_utils`: 그래프 초기화 +- `interface.app_pages.sidebar_components`: 사이드바 컴포넌트 + +**의존성:** +- `engine.query_executor.execute_query`: 실제 쿼리 실행 + +--- + +#### 3.3. graph_builder.py + +LangGraph 워크플로우를 구성하고 세션에 적용하는 페이지입니다. + +``` +┌──────────────────────────────────────────────────────────────┐ +│ LangGraph 구성 UI │ +├──────────────────────────────────────────────────────────────┤ +│ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ 프리셋 선택: ○ 기본 ○ 확장 ○ 커스텀 │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ 커스텀 옵션: │ │ +│ │ ☑ PROFILE_EXTRACTION 포함 │ │ +│ │ ☑ CONTEXT_ENRICHMENT 포함 │ │ +│ │ ☑ QUERY_MAKER 포함 │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ GET_TABLE_INFO 설정: │ │ +│ │ - 테이블 검색기: [벡터 검색 (기본) ▼] │ │ +│ │ - 검색할 테이블 정보 개수: [====●====] 5 │ │ +│ │ - 모델 실행 장치: [cpu ▼] │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ 실행 순서: │ │ +│ │ GET_TABLE_INFO → PROFILE_EXTRACTION → ... │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ 그래프 생성: │ │ +│ │ ℹ️ 그래프가 세션에 적용되었습니다. │ │ +│ │ [세션 그래프 새로고침] │ │ +│ └────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────────────────────────────────────────────────────┐ │ +│ │ 현재 세션 그래프 설정 (expander) │ │ +│ └────────────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────┘ +``` + +**주요 기능:** +- 프리셋 선택: 기본, 확장, 커스텀 +- 노드 시퀀스 구성 (GET_TABLE_INFO → PROFILE → CONTEXT → QUERY_MAKER) +- GET_TABLE_INFO 설정 (검색기, Top-N, 장치) +- 그래프 세션에 적용 및 새로고침 +- 현재 그래프 설정 확인 + +**주요 함수:** +- `build_selected_sequence()`: 프리셋에 따른 노드 시퀀스 생성 +- `build_state_graph()`: StateGraph 빌더 생성 +- `render_sequence()`: 시퀀스를 문자열로 변환 + +**사용 모듈:** +- `utils.llm.graph_utils.base`: 노드 정의 및 그래프 유틸 + +--- + +#### 3.4. chatbot.py + +AI ChatBot 페이지로 LangGraph 기반 대화형 인터페이스를 제공합니다. + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 🤖 AI ChatBot │ +├───────────────────────────┬──────────────────────────────────┤ +│ Sidebar │ Chat Area │ +│ │ │ +│ ┌───────────────────────┐ │ ┌─────────────────────────────┐ │ +│ │Data Source Selector │ │ │ 안녕하세요! 무엇을... 🤖 │ │ +│ └───────────────────────┘ │ └─────────────────────────────┘ │ +│ ───────────────────────── │ │ +│ ┌───────────────────────┐ │ ┌─────────────────────────────┐ │ +│ │LLM Selector │ │ │ 사용자: 데이터베이스 테이블... │ │ +│ └───────────────────────┘ │ └─────────────────────────────┘ │ +│ ───────────────────────── │ │ +│ ┌───────────────────────┐ │ ┌─────────────────────────────┐ │ +│ │Embedding Selector │ │ │ Assistant: 관련 테이블은... │ │ +│ └───────────────────────┘ │ │ 🤖 모델: gpt-4o-mini │ │ +│ ───────────────────────── │ └─────────────────────────────┘ │ +│ ┌───────────────────────┐ │ │ +│ │DB Selector │ │ ┌─────────────────────────────┐ │ +│ └───────────────────────┘ │ │ 사용자: [입력 중...] │ │ +│ ───────────────────────── │ └─────────────────────────────┘ │ +│ 🤖 ChatBot 설정 │ │ +│ ┌───────────────────────┐ │ │ +│ │ Thread ID: uuid... │ │ │ +│ │ [새 세션 시작] │ │ │ +│ └───────────────────────┘ │ │ +│ ───────────────────────── │ │ +│ 대화 기록: │ │ +│ - Thread ID │ │ +│ - 메시지 목록 (JSON) │ │ +└───────────────────────────┴─────────────────────────────────┘ +``` + +**주요 기능:** +- OpenAI 기반 대화형 AI 채팅 +- 사이드바 설정: 데이터 소스, LLM, Embedding, DB +- Thread ID 기반 세션 관리 +- 대화 기록 표시 및 관리 +- 신규 세션 시작 기능 + +**주요 함수:** +- `initialize_session_state()`: 세션 상태 초기화 및 ChatBot 인스턴스 생성 + +**사용 모듈:** +- `utils.llm.chatbot.ChatBot`: ChatBot 핵심 로직 +- `interface.app_pages.sidebar_components`: 사이드바 컴포넌트 +- `interface.core.config.load_config`: 설정 로드 + +**제약사항:** +- 현재 OpenAI만 지원 +- OpenAI API 키 필수 + +--- + +#### 3.5. settings.py + +설정 페이지로 데이터 소스, LLM, DB 설정을 탭으로 관리합니다. + +``` +┌──────────────────────────────────────────────────────────────┐ +│ ⚙️ 설정 │ +├──────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────┬──────────┬──────────┐ │ +│ │데이터 소스 │ LLM │ DB │ │ +│ └──────────┴──────────┴──────────┘ │ +│ │ +│ [선택된 탭 내용 표시] │ +│ │ +└──────────────────────────────────────────────────────────────┘ +``` + +**주요 기능:** +- 3개 탭으로 구성: 데이터 소스, LLM, DB +- 각 탭은 settings_sections 모듈 사용 +- 세션 우선 설정 반영 + +**사용 모듈:** +- `interface.app_pages.settings_sections`: 각 설정 섹션 + +--- + +#### 3.6. sidebar_components/ + +사이드바에서 사용되는 설정 선택 컴포넌트들입니다. + +**모듈 구조:** +- `data_source_selector.py`: 데이터 소스 선택 (DataHub/VectorDB) +- `llm_selector.py`: LLM 프로파일 선택 +- `embedding_selector.py`: Embedding 프로파일 선택 +- `db_selector.py`: DB 프로파일 선택 +- `chatbot_session_controller.py`: ChatBot 세션 관리 + +**사용처:** +- `lang2sql.py`: 메인 페이지 사이드바 +- `chatbot.py`: ChatBot 페이지 사이드바 + +**자세한 내용:** `sidebar_components/README.md` 참고 + +--- + +#### 3.7. settings_sections/ + +설정 페이지의 각 섹션 UI 모듈들입니다. + +**모듈 구조:** +- `data_source_section.py`: DataHub/VectorDB 관리 +- `llm_section.py`: LLM 및 Embedding 설정 +- `db_section.py`: DB 연결 설정 + +**사용처:** +- `settings.py`: 설정 페이지 탭 내용 + +**자세한 내용:** `settings_sections/README.md` 참고 + +--- + +### 4. core/ + +핵심 인터페이스 로직을 담당하는 모듈들입니다. + +#### 4.1. dialects.py + +SQL 다이얼렉트 프리셋 정의 및 관리 모듈입니다. + +**주요 내용:** +- `DialectOption`: SQL 엔진 특성 데이터클래스 + - `name`: 엔진 표시 이름 + - `supports_ilike`: ILIKE 지원 여부 + - `hints`: 자주 쓰이는 함수 목록 +- `PRESET_DIALECTS`: 9개 SQL 엔진 프리셋 + - PostgreSQL, ClickHouse, Trino, Snowflake, Redshift + - BigQuery, MSSQL, Oracle, DuckDB + +**사용처:** +- `lang2sql.py` (line 19, 85-124): DB 선택 및 편집 UI + +--- + +#### 4.2. lang2sql_runner.py + +Lang2SQL 실행 래퍼 모듈입니다. + +**주요 함수:** +- `run_lang2sql()`: 자연어 질의를 SQL로 변환 후 실행 + +**파라미터:** +- `query`: 자연어 질문 +- `database_env`: 데이터베이스 환경 이름 +- `retriever_name`: 검색기 유형 +- `top_n`: 검색할 테이블 정보 개수 +- `device`: 모델 실행 장치 + +**사용처:** +- `lang2sql.py` (line 139-145): 쿼리 실행 + +**의존성:** +- `engine.query_executor.execute_query`: 실제 실행 로직 + +--- + +#### 4.3. result_renderer.py + +Lang2SQL 실행 결과 시각화 모듈입니다. + +**주요 함수:** +- `display_result()`: Streamlit UI로 결과 출력 + +**표시 항목:** +- Question Gate 결과 +- 문서 적합성 평가 +- 토큰 사용량 +- SQL 쿼리 및 해석 +- 결과 설명 +- 재해석된 질문 +- 참고 테이블 목록 +- 쿼리 실행 결과 테이블 +- 결과 차트 (Plotly) + +**사용 모듈:** +- `infra.observability.token_usage.TokenUtils`: 토큰 사용량 +- `utils.databases.DatabaseFactory`: DB 커넥터 +- `utils.llm.llm_response_parser.LLMResponseParser`: SQL 파싱 +- `utils.visualization.display_chart.DisplayChart`: 차트 생성 + +**사용처:** +- `lang2sql.py` (line 146): 결과 표시 + +--- + +#### 4.4. session_utils.py + +Streamlit 세션 상태에서 그래프 빌더를 초기화하는 모듈입니다. + +**주요 함수:** +- `init_graph()`: 그래프 초기화 및 세션 상태 갱신 + +**파라미터:** +- `use_enriched`: 확장 그래프 사용 여부 + +**반환값:** +- 그래프 유형 문자열 ("확장된" 또는 "기본") + +**사용처:** +- `lang2sql.py` (line 72, 76): 그래프 초기화 + +**의존성:** +- `utils.llm.graph_utils.enriched_graph`: 확장 그래프 +- `utils.llm.graph_utils.basic_graph`: 기본 그래프 + +--- + +#### 4.5. config/ + +설정 관리 패키지로 데이터 소스, DB, LLM, Embedding 설정을 관리합니다. + +**아키텍처:** + +``` +config/ +├── models.py # 데이터 모델 정의 +│ ├── Config # 전역 설정 +│ ├── DataHubSource # DataHub 소스 +│ ├── VectorDBSource # VectorDB 소스 +│ ├── DataSourcesRegistry # 데이터 소스 레지스트리 +│ ├── DBConnectionProfile # DB 프로파일 +│ ├── DBConnectionsRegistry # DB 레지스트리 +│ ├── LLMProfile # LLM 프로파일 +│ ├── LLMRegistry # LLM 레지스트리 +│ ├── EmbeddingProfile # Embedding 프로파일 +│ └── EmbeddingRegistry # Embedding 레지스트리 +│ +├── paths.py # 파일 경로 관리 +│ ├── get_registry_file_path() # 데이터 소스 레지스트리 경로 +│ ├── get_db_registry_file_path() # DB 레지스트리 경로 +│ ├── get_llm_registry_file_path() # LLM 레지스트리 경로 +│ └── get_embedding_registry_file_path() # Embedding 레지스트리 경로 +│ +├── persist.py # 디스크 저장/로드 +│ ├── save_registry_to_disk() # 데이터 소스 저장 +│ ├── load_registry_from_disk() # 데이터 소스 로드 +│ ├── save_db_registry_to_disk() # DB 저장 +│ ├── load_db_registry_from_disk() # DB 로드 +│ ├── save_llm_registry_to_disk() # LLM 저장 +│ ├── load_llm_registry_from_disk() # LLM 로드 +│ ├── save_embedding_registry_to_disk() # Embedding 저장 +│ └── load_embedding_registry_from_disk() # Embedding 로드 +│ +├── settings.py # 설정 업데이트 API +│ ├── load_config() # 설정 로드 +│ ├── update_datahub_server() # DataHub 서버 업데이트 +│ ├── update_data_source_mode() # 데이터 소스 모드 업데이트 +│ ├── update_vectordb_settings() # VectorDB 설정 업데이트 +│ ├── update_llm_settings() # LLM 설정 업데이트 +│ ├── update_embedding_settings() # Embedding 설정 업데이트 +│ └── update_db_settings() # DB 설정 업데이트 +│ +├── registry_data_sources.py # 데이터 소스 레지스트리 관리 +│ ├── get_data_sources_registry() # 레지스트리 조회 +│ ├── add_datahub_source() # DataHub 추가 +│ ├── update_datahub_source() # DataHub 업데이트 +│ ├── delete_datahub_source() # DataHub 삭제 +│ ├── add_vectordb_source() # VectorDB 추가 +│ ├── update_vectordb_source() # VectorDB 업데이트 +│ └── delete_vectordb_source() # VectorDB 삭제 +│ +├── registry_db.py # DB 레지스트리 관리 +│ ├── get_db_connections_registry() # 레지스트리 조회 +│ ├── add_db_connection() # DB 추가 +│ ├── update_db_connection() # DB 업데이트 +│ └── delete_db_connection() # DB 삭제 +│ +├── registry_llm.py # LLM/Embedding 레지스트리 관리 +│ ├── get_llm_registry() # LLM 레지스트리 조회 +│ ├── save_llm_profile() # LLM 프로파일 저장 +│ ├── get_embedding_registry() # Embedding 레지스트리 조회 +│ └── save_embedding_profile() # Embedding 프로파일 저장 +│ +└── __init__.py # 패키지 공개 API +``` + +**설정 우선순위:** +1. 세션 상태 (`st.session_state`) +2. 환경 변수 (`os.getenv`) +3. 기본값 + +**저장 위치:** +- 기본: `./config/` 디렉토리 +- 환경 변수로 오버라이드 가능: + - `LANG2SQL_REGISTRY_PATH` + - `LANG2SQL_DB_REGISTRY_PATH` + - `LANG2SQL_LLM_REGISTRY_PATH` + - `LANG2SQL_EMBEDDING_REGISTRY_PATH` + +**사용 예시:** +```python +from interface.core.config import load_config, get_data_sources_registry + +# 설정 로드 +config = load_config() + +# 레지스트리 조회 +registry = get_data_sources_registry() + +# DataHub 추가 +from interface.core.config import add_datahub_source +add_datahub_source( + name="Production", + url="http://datahub.prod:8080", + faiss_path="./prod/faiss", + note="프로덕션 DataHub" +) +``` + +--- + +## 전체 데이터 흐름 + +``` +┌────────────────────────────────────────────────────────────┐ +│ 사용자 입력 │ +│ (자연어 질의, 설정 변경 등) │ +└──────────────────────┬─────────────────────────────────────┘ + │ + ▼ +┌────────────────────────────────────────────────────────────┐ +│ Streamlit UI Layer │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ app_pages/ │ │ core/ │ │ config/ │ │ +│ │ - lang2sql │ │ - runner │ │ - settings │ │ +│ │ - chatbot │ │ - renderer │ │ - registry │ │ +│ │ - settings │ │ - dialects │ │ - persist │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└──────────────────┬─────────────────────────────────────────┘ + │ + ▼ +┌────────────────────────────────────────────────────────────┐ +│ Business Logic Layer │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ engine/ │ │ utils/llm/ │ │ utils/data/ │ │ +│ │ - executor │ │ - graph │ │ - databases │ │ +│ │ │ │ - factory │ │ - hub │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└──────────────────┬─────────────────────────────────────────┘ + │ + ▼ +┌────────────────────────────────────────────────────────────┐ +│ Data & External Services │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ DataHub │ │ Database │ │ LLM APIs │ │ +│ │ VectorDB │ │ (DBs) │ │ (OpenAI, │ │ +│ │ │ │ │ │ AWS, etc) │ │ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +└────────────────────────────────────────────────────────────┘ + │ + ▼ +┌────────────────────────────────────────────────────────────┐ +│ 결과 반환 │ +│ (SQL, 테이블, 차트, 설명 등) │ +└────────────────────────────────────────────────────────────┘ +``` + +## 주요 설정 파일 + +설정은 JSON 파일로 `./config/` 디렉토리에 저장됩니다. + +- `data_sources.json`: DataHub/VectorDB 레지스트리 +- `db_connections.json`: DB 프로파일 레지스트리 +- `llm_profiles.json`: LLM 프로파일 레지스트리 +- `embedding_profiles.json`: Embedding 프로파일 레지스트리 + +**예시: data_sources.json** +```json +{ + "datahub": [ + { + "name": "Local DataHub", + "url": "http://localhost:8080", + "faiss_path": "./dev/table_info_db", + "note": "로컬 개발 환경" + } + ], + "vectordb": [ + { + "name": "Local FAISS", + "type": "faiss", + "location": "./dev/faiss_db", + "collection_prefix": null, + "note": "로컬 벡터 DB" + } + ] +} +``` + +## 사용 방법 + +### 애플리케이션 실행 + +```bash +# 메인 애플리케이션 실행 +streamlit run interface/streamlit_app.py + +# 또는 +python -m interface.streamlit_app +``` + +### 설정 관리 + +```python +from interface.core.config import ( + load_config, + get_data_sources_registry, + add_datahub_source, + update_db_settings, +) + +# 설정 로드 +config = load_config() + +# DataHub 추가 +add_datahub_source( + name="Production", + url="http://datahub.prod:8080", + faiss_path="./prod/faiss" +) + +# DB 설정 업데이트 +update_db_settings( + db_type="postgresql", + values={"host": "localhost", "port": "5432", "user": "admin"}, + secrets={"password": "secret"} +) +``` + +## 의존성 + +**주요 패키지:** +- `streamlit`: UI 프레임워크 +- `pandas`: 데이터 처리 +- `plotly`: 차트 시각화 +- `langchain_core`: LLM 메시지 처리 + +**프로젝트 내부 모듈:** +- `engine.query_executor`: 쿼리 실행 +- `utils.llm`: LLM 관련 유틸리티 +- `utils.data`: 데이터 관련 유틸리티 +- `utils.databases`: 데이터베이스 유틸리티 +- `infra.observability`: 모니터링 및 관찰성 + +## 참고 문서 + +- `app_pages/sidebar_components/README.md`: 사이드바 컴포넌트 상세 +- `app_pages/settings_sections/README.md`: 설정 섹션 상세 +- `README_UPDATE_CONDITION.md`: 문서 업데이트 가이드 + diff --git a/interface/app_pages/settings_sections/README.md b/interface/app_pages/settings_sections/README.md new file mode 100644 index 0000000..c81b768 --- /dev/null +++ b/interface/app_pages/settings_sections/README.md @@ -0,0 +1,185 @@ +# settings_sections + +설정 페이지의 각 섹션을 렌더링하는 모듈들입니다. + +## 디렉토리 구조 + +``` +settings_sections/ +├── __init__.py +├── data_source_section.py +├── db_section.py +└── llm_section.py +``` + +## 파일 목록 및 설명 + +### `__init__.py` + +네임스페이스 패키지 초기화 파일로, 패키지에서 export되는 모듈 목록을 정의합니다. + +**내보내는 모듈:** +- `data_source_section` +- `llm_section` +- `db_section` + +### `data_source_section.py` + +데이터 소스 설정을 관리하는 UI 섹션을 제공합니다. + +**주요 기능:** +- DataHub 또는 VectorDB 중 하나를 선택하여 데이터 소스 모드 설정 +- DataHub 서버 관리: + - 등록된 DataHub 목록 조회 및 표시 + - 새로운 DataHub 추가 (이름, URL, FAISS 저장 경로, 메모) + - 기존 DataHub 편집 및 삭제 + - GMS 서버 헬스 체크 기능 +- VectorDB 관리: + - 등록된 VectorDB 목록 조회 및 표시 (FAISS, pgvector 지원) + - 새로운 VectorDB 추가 (이름, 타입, 위치, 컬렉션 접두사, 메모) + - 기존 VectorDB 편집 및 삭제 + - 설정 검증 기능 + +**주요 함수:** +- `render_data_source_section(config: Config | None = None) -> None` + - 데이터 소스 설정 섹션을 Streamlit UI로 렌더링 + - `config` 파라미터가 없으면 내부에서 `load_config()`를 호출하여 로드 + +**의존성:** +- `interface.core.config`: Config 관리, 데이터 소스 레지스트리 조작 +- `infra.monitoring.check_server.CheckServer`: GMS 서버 헬스 체크 + +**상태 표시:** +- 현재 선택된 데이터 소스 모드에 따라 상태 배너 표시 +- DataHub: 헬스 체크 결과에 따른 성공/경고/정보 메시지 +- VectorDB: 설정 완전성에 따른 성공/경고 메시지 + +### `db_section.py` + +데이터베이스 연결 설정을 관리하는 UI 섹션을 제공합니다. + +**주요 기능:** +- 다양한 DB 타입 지원: + - PostgreSQL, MySQL, MariaDB, Oracle, ClickHouse + - DuckDB, SQLite + - Databricks, Snowflake, Trino +- DB 프로파일 관리: + - 등록된 DB 프로파일 목록 조회 및 표시 + - 새로운 DB 프로파일 추가 + - 기존 DB 프로파일 편집 및 삭제 +- DB 타입별 필드 동적 처리: + - 기본 필드: Host, Port, User, Database (또는 Path for DuckDB/SQLite) + - 추가 필드: Oracle(Service Name), Databricks(HTTP Path, Catalog, Schema), Snowflake(Account, Warehouse, Schema), Trino(HTTP Scheme, Catalog, Schema) + - 비밀 필드: Password 또는 Access Token (타입별 상이) +- 환경 변수 기반 자동 채우기 지원 +- 연결 테스트 기능 (SELECT 1 쿼리 실행) +- 설정 검증 및 세션 적용 기능 + +**주요 함수:** +- `render_db_section() -> None` + - DB 연결 설정 섹션을 Streamlit UI로 렌더링 + +**의존성:** +- `interface.core.config`: DB 연결 레지스트리 조작 +- `utils.databases.DatabaseFactory`: DB 커넥터 생성 및 연결 테스트 +- `utils.databases.factory.load_config_from_env`: 환경 변수에서 설정 로드 + +**헬퍼 함수:** +- `_non_secret_fields(db_type: str) -> list[tuple[str, str]]`: DB 타입별 기본 필드 정의 +- `_extra_non_secret_fields(db_type: str) -> list[tuple[str, str]]`: DB 타입별 추가 필드 정의 +- `_secret_fields(db_type: str) -> list[tuple[str, str]]`: DB 타입별 비밀 필드 정의 +- `_prefill_from_env(db_type: str, key: str) -> str`: 환경 변수에서 기본값 로드 + +### `llm_section.py` + +LLM 및 Embedding 설정을 관리하는 UI 섹션을 제공합니다. + +**주요 기능:** +- LLM 공급자 지원: + - OpenAI, Azure OpenAI, AWS Bedrock, Gemini, Ollama, Hugging Face +- Embedding 공급자 지원 (동일한 공급자 목록) +- 공급자별 필드 동적 처리: + - OpenAI: Model, API Key + - Azure: Endpoint, Deployment(Model), API Version, API Key + - Bedrock: Model, Access Key ID, Secret Access Key, Region + - Gemini: Model, API Key (embedding만) + - Ollama: Model, Base URL + - Hugging Face: Endpoint URL, Repo ID, Model, API Token (또는 Embedding: Model, Repo ID, API Token) +- 프로파일 저장 기능: + - LLM 프로파일 저장 (비밀키 제외 옵션) + - Embedding 프로파일 저장 (시크릿 포함) +- 저장된 프로파일 목록 조회 +- 환경 변수 및 세션 상태 기반 자동 채우기 + +**주요 함수:** +- `render_llm_section(config: Config | None = None) -> None` + - LLM 및 Embedding 설정 섹션을 Streamlit UI로 렌더링 + - 2개 컬럼으로 나뉘어 Chat LLM과 Embeddings를 각각 설정 + - `config` 파라미터가 없으면 내부에서 `load_config()`를 호출하거나 None 처리 + +**의존성:** +- `interface.core.config`: LLM/Embedding 설정 및 프로파일 관리 + +**헬퍼 함수:** +- `_llm_fields(provider: str) -> list[tuple[str, str, bool]]`: LLM 공급자별 필드 정의 (label, env_key, is_secret) +- `_embedding_fields(provider: str) -> list[tuple[str, str, bool]]`: Embedding 공급자별 필드 정의 + +## 사용 방법 + +이 모듈들은 `interface.app_pages.settings.py`에서 import되어 사용됩니다. + +### Import 예시 + +```python +from interface.app_pages.settings_sections.data_source_section import ( + render_data_source_section, +) +from interface.app_pages.settings_sections.llm_section import render_llm_section +from interface.app_pages.settings_sections.db_section import render_db_section +``` + +### 사용 예시 + +`settings.py`에서의 사용: + +```python +from interface.core.config import load_config + +config = load_config() + +tabs = st.tabs(["데이터 소스", "LLM", "DB"]) + +with tabs[0]: + render_data_source_section(config) + +with tabs[1]: + render_llm_section(config) + +with tabs[2]: + render_db_section() +``` + +### 함수 시그니처 + +#### `render_data_source_section(config: Config | None = None) -> None` +- **매개변수:** + - `config` (Config | None): 설정 객체. None이면 내부에서 `load_config()` 호출 +- **반환값:** None (Streamlit UI 직접 렌더링) + +#### `render_db_section() -> None` +- **매개변수:** 없음 +- **반환값:** None (Streamlit UI 직접 렌더링) + +#### `render_llm_section(config: Config | None = None) -> None` +- **매개변수:** + - `config` (Config | None): 설정 객체. None이면 내부에서 `load_config()` 호출하거나 None 처리 +- **반환값:** None (Streamlit UI 직접 렌더링) + +## 공통 특징 + +- 모든 섹션은 Streamlit을 사용하여 UI를 렌더링합니다. +- 설정 변경 시 `st.rerun()`을 호출하여 UI를 새로고침합니다. +- 에러 발생 시 `st.error()`를 사용하여 사용자에게 오류 메시지를 표시합니다. +- 성공적인 작업 완료 시 `st.success()`를 사용하여 확인 메시지를 표시합니다. +- 민감한 정보(비밀번호, API 키 등)는 `type="password"`를 사용하여 마스킹 처리합니다. + diff --git a/interface/app_pages/settings_sections/__init__.py b/interface/app_pages/settings_sections/__init__.py index 8b844eb..53cae96 100644 --- a/interface/app_pages/settings_sections/__init__.py +++ b/interface/app_pages/settings_sections/__init__.py @@ -4,6 +4,4 @@ "data_source_section", "llm_section", "db_section", - "vectordb_section", - "device_section", ] diff --git a/interface/app_pages/sidebar_components/README.md b/interface/app_pages/sidebar_components/README.md new file mode 100644 index 0000000..dab4f4e --- /dev/null +++ b/interface/app_pages/sidebar_components/README.md @@ -0,0 +1,297 @@ +# sidebar_components + +사이드바 UI 컴포넌트 모듈. Streamlit 애플리케이션의 사이드바에서 사용되는 설정 선택 및 관리 컴포넌트들을 제공합니다. + +## 디렉토리 구조 + +``` +sidebar_components/ +├── __init__.py +├── chatbot_session_controller.py +├── data_source_selector.py +├── db_selector.py +├── embedding_selector.py +└── llm_selector.py +``` + +## 파일 설명 + +### `__init__.py` + +모든 사이드바 컴포넌트 함수들을 모듈에서 export합니다. + +**Export되는 함수:** +- `render_sidebar_data_source_selector`: 데이터 소스 선택기 렌더링 +- `render_sidebar_llm_selector`: LLM 선택기 렌더링 +- `render_sidebar_embedding_selector`: Embeddings 선택기 렌더링 +- `render_sidebar_db_selector`: DB 연결 선택기 렌더링 +- `render_sidebar_chatbot_session_controller`: ChatBot 세션 컨트롤러 렌더링 + +**사용 예시:** +```python +from interface.app_pages.sidebar_components import ( + render_sidebar_data_source_selector, + render_sidebar_llm_selector, + render_sidebar_embedding_selector, + render_sidebar_db_selector, + render_sidebar_chatbot_session_controller, +) +``` + +--- + +### `chatbot_session_controller.py` + +ChatBot 세션 관리 및 대화 기록 표시를 위한 사이드바 컴포넌트입니다. + +**주요 기능:** +- 세션 ID 자동 생성 및 관리 (`chatbot_thread_id`) +- 새 세션 시작 버튼 +- 대화 기록 표시 (JSON 형식) +- 최근 메시지 미리보기 (최근 3개) + +**함수:** +```python +def render_sidebar_chatbot_session_controller() -> str +``` + +**반환값:** +- `str`: 현재 thread_id + +**사용 예시:** +```python +from interface.app_pages.sidebar_components import render_sidebar_chatbot_session_controller + +thread_id = render_sidebar_chatbot_session_controller() +``` + +**의존성:** +- `streamlit`: UI 렌더링 +- `uuid`: 세션 ID 생성 +- `st.session_state`: 세션 상태 관리 + - `chatbot_thread_id`: 현재 세션 ID + - `chatbot_messages`: 대화 기록 리스트 + +**사용처:** +- `/home/dwlee/Lang2SQL/interface/app_pages/chatbot.py` (line 112) + +--- + +### `data_source_selector.py` + +데이터 소스 선택 컴포넌트입니다. DataHub 또는 VectorDB 중 하나를 선택하고 설정을 적용할 수 있습니다. + +**주요 기능:** +- DataHub/VectorDB 모드 선택 (라디오 버튼) +- DataHub 인스턴스 선택 및 적용 +- VectorDB 인스턴스 선택 및 적용 +- FAISS 경로 자동 적용 (DataHub 선택 시) + +**함수:** +```python +def render_sidebar_data_source_selector(config=None) -> None +``` + +**매개변수:** +- `config` (optional): 설정 객체. None인 경우 내부에서 `load_config()`로 로드합니다. + +**사용 예시:** +```python +from interface.app_pages.sidebar_components import render_sidebar_data_source_selector +from interface.core.config import load_config + +config = load_config() +render_sidebar_data_source_selector(config) +``` + +**의존성:** +- `streamlit`: UI 렌더링 +- `interface.core.config`: + - `load_config()`: 설정 로드 + - `get_data_sources_registry()`: 데이터 소스 레지스트리 조회 + - `update_datahub_server()`: DataHub 서버 설정 업데이트 + - `update_vectordb_settings()`: VectorDB 설정 업데이트 + - `update_data_source_mode()`: 데이터 소스 모드 업데이트 + +**사용처:** +- `/home/dwlee/Lang2SQL/interface/app_pages/chatbot.py` (line 99) +- `/home/dwlee/Lang2SQL/interface/app_pages/lang2sql.py` (line 50) + +--- + +### `db_selector.py` + +데이터베이스 연결 프로파일 선택 컴포넌트입니다. + +**주요 기능:** +- 등록된 DB 프로파일 목록 표시 +- 프로파일 선택 및 적용 +- 세션 또는 환경 변수의 DB_TYPE과 일치하는 프로파일 자동 선택 + +**함수:** +```python +def render_sidebar_db_selector() -> None +``` + +**사용 예시:** +```python +from interface.app_pages.sidebar_components import render_sidebar_db_selector + +render_sidebar_db_selector() +``` + +**의존성:** +- `streamlit`: UI 렌더링 +- `os`: 환경 변수 조회 +- `interface.core.config`: + - `get_db_connections_registry()`: DB 연결 레지스트리 조회 + - `update_db_settings()`: DB 설정 업데이트 +- `st.session_state.get("DB_TYPE")`: 세션의 DB 타입 확인 +- `os.getenv("DB_TYPE")`: 환경 변수에서 DB 타입 확인 + +**사용처:** +- `/home/dwlee/Lang2SQL/interface/app_pages/chatbot.py` (line 105) +- `/home/dwlee/Lang2SQL/interface/app_pages/lang2sql.py` (line 56) + +--- + +### `embedding_selector.py` + +Embeddings 프로파일 선택 컴포넌트입니다. + +**주요 기능:** +- 등록된 Embeddings 프로파일 목록 표시 +- 프로파일 선택 및 적용 +- 프로파일이 없는 경우 공급자 직접 선택 (fallback 모드) +- 지원 공급자: openai, azure, bedrock, gemini, ollama, huggingface + +**함수:** +```python +def render_sidebar_embedding_selector() -> None +``` + +**사용 예시:** +```python +from interface.app_pages.sidebar_components import render_sidebar_embedding_selector + +render_sidebar_embedding_selector() +``` + +**의존성:** +- `streamlit`: UI 렌더링 +- `os`: 환경 변수 조회 +- `interface.core.config`: + - `get_embedding_registry()`: Embeddings 레지스트리 조회 + - `update_embedding_settings()`: Embeddings 설정 업데이트 +- `st.session_state.get("EMBEDDING_PROVIDER")`: 세션의 Embeddings 공급자 확인 +- `os.getenv("EMBEDDING_PROVIDER")`: 환경 변수에서 Embeddings 공급자 확인 + +**사용처:** +- `/home/dwlee/Lang2SQL/interface/app_pages/chatbot.py` (line 103) +- `/home/dwlee/Lang2SQL/interface/app_pages/lang2sql.py` (line 54) + +--- + +### `llm_selector.py` + +LLM 프로파일 선택 컴포넌트입니다. + +**주요 기능:** +- 등록된 LLM 프로파일 목록 표시 +- 프로파일 선택 및 적용 +- 프로파일이 없는 경우 공급자 직접 선택 (fallback 모드) +- 지원 공급자: openai, azure, bedrock, gemini, ollama, huggingface + +**함수:** +```python +def render_sidebar_llm_selector() -> None +``` + +**사용 예시:** +```python +from interface.app_pages.sidebar_components import render_sidebar_llm_selector + +render_sidebar_llm_selector() +``` + +**의존성:** +- `streamlit`: UI 렌더링 +- `os`: 환경 변수 조회 +- `interface.core.config`: + - `get_llm_registry()`: LLM 레지스트리 조회 + - `update_llm_settings()`: LLM 설정 업데이트 +- `st.session_state.get("LLM_PROVIDER")`: 세션의 LLM 공급자 확인 +- `os.getenv("LLM_PROVIDER")`: 환경 변수에서 LLM 공급자 확인 + +**사용처:** +- `/home/dwlee/Lang2SQL/interface/app_pages/chatbot.py` (line 101) +- `/home/dwlee/Lang2SQL/interface/app_pages/lang2sql.py` (line 52) + +--- + +## 전체 사용 예시 + +### chatbot.py에서의 사용 + +```python +from interface.app_pages.sidebar_components import ( + render_sidebar_data_source_selector, + render_sidebar_llm_selector, + render_sidebar_embedding_selector, + render_sidebar_db_selector, + render_sidebar_chatbot_session_controller, +) +from interface.core.config import load_config + +config = load_config() + +# 사이드바 UI 구성 +render_sidebar_data_source_selector(config) +st.sidebar.divider() +render_sidebar_llm_selector() +st.sidebar.divider() +render_sidebar_embedding_selector() +st.sidebar.divider() +render_sidebar_db_selector() +st.sidebar.divider() + +# ChatBot 전용 설정 +with st.sidebar: + st.markdown("### 🤖 ChatBot 설정") + st.divider() + thread_id = render_sidebar_chatbot_session_controller() +``` + +### lang2sql.py에서의 사용 + +```python +from interface.app_pages.sidebar_components import ( + render_sidebar_data_source_selector, + render_sidebar_llm_selector, + render_sidebar_embedding_selector, + render_sidebar_db_selector, +) +from interface.core.config import load_config + +config = load_config() + +render_sidebar_data_source_selector(config) +st.sidebar.divider() +render_sidebar_llm_selector() +st.sidebar.divider() +render_sidebar_embedding_selector() +st.sidebar.divider() +render_sidebar_db_selector() +st.sidebar.divider() +``` + +## 공통 패턴 + +모든 컴포넌트는 다음과 같은 공통 패턴을 따릅니다: + +1. **레지스트리 기반**: 각 컴포넌트는 해당 설정의 레지스트리(`get_*_registry()`)에서 프로파일/인스턴스 목록을 가져옵니다. +2. **Fallback 지원**: 프로파일이 없는 경우 기본 공급자 선택 옵션을 제공합니다. +3. **세션/환경 변수 통합**: 현재 세션 상태 또는 환경 변수와 일치하는 항목을 자동으로 선택합니다. +4. **설정 업데이트**: 선택한 항목을 적용하면 `update_*_settings()` 함수를 통해 설정을 업데이트합니다. +5. **에러 처리**: 적용 실패 시 `st.sidebar.error()`로 에러 메시지를 표시합니다. + diff --git a/utils/data/README.md b/utils/data/README.md new file mode 100644 index 0000000..f9294c4 --- /dev/null +++ b/utils/data/README.md @@ -0,0 +1,449 @@ +# utils/data 패키지 + +DataHub와의 상호작용을 위한 데이터 관련 유틸리티 패키지입니다. + +## 디렉토리 구조 + +``` +utils/data/ +├── __pycache__/ +├── datahub_services/ +│ ├── __pycache__/ +│ ├── base_client.py # 기본 클라이언트 +│ ├── glossary_service.py # 용어집 서비스 +│ ├── metadata_service.py # 메타데이터 서비스 +│ ├── query_service.py # 쿼리 서비스 +│ ├── __init__.py # 패키지 초기화 및 exports +│ └── README.md # 서비스 상세 문서 +├── datahub_source.py # 통합 메타데이터 페처 +└── queries.py # GraphQL 쿼리 모음 +``` + +## 파일별 상세 내용 + +### `datahub_source.py` + +DataHub 메타데이터 페처 - 리팩토링된 버전으로 기존 `DatahubMetadataFetcher`의 모든 기능을 유지하면서 내부적으로는 분리된 서비스 모듈들을 사용합니다. + +**클래스:** +- `DatahubMetadataFetcher`: 기존 인터페이스를 유지하는 통합 페처 + +**초기화:** +```python +from utils.data.datahub_source import DatahubMetadataFetcher + +fetcher = DatahubMetadataFetcher(gms_server="http://localhost:8080", extra_headers={}) +``` + +**주요 메서드:** + +#### 메타데이터 관련 메서드 + +##### `get_urns()` +필터를 적용하여 데이터셋의 URN 목록을 가져옵니다. + +**반환값:** +- URN 목록 + +##### `get_table_name(urn)` +URN에 대한 테이블 이름을 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**반환값:** +- `str`: 테이블 이름 (database.table 형태) 또는 None + +##### `get_table_description(urn)` +URN에 대한 테이블 설명을 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**반환값:** +- `str`: 테이블 설명 또는 None + +##### `get_column_names_and_descriptions(urn)` +URN에 대한 컬럼 이름 및 설명을 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**반환값:** +- `list`: 컬럼 정보 리스트 (각 항목: column_name, column_description, column_type) + +##### `get_table_lineage(urn, counts=100, direction="DOWNSTREAM", degree_values=None)` +URN에 대한 DOWNSTREAM/UPSTREAM lineage entity를 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN +- `counts` (int): 가져올 엔티티 수 (기본값: 100) +- `direction` (str): 리니지 방향 ("DOWNSTREAM" 또는 "UPSTREAM", 기본값: "DOWNSTREAM") +- `degree_values` (list): 필터링할 degree 값 리스트 (기본값: ["1", "2"]) + +**반환값:** +- `tuple`: (urn, lineage_result) + +##### `get_column_lineage(urn)` +URN에 대한 UPSTREAM lineage의 column source를 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**반환값:** +- `dict`: 컬럼 리니지 정보 + - `downstream_dataset`: 다운스트림 데이터셋 이름 + - `lineage_by_upstream_dataset`: 업스트림 데이터셋별 컬럼 매핑 + +##### `min_degree_lineage(lineage_result)` +lineage 중 최소 degree만 가져옵니다. + +**파라미터:** +- `lineage_result`: `get_table_lineage`의 반환값 + +**반환값:** +- `dict`: 테이블별 최소 degree 매핑 + +##### `build_table_metadata(urn, max_degree=2, sort_by_degree=True)` +테이블 단위로 통합 메타데이터를 생성합니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN +- `max_degree` (int): 최대 degree 제한 (기본값: 2) +- `sort_by_degree` (bool): degree 기준 정렬 여부 (기본값: True) + +**반환값:** +- `dict`: 통합 메타데이터 + - `table_name`: 테이블 이름 + - `description`: 테이블 설명 + - `columns`: 컬럼 정보 리스트 + - `lineage`: 리니지 정보 + +##### `get_urn_info(urn)` +특정 URN에 대한 모든 관련 정보를 가져옵니다. + +**파라미터:** +- `urn` (str): 조회할 데이터셋 URN + +**반환값:** +- `dict`: URN에 대한 전체 메타데이터 정보 + +##### `_print_urn_details(metadata)` +URN 메타데이터를 보기 좋게 출력하는 내부 함수입니다. + +#### 용어집 관련 메서드 + +##### `get_root_glossary_nodes()` +DataHub에서 루트 용어집 노드를 가져옵니다. + +**반환값:** +- `dict`: 루트 용어집 노드 정보 + +##### `get_glossary_node_by_urn(urn)` +특정 URN의 용어집 노드 및 그 자식 항목을 가져옵니다. + +**파라미터:** +- `urn` (str): 용어집 노드의 URN + +**반환값:** +- `dict`: 용어집 노드 정보와 자식 항목 + +##### `get_node_basic_info(node, index)` +용어집 노드의 기본 정보를 딕셔너리로 반환합니다. + +**파라미터:** +- `node` (dict): 용어집 노드 정보 +- `index` (int): 노드의 인덱스 + +**반환값:** +- `dict`: 노드의 기본 정보 + +##### `get_child_entity_info(entity, index)` +자식 엔티티(용어 또는 노드)의 정보를 딕셔너리로 반환합니다. + +**파라미터:** +- `entity` (dict): 자식 엔티티 정보 +- `index` (int): 엔티티의 인덱스 + +**반환값:** +- `dict`: 엔티티 정보 + +##### `process_node_details(node)` +노드의 상세 정보를 처리하고 딕셔너리로 반환합니다. + +**파라미터:** +- `node` (dict): 용어집 노드 정보 + +**반환값:** +- `dict`: 노드의 상세 정보 + +##### `process_glossary_nodes(result)` +용어집 노드 결과를 처리하고 딕셔너리로 반환합니다. + +**파라미터:** +- `result` (dict): API 응답 결과 + +**반환값:** +- `dict`: 처리된 용어집 노드 데이터 + +##### `get_glossary_data()` +DataHub에서 전체 용어집 데이터를 가져와 처리합니다. + +**반환값:** +- `dict`: 처리된 용어집 데이터 + +##### `get_glossary_terms_by_urn(dataset_urn)` +특정 데이터셋 URN의 glossary terms를 조회합니다. + +**파라미터:** +- `dataset_urn` (str): 데이터셋 URN + +**반환값:** +- `dict`: glossary terms 정보 + +#### 쿼리 관련 메서드 + +##### `get_queries(start=0, count=10, query="*", filters=None)` +DataHub에서 쿼리 목록을 가져옵니다. + +**파라미터:** +- `start` (int): 시작 인덱스 (기본값: 0) +- `count` (int): 반환할 쿼리 수 (기본값: 10) +- `query` (str): 필터링에 사용할 쿼리 문자열 (기본값: "*") +- `filters` (list): 추가 필터 (기본값: None) + +**반환값:** +- `dict`: 쿼리 목록 정보 + +##### `process_queries(result)` +쿼리 목록 결과를 처리하고 간소화된 형태로 반환합니다. + +**파라미터:** +- `result` (dict): API 응답 결과 + +**반환값:** +- `dict`: 처리된 쿼리 목록 데이터 + +##### `get_query_data(start=0, count=10, query="*", filters=None)` +DataHub에서 쿼리 목록을 가져와 처리합니다. + +**파라미터:** +- `start` (int): 시작 인덱스 (기본값: 0) +- `count` (int): 반환할 쿼리 수 (기본값: 10) +- `query` (str): 필터링에 사용할 쿼리 문자열 (기본값: "*") +- `filters` (list): 추가 필터 (기본값: None) + +**반환값:** +- `dict`: 처리된 쿼리 목록 데이터 + +##### `get_queries_by_urn(dataset_urn)` +특정 데이터셋 URN과 연관된 쿼리들을 조회합니다. + +**파라미터:** +- `dataset_urn` (str): 데이터셋 URN + +**반환값:** +- `dict`: 연관된 쿼리 목록 + +**의존성:** +- `utils.data.datahub_services.base_client.DataHubBaseClient`: 기본 클라이언트 +- `utils.data.datahub_services.metadata_service.MetadataService`: 메타데이터 서비스 +- `utils.data.datahub_services.query_service.QueryService`: 쿼리 서비스 +- `utils.data.datahub_services.glossary_service.GlossaryService`: 용어집 서비스 + +**사용 예시:** +```python +from utils.data.datahub_source import DatahubMetadataFetcher + +# 페처 초기화 +fetcher = DatahubMetadataFetcher(gms_server="http://localhost:8080") + +# 테이블 메타데이터 조회 +urn = "urn:li:dataset:(urn:li:dataPlatform:postgres,db.schema.table,TABLE)" +metadata = fetcher.get_urn_info(urn) + +# 용어집 조회 +glossary_data = fetcher.get_glossary_data() + +# 쿼리 조회 +queries = fetcher.get_query_data(start=0, count=10) +``` + +**import 되어 사용되는 위치:** +- `utils/llm/tools/datahub.py`: `from utils.data.datahub_source import DatahubMetadataFetcher` + +--- + +### `queries.py` + +DataHub GraphQL 쿼리 모음 파일입니다. DataHub GMS 서버와 통신하기 위한 모든 GraphQL 쿼리 문자열을 포함합니다. + +**주요 쿼리:** + +#### `ROOT_GLOSSARY_NODES_QUERY` +루트 용어집 노드를 조회하는 쿼리입니다. 4단계 계층 구조까지 포함합니다. + +**사용 위치:** +- `utils.data.datahub_services.glossary_service.GlossaryService.get_root_glossary_nodes()` + +#### `GLOSSARY_NODE_QUERY` +특정 URN의 용어집 노드 상세 정보를 조회하는 쿼리입니다. 자식 노드, 용어, 소유권, 권한 등의 상세 정보를 포함합니다. + +**파라미터:** +- `urn` (str): 용어집 노드 URN + +**사용 위치:** +- `utils.data.datahub_services.glossary_service.GlossaryService.get_glossary_node_by_urn()` + +#### `LIST_QUERIES_QUERY` +쿼리 목록을 조회하는 쿼리입니다. URN, 이름, 설명, SQL 문, 데이터셋 정보 등을 포함합니다. + +**파라미터:** +- `input` (dict): ListQueriesInput + - `start` (int): 시작 인덱스 + - `count` (int): 반환할 항목 수 + - `query` (str): 검색 쿼리 + - `filters` (list, optional): 추가 필터 + +**사용 위치:** +- `utils.data.datahub_services.query_service.QueryService.get_queries()` + +#### `QUERIES_BY_URN_QUERY` +특정 URN과 연관된 쿼리를 조회하는 단순화된 쿼리입니다. + +**파라미터:** +- `input` (dict): ListQueriesInput + +**사용 위치:** +- `utils.data.datahub_services.query_service.QueryService.get_queries_by_urn()` + +#### `GLOSSARY_TERMS_BY_URN_QUERY` +특정 데이터셋 URN의 glossary terms를 조회하는 쿼리입니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**사용 위치:** +- `utils.data.datahub_services.glossary_service.GlossaryService.get_glossary_terms_by_urn()` +- `utils.data.datahub_services.query_service.QueryService.get_glossary_terms_by_urn()` + +**import 되어 사용되는 위치:** +- `utils.data.datahub_services.glossary_service`: `from utils.data.queries import ...` +- `utils.data.datahub_services.query_service`: `from utils.data.queries import ...` + +--- + +### `datahub_services/` + +DataHub와의 상호작용을 위한 서비스 모듈들을 제공하는 서브패키지입니다. + +**주요 구성요소:** +- `base_client.py`: 기본 연결 및 통신 +- `glossary_service.py`: 용어집 서비스 +- `metadata_service.py`: 메타데이터 서비스 +- `query_service.py`: 쿼리 서비스 +- `__init__.py`: 패키지 초기화 및 exports + +상세한 문서는 [datahub_services/README.md](datahub_services/README.md)를 참조하세요. + +--- + +## 전체 사용 예시 + +### 예시 1: 기본 사용법 + +```python +from utils.data.datahub_source import DatahubMetadataFetcher + +# 페처 초기화 +fetcher = DatahubMetadataFetcher(gms_server="http://localhost:8080") + +# 테이블 메타데이터 조회 +urn = "urn:li:dataset:(urn:li:dataPlatform:postgres,db.schema.table,TABLE)" +metadata = fetcher.get_urn_info(urn) + +# 용어집 조회 +glossary_data = fetcher.get_glossary_data() + +# 쿼리 조회 +queries = fetcher.get_query_data(start=0, count=10) +``` + +### 예시 2: 분리된 서비스 사용 + +```python +from utils.data.datahub_services import ( + DataHubBaseClient, + MetadataService, + QueryService, + GlossaryService +) + +# 클라이언트 초기화 +client = DataHubBaseClient(gms_server="http://localhost:8080") + +# 서비스 초기화 +metadata_service = MetadataService(client) +query_service = QueryService(client) +glossary_service = GlossaryService(client) + +# 메타데이터 조회 +urn = "urn:li:dataset:(...)" +metadata = metadata_service.build_table_metadata(urn) + +# 쿼리 조회 +queries = query_service.get_query_data(start=0, count=10) + +# 용어집 조회 +glossary_data = glossary_service.get_glossary_data() +``` + +### 예시 3: 개별 메서드 사용 + +```python +from utils.data.datahub_source import DatahubMetadataFetcher + +fetcher = DatahubMetadataFetcher(gms_server="http://localhost:8080") + +# 테이블 정보 조회 +urn = "urn:li:dataset:(...)" +table_name = fetcher.get_table_name(urn) +description = fetcher.get_table_description(urn) +columns = fetcher.get_column_names_and_descriptions(urn) + +# 리니지 조회 +downstream_lineage = fetcher.get_table_lineage(urn, direction="DOWNSTREAM") +upstream_lineage = fetcher.get_table_lineage(urn, direction="UPSTREAM") +column_lineage = fetcher.get_column_lineage(urn) + +# 최소 degree 필터링 +min_degree = fetcher.min_degree_lineage(downstream_lineage) +``` + +--- + +## 의존성 + +### 외부 패키지 +- `requests`: HTTP 요청 처리 +- `datahub`: DataHub Python SDK + - `datahub.emitter.rest_emitter.DatahubRestEmitter` + - `datahub.ingestion.graph.client.DatahubClientConfig` + - `datahub.ingestion.graph.client.DataHubGraph` + - `datahub.metadata.schema_classes` + +### 내부 패키지 +- `utils.data.queries`: GraphQL 쿼리 정의 모듈 +- `utils.data.datahub_services.*`: DataHub 서비스 레이어 + +--- + +## 참고 사항 + +1. `DatahubMetadataFetcher`는 하위 호환성을 위해 분리된 서비스들을 내부적으로 사용합니다. +2. 모든 서비스는 `DataHubBaseClient`를 필요로 합니다. +3. GMS 서버 URL은 초기화 시 유효성 검사가 수행됩니다. +4. GraphQL 쿼리는 `queries.py`에 중앙 집중식으로 정의되어 있습니다. +5. 오류 발생 시 dict 형태로 `{"error": True, "message": "..."}` 구조로 반환됩니다. +6. `utils/llm/tools/datahub.py`에서 `DatahubMetadataFetcher`를 import하여 LLM 도구로 사용됩니다. + diff --git a/utils/data/datahub_services/README.md b/utils/data/datahub_services/README.md new file mode 100644 index 0000000..203c305 --- /dev/null +++ b/utils/data/datahub_services/README.md @@ -0,0 +1,527 @@ +# DataHub Services 패키지 + +DataHub와의 상호작용을 위한 서비스 모듈들을 제공하는 패키지입니다. + +## 디렉토리 구조 + +``` +datahub_services/ +├── __init__.py # 패키지 초기화 및 exports +├── base_client.py # 기본 클라이언트 +├── glossary_service.py # 용어집 서비스 +├── metadata_service.py # 메타데이터 서비스 +└── query_service.py # 쿼리 서비스 +``` + +## 파일별 상세 내용 + +### `__init__.py` + +패키지의 진입점이며, 주요 서비스 클래스들을 export합니다. + +**Export되는 클래스:** +- `DataHubBaseClient`: 기본 연결 및 통신 클라이언트 +- `MetadataService`: 메타데이터, 리니지, URN 관련 서비스 +- `QueryService`: 쿼리 관련 서비스 +- `GlossaryService`: 용어집 관련 서비스 + +**사용 방법:** +```python +from utils.data.datahub_services import ( + DataHubBaseClient, + MetadataService, + QueryService, + GlossaryService +) + +# 클라이언트 초기화 +client = DataHubBaseClient(gms_server="http://localhost:8080") + +# 서비스 초기화 +metadata_service = MetadataService(client) +query_service = QueryService(client) +glossary_service = GlossaryService(client) +``` + +--- + +### `base_client.py` + +DataHub GMS 서버와의 기본 연결 및 통신 기능을 제공하는 클라이언트입니다. + +**클래스:** +- `DataHubBaseClient` + +**주요 메서드:** + +#### `__init__(self, gms_server="http://localhost:8080", extra_headers={})` +DataHub 클라이언트를 초기화합니다. + +**파라미터:** +- `gms_server` (str): DataHub GMS 서버 URL +- `extra_headers` (dict): 추가 HTTP 헤더 + +**사용 예시:** +```python +from utils.data.datahub_services import DataHubBaseClient + +client = DataHubBaseClient(gms_server="http://localhost:8080") +``` + +#### `_is_valid_gms_server(self, gms_server)` +GMS 서버 주소의 유효성을 검사합니다. + +**파라미터:** +- `gms_server` (str): 검사할 GMS 서버 URL + +**반환값:** +- `bool`: 서버가 유효한 경우 True + +#### `execute_graphql_query(self, query, variables=None)` +GraphQL 쿼리를 실행합니다. + +**파라미터:** +- `query` (str): GraphQL 쿼리 문자열 +- `variables` (dict, optional): 쿼리 변수 + +**반환값:** +- `dict`: GraphQL 응답 또는 오류 정보 + +**사용 예시:** +```python +query = "{ health { status } }" +result = client.execute_graphql_query(query) +``` + +#### `get_datahub_graph(self)` +DataHub Graph 클라이언트를 반환합니다. + +**반환값:** +- DataHub Graph 객체 + +#### `get_urns(self)` +필터를 적용하여 데이터셋의 URN 목록을 가져옵니다. + +**반환값:** +- URN 목록 + +**의존성:** +- `requests`: HTTP 요청 처리 +- `datahub.emitter.rest_emitter.DatahubRestEmitter`: DataHub REST emitter + +--- + +### `glossary_service.py` + +DataHub의 용어집(Glossary) 관련 기능을 제공하는 서비스입니다. + +**클래스:** +- `GlossaryService` + +**초기화:** +```python +from utils.data.datahub_services import DataHubBaseClient, GlossaryService + +client = DataHubBaseClient(gms_server="http://localhost:8080") +glossary_service = GlossaryService(client) +``` + +**주요 메서드:** + +#### `get_root_glossary_nodes(self)` +DataHub에서 루트 용어집 노드를 가져옵니다. + +**반환값:** +- `dict`: 루트 용어집 노드 정보 + +#### `get_glossary_node_by_urn(self, urn)` +특정 URN의 용어집 노드 및 그 자식 항목을 가져옵니다. + +**파라미터:** +- `urn` (str): 용어집 노드의 URN + +**반환값:** +- `dict`: 용어집 노드 정보와 자식 항목 + +#### `get_node_basic_info(self, node, index)` +용어집 노드의 기본 정보를 딕셔너리로 반환합니다. + +**파라미터:** +- `node` (dict): 용어집 노드 정보 +- `index` (int): 노드의 인덱스 + +**반환값:** +- `dict`: 노드의 기본 정보 (index, name, description, child_count 등) + +#### `get_child_entity_info(self, entity, index)` +자식 엔티티(용어 또는 노드)의 정보를 딕셔너리로 반환합니다. + +**파라미터:** +- `entity` (dict): 자식 엔티티 정보 +- `index` (int): 엔티티의 인덱스 + +**반환값:** +- `dict`: 엔티티 정보 (index, type, name, description 등) + +#### `process_node_details(self, node)` +노드의 상세 정보를 처리하고 딕셔너리로 반환합니다. + +**파라미터:** +- `node` (dict): 용어집 노드 정보 + +**반환값:** +- `dict`: 노드의 상세 정보 (name, children 등) + +#### `process_glossary_nodes(self, result)` +용어집 노드 결과를 처리하고 딕셔너리로 반환합니다. + +**파라미터:** +- `result` (dict): API 응답 결과 + +**반환값:** +- `dict`: 처리된 용어집 노드 데이터 (total_nodes, nodes) + +#### `get_glossary_data(self)` +DataHub에서 전체 용어집 데이터를 가져와 처리합니다. + +**반환값:** +- `dict`: 처리된 용어집 데이터 또는 오류 정보 + +**사용 예시:** +```python +result = glossary_service.get_glossary_data() +print(f"전체 노드 수: {result['total_nodes']}") +for node in result['nodes']: + print(f" - {node['name']}: {node.get('description', 'N/A')}") +``` + +#### `get_glossary_terms_by_urn(self, dataset_urn)` +특정 데이터셋 URN의 glossary terms를 조회합니다. + +**파라미터:** +- `dataset_urn` (str): 데이터셋 URN + +**반환값:** +- `dict`: glossary terms 정보 + +**의존성:** +- `utils.data.datahub_services.base_client.DataHubBaseClient`: 기본 클라이언트 +- `utils.data.queries`: GraphQL 쿼리 정의 + - `GLOSSARY_NODE_QUERY` + - `GLOSSARY_TERMS_BY_URN_QUERY` + - `ROOT_GLOSSARY_NODES_QUERY` + +--- + +### `metadata_service.py` + +테이블 메타데이터, 리니지, URN 관련 기능을 제공하는 서비스입니다. + +**클래스:** +- `MetadataService` + +**초기화:** +```python +from utils.data.datahub_services import DataHubBaseClient, MetadataService + +client = DataHubBaseClient(gms_server="http://localhost:8080") +metadata_service = MetadataService(client) +``` + +**주요 메서드:** + +#### `get_table_name(self, urn)` +URN에 대한 테이블 이름을 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**반환값:** +- `str`: 테이블 이름 (database.table 형태) 또는 None + +#### `get_table_description(self, urn)` +URN에 대한 테이블 설명을 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**반환값:** +- `str`: 테이블 설명 또는 None + +#### `get_column_names_and_descriptions(self, urn)` +URN에 대한 컬럼 이름 및 설명을 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**반환값:** +- `list`: 컬럼 정보 리스트 (각 항목: column_name, column_description, column_type) + +#### `get_table_lineage(self, urn, counts=100, direction="DOWNSTREAM", degree_values=None)` +URN에 대한 DOWNSTREAM/UPSTREAM lineage entity를 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN +- `counts` (int): 가져올 엔티티 수 (기본값: 100) +- `direction` (str): 리니지 방향 ("DOWNSTREAM" 또는 "UPSTREAM", 기본값: "DOWNSTREAM") +- `degree_values` (list): 필터링할 degree 값 리스트 (기본값: ["1", "2"]) + +**반환값:** +- `tuple`: (urn, lineage_result) + +#### `get_column_lineage(self, urn)` +URN에 대한 UPSTREAM lineage의 column source를 가져옵니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN + +**반환값:** +- `dict`: 컬럼 리니지 정보 + - `downstream_dataset`: 다운스트림 데이터셋 이름 + - `lineage_by_upstream_dataset`: 업스트림 데이터셋별 컬럼 매핑 + - `upstream_dataset`: 업스트림 데이터셋 이름 + - `columns`: 컬럼 매핑 리스트 + - `upstream_column`: 업스트림 컬럼 + - `downstream_column`: 다운스트림 컬럼 + - `confidence`: 신뢰도 + +#### `min_degree_lineage(self, lineage_result)` +lineage 중 최소 degree만 가져옵니다. + +**파라미터:** +- `lineage_result`: `get_table_lineage`의 반환값 + +**반환값:** +- `dict`: 테이블별 최소 degree 매핑 + +#### `build_table_metadata(self, urn, max_degree=2, sort_by_degree=True)` +테이블 단위로 통합 메타데이터를 생성합니다. + +**파라미터:** +- `urn` (str): 데이터셋 URN +- `max_degree` (int): 최대 degree 제한 (기본값: 2) +- `sort_by_degree` (bool): degree 기준 정렬 여부 (기본값: True) + +**반환값:** +- `dict`: 통합 메타데이터 + - `table_name`: 테이블 이름 + - `description`: 테이블 설명 + - `columns`: 컬럼 정보 리스트 + - `lineage`: 리니지 정보 + - `downstream`: 다운스트림 테이블 리스트 + - `upstream`: 업스트림 테이블 리스트 + - `upstream_columns`: 컬럼 레벨 리니지 + +**사용 예시:** +```python +metadata = metadata_service.build_table_metadata(urn) +print(f"테이블: {metadata['table_name']}") +print(f"컬럼 수: {len(metadata['columns'])}") +print(f"다운스트림: {len(metadata['lineage']['downstream'])}개") +print(f"업스트림: {len(metadata['lineage']['upstream'])}개") +``` + +#### `get_urn_info(self, urn)` +특정 URN에 대한 모든 관련 정보를 가져옵니다. + +**파라미터:** +- `urn` (str): 조회할 데이터셋 URN + +**반환값:** +- `dict`: URN에 대한 전체 메타데이터 정보 또는 오류 정보 + +**사용 예시:** +```python +result = metadata_service.get_urn_info(urn) +# 콘솔에 자동으로 포맷된 정보 출력 및 반환 +``` + +**의존성:** +- `collections.defaultdict`: 딕셔너리 기본값 처리 +- `datahub.ingestion.graph.client`: DataHub Graph 클라이언트 + - `DatahubClientConfig` + - `DataHubGraph` +- `datahub.metadata.schema_classes`: DataHub 메타데이터 스키마 클래스 + - `DatasetPropertiesClass` + - `SchemaMetadataClass` + - `UpstreamLineageClass` +- `utils.data.datahub_services.base_client.DataHubBaseClient`: 기본 클라이언트 + +--- + +### `query_service.py` + +DataHub의 쿼리 관련 기능을 제공하는 서비스입니다. + +**클래스:** +- `QueryService` + +**초기화:** +```python +from utils.data.datahub_services import DataHubBaseClient, QueryService + +client = DataHubBaseClient(gms_server="http://localhost:8080") +query_service = QueryService(client) +``` + +**주요 메서드:** + +#### `get_queries(self, start=0, count=10, query="*", filters=None)` +DataHub에서 쿼리 목록을 가져옵니다. + +**파라미터:** +- `start` (int): 시작 인덱스 (기본값: 0) +- `count` (int): 반환할 쿼리 수 (기본값: 10) +- `query` (str): 필터링에 사용할 쿼리 문자열 (기본값: "*") +- `filters` (list): 추가 필터 (기본값: None) + +**반환값:** +- `dict`: 쿼리 목록 정보 + +#### `process_queries(self, result)` +쿼리 목록 결과를 처리하고 간소화된 형태로 반환합니다. + +**파라미터:** +- `result` (dict): API 응답 결과 + +**반환값:** +- `dict`: 처리된 쿼리 목록 데이터 + - `total_queries`: 전체 쿼리 수 + - `count`: 조회된 쿼리 수 + - `start`: 시작 인덱스 + - `queries`: 쿼리 리스트 (urn, name, description, statement 포함) + +#### `get_query_data(self, start=0, count=10, query="*", filters=None)` +DataHub에서 쿼리 목록을 가져와 처리합니다. + +**파라미터:** +- `start` (int): 시작 인덱스 (기본값: 0) +- `count` (int): 반환할 쿼리 수 (기본값: 10) +- `query` (str): 필터링에 사용할 쿼리 문자열 (기본값: "*") +- `filters` (list): 추가 필터 (기본값: None) + +**반환값:** +- `dict`: 처리된 쿼리 목록 데이터 또는 오류 정보 + +**사용 예시:** +```python +result = query_service.get_query_data(start=0, count=5, query="*") +print(f"전체 쿼리 수: {result['total_queries']}") +for idx, q in enumerate(result['queries'], 1): + print(f"{idx}. {q['name']}: {q.get('description', 'N/A')}") +``` + +#### `get_queries_by_urn(self, dataset_urn)` +특정 데이터셋 URN과 연관된 쿼리들을 조회합니다. + +**파라미터:** +- `dataset_urn` (str): 데이터셋 URN + +**반환값:** +- `dict`: 연관된 쿼리 목록 + +**주의:** 전체 쿼리를 가져온 후 클라이언트 사이드에서 필터링하는 방식 사용 + +#### `get_glossary_terms_by_urn(self, dataset_urn)` +특정 데이터셋 URN의 glossary terms를 조회합니다. + +**파라미터:** +- `dataset_urn` (str): 데이터셋 URN + +**반환값:** +- `dict`: glossary terms 정보 + +**의존성:** +- `utils.data.datahub_services.base_client.DataHubBaseClient`: 기본 클라이언트 +- `utils.data.queries`: GraphQL 쿼리 정의 + - `GLOSSARY_TERMS_BY_URN_QUERY` + - `LIST_QUERIES_QUERY` + - `QUERIES_BY_URN_QUERY` + +--- + +## 전체 사용 예시 + +### 예시 1: 기본 사용법 + +```python +from utils.data.datahub_services import ( + DataHubBaseClient, + MetadataService, + QueryService, + GlossaryService +) + +# 1. 클라이언트 초기화 +gms_server = "http://localhost:8080" +client = DataHubBaseClient(gms_server=gms_server) + +# 2. 서비스 초기화 +metadata_service = MetadataService(client) +query_service = QueryService(client) +glossary_service = GlossaryService(client) + +# 3. 메타데이터 조회 +urn = "urn:li:dataset:(...)" +metadata = metadata_service.get_urn_info(urn) + +# 4. 쿼리 조회 +queries = query_service.get_query_data(start=0, count=10) + +# 5. 용어집 조회 +glossary_data = glossary_service.get_glossary_data() +``` + +### 예시 2: 통합 페처 사용 (하위 호환성) + +```python +from utils.data.datahub_source import DatahubMetadataFetcher + +# 기존 인터페이스와 동일하게 사용 가능 +fetcher = DatahubMetadataFetcher(gms_server="http://localhost:8080") + +# 모든 메서드가 동일하게 동작 +metadata = fetcher.get_urn_info(urn) +queries = fetcher.get_query_data() +glossary = fetcher.get_glossary_data() +``` + +### 예시 3: 테스트 코드 + +`test.py` 파일에서 실제 사용 예시를 확인할 수 있습니다: + +```python +from utils.data.datahub_services import DataHubBaseClient, QueryService + +client = DataHubBaseClient(gms_server="http://35.222.65.99:8080") +query_service = QueryService(client) + +result = query_service.get_query_data(start=0, count=5, query="*") +print(json.dumps(result, indent=2, ensure_ascii=False)) +``` + +--- + +## 의존성 + +### 외부 패키지 +- `requests`: HTTP 요청 처리 +- `datahub`: DataHub Python SDK + - `datahub.emitter.rest_emitter.DatahubRestEmitter` + - `datahub.ingestion.graph.client.DatahubClientConfig` + - `datahub.ingestion.graph.client.DataHubGraph` + - `datahub.metadata.schema_classes` + +### 내부 패키지 +- `utils.data.queries`: GraphQL 쿼리 정의 모듈 + +--- + +## 참고 사항 + +1. 모든 서비스는 `DataHubBaseClient`를 필요로 합니다. +2. `DatahubMetadataFetcher`는 하위 호환성을 위해 이 서비스들을 내부적으로 사용합니다. +3. GMS 서버 URL은 초기화 시 유효성 검사가 수행됩니다. +4. GraphQL 쿼리는 `utils.data.queries` 모듈에 정의되어 있습니다. +5. 오류 발생 시 dict 형태로 `{"error": True, "message": "..."}` 구조로 반환됩니다. + diff --git a/utils/databases/README.md b/utils/databases/README.md new file mode 100644 index 0000000..03a161c --- /dev/null +++ b/utils/databases/README.md @@ -0,0 +1,251 @@ +# Databases 모듈 + +다양한 데이터베이스에 대한 연결 및 SQL 실행 기능을 제공하는 유틸리티 모듈입니다. + +## 디렉토리 구조 + +``` +databases/ +├── __init__.py +├── config.py +├── factory.py +├── logger.py +└── connector/ + ├── base_connector.py + ├── clickhouse_connector.py + ├── databricks_connector.py + ├── duckdb_connector.py + ├── mariadb_connector.py + ├── mysql_connector.py + ├── oracle_connector.py + ├── postgres_connector.py + ├── snowflake_connector.py + ├── sqlite_connector.py + ├── trino_connector.py + └── README.md +``` + +## 파일 설명 + +### __init__.py + +데이터베이스 유틸리티 패키지 초기화 모듈입니다. 주요 구성 요소를 외부로 노출합니다. + +**Export:** +- `DatabaseFactory`: 데이터베이스 커넥터 팩토리 클래스 +- `DBConfig`: 데이터베이스 설정 타입 + +**사용처:** +- `interface/app_pages/settings_sections/db_section.py`: DB 설정 인터페이스에서 import +- 다른 모듈에서 `from utils.databases import DatabaseFactory` 형태로 import되어 사용됨 + +### config.py + +데이터베이스 연결 설정 정보를 정의하는 모듈입니다. + +**클래스:** +- `DBConfig(TypedDict)`: 데이터베이스 연결 설정 정보를 표현하는 타입 딕셔너리 + - `host` (str): 데이터베이스 호스트명 또는 IP 주소 + - `port` (Optional[int]): 데이터베이스 포트 번호 + - `user` (Optional[str]): 접속 사용자명 + - `password` (Optional[str]): 접속 비밀번호 + - `database` (Optional[str]): 대상 데이터베이스 이름 + - `extra` (Optional[Dict[str, str]]): 드라이버별 추가 설정값 + +**사용처:** +- `utils.databases.factory`: DBConfig 타입을 사용하여 설정 정보 전달 +- `utils.databases.connector.*`: 모든 커넥터가 이 타입을 사용 +- `interface/core/config/models.py`: DBConnectionProfile 모델에서 참조 + +### factory.py + +데이터베이스 커넥터 팩토리 모듈입니다. DB 타입에 따라 알맞은 커넥터 클래스를 동적으로 로드하고 인스턴스를 생성합니다. + +**클래스:** +- `DatabaseFactory`: 데이터베이스 커넥터 팩토리 클래스 + - `get_connector(db_type, config)`: 주어진 DB 타입에 해당하는 Connector 인스턴스 반환 + - DB 타입이 지정되지 않은 경우 환경 변수(`DB_TYPE`)에서 자동으로 가져옴 + - config가 지정되지 않은 경우 `load_config_from_env()`로 환경 변수에서 로드 + - 지원되지 않는 DB 타입이거나 모듈을 로드할 수 없는 경우 `ValueError` 발생 + +**함수:** +- `load_config_from_env(prefix) -> DBConfig`: 환경변수에서 데이터베이스 접속 설정을 로드 + - prefix: 환경변수 접두어 (예: 'POSTGRES', 'MYSQL') + - `{PREFIX}_HOST`, `{PREFIX}_PORT`, `{PREFIX}_USER`, `{PREFIX}_PASSWORD`, `{PREFIX}_DATABASE` 로드 + - 추가 커스텀 환경변수는 `extra` 필드에 포함 + +**사용처:** +- `interface/app_pages/settings_sections/db_section.py`: DB 연결 테스트 및 설정 적용 (221번 라인) +- `interface/app_pages/settings_sections/db_section.py`: 환경변수 설정 검증 (272번 라인) +- `utils.databases.__init__.py`: DatabaseFactory를 외부로 노출 + +**환경변수 예시:** +```bash +DB_TYPE=postgres +POSTGRES_HOST=localhost +POSTGRES_PORT=5432 +POSTGRES_USER=myuser +POSTGRES_PASSWORD=mypassword +POSTGRES_DATABASE=mydb +``` + +### logger.py + +로깅 설정 모듈입니다. 애플리케이션 전역에서 사용할 기본 로깅 설정을 정의합니다. + +**내보내기:** +- `logger`: 표준 로거 인스턴스 + +**설정:** +- 레벨: `INFO` +- 포맷: `%(asctime)s [%(levelname)s] %(message)s` +- 날짜 포맷: `%Y-%m-%d %H:%M:%S` + +**사용처:** +- `utils.databases.factory`: DB 타입 로딩 실패 시 로깅 +- `utils.databases.connector.*`: 모든 커넥터에서 연결 및 SQL 실행 로깅 + +### connector/ + +데이터베이스별 커넥터 구현이 위치한 디렉토리입니다. + +자세한 내용은 [connector/README.md](connector/README.md)를 참조하세요. + +**주요 특징:** +- 모든 커넥터는 `BaseConnector` 추상 클래스를 상속 +- 공통 인터페이스: `connect()`, `run_sql(sql) -> pd.DataFrame`, `close()` +- 지원 데이터베이스: PostgreSQL, MySQL, MariaDB, Oracle, SQLite, DuckDB, Snowflake, Databricks, Trino, ClickHouse + +## 사용 방법 + +### Factory 패턴 사용 (권장) + +환경 변수를 설정하고 DatabaseFactory를 사용하여 커넥터를 생성합니다: + +```python +from utils.databases import DatabaseFactory + +# 환경 변수 사용 +connector = DatabaseFactory.get_connector() +result = connector.run_sql("SELECT * FROM users LIMIT 10") +connector.close() +``` + +### 명시적 설정 사용 + +DBConfig를 직접 생성하여 전달할 수 있습니다: + +```python +from utils.databases import DatabaseFactory, DBConfig + +config = DBConfig( + host="localhost", + port=5432, + user="myuser", + password="mypassword", + database="mydb", + extra={} +) +connector = DatabaseFactory.get_connector(db_type="postgres", config=config) +result = connector.run_sql("SELECT * FROM users LIMIT 10") +connector.close() +``` + +### 직접 커넥터 사용 + +특정 커넥터를 직접 import하여 사용할 수 있습니다: + +```python +from utils.databases.connector.postgres_connector import PostgresConnector +from utils.databases.config import DBConfig + +config = DBConfig( + host="localhost", + port=5432, + user="myuser", + password="mypassword", + database="mydb", + extra={} +) + +connector = PostgresConnector(config) +result = connector.run_sql("SELECT * FROM users LIMIT 10") +print(result) +connector.close() +``` + +## 지원되는 데이터베이스 + +1. **PostgreSQL** (`postgres`) +2. **MySQL** (`mysql`) +3. **MariaDB** (`mariadb`) +4. **Oracle** (`oracle`) +5. **SQLite** (`sqlite`) +6. **DuckDB** (`duckdb`) +7. **Snowflake** (`snowflake`) +8. **Databricks** (`databricks`) +9. **Trino** (`trino`) +10. **ClickHouse** (`clickhouse`) + +각 데이터베이스의 상세한 설정 방법은 [connector/README.md](connector/README.md)를 참조하세요. + +## 통합 사용 예시 + +### Streamlit 인터페이스에서 사용 + +`interface/app_pages/settings_sections/db_section.py`에서 DB 연결을 설정하고 테스트: + +```python +from utils.databases import DatabaseFactory + +# 연결 테스트 +connector = DatabaseFactory.get_connector(db_type=db_type) +test_sql = "SELECT 1" +df = connector.run_sql(test_sql) +connector.close() +``` + +### CLI에서 사용 + +환경 변수를 통해 커넥터를 생성하고 SQL 쿼리를 실행할 수 있습니다. + +## 에러 처리 + +- **연결 실패**: `ConnectionError` 발생 +- **SQL 실행 실패**: `RuntimeError` 발생 +- **지원되지 않는 DB 타입**: `ValueError` 발생 +- **DB_TYPE 미지정**: `ValueError("DB_TYPE이 환경변수 또는 인자로 제공되어야 합니다.")` 발생 + +## 로깅 + +모든 커넥터는 `utils.databases.logger`를 사용하여 다음 정보를 로깅합니다: +- 연결 성공/실패 +- SQL 실행 결과 +- 에러 발생 상황 + +로그 포맷: `YYYY-MM-DD HH:MM:SS [LEVEL] 메시지` + +## 의존성 + +각 커넥터는 해당 데이터베이스의 Python 드라이버를 필요로 합니다: + +- PostgreSQL: `psycopg2` +- MySQL/MariaDB: `mysql-connector-python` +- Oracle: `oracledb` +- SQLite: `sqlite3` (표준 라이브러리) +- DuckDB: `duckdb` +- Snowflake: `snowflake-connector-python` +- Databricks: `databricks-sql-connector` +- Trino: `trino` +- ClickHouse: `clickhouse-driver` + +## 확장성 + +새로운 데이터베이스를 추가하려면: + +1. `connector/` 디렉토리에 `{db_type}_connector.py` 파일 생성 +2. `BaseConnector`를 상속받는 `{DBType}Connector` 클래스 구현 +3. `connect()`, `run_sql(sql) -> pd.DataFrame`, `close()` 메서드 구현 +4. `DatabaseFactory.get_connector()`가 자동으로 새 커넥터를 로드 + +자세한 내용은 `connector/base_connector.py`를 참조하세요. diff --git a/utils/databases/connector/README.md b/utils/databases/connector/README.md new file mode 100644 index 0000000..8349e14 --- /dev/null +++ b/utils/databases/connector/README.md @@ -0,0 +1,302 @@ +# Connector 모듈 + +데이터베이스 연결 및 SQL 실행을 위한 커넥터 클래스들을 제공하는 모듈입니다. + +## 디렉토리 구조 + +``` +connector/ +├── __pycache__/ +├── base_connector.py +├── clickhouse_connector.py +├── databricks_connector.py +├── duckdb_connector.py +├── mariadb_connector.py +├── mysql_connector.py +├── oracle_connector.py +├── postgres_connector.py +├── snowflake_connector.py +├── sqlite_connector.py +└── trino_connector.py +``` + +## 파일 설명 + +### base_connector.py + +데이터베이스 커넥터의 기본 인터페이스를 정의하는 모듈입니다. + +**클래스:** +- `BaseConnector`: 모든 DB 커넥터가 상속받아야 하는 추상 클래스 + - `connection`: DB 연결 객체를 저장하는 클래스 변수 + - `connect()`: 데이터베이스 연결 수행 (abstractmethod) + - `run_sql(sql: str) -> pd.DataFrame`: SQL 쿼리 실행 및 결과 반환 (abstractmethod) + - `close() -> None`: 데이터베이스 연결 종료 (abstractmethod) + +**사용처:** +- 모든 구체적인 DB 커넥터 클래스들이 이 클래스를 상속받음 +- `utils.databases.connector.*` 모듈들에서 import되어 사용됨 + +### clickhouse_connector.py + +ClickHouse 데이터베이스 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `ClickHouseConnector(BaseConnector)`: ClickHouse 서버 연결을 위한 커넥터 + - `client`: ClickHouse Client 객체 + - `__init__(config: DBConfig)`: 호스트, 포트, 사용자, 비밀번호, 데이터베이스 설정으로 초기화 + - `connect() -> None`: clickhouse_driver.Client로 ClickHouse 서버 연결 + - `run_sql(sql: str) -> pd.DataFrame`: 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 클라이언트 연결 해제 + +**의존성:** +- `clickhouse_driver` +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### databricks_connector.py + +Databricks SQL Warehouse 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `DatabricksConnector(BaseConnector)`: Databricks SQL Warehouse 연결을 위한 커넥터 + - `connection`: Databricks 연결 객체 + - `__init__(config: DBConfig)`: + - 필수 설정: host, extra.http_path, extra.access_token + - 선택 설정: extra.catalog, extra.schema + - `connect() -> None`: databricks.sql 모듈로 연결 설정 + - `run_sql(sql: str) -> pd.DataFrame`: 커서를 사용해 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `databricks.sql` +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### duckdb_connector.py + +DuckDB 데이터베이스 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `DuckDBConnector(BaseConnector)`: DuckDB 연결을 위한 커넥터 + - `connection`: DuckDB 연결 객체 + - `__init__(config: DBConfig)`: path 설정 (기본값: ":memory:") + - `connect() -> None`: duckdb.connect로 데이터베이스 연결 + - `run_sql(sql: str) -> pd.DataFrame`: execute().fetchdf()로 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `duckdb` +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### mariadb_connector.py + +MariaDB 데이터베이스 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `MariaDBConnector(BaseConnector)`: MariaDB 서버 연결을 위한 커넥터 + - `connection`: MariaDB 연결 객체 + - `__init__(config: DBConfig)`: 호스트, 포트(기본: 3306), 사용자, 비밀번호, 데이터베이스 설정 + - `connect() -> None`: mysql.connector로 MariaDB 서버 연결 + - `run_sql(sql: str) -> pd.DataFrame`: 커서를 사용해 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `mysql.connector` +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### mysql_connector.py + +MySQL 데이터베이스 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `MySQLConnector(BaseConnector)`: MySQL 서버 연결을 위한 커넥터 + - `connection`: MySQL 연결 객체 + - `__init__(config: DBConfig)`: 호스트, 포트(기본: 3306), 사용자, 비밀번호, 데이터베이스 설정 + - `connect() -> None`: mysql.connector로 MySQL 서버 연결 + - `run_sql(sql: str) -> pd.DataFrame`: 커서를 사용해 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `mysql.connector` +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### oracle_connector.py + +Oracle 데이터베이스 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `OracleConnector(BaseConnector)`: Oracle 서버 연결을 위한 커넥터 + - `connection`: Oracle 연결 객체 + - `__init__(config: DBConfig)`: + - 필수 설정: host, port, user, password + - 선택 설정: extra.service_name (기본값: "orcl") + - `connect() -> None`: oracledb.connect로 DSN 형식으로 연결 + - `run_sql(sql: str) -> pd.DataFrame`: 커서를 사용해 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `oracledb` +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### postgres_connector.py + +PostgreSQL 데이터베이스 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `PostgresConnector(BaseConnector)`: PostgreSQL 서버 연결을 위한 커넥터 + - `connection`: PostgreSQL 연결 객체 + - `__init__(config: DBConfig)`: 호스트, 포트, 사용자, 비밀번호, 데이터베이스 설정 + - `connect() -> None`: psycopg2.connect로 PostgreSQL 서버 연결 + - `run_sql(sql: str) -> pd.DataFrame`: 커서를 사용해 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `psycopg2` +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### snowflake_connector.py + +Snowflake 데이터베이스 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `SnowflakeConnector(BaseConnector)`: Snowflake 서버 연결을 위한 커넥터 + - `connection`: Snowflake 연결 객체 + - `cursor`: Snowflake 커서 객체 + - `__init__(config: DBConfig)`: + - 필수 설정: user, password, extra.account + - 선택 설정: extra.warehouse, database, extra.schema + - `connect() -> None`: snowflake.connector로 연결 및 커서 생성 + - `run_sql(sql: str) -> pd.DataFrame`: 커서를 사용해 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `snowflake.connector` +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### sqlite_connector.py + +SQLite 데이터베이스 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `SQLiteConnector(BaseConnector)`: SQLite 파일 또는 인메모리 데이터베이스 연결을 위한 커넥터 + - `connection`: SQLite 연결 객체 + - `__init__(config: DBConfig)`: path 설정 (None 또는 ":memory:"인 경우 인메모리 DB) + - `connect() -> None`: sqlite3.connect로 데이터베이스 연결 + - `run_sql(sql: str) -> pd.DataFrame`: 커서를 사용해 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `sqlite3` (Python 표준 라이브러리) +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +### trino_connector.py + +Trino 클러스터 연결 및 SQL 실행을 담당하는 모듈입니다. + +**클래스:** +- `TrinoConnector(BaseConnector)`: Trino 클러스터 연결을 위한 커넥터 + - `connection`: Trino 연결 객체 + - `__init__(config: DBConfig)`: + - 필수 설정: host, port + - 선택 설정: user, password, database, extra.catalog, extra.schema, extra.http_scheme + - database가 "catalog.schema" 형태일 경우 자동 분리 + - `connect() -> None`: trino.dbapi.connect로 연결 설정 + - `run_sql(sql: str) -> pd.DataFrame`: 커서를 사용해 쿼리 실행 후 DataFrame 반환 + - `close() -> None`: 연결 종료 + +**의존성:** +- `trino` (런타임에 동적으로 로드) +- `utils.databases.config.DBConfig` +- `utils.databases.logger.logger` + +## 사용 방법 + +### 직접 사용 + +각 커넥터 클래스를 직접 인스턴스화하여 사용할 수 있습니다: + +```python +from utils.databases.connector.postgres_connector import PostgresConnector +from utils.databases.config import DBConfig + +config = DBConfig( + host="localhost", + port=5432, + user="myuser", + password="mypassword", + database="mydb", + extra={} +) + +connector = PostgresConnector(config) +result = connector.run_sql("SELECT * FROM users") +print(result) +connector.close() +``` + +### Factory 패턴 사용 (권장) + +`DatabaseFactory`를 사용하여 DB 타입에 따라 자동으로 적절한 커넥터를 선택할 수 있습니다: + +```python +from utils.databases import DatabaseFactory + +# 환경 변수 사용 +connector = DatabaseFactory.get_connector() +result = connector.run_sql("SELECT * FROM users") +connector.close() + +# 명시적 설정 +config = DBConfig( + host="localhost", + port=5432, + user="myuser", + password="mypassword", + database="mydb", + extra={} +) +connector = DatabaseFactory.get_connector(db_type="postgres", config=config) +result = connector.run_sql("SELECT * FROM users") +connector.close() +``` + +### 지원되는 데이터베이스 타입 + +다음 데이터베이스들이 지원됩니다: + +1. **PostgreSQL** (`postgres`) +2. **MySQL** (`mysql`) +3. **MariaDB** (`mariadb`) +4. **Oracle** (`oracle`) +5. **SQLite** (`sqlite`) +6. **DuckDB** (`duckdb`) +7. **Snowflake** (`snowflake`) +8. **Databricks** (`databricks`) +9. **Trino** (`trino`) +10. **ClickHouse** (`clickhouse`) + +## 공통 인터페이스 + +모든 커넥터는 `BaseConnector` 추상 클래스를 상속받아 다음과 같은 공통 인터페이스를 구현합니다: + +- `connect() -> None`: 데이터베이스에 연결 +- `run_sql(sql: str) -> pd.DataFrame`: SQL 쿼리 실행 및 결과를 pandas DataFrame으로 반환 +- `close() -> None`: 데이터베이스 연결 종료 + +## 로깅 + +모든 커넥터는 `utils.databases.logger`를 사용하여 연결 성공/실패 및 SQL 실행 결과를 로깅합니다. + +## 에러 처리 + +- 연결 실패 시: `ConnectionError` 발생 +- SQL 실행 실패 시: `RuntimeError` 발생 +- 지원되지 않는 DB 타입: `ValueError` 발생 diff --git a/utils/llm/README.md b/utils/llm/README.md index f52b406..993ee98 100644 --- a/utils/llm/README.md +++ b/utils/llm/README.md @@ -2,77 +2,224 @@ Lang2SQL 파이프라인에서 LLM, 검색(RAG), 그래프 워크플로우, DB 실행, 시각화 등 보조 유틸리티를 모아둔 패키지입니다. 이 문서는 depth(계층)별로 기능과 통합 흐름을 정리합니다. -### Depth 0: 최상위 유틸리티 +## 디렉토리 구조 -- (Moved) `engine/query_executor.py`: Lang2SQL 그래프 선택/컴파일/실행 진입점. -- (Moved) `utils/visualization/display_chart.py`: LLM 활용 Plotly 시각화 유틸. -- (Moved) `infra/monitoring/check_server.py`: GMS 헬스체크. -- (Moved) `infra/db/connect_db.py`: ClickHouse 연결/실행. -- (Moved) `infra/observability/token_usage.py`: LLM 메시지의 `usage_metadata` 합산 토큰 집계. -- **`llm_response_parser.py`**: LLM 응답에서 ``, `<해석>` 블록 추출. -- **`prompts_class.py`**: LangChain SQL 프롬프트를 로컬 YAML로 오버라이드. -- (Moved) `graph_utils/profile_utils.py`: `profile_to_text(profile)` 등 그래프 관련 포맷 유틸. +``` +utils/llm/ +├── README.md # 이 파일 +├── chains.py # LangChain 체인 생성 모듈 +├── retrieval.py # 테이블 메타 검색 및 재순위화 +├── llm_response_parser.py # LLM 응답에서 SQL 블록 추출 +├── chatbot.py # LangGraph ChatBot 구현 +├── core/ # LLM/Embedding 팩토리 모듈 +│ ├── __init__.py +│ ├── factory.py # LLM 및 Embedding 모델 생성 팩토리 +│ └── README.md # [상세 문서](./core/README.md) +├── graph_utils/ # LangGraph 워크플로우 모듈 +│ ├── __init__.py +│ ├── base.py # 공통 상태 및 노드 함수 +│ ├── basic_graph.py # 기본 워크플로우 그래프 +│ ├── enriched_graph.py # 확장된 워크플로우 그래프 +│ ├── profile_utils.py # 프로파일 유틸리티 함수 +│ └── README.md # [상세 문서](./graph_utils/README.md) +├── vectordb/ # 벡터 데이터베이스 모듈 +│ ├── __init__.py +│ ├── factory.py # VectorDB 팩토리 +│ ├── faiss_db.py # FAISS 벡터DB 구현 +│ ├── pgvector_db.py # pgvector 벡터DB 구현 +│ └── README.md # [상세 문서](./vectordb/README.md) +├── tools/ # DataHub 메타데이터 및 ChatBot 도구 +│ ├── __init__.py +│ ├── datahub.py # DataHub 메타데이터 수집 +│ ├── chatbot_tool.py # LangGraph ChatBot용 Tool 함수들 +│ └── README.md # [상세 문서](./tools/README.md) +└── output_schema/ # LLM 구조화 출력 Pydantic 모델 + ├── document_suitability.py # 문서 적합성 평가 모델 + ├── question_suitability.py # 질문 적합성 판단 모델 + └── README.md # [상세 문서](./output_schema/README.md) +``` + +## 모듈 상세 설명 + +### 최상위 유틸리티 파일 + +#### `chains.py` +**목적**: LangChain 기반 체인 생성 모듈 + +**주요 함수:** +- `create_query_maker_chain(llm)`: SQL 쿼리 생성 체인 +- `create_profile_extraction_chain(llm)`: 질문 프로파일 추출 체인 +- `create_query_enrichment_chain(llm)`: 질문 컨텍스트 보강 체인 +- `create_question_gate_chain(llm)`: SQL 적합성 판별 체인 +- `create_document_suitability_chain(llm)`: 문서 적합성 평가 체인 + +**내부 모델:** +- `QuestionProfile`: 자연어 질문의 특징을 구조화하는 Pydantic 모델 + +**의존성:** +- `utils.llm.core.get_llm`: LLM 인스턴스 생성 +- `utils.llm.output_schema`: 구조화 출력 모델 + +**사용처:** +- `utils/llm/graph_utils/base.py`: 각 노드에서 체인 호출 + +#### `retrieval.py` +**목적**: 테이블 메타데이터 검색 및 재순위화 + +**주요 함수:** +- `search_tables(query, retriever_name, top_n, device)`: 테이블 메타데이터 검색 + - `retriever_name`: "기본" 또는 "Reranker" + - `top_n`: 반환할 상위 결과 개수 +- `get_retriever(retriever_name, top_n, device)`: 검색기 생성 +- `load_reranker_model(device)`: 한국어 reranker 모델 로드 + +**의존성:** +- `utils.llm.vectordb.get_vector_db`: 벡터DB 인스턴스 +- `ko-reranker`: 한국어 재순위화 모델 + +**사용처:** +- `utils/llm/graph_utils/base.py`: `get_table_info_node`에서 호출 +- `utils/llm/tools/chatbot_tool.py`: `search_database_tables`에서 호출 + +#### `llm_response_parser.py` +**목적**: LLM 응답에서 ``, `<해석>` 블록 추출 + +**사용처:** +- `engine/query_executor.py`: SQL 추출 함수 -### Depth 1: LLM/임베딩/검색 +### 하위 디렉토리 모듈 -- **`llm_factory.py`**: 환경변수로 LLM/임베딩 공급자 선택 팩토리. - - LLM: `openai`, `azure`, `bedrock`, `gemini`, `ollama`, `huggingface` - - Embeddings: `openai`, `azure`, `bedrock`, `gemini`, `ollama`, `huggingface` - - 사용처: 체인/그래프 전반 및 `vectordb` 인덱싱/검색. -- **`retrieval.py`**: 테이블 메타 검색 및 재순위화. - - `search_tables(query, retriever_name, top_n, device)` - - 기본: FAISS/pgvector에서 similarity_search. - - `Reranker`: ko-reranker(CrossEncoder)로 재순위. +#### `core/` - LLM/Embedding 팩토리 +**목적**: 다양한 제공자(OpenAI, Azure, Bedrock, Gemini, Ollama, HuggingFace)의 LLM과 Embedding 모델을 통일된 인터페이스로 사용 -### Depth 1.5: 벡터DB +**주요 기능:** +- `get_llm(**kwargs)`: 환경변수 기반 LLM 인스턴스 생성 +- `get_embeddings()`: 환경변수 기반 Embedding 인스턴스 생성 +- 제공자별 전용 함수들 제공 -- **`vectordb/factory.py` → `get_vector_db()`**: `VECTORDB_TYPE`(`faiss`|`pgvector`)에 따라 인스턴스 반환. -- **`vectordb/faiss_db.py`**: 로컬 디스크 `dev/table_info_db` 로드/없으면 `tools.get_info_from_db()`로 빌드 후 저장. -- **`vectordb/pgvector_db.py`**: PGVector 컬렉션 연결, 없거나 비면 `from_documents`로 재구성. +**사용처:** +- `utils/llm/chains.py`: `get_llm()` 호출 +- `utils/llm/vectordb/faiss_db.py`: `get_embeddings()` 호출 +- `utils/llm/vectordb/pgvector_db.py`: `get_embeddings()` 호출 -### Depth 2: 데이터 소스/메타 수집 +**상세 문서**: [core/README.md](./core/README.md) -- **`tools.py`**: DataHub 기반 메타데이터 수집. - - `set_gms_server(gms_server)`로 GMS 설정. - - `get_info_from_db()` → `langchain.schema.Document` 리스트: 테이블 설명, 컬럼, 예시 쿼리, 용어집을 포맷. - - `get_metadata_from_db()` → 풍부한 전체 메타데이터(dict) 목록. +#### `graph_utils/` - LangGraph 워크플로우 +**목적**: LangGraph를 사용하여 자연어 질문을 SQL 쿼리로 변환하는 워크플로우 구현 -### Depth 2.5: 체인(Chains) +**주요 컴포넌트:** +- `base.py`: 공통 상태(`QueryMakerState`) 및 노드 함수들 +- `basic_graph.py`: 기본 워크플로우 (QUESTION_GATE → GET_TABLE_INFO → EVALUATE_DOCUMENT_SUITABILITY → QUERY_MAKER) +- `enriched_graph.py`: 확장 워크플로우 (PROFILE_EXTRACTION, CONTEXT_ENRICHMENT 추가) -- **`chains.py`**: LangChain ChatPromptTemplate로 구성된 체인. - - `create_query_maker_chain`, `create_profile_extraction_chain`, `create_query_enrichment_chain` - - `QuestionProfile` Pydantic 모델로 질의 특성 구조화 추출. +**워크플로우 노드:** +- `question_gate_node`: SQL 적합성 판별 +- `get_table_info_node`: 벡터 검색으로 테이블 정보 수집 +- `document_suitability_node`: 문서 적합성 평가 +- `profile_extraction_node`: 질문 프로파일 추출 +- `context_enrichment_node`: 질문 컨텍스트 보강 +- `query_maker_node`: SQL 쿼리 생성 -### Depth 3: 그래프(Graph) 워크플로우 +**사용처:** +- `engine/query_executor.py`: 그래프 선택 및 실행 +- `interface/core/session_utils.py`: Streamlit 세션 그래프 초기화 -- **`graph_utils/base.py`**: 공통 상태(`QueryMakerState`)와 노드 함수 집합. - - 노드: `get_table_info_node`(RAG), `profile_extraction_node`, `context_enrichment_node`, `query_maker_node`, `query_maker_node_without_refiner`. - - 각 노드는 `chains.py`와 `retrieval.py`, `utils.profile_to_text` 등을 호출하며 상태를 갱신. -- **`graph_utils/basic_graph.py`**: GET_TABLE_INFO → QUERY_MAKER → END -- **`graph_utils/enriched_graph.py`**: GET_TABLE_INFO → PROFILE_EXTRACTION → CONTEXT_ENRICHMENT → QUERY_MAKER → END -- **`graph_utils/simplified_graph.py`**: GET_TABLE_INFO → PROFILE_EXTRACTION → CONTEXT_ENRICHMENT → QUERY_MAKER(without refiner) → END +**상세 문서**: [graph_utils/README.md](./graph_utils/README.md) + +#### `vectordb/` - 벡터 데이터베이스 +**목적**: 테이블 메타데이터를 벡터화하여 저장하고 검색 + +**주요 기능:** +- `get_vector_db()`: 환경변수 기반 벡터DB 인스턴스 반환 +- FAISS: 로컬 디스크 기반 벡터DB +- pgvector: PostgreSQL 기반 벡터DB + +**사용처:** +- `utils/llm/retrieval.py`: 테이블 검색 시 벡터DB 사용 + +**상세 문서**: [vectordb/README.md](./vectordb/README.md) + +#### `tools/` - DataHub 메타데이터 및 ChatBot 도구 +**목적**: DataHub 메타데이터 수집 및 LangGraph ChatBot용 Tool 함수 제공 + +**주요 기능:** +- `get_info_from_db()`: DataHub에서 테이블 메타데이터를 LangChain Document로 수집 +- `get_metadata_from_db()`: 전체 메타데이터 딕셔너리 반환 +- `search_database_tables()`: 벡터 검색 기반 테이블 정보 검색 Tool +- `get_glossary_terms()`: 용어집 정보 조회 Tool +- `get_query_examples()`: 쿼리 예제 조회 Tool + +**사용처:** +- `utils/llm/vectordb/faiss_db.py`: 벡터DB 초기화 시 메타데이터 수집 +- `utils/llm/vectordb/pgvector_db.py`: 벡터DB 초기화 시 메타데이터 수집 +- `utils/llm/chatbot.py`: ChatBot 도구로 사용 + +**상세 문서**: [tools/README.md](./tools/README.md) + +#### `output_schema/` - 구조화 출력 모델 +**목적**: LLM 구조화 출력을 위한 Pydantic 모델 정의 + +**주요 모델:** +- `QuestionSuitability`: SQL 생성 적합성 판단 결과 +- `DocumentSuitability`: 단일 테이블 적합성 평가 결과 +- `DocumentSuitabilityList`: 문서 적합성 평가 결과 리스트 + +**사용처:** +- `utils/llm/chains.py`: 체인 생성 시 구조화 출력 모델로 사용 + +**상세 문서**: [output_schema/README.md](./output_schema/README.md) ### 통합 흐름(End-to-End) -1) 사용자가 자연어 질문 입력 → `query_executor.execute_query()` 호출 -2) 그래프 선택(`basic`/`enriched`/`simplified`) 및 컴파일 -3) `GET_TABLE_INFO`에서 `retrieval.search_tables()`로 관련 테이블/컬럼/예시쿼리/용어집 수집 -4) `PROFILE_EXTRACTION`(선택)에서 `chains.profile_extraction_chain`으로 질문 특성 추출 → `utils.profile_to_text` -5) `QUERY_REFINER`(선택) 또는 `CONTEXT_ENRICHMENT`로 질문을 정교화/보강 -6) `QUERY_MAKER`에서 DB 가이드/메타를 바탕으로 SQL 생성 (`` 코드블록 포함 권장) -7) 반환 `messages`에서 `llm_response_parser.extract_sql()`로 SQL 추출 -8) 필요 시 `connect_db.run_sql()`로 실행, `display_chart`로 결과 시각화 +1. **사용자 질문 입력** → `engine/query_executor.execute_query()` 호출 +2. **그래프 선택 및 컴파일** → `graph_utils/basic_graph` 또는 `graph_utils/enriched_graph` 선택 +3. **QUESTION_GATE 노드** → `chains.create_question_gate_chain()`으로 SQL 적합성 판별 +4. **GET_TABLE_INFO 노드** → `retrieval.search_tables()` 호출 + - `vectordb.get_vector_db()`로 벡터DB 로드 + - 유사도 검색 또는 Reranker로 재순위화 + - 관련 테이블/컬럼 메타데이터 반환 +5. **EVALUATE_DOCUMENT_SUITABILITY 노드** → `chains.create_document_suitability_chain()`으로 문서 적합성 평가 +6. **PROFILE_EXTRACTION 노드** (확장 그래프만) → `chains.create_profile_extraction_chain()`으로 질문 특성 추출 + - `graph_utils/profile_utils.profile_to_text()`로 텍스트 변환 +7. **CONTEXT_ENRICHMENT 노드** (확장 그래프만) → `chains.create_query_enrichment_chain()`으로 질문 컨텍스트 보강 +8. **QUERY_MAKER 노드** → `chains.create_query_maker_chain()`으로 SQL 생성 + - DB 가이드/메타데이터 기반으로 SQL 생성 (`` 코드블록 포함) +9. **SQL 추출** → `llm_response_parser.extract_sql()`로 최종 SQL 추출 +10. **실행 및 시각화** (선택적) → `infra/db/connect_db.run_sql()` 실행, `utils/visualization/display_chart`로 시각화 ### 환경 변수 요약 -- **LLM 관련**: `LLM_PROVIDER`, `OPEN_AI_KEY`, `OPEN_AI_LLM_MODEL`, `AZURE_*`, `AWS_BEDROCK_*`, `GEMINI_*`, `OLLAMA_*`, `HUGGING_FACE_*` -- **임베딩 관련**: `EMBEDDING_PROVIDER`, 각 공급자별 키/모델 -- **VectorDB**: `VECTORDB_TYPE`(faiss|pgvector), `VECTORDB_LOCATION`, `PGVECTOR_*` -- **DataHub**: `DATAHUB_SERVER` -- **ClickHouse**: `CLICKHOUSE_HOST`, `CLICKHOUSE_PORT`, `CLICKHOUSE_DATABASE`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD` +#### LLM 관련 +- **`LLM_PROVIDER`**: LLM 제공자 선택 (`openai`, `azure`, `bedrock`, `gemini`, `ollama`, `huggingface`) +- 제공자별 환경변수 (상세는 [core/README.md](./core/README.md) 참고) + - OpenAI: `OPEN_AI_KEY`, `OPEN_AI_LLM_MODEL` + - Azure: `AZURE_OPENAI_LLM_KEY`, `AZURE_OPENAI_LLM_ENDPOINT`, `AZURE_OPENAI_LLM_MODEL`, `AZURE_OPENAI_LLM_API_VERSION` + - AWS Bedrock: `AWS_BEDROCK_LLM_MODEL`, `AWS_BEDROCK_LLM_ACCESS_KEY_ID`, `AWS_BEDROCK_LLM_SECRET_ACCESS_KEY`, `AWS_BEDROCK_LLM_REGION` + - Gemini: `GEMINI_LLM_MODEL` + - Ollama: `OLLAMA_LLM_MODEL`, `OLLAMA_LLM_BASE_URL` + - HuggingFace: `HUGGING_FACE_LLM_MODEL`, `HUGGING_FACE_LLM_REPO_ID`, `HUGGING_FACE_LLM_ENDPOINT`, `HUGGING_FACE_LLM_API_TOKEN` + +#### Embedding 관련 +- **`EMBEDDING_PROVIDER`**: Embedding 제공자 선택 (`openai`, `azure`, `bedrock`, `gemini`, `ollama`, `huggingface`) +- 제공자별 환경변수 (상세는 [core/README.md](./core/README.md) 참고) + +#### VectorDB 관련 +- **`VECTORDB_TYPE`**: 벡터DB 타입 선택 (`faiss` 또는 `pgvector`, 기본: `faiss`) +- **FAISS**: `VECTORDB_LOCATION` (기본: `./dev/table_info_db`) +- **pgvector**: `PGVECTOR_HOST`, `PGVECTOR_PORT`, `PGVECTOR_USER`, `PGVECTOR_PASSWORD`, `PGVECTOR_DATABASE`, `PGVECTOR_COLLECTION` +- 상세는 [vectordb/README.md](./vectordb/README.md) 참고 + +#### DataHub 관련 +- **`DATAHUB_SERVER`**: DataHub GMS 서버 URL (예: `http://localhost:8080`) +- 상세는 [tools/README.md](./tools/README.md) 참고 + +#### ClickHouse 관련 (SQL 실행 시) +- `CLICKHOUSE_HOST`, `CLICKHOUSE_PORT`, `CLICKHOUSE_DATABASE`, `CLICKHOUSE_USER`, `CLICKHOUSE_PASSWORD` ### 핵심 사용 예시 +#### 1. 기본 쿼리 실행 + ```python from engine.query_executor import execute_query, extract_sql_from_result @@ -88,18 +235,95 @@ res = execute_query( sql = extract_sql_from_result(res) ``` +#### 2. 체인 직접 사용 + ```python -from utils.visualization.display_chart import DisplayChart +from utils.llm.core import get_llm +from utils.llm.chains import create_query_maker_chain -chart = DisplayChart(question="지난달 매출 추이", sql=sql, df_metadata=str(df.dtypes)) -code = chart.generate_plotly_code() -fig = chart.get_plotly_figure(code, df) +llm = get_llm() +chain = create_query_maker_chain(llm) + +result = chain.invoke({ + "user_input": "지난달 매출", + "user_database_env": "postgres", + "searched_tables": {...} +}) ``` -### 파일간 의존 관계(요약) +#### 3. 벡터 검색 직접 사용 + +```python +from utils.llm.retrieval import search_tables + +tables = search_tables( + query="고객 정보", + retriever_name="Reranker", + top_n=5, + device="cpu" +) +``` + +#### 4. 그래프 빌더 직접 사용 + +```python +from utils.llm.graph_utils import basic_builder, enriched_builder + +# 기본 그래프 +graph = basic_builder.compile() + +# 확장 그래프 +graph = enriched_builder.compile() + +# 그래프 실행 +result = graph.invoke({ + "messages": [HumanMessage(content="지난달 매출 보여줘")], + "user_database_env": "postgres", + # ... 기타 상태 정보 +}) +``` + +### 파일간 의존 관계 + +#### 상위 레벨 의존성 +``` +engine/query_executor.py +├── utils/llm/graph_utils/ +│ ├── basic_graph.py +│ ├── enriched_graph.py +│ └── base.py +│ ├── utils/llm/chains.py +│ │ ├── utils/llm/core/get_llm() +│ │ └── utils/llm/output_schema/ +│ └── utils/llm/retrieval.py +│ └── utils/llm/vectordb/get_vector_db() +│ ├── utils/llm/core/get_embeddings() +│ └── utils/llm/tools/get_info_from_db() +└── utils/llm/llm_response_parser.py +``` + +#### 주요 import 관계 + +**graph_utils 모듈:** +- `graph_utils/base.py` → `chains.py`, `retrieval.py` 사용 +- `graph_utils/basic_graph.py` → `graph_utils/base.py` 사용 +- `graph_utils/enriched_graph.py` → `graph_utils/base.py` 사용 + +**chains 모듈:** +- `chains.py` → `core/get_llm()`, `output_schema/` 사용 + +**retrieval 모듈:** +- `retrieval.py` → `vectordb/get_vector_db()` 사용 + +**vectordb 모듈:** +- `vectordb/faiss_db.py` → `core/get_embeddings()`, `tools/get_info_from_db()` 사용 +- `vectordb/pgvector_db.py` → `core/get_embeddings()`, `tools/get_info_from_db()` 사용 + +**tools 모듈:** +- `tools/datahub.py` → DataHub 메타데이터 수집 +- `tools/chatbot_tool.py` → `retrieval/search_tables()` 사용 -- `query_executor.py` → `graph_utils/*` → `chains.py`, `retrieval.py`, `llm_factory.py`, `utils.py` -- `retrieval.py` → `vectordb/*` → `llm_factory.get_embeddings()`, `tools.get_info_from_db()` -- `display_chart.py` → OpenAI LLM(선택적)로 코드 생성 → Plotly 실행 -- `connect_db.py` → ClickHouse 클라이언트로 SQL 실행 -- `llm_response_parser.py` → 결과 파서 +**외부 의존성:** +- `engine/query_executor.py` → `graph_utils/` 사용 +- `interface/core/session_utils.py` → `graph_utils/` 사용 +- `interface/app_pages/graph_builder.py` → `graph_utils/base.py` 사용 diff --git a/utils/llm/chains.py b/utils/llm/chains.py index bb2ab2e..6e66f8b 100644 --- a/utils/llm/chains.py +++ b/utils/llm/chains.py @@ -13,8 +13,8 @@ from prompt.template_loader import get_prompt_template from utils.llm.core import get_llm -from utils.llm.output_parser.document_suitability import DocumentSuitabilityList -from utils.llm.output_parser.question_suitability import QuestionSuitability +from utils.llm.output_schema.document_suitability import DocumentSuitabilityList +from utils.llm.output_schema.question_suitability import QuestionSuitability llm = get_llm() diff --git a/utils/llm/core/README.md b/utils/llm/core/README.md new file mode 100644 index 0000000..c23e75c --- /dev/null +++ b/utils/llm/core/README.md @@ -0,0 +1,251 @@ +# core + +LLM(Large Language Model)과 Embedding 모델을 생성하는 팩토리 패턴을 구현한 모듈입니다. 환경변수를 통해 다양한 제공자(OpenAI, Azure, Bedrock, Gemini, Ollama, HuggingFace)의 LLM과 Embedding 모델을 통일된 인터페이스로 사용할 수 있도록 합니다. + +## 디렉토리 구조 + +``` +core/ +├── __init__.py +├── factory.py +└── README.md +``` + +## 파일 설명 + +### `__init__.py` +core 모듈의 공개 인터페이스를 정의합니다. + +**주요 내보내기:** +- **LLM 팩토리 함수들:** + - `get_llm`: 환경변수(`LLM_PROVIDER`)에 따라 적절한 LLM 제공자를 선택하여 반환 + - `get_llm_openai`: OpenAI LLM 인스턴스 생성 + - `get_llm_azure`: Azure OpenAI LLM 인스턴스 생성 + - `get_llm_bedrock`: AWS Bedrock LLM 인스턴스 생성 + - `get_llm_gemini`: Google Gemini LLM 인스턴스 생성 + - `get_llm_ollama`: Ollama LLM 인스턴스 생성 + - `get_llm_huggingface`: HuggingFace LLM 인스턴스 생성 + +- **Embedding 팩토리 함수들:** + - `get_embeddings`: 환경변수(`EMBEDDING_PROVIDER`)에 따라 적절한 Embedding 제공자를 선택하여 반환 + - `get_embeddings_openai`: OpenAI Embedding 인스턴스 생성 + - `get_embeddings_azure`: Azure OpenAI Embedding 인스턴스 생성 + - `get_embeddings_bedrock`: AWS Bedrock Embedding 인스턴스 생성 + - `get_embeddings_gemini`: Google Gemini Embedding 인스턴스 생성 + - `get_embeddings_ollama`: Ollama Embedding 인스턴스 생성 + - `get_embeddings_huggingface`: HuggingFace Embedding 인스턴스 생성 + +### `factory.py` +LLM과 Embedding 모델을 생성하는 팩토리 함수들의 구현을 포함합니다. + +**주요 내용:** + +#### LLM 팩토리 함수들 + +- **`get_llm(**kwargs) -> BaseLanguageModel`** + - 환경변수 `LLM_PROVIDER`를 확인하여 적절한 LLM 제공자를 선택합니다. + - 지원하는 제공자: `openai`, `azure`, `bedrock`, `gemini`, `ollama`, `huggingface` + - 각 제공자별 전용 함수를 호출하여 LLM 인스턴스를 반환합니다. + +- **제공자별 LLM 생성 함수들:** + - `get_llm_openai(**kwargs)`: `ChatOpenAI` 인스턴스 생성 + - 환경변수: `OPEN_AI_LLM_MODEL`, `OPEN_AI_KEY` + - `get_llm_azure(**kwargs)`: `AzureChatOpenAI` 인스턴스 생성 + - 환경변수: `AZURE_OPENAI_LLM_KEY`, `AZURE_OPENAI_LLM_ENDPOINT`, `AZURE_OPENAI_LLM_MODEL`, `AZURE_OPENAI_LLM_API_VERSION` + - `get_llm_bedrock(**kwargs)`: `ChatBedrockConverse` 인스턴스 생성 + - 환경변수: `AWS_BEDROCK_LLM_MODEL`, `AWS_BEDROCK_LLM_ACCESS_KEY_ID`, `AWS_BEDROCK_LLM_SECRET_ACCESS_KEY`, `AWS_BEDROCK_LLM_REGION` + - `get_llm_gemini(**kwargs)`: `ChatGoogleGenerativeAI` 인스턴스 생성 + - 환경변수: `GEMINI_LLM_MODEL` + - `get_llm_ollama(**kwargs)`: `ChatOllama` 인스턴스 생성 + - 환경변수: `OLLAMA_LLM_MODEL`, `OLLAMA_LLM_BASE_URL` (선택적) + - `get_llm_huggingface(**kwargs)`: `ChatHuggingFace` 인스턴스 생성 + - 환경변수: `HUGGING_FACE_LLM_MODEL`, `HUGGING_FACE_LLM_REPO_ID`, `HUGGING_FACE_LLM_ENDPOINT`, `HUGGING_FACE_LLM_API_TOKEN` + +#### Embedding 팩토리 함수들 + +- **`get_embeddings() -> Optional[BaseLanguageModel]`** + - 환경변수 `EMBEDDING_PROVIDER`를 확인하여 적절한 Embedding 제공자를 선택합니다. + - 지원하는 제공자: `openai`, `azure`, `bedrock`, `gemini`, `ollama`, `huggingface` + - 각 제공자별 전용 함수를 호출하여 Embedding 인스턴스를 반환합니다. + +- **제공자별 Embedding 생성 함수들:** + - `get_embeddings_openai()`: `OpenAIEmbeddings` 인스턴스 생성 + - 환경변수: `OPEN_AI_EMBEDDING_MODEL`, `OPEN_AI_KEY` + - `get_embeddings_azure()`: `AzureOpenAIEmbeddings` 인스턴스 생성 + - 환경변수: `AZURE_OPENAI_EMBEDDING_KEY`, `AZURE_OPENAI_EMBEDDING_ENDPOINT`, `AZURE_OPENAI_EMBEDDING_MODEL`, `AZURE_OPENAI_EMBEDDING_API_VERSION` + - `get_embeddings_bedrock()`: `BedrockEmbeddings` 인스턴스 생성 + - 환경변수: `AWS_BEDROCK_EMBEDDING_MODEL`, `AWS_BEDROCK_EMBEDDING_ACCESS_KEY_ID`, `AWS_BEDROCK_EMBEDDING_SECRET_ACCESS_KEY`, `AWS_BEDROCK_EMBEDDING_REGION` + - `get_embeddings_gemini()`: `GoogleGenerativeAIEmbeddings` 인스턴스 생성 + - 환경변수: `GEMINI_EMBEDDING_MODEL`, `GEMINI_EMBEDDING_KEY` + - `get_embeddings_ollama()`: `OllamaEmbeddings` 인스턴스 생성 + - 환경변수: `OLLAMA_EMBEDDING_MODEL`, `OLLAMA_EMBEDDING_BASE_URL` + - `get_embeddings_huggingface()`: `HuggingFaceEndpointEmbeddings` 인스턴스 생성 + - 환경변수: `HUGGING_FACE_EMBEDDING_MODEL`, `HUGGING_FACE_EMBEDDING_REPO_ID`, `HUGGING_FACE_EMBEDDING_API_TOKEN` + +## 사용 방법 + +### 1. `utils/llm/chains.py`에서의 사용 + +LangChain 체인을 생성할 때 LLM 인스턴스를 가져옵니다: + +```python +from utils.llm.core import get_llm + +# 환경변수 LLM_PROVIDER에 따라 적절한 LLM 반환 +llm = get_llm() + +# 체인 생성 시 사용 +chain = prompt | llm | output_parser +``` + +**사용 위치:** `/home/dwlee/Lang2SQL/utils/llm/chains.py`의 모듈 레벨에서 `llm = get_llm()`로 전역 LLM 인스턴스 생성 + +**사용되는 체인:** +- Query Maker Chain +- Query Enrichment Chain +- Profile Extraction Chain +- Question Gate Chain +- Document Suitability Chain + +### 2. `utils/llm/vectordb/faiss_db.py`에서의 사용 + +FAISS 벡터 데이터베이스를 생성하거나 로드할 때 Embedding 모델을 가져옵니다: + +```python +from utils.llm.core import get_embeddings + +# 환경변수 EMBEDDING_PROVIDER에 따라 적절한 Embedding 반환 +embeddings = get_embeddings() + +# FAISS 벡터 DB 생성 +db = FAISS.from_documents(documents, embeddings) + +# 또는 로드 +db = FAISS.load_local(vectordb_path, embeddings, allow_dangerous_deserialization=True) +``` + +**사용 위치:** `/home/dwlee/Lang2SQL/utils/llm/vectordb/faiss_db.py`의 `get_faiss_vector_db()` 함수 + +### 3. `utils/llm/vectordb/pgvector_db.py`에서의 사용 + +PGVector 벡터 데이터베이스를 생성하거나 연결할 때 Embedding 모델을 가져옵니다: + +```python +from utils.llm.core import get_embeddings + +# 환경변수 EMBEDDING_PROVIDER에 따라 적절한 Embedding 반환 +embeddings = get_embeddings() + +# PGVector 벡터 스토어 생성 +vector_store = PGVector.from_documents( + documents=documents, + embedding=embeddings, + collection_name=collection_name, + connection_string=connection_string, +) +``` + +**사용 위치:** `/home/dwlee/Lang2SQL/utils/llm/vectordb/pgvector_db.py`의 `get_pgvector_db()` 함수 + +## 환경변수 설정 + +이 모듈을 사용하려면 다음 환경변수들을 설정해야 합니다: + +### LLM 설정 + +```bash +# LLM 제공자 선택 (필수) +export LLM_PROVIDER="openai" # 또는 azure, bedrock, gemini, ollama, huggingface + +# OpenAI 설정 +export OPEN_AI_LLM_MODEL="gpt-4o" +export OPEN_AI_KEY="your-api-key" + +# Azure OpenAI 설정 +export AZURE_OPENAI_LLM_KEY="your-key" +export AZURE_OPENAI_LLM_ENDPOINT="your-endpoint" +export AZURE_OPENAI_LLM_MODEL="your-deployment-name" +export AZURE_OPENAI_LLM_API_VERSION="2023-07-01-preview" + +# AWS Bedrock 설정 +export AWS_BEDROCK_LLM_MODEL="anthropic.claude-3-sonnet-20240229-v1:0" +export AWS_BEDROCK_LLM_ACCESS_KEY_ID="your-access-key" +export AWS_BEDROCK_LLM_SECRET_ACCESS_KEY="your-secret-key" +export AWS_BEDROCK_LLM_REGION="us-east-1" + +# Gemini 설정 +export GEMINI_LLM_MODEL="gemini-pro" + +# Ollama 설정 +export OLLAMA_LLM_MODEL="llama2" +export OLLAMA_LLM_BASE_URL="http://localhost:11434" # 선택적 + +# HuggingFace 설정 +export HUGGING_FACE_LLM_MODEL="meta-llama/Llama-2-7b-chat-hf" +export HUGGING_FACE_LLM_REPO_ID="your-repo-id" +export HUGGING_FACE_LLM_ENDPOINT="your-endpoint" +export HUGGING_FACE_LLM_API_TOKEN="your-token" +``` + +### Embedding 설정 + +```bash +# Embedding 제공자 선택 (필수) +export EMBEDDING_PROVIDER="openai" # 또는 azure, bedrock, gemini, ollama, huggingface + +# OpenAI Embedding 설정 +export OPEN_AI_EMBEDDING_MODEL="text-embedding-ada-002" +export OPEN_AI_KEY="your-api-key" + +# Azure OpenAI Embedding 설정 +export AZURE_OPENAI_EMBEDDING_KEY="your-key" +export AZURE_OPENAI_EMBEDDING_ENDPOINT="your-endpoint" +export AZURE_OPENAI_EMBEDDING_MODEL="your-deployment-name" +export AZURE_OPENAI_EMBEDDING_API_VERSION="2023-07-01-preview" + +# AWS Bedrock Embedding 설정 +export AWS_BEDROCK_EMBEDDING_MODEL="amazon.titan-embed-text-v1" +export AWS_BEDROCK_EMBEDDING_ACCESS_KEY_ID="your-access-key" +export AWS_BEDROCK_EMBEDDING_SECRET_ACCESS_KEY="your-secret-key" +export AWS_BEDROCK_EMBEDDING_REGION="us-east-1" + +# Gemini Embedding 설정 +export GEMINI_EMBEDDING_MODEL="models/embedding-001" +export GEMINI_EMBEDDING_KEY="your-api-key" + +# Ollama Embedding 설정 +export OLLAMA_EMBEDDING_MODEL="nomic-embed-text" +export OLLAMA_EMBEDDING_BASE_URL="http://localhost:11434" + +# HuggingFace Embedding 설정 +export HUGGING_FACE_EMBEDDING_MODEL="sentence-transformers/all-MiniLM-L6-v2" +export HUGGING_FACE_EMBEDDING_REPO_ID="your-repo-id" +export HUGGING_FACE_EMBEDDING_API_TOKEN="your-token" +``` + +## 설계 패턴 + +이 모듈은 **팩토리 패턴(Factory Pattern)**을 사용하여 구현되었습니다: + +1. **통일된 인터페이스**: `get_llm()`과 `get_embeddings()` 함수를 통해 다양한 제공자를 동일한 방식으로 사용 가능 +2. **환경변수 기반 설정**: 코드 변경 없이 환경변수만 수정하여 다른 제공자로 전환 가능 +3. **확장성**: 새로운 제공자를 추가하려면 `factory.py`에 해당 제공자의 생성 함수만 추가하면 됨 + +## 지원하는 제공자 + +### LLM 제공자 +- **OpenAI**: GPT 모델 시리즈 +- **Azure OpenAI**: Azure에서 호스팅되는 OpenAI 모델 +- **AWS Bedrock**: Claude, Llama 등 다양한 모델 +- **Google Gemini**: Gemini 프로/플래시 모델 +- **Ollama**: 로컬에서 실행되는 오픈소스 LLM +- **HuggingFace**: HuggingFace Hub/Endpoint를 통한 모델 접근 + +### Embedding 제공자 +- **OpenAI**: text-embedding-ada-002 등 +- **Azure OpenAI**: Azure에서 호스팅되는 OpenAI Embedding 모델 +- **AWS Bedrock**: Amazon Titan Embedding 모델 +- **Google Gemini**: Gemini Embedding 모델 +- **Ollama**: 로컬에서 실행되는 Embedding 모델 +- **HuggingFace**: HuggingFace Hub/Endpoint를 통한 Embedding 모델 + diff --git a/utils/llm/graph_utils/README.md b/utils/llm/graph_utils/README.md new file mode 100644 index 0000000..595323a --- /dev/null +++ b/utils/llm/graph_utils/README.md @@ -0,0 +1,185 @@ +# graph_utils + +이 모듈은 **LangGraph workflow**를 위한 그래프 유틸리티들을 제공합니다. Lang2SQL 프로젝트에서 자연어 질문을 SQL 쿼리로 변환하는 워크플로우를 LangGraph를 사용하여 구성합니다. + +## 디렉토리 구조 + +``` +graph_utils/ +├── __init__.py +├── base.py +├── basic_graph.py +├── enriched_graph.py +├── profile_utils.py +└── README.md +``` + +## 파일 설명 + +### `__init__.py` +그래프 관련 유틸리티 모듈의 공개 인터페이스를 정의합니다. + +**주요 사용:** +- **상태 및 노드 식별자:** + - `QueryMakerState`: 그래프의 상태 타입 정의 + - `GET_TABLE_INFO`, `QUERY_MAKER`, `PROFILE_EXTRACTION`, `CONTEXT_ENRICHMENT`: 노드 식별자 상수 + +- **노드 함수들:** + - `get_table_info_node`: 테이블 정보 검색 노드 + - `query_maker_node`: SQL 쿼리 생성 노드 + - `profile_extraction_node`: 질문 프로파일 추출 노드 + - `context_enrichment_node`: 컨텍스트 보강 노드 + +- **그래프 빌더들:** + - `basic_builder`: 기본 워크플로우 그래프 빌더 + - `enriched_builder`: 확장된 워크플로우 그래프 빌더 + +### `base.py` +LangGraph 워크플로우의 핵심 노드 함수들과 상태 정의를 포함합니다. + +**주요 내용:** +- **상태 타입 (`QueryMakerState`):** TypedDict를 사용하여 그래프 상태 구조를 정의 + - `messages`: LLM 메시지 리스트 + - `user_database_env`: 사용자 데이터베이스 환경 + - `searched_tables`: 검색된 테이블 정보 + - `question_profile`: 질문 프로파일 정보 + - `generated_query`: 생성된 SQL 쿼리 + - 기타 워크플로우에 필요한 상태 정보 + +- **노드 식별자 상수:** + - `QUESTION_GATE`, `EVALUATE_DOCUMENT_SUITABILITY`, `GET_TABLE_INFO`, `TOOL`, `TABLE_FILTER`, `QUERY_MAKER`, `PROFILE_EXTRACTION`, `CONTEXT_ENRICHMENT` + +- **노드 함수들:** + - `question_gate_node`: 사용자 질문이 SQL로 답변 가능한지 판별하는 게이트 노드 + - `get_table_info_node`: 벡터 검색을 통해 관련 테이블 정보를 가져오는 노드 + - `document_suitability_node`: 검색된 테이블들의 문서 적합성 점수를 계산하는 노드 + - `profile_extraction_node`: 자연어 쿼리로부터 질문 유형(시계열, 집계, 필터 등)을 추출하는 노드 + - `context_enrichment_node`: 질문과 관련된 메타데이터를 기반으로 질문을 풍부하게 만드는 노드 + - `query_maker_node`: 최종 SQL 쿼리를 생성하는 노드 + +### `basic_graph.py` +기본 워크플로우를 위한 StateGraph 구성을 정의합니다. + +**워크플로우 순서:** +``` +QUESTION_GATE → GET_TABLE_INFO → EVALUATE_DOCUMENT_SUITABILITY → QUERY_MAKER → END +``` + +**주요 내용:** +- `StateGraph`를 사용하여 기본 워크플로우 그래프 생성 +- `builder` 객체를 export하여 다른 모듈에서 사용 가능 +- 조건부 라우팅(`add_conditional_edges`)을 통해 게이트 노드 이후 흐름 제어 + +### `enriched_graph.py` +기본 워크플로우에 프로파일 추출과 컨텍스트 보강 단계를 추가한 확장된 그래프입니다. + +**워크플로우 순서:** +``` +QUESTION_GATE → GET_TABLE_INFO → EVALUATE_DOCUMENT_SUITABILITY → +PROFILE_EXTRACTION → CONTEXT_ENRICHMENT → QUERY_MAKER → END +``` + +**주요 내용:** +- `basic_graph`와 동일한 구조이지만 `PROFILE_EXTRACTION`과 `CONTEXT_ENRICHMENT` 노드가 추가됨 +- 더 정교한 질문 분석과 컨텍스트 보강을 통해 더 나은 SQL 쿼리 생성이 가능 + +### `profile_utils.py` +질문 프로파일 객체를 텍스트로 변환하는 유틸리티 함수를 제공합니다. + +**주요 함수:** +- `profile_to_text(profile_obj) -> str`: 질문 프로파일 객체를 읽기 쉬운 텍스트 형태로 변환 + - 시계열 분석 필요 여부 + - 집계 함수 필요 여부 + - WHERE 조건 필요 여부 + - GROUP BY 필요 여부 + - 정렬/순위 필요 여부 + - 기간 비교 필요 여부 + - 의도 유형 정보 + +## 사용 방법 + +### 1. `engine/query_executor.py`에서의 사용 + +기본 또는 확장된 그래프 빌더를 선택하여 쿼리를 실행합니다: + +```python +from utils.llm.graph_utils.basic_graph import builder as basic_builder +from utils.llm.graph_utils.enriched_graph import builder as enriched_builder + +# 그래프 선택 +if use_enriched_graph: + graph_builder = enriched_builder +else: + graph_builder = basic_builder + +# 그래프 컴파일 및 실행 +graph = graph_builder.compile() +result = graph.invoke({ + "messages": [HumanMessage(content=query)], + "user_database_env": database_env, + # ... 기타 상태 정보 +}) +``` + +**사용 위치:** `/home/dwlee/Lang2SQL/engine/query_executor.py`의 `execute_query()` 함수 + +### 2. `interface/core/session_utils.py`에서의 사용 + +Streamlit 세션 상태에서 그래프 빌더를 동적으로 초기화합니다: + +```python +def init_graph(use_enriched: bool) -> str: + builder_module = ( + "utils.llm.graph_utils.enriched_graph" + if use_enriched + else "utils.llm.graph_utils.basic_graph" + ) + builder = __import__(builder_module, fromlist=["builder"]).builder + st.session_state["graph"] = builder.compile() + return "확장된" if use_enriched else "기본" +``` + +**사용 위치:** `/home/dwlee/Lang2SQL/interface/core/session_utils.py`의 `init_graph()` 함수 + +### 3. `interface/app_pages/graph_builder.py`에서의 사용 + +Streamlit 인터페이스에서 커스텀 그래프를 구성할 때 개별 노드 함수들을 사용합니다: + +```python +from utils.llm.graph_utils.base import ( + CONTEXT_ENRICHMENT, + GET_TABLE_INFO, + PROFILE_EXTRACTION, + QUERY_MAKER, + QueryMakerState, + context_enrichment_node, + get_table_info_node, + profile_extraction_node, + query_maker_node, +) + +# 커스텀 시퀀스에 따라 노드 등록 +builder = StateGraph(QueryMakerState) +for node_id in sequence: + if node_id == GET_TABLE_INFO: + builder.add_node(GET_TABLE_INFO, get_table_info_node) + elif node_id == PROFILE_EXTRACTION: + builder.add_node(PROFILE_EXTRACTION, profile_extraction_node) + # ... 기타 노드들 +``` + +**사용 위치:** `/home/dwlee/Lang2SQL/interface/app_pages/graph_builder.py`의 `build_state_graph()` 함수 + +## 워크플로우 개요 + +이 모듈은 **LangGraph**를 사용하여 자연어 질문을 SQL 쿼리로 변환하는 워크플로우를 구현합니다: + +1. **QUESTION_GATE**: 질문이 SQL로 답변 가능한지 판별 +2. **GET_TABLE_INFO**: 벡터 검색을 통해 관련 테이블 정보 검색 +3. **EVALUATE_DOCUMENT_SUITABILITY**: 검색된 테이블들의 적합성 평가 +4. **PROFILE_EXTRACTION** (확장 그래프만): 질문의 특성 추출 (시계열, 집계 등) +5. **CONTEXT_ENRICHMENT** (확장 그래프만): 질문을 컨텍스트 정보로 보강 +6. **QUERY_MAKER**: 최종 SQL 쿼리 생성 + +각 노드는 `QueryMakerState`를 입력으로 받아 상태를 업데이트하고 반환합니다. + diff --git a/utils/llm/output_schema/README.md b/utils/llm/output_schema/README.md new file mode 100644 index 0000000..2e220c2 --- /dev/null +++ b/utils/llm/output_schema/README.md @@ -0,0 +1,114 @@ +# output_schema 모듈 + +LLM 구조화 출력을 위한 Pydantic 모델 정의 모듈입니다. + +## 디렉토리 구조 + +``` +output_schema/ +├── __pycache__/ +├── document_suitability.py +└── question_suitability.py +``` + +## 파일 목록 및 설명 + +### document_suitability.py + +**목적**: LLM 구조화 출력으로부터 테이블별 적합성 평가 결과를 표현하는 Pydantic 모델을 정의합니다. + +**주요 클래스**: + +- `DocumentSuitability`: 단일 테이블에 대한 적합성 평가 결과를 표현하는 모델 + - `table_name` (str): 테이블명 + - `score` (float): 0.0~1.0 사이의 적합도 점수 + - `reason` (str): 한국어 한두 문장 근거 + - `matched_columns` (List[str]): 질문과 직접 연관된 컬럼명 목록 + - `missing_entities` (List[str]): 부족한 엔티티/지표/기간 등 + +- `DocumentSuitabilityList`: 문서 적합성 평가 결과 리스트 래퍼 + - `results` (List[DocumentSuitability]): 평가 결과 목록 + - OpenAI Structured Outputs 호환을 위해 명시적 최상위 키(`results`)를 제공 + +### question_suitability.py + +**목적**: LLM 구조화 출력으로부터 SQL 적합성 판단 결과를 표현하는 Pydantic 모델을 정의합니다. + +**주요 클래스**: + +- `QuestionSuitability`: SQL 생성 적합성 결과 모델 + - `reason` (str): 보완/설명 사유 요약 + - `missing_entities` (list[str]): 질문에서 누락된 핵심 엔터티/기간 등 + - `requires_data_science` (bool): SQL을 넘어 ML/통계 분석이 필요한지 여부 + +## 사용 방법 + +### Import 및 사용 위치 + +이 모듈의 클래스들은 `utils/llm/chains.py`에서 import되어 사용됩니다: + +```python +from utils.llm.output_schema.document_suitability import DocumentSuitabilityList +from utils.llm.output_schema.question_suitability import QuestionSuitability +``` + +### 사용 예시 + +#### 1. QuestionSuitability 사용 + +`create_question_gate_chain()` 함수에서 질문 적합성을 판단하는 체인을 생성할 때 사용됩니다: + +```python +def create_question_gate_chain(llm): + """ + 질문 적합성(Question Gate) 체인을 생성합니다. + + Returns: + Runnable: invoke({"question": str}) -> QuestionSuitability + """ + prompt = get_prompt_template("question_gate_prompt") + gate_prompt = ChatPromptTemplate.from_messages( + [SystemMessagePromptTemplate.from_template(prompt)] + ) + return gate_prompt | llm.with_structured_output(QuestionSuitability) +``` + +**사용 흐름**: +1. 사용자 질문을 입력으로 받음 +2. LLM이 구조화된 출력으로 `QuestionSuitability` 객체를 반환 +3. SQL 생성이 적합한지 여부와 필요 보완 사항을 판단 + +#### 2. DocumentSuitabilityList 사용 + +`create_document_suitability_chain()` 함수에서 문서(테이블) 적합성을 평가하는 체인을 생성할 때 사용됩니다: + +```python +def create_document_suitability_chain(llm): + """ + 문서 적합성 평가 체인을 생성합니다. + + Returns: + Runnable: invoke({"question": str, "tables": dict}) -> {"results": DocumentSuitability[]} + """ + prompt = get_prompt_template("document_suitability_prompt") + doc_prompt = ChatPromptTemplate.from_messages( + [SystemMessagePromptTemplate.from_template(prompt)] + ) + return doc_prompt | llm.with_structured_output(DocumentSuitabilityList) +``` + +**사용 흐름**: +1. 사용자 질문과 검색된 테이블 메타데이터를 입력으로 받음 +2. LLM이 각 테이블에 대한 적합도 점수와 평가 결과를 포함한 `DocumentSuitabilityList` 객체를 반환 +3. 가장 적합한 테이블을 선택하거나 적합도가 낮은 경우 사용자에게 알림 + +### 구조화 출력 활용 + +두 모델 모두 LangChain의 `with_structured_output()` 메서드와 함께 사용되어 LLM의 출력을 자동으로 Pydantic 모델로 변환합니다. 이를 통해: + +- 타입 안전성 보장 +- 자동 검증 및 직렬화 +- 명확한 API 계약 + +을 제공합니다. + diff --git a/utils/llm/output_parser/document_suitability.py b/utils/llm/output_schema/document_suitability.py similarity index 100% rename from utils/llm/output_parser/document_suitability.py rename to utils/llm/output_schema/document_suitability.py diff --git a/utils/llm/output_parser/question_suitability.py b/utils/llm/output_schema/question_suitability.py similarity index 100% rename from utils/llm/output_parser/question_suitability.py rename to utils/llm/output_schema/question_suitability.py diff --git a/utils/llm/tools/README.md b/utils/llm/tools/README.md new file mode 100644 index 0000000..fa7153d --- /dev/null +++ b/utils/llm/tools/README.md @@ -0,0 +1,284 @@ +## utils.llm.tools 개요 + +Lang2SQL 파이프라인에서 DataHub 메타데이터 수집 및 검색, 그리고 LangGraph ChatBot에서 사용하는 도구(Tool) 함수들을 제공하는 모듈입니다. 병렬 처리 기반의 효율적인 메타데이터 수집과 LangChain Tool 인터페이스를 통한 챗봇 기능을 지원합니다. + +### 파일 구조 + +``` +utils/llm/tools/ +├── __init__.py # 모듈 진입점, 6개 함수 export +├── datahub.py # DataHub 메타데이터 수집 및 처리 +└── chatbot_tool.py # LangGraph ChatBot용 Tool 함수들 +``` + +### 각 파일 상세 설명 + +#### __init__.py + +**목적**: tools 모듈의 공개 인터페이스 정의 + +**Export 함수들**: + +**datahub 모듈에서**: +- `set_gms_server`: GMS 서버 설정 +- `get_info_from_db`: LangChain Document 리스트로 테이블/컬럼 정보 반환 +- `get_metadata_from_db`: 전체 메타데이터 딕셔너리 리스트 반환 + +**chatbot_tool 모듈에서**: +- `search_database_tables`: 벡터 검색 기반 테이블 정보 검색 +- `get_glossary_terms`: 용어집 정보 조회 +- `get_query_examples`: 쿼리 예제 조회 + +#### datahub.py + +**목적**: DataHub에서 테이블 및 컬럼 메타데이터를 수집하고 LangChain Document 형식으로 변환 + +**주요 함수**: + +1. **`set_gms_server(gms_server: str)`** + - 환경변수 `DATAHUB_SERVER`를 설정하고 DatahubMetadataFetcher 초기화 + - 유효하지 않은 서버 URL 시 ValueError 발생 + +2. **`get_info_from_db(max_workers: int = 8) -> List[Document]`** + - DataHub에서 모든 테이블 메타데이터를 수집하여 LangChain Document 리스트 반환 + - 각 Document에는 테이블명, 설명, 컬럼 정보가 포함 + - 형식: `"{테이블명}: {설명}\nColumns:\n {컬럼명}: {컬럼설명}"` + - `parallel_process()`로 병렬 처리 (기본 8 워커) + - 반환: LangChain Document 리스트 + +3. **`get_metadata_from_db() -> List[Dict]`** + - DataHub에서 전체 메타데이터를 딕셔너리 형태로 수집 + - 각 테이블의 상세 메타데이터 반환 + - 반환: 메타데이터 딕셔너리 리스트 + +**내부 헬퍼 함수**: + +- **`parallel_process()`**: ThreadPoolExecutor 기반 병렬 처리 유틸리티 + - tqdm 진행률 표시 지원 + - `max_workers`: 동시 실행 워커 수 (기본: 8) + +- **`_get_fetcher()`**: 환경변수 기반 DatahubMetadataFetcher 인스턴스 생성 + +- **`_process_urn()`**: URN에서 테이블명과 설명 추출 + +- **`_get_table_info()`**: 병렬 처리로 모든 테이블 정보 수집 + +- **`_get_column_info()`**: 특정 테이블의 컬럼 정보 수집 + +- **`_extract_dataset_name_from_urn()`**: URN에서 데이터셋 이름 추출 + +**의존성**: +- `langchain.schema.Document`: LangChain Document 타입 +- `utils.data.datahub_source.DatahubMetadataFetcher`: DataHub 메타데이터 페처 +- `concurrent.futures.ThreadPoolExecutor`: 병렬 처리 +- `tqdm`: 진행률 표시 + +**사용처**: +- `utils/llm/vectordb/faiss_db.py`: FAISS 벡터DB 초기화 시 메타데이터 수집 +- `utils/llm/vectordb/pgvector_db.py`: pgvector 벡터DB 초기화 시 메타데이터 수집 + +**특징**: +- 병렬 처리로 성능 최적화 +- tqdm 진행률 표시 +- 자동 재시도/에러 핸들링 +- LangChain Document 형식 지원 + +#### chatbot_tool.py + +**목적**: LangGraph ChatBot에서 사용하는 LangChain Tool 함수들 + +**주요 함수 (모두 `@tool` 데코레이터 사용)**: + +1. **`search_database_tables(query, retriever_name, top_n, device)`** + - **목적**: 자연어 쿼리를 기반으로 관련 테이블 정보 검색 + - **파라미터**: + - `query`: 검색할 자연어 질문 + - `retriever_name`: "기본" 또는 "Reranker" (기본: "기본") + - `top_n`: 반환할 테이블 개수 (기본: 5) + - `device`: "cpu" 또는 "cuda" (기본: "cpu") + - **반환**: `{테이블명: {table_description, 컬럼명: 컬럼설명, ...}}` + - **내부**: `utils.llm.retrieval.search_tables()` 호출 + - **사용 시기**: + - SQL 쿼리 생성 전 스키마 정보 필요 + - "어떤 테이블을 사용해야 해?" + - "고객 관련 테이블 정보를 알려줘" + +2. **`get_glossary_terms(gms_server)`** + - **목적**: DataHub 용어집(Glossary) 정보 조회 + - **파라미터**: + - `gms_server`: DataHub GMS 서버 URL (기본: "http://35.222.65.99:8080") + - **반환**: `[{name, description, children: [...]}, ...]` + - **내부**: `GlossaryService.get_glossary_data()` 호출 + - **특징**: + - 조직 특화 용어/비즈니스 정의 제공 + - `_simplify_glossary_data()`로 필수 필드만 추출 + - **사용 시기**: + - 모호한 용어 이해 필요 + - "용어집을 보여줘" + - 조직 내부 용어 확인 + +3. **`get_query_examples(gms_server, start, count, query)`** + - **목적**: DataHub에 저장된 SQL 쿼리 예제 조회 + - **파라미터**: + - `gms_server`: DataHub GMS 서버 URL (기본: "http://35.222.65.99:8080") + - `start`: 시작 위치 (기본: 0) + - `count`: 반환 개수 (기본: 10) + - `query`: 검색 쿼리 (기본: "*") + - **반환**: `[{name, description, statement}, ...]` + - **내부**: `QueryService.get_query_data()` 호출 + - **특징**: 조직 내 검증된 쿼리 패턴 참고 + - **사용 시기**: + - 복잡한 쿼리 생성 시 참고 + - "쿼리 예제를 보여줘" + - "비슷한 쿼리 있어?" + +**내부 헬퍼 함수**: + +- **`_simplify_glossary_data()`**: 용어집 데이터를 name, description, children만 포함하는 간단한 형태로 변환 + +**의존성**: +- `langchain_core.tools.tool`: LangChain Tool 데코레이터 +- `utils.data.datahub_services.base_client.DataHubBaseClient`: DataHub 기본 클라이언트 +- `utils.data.datahub_services.glossary_service.GlossaryService`: 용어집 서비스 +- `utils.data.datahub_services.query_service.QueryService`: 쿼리 서비스 +- `utils.llm.retrieval.search_tables`: 벡터 검색 함수 + +**사용처**: +- `utils/llm/chatbot.py`: ChatBot 클래스에서 LLM에 바인딩하여 사용 + +**특징**: +- LangChain Tool 인터페이스 준수 +- LLM이 자동으로 필요 시 호출 +- 상세한 docstring으로 LLM 이해도 향상 +- 에러 처리 및 fallback 제공 + +### 사용 방법 + +#### 1. DataHub 메타데이터 수집 (vectorDB 초기화) + +```python +from utils.llm.tools import get_info_from_db + +# 모든 테이블 메타데이터를 LangChain Document로 수집 +documents = get_info_from_db(max_workers=8) + +# 각 document는 다음과 같은 형식: +# "테이블명: 설명\nColumns:\n 컬럼1: 설명1\n 컬럼2: 설명2" +``` + +#### 2. GMS 서버 설정 + +```python +from utils.llm.tools import set_gms_server + +# DataHub 서버 설정 +set_gms_server("http://localhost:8080") +``` + +#### 3. ChatBot에서 Tool 사용 + +```python +from utils.llm.chatbot import ChatBot +from utils.llm.tools import ( + search_database_tables, + get_glossary_terms, + get_query_examples +) + +# ChatBot 초기화 (도구들이 자동으로 바인딩됨) +chatbot = ChatBot( + openai_api_key="your-key", + model_name="gpt-4o-mini", + gms_server="http://localhost:8080" +) + +# LLM이 필요시 자동으로 tool 호출 +response = chatbot.invoke("고객 테이블 정보를 알려줘") +# LLM이 search_database_tables를 자동으로 호출 +``` + +#### 4. 직접 Tool 함수 호출 + +```python +from utils.llm.tools import search_database_tables, get_glossary_terms, get_query_examples + +# 테이블 검색 +tables = search_database_tables( + query="고객 정보", + retriever_name="기본", + top_n=5 +) + +# 용어집 조회 +glossary = get_glossary_terms(gms_server="http://localhost:8080") + +# 쿼리 예제 조회 +queries = get_query_examples( + gms_server="http://localhost:8080", + start=0, + count=10 +) +``` + +### import 관계 + +**import하는 파일**: +- `utils/llm/chatbot.py`: `from utils.llm.tools import search_database_tables, get_glossary_terms, get_query_examples` +- `utils/llm/vectordb/faiss_db.py`: `from utils.llm.tools import get_info_from_db` +- `utils/llm/vectordb/pgvector_db.py`: `from utils.llm.tools import get_info_from_db` +- `interface/core/config/settings.py`: `from utils.llm.tools import set_gms_server` + +**내부 의존성**: +- `utils.data.datahub_source.DatahubMetadataFetcher`: DataHub 메타데이터 페처 +- `utils.data.datahub_services.*`: DataHub 서비스 레이어 +- `utils.llm.retrieval.search_tables`: 벡터 검색 기능 + +**외부 의존성**: +- `langchain.schema.Document`: LangChain Document 타입 +- `langchain_core.tools.tool`: LangChain Tool 데코레이터 +- `concurrent.futures.ThreadPoolExecutor`: 병렬 처리 +- `tqdm`: 진행률 표시 + +### 환경 변수 요약 + +- **`DATAHUB_SERVER`**: DataHub GMS 서버 URL (예: "http://localhost:8080") +- **`VECTORDB_TYPE`**: 벡터DB 타입 (datahub.py 사용 시 간접적으로 영향) +- **`EMBEDDING_PROVIDER`**: 임베딩 공급자 (retrieval 기능 사용 시 필요) + +### 주요 특징 + +1. **병렬 처리**: 8개 워커로 메타데이터 수집 속도 향상 +2. **LangChain 통합**: Document 및 Tool 인터페이스 지원 +3. **LangGraph ChatBot 연동**: LLM이 자동으로 도구 호출 +4. **진행률 표시**: tqdm을 통한 실시간 진행 상황 표시 +5. **에러 처리**: 유효한 GMS 서버 확인 및 예외 처리 +6. **데이터 정규화**: 조직 특화 데이터를 표준 형식으로 변환 + +### 통합 흐름 + +#### 메타데이터 수집 흐름 (벡터DB 초기화 시) + +1. `get_info_from_db()` 호출 +2. `_get_fetcher()`로 DatahubMetadataFetcher 인스턴스 생성 +3. `parallel_process()`로 병렬 테이블 정보 수집 +4. 각 테이블별로 컬럼 정보 추가 수집 +5. LangChain Document 리스트로 변환하여 반환 +6. vectordb가 이를 임베딩하여 벡터DB에 저장 + +#### ChatBot 도구 사용 흐름 + +1. ChatBot 초기화 시 `@tool` 데코레이터 함수들을 tools 리스트에 추가 +2. LLM에 `bind_tools(tools)`로 바인딩 +3. 사용자 질문 처리 중 LLM이 필요한 도구 판단 +4. ToolNode가 자동으로 해당 함수 호출 +5. 결과를 LLM에 전달하여 최종 응답 생성 + +### 개선 가능 영역 + +- 추가 메타데이터 타입 지원 (용어집, 관계 등) +- 캐싱 메커니즘으로 성능 향상 +- 재시도 로직 강화 +- 더 많은 Tool 함수 추가 +- 도구 사용 통계 및 모니터링 +- 비동기 처리 지원 + diff --git a/utils/llm/vectordb/README.md b/utils/llm/vectordb/README.md new file mode 100644 index 0000000..356ffcd --- /dev/null +++ b/utils/llm/vectordb/README.md @@ -0,0 +1,223 @@ +## utils.llm.vectordb 개요 + +Lang2SQL 파이프라인에서 테이블 메타데이터를 벡터화하여 저장하고 검색하기 위한 벡터 데이터베이스 모듈입니다. FAISS와 pgvector 두 가지 백엔드를 지원하며, 환경변수를 통해 선택이 가능합니다. + +### 파일 구조 + +``` +utils/llm/vectordb/ +├── __init__.py # 모듈 진입점, get_vector_db 함수 export +├── factory.py # VectorDB 팩토리 - 타입에 따라 적절한 인스턴스 생성 +├── faiss_db.py # FAISS 벡터 데이터베이스 구현 +└── pgvector_db.py # pgvector (PostgreSQL) 벡터 데이터베이스 구현 +``` + +### 각 파일 상세 설명 + +#### __init__.py + +**목적**: 벡터DB 모듈의 공개 인터페이스 정의 + +**Export 함수**: +- `get_vector_db`: 환경변수 기반으로 적절한 벡터DB 인스턴스 반환 + +#### factory.py + +**목적**: VectorDB 타입과 위치에 따라 적절한 VectorDB 인스턴스를 생성하는 팩토리 + +**주요 함수**: + +1. **`get_vector_db(vectordb_type=None, vectordb_location=None)`** + - 환경변수 또는 파라미터로 VectorDB 타입과 위치를 받아 적절한 인스턴스 반환 + - `vectordb_type`: "faiss" 또는 "pgvector" (기본: 환경변수 `VECTORDB_TYPE`, fallback: "faiss") + - `vectordb_location`: + - FAISS: 디렉토리 경로 + - pgvector: PostgreSQL 연결 문자열 + - 기본: 환경변수 `VECTORDB_LOCATION` + - 반환: FAISS 또는 PGVector 인스턴스 + - 에러: 지원하지 않는 타입 시 ValueError 발생 + +**의존성**: +- `utils.llm.vectordb.faiss_db.get_faiss_vector_db`: FAISS 인스턴스 생성 +- `utils.llm.vectordb.pgvector_db.get_pgvector_db`: PGVector 인스턴스 생성 + +#### faiss_db.py + +**목적**: FAISS 벡터 데이터베이스 구현 (로컬 디스크 기반) + +**주요 함수**: + +1. **`get_faiss_vector_db(vectordb_path=None)`** + - FAISS 벡터 데이터베이스를 로드하거나 새로 생성 + - `vectordb_path`: 저장 경로 (기본: `dev/table_info_db`) + - 동작 방식: + - 기존 DB가 있으면 `FAISS.load_local()`로 로드 + - 없으면 `get_info_from_db()`로 문서 수집 후 `FAISS.from_documents()` 생성 및 저장 + - 반환: FAISS 벡터스토어 인스턴스 + +**의존성**: +- `langchain_community.vectorstores.FAISS`: LangChain FAISS 래퍼 +- `utils.llm.core.get_embeddings`: 임베딩 모델 로드 +- `utils.llm.tools.get_info_from_db`: DataHub에서 테이블 메타데이터 수집 + +**특징**: +- 로컬 디스크에 저장되어 네트워크 연결 불필요 +- 빠른 검색 성능 +- 싱글 머신 환경에 최적화 + +#### pgvector_db.py + +**목적**: pgvector를 활용한 PostgreSQL 벡터 데이터베이스 구현 + +**주요 함수**: + +1. **`get_pgvector_db(connection_string=None, collection_name=None)`** + - pgvector 벡터 데이터베이스를 로드하거나 새로 생성 + - `connection_string`: PostgreSQL 연결 문자열 (기본: 환경변수 조합) + - `collection_name`: 컬렉션 이름 (기본: `lang2sql_table_info_db`) + - 환경변수 (기본값): + - `PGVECTOR_HOST`: "localhost" + - `PGVECTOR_PORT`: "5432" + - `PGVECTOR_USER`: "postgres" + - `PGVECTOR_PASSWORD`: "postgres" + - `PGVECTOR_DATABASE`: "postgres" + - `PGVECTOR_COLLECTION`: "lang2sql_table_info_db" + - 동작 방식: + - 기존 컬렉션이 있고 비어있지 않으면 로드 + - 없거나 비어있으면 `get_info_from_db()`로 문서 수집 후 `PGVector.from_documents()` 생성 + - 반환: PGVector 벡터스토어 인스턴스 + +2. **`_check_collection_exists(connection_string, collection_name)`** + - PostgreSQL에서 컬렉션 존재 여부 확인 + - `langchain_pg_embedding` 테이블에서 collection_name 조회 + - 반환: bool (존재 여부) + +**의존성**: +- `langchain_postgres.vectorstores.PGVector`: LangChain pgvector 래퍼 +- `psycopg2`: PostgreSQL 연결 +- `utils.llm.core.get_embeddings`: 임베딩 모델 로드 +- `utils.llm.tools.get_info_from_db`: DataHub에서 테이블 메타데이터 수집 + +**특징**: +- PostgreSQL 데이터베이스에 저장되어 다중 서버 환경에 적합 +- ACID 트랜잭션 지원 +- 확장 가능한 인프라 +- 네트워크 연결 필요 + +### 사용 방법 + +#### 1. 기본 사용법 (retrieval.py에서 실제 사용) + +```python +from utils.llm.vectordb import get_vector_db + +# 환경변수 기반으로 적절한 벡터DB 로드 +db = get_vector_db() + +# 유사도 검색 +documents = db.similarity_search("고객 테이블", k=5) + +# Retriever 인터페이스 사용 +retriever = db.as_retriever(search_kwargs={"k": 5}) +results = retriever.invoke("매출 관련 테이블") +``` + +#### 2. FAISS 명시적 사용 + +```python +from utils.llm.vectordb.factory import get_vector_db + +# FAISS 타입 지정 +db = get_vector_db(vectordb_type="faiss", vectordb_location="./my_faiss_db") + +# 검색 +results = db.similarity_search("사용자 정보", k=10) +``` + +#### 3. pgvector 명시적 사용 + +```python +from utils.llm.vectordb.factory import get_vector_db + +# pgvector 타입 지정 +connection_string = "postgresql://user:password@localhost:5432/mydb" +db = get_vector_db(vectordb_type="pgvector", vectordb_location=connection_string) + +# 검색 +results = db.similarity_search("주문 테이블", k=5) +``` + +#### 4. 통합 흐름 (Lang2SQL 파이프라인 내) + +`utils/llm/retrieval.py`의 `search_tables()` 함수에서 사용: + +1. `get_vector_db()`로 벡터DB 로드 (환경변수 기반) +2. `similarity_search()` 또는 `retriever.invoke()`로 유사도 기반 검색 +3. 결과를 테이블/컬럼 정보 딕셔너리로 파싱 및 반환 + +**경로**: `utils/llm/retrieval.py` (60-104번째 줄) + +#### 5. CLI 환경변수 설정 + +```bash +# FAISS 사용 +export VECTORDB_TYPE=faiss +export VECTORDB_LOCATION=./dev/table_info_db # 선택사항 + +# pgvector 사용 +export VECTORDB_TYPE=pgvector +export PGVECTOR_HOST=localhost +export PGVECTOR_PORT=5432 +export PGVECTOR_USER=postgres +export PGVECTOR_PASSWORD=postgres +export PGVECTOR_DATABASE=postgres +export PGVECTOR_COLLECTION=lang2sql_table_info_db +``` + +### import 관계 + +**import하는 파일**: +- `utils/llm/retrieval.py`: `from utils.llm.vectordb import get_vector_db` + +**내부 의존성**: +- `utils/llm/core/factory.py`: `get_embeddings()` - 임베딩 모델 로드 +- `utils/llm/tools/datahub.py`: `get_info_from_db()` - DataHub 메타데이터 수집 + +**외부 의존성**: +- `langchain_community.vectorstores.FAISS`: FAISS 벡터스토어 +- `langchain_postgres.vectorstores.PGVector`: pgvector 벡터스토어 +- `psycopg2`: PostgreSQL 연결 (pgvector 전용) + +### 환경 변수 요약 + +#### VectorDB 타입 선택 +- **`VECTORDB_TYPE`**: "faiss" 또는 "pgvector" (기본: "faiss") + +#### FAISS 환경변수 +- **`VECTORDB_LOCATION`**: FAISS 저장 디렉토리 경로 (기본: `./dev/table_info_db`) + +#### pgvector 환경변수 +- **`PGVECTOR_HOST`**: PostgreSQL 호스트 (기본: "localhost") +- **`PGVECTOR_PORT`**: PostgreSQL 포트 (기본: "5432") +- **`PGVECTOR_USER`**: PostgreSQL 사용자 (기본: "postgres") +- **`PGVECTOR_PASSWORD`**: PostgreSQL 비밀번호 (기본: "postgres") +- **`PGVECTOR_DATABASE`**: PostgreSQL 데이터베이스 (기본: "postgres") +- **`PGVECTOR_COLLECTION`**: 컬렉션 이름 (기본: "lang2sql_table_info_db") +- **`EMBEDDING_PROVIDER`**: 임베딩 모델 공급자 (필수, 모든 타입 공통) + +### 주요 특징 + +1. **이중 백엔드 지원**: FAISS(로컬) 및 pgvector(PostgreSQL) 자유 선택 +2. **자동 초기화**: 벡터DB가 없으면 DataHub에서 자동으로 생성 +3. **환경변수 기반 설정**: 코드 수정 없이 실행 시점에 선택 가능 +4. **LangChain 통합**: 표준 VectorStore 인터페이스 제공 +5. **유사도 검색**: 테이블 메타데이터에 대한 의미 기반 검색 + +### 개선 가능 영역 + +- 다른 벡터DB 지원 (Qdrant 등) +- 증분 인덱싱 지원 +- 벡터DB 버전 관리 +- 성능 최적화 (인덱스 튜닝) +- 모니터링 및 로깅 강화 + diff --git a/utils/visualization/README.md b/utils/visualization/README.md new file mode 100644 index 0000000..1ecd55e --- /dev/null +++ b/utils/visualization/README.md @@ -0,0 +1,125 @@ +## utils.visualization 개요 + +Lang2SQL 파이프라인에서 SQL 쿼리 결과를 시각화하기 위한 유틸리티 모듈입니다. LLM을 활용하여 적절한 차트를 자동 생성하고 Plotly를 통해 렌더링합니다. + +### 파일 구조 + +``` +utils/visualization/ +└── display_chart.py # SQL 결과를 Plotly 차트로 변환하는 핵심 모듈 +``` + +### 각 파일 상세 설명 + +#### display_chart.py + +**목적**: SQL 쿼리 실행 결과를 다양한 형태의 Plotly 차트로 자동 변환하는 모듈 + +**주요 클래스**: + +- **`DisplayChart`**: SQL 결과 시각화를 담당하는 메인 클래스 + - `question` (str): 사용자가 입력한 자연어 질문 + - `sql` (str): 실행된 SQL 쿼리 + - `df_metadata` (str): 데이터프레임의 메타데이터 정보 + +**주요 메서드**: + +1. **`llm_model_for_chart(message_log)`** + - 환경변수 `LLM_PROVIDER`가 "openai"일 경우 ChatOpenAI로 차트 코드 생성 + - 필요 환경변수: `OPEN_AI_KEY`, `OPEN_AI_LLM_MODEL` (기본: "gpt-4o") + - 반환: 생성된 차트 코드 또는 None + +2. **`generate_plotly_code()`** + - 사용자 질문, SQL 쿼리, 데이터프레임 메타데이터를 프롬프트로 구성 + - LLM이 데이터에 맞는 적절한 Plotly 코드 생성 + - 반환: Python 코드 문자열 + +3. **`get_plotly_figure(plotly_code, df, dark_mode=True)`** + - 생성된 Plotly 코드를 실행하여 Figure 객체 생성 + - 에러 발생 시 데이터 타입 기반 fallback 차트 생성: + - 숫자 컬럼 2개 이상 → scatter plot + - 숫자 1개 + 범주 1개 → bar plot + - 범주 1개 (고유값 < 10) → pie chart + - 기타 → line plot + - dark_mode=True 시 "plotly_dark" 템플릿 적용 + - 반환: Plotly Figure 객체 또는 None + +4. **내부 헬퍼 메서드**: + - `_extract_python_code(markdown_string)`: 마크다운에서 Python 코드 블록 추출 + - `_sanitize_plotly_code(raw_plotly_code)`: 불필요한 `fig.show()` 문 제거 + +**의존성**: +- `pandas`: 데이터프레임 처리 +- `plotly.express` (px): 간단한 차트 생성 +- `plotly.graph_objects` (go): 고급 차트 구성 +- `langchain_openai.ChatOpenAI`: LLM 차트 코드 생성 +- `langchain_core.messages`: SystemMessage, HumanMessage + +### 사용 방법 + +#### 1. 기본 사용법 (interface/core/result_renderer.py에서 실제 사용) + +```python +from utils.visualization.display_chart import DisplayChart +import pandas as pd + +# DisplayChart 인스턴스 생성 +display_code = DisplayChart( + question="지난달 매출 추이를 보여줘", + sql="SELECT date, revenue FROM sales WHERE ...", + df_metadata=f"Running df.dtypes gives:\n{df.dtypes}" +) + +# Plotly 코드 생성 +plotly_code = display_code.generate_plotly_code() + +# Figure 객체 생성 +fig = display_code.get_plotly_figure(plotly_code=plotly_code, df=df) + +# Streamlit에서 차트 표시 +st.plotly_chart(fig) +``` + +#### 2. 통합 흐름 (Lang2SQL 파이프라인 내) + +`interface/core/result_renderer.py`의 `display_result()` 함수에서 사용: + +1. SQL 쿼리 실행 후 pandas DataFrame 반환 +2. `DisplayChart` 초기화 (질문, SQL, 메타데이터) +3. `generate_plotly_code()`로 LLM 기반 차트 코드 생성 +4. `get_plotly_figure()`로 실행 및 Figure 객체 획득 +5. `st.plotly_chart()`로 Streamlit UI에 렌더링 + +**경로**: `interface/core/result_renderer.py` (200-211번째 줄) + +### import 관계 + +**import하는 파일**: +- `interface/core/result_renderer.py`: `from utils.visualization.display_chart import DisplayChart` + +**외부 의존성**: +- `langchain_openai.ChatOpenAI`: OpenAI LLM API 호출 +- `plotly`: 차트 렌더링 및 Figure 객체 관리 +- `pandas`: 데이터프레임 처리 +- 환경변수: `LLM_PROVIDER`, `OPEN_AI_KEY`, `OPEN_AI_LLM_MODEL` + +### 환경 변수 요약 + +- **`LLM_PROVIDER`**: LLM 공급자 지정 (현재 "openai"만 지원) +- **`OPEN_AI_KEY`**: OpenAI API 키 +- **`OPEN_AI_LLM_MODEL`**: 사용할 모델 (기본값: "gpt-4o") + +### 주요 특징 + +1. **LLM 기반 지능형 차트 생성**: 데이터 구조와 질문 내용에 맞춰 적절한 차트 유형 자동 선택 +2. **Fallback 메커니즘**: LLM 코드 생성 실패 시 데이터 타입 기반 대체 차트 제공 +3. **다크 모드 지원**: 기본적으로 plotly_dark 템플릿 적용 +4. **에러 안전성**: 코드 실행 중 예외 발생 시에도 항상 유효한 Figure 객체 반환 + +### 개선 가능 영역 + +- 다른 LLM 공급자 지원 (현재 OpenAI만 지원) +- 더 다양한 차트 유형 지원 +- 컬러 스킴 및 스타일 커스터마이징 옵션 +- 성능 최적화 (코드 생성 시간 단축) +