|
import subprocess |
|
|
|
|
|
subprocess.run(["pip", "install", "--upgrade", "pip"]) |
|
subprocess.run(["pip", "install", "--upgrade", "openai", "yfinance", "gradio", "matplotlib", "Pillow"]) |
|
|
|
import os |
|
import matplotlib.font_manager as fm |
|
import matplotlib.pyplot as plt |
|
import yfinance as yf |
|
import numpy as np |
|
import re |
|
import gradio as gr |
|
import io |
|
from PIL import Image |
|
from datetime import datetime, timedelta |
|
from openai import OpenAI |
|
|
|
|
|
def install_nanum_font(): |
|
try: |
|
subprocess.run(["apt-get", "update"], check=True) |
|
subprocess.run(["apt-get", "install", "-y", "fonts-nanum"], check=True) |
|
subprocess.run(["fc-cache", "-fv"], check=True) |
|
except Exception as e: |
|
print(f"ํฐํธ ์ค์น ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค: {e}") |
|
|
|
install_nanum_font() |
|
|
|
|
|
font_path = '/usr/share/fonts/truetype/nanum/NanumGothic.ttf' |
|
|
|
if os.path.exists(font_path): |
|
fm.fontManager.addfont(font_path) |
|
else: |
|
print("ํฐํธ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.") |
|
|
|
|
|
font_prop = fm.FontProperties(fname=font_path) |
|
plt.rcParams['font.family'] = font_prop.get_name() |
|
plt.rcParams['axes.unicode_minus'] = False |
|
|
|
|
|
ticker = '005930.KS' |
|
stock = yf.Ticker(ticker) |
|
stock_data = stock.history(period="max") |
|
|
|
|
|
print(stock_data.head()) |
|
|
|
|
|
plt.figure(figsize=(10, 6)) |
|
|
|
|
|
dates = stock_data.index.to_numpy() |
|
closing_prices = stock_data['Close'].to_numpy() |
|
|
|
|
|
plt.plot(dates, closing_prices, label='์ผ์ฑ์ ์ ์ข
๊ฐ') |
|
|
|
|
|
plt.title('์ผ์ฑ์ ์ ์ฃผ๊ฐ ์ถ์ด', fontproperties=font_prop) |
|
plt.xlabel('๋ ์ง', fontproperties=font_prop) |
|
plt.ylabel('์ข
๊ฐ', fontproperties=font_prop) |
|
plt.legend(prop=font_prop) |
|
|
|
|
|
|
|
|
|
API_KEY = "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" |
|
|
|
|
|
def get_real_news_summary(company, date): |
|
|
|
client = OpenAI(api_key=API_KEY, base_url="https://api.perplexity.ai") |
|
|
|
|
|
target_date = datetime.strptime(date, '%Y-%m-%d') |
|
start_date = (target_date - timedelta(days=1)).strftime('%Y-%m-%d') |
|
end_date = (target_date + timedelta(days=1)).strftime('%Y-%m-%d') |
|
|
|
|
|
messages = [ |
|
{"role": "system", "content": "You are a helpful assistant that summarizes stock news strictly in Korean."}, |
|
{"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."} |
|
] |
|
|
|
try: |
|
|
|
response = client.chat.completions.create( |
|
model="llama-3.1-sonar-large-128k-online", |
|
messages=messages |
|
) |
|
|
|
|
|
summary = response.choices[0].message.content |
|
|
|
|
|
korean_only_summary = re.sub(r'[^\uAC00-\uD7A3\u3131-\u318E\u1100-\u11FF\u3131-\uD79D0-9a-zA-Z\s#.,!%()\[\]]', '', summary) |
|
|
|
|
|
formatted_summary = re.sub(r'##\s*(.+)', r'**\1**', korean_only_summary) |
|
|
|
return formatted_summary |
|
except Exception as e: |
|
return f"๋ด์ค ์์ฝ ์ค ์๋ฌ๊ฐ ๋ฐ์ํ์ต๋๋ค: {str(e)}" |
|
|
|
|
|
def handle_click(company_name, date_clicked): |
|
return get_real_news_summary(company_name, date_clicked) |
|
|
|
|
|
def update_news(input_value, selected_date): |
|
if selected_date == "" or selected_date is None: |
|
return "๋ ์ง๋ฅผ ์ ํํด์ฃผ์ธ์." |
|
else: |
|
|
|
ticker = name_to_ticker.get(input_value, input_value) |
|
company_name = input_value if ticker == input_value else list(name_to_ticker.keys())[list(name_to_ticker.values()).index(ticker)] |
|
return handle_click(company_name, selected_date) |
|
|
|
|
|
name_to_ticker = { |
|
"์ผ์ฑ์ ์": "005930.KS", |
|
"SK๋ฐ์ด์คํ": "326030.KS", |
|
"Apple": "AAPL", |
|
"Nvidia": "NVDA", |
|
"Vertex": "VRTX", |
|
"Eli Lilly": "LLY", |
|
"ํ๋์ฐจ": "005380.KS", |
|
"์นด์นด์ค": "035720.KS", |
|
"LGํํ": "051910.KS", |
|
"์
ํธ๋ฆฌ์จ": "068270.KS", |
|
"๋ค์ด๋ฒ": "035420.KS", |
|
"์์ฝํ๋ก๋น์ ": "247540.KS", |
|
"์ํ
์ค์ ": "196170.KQ", |
|
|
|
"๋์ค๋ฅ ์์ด 1์": "AAPL", |
|
"๋์ค๋ฅ ๋ฐ์ด์คํ
์์ด 1์": "VRTX", |
|
"๋์ค๋ฅ ํฌ์ค์ผ์ด ์์ด 1์": "LLY", |
|
"์ฝ์คํผ ์์ด 1์": "005930.KS", |
|
"์ฝ์ค๋ฅ ์์ด 1์": "196170.KQ", |
|
} |
|
|
|
|
|
def display_stock_with_highlight(input_value, change_type, percent_change): |
|
try: |
|
|
|
ticker = name_to_ticker.get(input_value, input_value) |
|
stock = yf.Ticker(ticker) |
|
stock_data = stock.history(period="5y") |
|
|
|
if stock_data.empty: |
|
return "์ฃผ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.", [] |
|
|
|
stock_data['Change'] = stock_data['Close'].pct_change() * 100 |
|
|
|
percent_change = float(percent_change) |
|
|
|
if change_type == "์์น": |
|
highlight_data = stock_data[stock_data['Change'] >= percent_change] |
|
color = "darkorange" |
|
elif change_type == "ํ๋ฝ": |
|
highlight_data = stock_data[stock_data['Change'] <= -percent_change] |
|
color = "purple" |
|
else: |
|
return "Invalid change type", [] |
|
|
|
dates = stock_data.index.to_numpy() |
|
closing_prices = stock_data['Close'].to_numpy() |
|
|
|
plt.figure(figsize=(10, 6)) |
|
plt.plot(dates, closing_prices, color='gray', label=input_value) |
|
plt.scatter(highlight_data.index, highlight_data['Close'], color=color, label=f'{change_type} ํฌ์ธํธ') |
|
|
|
for index, row in highlight_data.iterrows(): |
|
plt.text(index, row['Close'], index.strftime('%Y-%m-%d'), fontsize=10, fontweight='bold', color=color, ha='right') |
|
plt.axvline(x=index, color=color, linestyle='--', linewidth=1) |
|
|
|
|
|
company_name = list(name_to_ticker.keys())[list(name_to_ticker.values()).index(ticker)] |
|
plt.title(f'{company_name} ์ฃผ๊ฐ ์ถ์ด', fontproperties=font_prop) |
|
plt.xlabel('๋ ์ง', fontproperties=font_prop) |
|
plt.ylabel('์ข
๊ฐ', fontproperties=font_prop) |
|
plt.legend() |
|
|
|
buf = io.BytesIO() |
|
plt.savefig(buf, format='png') |
|
plt.close() |
|
buf.seek(0) |
|
img = Image.open(buf) |
|
|
|
highlight_dates = highlight_data.index.strftime('%Y-%m-%d').tolist() |
|
|
|
return img, gr.update(choices=highlight_dates) |
|
except Exception as e: |
|
return f"Error processing data: {e}", gr.update(choices=[]) |
|
|
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("## ์ฃผ๊ฐ ๊ทธ๋ํ์ ๋ด์ค ์์ฝ") |
|
|
|
with gr.Row(): |
|
with gr.Column(): |
|
input_value = gr.Textbox(label="์ข
๋ชฉ๋ช
๋๋ ํฐ์ปค ์
๋ ฅ", placeholder="์: SK๋ฐ์ด์คํ, AAPL") |
|
change_type = gr.Dropdown(choices=["์์น", "ํ๋ฝ"], label="์์น ๋๋ ํ๋ฝ ์ ํ", value="์์น") |
|
percent_change = gr.Textbox(label="๋ณ๋ ํผ์ผํธ (%)", placeholder="์: 10", value="10") |
|
|
|
submit_btn = gr.Button("Submit") |
|
|
|
|
|
examples = [["SK๋ฐ์ด์คํ"], |
|
["๋์ค๋ฅ ์์ด 1์"], |
|
["๋์ค๋ฅ ํฌ์ค์ผ์ด ์์ด 1์"], |
|
["๋์ค๋ฅ ๋ฐ์ด์คํ
์์ด 1์"], |
|
["์ฝ์คํผ ์์ด 1์"], |
|
["์ฝ์ค๋ฅ ์์ด 1์"]] |
|
gr.Examples(examples=examples, inputs=[input_value]) |
|
|
|
with gr.Column(): |
|
plot = gr.Image(label="์ฃผ๊ฐ ๊ทธ๋ํ") |
|
date_dropdown = gr.Dropdown(label="์กฐ๊ฑด์ ํด๋นํ๋ ๋ ์ง ์ ํ", choices=[]) |
|
|
|
with gr.Column(): |
|
|
|
news_output = gr.Markdown(label="๋ด์ค ์์ฝ", value="") |
|
|
|
|
|
submit_btn.click( |
|
fn=display_stock_with_highlight, |
|
inputs=[input_value, change_type, percent_change], |
|
outputs=[plot, date_dropdown] |
|
) |
|
|
|
|
|
date_dropdown.change( |
|
fn=update_news, |
|
inputs=[input_value, date_dropdown], |
|
outputs=[news_output] |
|
) |
|
|
|
|
|
demo.launch() |
|
|