cutechicken commited on
Commit
95bd5ef
ยท
verified ยท
1 Parent(s): 6a32883

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +130 -25
app.py CHANGED
@@ -38,11 +38,33 @@ COMMON_TICKERS = {
38
  "meta": "META",
39
  "tesla": "TSLA",
40
  "nvidia": "NVDA",
 
 
 
 
 
 
 
 
41
  "bitcoin": "BTC-USD",
42
  "ethereum": "ETH-USD",
 
 
 
 
43
  "samsung": "005930.KS", # ํ•œ๊ตญ ์‚ผ์„ฑ์ „์ž
44
  "hyundai": "005380.KS", # ํ˜„๋Œ€์ž๋™์ฐจ
45
  "sk hynix": "000660.KS", # SKํ•˜์ด๋‹‰์Šค
 
 
 
 
 
 
 
 
 
 
46
  }
47
 
48
  def fetch_articles(query, max_articles=30):
@@ -167,27 +189,73 @@ def get_stock_ticker(asset_name):
167
  """
168
  ์ž์‚ฐ๋ช…์œผ๋กœ๋ถ€ํ„ฐ ์ฃผ์‹ ํ‹ฐ์ปค ์‹ฌ๋ณผ์„ ์ถ”์ถœ
169
  """
 
 
170
  # ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋งคํ•‘ ํ™•์ธ
171
- asset_lower = asset_name.lower()
172
 
173
  # ์ง์ ‘ ํ‹ฐ์ปค๋กœ ์ž…๋ ฅํ•œ ๊ฒฝ์šฐ (๋Œ€๋ฌธ์ž 3-5์ž ํ˜•ํƒœ)
174
- if asset_name.isupper() and 3 <= len(asset_name) <= 5:
 
175
  return asset_name
176
 
177
  # ์ผ๋ฐ˜์ ์ธ ์ข…๋ชฉ๋ช… ๋งคํ•‘ ํ™•์ธ
178
  if asset_lower in COMMON_TICKERS:
179
- return COMMON_TICKERS[asset_lower]
180
-
181
- # ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ yfinance๋กœ ๊ฒ€์ƒ‰ ์‹œ๋„
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  try:
 
183
  ticker_search = yf.Ticker(asset_name)
184
- # ๊ธฐ๋ณธ ์ •๋ณด ๊ฐ€์ ธ์™€์„œ ์œ ํšจํ•œ ํ‹ฐ์ปค์ธ์ง€ ํ™•์ธ
185
- info = ticker_search.info
186
- if 'symbol' in info:
187
- return info['symbol']
188
- except:
189
- pass
190
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  return None
192
 
193
  def create_stock_chart(ticker, period="1mo"):
@@ -196,12 +264,28 @@ def create_stock_chart(ticker, period="1mo"):
196
  """
197
  try:
198
  logging.info(f"Fetching stock data for {ticker}")
199
- stock_data = yf.download(ticker, period=period)
 
 
 
 
 
 
 
 
 
 
 
200
 
201
  if stock_data.empty:
202
  logging.warning(f"No stock data found for ticker: {ticker}")
203
  return None
204
 
 
 
 
 
 
205
  fig, ax = plt.subplots(figsize=(10, 6))
206
 
207
  # ์ข…๊ฐ€ ๊ทธ๋ž˜ํ”„
@@ -212,10 +296,19 @@ def create_stock_chart(ticker, period="1mo"):
212
  stock_data['MA20'] = stock_data['Close'].rolling(window=20).mean()
213
  ax.plot(stock_data.index, stock_data['MA20'], label='20-day MA', color='orange')
214
 
215
- # ๊ฑฐ๋ž˜๋Ÿ‰ ์„œ๋ธŒํ”Œ๋กฏ ์ถ”๊ฐ€
216
- ax2 = ax.twinx()
217
- ax2.bar(stock_data.index, stock_data['Volume'], alpha=0.3, color='gray', label='Volume')
218
- ax2.set_ylabel('Volume')
 
 
 
 
 
 
 
 
 
219
 
220
  # ์ฐจํŠธ ์Šคํƒ€์ผ๋ง
221
  ax.set_title(f"{ticker} Stock Price")
@@ -223,15 +316,10 @@ def create_stock_chart(ticker, period="1mo"):
223
  ax.set_ylabel('Price')
224
  ax.grid(True, alpha=0.3)
225
 
226
- # ๋ฒ”๋ก€ ์ถ”๊ฐ€
227
- lines, labels = ax.get_legend_handles_labels()
228
- lines2, labels2 = ax2.get_legend_handles_labels()
229
- ax.legend(lines + lines2, labels + labels2, loc='upper left')
230
-
231
  plt.tight_layout()
232
 
233
  # ์ด๋ฏธ์ง€ ์ €์žฅ
234
- chart_path = f"stock_chart_{ticker.replace('-', '_')}.png"
235
  plt.savefig(chart_path)
236
  plt.close()
237
 
@@ -239,7 +327,18 @@ def create_stock_chart(ticker, period="1mo"):
239
  return chart_path
240
  except Exception as e:
241
  logging.error(f"Error creating stock chart for {ticker}: {e}")
242
- return None
 
 
 
 
 
 
 
 
 
 
 
243
 
244
  def analyze_asset_sentiment(asset_name):
245
  logging.info(f"Starting sentiment analysis for asset: {asset_name}")
@@ -422,7 +521,13 @@ with gr.Blocks() as iface:
422
  wrap=False,
423
  )
424
 
425
- analyze_button.click(
 
 
 
 
 
 
426
  analyze_asset_sentiment,
427
  inputs=[input_asset],
428
  outputs=[articles_output, sentiment_summary, stock_chart, ticker_info],
 
38
  "meta": "META",
39
  "tesla": "TSLA",
40
  "nvidia": "NVDA",
41
+ "netflix": "NFLX",
42
+ "amd": "AMD",
43
+ "intel": "INTC",
44
+ "ibm": "IBM",
45
+ "oracle": "ORCL",
46
+ "paypal": "PYPL",
47
+ "adobe": "ADBE",
48
+ "cisco": "CSCO",
49
  "bitcoin": "BTC-USD",
50
  "ethereum": "ETH-USD",
51
+ "dogecoin": "DOGE-USD",
52
+ "cardano": "ADA-USD",
53
+ "xrp": "XRP-USD",
54
+ "litecoin": "LTC-USD",
55
  "samsung": "005930.KS", # ํ•œ๊ตญ ์‚ผ์„ฑ์ „์ž
56
  "hyundai": "005380.KS", # ํ˜„๋Œ€์ž๋™์ฐจ
57
  "sk hynix": "000660.KS", # SKํ•˜์ด๋‹‰์Šค
58
+ "lg": "003550.KS", # LG
59
+ "lge": "066570.KS", # LG์ „์ž
60
+ "ncsoft": "036570.KS", # ์—”์”จ์†Œํ”„ํŠธ
61
+ "kakao": "035720.KS", # ์นด์นด์˜ค
62
+ "naver": "035420.KS", # ๋„ค์ด๋ฒ„
63
+ "ํ˜„๋Œ€์ฐจ": "005380.KS", # ํ˜„๋Œ€์ž๋™์ฐจ
64
+ "์‚ผ์„ฑ์ „์ž": "005930.KS", # ์‚ผ์„ฑ์ „์ž
65
+ "์‚ผ์„ฑ": "005930.KS", # ์‚ผ์„ฑ์ „์ž
66
+ "์นด์นด์˜ค": "035720.KS", # ์นด์นด์˜ค
67
+ "๋„ค์ด๋ฒ„": "035420.KS", # ๋„ค์ด๋ฒ„
68
  }
69
 
70
  def fetch_articles(query, max_articles=30):
 
189
  """
190
  ์ž์‚ฐ๋ช…์œผ๋กœ๋ถ€ํ„ฐ ์ฃผ์‹ ํ‹ฐ์ปค ์‹ฌ๋ณผ์„ ์ถ”์ถœ
191
  """
192
+ logging.info(f"Identifying ticker for: {asset_name}")
193
+
194
  # ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ๋งคํ•‘ ํ™•์ธ
195
+ asset_lower = asset_name.lower().strip()
196
 
197
  # ์ง์ ‘ ํ‹ฐ์ปค๋กœ ์ž…๋ ฅํ•œ ๊ฒฝ์šฐ (๋Œ€๋ฌธ์ž 3-5์ž ํ˜•ํƒœ)
198
+ if asset_name.isupper() and 2 <= len(asset_name) <= 6:
199
+ logging.info(f"Input appears to be a ticker symbol: {asset_name}")
200
  return asset_name
201
 
202
  # ์ผ๋ฐ˜์ ์ธ ์ข…๋ชฉ๋ช… ๋งคํ•‘ ํ™•์ธ
203
  if asset_lower in COMMON_TICKERS:
204
+ ticker = COMMON_TICKERS[asset_lower]
205
+ logging.info(f"Found ticker in common tickers map: {ticker}")
206
+ return ticker
207
+
208
+ # ์—ฌ๋Ÿฌ ๋‹จ์–ด๋กœ ๋œ ์ด๋ฆ„์˜ ๊ฐ ๋ถ€๋ถ„์— ๋Œ€ํ•œ ๊ฒ€์ƒ‰๋„ ์‹œ๋„
209
+ asset_parts = asset_lower.split()
210
+ for part in asset_parts:
211
+ if part in COMMON_TICKERS:
212
+ ticker = COMMON_TICKERS[part]
213
+ logging.info(f"Found ticker for part '{part}': {ticker}")
214
+ return ticker
215
+
216
+ # ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ ์ง์ ‘ ํ‹ฐ์ปค๋กœ ์‹œ๋„
217
+ potential_ticker = asset_name.upper().replace(" ", "")
218
+ if 2 <= len(potential_ticker) <= 6:
219
+ # ์‹ค์ œ๋กœ ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ
220
+ try:
221
+ logging.info(f"Trying potential ticker: {potential_ticker}")
222
+ test_data = yf.download(potential_ticker, period="1d", progress=False)
223
+ if not test_data.empty:
224
+ logging.info(f"Valid ticker found: {potential_ticker}")
225
+ return potential_ticker
226
+ except Exception as e:
227
+ logging.debug(f"Error testing potential ticker: {e}")
228
+
229
+ # ๊ทธ ์™ธ์˜ ๊ฒฝ์šฐ yfinance๋กœ ๊ฒ€์ƒ‰ ์‹œ๋„ (info ๋ฐ์ดํ„ฐ)
230
  try:
231
+ # ์ผ๋ถ€ ํ‹ฐ์ปค๋Š” ์ง์ ‘ yfinance ๊ธฐ๋ฐ˜ ๊ฒ€์ƒ‰์œผ๋กœ๋Š” ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ
232
  ticker_search = yf.Ticker(asset_name)
233
+ try:
234
+ info = ticker_search.info
235
+ if 'symbol' in info and info['symbol']:
236
+ ticker = info['symbol']
237
+ logging.info(f"Found ticker from info API: {ticker}")
238
+ return ticker
239
+ except (ValueError, KeyError, TypeError) as e:
240
+ logging.debug(f"Error getting ticker info: {e}")
241
+ pass
242
+ except Exception as e:
243
+ logging.debug(f"Error initializing ticker object: {e}")
244
+
245
+ # ์ถ”๊ฐ€ ์‹œ๋„: ์ผ๋ฐ˜์ ์ธ ๋ฏธ๊ตญ ์ฆ์‹œ ํ‹ฐ์ปค ํ˜•์‹ ํ™•์ธ
246
+ major_exchanges = ["", ".KS", ".KQ", "-USD"] # ์ฃผ์š” ๊ฑฐ๋ž˜์†Œ ์ ‘๋ฏธ์‚ฌ (ํ•œ๊ตญ ํฌํ•จ)
247
+ for exchange in major_exchanges:
248
+ try:
249
+ test_ticker = f"{asset_name.upper().replace(' ', '')}{exchange}"
250
+ logging.info(f"Trying with exchange suffix: {test_ticker}")
251
+ test_data = yf.download(test_ticker, period="1d", progress=False)
252
+ if not test_data.empty:
253
+ logging.info(f"Valid ticker found with suffix: {test_ticker}")
254
+ return test_ticker
255
+ except:
256
+ pass
257
+
258
+ logging.warning(f"Could not identify ticker for: {asset_name}")
259
  return None
260
 
261
  def create_stock_chart(ticker, period="1mo"):
 
264
  """
265
  try:
266
  logging.info(f"Fetching stock data for {ticker}")
267
+ # Graceful handling for problematic symbols
268
+ try:
269
+ stock_data = yf.download(ticker, period=period, progress=False)
270
+ except Exception as dl_error:
271
+ logging.error(f"Error downloading stock data: {dl_error}")
272
+ # Try alternative symbol format
273
+ if "-" in ticker:
274
+ alt_ticker = ticker.replace("-", ".")
275
+ logging.info(f"Trying alternative ticker format: {alt_ticker}")
276
+ stock_data = yf.download(alt_ticker, period=period, progress=False)
277
+ else:
278
+ raise dl_error
279
 
280
  if stock_data.empty:
281
  logging.warning(f"No stock data found for ticker: {ticker}")
282
  return None
283
 
284
+ # ๋ฐ์ดํ„ฐ ํ™•์ธ ๋ฐ ๋””๋ฒ„๊ทธ ๋กœ๊น…
285
+ logging.info(f"Downloaded data shape: {stock_data.shape}")
286
+ logging.info(f"Data columns: {stock_data.columns.tolist()}")
287
+
288
+ # ๊ทธ๋ž˜ํ”„ ์ž‘์„ฑ
289
  fig, ax = plt.subplots(figsize=(10, 6))
290
 
291
  # ์ข…๊ฐ€ ๊ทธ๋ž˜ํ”„
 
296
  stock_data['MA20'] = stock_data['Close'].rolling(window=20).mean()
297
  ax.plot(stock_data.index, stock_data['MA20'], label='20-day MA', color='orange')
298
 
299
+ # ๊ฑฐ๋ž˜๋Ÿ‰ ์„œ๋ธŒํ”Œ๋กฏ ์ถ”๊ฐ€ (๊ฑฐ๋ž˜๋Ÿ‰์ด ์žˆ๋Š” ๊ฒฝ์šฐ๋งŒ)
300
+ if 'Volume' in stock_data.columns and not stock_data['Volume'].isna().all():
301
+ ax2 = ax.twinx()
302
+ ax2.bar(stock_data.index, stock_data['Volume'], alpha=0.3, color='gray', label='Volume')
303
+ ax2.set_ylabel('Volume')
304
+
305
+ # ๋ฒ”๋ก€ ์ถ”๊ฐ€ (๊ฑฐ๋ž˜๋Ÿ‰ ์žˆ๋Š” ๊ฒฝ์šฐ)
306
+ lines, labels = ax.get_legend_handles_labels()
307
+ lines2, labels2 = ax2.get_legend_handles_labels()
308
+ ax.legend(lines + lines2, labels + labels2, loc='upper left')
309
+ else:
310
+ # ๊ฑฐ๋ž˜๋Ÿ‰ ์—†๋Š” ๊ฒฝ์šฐ ์ข…๊ฐ€๋งŒ ํ‘œ์‹œ
311
+ ax.legend(loc='upper left')
312
 
313
  # ์ฐจํŠธ ์Šคํƒ€์ผ๋ง
314
  ax.set_title(f"{ticker} Stock Price")
 
316
  ax.set_ylabel('Price')
317
  ax.grid(True, alpha=0.3)
318
 
 
 
 
 
 
319
  plt.tight_layout()
320
 
321
  # ์ด๋ฏธ์ง€ ์ €์žฅ
322
+ chart_path = f"stock_chart_{ticker.replace('-', '_').replace('.', '_')}.png"
323
  plt.savefig(chart_path)
324
  plt.close()
325
 
 
327
  return chart_path
328
  except Exception as e:
329
  logging.error(f"Error creating stock chart for {ticker}: {e}")
330
+ # ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ์—๋„ ๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ ์‹œ๋„ (๊ธฐ๋ณธ ํ…์ŠคํŠธ ์•ˆ๋‚ด)
331
+ try:
332
+ fig, ax = plt.subplots(figsize=(10, 6))
333
+ ax.text(0.5, 0.5, f"Unable to load data for {ticker}\nError: {str(e)}",
334
+ horizontalalignment='center', verticalalignment='center', transform=ax.transAxes)
335
+ ax.set_axis_off()
336
+ chart_path = f"stock_chart_error_{ticker.replace('-', '_').replace('.', '_')}.png"
337
+ plt.savefig(chart_path)
338
+ plt.close()
339
+ return chart_path
340
+ except:
341
+ return None
342
 
343
  def analyze_asset_sentiment(asset_name):
344
  logging.info(f"Starting sentiment analysis for asset: {asset_name}")
 
521
  wrap=False,
522
  )
523
 
524
+ # ๋””๋ฒ„๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜ ์ถ”๊ฐ€
525
+ def debug_callback(message):
526
+ logging.info(f"DEBUG: {message}")
527
+ return f"Debug: {message}"
528
+
529
+ # ๋ถ„์„ ๋ฒ„ํŠผ ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ์—ฐ๊ฒฐ
530
+ analyze_button.click(
531
  analyze_asset_sentiment,
532
  inputs=[input_asset],
533
  outputs=[articles_output, sentiment_summary, stock_chart, ticker_info],