StockPulse / app.py
llllllllllllllllllllllllllleeeeeeeeeeeeee's picture
Update app.py
b9cf696 verified
raw
history blame
5.83 kB
# ν•„μš”ν•œ 라이브러리 μ„€μΉ˜ 및 μ—…λ°μ΄νŠΈ
import subprocess
subprocess.run(["pip", "install", "--upgrade", "pip"])
subprocess.run(["pip", "install", "--upgrade", "yfinance", "gradio", "matplotlib", "Pillow"])
# 라이브러리 μž„ν¬νŠΈ
import yfinance as yf
import gradio as gr
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import numpy as np
import pandas as pd
import re
import io
from PIL import Image
from datetime import datetime, timedelta
# λ‚˜λˆ”κ³ λ”• 폰트 μ„€μΉ˜ 및 적용
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)
plt.rcParams['font.family'] = 'NanumGothic'
except Exception as e:
print(f"폰트 μ„€μΉ˜ 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {e}")
install_nanum_font()
# λ‰΄μŠ€ μš”μ•½ ν•¨μˆ˜ (μ—¬κΈ°μ„œλŠ” κ°„λ‹¨νžˆ μ˜ˆμ‹œλ‘œ 처리)
def get_real_news_summary(company, date):
# μ‹€μ œ APIλ₯Ό μ‚¬μš©ν•  수 μ—†λŠ” ν™˜κ²½μ΄λ―€λ‘œ, κ°„λ‹¨ν•œ λ¬Έμžμ—΄λ‘œ λŒ€μ²΄ν•©λ‹ˆλ‹€.
return f"{company}의 {date} μ£Όλ³€ λ‰΄μŠ€ μš”μ•½μž…λ‹ˆλ‹€."
def handle_click(company_name, date_clicked):
return get_real_news_summary(company_name, date_clicked)
def update_news(input_value, selected_date):
if not selected_date:
return "λ‚ μ§œλ₯Ό μ„ νƒν•΄μ£Όμ„Έμš”."
else:
ticker = name_to_ticker.get(input_value, input_value)
company_name = ticker_to_name.get(ticker, input_value)
return handle_click(company_name, selected_date)
# μ’…λͺ©λͺ…κ³Ό 티컀 λ§€ν•‘ λ”•μ…”λ„ˆλ¦¬
name_to_ticker = {
"SKλ°”μ΄μ˜€νŒœ": "326030.KS",
"λ‚˜μŠ€λ‹₯ μ‹œμ΄ 1μœ„": "AAPL",
"λ‚˜μŠ€λ‹₯ λ°”μ΄μ˜€ν… μ‹œμ΄ 1μœ„": "AMGN",
"λ‚˜μŠ€λ‹₯ ν—¬μŠ€μΌ€μ–΄ μ‹œμ΄ 1μœ„": "JNJ",
"μ½”μŠ€ν”Ό μ‹œμ΄ 1μœ„": "005930.KS",
"μ½”μŠ€λ‹₯ μ‹œμ΄ 1μœ„": "247540.KQ", # μ—μ½”ν”„λ‘œλΉ„μ— 
}
ticker_to_name = {v: k for k, v in name_to_ticker.items()}
# μ£Όκ°€ 데이터λ₯Ό κ°€μ Έμ˜€κ³  κ·Έλž˜ν”„λ₯Ό κ·Έλ¦¬λŠ” ν•¨μˆ˜
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 "μ£Όκ°€ 데이터λ₯Ό 찾을 수 μ—†μŠ΅λ‹ˆλ‹€.", gr.Dropdown.update(choices=[])
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", gr.Dropdown.update(choices=[])
dates = stock_data.index
closing_prices = stock_data['Close']
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=8, color=color, ha='right')
plt.axvline(x=index, color=color, linestyle='--', linewidth=1)
company_name = ticker_to_name.get(ticker, input_value)
plt.title(f'{company_name} μ£Όκ°€ 좔이')
plt.xlabel('λ‚ μ§œ')
plt.ylabel('μ’…κ°€')
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.Dropdown.update(choices=highlight_dates)
except Exception as e:
print(f"Error: {e}")
return f"데이터 처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {e}", gr.Dropdown.update(choices=[])
# Gradio μΈν„°νŽ˜μ΄μŠ€ 생성 (3μ—΄ λ ˆμ΄μ•„μ›ƒ)
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 λ²„νŠΌ 클릭 μ‹œ κ·Έλž˜ν”„ 및 λ‚ μ§œ λ“œλ‘­λ‹€μš΄ μ—…λ°μ΄νŠΈ
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()