Spaces:
Runtime error
Runtime error
| import argparse | |
| import csv | |
| import json | |
| import pandas as pd | |
| import requests | |
| from datetime import datetime | |
| from pathlib import Path | |
| from io import StringIO | |
| def get_user_df(input_path: str, top_n: int) -> pd.DataFrame: | |
| df = pd.read_csv(input_path, dtype={'์ข ๋ชฉ์ฝ๋': str}) | |
| df['๋งค์ ๊ธ์ก'] = df['๋งค์ ์ฃผ๊ฐ'] * df['๋ณด์ ์ฃผ์์'] | |
| df_sorted = df.sort_values(by='๋งค์ ๊ธ์ก', ascending=False) | |
| df_top = df_sorted.head(top_n) | |
| df_top = df_top[['์ข ๋ชฉ์ฝ๋', '์ข ๋ชฉ๋ช ', '๋งค์ ์ฃผ๊ฐ', '๋ณด์ ์ฃผ์์']] | |
| return df_top | |
| def request_post(base_url: str, service: str, req_body: dict) -> dict: | |
| try: | |
| url = f'{base_url}/{service}' | |
| res = requests.post( | |
| url=url, | |
| json=req_body | |
| ) | |
| res.raise_for_status() | |
| except Exception as e: | |
| print(f'[ERROR] {service} / ์๋ฌ ๋ฐ์: {str(e)}') | |
| res_body = res.json() | |
| if res_body['success']: | |
| return res_body['data'] | |
| def update_user_with_stock_price(json_data, res_data): | |
| """ | |
| res_data ๋ก ๋ฐ์ stock_price ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก | |
| json_data["user"] ํญ๋ชฉ์ ํ์ฌ์ฃผ๊ฐ, ์์ต๋ฅ , ํ์ฌ์์ฐ์ ์ ๋ฐ์ดํธ | |
| """ | |
| def normalize(code): | |
| return str(code).strip().upper() | |
| # user ๋ชฉ๋ก ๊ฐ์ ธ์ค๊ธฐ | |
| user_list = json_data.get("user", []) | |
| if not isinstance(user_list, list): | |
| print("[WARN] user ๋ฐ์ดํฐ ๊ตฌ์กฐ๊ฐ list ์๋ โ ์ ๋ฐ์ดํธ ๋ถ๊ฐ") | |
| return | |
| # ์ข ๋ชฉ ๊ฐ๊ฒฉ dict(normalized) | |
| stock_price_map = {normalize(k): v for k, v in res_data.items()} | |
| # user ๊ฐ ํญ๋ชฉ ์ ๋ฐ์ดํธ | |
| for user_item in user_list: | |
| raw_code = user_item.get("์ข ๋ชฉ์ฝ๋") | |
| if not raw_code: | |
| continue | |
| code = normalize(raw_code) | |
| # stock_price ์ ํด๋น ์ข ๋ชฉ์ด ์กด์ฌํ๋์ง ํ์ธ | |
| prices = stock_price_map.get(code) | |
| if not prices: | |
| print(f"[WARN] {code} ์ข ๋ชฉ์ ์ฃผ๊ฐ ๋ฐ์ดํฐ ์์ โ user ์ถ๊ฐ์ ๋ณด ์คํต") | |
| continue | |
| # ์ต์ ์ข ๊ฐ (list ๋ง์ง๋ง) | |
| last_row = prices[-1] | |
| try: | |
| current_price = float(last_row.get("Close")) | |
| buy_price = float(user_item.get("๋งค์ ์ฃผ๊ฐ")) | |
| qty = float(user_item.get("๋ณด์ ์ฃผ์์")) | |
| except Exception: | |
| print(f"[WARN] {code} ๊ฐ ๋ณํ ์ค๋ฅ โ user ์ถ๊ฐ์ ๋ณด ์คํต") | |
| continue | |
| # ์์ต๋ฅ ๊ณ์ฐ | |
| profit_rate = round(((current_price - buy_price) / buy_price) * 100, 2) | |
| current_asset = round(current_price * qty, 2) | |
| # ์ ๋ฐ์ดํธ | |
| user_item["ํ์ฌ์ฃผ๊ฐ"] = str(current_price) | |
| user_item["์์ต๋ฅ "] = f"{profit_rate}%" | |
| user_item["ํ์ฌ์์ฐ"] = str(current_asset) | |
| # ์ ์ฅ | |
| json_data["user"] = user_list | |
| return json_data | |
| def collect_data(region, base_url: str, portfolio: pd.DataFrame): | |
| json_data = { | |
| 'user': [], | |
| 'similar_investors': {}, | |
| 'investment_company': {}, | |
| 'industry_info': [], | |
| 'theme_info': [], | |
| 'stock_price': {}, | |
| 'stock_news': {}, | |
| } | |
| # ------------------------------ | |
| # ์ ์ฌ ํฌ์์ | |
| # ------------------------------ | |
| service = 'similar_investors' | |
| req_body = { | |
| 'csv_text': portfolio.to_csv(index=False), | |
| 'region': region[0] if isinstance(region, list) else region, | |
| 'top': 5 | |
| } | |
| print(f"[INFO] ์ ์ฌ ํฌ์์ {req_body['top']}๊ฐ ์์ง ์์..") | |
| res_data = request_post(base_url, service, req_body) | |
| if not res_data: | |
| print(f'[ERROR] ์ ์ฌ ํฌ์์ ์์ง ์คํจ..') | |
| return None | |
| print(f'[INFO] ์ ์ฌ ํฌ์์ ์์ง ์๋ฃ:', res_data) | |
| json_data[service] = res_data | |
| # user ํค ์ ์ฅ | |
| used_user_csv = portfolio.to_csv(index=False) | |
| f = StringIO(used_user_csv) | |
| reader = csv.reader(f) | |
| rows = list(reader) | |
| if not rows or len(rows) < 2: | |
| print("[WARN] portfolio CSV ๋ด์ฉ์ด ๋น์ด ์์ด user ๋ฐ์ดํฐ ์ ์ฅ์ ์๋ตํฉ๋๋ค.") | |
| json_data["user"] = [] | |
| else: | |
| headers = rows[0] | |
| user_list = [dict(zip(headers, cols)) for cols in rows[1:]] | |
| json_data["user"] = user_list | |
| # ์ฐ์ , ํ ๋ง ์์ฒญ์ ํฌ์์ ์ข ๋ชฉ๋ ํฌํจ | |
| si_names = list(set([d['NAME'] for rows in res_data.values() for d in rows])) | |
| si_companies = list(set([d['COMPANY'] for rows in res_data.values() for d in rows])) | |
| # ------------------------------ | |
| # ์ ์ฌ ํฌ์ํ์ฌ ์ค๋ช | |
| # ------------------------------ | |
| print("[INFO] ํฌ์ํ์ฌ name ๋ชฉ๋ก:", si_names) | |
| service = "investment_company" | |
| for name in si_names: | |
| print(f"[INFO] {name} ์ค๋ช ์์ง ์์..") | |
| req_body = {"name": name} | |
| res_data = request_post(base_url, service, req_body) | |
| if not res_data: | |
| print("[ERROR] ์ค๋ช ์์ง ์คํจ:", name) | |
| json_data[service][name] = { | |
| "error": True, | |
| "detail": "request_post failed" | |
| } | |
| continue | |
| print("[INFO] ์ค๋ช ์์ง ์๋ฃ:", res_data) | |
| json_data[service][name] = res_data | |
| if not json_data[service]: | |
| print(f'[ERROR] ์ ์ฌ ํฌ์์ ์์ง ์คํจ..') | |
| return None | |
| print() | |
| # ------------------------------ | |
| # ์ฐ์ ์ ๋ณด | |
| # ------------------------------ | |
| service = 'industry_info' | |
| stock = portfolio['์ข ๋ชฉ์ฝ๋'].to_list() + si_companies | |
| req_body = { | |
| 'stock': stock | |
| } | |
| print(f'[INFO] ์ฐ์ ์ ๋ณด {",".join(stock)} ์์ง ์์..') | |
| res_data = request_post(base_url, service, req_body) | |
| if not res_data: | |
| print(f'[ERROR] ์ฐ์ ์ ๋ณด ์์ง ์คํจ..') | |
| return None | |
| # ์ค๋ณต ์ ๊ฑฐ | |
| seen = set() | |
| unique_data = [d for d in res_data if not (d['stock'] in seen or seen.add(d['stock']))] | |
| print(f'[INFO] ์ฐ์ ์ ๋ณด ์์ง ์๋ฃ:', unique_data) | |
| print() | |
| json_data[service] = unique_data | |
| # ------------------------------ | |
| # ํ ๋ง์ ๋ณด | |
| # ------------------------------ | |
| service = 'theme_info' | |
| stock = portfolio['์ข ๋ชฉ์ฝ๋'].to_list() + si_companies | |
| req_body = { | |
| 'stock': stock | |
| } | |
| print(f'[INFO] ํ ๋ง์ ๋ณด {",".join(stock)} ์์ง ์์..') | |
| res_data = request_post(base_url, service, req_body) | |
| if not res_data: | |
| print(f'[ERROR] ํ ๋ง์ ๋ณด ์์ง ์คํจ..') | |
| return None | |
| # ์ค๋ณต ์ ๊ฑฐ | |
| seen = set() | |
| unique_data = [d for d in res_data if not (d['stock'] in seen or seen.add(d['stock']))] | |
| print(f'[INFO] ํ ๋ง์ ๋ณด ์์ง ์๋ฃ:', unique_data) | |
| print() | |
| json_data[service] = unique_data | |
| # ------------------------------ | |
| # ์ข ๋ชฉ ๊ฐ๊ฒฉ | |
| # ------------------------------ | |
| service = 'stock_price' | |
| stock = ','.join(portfolio['์ข ๋ชฉ์ฝ๋']) | |
| req_body = {'stock': stock} | |
| print(f'[INFO] ์ข ๋ชฉ๊ฐ๊ฒฉ {stock} ์์ง ์์..') | |
| res_data = request_post(base_url, service, req_body) | |
| if not res_data: | |
| print(f'[ERROR] ์ข ๋ชฉ๊ฐ๊ฒฉ ์์ง ์คํจ..') | |
| return None | |
| print(f'[INFO] ์ข ๋ชฉ๊ฐ๊ฒฉ ์์ง ์๋ฃ:', res_data) | |
| print() | |
| json_data[service] = res_data | |
| json_data = update_user_with_stock_price(json_data, res_data) | |
| # ------------------------------ | |
| # ์ข ๋ชฉ ๋ด์ค | |
| # ------------------------------ | |
| service = 'stock_news' | |
| for stock in portfolio['์ข ๋ชฉ์ฝ๋']: | |
| print(f'[INFO] ์ข ๋ชฉ๋ด์ค {stock} ์์ง ์์..') | |
| req_body = { | |
| 'stock': stock, | |
| 'period': 7 | |
| } | |
| res_data = request_post(base_url, service, req_body) | |
| if res_data: | |
| print(f'[INFO] ์ข ๋ชฉ๋ด์ค {stock} ์์ง ์๋ฃ:', res_data) | |
| json_data[service] |= res_data | |
| else: | |
| print(f'[ERROR] ์ข ๋ชฉ๋ด์ค {stock} ์์ง ์คํจ..') | |
| if not json_data[service]: | |
| print(f'[ERROR] ์ข ๋ชฉ๋ด์ค ์์ง ์คํจ..') | |
| return None | |
| print() | |
| return json_data | |
| def save_results(output_root: str, user_csv: str, output_json: dict, report: str): | |
| output_dir = Path(output_root) / datetime.now().strftime('%y%m%d_%H%M%S') | |
| output_dir.mkdir(parents=True, exist_ok=True) | |
| # ------------------------------ | |
| # ์ ์ ํฌํธํด๋ฆฌ์ค ์ ์ฅ | |
| # ------------------------------ | |
| user_path = output_dir / 'user.csv' | |
| with open(user_path, 'w') as f: | |
| f.write(user_csv) | |
| print(f'[INFO] ์ ์ ํฌํธํด๋ฆฌ์ค ์ ์ฅ ์๋ฃ -> {user_path}') | |
| # ------------------------------ | |
| # ๋ฐ์ดํฐ ์ ์ฅ | |
| # ------------------------------ | |
| output_path = output_dir / 'output.json' | |
| with open(output_path, 'w') as f: | |
| json.dump(output_json, f, ensure_ascii=False, indent=2) | |
| print(f'[INFO] ๋ฐ์ดํฐ ์ ์ฅ ์๋ฃ -> {output_path}') | |
| # ------------------------------ | |
| # ๋ฆฌํฌํธ ์ ์ฅ | |
| # ------------------------------ | |
| report_path = output_dir / 'report.txt' | |
| with open(report_path, 'w') as f: | |
| f.write(report) | |
| print(f'[INFO] ๋ฆฌํฌํธ ์ ์ฅ ์๋ฃ -> {report_path}') | |
| def main(): | |
| parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) | |
| parser.add_argument('--server', type=str, default='http://localhost:8080', help='์๋ฒ ์ฃผ์') | |
| parser.add_argument("--region", choices=['ko', 'us'], required=True, help="์ง์ญ ์ ํ: ko(ํ๊ตญ) ๋๋ us(๋ฏธ๊ตญ)") | |
| parser.add_argument('--user', type=str, default='user.csv', help='์ ์ ํฌํธํด๋ฆฌ์ค csv ํ์ผ ๊ฒฝ๋ก') | |
| parser.add_argument('--user_name', type=str, default='์ด์์ค', help='ํฌ์์ ์ด๋ฆ') | |
| parser.add_argument('--output', type=str, default='results', help='๊ฒฐ๊ณผ ๊ฒฝ๋ก') | |
| args = parser.parse_args() | |
| # ------------------------------ | |
| # ๋ฐ์ดํฐ ์์ง | |
| # ------------------------------ | |
| user_df = get_user_df(args.user, top_n=5) | |
| json_data = collect_data(args.region, args.server, user_df) | |
| if not json_data: | |
| print(f'[ERROR] ๋ฐ์ดํฐ ์์ง ์คํจ.. ๋ณด๊ณ ์ ์์ฑ ์ข ๋ฃ.') | |
| return | |
| # ------------------------------ | |
| # ๋ณด๊ณ ์ ์์ฑ | |
| # ------------------------------ | |
| service = 'report' | |
| req_body = { | |
| "date": datetime.now().strftime("%Y-%m-%d"), # ๋ฆฌํฌํธ ์์ฑ ๋ ์ง (๊ธฐ๋ณธ: ์ค๋ ๋ ์ง) | |
| 'user_name': args.user_name, | |
| 'csv_text': user_df.to_csv(index=False), | |
| 'json_text': json_data | |
| } | |
| print(f'[INFO] ์ ์ [{args.user_name}] ๋ณด๊ณ ์ ์์ฑ ์์..') | |
| report_data = request_post(args.server, service, req_body) | |
| if not report_data: | |
| print(f'[ERROR] ๋ณด๊ณ ์ ์์ฑ ์คํจ..') | |
| return | |
| report = report_data['report'] | |
| # ------------------------------ | |
| # ๊ฒฐ๊ณผ ์ ์ฅ | |
| # ------------------------------ | |
| save_results(args.output, user_df.to_csv(index=False), json_data, report) | |
| if __name__ == '__main__': | |
| main() | |