1- """
2- Lang2SQL CLI 프로그램입니다.
1+ """Lang2SQL CLI 프로그램입니다.
32이 프로그램은 Datahub GMS 서버 URL을 설정하고, 필요 시 Streamlit 인터페이스를 실행합니다.
43
54명령어 예시: lang2sql --datahub_server http://localhost:8080 --run-streamlit
65"""
76
8- import logging
9- import os
10- import subprocess
11-
127import click
13- import dotenv
148
9+ from cli .commands .quary import query_command
10+ from cli .commands .run_streamlit import run_streamlit_cli_command
11+ from cli .core .environment import initialize_environment
12+ from cli .core .streamlit_runner import run_streamlit_command
13+ from cli .utils .logger import configure_logging
1514from infra .monitoring .check_server import CheckServer
1615from llm_utils .tools import set_gms_server
1716from version import __version__
1817
19- logging .basicConfig (
20- level = logging .INFO ,
21- format = "%(asctime)s [%(levelname)s] %(message)s" ,
22- datefmt = "%Y-%m-%d %H:%M:%S" ,
23- )
24- logger = logging .getLogger (__name__ )
18+ logger = configure_logging ()
2519
2620
21+ # pylint: disable=redefined-outer-name,broad-exception-caught
2722@click .group ()
2823@click .version_option (version = __version__ )
2924@click .pass_context
7974 "기본값: FAISS는 './dev/table_info_db', pgvector는 환경변수 사용"
8075 ),
8176)
82- # pylint: disable=redefined-outer-name
8377def cli (
8478 ctx : click .Context ,
8579 datahub_server : str ,
@@ -90,69 +84,24 @@ def cli(
9084 vectordb_type : str = "faiss" ,
9185 vectordb_location : str = None ,
9286) -> None :
93- """
94- Datahub GMS 서버 URL을 설정하고, Streamlit 애플리케이션을 실행할 수 있는 CLI 명령 그룹입니다.
95-
96- 이 함수는 다음 역할을 수행합니다:
97- - 전달받은 'datahub_server' URL을 바탕으로 GMS 서버 연결을 설정합니다.
98- - 설정 과정 중 오류가 발생하면 오류 메시지를 출력하고 프로그램을 종료합니다.
99- - '--run-streamlit' 옵션이 활성화된 경우, 지정된 포트에서 Streamlit 웹 앱을 즉시 실행합니다.
100- - '--env-file-path' 옵션이 지정된 경우, 해당 .env 파일에서 환경 변수를 로드합니다.
101- - '--prompt-dir-path' 옵션이 지정된 경우, 해당 디렉토리에서 프롬프트 템플릿을 로드합니다.
102-
103- 매개변수:
104- ctx (click.Context): 명령어 실행 컨텍스트 객체입니다.
105- datahub_server (str): 설정할 Datahub GMS 서버의 URL입니다.
106- run_streamlit (bool): Streamlit 앱을 실행할지 여부를 나타내는 플래그입니다.
107- port (int): Streamlit 서버가 바인딩될 포트 번호입니다.
108- env_file_path (str, optional): 환경 변수를 로드할 .env 파일 경로입니다.
109- prompt_dir_path (str, optional): 프롬프트 템플릿을 로드할 디렉토리 경로입니다.
87+ """Lang2SQL CLI 엔트리포인트.
11088
111- 주의:
112- 'set_gms_server' 함수에서 ValueError가 발생할 경우, 프로그램은 비정상 종료(exit code 1)합니다.
89+ - 환경 변수 및 VectorDB 설정 초기화
90+ - GMS 서버 연결 및 헬스체크
91+ - 필요 시 Streamlit 애플리케이션 실행
11392 """
11493
115- # 환경 변수 파일 로드
116- if env_file_path :
117- try :
118- if not dotenv .load_dotenv (env_file_path , override = True ):
119- click .secho (f"환경 변수 파일 로드 실패: { env_file_path } " , fg = "yellow" )
120- else :
121- click .secho (f"환경 변수 파일 로드 성공: { env_file_path } " , fg = "green" )
122- except Exception as e :
123- click .secho (f"환경 변수 로드 중 오류 발생: { str (e )} " , fg = "red" )
124- ctx .exit (1 )
125- else :
126- dotenv .load_dotenv (override = True )
127-
128- # 프롬프트 디렉토리를 환경 변수로 설정
129- if prompt_dir_path :
130- try :
131- os .environ ["PROMPT_TEMPLATES_DIR" ] = prompt_dir_path
132- click .secho (
133- f"프롬프트 디렉토리 환경변수 설정됨: { prompt_dir_path } " , fg = "green"
134- )
135- except Exception as e :
136- click .secho (f"프롬프트 디렉토리 환경변수 설정 실패: { str (e )} " , fg = "red" )
137- ctx .exit (1 )
138-
139- # VectorDB 타입을 환경 변수로 설정
14094 try :
141- os .environ ["VECTORDB_TYPE" ] = vectordb_type
142- click .secho (f"VectorDB 타입 설정됨: { vectordb_type } " , fg = "green" )
143- except Exception as e :
144- click .secho (f"VectorDB 타입 설정 실패: { str (e )} " , fg = "red" )
95+ initialize_environment (
96+ env_file_path = env_file_path ,
97+ prompt_dir_path = prompt_dir_path ,
98+ vectordb_type = vectordb_type ,
99+ vectordb_location = vectordb_location ,
100+ )
101+ except Exception :
102+ logger .error ("Initialization failed." , exc_info = True )
145103 ctx .exit (1 )
146104
147- # VectorDB 경로를 환경 변수로 설정
148- if vectordb_location :
149- try :
150- os .environ ["VECTORDB_LOCATION" ] = vectordb_location
151- click .secho (f"VectorDB 경로 설정됨: { vectordb_location } " , fg = "green" )
152- except Exception as e :
153- click .secho (f"VectorDB 경로 설정 실패: { str (e )} " , fg = "red" )
154- ctx .exit (1 )
155-
156105 logger .info (
157106 "Initialization started: GMS server = %s, run_streamlit = %s, port = %d" ,
158107 datahub_server ,
@@ -171,181 +120,5 @@ def cli(
171120 run_streamlit_command (port )
172121
173122
174- def run_streamlit_command (port : int ) -> None :
175- """
176- 지정된 포트에서 Streamlit 애플리케이션을 실행하는 함수입니다.
177-
178- 이 함수는 subprocess를 통해 'streamlit run' 명령어를 실행하여
179- 'interface/streamlit_app.py' 파일을 웹 서버 형태로 구동합니다.
180- 사용자가 지정한 포트 번호를 Streamlit 서버의 포트로 설정합니다.
181-
182- 매개변수:
183- port (int): Streamlit 서버가 바인딩될 포트 번호입니다.
184-
185- 주의:
186- - Streamlit이 시스템에 설치되어 있어야 정상 동작합니다.
187- - subprocess 호출 실패 시 예외가 발생할 수 있습니다.
188- """
189-
190- logger .info ("Starting Streamlit application on port %d..." , port )
191-
192- try :
193- subprocess .run (
194- [
195- "streamlit" ,
196- "run" ,
197- "interface/streamlit_app.py" ,
198- "--server.address=0.0.0.0" ,
199- "--server.port" ,
200- str (port ),
201- ],
202- check = True ,
203- )
204- logger .info ("Streamlit application started successfully." )
205- except subprocess .CalledProcessError as e :
206- logger .error ("Failed to start Streamlit application: %s" , e )
207- raise
208-
209-
210- @cli .command (name = "run-streamlit" )
211- @click .option (
212- "-p" ,
213- "--port" ,
214- type = int ,
215- default = 8501 ,
216- help = (
217- "Streamlit 애플리케이션이 바인딩될 포트 번호를 지정합니다. "
218- "기본 포트는 8501이며, 필요 시 포트 충돌을 피하거나 "
219- "여러 인스턴스를 동시에 실행할 때 다른 포트 번호를 설정할 수 있습니다."
220- ),
221- )
222- def run_streamlit_cli_command (port : int ) -> None :
223- """
224- CLI 명령어를 통해 Streamlit 애플리케이션을 실행하는 함수입니다.
225-
226- 이 명령은 'interface/streamlit_app.py' 파일을 Streamlit 서버로 구동하며,
227- 사용자가 지정한 포트 번호를 바인딩하여 웹 인터페이스를 제공합니다.
228-
229- 매개변수:
230- port (int): Streamlit 서버가 사용할 포트 번호입니다. 기본값은 8501입니다.
231-
232- 주의:
233- - Streamlit이 시스템에 설치되어 있어야 정상적으로 실행됩니다.
234- - Streamlit 실행에 실패할 경우 subprocess 호출에서 예외가 발생할 수 있습니다.
235- """
236-
237- logger .info ("Executing 'run-streamlit' command on port %d..." , port )
238- run_streamlit_command (port )
239-
240-
241- @cli .command (name = "query" )
242- @click .argument ("question" , type = str )
243- @click .option (
244- "--database-env" ,
245- default = "clickhouse" ,
246- help = "사용할 데이터베이스 환경 (기본값: clickhouse)" ,
247- )
248- @click .option (
249- "--retriever-name" ,
250- default = "기본" ,
251- help = "테이블 검색기 이름 (기본값: 기본)" ,
252- )
253- @click .option (
254- "--top-n" ,
255- type = int ,
256- default = 5 ,
257- help = "검색된 상위 테이블 수 제한 (기본값: 5)" ,
258- )
259- @click .option (
260- "--device" ,
261- default = "cpu" ,
262- help = "LLM 실행에 사용할 디바이스 (기본값: cpu)" ,
263- )
264- @click .option (
265- "--use-enriched-graph" ,
266- is_flag = True ,
267- help = "확장된 그래프(프로파일 추출 + 컨텍스트 보강) 사용 여부" ,
268- )
269- @click .option (
270- "--vectordb-type" ,
271- type = click .Choice (["faiss" , "pgvector" ]),
272- default = "faiss" ,
273- help = "사용할 벡터 데이터베이스 타입 (기본값: faiss)" ,
274- )
275- @click .option (
276- "--vectordb-location" ,
277- help = (
278- "VectorDB 위치 설정\n "
279- "- FAISS: 디렉토리 경로 (예: ./my_vectordb)\n "
280- "- pgvector: 연결 문자열 (예: postgresql://user:pass@host:port/db)\n "
281- "기본값: FAISS는 './dev/table_info_db', pgvector는 환경변수 사용"
282- ),
283- )
284- def query_command (
285- question : str ,
286- database_env : str ,
287- retriever_name : str ,
288- top_n : int ,
289- device : str ,
290- use_enriched_graph : bool ,
291- vectordb_type : str = "faiss" ,
292- vectordb_location : str = None ,
293- ) -> None :
294- """
295- 자연어 질문을 SQL 쿼리로 변환하여 출력하는 명령어입니다.
296-
297- 이 명령은 사용자가 입력한 자연어 질문을 받아서 SQL 쿼리로 변환하고,
298- 생성된 SQL 쿼리만을 표준 출력으로 출력합니다.
299-
300- 매개변수:
301- question (str): SQL로 변환할 자연어 질문
302- database_env (str): 사용할 데이터베이스 환경
303- retriever_name (str): 테이블 검색기 이름
304- top_n (int): 검색된 상위 테이블 수 제한
305- device (str): LLM 실행에 사용할 디바이스
306- use_enriched_graph (bool): 확장된 그래프 사용 여부
307-
308- 예시:
309- lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리"
310- lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" --use-enriched-graph
311- lang2sql query "고객 데이터를 기반으로 유니크한 유저 수를 카운트하는 쿼리" --vectordb-type pgvector
312- """
313-
314- try :
315- from engine .query_executor import execute_query , extract_sql_from_result
316-
317- # VectorDB 타입을 환경 변수로 설정
318- os .environ ["VECTORDB_TYPE" ] = vectordb_type
319-
320- # VectorDB 위치를 환경 변수로 설정
321- if vectordb_location :
322- os .environ ["VECTORDB_LOCATION" ] = vectordb_location
323-
324- # 공용 함수를 사용하여 쿼리 실행
325- res = execute_query (
326- query = question ,
327- database_env = database_env ,
328- retriever_name = retriever_name ,
329- top_n = top_n ,
330- device = device ,
331- use_enriched_graph = use_enriched_graph ,
332- )
333-
334- # SQL 추출 및 출력
335- sql = extract_sql_from_result (res )
336- if sql :
337- print (sql )
338- else :
339- # SQL 추출 실패 시 원본 쿼리 텍스트 출력
340- generated_query = res .get ("generated_query" )
341- if generated_query :
342- query_text = (
343- generated_query .content
344- if hasattr (generated_query , "content" )
345- else str (generated_query )
346- )
347- print (query_text )
348-
349- except Exception as e :
350- logger .error ("쿼리 처리 중 오류 발생: %s" , e )
351- raise
123+ cli .add_command (run_streamlit_cli_command )
124+ cli .add_command (query_command )
0 commit comments