Skip to content

Commit 5e825ee

Browse files
committed
refactor: viz 모듈을 utils/visualization으로 이동
1 parent 472c892 commit 5e825ee

File tree

5 files changed

+84
-25
lines changed

5 files changed

+84
-25
lines changed

interface/core/result_renderer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from infra.observability.token_usage import TokenUtils
1414
from utils.databases import DatabaseFactory
1515
from utils.llm.llm_response_parser import LLMResponseParser
16-
from viz.display_chart import DisplayChart
16+
from utils.visualization.display_chart import DisplayChart
1717

1818

1919
def display_result(res: dict) -> None:

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ packages = [
7070
"interface",
7171
"engine",
7272
"infra",
73-
"viz",
7473
"prompt",
7574
"utils",
7675
]

utils/llm/README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Lang2SQL 파이프라인에서 LLM, 검색(RAG), 그래프 워크플로우, DB
55
### Depth 0: 최상위 유틸리티
66

77
- (Moved) `engine/query_executor.py`: Lang2SQL 그래프 선택/컴파일/실행 진입점.
8-
- (Moved) `viz/display_chart.py`: LLM 활용 Plotly 시각화 유틸.
8+
- (Moved) `utils/visualization/display_chart.py`: LLM 활용 Plotly 시각화 유틸.
99
- (Moved) `infra/monitoring/check_server.py`: GMS 헬스체크.
1010
- (Moved) `infra/db/connect_db.py`: ClickHouse 연결/실행.
1111
- (Moved) `infra/observability/token_usage.py`: LLM 메시지의 `usage_metadata` 합산 토큰 집계.
@@ -89,7 +89,7 @@ sql = extract_sql_from_result(res)
8989
```
9090

9191
```python
92-
from viz.display_chart import DisplayChart
92+
from utils.visualization.display_chart import DisplayChart
9393

9494
chart = DisplayChart(question="지난달 매출 추이", sql=sql, df_metadata=str(df.dtypes))
9595
code = chart.generate_plotly_code()
@@ -103,5 +103,3 @@ fig = chart.get_plotly_figure(code, df)
103103
- `display_chart.py` → OpenAI LLM(선택적)로 코드 생성 → Plotly 실행
104104
- `connect_db.py` → ClickHouse 클라이언트로 SQL 실행
105105
- `llm_response_parser.py` → 결과 파서
106-
107-

viz/display_chart.py renamed to utils/visualization/display_chart.py

Lines changed: 81 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1-
import re
2-
from langchain_openai import ChatOpenAI
3-
from langchain_core.messages import HumanMessage, SystemMessage
4-
import pandas as pd
1+
"""
2+
SQL 쿼리 결과를 Plotly로 시각화하는 모듈
3+
4+
이 모듈은 Lang2SQL 실행 결과를 다양한 형태의 차트로 시각화하는 기능을 제공합니다.
5+
LLM을 활용하여 적절한 Plotly 코드를 생성하고 실행합니다.
6+
"""
7+
58
import os
9+
import re
10+
from typing import Optional
611

12+
import pandas as pd
713
import plotly
814
import plotly.express as px
915
import plotly.graph_objects as go
16+
from langchain_core.messages import HumanMessage, SystemMessage
17+
from langchain_openai import ChatOpenAI
1018

1119

1220
class DisplayChart:
@@ -17,12 +25,29 @@ class DisplayChart:
1725
plotly코드를 출력하여 excute한 결과를 fig 객체로 반환합니다.
1826
"""
1927

20-
def __init__(self, question, sql, df_metadata):
28+
def __init__(self, question: str, sql: str, df_metadata: str):
29+
"""
30+
DisplayChart 인스턴스를 초기화합니다.
31+
32+
Args:
33+
question (str): 사용자 질문
34+
sql (str): 실행된 SQL 쿼리
35+
df_metadata (str): 데이터프레임 메타데이터
36+
"""
2137
self.question = question
2238
self.sql = sql
2339
self.df_metadata = df_metadata
2440

25-
def llm_model_for_chart(self, message_log):
41+
def llm_model_for_chart(self, message_log) -> Optional[str]:
42+
"""
43+
LLM 모델을 사용하여 차트 생성 코드를 생성합니다.
44+
45+
Args:
46+
message_log: LLM에 전달할 메시지 목록
47+
48+
Returns:
49+
Optional[str]: 생성된 차트 코드 또는 None
50+
"""
2651
provider = os.getenv("LLM_PROVIDER")
2752
if provider == "openai":
2853
llm = ChatOpenAI(
@@ -31,18 +56,29 @@ def llm_model_for_chart(self, message_log):
3156
)
3257
result = llm.invoke(message_log)
3358
return result
59+
return None
3460

3561
def _extract_python_code(self, markdown_string: str) -> str:
62+
"""
63+
마크다운 문자열에서 Python 코드 블록을 추출합니다.
64+
65+
Args:
66+
markdown_string: 마크다운 형식의 문자열
67+
68+
Returns:
69+
str: 추출된 Python 코드
70+
"""
3671
# Strip whitespace to avoid indentation errors in LLM-generated code
37-
markdown_string = markdown_string.content.split("```")[1][6:].strip()
72+
if hasattr(markdown_string, "content"):
73+
markdown_string = markdown_string.content.split("```")[1][6:].strip()
74+
else:
75+
markdown_string = str(markdown_string)
3876

3977
# Regex pattern to match Python code blocks
40-
pattern = r"```[\w\s]*python\n([\s\S]*?)```|```([\s\S]*?)```" # 여러 문자와 공백 뒤에 python이 나오고, 줄바꿈 이후의 모든 내용
78+
pattern = r"```[\w\s]*python\n([\s\S]*?)```|```([\s\S]*?)```"
4179

4280
# Find all matches in the markdown string
43-
matches = re.findall(
44-
pattern, markdown_string, re.IGNORECASE
45-
) # 대소문자 구분 안함
81+
matches = re.findall(pattern, markdown_string, re.IGNORECASE)
4682

4783
# Extract the Python code from the matches
4884
python_code = []
@@ -55,13 +91,27 @@ def _extract_python_code(self, markdown_string: str) -> str:
5591

5692
return python_code[0]
5793

58-
def _sanitize_plotly_code(self, raw_plotly_code):
94+
def _sanitize_plotly_code(self, raw_plotly_code: str) -> str:
95+
"""
96+
Plotly 코드에서 불필요한 부분을 제거합니다.
97+
98+
Args:
99+
raw_plotly_code: 원본 Plotly 코드
100+
101+
Returns:
102+
str: 정리된 Plotly 코드
103+
"""
59104
# Remove the fig.show() statement from the plotly code
60105
plotly_code = raw_plotly_code.replace("fig.show()", "")
61-
62106
return plotly_code
63107

64108
def generate_plotly_code(self) -> str:
109+
"""
110+
LLM을 사용하여 Plotly 코드를 생성합니다.
111+
112+
Returns:
113+
str: 생성된 Plotly 코드
114+
"""
65115
if self.question is not None:
66116
system_msg = f"The following is a pandas DataFrame that contains the results of the query that answers the question the user asked: '{self.question}'"
67117
else:
@@ -82,20 +132,33 @@ def generate_plotly_code(self) -> str:
82132
]
83133

84134
plotly_code = self.llm_model_for_chart(message_log)
135+
if plotly_code is None:
136+
return ""
85137

86138
return self._sanitize_plotly_code(self._extract_python_code(plotly_code))
87139

88140
def get_plotly_figure(
89141
self, plotly_code: str, df: pd.DataFrame, dark_mode: bool = True
90-
) -> plotly.graph_objs.Figure:
91-
142+
) -> Optional[plotly.graph_objs.Figure]:
143+
"""
144+
Plotly 코드를 실행하여 Figure 객체를 생성합니다.
145+
146+
Args:
147+
plotly_code: 실행할 Plotly 코드
148+
df: 데이터프레임
149+
dark_mode: 다크 모드 사용 여부
150+
151+
Returns:
152+
Optional[plotly.graph_objs.Figure]: 생성된 Figure 객체 또는 None
153+
"""
92154
ldict = {"df": df, "px": px, "go": go}
155+
fig = None
156+
93157
try:
94-
exec(plotly_code, globals(), ldict)
158+
exec(plotly_code, globals(), ldict) # noqa: S102
95159
fig = ldict.get("fig", None)
96160

97-
except Exception as e:
98-
161+
except Exception:
99162
# Inspect data types
100163
numeric_cols = df.select_dtypes(include=["number"]).columns.tolist()
101164
categorical_cols = df.select_dtypes(

viz/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)