KYTHY commited on
Commit
7e7aab1
·
verified ·
1 Parent(s): 221c693

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -52
app.py CHANGED
@@ -11,13 +11,14 @@ from io import BytesIO
11
  import numpy as np
12
  from sklearn.linear_model import LinearRegression
13
  import plotly.graph_objects as go
 
14
  import yfinance as yf
15
 
16
  # --------------------------
17
  # CONFIG
18
  # --------------------------
19
  st.set_page_config(page_title="📰 SentimentSync NewsAI", layout="wide")
20
- API_KEY = "88bc396d4eab4be494a4b86ec842db47" # (อย่าลืมเปลี่ยนคีย์ของคุณถ้าแชร์โค้ด)
21
 
22
  # --------------------------
23
  # UTILITIES
@@ -118,29 +119,28 @@ def fetch_financial_news(keyword):
118
 
119
 
120
  # --------------------------
121
- # (*** ส่วนที่ 1: แก้ไข)
122
- # ดึงราคาหุ้นย้อนหลัง 8 วัน
123
  # --------------------------
124
  @st.cache_data(ttl=3600)
125
- def fetch_stock_price(symbol):
 
 
 
126
  try:
127
- # แก้ไข: ใช้ start/end date ที่ชัดเจน ให้ตรงกับช่วงข่าว
128
- end_date = datetime.now()
129
- start_date = end_date - timedelta(days=8) # ดึง 8 วัน เผื่อวันหยุด
130
 
131
- df = yf.download(symbol,
132
- start=start_date.strftime('%Y-%m-%d'),
133
- end=end_date.strftime('%Y-%m-%d'),
134
- interval="1d")
135
 
136
  if df.empty:
137
- st.warning("ไม่พบข้อมูลราคาหุ้นในช่วง 8 วันที่ผ่านมา")
138
- return pd.DataFrame()
139
-
140
  df = df.reset_index()[["Date", "Close"]]
141
  df.rename(columns={"Date": "date", "Close": "price"}, inplace=True)
142
- # **สำคัญมาก** เราต้อง normalize date ให้เป็น date (00:00)
143
- df["date"] = pd.to_datetime(df["date"].dt.date)
144
  return df
145
  except Exception as e:
146
  st.warning(f"ไม่สามารถดึงราคาหุ้นได้: {e}")
@@ -148,7 +148,7 @@ def fetch_stock_price(symbol):
148
 
149
 
150
  # --------------------------
151
- # MAIN APP (*** ส่วนที่ 2: แก้ไข)
152
  # --------------------------
153
  def main():
154
  st.title("📰 SentimentSync NewsAI")
@@ -195,73 +195,113 @@ def main():
195
  st.image(f"data:image/png;base64,{img}", use_column_width=True)
196
 
197
  # -----------------------------------------------------------------
198
- # (ส่วนที่แก้ไข) แนวโน้ม + พยากรณ์ + ราคาหุ้น
199
  # -----------------------------------------------------------------
200
  st.subheader("📈 แนวโน้มอารมณ์ของข่าว & ราคาหุ้น")
201
 
202
- # 1. (ใหม่) รวบรวมข้อมูลข่าวเป็น "ค่าเฉลี่ยรายวัน"
203
- # **สำคัญมาก** เราต้อง normalize date ให้เป็น date (00:00)
204
  news_df["date_day"] = pd.to_datetime(news_df["date"].dt.date)
 
 
 
 
 
205
 
206
- daily_sentiment_df = news_df.groupby("date_day").agg(
 
 
207
  avg_sentiment=('sentiment', 'mean')
208
  ).reset_index()
209
 
210
- # 2. (ใหม่) ใช้ข้อมูล "รายวัน" นี้ในการเทรนโมเดล
211
- df_sorted = daily_sentiment_df.sort_values("date_day").copy()
 
 
 
 
 
 
 
 
212
  df_sorted["timestamp"] = (df_sorted["date_day"] - df_sorted["date_day"].min()).dt.days
213
 
214
- # Train sentiment model
215
  model = LinearRegression()
216
  model.fit(df_sorted[["timestamp"]], df_sorted["avg_sentiment"])
217
 
218
- # Forecast next 7 days
219
  future_days = 7
220
  future_timestamps = np.arange(df_sorted["timestamp"].max() + 1, df_sorted["timestamp"].max() + future_days + 1)
221
  future_dates = [df_sorted["date_day"].max() + timedelta(days=i) for i in range(1, future_days + 1)]
222
  future_preds = model.predict(future_timestamps.reshape(-1, 1))
223
 
224
- # 3. ดึงราคาหุ้น (ซึ่งตอนนี้เราแก้ฟังก์ชัน `fetch_stock_price` แล้ว)
225
  _, symbol = resolve_company_symbol(keyword)
226
- stock_df = fetch_stock_price(symbol)
227
-
228
- # 4. Plot (ตอนนี้ X-axis ทั้ง 3 เส้นจะตรงกันแล้ว)
229
- fig = go.Figure()
230
 
231
- # Actual sentiment (จากค่าเฉลี่ยรายวัน)
232
- fig.add_trace(go.Scatter(
233
- x=df_sorted["date_day"], y=df_sorted["avg_sentiment"],
234
- mode="lines+markers", name="Actual Sentiment (Daily Avg)",
235
- line=dict(color="blue")
236
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
- # Predicted sentiment (จากโมเดลรายวัน)
239
  fig.add_trace(go.Scatter(
240
  x=future_dates, y=future_preds,
241
  mode="lines+markers", name="Predicted Sentiment (7-day Forecast)",
242
- line=dict(color="orange", dash="dash")
 
243
  ))
244
-
245
- # Stock price (จาก yfinance ที่เป็นรายวัน)
246
- if not stock_df.empty:
247
- fig.add_trace(go.Scatter(
248
- x=stock_df["date"], y=stock_df["price"],
249
- mode="lines+markers", name=f"{symbol} Stock Price",
250
- line=dict(color="green"), yaxis="y2"
251
- ))
252
 
 
 
 
 
 
 
253
  fig.update_layout(
254
- title=f"แนวโน้มและพยากรณ์อารมณ์ข่าว & ราคาหุ้น '{keyword}'",
255
- xaxis_title="วันที่",
256
- yaxis=dict(title="Sentiment", side="left", range=[-1, 1]),
257
- yaxis2=dict(title="Stock Price", overlaying="y", side="right", showgrid=False),
258
  hovermode="x unified",
259
- template="plotly_white"
 
 
 
260
  )
 
 
 
 
 
261
 
262
  st.plotly_chart(fig, use_container_width=True)
263
 
264
- # แสดงข่าว (ยังใช้ข้อมูลดิบรายบทความ)
265
  st.subheader("📰 รายการข่าว")
266
  st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_container_width=True)
267
 
 
11
  import numpy as np
12
  from sklearn.linear_model import LinearRegression
13
  import plotly.graph_objects as go
14
+ from plotly.subplots import make_subplots # Import สิ่งนี้
15
  import yfinance as yf
16
 
17
  # --------------------------
18
  # CONFIG
19
  # --------------------------
20
  st.set_page_config(page_title="📰 SentimentSync NewsAI", layout="wide")
21
+ API_KEY = "88bc396d4eab4be494a4b86ec842db47"
22
 
23
  # --------------------------
24
  # UTILITIES
 
119
 
120
 
121
  # --------------------------
122
+ # (*** ส่วนที่แก้ไข ***)
123
+ # ดึงราคาหุ้นตามช่วงเวลาที่กำหนด
124
  # --------------------------
125
  @st.cache_data(ttl=3600)
126
+ def fetch_stock_price(symbol, start_date, end_date):
127
+ """
128
+ แก้ไข: รับ start_date และ end_date เพื่อดึงข้อมูลให้ตรงกัน
129
+ """
130
  try:
131
+ start_str = (start_date - timedelta(days=2)).strftime('%Y-%m-%d')
132
+ end_str = (end_date + timedelta(days=1)).strftime('%Y-%m-%d')
 
133
 
134
+ df = yf.download(symbol, start=start_str, end=end_str, interval="1d")
 
 
 
135
 
136
  if df.empty:
137
+ st.warning("ไม่พบข้อมูลราคาหุ้นในช่วงเวลานี้")
138
+ return pd.DataFrame()
139
+
140
  df = df.reset_index()[["Date", "Close"]]
141
  df.rename(columns={"Date": "date", "Close": "price"}, inplace=True)
142
+ # Normalize วันที่ให้เป็น .dt.date
143
+ df["date"] = pd.to_datetime(df["date"].dt.date)
144
  return df
145
  except Exception as e:
146
  st.warning(f"ไม่สามารถดึงราคาหุ้นได้: {e}")
 
148
 
149
 
150
  # --------------------------
151
+ # MAIN APP (*** ส่วนที่แก้ไขทั้งหมด ***)
152
  # --------------------------
153
  def main():
154
  st.title("📰 SentimentSync NewsAI")
 
195
  st.image(f"data:image/png;base64,{img}", use_column_width=True)
196
 
197
  # -----------------------------------------------------------------
198
+ # (ส่วนที่แก้ไข) กราฟไฮบริด (Ref1 + Prediction)
199
  # -----------------------------------------------------------------
200
  st.subheader("📈 แนวโน้มอารมณ์ของข่าว & ราคาหุ้น")
201
 
202
+ # 1. รวบรวมข้อมูลข่าวเป็นรายวัน (Daily Aggregation)
 
203
  news_df["date_day"] = pd.to_datetime(news_df["date"].dt.date)
204
+
205
+ def sentiment_type(score):
206
+ if score > 0.1: return "positive"
207
+ if score < -0.1: return "negative"
208
+ return "neutral"
209
 
210
+ news_df["sentiment_type"] = news_df["sentiment"].apply(sentiment_type)
211
+
212
+ daily_avg_sentiment = news_df.groupby("date_day").agg(
213
  avg_sentiment=('sentiment', 'mean')
214
  ).reset_index()
215
 
216
+ daily_counts = news_df.groupby(["date_day", "sentiment_type"]).size().unstack(fill_value=0).reset_index()
217
+
218
+ daily_data = pd.merge(daily_avg_sentiment, daily_counts, on="date_day", how="left").fillna(0)
219
+
220
+ for col in ['positive', 'negative', 'neutral']:
221
+ if col not in daily_data.columns:
222
+ daily_data[col] = 0
223
+
224
+ # 2. (ใหม่) เทรนโมเดล Prediction โดยใช้ข้อมูล "รายวัน"
225
+ df_sorted = daily_data.sort_values("date_day").copy()
226
  df_sorted["timestamp"] = (df_sorted["date_day"] - df_sorted["date_day"].min()).dt.days
227
 
 
228
  model = LinearRegression()
229
  model.fit(df_sorted[["timestamp"]], df_sorted["avg_sentiment"])
230
 
 
231
  future_days = 7
232
  future_timestamps = np.arange(df_sorted["timestamp"].max() + 1, df_sorted["timestamp"].max() + future_days + 1)
233
  future_dates = [df_sorted["date_day"].max() + timedelta(days=i) for i in range(1, future_days + 1)]
234
  future_preds = model.predict(future_timestamps.reshape(-1, 1))
235
 
236
+ # 3. ดึงราคาหุ้น (ในช่วงเวลาเดียวกับข่าว)
237
  _, symbol = resolve_company_symbol(keyword)
238
+ min_date = df_sorted["date_day"].min()
239
+ max_date = df_sorted["date_day"].max()
 
 
240
 
241
+ st.info(f"กำลังดึงราคาหุ้น {symbol} ระหว่างวันที่ {min_date.strftime('%Y-%m-%d')} ถึง {max_date.strftime('%Y-%m-%d')}...")
242
+ stock_df = fetch_stock_price(symbol, min_date, max_date)
243
+
244
+ # 4. สร้างกราฟ (Plot) ด้วย Subplots
245
+ fig = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]],
246
+ row_heights=[0.7, 0.3], vertical_spacing=0.1,
247
+ shared_xaxes=True)
248
+
249
+ # --- กราฟส่วนบน (ราคา, Sentiment, Prediction) ---
250
+
251
+ # Add stock price (Y-axis 1, สีเขียว)
252
+ if not stock_df.empty:
253
+ fig.add_trace(
254
+ go.Scatter(
255
+ x=stock_df["date"], y=stock_df["price"],
256
+ name=f"{symbol} Stock Price",
257
+ line=dict(color="green", width=2) # ใช้สีเขียวตามโค้ดเดิม
258
+ ),
259
+ row=1, col=1, secondary_y=False
260
+ )
261
+
262
+ # Add daily sentiment score (Y-axis 2, สีน้ำเงิน)
263
+ fig.add_trace(
264
+ go.Scatter(
265
+ x=df_sorted["date_day"], y=df_sorted["avg_sentiment"],
266
+ name="Actual Sentiment (Daily Avg)",
267
+ mode="lines+markers",
268
+ line=dict(color="blue", width=2) # ใช้สีน้ำเงินตามโค้ดเดิม
269
+ ),
270
+ row=1, col=1, secondary_y=True
271
+ )
272
 
273
+ # (ใหม่) Add Predicted sentiment (Y-axis 2, สีส้ม)
274
  fig.add_trace(go.Scatter(
275
  x=future_dates, y=future_preds,
276
  mode="lines+markers", name="Predicted Sentiment (7-day Forecast)",
277
+ line=dict(color="orange", dash="dash"),
278
+ secondary_y=True # <-- สำคัญ: ต้องอยู่แกน Y เดียวกับ Actual
279
  ))
 
 
 
 
 
 
 
 
280
 
281
+ # --- กราฟส่วนล่าง (จำนวนข่าว) ---
282
+ 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)
283
+ 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)
284
+ 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)
285
+
286
+ # 5. ตกแต่ง Layout
287
  fig.update_layout(
288
+ title=f"แนวโน้มอารมณ์ข่าว & ราคาหุ้น '{keyword}'",
289
+ template="plotly_white",
 
 
290
  hovermode="x unified",
291
+ barmode='stack',
292
+ legend=dict(orientation='h', yanchor='bottom', y=1.02, xanchor='right', x=1),
293
+ height=600,
294
+ margin=dict(l=20, r=20, t=80, b=20)
295
  )
296
+
297
+ fig.update_yaxes(title_text="Stock Price", row=1, col=1, secondary_y=False)
298
+ fig.update_yaxes(title_text="Sentiment Score", range=[-1, 1], row=1, col=1, secondary_y=True)
299
+ fig.update_yaxes(title_text="Article Count", row=2, col=1)
300
+ fig.update_xaxes(title_text="วันที่", row=2, col=1)
301
 
302
  st.plotly_chart(fig, use_container_width=True)
303
 
304
+ # แสดงข่าว (ยังอยู่เหมือนเดิม)
305
  st.subheader("📰 รายการข่าว")
306
  st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_container_width=True)
307