-
Notifications
You must be signed in to change notification settings - Fork 2
[AI] SISC2-35 [FIX] AI 파트 통합 파이프라인 #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "SISC2-35-AI-\uAE40\uC601\uD5CC-AI-\uD30C\uD2B8-\uD1B5\uD569-\uD30C\uC774\uD504\uB77C\uC778"
Conversation
- finder, transform, xai 모듈을 순차 실행하는 기본 파이프라인 구조를 구현합니다. - DB 스키마 및 import 경로 등 발견된 오류를 수정합니다. - 향후 실제 모듈 테스트를 위해 임시 데이터는 주석으로 남겨둡니다.
- 기존 selenium 기반 뉴스 수집 방식은 유지합니다. - requests와 beautifulsoup를 사용하는 새로운 수집 방식(news_processing_requests.py)을 추가하여, import 구문 변경만으로 수집 방식을 선택할 수 있도록 개선합니다.
Walkthrough파이프라인이 주간 발굴, 신호 변환, XAI 리포트의 모듈식 단계로 재구성되었고, 새로운 상위 오케스트레이터 run_pipeline이 단계들을 순차 실행하도록 추가되었습니다. OHLCV 데이터 조회 SQL과 뉴스 수집/요약 모듈, 요구 패키지 목록도 변경되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Pipeline
participant Finder
participant Transform
participant OHLCV
participant XAI
participant Config
Client->>Pipeline: run_pipeline()
Pipeline->>Config: Load configs/config.json (optional)
Config-->>Pipeline: config dict or {}
rect rgb(220, 235, 255)
Note over Pipeline,Finder: Phase 1 — Weekly Finder
Pipeline->>Finder: run_weekly_finder()
Finder-->>Pipeline: List[tickers]
end
rect rgb(220, 235, 255)
Note over Pipeline,Transform: Phase 2 — Signal Transform
Pipeline->>Transform: run_signal_transform(tickers, config)
loop per ticker
Transform->>OHLCV: fetch_ohlcv(ticker)
OHLCV-->>Transform: DataFrame
end
Transform-->>Pipeline: decision_log (DataFrame)
end
rect rgb(220, 235, 255)
Note over Pipeline,XAI: Phase 3 — XAI Report
Pipeline->>XAI: run_xai_report(decision_log)
XAI-->>Pipeline: List[reports] or error entries
end
Pipeline-->>Client: reports or None
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 분 주의할 파일/영역:
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
AI/transform/modules/main.py (1)
163-170: 컬럼 소문자화 이전에 타임스탬프 컬럼 탐지 → 대소문자 혼용 입력 시 실패 위험.현재
ts_col을 찾은 뒤에 컬럼을 소문자화합니다. 입력 DF에Date등 대문자 컬럼이 오면ts_col is None로 예외가 납니다. 소문자화 → 컬럼 탐지 순서로 교체하세요.- df = raw_data.copy() - ts_col = "ts_local" if "ts_local" in df.columns else ("date" if "date" in df.columns else None) - if ts_col is None: - raise ValueError("raw_data에 'ts_local' 또는 'date' 컬럼이 필요합니다.") - df[ts_col] = pd.to_datetime(df[ts_col]) - df = df.rename(columns={c: c.lower() for c in df.columns}) + df = raw_data.copy() + # 1) 우선 컬럼명을 소문자화 + df = df.rename(columns={c: c.lower() for c in df.columns}) + # 2) 그 후 타임스탬프 컬럼 탐지 + ts_col = "ts_local" if "ts_local" in df.columns else ("date" if "date" in df.columns else None) + if ts_col is None: + raise ValueError("raw_data에 'ts_local' 또는 'date' 컬럼이 필요합니다.") + df[ts_col] = pd.to_datetime(df[ts_col])
🧹 Nitpick comments (10)
AI/libs/utils/data/fetch_ohlcv.py (2)
17-23: interval 인자/설명 불일치(더 이상 사용 안 함).SQL에서 인터벌 필터가 제거되었는데 함수 시그니처와 Docstring에는 여전히 남아 있습니다. 혼선을 줄이기 위해 Docstring에 “deprecated/미사용” 표기 또는 인자 제거를 제안합니다(제거 시 상위 호출부 영향 확인 필요).
- interval: str = "1d", + interval: str = "1d", # deprecated, unused @@ - interval (str): 데이터 간격 ('1d' 등) + interval (str): (deprecated) 현재 무시됩니다.Also applies to: 27-36
37-51: DB 커넥션 누수 방지 및 예외 안전성 향상(컨텍스트 매니저).
with문을 사용해 커넥션을 자동 종료하면 예외 시에도 안전합니다.- conn = get_db_conn(config) - - query = """ + query = """ SELECT date, open, high, low, close, volume FROM public.price_data WHERE ticker = %s AND date BETWEEN %s AND %s ORDER BY date; """ - # 파라미터 바인딩 (%s) 사용 → SQL injection 방지 - df = pd.read_sql(query, conn, params=(ticker, start, end)) - - conn.close() - return df + # 파라미터 바인딩 (%s) 사용 → SQL injection 방지 + with get_db_conn(config) as conn: + df = pd.read_sql(query, conn, params=(ticker, start, end)) + return dfAI/libs/core/pipeline.py (3)
9-11: sys.path 주입 중복 방지.동일 경로가 여러 번 추가되지 않도록 가드하세요.
-project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -sys.path.append(project_root) +project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +if project_root not in sys.path: + sys.path.append(project_root)
24-28: 불필요한 f-string 제거(F541).플레이스홀더 없는 f-string은 일반 문자열로 변경하세요. Ruff F541.
- print("--- [PIPELINE-STEP 1] Finder 모듈 실행 시작 ---") + print("--- [PIPELINE-STEP 1] Finder 모듈 실행 시작 ---") @@ - print(f"--- [PIPELINE-STEP 1] Finder 모듈 실행 완료 ---") + print("--- [PIPELINE-STEP 1] Finder 모듈 실행 완료 ---")
86-114: XAI 단계: f-string(F541) 및 광범위 예외(BLE001).
- 플레이스홀더 없는 f-string을 일반 문자열로 교체하세요. Ruff F541.
- 광범위
except Exception은 가능한 한 구체화가 바람직합니다. 당장 축소가 어렵다면 TODO로 명시해 추후run_xai가 던질 수 있는 예외군으로 좁히는 것을 권장합니다.- print("--- [PIPELINE-STEP 3] XAI 리포트 생성 시작 ---") + print("--- [PIPELINE-STEP 3] XAI 리포트 생성 시작 ---") @@ - print(f"--- [PIPELINE-STEP 3] XAI 리포트 생성 완료 ---") + print("--- [PIPELINE-STEP 3] XAI 리포트 생성 완료 ---")추가로,
except Exception as e:구문 위에 다음과 같은 주석을 남겨 향후 축소 계획을 표시하는 것을 권장합니다.# TODO: run_xai에서 발생 가능한 예외군으로 예외 범위 축소(ValueError, TimeoutError 등)AI/libs/utils/news_processing_requests.py (4)
63-67: wdate 선택자 None 가드 추가.요약 영역에
span.wdate가 없는 경우AttributeError가 발생할 수 있습니다. 안전 가드를 추가하세요.- if i < len(summaries): - time_list.append(summaries[i].find('span', class_='wdate').text.strip()) + if i < len(summaries): + w = summaries[i].find('span', class_='wdate') + time_list.append(w.text.strip() if w else '') else: time_list.append('')
154-155: 불리언 비교 스타일(E712).
== False대신notnull()/isnull()을 사용하세요. 현재 표현식은 가독성과 정확성이 떨어집니다.- valid_df = href_df[href_df['content'].isnull()==False].reset_index(drop=True) + valid_df = href_df[href_df['content'].notnull()].reset_index(drop=True)
17-29: 타입 힌트/사용 불일치: target_date는 문자열(YYYYMMDD)로 사용됩니다.함수는
datetime을 받도록 선언했지만 실제로는 문자열을 전달/사용합니다. 타입 일치로 혼란을 줄이세요.-def _news_href_crawl(target_date: datetime) -> pd.DataFrame: +def _news_href_crawl(target_date: str) -> pd.DataFrame: @@ - "date": target_date + "date": target_date
143-161: 타입 힌트/사용 불일치:_collect_and_summarize_news의 target_date.여기도 동일하게 문자열을 사용합니다. 시그니처/Docstring을 정합화하세요.
-def _collect_and_summarize_news(target_date: datetime, llm_client) -> pd.DataFrame: +def _collect_and_summarize_news(target_date: str, llm_client) -> pd.DataFrame: @@ - 지정된 날짜의 해외증시 뉴스를 수집하고 LLM으로 요약하는 함수 + 지정된 날짜(YYYYMMDD)의 해외증시 뉴스를 수집하고 LLM으로 요약하는 함수AI/transform/modules/main.py (1)
145-154: 미사용 매개변수pred_h,interval정리 권장 확인됨.코드 검증 결과, 두 매개변수 모두 함수 내에서 실제로 사용되지 않습니다:
pred_h: 호출부(AI/libs/core/pipeline.py:54)에서pred_h=1로 전달되지만, 함수 본체에서 참조 없음interval: 기본값"1d"로 정의되어 있으나 함수 로직 어디서도 사용되지 않음즉시 제거하거나, 향후 사용을 대비한 의도 표시로
_ = (pred_h, interval)추가를 권장합니다.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
AI/libs/core/pipeline.py(1 hunks)AI/libs/utils/data/fetch_ohlcv.py(1 hunks)AI/libs/utils/news_processing_requests.py(1 hunks)AI/requirements.txt(1 hunks)AI/transform/modules/main.py(1 hunks)AI/xai/requirements.txt(0 hunks)
💤 Files with no reviewable changes (1)
- AI/xai/requirements.txt
🧰 Additional context used
🧬 Code graph analysis (1)
AI/libs/core/pipeline.py (4)
AI/finder/main.py (1)
run_finder(14-44)AI/transform/modules/main.py (1)
run_transform(145-272)AI/libs/utils/data/fetch_ohlcv.py (1)
fetch_ohlcv(17-51)AI/xai/run_xai.py (1)
run_xai(29-33)
🪛 Ruff (0.14.1)
AI/libs/utils/news_processing_requests.py
37-37: Probable use of requests call without timeout
(S113)
79-79: Probable use of requests call without timeout
(S113)
154-154: Avoid equality comparisons to False; use not href_df['content'].isnull(): for false checks
Replace with not href_df['content'].isnull()
(E712)
183-183: Do not catch blind exception: Exception
(BLE001)
211-211: Do not catch blind exception: Exception
(BLE001)
AI/libs/core/pipeline.py
27-27: f-string without any placeholders
Remove extraneous f prefix
(F541)
79-79: f-string without any placeholders
Remove extraneous f prefix
(F541)
89-89: Avoid specifying long messages outside the exception class
(TRY003)
109-109: Do not catch blind exception: Exception
(BLE001)
113-113: f-string without any placeholders
Remove extraneous f prefix
(F541)
| def run_signal_transform(tickers: List[str], config: Dict) -> pd.DataFrame: | ||
| """ | ||
| 종목 리스트를 받아 Transform 모듈을 실행하고, 신호(결정 로그)를 반환합니다. | ||
| """ | ||
| print("--- [PIPELINE-STEP 2] Transform 모듈 실행 시작 ---") | ||
|
|
||
| # --- 실제 Transform 모듈 호출 --- | ||
| end_date = datetime.now() | ||
| start_date = end_date - timedelta(days=600) | ||
| all_ohlcv_df = [] | ||
| for ticker in tickers: | ||
| ohlcv_df = fetch_ohlcv( | ||
| ticker=ticker, | ||
| start=start_date.strftime('%Y-%m-%d'), | ||
| end=end_date.strftime('%Y-%m-%d'), | ||
| config=config | ||
| ) | ||
| ohlcv_df['ticker'] = ticker | ||
| all_ohlcv_df.append(ohlcv_df) | ||
| if not all_ohlcv_df: | ||
| print("OHLCV 데이터를 가져오지 못했습니다.") | ||
| return pd.DataFrame() | ||
| raw_data = pd.concat(all_ohlcv_df, ignore_index=True) | ||
| finder_df = pd.DataFrame(tickers, columns=['ticker']) | ||
| transform_result = run_transform( | ||
| finder_df=finder_df, | ||
| seq_len=60, | ||
| pred_h=1, | ||
| raw_data=raw_data, | ||
| config=config | ||
| ) | ||
| logs_df: pd.DataFrame = tr["logs"] # (종목,날짜,매매여부,가격,비중,피쳐...,확률...) | ||
|
|
||
| # Transform 로그 저장 (Parquet) | ||
| out_dir = os.path.join(config["storage"]["out_dir"], "transform") | ||
| os.makedirs(out_dir, exist_ok=True) | ||
| log_path = os.path.join(out_dir, f"logs_{run_date}.parquet") | ||
| logs_df.to_parquet(log_path, index=False) | ||
|
|
||
| # XAI 리포트 생성 + 저장 (JSON per ticker) | ||
| xai_out_dir = os.path.join(config["storage"]["out_dir"], "xai", run_date) | ||
| os.makedirs(xai_out_dir, exist_ok=True) | ||
|
|
||
| xai_reports = run_xai(logs_df) | ||
| for ticker, report in xai_reports.items(): | ||
| with open(os.path.join(xai_out_dir, f"{ticker}.json"), "w", encoding="utf-8") as f: | ||
| json.dump(report, f, ensure_ascii=False, indent=2) | ||
|
|
||
| _log(f"[DAILY] Transform 로그 + XAI 저장 완료 ({run_date})") | ||
|
|
||
| # ============================================== | ||
| # 메인 파이프라인 | ||
| # ============================================== | ||
| def run_pipeline(config: dict) -> bool: | ||
| run_date = dt.datetime.now(dt.timezone(dt.timedelta(hours=9))).strftime("%Y-%m-%d") | ||
|
|
||
| logs_df = transform_result.get("logs", pd.DataFrame()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DB 설정 누락 시 즉시 크래시(핵심 경로 가드 필요).
config=None인 상태에서 fetch_ohlcv 호출 시 TypeError: 'NoneType' is not subscriptable로 파이프라인이 중단됩니다. 설정 부재 시 조기 반환하도록 가드하세요. 이는 데모/테스트 실행 안정성에 중요합니다.
-def run_signal_transform(tickers: List[str], config: Dict) -> pd.DataFrame:
+def run_signal_transform(tickers: List[str], config: Dict | None) -> pd.DataFrame:
@@
- print("--- [PIPELINE-STEP 2] Transform 모듈 실행 시작 ---")
+ print("--- [PIPELINE-STEP 2] Transform 모듈 실행 시작 ---")
+ if not config or "db" not in config:
+ print("[WARN] DB 설정이 없어 Transform 단계를 건너뜁니다.")
+ return pd.DataFrame()
@@
- for ticker in tickers:
- ohlcv_df = fetch_ohlcv(
- ticker=ticker,
- start=start_date.strftime('%Y-%m-%d'),
- end=end_date.strftime('%Y-%m-%d'),
- config=config
- )
- ohlcv_df['ticker'] = ticker
- all_ohlcv_df.append(ohlcv_df)
+ for ticker in tickers:
+ try:
+ ohlcv_df = fetch_ohlcv(
+ ticker=ticker,
+ start=start_date.strftime('%Y-%m-%d'),
+ end=end_date.strftime('%Y-%m-%d'),
+ config=config,
+ )
+ if ohlcv_df.empty:
+ continue
+ ohlcv_df['ticker'] = ticker
+ all_ohlcv_df.append(ohlcv_df)
+ except Exception as e:
+ print(f"[WARN] {ticker} OHLCV 조회 실패: {e}")
+ continue📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def run_signal_transform(tickers: List[str], config: Dict) -> pd.DataFrame: | |
| """ | |
| 종목 리스트를 받아 Transform 모듈을 실행하고, 신호(결정 로그)를 반환합니다. | |
| """ | |
| print("--- [PIPELINE-STEP 2] Transform 모듈 실행 시작 ---") | |
| # --- 실제 Transform 모듈 호출 --- | |
| end_date = datetime.now() | |
| start_date = end_date - timedelta(days=600) | |
| all_ohlcv_df = [] | |
| for ticker in tickers: | |
| ohlcv_df = fetch_ohlcv( | |
| ticker=ticker, | |
| start=start_date.strftime('%Y-%m-%d'), | |
| end=end_date.strftime('%Y-%m-%d'), | |
| config=config | |
| ) | |
| ohlcv_df['ticker'] = ticker | |
| all_ohlcv_df.append(ohlcv_df) | |
| if not all_ohlcv_df: | |
| print("OHLCV 데이터를 가져오지 못했습니다.") | |
| return pd.DataFrame() | |
| raw_data = pd.concat(all_ohlcv_df, ignore_index=True) | |
| finder_df = pd.DataFrame(tickers, columns=['ticker']) | |
| transform_result = run_transform( | |
| finder_df=finder_df, | |
| seq_len=60, | |
| pred_h=1, | |
| raw_data=raw_data, | |
| config=config | |
| ) | |
| logs_df: pd.DataFrame = tr["logs"] # (종목,날짜,매매여부,가격,비중,피쳐...,확률...) | |
| # Transform 로그 저장 (Parquet) | |
| out_dir = os.path.join(config["storage"]["out_dir"], "transform") | |
| os.makedirs(out_dir, exist_ok=True) | |
| log_path = os.path.join(out_dir, f"logs_{run_date}.parquet") | |
| logs_df.to_parquet(log_path, index=False) | |
| # XAI 리포트 생성 + 저장 (JSON per ticker) | |
| xai_out_dir = os.path.join(config["storage"]["out_dir"], "xai", run_date) | |
| os.makedirs(xai_out_dir, exist_ok=True) | |
| xai_reports = run_xai(logs_df) | |
| for ticker, report in xai_reports.items(): | |
| with open(os.path.join(xai_out_dir, f"{ticker}.json"), "w", encoding="utf-8") as f: | |
| json.dump(report, f, ensure_ascii=False, indent=2) | |
| _log(f"[DAILY] Transform 로그 + XAI 저장 완료 ({run_date})") | |
| # ============================================== | |
| # 메인 파이프라인 | |
| # ============================================== | |
| def run_pipeline(config: dict) -> bool: | |
| run_date = dt.datetime.now(dt.timezone(dt.timedelta(hours=9))).strftime("%Y-%m-%d") | |
| logs_df = transform_result.get("logs", pd.DataFrame()) | |
| def run_signal_transform(tickers: List[str], config: Dict | None) -> pd.DataFrame: | |
| """ | |
| 종목 리스트를 받아 Transform 모듈을 실행하고, 신호(결정 로그)를 반환합니다. | |
| """ | |
| print("--- [PIPELINE-STEP 2] Transform 모듈 실행 시작 ---") | |
| if not config or "db" not in config: | |
| print("[WARN] DB 설정이 없어 Transform 단계를 건너뜁니다.") | |
| return pd.DataFrame() | |
| # --- 실제 Transform 모듈 호출 --- | |
| end_date = datetime.now() | |
| start_date = end_date - timedelta(days=600) | |
| all_ohlcv_df = [] | |
| for ticker in tickers: | |
| try: | |
| ohlcv_df = fetch_ohlcv( | |
| ticker=ticker, | |
| start=start_date.strftime('%Y-%m-%d'), | |
| end=end_date.strftime('%Y-%m-%d'), | |
| config=config, | |
| ) | |
| if ohlcv_df.empty: | |
| continue | |
| ohlcv_df['ticker'] = ticker | |
| all_ohlcv_df.append(ohlcv_df) | |
| except Exception as e: | |
| print(f"[WARN] {ticker} OHLCV 조회 실패: {e}") | |
| continue | |
| if not all_ohlcv_df: | |
| print("OHLCV 데이터를 가져오지 못했습니다.") | |
| return pd.DataFrame() | |
| raw_data = pd.concat(all_ohlcv_df, ignore_index=True) | |
| finder_df = pd.DataFrame(tickers, columns=['ticker']) | |
| transform_result = run_transform( | |
| finder_df=finder_df, | |
| seq_len=60, | |
| pred_h=1, | |
| raw_data=raw_data, | |
| config=config | |
| ) | |
| logs_df = transform_result.get("logs", pd.DataFrame()) |
🤖 Prompt for AI Agents
In AI/libs/core/pipeline.py around lines 30 to 61, the function
run_signal_transform assumes config is present and passes it to fetch_ohlcv,
causing a TypeError when config is None; add an early guard at the top of the
function that checks for a missing or invalid config (e.g., if config is None or
required keys like DB/settings are absent), log/print a clear message about the
missing configuration, and immediately return an empty pd.DataFrame to avoid
calling fetch_ohlcv with None; this prevents crashes for demo/test runs and
ensures the pipeline fails gracefully.
| response = requests.get(base_url, params=params, headers={'User-Agent': 'Mozilla/5.0'}) | ||
| response.raise_for_status() | ||
| soup = BeautifulSoup(response.content, 'html.parser') | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네트워크 호출 타임아웃 누락(S113).
외부 호출에 타임아웃이 없어 무기한 블로킹 위험이 있습니다. 합리적인 타임아웃을 지정하세요.
- response = requests.get(base_url, params=params, headers={'User-Agent': 'Mozilla/5.0'})
+ response = requests.get(
+ base_url,
+ params=params,
+ headers={'User-Agent': 'Mozilla/5.0'},
+ timeout=10,
+ )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| response = requests.get(base_url, params=params, headers={'User-Agent': 'Mozilla/5.0'}) | |
| response.raise_for_status() | |
| soup = BeautifulSoup(response.content, 'html.parser') | |
| response = requests.get( | |
| base_url, | |
| params=params, | |
| headers={'User-Agent': 'Mozilla/5.0'}, | |
| timeout=10, | |
| ) | |
| response.raise_for_status() | |
| soup = BeautifulSoup(response.content, 'html.parser') |
🧰 Tools
🪛 Ruff (0.14.1)
37-37: Probable use of requests call without timeout
(S113)
🤖 Prompt for AI Agents
In AI/libs/utils/news_processing_requests.py around lines 37-40, the
requests.get call lacks a timeout which can block indefinitely; add a reasonable
timeout to the call (for example timeout=10 or a connect/read tuple like
timeout=(5,10)) and update the call to requests.get(base_url, params=params,
headers=..., timeout=...) ; also wrap the network call in a try/except to catch
requests.Timeout and requests.RequestException and handle/log or re-raise
appropriately so callers won't hang indefinitely.
| response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}) | ||
| response.raise_for_status() | ||
| soup = BeautifulSoup(response.content, 'html.parser') | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네트워크 호출 타임아웃 누락(S113).
본문 수집 요청에도 동일하게 타임아웃을 지정하세요.
- response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
+ response = requests.get(
+ url,
+ headers={'User-Agent': 'Mozilla/5.0'},
+ timeout=10,
+ )📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'}) | |
| response.raise_for_status() | |
| soup = BeautifulSoup(response.content, 'html.parser') | |
| response = requests.get( | |
| url, | |
| headers={'User-Agent': 'Mozilla/5.0'}, | |
| timeout=10, | |
| ) | |
| response.raise_for_status() | |
| soup = BeautifulSoup(response.content, 'html.parser') |
🧰 Tools
🪛 Ruff (0.14.1)
79-79: Probable use of requests call without timeout
(S113)
🤖 Prompt for AI Agents
In AI/libs/utils/news_processing_requests.py around lines 79 to 82, the
requests.get call lacks a timeout which can hang the process; update the call to
include a timeout parameter (e.g., timeout=10 or use a configured TIMEOUT
constant) so requests.get(url, headers=..., timeout=TIMEOUT). Ensure the chosen
timeout value is reasonable for your environment and keep
response.raise_for_status() and parsing logic unchanged.
| pandas | ||
| psycopg2-binary | ||
| langchain-community | ||
| tqdm | ||
| selenium | ||
| webdriver-manager | ||
| numpy | ||
| scikit-learn | ||
| tensorflow | ||
| yfinance | ||
| groq |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
뉴스 수집 모듈 필수 의존성 누락(런타임 실패 가능).
AI/libs/utils/news_processing_requests.py에서 requests, bs4(beautifulsoup4)를 사용하지만 본 파일에 미기재입니다. 현재 상태로는 파이프라인 1단계(Finder) 실행 시 ImportError/ModuleNotFoundError가 납니다. 최소한 아래 패키지를 추가하세요. 또한 버전 고정은 추후 constraints.txt로 관리 권장.
pandas
psycopg2-binary
langchain-community
tqdm
selenium
webdriver-manager
numpy
scikit-learn
tensorflow
yfinance
groq
+requests
+beautifulsoup4
+# HTML parser 가속/안정성 개선용 (선택)
+lxml다음 스크립트로 의존성-사용처 미스매치 여부를 점검해 주세요.
🏁 Script executed:
#!/bin/bash
echo "[imports needing deps]"
rg -nP --type=python -C1 '(^\s*import requests\b)|(^\s*from\s+bs4\s+import\s+BeautifulSoup\b)' AI | sed 's/^/ /'
echo
echo "[requirements]"
nl -ba AI/requirements.txt
echo
echo "[check presence]"
grep -Eq '^\s*requests(\b|[=<>~])' AI/requirements.txt || echo "MISSING: requests"
grep -Eq '^\s*beautifulsoup4(\b|[=<>~])' AI/requirements.txt || echo "MISSING: beautifulsoup4"Length of output: 170
🏁 Script executed:
#!/bin/bash
# Find the file and check its imports
echo "=== Checking for news_processing_requests.py ==="
find . -name "news_processing_requests.py" -type f 2>/dev/null | head -5
echo
echo "=== Content of AI/libs/utils/news_processing_requests.py ==="
if [ -f "AI/libs/utils/news_processing_requests.py" ]; then
head -50 AI/libs/utils/news_processing_requests.py
else
echo "File not found"
fi
echo
echo "=== Current AI/requirements.txt ==="
cat AI/requirements.txt
echo
echo "=== Verification: Search for requests/bs4 imports ==="
grep -n "import requests\|from bs4" AI/libs/utils/news_processing_requests.py 2>/dev/null || echo "No matches found"Length of output: 334
---
🏁 Script executed:
```shell
#!/bin/bash
# Use corrected paths based on find output
echo "=== Content of news_processing_requests.py ==="
cat ./git/AI/libs/utils/news_processing_requests.py
echo
echo "=== Current AI/requirements.txt ==="
cat ./git/AI/requirements.txt
echo
echo "=== Search for requests/bs4 imports ==="
grep -n "import requests\|from bs4" ./git/AI/libs/utils/news_processing_requests.py
Length of output: 343
뉴스 수집 모듈 필수 의존성 누락 - 즉시 추가 필요.
AI/requirements.txt에서 requests와 beautifulsoup4가 누락되어 있습니다. 런타임에 ImportError/ModuleNotFoundError가 발생합니다. 다음 패키지를 추가하세요.
pandas
psycopg2-binary
langchain-community
tqdm
selenium
webdriver-manager
numpy
scikit-learn
tensorflow
yfinance
groq
+requests
+beautifulsoup4
+lxmlrequests: HTTP 요청 라이브러리beautifulsoup4: HTML 파싱 라이브러리 (bs4 모듈 제공)lxml: 선택사항, HTML 파서 성능 개선용
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| pandas | |
| psycopg2-binary | |
| langchain-community | |
| tqdm | |
| selenium | |
| webdriver-manager | |
| numpy | |
| scikit-learn | |
| tensorflow | |
| yfinance | |
| groq | |
| pandas | |
| psycopg2-binary | |
| langchain-community | |
| tqdm | |
| selenium | |
| webdriver-manager | |
| numpy | |
| scikit-learn | |
| tensorflow | |
| yfinance | |
| groq | |
| requests | |
| beautifulsoup4 | |
| lxml |
🤖 Prompt for AI Agents
In AI/requirements.txt lines 1-11, the news-collection module is missing
HTTP/HTML parsing deps; add requests and beautifulsoup4 to the requirements (and
optionally lxml for improved parsing) so imports don't raise
ImportError/ModuleNotFoundError at runtime; append these packages to the file
(or insert in alphabetical order) and run your dependency installation/test to
confirm the news scraper imports successfully.
requests beautifulsoup4 누락 되어 있어서 수정
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
AI/requirements.txt (2)
1-13: 버전 고정 없음 — 재현성 및 안정성 저하 가능.모든 의존성이 버전 지정자 없이 나열되어 있어, 패키지 설치 시점에 따라 다른 버전이 설치될 수 있습니다. 특히 주요 버전 업그레이드 시 예기치 않은 동작 변경이나 호환성 문제가 발생할 수 있습니다.
추천: 각 패키지에 정확한 버전을 고정하거나, 향후
constraints.txt를 도입하여 명시적으로 관리하세요.-pandas -psycopg2-binary -langchain-community +pandas==2.1.4 +psycopg2-binary==2.9.9 +langchain-community==0.2.5 tqdm selenium webdriver-manager numpy scikit-learn tensorflow yfinance groq requests beautifulsoup4
12-13: 선택사항: HTML 파싱 성능 개선용lxml추가 검토.이전 리뷰에서 제안한
lxml은 BeautifulSoup의 HTML 파서로 사용되어 파싱 속도 및 안정성을 향상시킵니다. 뉴스 크롤링 성능이 중요하다면 추가를 고려하세요.requests beautifulsoup4 +lxml
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
AI/requirements.txt(1 hunks)
🔇 Additional comments (1)
AI/requirements.txt (1)
12-13: ✅ 이전 리뷰의 필수 의존성 누락 문제 해결됨.이전 리뷰에서 지적된
requests와beautifulsoup4가 이제 추가되었습니다. 뉴스 수집 모듈의 런타임 ImportError 문제가 해결되었습니다.
|
고생했습니당 |
AI 모듈의 finder, transform, xai를 연결하는 통합 파이프라인을 구축하고 뉴스 수집 방식을 개선함.
테스트 방법
1 python libs/core/pipeline.py
향후 작업
Summary by CodeRabbit
새로운 기능
리팩토링
버그 수정
Chores