Commit
b8aa6cf
ยท
verified ยท
1 Parent(s): 5e70a47

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +146 -31
app.py CHANGED
@@ -1,52 +1,165 @@
1
- import yfinance as yf
2
  import subprocess
 
 
 
 
 
 
 
 
3
  import matplotlib.font_manager as fm
4
  import matplotlib.pyplot as plt
 
 
5
  import gradio as gr
6
  import io
7
  from PIL import Image
8
  from datetime import datetime, timedelta
9
- import os
10
 
11
- # ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ ๋ฐ ์—…๋ฐ์ดํŠธ
12
- subprocess.run(["pip", "install", "--upgrade", "pip"])
13
- subprocess.run(["pip", "install", "--upgrade", "openai", "yfinance", "gradio", "matplotlib", "Pillow"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
  # Perplexity AI API ์„ค์ •
16
  API_KEY = "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" # ์—ฌ๊ธฐ์— Perplexity AI API ํ‚ค๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.
17
 
18
- # yfinance๋กœ ๋‚˜์Šค๋‹ฅ ํ—ฌ์Šค์ผ€์–ด ์‹œ์ด 1์œ„ ์ข…๋ชฉ ๊ฐ€์ ธ์˜ค๊ธฐ
19
- def get_nasdaq_healthcare_leader():
20
- # ํ—ฌ์Šค์ผ€์–ด ์„นํ„ฐ ์ƒ์œ„ ๊ธฐ์—…๋“ค์„ ๊ฐ€์ ธ์˜ด
21
- healthcare_tickers = ["JNJ", "PFE", "MRNA", "VRTX", "AMGN"] # ์˜ˆ์‹œ๋กœ ๋‚˜์Šค๋‹ฅ ํ—ฌ์Šค์ผ€์–ด ์ƒ์œ„ ํ‹ฐ์ปค๋“ค
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  largest_market_cap = 0
23
- leader_ticker = ""
24
 
25
- for ticker in healthcare_tickers:
26
  stock = yf.Ticker(ticker)
27
- stock_data = stock.history(period="1d") # ์ „์ผ ์ข…๊ฐ€ ๊ธฐ์ค€
28
- market_cap = stock.info.get('marketCap', 0)
 
 
 
 
 
 
 
29
 
30
  if market_cap > largest_market_cap:
31
  largest_market_cap = market_cap
32
- leader_ticker = ticker
33
-
34
- return leader_ticker
35
 
36
- # ์ข…๋ชฉ๋ช…๊ณผ ํ‹ฐ์ปค๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๋”•์…”๋„ˆ๋ฆฌ ํ™•์žฅ ๋ฐ ์กฐ๊ฑด๋ณ„ ์ข…๋ชฉ ๋งคํ•‘
37
- name_to_ticker = {
38
- "๋‚˜์Šค๋‹ฅ ์‹œ์ด 1์œ„": "AAPL", # Apple
39
- "๋‚˜์Šค๋‹ฅ ๋ฐ”์ด์˜คํ… ์‹œ์ด 1์œ„": "VRTX", # Vertex Pharmaceuticals
40
- "๋‚˜์Šค๋‹ฅ ํ—ฌ์Šค์ผ€์–ด ์‹œ์ด 1์œ„": get_nasdaq_healthcare_leader(), # yfinance๋กœ ๋™์ ์œผ๋กœ ์„ค์ •
41
- "์ฝ”์Šคํ”ผ ์‹œ์ด 1์œ„": "005930.KS", # ์‚ผ์„ฑ์ „์ž
42
- "์ฝ”์Šค๋‹ฅ ์‹œ์ด 1์œ„": "196170.KQ", # ์•Œํ…Œ์˜ค์  
43
- }
44
 
45
  # ์ฃผ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์กฐ๊ฑด์— ๋งž๋Š” ๋‚ ์งœ์™€ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
46
  def display_stock_with_highlight(input_value, change_type, percent_change):
47
  try:
48
  # ์ž…๋ ฅ๊ฐ’์„ ํ‹ฐ์ปค๋กœ ๋ณ€ํ™˜
49
- ticker = name_to_ticker.get(input_value, input_value)
50
  stock = yf.Ticker(ticker)
51
  stock_data = stock.history(period="5y") # ์ตœ๊ทผ 5๋…„ ๋ฐ์ดํ„ฐ๋กœ ์ œํ•œ
52
 
@@ -74,11 +187,13 @@ def display_stock_with_highlight(input_value, change_type, percent_change):
74
 
75
  for index, row in highlight_data.iterrows():
76
  plt.text(index, row['Close'], index.strftime('%Y-%m-%d'), fontsize=10, fontweight='bold', color=color, ha='right')
77
- plt.axvline(x=index, color=color, linestyle='--', linewidth=1) # x์ถ•๊ณผ์˜ ์—ฐ๊ฒฐ์„  ์ ์„ ์œผ๋กœ ํ‘œ์‹œ
78
 
79
- plt.title(f'{input_value} ์ฃผ๊ฐ€ ์ถ”์ด')
80
- plt.xlabel('๋‚ ์งœ')
81
- plt.ylabel('์ข…๊ฐ€')
 
 
82
  plt.legend()
83
 
84
  buf = io.BytesIO()
@@ -105,11 +220,11 @@ with gr.Blocks() as demo:
105
 
106
  submit_btn = gr.Button("Submit")
107
 
108
- # ์˜ˆ์ œ (์ด์ „ ๋ ˆ์ด์•„์›ƒ์œผ๋กœ ๋ณต์›)
109
  examples = [["SK๋ฐ”์ด์˜คํŒœ"],
110
  ["๋‚˜์Šค๋‹ฅ ์‹œ์ด 1์œ„"],
111
  ["๋‚˜์Šค๋‹ฅ ๋ฐ”์ด์˜คํ… ์‹œ์ด 1์œ„"],
112
- ["๋‚˜์Šค๋‹ฅ ํ—ฌ์Šค์ผ€์–ด ์‹œ์ด 1์œ„"], # ์ˆ˜์ •๋œ ์˜ˆ์ œ
113
  ["์ฝ”์Šคํ”ผ ์‹œ์ด 1์œ„"],
114
  ["์ฝ”์Šค๋‹ฅ ์‹œ์ด 1์œ„"]]
115
  gr.Examples(examples=examples, inputs=[input_value])
 
1
+ # ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ ๋ฐ ์—…๋ฐ์ดํŠธ๋ฅผ ์ตœ์ƒ๋‹จ์— ๋ฐฐ์น˜
2
  import subprocess
3
+
4
+ # ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ ๋ฐ ์—…๋ฐ์ดํŠธ
5
+ subprocess.run(["pip", "install", "--upgrade", "pip"])
6
+ subprocess.run(["pip", "install", "--upgrade", "openai", "yfinance", "gradio", "matplotlib", "Pillow"])
7
+
8
+ # ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ž„ํฌํŠธ
9
+ import yfinance as yf
10
+ import os
11
  import matplotlib.font_manager as fm
12
  import matplotlib.pyplot as plt
13
+ import numpy as np
14
+ import re # ํ•œ๊ธ€, ์ˆซ์ž, ๊ธฐํ˜ธ๋ฅผ ๋‚จ๊ธฐ๊ธฐ ์œ„ํ•œ ์ •๊ทœ ํ‘œํ˜„์‹์— ์‚ฌ์šฉ
15
  import gradio as gr
16
  import io
17
  from PIL import Image
18
  from datetime import datetime, timedelta
19
+ from openai import OpenAI
20
 
21
+ # 1. ๋‚˜๋ˆ”๊ณ ๋”• ํฐํŠธ ์„ค์น˜ ๋ฐ ์ ์šฉ
22
+ def install_nanum_font():
23
+ try:
24
+ subprocess.run(["apt-get", "update"], check=True)
25
+ subprocess.run(["apt-get", "install", "-y", "fonts-nanum"], check=True)
26
+ subprocess.run(["fc-cache", "-fv"], check=True)
27
+ except Exception as e:
28
+ print(f"ํฐํŠธ ์„ค์น˜ ์ค‘ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {e}")
29
+
30
+ install_nanum_font()
31
+
32
+ # ๋‚˜๋ˆ”๊ณ ๋”• ํฐํŠธ ๊ฒฝ๋กœ ์„ค์ • ๋ฐ ๊ฐ•์ œ ์ ์šฉ
33
+ font_path = '/usr/share/fonts/truetype/nanum/NanumGothic.ttf'
34
+
35
+ if os.path.exists(font_path):
36
+ fm.fontManager.addfont(font_path)
37
+ else:
38
+ print("ํฐํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.")
39
+
40
+ # ๋‚˜๋ˆ”๊ณ ๋”• ํฐํŠธ ๊ฐ•์ œ ์ ์šฉ
41
+ font_prop = fm.FontProperties(fname=font_path)
42
+ plt.rcParams['font.family'] = font_prop.get_name()
43
+ plt.rcParams['axes.unicode_minus'] = False # ๋งˆ์ด๋„ˆ์Šค ๋ถ€ํ˜ธ ๊นจ์ง ๋ฐฉ์ง€
44
 
45
  # Perplexity AI API ์„ค์ •
46
  API_KEY = "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" # ์—ฌ๊ธฐ์— Perplexity AI API ํ‚ค๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”.
47
 
48
+ # ๋‰ด์Šค ์š”์•ฝ์„ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜ (๊ธฐ์กด ์ฝ”๋“œ ์œ ์ง€)
49
+ def get_real_news_summary(company, date):
50
+ # OpenAI ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐํ™”
51
+ client = OpenAI(api_key=API_KEY, base_url="https://api.perplexity.ai")
52
+
53
+ # ๋‚ ์งœ ํ˜•์‹์„ ๋งž์ถฐ์ฃผ๊ธฐ ์œ„ํ•œ ์ฒ˜๋ฆฌ
54
+ target_date = datetime.strptime(date, '%Y-%m-%d')
55
+ start_date = (target_date - timedelta(days=1)).strftime('%Y-%m-%d')
56
+ end_date = (target_date + timedelta(days=1)).strftime('%Y-%m-%d')
57
+
58
+ # API ์š”์ฒญ์„ ์œ„ํ•œ ๋ฉ”์‹œ์ง€ ๊ตฌ์„ฑ - ํ•œ๊ตญ์–ด๋กœ๋งŒ ์‘๋‹ต์„ ๋ฐ›๋„๋ก ์ง€์‹œ
59
+ messages = [
60
+ {"role": "system", "content": "You are a helpful assistant that summarizes stock news strictly in Korean."},
61
+ {"role": "user", "content": f"Summarize the stock news for {company} between {start_date} and {end_date} in Korean. Only focus on news within this date range."}
62
+ ]
63
+
64
+ try:
65
+ # API ์š”์ฒญ
66
+ response = client.chat.completions.create(
67
+ model="llama-3.1-sonar-large-128k-online",
68
+ messages=messages
69
+ )
70
+
71
+ # ์‘๋‹ต์—์„œ ์š”์•ฝ ์ถ”์ถœ
72
+ summary = response.choices[0].message.content
73
+
74
+ # ํ•œ๊ธ€, ์ˆซ์ž, ๊ณต๋ฐฑ, ํŠน์ˆ˜ ๊ธฐํ˜ธ๋งŒ ๋‚จ๊ธฐ๋Š” ์ •๊ทœ ํ‘œํ˜„์‹
75
+ korean_only_summary = re.sub(r'[^\w\s#.,!%()\-\[\]]', '', summary)
76
+
77
+ # ##๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ถ€๋ถ„์„ **์œผ๋กœ ๊ฐ์‹ธ์„œ Bold ์ฒ˜๋ฆฌ
78
+ formatted_summary = re.sub(r'##\s*(.+)', r'**\1**', korean_only_summary)
79
+
80
+ return formatted_summary
81
+ except Exception as e:
82
+ return f"๋‰ด์Šค ์š”์•ฝ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค: {str(e)}"
83
+
84
+ # ๋‰ด์Šค ์š”์•ฝ์„ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
85
+ def handle_click(company_name, date_clicked):
86
+ return get_real_news_summary(company_name, date_clicked)
87
+
88
+ # Gradio์—์„œ ์‚ฌ์šฉํ•  ํ•จ์ˆ˜ (๋‰ด์Šค ์š”์•ฝ ํฌํ•จ)
89
+ def update_news(input_value, selected_date):
90
+ if selected_date == "" or selected_date is None:
91
+ return "๋‚ ์งœ๋ฅผ ์„ ํƒํ•ด์ฃผ์„ธ์š”."
92
+ else:
93
+ # ์ข…๋ชฉ๋ช…์„ ๊ฐ€์ ธ์™€์„œ Perplexity๋กœ ๊ฒ€์ƒ‰
94
+ ticker = get_dynamic_ticker(input_value)
95
+ company_name = input_value if ticker == input_value else ticker_to_name.get(ticker, input_value)
96
+ return handle_click(company_name, selected_date)
97
+
98
+ # ์ข…๋ชฉ๋ช…๊ณผ ํ‹ฐ์ปค๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๋”•์…”๋„ˆ๋ฆฌ
99
+ ticker_to_name = {}
100
+ name_to_ticker = {}
101
+
102
+ # ๋ชจ๋“  ์˜ˆ์ œ๋ฅผ ๋™์ ์œผ๋กœ ๋งค์นญํ•˜๊ธฐ ์œ„ํ•œ ํ•จ์ˆ˜
103
+ def get_dynamic_ticker(input_value):
104
+ if input_value == "๋‚˜์Šค๋‹ฅ ์‹œ์ด 1์œ„":
105
+ return get_top_market_cap_stock("๋‚˜์Šค๋‹ฅ")
106
+ elif input_value == "๋‚˜์Šค๋‹ฅ ๋ฐ”์ด์˜คํ… ์‹œ์ด 1์œ„":
107
+ return get_top_market_cap_stock("๋‚˜์Šค๋‹ฅ", industry="Biotechnology")
108
+ elif input_value == "๋‚˜์Šค๋‹ฅ ํ—ฌ์Šค์ผ€์–ด ์‹œ์ด 1์œ„":
109
+ return get_top_market_cap_stock("๋‚˜์Šค๋‹ฅ", sector="Healthcare")
110
+ elif input_value == "์ฝ”์Šคํ”ผ ๏ฟฝ๏ฟฝ์ด 1์œ„":
111
+ return get_top_market_cap_stock("์ฝ”์Šคํ”ผ")
112
+ elif input_value == "์ฝ”์Šค๋‹ฅ ์‹œ์ด 1์œ„":
113
+ return get_top_market_cap_stock("์ฝ”์Šค๋‹ฅ")
114
+ else:
115
+ # ์‚ฌ์ „์— ๋“ฑ๋ก๋œ ์ข…๋ชฉ๋ช… ๋ฐ˜ํ™˜
116
+ return name_to_ticker.get(input_value, input_value)
117
+
118
+ # ์‹œ๊ฐ€์ด์•ก ์ƒ์œ„ ์ข…๋ชฉ์„ ๊ฐ€์ ธ์˜ค๋Š” ํ•จ์ˆ˜
119
+ def get_top_market_cap_stock(market, sector=None, industry=None):
120
+ # yfinance๋Š” ์ข…๋ชฉ ๋ชฉ๋ก์„ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ETF๋ฅผ ํ™œ์šฉ
121
+ if market == "๋‚˜์Šค๋‹ฅ":
122
+ etf_ticker = "QQQ" # ๋‚˜์Šค๋‹ฅ 100 ETF
123
+ elif market == "์ฝ”์Šคํ”ผ":
124
+ etf_ticker = "EWY" # ํ•œ๊ตญ ETF
125
+ elif market == "์ฝ”์Šค๋‹ฅ":
126
+ # ์ฝ”์Šค๋‹ฅ ์ข…๋ชฉ์€ ์ ‘๊ทผํ•˜๊ธฐ ์–ด๋ ค์šฐ๋ฏ€๋กœ ์‚ฌ์ „ ์ •์˜๋œ ๋ฆฌ์ŠคํŠธ ์‚ฌ์šฉ
127
+ tickers = ["035420.KQ", "068270.KQ", "035720.KQ"]
128
+ else:
129
+ return None
130
+
131
+ if market in ["๋‚˜์Šค๋‹ฅ", "์ฝ”์Šคํ”ผ"]:
132
+ etf = yf.Ticker(etf_ticker)
133
+ holdings = etf.info.get('holdings', [])
134
+ tickers = [holding['symbol'] for holding in holdings]
135
+
136
  largest_market_cap = 0
137
+ top_ticker = None
138
 
139
+ for ticker in tickers:
140
  stock = yf.Ticker(ticker)
141
+ stock_info = stock.info
142
+ market_cap = stock_info.get('marketCap', 0)
143
+ stock_sector = stock_info.get('sector', None)
144
+ stock_industry = stock_info.get('industry', None)
145
+
146
+ if sector and stock_sector != sector:
147
+ continue
148
+ if industry and stock_industry != industry:
149
+ continue
150
 
151
  if market_cap > largest_market_cap:
152
  largest_market_cap = market_cap
153
+ top_ticker = ticker
154
+ ticker_to_name[ticker] = stock_info.get('shortName', ticker)
 
155
 
156
+ return top_ticker
 
 
 
 
 
 
 
157
 
158
  # ์ฃผ๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์กฐ๊ฑด์— ๋งž๋Š” ๋‚ ์งœ์™€ ๊ทธ๋ž˜ํ”„๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
159
  def display_stock_with_highlight(input_value, change_type, percent_change):
160
  try:
161
  # ์ž…๋ ฅ๊ฐ’์„ ํ‹ฐ์ปค๋กœ ๋ณ€ํ™˜
162
+ ticker = get_dynamic_ticker(input_value)
163
  stock = yf.Ticker(ticker)
164
  stock_data = stock.history(period="5y") # ์ตœ๊ทผ 5๋…„ ๋ฐ์ดํ„ฐ๋กœ ์ œํ•œ
165
 
 
187
 
188
  for index, row in highlight_data.iterrows():
189
  plt.text(index, row['Close'], index.strftime('%Y-%m-%d'), fontsize=10, fontweight='bold', color=color, ha='right')
190
+ plt.axvline(x=index, color=color, linestyle='--', linewidth=1)
191
 
192
+ # ์ข…๋ชฉ๋ช… + '์ฃผ๊ฐ€ ์ถ”์ด'๋กœ ์ œ๋ชฉ ์„ค์ • (์ข…๋ชฉ๋ช… ๊ธฐ๋ฐ˜)
193
+ company_name = ticker_to_name.get(ticker, input_value)
194
+ plt.title(f'{company_name} ์ฃผ๊ฐ€ ์ถ”์ด', fontproperties=font_prop)
195
+ plt.xlabel('๋‚ ์งœ', fontproperties=font_prop)
196
+ plt.ylabel('์ข…๊ฐ€', fontproperties=font_prop)
197
  plt.legend()
198
 
199
  buf = io.BytesIO()
 
220
 
221
  submit_btn = gr.Button("Submit")
222
 
223
+ # ์˜ˆ์ œ (๋™์ ์œผ๋กœ ๋งค์นญ)
224
  examples = [["SK๋ฐ”์ด์˜คํŒœ"],
225
  ["๋‚˜์Šค๋‹ฅ ์‹œ์ด 1์œ„"],
226
  ["๋‚˜์Šค๋‹ฅ ๋ฐ”์ด์˜คํ… ์‹œ์ด 1์œ„"],
227
+ ["๋‚˜์Šค๋‹ฅ ํ—ฌ์Šค์ผ€์–ด ์‹œ์ด 1์œ„"],
228
  ["์ฝ”์Šคํ”ผ ์‹œ์ด 1์œ„"],
229
  ["์ฝ”์Šค๋‹ฅ ์‹œ์ด 1์œ„"]]
230
  gr.Examples(examples=examples, inputs=[input_value])