KYTHY commited on
Commit
5bb810d
·
verified ·
1 Parent(s): fb9ddf4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +59 -30
app.py CHANGED
@@ -45,6 +45,7 @@ def analyze_text(text):
45
  """วิเคราะห์อารมณ์ของข่าวด้วย FinBERT"""
46
  if not text or not text.strip():
47
  return 0
 
48
  inputs = tokenizer(
49
  text,
50
  return_tensors="pt",
@@ -52,14 +53,17 @@ def analyze_text(text):
52
  truncation=True,
53
  max_length=512
54
  )
 
55
  with torch.no_grad():
56
  outputs = model(**inputs)
57
  logits = outputs.logits
58
  probs = torch.softmax(logits, dim=1).numpy()[0]
59
- # FinBERT = [negative, neutral, positive]
60
- score = (-1 * probs[0]) + (0 * probs[1]) + (1 * probs[2])
 
61
  return float(score)
62
 
 
63
  def summarize_themes(news_texts):
64
  """สรุปธีมข่าวด้วย Zero-shot classification"""
65
  themes = []
@@ -77,6 +81,7 @@ def resolve_company_symbol(keyword: str):
77
  keyword = keyword.strip()
78
  ticker = None
79
  name = None
 
80
  try:
81
  data = yf.Ticker(keyword)
82
  info = data.info
@@ -92,10 +97,12 @@ def resolve_company_symbol(keyword: str):
92
  name = q.get("longname", q.get("shortname", keyword))
93
  except:
94
  pass
 
95
  if not ticker:
96
  ticker = keyword.upper()
97
  if not name:
98
  name = keyword.capitalize()
 
99
  return name, ticker
100
 
101
  # --------------------------
@@ -106,7 +113,9 @@ def fetch_financial_news(keyword):
106
  company, symbol = resolve_company_symbol(keyword)
107
  to_date = datetime.now().strftime('%Y-%m-%d')
108
  from_date = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
 
109
  query_keyword = f"({company} OR {symbol}) finance stock"
 
110
  all_articles = []
111
  page = 1
112
  while True:
@@ -122,9 +131,11 @@ def fetch_financial_news(keyword):
122
  if data.get("status") != "ok":
123
  st.error(f"API Error: {data}")
124
  break
 
125
  articles = data.get("articles", [])
126
  if not articles:
127
  break
 
128
  for a in articles:
129
  if a["description"]:
130
  all_articles.append({
@@ -133,9 +144,11 @@ def fetch_financial_news(keyword):
133
  "source": a["source"]["name"],
134
  "url": a["url"]
135
  })
 
136
  if len(articles) < 100:
137
  break
138
  page += 1
 
139
  return pd.DataFrame(all_articles)
140
 
141
  # --------------------------
@@ -147,14 +160,18 @@ def fetch_stock_price(symbol, start_date, end_date):
147
  start_str = (start_date - timedelta(days=2)).strftime('%Y-%m-%d')
148
  end_str = (end_date + timedelta(days=1)).strftime('%Y-%m-%d')
149
  df = yf.download(symbol, start=start_str, end=end_str, interval="1d")
 
150
  if df.empty:
151
  st.warning("ไม่พบข้อมูลราคาหุ้น")
152
  return pd.DataFrame()
 
153
  df = df.reset_index()
154
  df_subset = df[['Date', 'Close']]
155
  df_subset.columns = ['date', 'price']
156
  df_subset["date"] = pd.to_datetime(df_subset["date"].dt.date)
 
157
  return df_subset
 
158
  except Exception as e:
159
  st.warning(f"ดึงราคาหุ้นล้มเหลว: {e}")
160
  return pd.DataFrame()
@@ -178,7 +195,6 @@ def main():
178
  # ดึงข่าว
179
  st.info(f"กำลังดึงข่าวย้อนหลัง 7 วันสำหรับ '{keyword}'...")
180
  news_df = fetch_financial_news(keyword)
181
-
182
  if news_df.empty:
183
  st.warning("ไม่พบบทความข่าว")
184
  return
@@ -210,6 +226,7 @@ def main():
210
  # ส่วนกราฟ Sentiment & Price (เหมือนเดิม)
211
  # ---------------------------------------------------------
212
  st.subheader("📈 แนวโน้มอารมณ์ของข่าว & ราคาหุ้น")
 
213
  news_df["date_day"] = pd.to_datetime(news_df["date"].dt.date)
214
 
215
  def sentiment_type(score):
@@ -223,6 +240,7 @@ def main():
223
 
224
  daily_avg = news_df.groupby("date_day")["sentiment"].mean().reset_index(name="avg_sentiment")
225
  daily_counts = news_df.groupby(["date_day", "sentiment_type"]).size().unstack(fill_value=0).reset_index()
 
226
  df_sorted = pd.merge(daily_avg, daily_counts, on="date_day").sort_values("date_day")
227
 
228
  if len(df_sorted) < 2:
@@ -245,7 +263,7 @@ def main():
245
  corr_text = "มีความสัมพันธ์ในทิศทางเดียวกัน"
246
  elif correlation < -0.5:
247
  corr_text = "มีความสัมพันธ์ในทิศทางตรงข้าม"
248
- st.metric("วิเคราะห์ความสัมพันธ์ระหว่างอารมณ์ของข่าวกับราคาหุ้น (Correlation)", corr_text, f"{correlation:.2f}")
249
 
250
  # Forecast Sentiment
251
  plot_data["timestamp"] = (plot_data["date_day"] - plot_data["date_day"].min()).dt.days
@@ -263,36 +281,47 @@ def main():
263
  future_dates = [plot_data["date_day"].max() + timedelta(days=i) for i in range(1, future_days + 1)]
264
  future_preds = model_lr.predict(future_timestamps.reshape(-1, 1))
265
 
266
- # Plot
267
- fig = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]], row_heights=[0.7, 0.3], vertical_spacing=0.1, shared_xaxes=True)
268
-
269
- # ราคาหุ้น
270
- fig.add_trace(go.Scatter(x=plot_data["date_day"], y=plot_data["price"], name=f"{symbol} Price", mode="lines+markers", line=dict(color="orange")), row=1, col=1, secondary_y=False)
271
-
272
- # Sentiment จริง
273
- fig.add_trace(go.Scatter(x=plot_data["date_day"], y=plot_data["avg_sentiment"], name="Actual Sentiment", mode="lines+markers", line=dict(color="blue")), row=1, col=1, secondary_y=True)
274
-
275
- # Sentiment พยากรณ์
276
- if "future_preds" in locals():
277
- fig.add_trace(go.Scatter(x=future_dates, y=future_preds, name="Predicted Sentiment", mode="lines+markers", line=dict(color="#05a0fa", dash="dash")), row=1, col=1, secondary_y=True)
278
-
 
 
279
  # เส้นเชื่อม Actual -> Predicted
280
  last_actual_date = plot_data["date_day"].max()
281
  last_actual_value = plot_data["avg_sentiment"].iloc[-1]
282
  first_pred_date = future_dates[0]
283
  first_pred_value = future_preds[0]
284
- fig.add_trace(go.Scatter(x=[last_actual_date, first_pred_date], y=[last_actual_value, first_pred_value], mode="lines", line=dict(color="#05a0fa", dash="dot"), name="Connector Actual→Predicted"), row=1, col=1, secondary_y=True)
285
-
286
- # จำนวนข่าว
287
- for col in ["neutral", "negative", "positive"]:
288
- if col not in plot_data.columns:
289
- plot_data[col] = 0
290
- fig.add_trace(go.Bar(x=plot_data["date_day"], y=plot_data["neutral"], name="Neutral", marker_color='rgba(128, 128, 128, 0.7)'), row=2, col=1)
291
- fig.add_trace(go.Bar(x=plot_data["date_day"], y=plot_data["negative"], name="Negative", marker_color='rgba(255, 0, 0, 0.7)'), row=2, col=1)
292
- fig.add_trace(go.Bar(x=plot_data["date_day"], y=plot_data["positive"], name="Positive", marker_color='rgba(0, 128, 0, 0.7)'), row=2, col=1)
293
-
294
- fig.update_layout(title=f"แนวโน้มอารมณ์ของข่าว + ราคาหุ้น ({symbol})", barmode="stack", height=650, hovermode="x unified", template="plotly_white")
295
- st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
296
 
297
  # แสดงรายการข่าว
298
  st.subheader("📰 รายการข่าวทั้งหมด")
@@ -303,4 +332,4 @@ def main():
303
  # ---------------------------------------------------------
304
  if __name__ == "__main__":
305
  nltk.download("stopwords", quiet=True)
306
- main()
 
45
  """วิเคราะห์อารมณ์ของข่าวด้วย FinBERT"""
46
  if not text or not text.strip():
47
  return 0
48
+
49
  inputs = tokenizer(
50
  text,
51
  return_tensors="pt",
 
53
  truncation=True,
54
  max_length=512
55
  )
56
+
57
  with torch.no_grad():
58
  outputs = model(**inputs)
59
  logits = outputs.logits
60
  probs = torch.softmax(logits, dim=1).numpy()[0]
61
+
62
+ # FinBERT = [negative, neutral, positive]
63
+ score = (-1 * probs[0]) + (0 * probs[1]) + (1 * probs[2])
64
  return float(score)
65
 
66
+
67
  def summarize_themes(news_texts):
68
  """สรุปธีมข่าวด้วย Zero-shot classification"""
69
  themes = []
 
81
  keyword = keyword.strip()
82
  ticker = None
83
  name = None
84
+
85
  try:
86
  data = yf.Ticker(keyword)
87
  info = data.info
 
97
  name = q.get("longname", q.get("shortname", keyword))
98
  except:
99
  pass
100
+
101
  if not ticker:
102
  ticker = keyword.upper()
103
  if not name:
104
  name = keyword.capitalize()
105
+
106
  return name, ticker
107
 
108
  # --------------------------
 
113
  company, symbol = resolve_company_symbol(keyword)
114
  to_date = datetime.now().strftime('%Y-%m-%d')
115
  from_date = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
116
+
117
  query_keyword = f"({company} OR {symbol}) finance stock"
118
+
119
  all_articles = []
120
  page = 1
121
  while True:
 
131
  if data.get("status") != "ok":
132
  st.error(f"API Error: {data}")
133
  break
134
+
135
  articles = data.get("articles", [])
136
  if not articles:
137
  break
138
+
139
  for a in articles:
140
  if a["description"]:
141
  all_articles.append({
 
144
  "source": a["source"]["name"],
145
  "url": a["url"]
146
  })
147
+
148
  if len(articles) < 100:
149
  break
150
  page += 1
151
+
152
  return pd.DataFrame(all_articles)
153
 
154
  # --------------------------
 
160
  start_str = (start_date - timedelta(days=2)).strftime('%Y-%m-%d')
161
  end_str = (end_date + timedelta(days=1)).strftime('%Y-%m-%d')
162
  df = yf.download(symbol, start=start_str, end=end_str, interval="1d")
163
+
164
  if df.empty:
165
  st.warning("ไม่พบข้อมูลราคาหุ้น")
166
  return pd.DataFrame()
167
+
168
  df = df.reset_index()
169
  df_subset = df[['Date', 'Close']]
170
  df_subset.columns = ['date', 'price']
171
  df_subset["date"] = pd.to_datetime(df_subset["date"].dt.date)
172
+
173
  return df_subset
174
+
175
  except Exception as e:
176
  st.warning(f"ดึงราคาหุ้นล้มเหลว: {e}")
177
  return pd.DataFrame()
 
195
  # ดึงข่าว
196
  st.info(f"กำลังดึงข่าวย้อนหลัง 7 วันสำหรับ '{keyword}'...")
197
  news_df = fetch_financial_news(keyword)
 
198
  if news_df.empty:
199
  st.warning("ไม่พบบทความข่าว")
200
  return
 
226
  # ส่วนกราฟ Sentiment & Price (เหมือนเดิม)
227
  # ---------------------------------------------------------
228
  st.subheader("📈 แนวโน้มอารมณ์ของข่าว & ราคาหุ้น")
229
+
230
  news_df["date_day"] = pd.to_datetime(news_df["date"].dt.date)
231
 
232
  def sentiment_type(score):
 
240
 
241
  daily_avg = news_df.groupby("date_day")["sentiment"].mean().reset_index(name="avg_sentiment")
242
  daily_counts = news_df.groupby(["date_day", "sentiment_type"]).size().unstack(fill_value=0).reset_index()
243
+
244
  df_sorted = pd.merge(daily_avg, daily_counts, on="date_day").sort_values("date_day")
245
 
246
  if len(df_sorted) < 2:
 
263
  corr_text = "มีความสัมพันธ์ในทิศทางเดียวกัน"
264
  elif correlation < -0.5:
265
  corr_text = "มีความสัมพันธ์ในทิศทางตรงข้าม"
266
+ st.metric("วิเคราะห์ความสัมพันธ์ระหว่างอารมณ์ของข่าวกับราคาหุ้น", corr_text, f"{correlation:.2f}")
267
 
268
  # Forecast Sentiment
269
  plot_data["timestamp"] = (plot_data["date_day"] - plot_data["date_day"].min()).dt.days
 
281
  future_dates = [plot_data["date_day"].max() + timedelta(days=i) for i in range(1, future_days + 1)]
282
  future_preds = model_lr.predict(future_timestamps.reshape(-1, 1))
283
 
284
+ # Plot
285
+ fig = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]],
286
+ row_heights=[0.7, 0.3], vertical_spacing=0.1,
287
+ shared_xaxes=True)
288
+
289
+ # ราคาหุ้น
290
+ fig.add_trace(go.Scatter(x=plot_data["date_day"], y=plot_data["price"], name=f"{symbol} Price",
291
+ mode="lines+markers", line=dict(color="orange")), row=1, col=1, secondary_y=False)
292
+ # Sentiment จริง
293
+ fig.add_trace(go.Scatter(x=plot_data["date_day"], y=plot_data["avg_sentiment"], name="Actual Sentiment",
294
+ mode="lines+markers", line=dict(color="blue")), row=1, col=1, secondary_y=True)
295
+ # Sentiment พยากรณ์
296
+ if "future_preds" in locals():
297
+ fig.add_trace(go.Scatter(x=future_dates, y=future_preds, name="Predicted Sentiment",
298
+ mode="lines+markers", line=dict(color="#05a0fa", dash="dash")), row=1, col=1, secondary_y=True)
299
  # เส้นเชื่อม Actual -> Predicted
300
  last_actual_date = plot_data["date_day"].max()
301
  last_actual_value = plot_data["avg_sentiment"].iloc[-1]
302
  first_pred_date = future_dates[0]
303
  first_pred_value = future_preds[0]
304
+ fig.add_trace(go.Scatter(x=[last_actual_date, first_pred_date],
305
+ y=[last_actual_value, first_pred_value],
306
+ mode="lines",
307
+ line=dict(color="#05a0fa", dash="dot"),
308
+ name="Connector Actual→Predicted"), row=1, col=1, secondary_y=True)
309
+
310
+ # จำนวนข่าว
311
+ for col in ["neutral", "negative", "positive"]:
312
+ if col not in plot_data.columns:
313
+ plot_data[col] = 0
314
+ fig.add_trace(go.Bar(x=plot_data["date_day"], y=plot_data["neutral"], name="Neutral",
315
+ marker_color='rgba(128, 128, 128, 0.7)'), row=2, col=1)
316
+ fig.add_trace(go.Bar(x=plot_data["date_day"], y=plot_data["negative"], name="Negative",
317
+ marker_color='rgba(255, 0, 0, 0.7)'), row=2, col=1)
318
+ fig.add_trace(go.Bar(x=plot_data["date_day"], y=plot_data["positive"], name="Positive",
319
+ marker_color='rgba(0, 128, 0, 0.7)'), row=2, col=1)
320
+
321
+ fig.update_layout(title=f"แนวโน้มอารมณ์ของข่าว + ราคาหุ้น ({symbol})",
322
+ barmode="stack", height=650, hovermode="x unified", template="plotly_white")
323
+
324
+ st.plotly_chart(fig, use_container_width=True)
325
 
326
  # แสดงรายการข่าว
327
  st.subheader("📰 รายการข่าวทั้งหมด")
 
332
  # ---------------------------------------------------------
333
  if __name__ == "__main__":
334
  nltk.download("stopwords", quiet=True)
335
+ main()