Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -6,19 +6,19 @@ from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
|
|
| 6 |
from textblob import TextBlob
|
| 7 |
import nltk
|
| 8 |
from wordcloud import WordCloud
|
| 9 |
-
import
|
| 10 |
from io import BytesIO
|
| 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
|
| 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
|
|
@@ -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
|
| 40 |
|
| 41 |
|
| 42 |
# --------------------------
|
|
@@ -123,6 +123,9 @@ def fetch_financial_news(keyword):
|
|
| 123 |
# --------------------------
|
| 124 |
@st.cache_data(ttl=3600)
|
| 125 |
def fetch_stock_price(symbol, start_date, end_date):
|
|
|
|
|
|
|
|
|
|
| 126 |
try:
|
| 127 |
start_str = (start_date - timedelta(days=2)).strftime('%Y-%m-%d')
|
| 128 |
end_str = (end_date + timedelta(days=1)).strftime('%Y-%m-%d')
|
|
@@ -135,6 +138,7 @@ def fetch_stock_price(symbol, start_date, end_date):
|
|
| 135 |
|
| 136 |
df = df.reset_index()[["Date", "Close"]]
|
| 137 |
df.rename(columns={"Date": "date", "Close": "price"}, inplace=True)
|
|
|
|
| 138 |
df["date"] = pd.to_datetime(df["date"].dt.date)
|
| 139 |
return df
|
| 140 |
except Exception as e:
|
|
@@ -143,7 +147,7 @@ def fetch_stock_price(symbol, start_date, end_date):
|
|
| 143 |
|
| 144 |
|
| 145 |
# --------------------------
|
| 146 |
-
# MAIN APP
|
| 147 |
# --------------------------
|
| 148 |
def main():
|
| 149 |
st.title("📰 SentimentSync NewsAI")
|
|
@@ -219,8 +223,12 @@ def main():
|
|
| 219 |
# 2. เทรนโมเดล Prediction โดยใช้ข้อมูล "รายวัน"
|
| 220 |
df_sorted = daily_data.sort_values("date_day").copy()
|
| 221 |
|
|
|
|
| 222 |
if len(df_sorted) < 2:
|
| 223 |
st.warning("มีข้อมูลข่าวไม่เพียงพอที่จะสร้างแนวโน้ม (น้อยกว่า 2 วัน)")
|
|
|
|
|
|
|
|
|
|
| 224 |
return
|
| 225 |
|
| 226 |
df_sorted["timestamp"] = (df_sorted["date_day"] - df_sorted["date_day"].min()).dt.days
|
|
@@ -241,29 +249,26 @@ def main():
|
|
| 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 |
-
# ---------------------------------
|
| 245 |
-
# ----- (เพิ่ม DEBUGGING) -----
|
| 246 |
-
st.subheader("🕵️ DEBUGGING INFO: ข้อมูลราคาหุ้นที่ดึงได้")
|
| 247 |
-
st.write(f"Found {len(stock_df)} stock price data points:")
|
| 248 |
-
st.dataframe(stock_df)
|
| 249 |
-
# ---------------------------------
|
| 250 |
-
|
| 251 |
# 4. สร้างกราฟ (Plot) ด้วย Subplots
|
| 252 |
fig = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]],
|
| 253 |
row_heights=[0.7, 0.3], vertical_spacing=0.1,
|
| 254 |
shared_xaxes=True)
|
| 255 |
|
| 256 |
# --- กราฟส่วนบน (ราคา, Sentiment, Prediction) ---
|
|
|
|
|
|
|
| 257 |
if not stock_df.empty:
|
| 258 |
fig.add_trace(
|
| 259 |
go.Scatter(
|
| 260 |
x=stock_df["date"], y=stock_df["price"],
|
| 261 |
name=f"{symbol} Stock Price",
|
|
|
|
| 262 |
line=dict(color="green", width=2)
|
| 263 |
),
|
| 264 |
row=1, col=1, secondary_y=False
|
| 265 |
)
|
| 266 |
|
|
|
|
| 267 |
fig.add_trace(
|
| 268 |
go.Scatter(
|
| 269 |
x=df_sorted["date_day"], y=df_sorted["avg_sentiment"],
|
|
@@ -274,6 +279,7 @@ def main():
|
|
| 274 |
row=1, col=1, secondary_y=True
|
| 275 |
)
|
| 276 |
|
|
|
|
| 277 |
fig.add_trace(go.Scatter(
|
| 278 |
x=future_dates, y=future_preds,
|
| 279 |
mode="lines+markers", name="Predicted Sentiment (7-day Forecast)",
|
|
@@ -306,9 +312,9 @@ def main():
|
|
| 306 |
|
| 307 |
st.plotly_chart(fig, use_container_width=True)
|
| 308 |
|
| 309 |
-
# แสดงข่าว
|
| 310 |
st.subheader("📰 รายการข่าว")
|
| 311 |
-
st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]],
|
| 312 |
|
| 313 |
|
| 314 |
if __name__ == "__main__":
|
|
|
|
| 6 |
from textblob import TextBlob
|
| 7 |
import nltk
|
| 8 |
from wordcloud import WordCloud
|
| 9 |
+
import base66
|
| 10 |
from io import BytesIO
|
| 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
|
|
|
|
| 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 base66.b64encode(buf.getvalue()).decode()
|
| 40 |
|
| 41 |
|
| 42 |
# --------------------------
|
|
|
|
| 123 |
# --------------------------
|
| 124 |
@st.cache_data(ttl=3600)
|
| 125 |
def fetch_stock_price(symbol, start_date, end_date):
|
| 126 |
+
"""
|
| 127 |
+
ดึงราคาหุ้นตามช่วงเวลาของข่าวที่พบ (บวก/ลบ 1-2 วัน เผื่อวันหยุด)
|
| 128 |
+
"""
|
| 129 |
try:
|
| 130 |
start_str = (start_date - timedelta(days=2)).strftime('%Y-%m-%d')
|
| 131 |
end_str = (end_date + timedelta(days=1)).strftime('%Y-%m-%d')
|
|
|
|
| 138 |
|
| 139 |
df = df.reset_index()[["Date", "Close"]]
|
| 140 |
df.rename(columns={"Date": "date", "Close": "price"}, inplace=True)
|
| 141 |
+
# Normalize วันที่ให้เป็น .dt.date
|
| 142 |
df["date"] = pd.to_datetime(df["date"].dt.date)
|
| 143 |
return df
|
| 144 |
except Exception as e:
|
|
|
|
| 147 |
|
| 148 |
|
| 149 |
# --------------------------
|
| 150 |
+
# MAIN APP
|
| 151 |
# --------------------------
|
| 152 |
def main():
|
| 153 |
st.title("📰 SentimentSync NewsAI")
|
|
|
|
| 223 |
# 2. เทรนโมเดล Prediction โดยใช้ข้อมูล "รายวัน"
|
| 224 |
df_sorted = daily_data.sort_values("date_day").copy()
|
| 225 |
|
| 226 |
+
# ป้องกัน Error ถ้ามีข้อมูลน้อยกว่า 2 วัน
|
| 227 |
if len(df_sorted) < 2:
|
| 228 |
st.warning("มีข้อมูลข่าวไม่เพียงพอที่จะสร้างแนวโน้ม (น้อยกว่า 2 วัน)")
|
| 229 |
+
# แสดงตารางข่าวต่อไป แม้จะพล็อตไม่ได้
|
| 230 |
+
st.subheader("📰 รายการข่าว")
|
| 231 |
+
st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_column_width=True)
|
| 232 |
return
|
| 233 |
|
| 234 |
df_sorted["timestamp"] = (df_sorted["date_day"] - df_sorted["date_day"].min()).dt.days
|
|
|
|
| 249 |
st.info(f"กำลังดึงราคาหุ้น {symbol} ระหว่างวันที่ {min_date.strftime('%Y-%m-%d')} ถึง {max_date.strftime('%Y-%m-%d')}...")
|
| 250 |
stock_df = fetch_stock_price(symbol, min_date, max_date)
|
| 251 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
# 4. สร้างกราฟ (Plot) ด้วย Subplots
|
| 253 |
fig = make_subplots(rows=2, cols=1, specs=[[{"secondary_y": True}], [{}]],
|
| 254 |
row_heights=[0.7, 0.3], vertical_spacing=0.1,
|
| 255 |
shared_xaxes=True)
|
| 256 |
|
| 257 |
# --- กราฟส่วนบน (ราคา, Sentiment, Prediction) ---
|
| 258 |
+
|
| 259 |
+
# Add stock price (Y-axis 1, สีเขียว)
|
| 260 |
if not stock_df.empty:
|
| 261 |
fig.add_trace(
|
| 262 |
go.Scatter(
|
| 263 |
x=stock_df["date"], y=stock_df["price"],
|
| 264 |
name=f"{symbol} Stock Price",
|
| 265 |
+
mode="lines+markers", # <-- นี่คือจุดที่แก้ไขล่าสุด
|
| 266 |
line=dict(color="green", width=2)
|
| 267 |
),
|
| 268 |
row=1, col=1, secondary_y=False
|
| 269 |
)
|
| 270 |
|
| 271 |
+
# Add daily sentiment score (Y-axis 2, สีน้ำเงิน)
|
| 272 |
fig.add_trace(
|
| 273 |
go.Scatter(
|
| 274 |
x=df_sorted["date_day"], y=df_sorted["avg_sentiment"],
|
|
|
|
| 279 |
row=1, col=1, secondary_y=True
|
| 280 |
)
|
| 281 |
|
| 282 |
+
# Add Predicted sentiment (Y-axis 2, สีส้ม)
|
| 283 |
fig.add_trace(go.Scatter(
|
| 284 |
x=future_dates, y=future_preds,
|
| 285 |
mode="lines+markers", name="Predicted Sentiment (7-day Forecast)",
|
|
|
|
| 312 |
|
| 313 |
st.plotly_chart(fig, use_container_width=True)
|
| 314 |
|
| 315 |
+
# แสดงข่าว (ยังอยู่เหมือนเดิม)
|
| 316 |
st.subheader("📰 รายการข่าว")
|
| 317 |
+
st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_column_width=True)
|
| 318 |
|
| 319 |
|
| 320 |
if __name__ == "__main__":
|