StockPulse / app.py
llllllllllllllllllllllllllleeeeeeeeeeeeee's picture
Update app.py
bf83c95 verified
raw
history blame
6.08 kB
# ν•„μš”ν•œ 라이브러리 μ„€μΉ˜ 및 μ—…λ°μ΄νŠΈ
!pip install --upgrade pip
!pip install --upgrade openai yfinance gradio matplotlib Pillow
# λͺ¨λ“  ν•„μš”ν•œ νŒ¨ν‚€μ§€κ°€ μ„€μΉ˜λœ ν›„ κ³„μ†ν•΄μ„œ μ‹€ν–‰λ˜λ„λ‘ 함.
import requests
import gradio as gr
import yfinance as yf
import matplotlib.pyplot as plt
import io
from PIL import Image
from datetime import datetime, timedelta
from openai import OpenAI
import os
# Perplexity AI API μ„€μ •
API_KEY = "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" # 여기에 Perplexity AI API ν‚€λ₯Ό μž…λ ₯ν•˜μ„Έμš”.
def get_real_news_summary(company, date):
# OpenAI ν΄λΌμ΄μ–ΈνŠΈ μ΄ˆκΈ°ν™”
client = OpenAI(api_key=API_KEY, base_url="https://api.perplexity.ai")
# API μš”μ²­μ„ μœ„ν•œ λ©”μ‹œμ§€ ꡬ성
messages = [
{"role": "system", "content": "You are a helpful assistant that summarizes stock news in Korean."},
{"role": "user", "content": f"Summarize the latest stock news for {company} on {date} in Korean. If there's no specific news for that date, provide the most recent relevant information."}
]
try:
# API μš”μ²­
response = client.chat.completions.create(
model="llama-3.1-sonar-large-128k-online",
messages=messages
)
# μ‘λ‹΅μ—μ„œ μš”μ•½ μΆ”μΆœ
summary = response.choices[0].message.content
return summary
except Exception as e:
return f"λ‰΄μŠ€ μš”μ•½ 쀑 μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: {str(e)}"
# λ‰΄μŠ€ μš”μ•½μ„ κ°€μ Έμ˜€λŠ” ν•¨μˆ˜
def handle_click(input_value, date_clicked):
return get_real_news_summary(input_value, date_clicked)
# Gradioμ—μ„œ μ‚¬μš©ν•  ν•¨μˆ˜ (λ‰΄μŠ€ μš”μ•½ 포함)
def update_news(input_value, selected_date):
if selected_date == "" or selected_date is None:
return "λ‚ μ§œλ₯Ό μ„ νƒν•΄μ£Όμ„Έμš”."
else:
return handle_click(input_value, selected_date)
# μ’…λͺ©λͺ…κ³Ό 티컀λ₯Ό λ§€ν•‘ν•˜λŠ” λ”•μ…”λ„ˆλ¦¬
name_to_ticker = {
"μ‚Όμ„±μ „μž": "005930.KS",
"SKλ°”μ΄μ˜€νŒœ": "326030.KS",
"Apple": "AAPL",
# ν•„μš”ν•œ μ’…λͺ©λ“€μ„ μΆ”κ°€ν•˜μ„Έμš”
}
# μ£Όκ°€ 데이터λ₯Ό κ°€μ Έμ˜€κ³  쑰건에 λ§žλŠ” λ‚ μ§œμ™€ κ·Έλž˜ν”„λ₯Ό λ°˜ν™˜ν•˜λŠ” ν•¨μˆ˜
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") # 졜근 5λ…„ λ°μ΄ν„°λ‘œ μ œν•œ
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) # xμΆ•κ³Όμ˜ μ—°κ²°μ„  μ μ„ μœΌλ‘œ ν‘œμ‹œ
plt.title(f'{input_value} μ£Όκ°€ 좔이 ({change_type} ν‘œμ‹œ)')
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.update(choices=highlight_dates)
except Exception as e:
return f"Error processing data: {e}", gr.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.Textbox(label="λ‰΄μŠ€ μš”μ•½")
# 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]
)
# Gradio μ‹€ν–‰
demo.launch()