-
Notifications
You must be signed in to change notification settings - Fork 2
[AI] SISC2-37 [FEAT] transform 학습 파일 저장기능 구현 #71
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-37-AI-\uC11D\uC7AC\uBE48-trasform-\uD559\uC2B5-\uD30C\uC77C-\uC800\uC7A5\uAE30\uB2A5-\uAD6C\uD604"
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| { | ||
| { | ||
| "db": { | ||
| "host": "ep-misty-lab-adgec0kl-pooler.c-2.us-east-1.aws.neon.tech", | ||
| "user": "neondb_owner", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,47 +1,75 @@ | ||
| # finder/run_finder.py | ||
| import csv | ||
| import sys | ||
| import os | ||
|
|
||
| from libs.utils import news_processing | ||
| from finder import ticker_selector | ||
| import time | ||
| import requests | ||
| import pandas as pd | ||
| from langchain_community.llms import Ollama | ||
|
|
||
|
|
||
| # ---- 경로 세팅 ---- | ||
| project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
| sys.path.append(project_root) | ||
|
|
||
| from libs.utils import news_processing | ||
| from finder import ticker_selector | ||
| from libs.llm_clients.ollama_client import get_ollama_client # ← 분리된 유틸 임포트 | ||
|
|
||
| def run_finder(): | ||
| ''' | ||
| """ | ||
| 전체 프로세스를 조율하여 최종 Top 3 투자 종목 반환 | ||
| ''' | ||
| """ | ||
| # --- 1단계: 의존성 객체 및 데이터 준비 --- | ||
| llm = Ollama(model="llama3.2") | ||
|
|
||
| try: | ||
| stability_df = pd.read_csv('data/stability_score_2025.csv') | ||
| llm = get_ollama_client() # ✅ 헬스체크 및 모델 확인 포함 | ||
| except Exception as e: | ||
| print(str(e)) | ||
| return [] | ||
|
|
||
| csv_path = os.path.join(project_root, "data", "stability_score_2025.csv") | ||
|
Comment on lines
+26
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 임시 하드코딩으로 Finder 단계가 무력화됩니다
- #top_tickers = run_finder()
- top_tickers = ['AAPL', 'MSFT', 'GOOGL'] # 임시 데이터
+ top_tickers = run_finder()
+ if not top_tickers:
+ print("Finder에서 종목을 찾지 못했습니다.")
+ return []
🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다음 패치때 변경 예정 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @twq110, 알겠습니다! 다음 패치에서 수정하시는 것으로 확인했습니다. 필요하시면 추적을 위한 이슈를 생성해드릴 수 있습니다. 이슈를 생성하시겠습니까? |
||
|
|
||
| try: | ||
| stability_df = pd.read_csv(csv_path) | ||
| except FileNotFoundError: | ||
| print("오류: 'data/stability_score_2025.csv' 파일을 찾을 수 없습니다.") | ||
| print(f"오류: {csv_path} 파일을 찾을 수 없습니다.") | ||
| return [] | ||
|
|
||
| # --- 2단계: 주간 뉴스 데이터 수집 및 요약 --- | ||
| weekly_news_df = news_processing.get_weekly_news_summary(days=5, llm_client=llm) | ||
| try: | ||
| weekly_news_df = news_processing.get_weekly_news_summary(days=5, llm_client=llm) | ||
| except requests.exceptions.ConnectionError as e: | ||
| print(f"[LLM 연결 오류] 뉴스 요약 단계에서 LLM 서버 연결 실패: {e}") | ||
| return [] | ||
| except requests.exceptions.Timeout as e: | ||
| print(f"[LLM 타임아웃] 뉴스 요약 단계에서 응답 지연: {e}") | ||
| return [] | ||
| except Exception as e: | ||
| print(f"[예기치 못한 오류] 뉴스 요약 단계: {e}") | ||
| return [] | ||
|
|
||
| if weekly_news_df.empty: | ||
| if weekly_news_df is None or getattr(weekly_news_df, "empty", False): | ||
| print("분석할 뉴스 데이터가 없어 프로세스를 종료합니다.") | ||
| return [] | ||
|
|
||
| # --- 3단계: 뉴스 데이터와 재무 데이터를 기반으로 Top 3 종목 선정 --- | ||
| top_3_tickers = ticker_selector.select_top_stocks( | ||
| news_summary_df=weekly_news_df, | ||
| stability_df=stability_df, | ||
| llm_client=llm | ||
| ) | ||
| try: | ||
| top_3_tickers = ticker_selector.select_top_stocks( | ||
| news_summary_df=weekly_news_df, | ||
| stability_df=stability_df, | ||
| llm_client=llm | ||
| ) | ||
| except requests.exceptions.ConnectionError as e: | ||
| print(f"[LLM 연결 오류] 종목 선정 단계에서 LLM 서버 연결 실패: {e}") | ||
| return [] | ||
| except requests.exceptions.Timeout as e: | ||
| print(f"[LLM 타임아웃] 종목 선정 단계에서 응답 지연: {e}") | ||
| return [] | ||
| except Exception as e: | ||
| print(f"[예기치 못한 오류] 종목 선정 단계: {e}") | ||
| return [] | ||
|
|
||
| print("\n🎉 [Finder 모듈 최종 결과] 투자 추천 Top 3 종목 🎉") | ||
| print(top_3_tickers) | ||
|
|
||
| return top_3_tickers | ||
|
|
||
| if __name__ == '__main__': | ||
| run_finder() | ||
| run_finder() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| #AI/libs/llm_clients/ollama_client.py | ||
| from libs.llm_clients.ollama_client import get_ollama_client | ||
| __all__ = ["get_ollama_client"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # libs/llm_clients/ollama_client.py | ||
| import os | ||
| import requests | ||
| from typing import Optional | ||
| from langchain_community.llms import Ollama | ||
|
|
||
| # ---- 기본 설정 (환경변수로 오버라이드 가능) ---- | ||
| OLLAMA_BASE_URL = os.environ.get("OLLAMA_BASE_URL", "http://127.0.0.1:11434") | ||
| OLLAMA_MODEL = os.environ.get("OLLAMA_MODEL", "llama3.2") | ||
|
|
||
| def _ollama_alive(base_url: str, timeout: float = 3.0) -> bool: | ||
| """ | ||
| Ollama 서버 헬스체크: /api/tags 로 간단 확인 | ||
| """ | ||
| try: | ||
| r = requests.get(f"{base_url}/api/tags", timeout=timeout) | ||
| return r.ok | ||
| except requests.exceptions.RequestException: | ||
| return False | ||
|
|
||
| def _model_available(base_url: str, model: str) -> bool: | ||
| """ | ||
| 지정 모델이 로컬 Ollama에 존재하는지 확인 | ||
| """ | ||
| try: | ||
| r = requests.get(f"{base_url}/api/tags", timeout=5) | ||
| r.raise_for_status() | ||
| tags = r.json().get("models", []) | ||
| names = {m.get("name") for m in tags if isinstance(m, dict)} | ||
| # ollama는 "llama3.2" 또는 "llama3.2:latest" 식으로 존재 가능 | ||
| return model in names or f"{model}:latest" in names | ||
| except Exception: | ||
| return False | ||
|
|
||
| def get_ollama_client( | ||
| model: Optional[str] = None, | ||
| base_url: Optional[str] = None, | ||
| # langchain 0.2+에서 request_timeout 인자를 직접 받지 않는 경우가 있어 주석 처리 | ||
| # request_timeout: float = 60.0, | ||
| ) -> Ollama: | ||
| """ | ||
| Ollama LangChain LLM 클라이언트 생성 | ||
| - 서버와 모델 존재 여부를 사전 점검 | ||
| """ | ||
| model = model or OLLAMA_MODEL | ||
| base_url = base_url or OLLAMA_BASE_URL | ||
|
|
||
| if not _ollama_alive(base_url): | ||
| raise RuntimeError( | ||
| f"[연결 실패] Ollama 서버에 접속할 수 없습니다. llama3.2 설치 여부 확인해주세요.\n" | ||
| f"- base_url: {base_url}\n" | ||
| f"- 조치: (1) 'ollama serve' 실행 여부 확인 (2) 방화벽/프록시 (NO_PROXY=localhost,127.0.0.1) (3) 11434 포트 개방\n" | ||
| f"- 테스트: curl {base_url}/api/tags" | ||
| ) | ||
|
|
||
| if not _model_available(base_url, model): | ||
| raise RuntimeError( | ||
| f"[모델 없음] '{model}' 모델이 Ollama에 없습니다.\n" | ||
| f"- 조치: ollama pull {model}\n" | ||
| f"- 보유 모델 확인: curl {base_url}/api/tags" | ||
| ) | ||
|
|
||
| return Ollama( | ||
| model=model, | ||
| base_url=base_url, | ||
| # 필요 시 model_kwargs로 세부 파라미터 전달 가능 | ||
| # model_kwargs={"num_ctx": 4096}, | ||
| ) |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,8 @@ | ||||||
| # AI/libs/utils/__init__.py | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BOM 문자를 제거하세요. 파일 첫 줄에 BOM 문자( 다음과 같이 수정하세요: -# AI/libs/utils/__init__.py
+# AI/libs/utils/__init__.py📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| from .fetch_ohlcv import fetch_ohlcv | ||||||
| from .get_db_conn import get_db_conn | ||||||
|
|
||||||
| __all__ = [ | ||||||
| "fetch_ohlcv", | ||||||
| "get_db_conn", | ||||||
| ] | ||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,4 +1,4 @@ | ||||||
| pandas | ||||||
| pandas | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. BOM(Byte Order Mark) 문자를 제거하세요. 파일 첫 줄에 BOM 문자( 다음과 같이 수정하세요: -pandas
+pandas📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| psycopg2-binary | ||||||
| langchain-community | ||||||
| tqdm | ||||||
|
|
@@ -11,3 +11,4 @@ yfinance | |||||
| groq | ||||||
| requests | ||||||
| beautifulsoup4 | ||||||
| pathlib | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 불필요한 의존성을 제거하세요.
다음 줄을 삭제하세요: -pathlib📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # quick_db_check.py | ||
| import os | ||
| import sys | ||
| import json | ||
| from typing import Dict, Union | ||
|
|
||
| import psycopg2 | ||
|
|
||
|
|
||
| # --- 프로젝트 루트 경로 설정 --------------------------------------------------- | ||
| project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | ||
| sys.path.append(project_root) | ||
|
|
||
| # --- 설정 파일 로드 ------------------------------------------------------------ | ||
| cfg_path = os.path.join(project_root, "configs", "config.json") | ||
|
|
||
| config: Dict = {} | ||
| if os.path.isfile(cfg_path): | ||
| with open(cfg_path, "r", encoding="utf-8") as f: | ||
| config = json.load(f) | ||
| print("[INFO] configs/config.json 로드 완료") | ||
| else: | ||
| print(f"[WARN] 설정 파일이 없습니다: {cfg_path}") | ||
|
|
||
| db_cfg: Union[str, Dict] = (config or {}).get("db", {}) | ||
|
|
||
| # --- DB 연결 테스트 ------------------------------------------------------------ | ||
| conn = None | ||
| try: | ||
| # db 설정이 dict면 키워드 인자로, 문자열(DSN)이면 그대로 사용 | ||
| if isinstance(db_cfg, dict): | ||
| conn = psycopg2.connect(**db_cfg) # 예: {"host": "...", ...} | ||
| else: | ||
| conn = psycopg2.connect(dsn=str(db_cfg)) | ||
|
|
||
| with conn: | ||
| with conn.cursor() as cur: | ||
| cur.execute("SELECT version();") | ||
| print("✅ 연결 성공:", cur.fetchone()[0]) | ||
|
|
||
| cur.execute("SELECT current_database(), current_user;") | ||
| db, user = cur.fetchone() | ||
| print(f"ℹ️ DB/USER: {db} / {user}") | ||
| except Exception as e: | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| print("❌ 연결 실패:", repr(e)) | ||
| finally: | ||
| if conn is not None: | ||
| conn.close() | ||
|
|
||
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.
BOM 문자를 제거하세요.
JSON 파일 첫 줄에 BOM 문자(
)가 추가되었습니다. 이는 JSON 파싱 오류를 일으킬 수 있습니다.다음과 같이 수정하세요:
📝 Committable suggestion
🤖 Prompt for AI Agents