KYTHY commited on
Commit
96505cf
·
verified ·
1 Parent(s): f6b1ca2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +49 -40
app.py CHANGED
@@ -6,7 +6,7 @@ from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
6
  from textblob import TextBlob
7
  import nltk
8
  from wordcloud import WordCloud
9
- import base64
10
  from io import BytesIO
11
  import numpy as np
12
  from sklearn.linear_model import LinearRegression
@@ -36,7 +36,7 @@ def generate_wordcloud(text):
36
  wordcloud = WordCloud(width=800, height=400, background_color="white", stopwords=stopwords).generate(text)
37
  buf = BytesIO()
38
  wordcloud.to_image().save(buf, format="PNG")
39
- return base64.b64encode(buf.getvalue()).decode()
40
 
41
 
42
  # --------------------------
@@ -167,12 +167,12 @@ def main():
167
  st.warning("ไม่พบบทความข่าวในช่วง 7 วันที่ผ่านมา")
168
  return
169
 
170
- # วิเคราะห์ sentiment (รายบทความ)
171
  st.info("กำลังวิเคราะห์อารมณ์ของข่าว...")
172
  news_df["sentiment"] = news_df["text"].apply(lambda x: analyze_text(x, vader))
173
  news_df["date"] = pd.to_datetime(news_df["date"])
174
 
175
- # แสดง Metric (ยังใช้ข้อมูลทั้งหมด)
176
  avg_sentiment = news_df["sentiment"].mean()
177
  pos_pct = (news_df["sentiment"] > 0.1).mean() * 100
178
  neg_pct = (news_df["sentiment"] < -0.1).mean() * 100
@@ -183,7 +183,7 @@ def main():
183
  col2.metric("ข่าวเชิงบวก", f"{pos_pct:.1f}%")
184
  col3.metric("ข่าวเชิงลบ", f"{neg_pct:.1f}%")
185
 
186
- # Wordcloud (ยังใช้ข้อมูลทั้งหมด)
187
  st.subheader("☁️ Word Cloud ของข่าว")
188
  all_text = " ".join(news_df["text"].tolist())
189
  img = generate_wordcloud(all_text)
@@ -216,28 +216,15 @@ def main():
216
  if col not in daily_data.columns:
217
  daily_data[col] = 0
218
 
219
- # 2. เทรนโมเดล Prediction โดยใช้ข้อมูล "รายวัน"
220
  df_sorted = daily_data.sort_values("date_day").copy()
221
 
222
- # ป้องกัน Error ถ้ามีข้อมูลน้อยกว่า 2 วัน
223
  if len(df_sorted) < 2:
224
  st.warning("มีข้อมูลข่าวไม่เพียงพอที่จะสร้างแนวโน้ม (น้อยกว่า 2 วัน)")
225
  st.subheader("📰 รายการข่าว")
226
- # (แก้ไข) เปลี่ยน use_column_width เป็น use_container_width
227
- st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_container_width=True)
228
  return
229
 
230
- df_sorted["timestamp"] = (df_sorted["date_day"] - df_sorted["date_day"].min()).dt.days
231
-
232
- model = LinearRegression()
233
- model.fit(df_sorted[["timestamp"]], df_sorted["avg_sentiment"])
234
-
235
- future_days = 7
236
- future_timestamps = np.arange(df_sorted["timestamp"].max() + 1, df_sorted["timestamp"].max() + future_days + 1)
237
- future_dates = [df_sorted["date_day"].max() + timedelta(days=i) for i in range(1, future_days + 1)]
238
- future_preds = model.predict(future_timestamps.reshape(-1, 1))
239
-
240
- # 3. ดึงราคาหุ้น (ในช่วงเวลาเดียวกับข่าว)
241
  _, symbol = resolve_company_symbol(keyword)
242
  min_date = df_sorted["date_day"].min()
243
  max_date = df_sorted["date_day"].max()
@@ -245,27 +232,50 @@ def main():
245
  st.info(f"กำลังดึงราคาหุ้น {symbol} ระหว่างวันที่ {min_date.strftime('%Y-%m-%d')} ถึง {max_date.strftime('%Y-%m-%d')}...")
246
  stock_df = fetch_stock_price(symbol, min_date, max_date)
247
 
248
- # 4. สร้างกราฟ (Plot) ด้วย Subplots
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  fig = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]],
250
  row_heights=[0.7, 0.3], vertical_spacing=0.1,
251
  shared_xaxes=True)
252
 
253
  # --- กราฟส่วนบน (ราคา, Sentiment, Prediction) ---
254
 
255
- if not stock_df.empty:
256
- fig.add_trace(
257
- go.Scatter(
258
- x=stock_df["date"], y=stock_df["price"],
259
- name=f"{symbol} Stock Price",
260
- mode="lines+markers",
261
- line=dict(color="green", width=2)
262
- ),
263
- row=1, col=1, secondary_y=False
264
- )
265
 
 
266
  fig.add_trace(
267
  go.Scatter(
268
- x=df_sorted["date_day"], y=df_sorted["avg_sentiment"],
269
  name="Actual Sentiment (Daily Avg)",
270
  mode="lines+markers",
271
  line=dict(color="blue", width=2)
@@ -273,6 +283,7 @@ def main():
273
  row=1, col=1, secondary_y=True
274
  )
275
 
 
276
  fig.add_trace(go.Scatter(
277
  x=future_dates, y=future_preds,
278
  mode="lines+markers", name="Predicted Sentiment (7-day Forecast)",
@@ -283,11 +294,11 @@ def main():
283
  )
284
 
285
  # --- กราฟส่วนล่าง (จำนวนข่าว) ---
286
- fig.add_trace(go.Bar(x=df_sorted["date_day"], y=df_sorted["neutral"], name="Neutral", marker_color='rgba(128, 128, 128, 0.7)'), row=2, col=1)
287
- fig.add_trace(go.Bar(x=df_sorted["date_day"], y=df_sorted["negative"], name="Negative", marker_color='rgba(255, 0, 0, 0.7)'), row=2, col=1)
288
- fig.add_trace(go.Bar(x=df_sorted["date_day"], y=df_sorted["positive"], name="Positive", marker_color='rgba(0, 128, 0, 0.7)'), row=2, col=1)
289
 
290
- # 5. ตกแต่ง Layout
291
  fig.update_layout(
292
  title=f"แนวโน้มอารมณ์ข่าว & ราคาหุ้น '{keyword}'",
293
  template="plotly_white",
@@ -305,11 +316,9 @@ def main():
305
 
306
  st.plotly_chart(fig, use_container_width=True)
307
 
308
- # แสดงข่าว (ยังอยู่เหมือนเดิม)
309
  st.subheader("📰 รายการข่าว")
310
- # ----- (นี่คือบรรทัดที่แก้ไข) -----
311
- st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_container_width=True)
312
- # -----------------------------------
313
 
314
 
315
  if __name__ == "__main__":
 
6
  from textblob import TextBlob
7
  import nltk
8
  from wordcloud import WordCloud
9
+ import base64 # (แก้ไข Typo)
10
  from io import BytesIO
11
  import numpy as np
12
  from sklearn.linear_model import LinearRegression
 
36
  wordcloud = WordCloud(width=800, height=400, background_color="white", stopwords=stopwords).generate(text)
37
  buf = BytesIO()
38
  wordcloud.to_image().save(buf, format="PNG")
39
+ return base64.b64encode(buf.getvalue()).decode() # (แก้ไข Typo)
40
 
41
 
42
  # --------------------------
 
167
  st.warning("ไม่พบบทความข่าวในช่วง 7 วันที่ผ่านมา")
168
  return
169
 
170
+ # วิเคราะห์ sentiment
171
  st.info("กำลังวิเคราะห์อารมณ์ของข่าว...")
172
  news_df["sentiment"] = news_df["text"].apply(lambda x: analyze_text(x, vader))
173
  news_df["date"] = pd.to_datetime(news_df["date"])
174
 
175
+ # แสดง Metric
176
  avg_sentiment = news_df["sentiment"].mean()
177
  pos_pct = (news_df["sentiment"] > 0.1).mean() * 100
178
  neg_pct = (news_df["sentiment"] < -0.1).mean() * 100
 
183
  col2.metric("ข่าวเชิงบวก", f"{pos_pct:.1f}%")
184
  col3.metric("ข่าวเชิงลบ", f"{neg_pct:.1f}%")
185
 
186
+ # Wordcloud
187
  st.subheader("☁️ Word Cloud ของข่าว")
188
  all_text = " ".join(news_df["text"].tolist())
189
  img = generate_wordcloud(all_text)
 
216
  if col not in daily_data.columns:
217
  daily_data[col] = 0
218
 
 
219
  df_sorted = daily_data.sort_values("date_day").copy()
220
 
 
221
  if len(df_sorted) < 2:
222
  st.warning("มีข้อมูลข่าวไม่เพียงพอที่จะสร้างแนวโน้ม (น้อยกว่า 2 วัน)")
223
  st.subheader("📰 รายการข่าว")
224
+ st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_container_width=True) # (แก้ไข Typo)
 
225
  return
226
 
227
+ # 2. ดึงราคาหุ้น
 
 
 
 
 
 
 
 
 
 
228
  _, symbol = resolve_company_symbol(keyword)
229
  min_date = df_sorted["date_day"].min()
230
  max_date = df_sorted["date_day"].max()
 
232
  st.info(f"กำลังดึงราคาหุ้น {symbol} ระหว่างวันที่ {min_date.strftime('%Y-%m-%d')} ถึง {max_date.strftime('%Y-%m-%d')}...")
233
  stock_df = fetch_stock_price(symbol, min_date, max_date)
234
 
235
+ # 3. (*** นี่คือตรรกะใหม่ที่สำคัญ ***)
236
+ # Merge ข้อมูล 2 ชุด (Sentiment & Stock) ให้มีแกน X เดียวกัน
237
+ plot_data = pd.merge(
238
+ df_sorted,
239
+ stock_df,
240
+ left_on="date_day",
241
+ right_on="date",
242
+ how="left" # ยึดวันที่ของข่าว (ซ้าย) เป็นหลัก
243
+ )
244
+ # (ตอนนี้ plot_data จะมีคอลัมน์ price ที่เป็น NaN ในวันที่ตลาดปิด)
245
+
246
+ # 4. เทรนโมเดล Prediction (ใช้ข้อมูลที่ Merge แล้ว)
247
+ plot_data["timestamp"] = (plot_data["date_day"] - plot_data["date_day"].min()).dt.days
248
+ model = LinearRegression()
249
+ model.fit(plot_data[["timestamp"]], plot_data["avg_sentiment"])
250
+
251
+ future_days = 7
252
+ future_timestamps = np.arange(plot_data["timestamp"].max() + 1, plot_data["timestamp"].max() + future_days + 1)
253
+ future_dates = [plot_data["date_day"].max() + timedelta(days=i) for i in range(1, future_days + 1)]
254
+ future_preds = model.predict(future_timestamps.reshape(-1, 1))
255
+
256
+
257
+ # 5. สร้างกราฟ (Plot) ด้วย Subplots (ใช้ 'plot_data' เป็นหลัก)
258
  fig = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]],
259
  row_heights=[0.7, 0.3], vertical_spacing=0.1,
260
  shared_xaxes=True)
261
 
262
  # --- กราฟส่วนบน (ราคา, Sentiment, Prediction) ---
263
 
264
+ # Add stock price (Y-axis 1, สีเขียว)
265
+ fig.add_trace(
266
+ go.Scatter(
267
+ x=plot_data["date_day"], y=plot_data["price"], # <--- ใช้ plot_data
268
+ name=f"{symbol} Stock Price",
269
+ mode="lines+markers",
270
+ line=dict(color="green", width=2)
271
+ ),
272
+ row=1, col=1, secondary_y=False
273
+ )
274
 
275
+ # Add daily sentiment score (Y-axis 2, สีน้ำเงิน)
276
  fig.add_trace(
277
  go.Scatter(
278
+ x=plot_data["date_day"], y=plot_data["avg_sentiment"], # <--- ใช้ plot_data
279
  name="Actual Sentiment (Daily Avg)",
280
  mode="lines+markers",
281
  line=dict(color="blue", width=2)
 
283
  row=1, col=1, secondary_y=True
284
  )
285
 
286
+ # Add Predicted sentiment (Y-axis 2, สีส้ม)
287
  fig.add_trace(go.Scatter(
288
  x=future_dates, y=future_preds,
289
  mode="lines+markers", name="Predicted Sentiment (7-day Forecast)",
 
294
  )
295
 
296
  # --- กราฟส่วนล่าง (จำนวนข่าว) ---
297
+ 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) # <--- ใช้ plot_data
298
+ 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) # <--- ใช้ plot_data
299
+ 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) # <--- ใช้ plot_data
300
 
301
+ # 6. ตกแต่ง Layout
302
  fig.update_layout(
303
  title=f"แนวโน้มอารมณ์ข่าว & ราคาหุ้น '{keyword}'",
304
  template="plotly_white",
 
316
 
317
  st.plotly_chart(fig, use_container_width=True)
318
 
319
+ # แสดงข่าว (ยังใช้ news_df ตัวเต็ม)
320
  st.subheader("📰 รายการข่าว")
321
+ st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_container_width=True) # (แก้ไข Typo)
 
 
322
 
323
 
324
  if __name__ == "__main__":