Commit
โข
7878351
1
Parent(s):
7e3f770
Update app.py
Browse files
app.py
CHANGED
@@ -42,7 +42,6 @@ class MyClient(discord.Client):
|
|
42 |
if not self.is_message_in_specific_channel(message):
|
43 |
return
|
44 |
if self.is_processing:
|
45 |
-
await message.channel.send("ํ์ฌ ๋ค๋ฅธ ์์ฒญ์ ์ฒ๋ฆฌ ์ค์
๋๋ค. ์ ์๋ง ๊ธฐ๋ค๋ ค ์ฃผ์ธ์.")
|
46 |
return
|
47 |
self.is_processing = True
|
48 |
try:
|
@@ -52,150 +51,128 @@ class MyClient(discord.Client):
|
|
52 |
self.is_processing = False
|
53 |
|
54 |
def is_message_in_specific_channel(self, message):
|
55 |
-
# ๋ฉ์์ง๊ฐ ์ง์ ๋ ์ฑ๋์ด๊ฑฐ๋, ํด๋น ์ฑ๋์ ์ฐ๋ ๋์ธ ๊ฒฝ์ฐ True ๋ฐํ
|
56 |
return message.channel.id == SPECIFIC_CHANNEL_ID or (
|
57 |
isinstance(message.channel, discord.Thread) and message.channel.parent_id == SPECIFIC_CHANNEL_ID
|
58 |
)
|
59 |
|
60 |
async def handle_message(message):
|
61 |
-
|
62 |
-
user_input = message.content.strip()
|
63 |
user_mention = message.author.mention
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
else:
|
69 |
-
ticker = get_ticker_from_name(user_input)
|
70 |
if ticker:
|
71 |
-
return f"{user_mention},
|
72 |
else:
|
73 |
-
return f"{user_mention},
|
|
|
|
|
|
|
|
|
74 |
|
75 |
async def handle_ticker(ticker, user_mention):
|
76 |
global conversation_history # ์ ์ญ ๋ณ์ ์ฌ์ฉ์ ๋ช
์
|
77 |
-
|
|
|
78 |
|
79 |
-
|
|
|
|
|
80 |
if len(conversation_history) > 20:
|
81 |
-
conversation_history
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
"""
|
98 |
|
99 |
-
|
100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
logging.debug(f'๋ชจ๋ธ ์ ์ฒด ์๋ต: {full_response_text}')
|
108 |
-
|
109 |
-
# ์ด์์คํดํธ ์๋ต์ ๋ํ ํ์คํ ๋ฆฌ์ ์ถ๊ฐ
|
110 |
-
conversation_history.append({"role": "assistant", "content": full_response_text})
|
111 |
-
|
112 |
-
# ์ต์ข
์๋ต: ํ์ฌ ์ ๋ณด์ ๋ชจ๋ธ์ ์๋ต ๊ฒฐํฉ
|
113 |
-
final_response = f"{user_mention}, {full_response_text}\n\n**ํ์ฌ ์ ๋ณด:**\n{company_info}"
|
114 |
-
|
115 |
-
return final_response
|
116 |
-
|
117 |
-
def get_ticker_from_name(name):
|
118 |
-
try:
|
119 |
-
ticker_search = Ticker(name)
|
120 |
-
summary = ticker_search.summary_profile
|
121 |
-
# ํฐ์ปค๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ํ์ฑ๋์๋์ง ํ์ธ
|
122 |
-
if summary and isinstance(summary, dict):
|
123 |
-
# ๊ฐ์ฅ ๋งค์นญ๋ ํค๋ฅผ ํฐ์ปค๋ก ์ฌ์ฉ
|
124 |
-
ticker = next(iter(summary.keys()))
|
125 |
-
return ticker
|
126 |
-
return None
|
127 |
-
except Exception as e:
|
128 |
-
logging.error(f'Error retrieving ticker for {name}: {e}')
|
129 |
-
return None
|
130 |
-
|
131 |
-
def get_company_info(ticker):
|
132 |
-
try:
|
133 |
-
stock = Ticker(ticker)
|
134 |
-
summary = stock.summary_detail.get(ticker, {})
|
135 |
-
if not summary:
|
136 |
-
return f"ํฐ์ปค {ticker}์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐ ์คํจํ์ต๋๋ค."
|
137 |
-
|
138 |
-
history = stock.history(period="10y")
|
139 |
-
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
140 |
-
|
141 |
-
company_summary = f"""
|
142 |
-
**ํ์ฌ ์ด๋ฆ:** {summary.get('longName', 'N/A')}
|
143 |
-
**ํฐ์ปค:** {ticker}
|
144 |
-
**์ฐ์
:** {summary.get('industry', 'N/A')}
|
145 |
-
**์นํฐ:** {summary.get('sector', 'N/A')}
|
146 |
-
**์๊ฐ ์ด์ก:** {summary.get('marketCap', 'N/A')}
|
147 |
-
**ํ์ฌ๊ฐ:** {summary.get('previousClose', 'N/A')}
|
148 |
-
**๋ฐ์ดํฐ ์
๋ฐ์ดํธ:** {now}
|
149 |
-
|
150 |
-
**์ต๊ทผ 1์ผ ์ฐจํธ:**\n{get_chart_summary(history, period='1d')}
|
151 |
-
**์ต๊ทผ 1์ฃผ ์ฐจํธ:**\n{get_chart_summary(history, period='1wk')}
|
152 |
-
**์ต๊ทผ 1๊ฐ์ ์ฐจํธ:**\n{get_chart_summary(history, period='1mo')}
|
153 |
-
**์ต๊ทผ 1๋
์ฐจํธ:**\n{get_chart_summary(history, period='1y')}
|
154 |
-
**์ต๊ทผ 10๋
์ฐจํธ:**\n{get_chart_summary(history, period='10y')}
|
155 |
-
|
156 |
-
**์ต์ ๋ด์ค:**\n{get_news_summary(ticker)}
|
157 |
-
|
158 |
-
**ํฅํ 1์ฃผ์ผ๊ฐ ์์ธ ์์ธก:** (๋ชจ๋ธ ๊ธฐ๋ฐ ์์ธก ์ฌ์ฉ)
|
159 |
-
"""
|
160 |
-
|
161 |
-
return company_summary
|
162 |
-
except Exception as e:
|
163 |
-
logging.error(f'Error retrieving company info for {ticker}: {e}')
|
164 |
-
return f"ํฐ์ปค {ticker}์ ๋ํ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๋ฐ ์คํจํ์ต๋๋ค."
|
165 |
-
|
166 |
-
def get_chart_summary(history, period):
|
167 |
if history.empty:
|
168 |
-
return "
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
elif period == '1y':
|
177 |
-
recent = history.tail(365)
|
178 |
-
else: # '10y'
|
179 |
-
recent = history
|
180 |
-
|
181 |
-
average_price = recent['close'].mean()
|
182 |
-
highest_price = recent['close'].max()
|
183 |
-
lowest_price = recent['close'].min()
|
184 |
-
return f"ํ๊ท ๊ฐ: {average_price:.2f}, ์ต๊ณ ๊ฐ: {highest_price:.2f}, ์ต์ ๊ฐ: {lowest_price:.2f}"
|
185 |
-
|
186 |
-
def get_news_summary(ticker):
|
187 |
-
try:
|
188 |
-
stock = Ticker(ticker)
|
189 |
-
news = stock.news()
|
190 |
-
if not news:
|
191 |
-
return "์ต์ ๋ด์ค ์์"
|
192 |
-
|
193 |
-
top_news = news[:3]
|
194 |
-
news_summary = "\n".join([f"{i+1}. [{article['title']}]({article['link']}) - {datetime.fromtimestamp(article['providerPublishTime']).strftime('%Y-%m-%d %H:%M:%S')}" for i, article in enumerate(top_news)])
|
195 |
-
return news_summary
|
196 |
-
except Exception as e:
|
197 |
-
logging.error(f'Error retrieving news for {ticker}: {e}')
|
198 |
return "๋ด์ค ์์ฝ์ ๊ฐ์ ธ์ค๋ ๋ฐ ์คํจํ์ต๋๋ค."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
|
200 |
if __name__ == "__main__":
|
201 |
discord_token = os.getenv('DISCORD_TOKEN')
|
|
|
42 |
if not self.is_message_in_specific_channel(message):
|
43 |
return
|
44 |
if self.is_processing:
|
|
|
45 |
return
|
46 |
self.is_processing = True
|
47 |
try:
|
|
|
51 |
self.is_processing = False
|
52 |
|
53 |
def is_message_in_specific_channel(self, message):
|
|
|
54 |
return message.channel.id == SPECIFIC_CHANNEL_ID or (
|
55 |
isinstance(message.channel, discord.Thread) and message.channel.parent_id == SPECIFIC_CHANNEL_ID
|
56 |
)
|
57 |
|
58 |
async def handle_message(message):
|
59 |
+
user_input = message.content
|
|
|
60 |
user_mention = message.author.mention
|
61 |
|
62 |
+
# ํฐ์ปค๋ฅผ ์ ๊ณตํ์ง ์์ ๊ฒฝ์ฐ
|
63 |
+
if not user_input.startswith("!t "):
|
64 |
+
ticker = await find_ticker(user_input)
|
|
|
|
|
65 |
if ticker:
|
66 |
+
return f"{user_mention}, ์ข
๋ชฉ๋ช
์ ์ฐพ์์ต๋๋ค: {ticker}. ํฐ์ปค ์ ๋ณด๋ฅผ ์ํ๋ฉด '!t {ticker}'๋ผ๊ณ ์
๋ ฅํ์ธ์."
|
67 |
else:
|
68 |
+
return f"{user_mention}, ์ข
๋ชฉ๋ช
์ ์ฐพ์ ์ ์์ต๋๋ค. ์ฌ๋ฐ๋ฅธ ์ข
๋ชฉ๋ช
์ ์
๋ ฅํ์ธ์."
|
69 |
+
|
70 |
+
# ํฐ์ปค๋ฅผ ์ ๊ณตํ ๊ฒฝ์ฐ
|
71 |
+
ticker = user_input[3:].strip().upper()
|
72 |
+
return await handle_ticker(ticker, user_mention)
|
73 |
|
74 |
async def handle_ticker(ticker, user_mention):
|
75 |
global conversation_history # ์ ์ญ ๋ณ์ ์ฌ์ฉ์ ๋ช
์
|
76 |
+
conversation_history.append({"role": "user", "content": ticker})
|
77 |
+
logging.debug(f'Conversation history updated: {conversation_history}')
|
78 |
|
79 |
+
company_info, charts, news_summary, prediction = await get_stock_info(ticker)
|
80 |
+
|
81 |
+
conversation_history.append({"role": "assistant", "content": prediction})
|
82 |
if len(conversation_history) > 20:
|
83 |
+
conversation_history.pop(0)
|
84 |
+
|
85 |
+
return f"""
|
86 |
+
**ํ์ฌ ์ ๋ณด:**
|
87 |
+
ํ์ฌ ์ด๋ฆ: {company_info.get('longName', 'N/A')}
|
88 |
+
ํฐ์ปค: {ticker}
|
89 |
+
์ฐ์
: {company_info.get('industry', 'N/A')}
|
90 |
+
์นํฐ: {company_info.get('sector', 'N/A')}
|
91 |
+
์๊ฐ ์ด์ก: {company_info.get('marketCap', 'N/A')}
|
92 |
+
ํ์ฌ๊ฐ: {company_info.get('currentPrice', 'N/A')}
|
93 |
+
๋ฐ์ดํฐ ์
๋ฐ์ดํธ: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
|
94 |
+
|
95 |
+
**์ต๊ทผ 1์ผ ์ฐจํธ:**
|
96 |
+
{charts['1d']}
|
97 |
+
**์ต๊ทผ 1์ฃผ ์ฐจํธ:**
|
98 |
+
{charts['1w']}
|
99 |
+
**์ต๊ทผ 1๊ฐ์ ์ฐจํธ:**
|
100 |
+
{charts['1m']}
|
101 |
+
**์ต๊ทผ 1๋
์ฐจํธ:**
|
102 |
+
{charts['1y']}
|
103 |
+
**์ต๊ทผ 10๋
์ฐจํธ:**
|
104 |
+
{charts['10y']}
|
105 |
+
|
106 |
+
**์ต์ ๋ด์ค:**
|
107 |
+
{news_summary}
|
108 |
+
|
109 |
+
**ํฅํ 1์ฃผ์ผ๊ฐ ์์ธ ์์ธก:**
|
110 |
+
{prediction}
|
111 |
"""
|
112 |
|
113 |
+
async def find_ticker(query):
|
114 |
+
tickers = Ticker(query)
|
115 |
+
for ticker in tickers.symbols:
|
116 |
+
return ticker
|
117 |
+
return None
|
118 |
+
|
119 |
+
async def get_stock_info(ticker):
|
120 |
+
tickers = Ticker(ticker)
|
121 |
+
summary = tickers.summary_detail[ticker]
|
122 |
+
price = summary.get("previousClose", "N/A")
|
123 |
+
|
124 |
+
company_info = {
|
125 |
+
'longName': tickers.asset_profile[ticker].get('longName', 'N/A'),
|
126 |
+
'industry': tickers.asset_profile[ticker].get('industry', 'N/A'),
|
127 |
+
'sector': tickers.asset_profile[ticker].get('sector', 'N/A'),
|
128 |
+
'marketCap': summary.get('marketCap', 'N/A'),
|
129 |
+
'currentPrice': price,
|
130 |
+
}
|
131 |
+
|
132 |
+
charts = {
|
133 |
+
'1d': get_chart_summary(tickers.history(period="1d", interval="1d")),
|
134 |
+
'1w': get_chart_summary(tickers.history(period="5d", interval="1d")),
|
135 |
+
'1m': get_chart_summary(tickers.history(period="1mo", interval="1d")),
|
136 |
+
'1y': get_chart_summary(tickers.history(period="1y", interval="1d")),
|
137 |
+
'10y': get_chart_summary(tickers.history(period="10y", interval="1d")),
|
138 |
+
}
|
139 |
+
|
140 |
+
news_summary = get_news_summary(tickers.news())
|
141 |
|
142 |
+
prediction = await predict_stock(ticker)
|
143 |
+
|
144 |
+
return company_info, charts, news_summary, prediction
|
145 |
+
|
146 |
+
def get_chart_summary(history):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
if history.empty:
|
148 |
+
return "๋ฐ์ดํฐ ์์"
|
149 |
+
avg_price = history['close'].mean()
|
150 |
+
max_price = history['close'].max()
|
151 |
+
min_price = history['close'].min()
|
152 |
+
return f"ํ๊ท ๊ฐ: {avg_price:.2f}, ์ต๊ณ ๊ฐ: {max_price:.2f}, ์ต์ ๊ฐ: {min_price:.2f}"
|
153 |
+
|
154 |
+
def get_news_summary(news):
|
155 |
+
if not news:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
return "๋ด์ค ์์ฝ์ ๊ฐ์ ธ์ค๋ ๋ฐ ์คํจํ์ต๋๋ค."
|
157 |
+
news_summary = ""
|
158 |
+
for article in news[:5]:
|
159 |
+
news_summary += f"- {article['title']}: {article['summary']}\n"
|
160 |
+
return news_summary.strip()
|
161 |
+
|
162 |
+
async def predict_stock(ticker):
|
163 |
+
messages = [{"role": "system", "content": f"์ฌ์ฉ์๊ฐ ํฐ์ปค '{ticker}'์ ๋ํด ์๊ณ ์ถ์ดํฉ๋๋ค."}] + conversation_history
|
164 |
+
logging.debug(f'๋ชจ๋ธ์ ๋ณด๋ผ ๋ฉ์์ง: {messages}')
|
165 |
+
|
166 |
+
loop = asyncio.get_event_loop()
|
167 |
+
response = await loop.run_in_executor(None, lambda: hf_client.chat_completion(
|
168 |
+
messages, max_tokens=1000, stream=True, temperature=0.7, top_p=0.85))
|
169 |
+
|
170 |
+
full_response = []
|
171 |
+
for part in response:
|
172 |
+
if part.choices and part.choices[0].delta and part.choices[0].delta.content:
|
173 |
+
full_response.append(part.choices[0].delta.content)
|
174 |
+
|
175 |
+
return ''.join(full_response).strip()
|
176 |
|
177 |
if __name__ == "__main__":
|
178 |
discord_token = os.getenv('DISCORD_TOKEN')
|