KYTHY commited on
Commit
b14206a
·
verified ·
1 Parent(s): 076f95b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +73 -87
app.py CHANGED
@@ -3,45 +3,40 @@ import requests
3
  import pandas as pd
4
  from datetime import datetime, timedelta
5
  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
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
24
  # --------------------------
 
 
 
 
 
 
25
  def analyze_text(text, vader):
26
  if not text.strip():
27
  return 0
28
- vader_score = vader.polarity_scores(text)["compound"]
29
- textblob_score = TextBlob(text).sentiment.polarity
30
- return np.mean([vader_score, textblob_score])
31
-
32
-
33
- def generate_wordcloud(text):
34
- stopwords = nltk.corpus.stopwords.words('english')
35
- wordcloud = WordCloud(width=800, height=400, background_color="white", stopwords=stopwords).generate(text)
36
- buf = BytesIO()
37
- wordcloud.to_image().save(buf, format="PNG")
38
- return base64.b64encode(buf.getvalue()).decode()
39
-
40
 
41
- # --------------------------
42
- # แปลงชื่อ/ตัวย่อ → (Company Name, Symbol)
43
- # --------------------------
44
  def resolve_company_symbol(keyword: str):
 
 
 
 
 
 
45
  keyword = keyword.strip()
46
  ticker = None
47
  name = None
@@ -69,27 +64,23 @@ def resolve_company_symbol(keyword: str):
69
 
70
  return name, ticker
71
 
72
-
73
- # --------------------------
74
- # ดึงข่าว 7 วัน สำหรับ Company + Symbol
75
- # --------------------------
76
  @st.cache_data(ttl=3600)
77
- def fetch_financial_news(keyword):
78
- company, symbol = resolve_company_symbol(keyword)
79
  to_date = datetime.now().strftime('%Y-%m-%d')
80
  from_date = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
81
 
82
- query_keyword = f"({company} OR {symbol}) finance stock"
83
 
84
  all_articles = []
85
  page = 1
86
  while True:
87
  url = (
88
  f"https://newsapi.org/v2/everything?"
89
- f"q={query_keyword}&"
90
  f"from={from_date}&to={to_date}&"
91
  f"language=en&sortBy=publishedAt&"
92
- f"pageSize=100&page={page}&apiKey={API_KEY}"
93
  )
94
  r = requests.get(url)
95
  data = r.json()
@@ -114,46 +105,54 @@ def fetch_financial_news(keyword):
114
  break
115
  page += 1
116
 
117
- return pd.DataFrame(all_articles), company, symbol
118
 
 
 
 
 
 
 
119
 
120
- # --------------------------
121
- # ดึงราคาหุ้นย้อนหลัง 14 วัน
122
- # --------------------------
123
- @st.cache_data(ttl=3600)
124
- def fetch_stock_price(symbol):
125
  try:
126
- df = yf.download(symbol, period="14d", interval="1d")
127
- df = df.reset_index()[["Date", "Close"]]
128
- df.rename(columns={"Date": "date", "Close": "price"}, inplace=True)
129
- df["date"] = pd.to_datetime(df["date"])
130
- return df
 
 
 
131
  except Exception as e:
132
- st.warning(f"ไม่สามารถดึงราคาหุ้นได้: {e}")
133
  return pd.DataFrame()
134
 
135
-
136
  # --------------------------
137
  # MAIN APP
138
  # --------------------------
139
  def main():
140
- st.title("📰 SentimentSync NewsAI")
141
- st.markdown("วิเคราะห์แนวโน้มอารมณ์ของข่าวย้อนหลัง 7 วัน พร้อมราคาหุ้น")
142
 
143
- # Sidebar
144
  with st.sidebar:
145
- keyword = st.text_input("ค้นหาคำ / ตัวย่อหุ้น (เช่น Tesla หรือ TSLA):", "")
146
  analyze_btn = st.button("วิเคราะห์เลย")
147
 
148
  if not analyze_btn:
149
- st.info("กรอกคำค้นแล้วกด 'วิเคราะห์เลย' เพื่อเริ่มต้น")
150
  return
151
 
152
- vader = SentimentIntensityAnalyzer()
 
 
 
 
153
 
154
  # ดึงข่าว
155
- st.info(f"กำลังดึงข่าวย้อนหลัง 7 วันสำหรับ '{keyword}' ...")
156
- news_df, company, symbol = fetch_financial_news(keyword)
157
  if news_df.empty:
158
  st.warning("ไม่พบบทความข่าวในช่วง 7 วันที่ผ่านมา")
159
  return
@@ -163,6 +162,7 @@ def main():
163
  news_df["sentiment"] = news_df["text"].apply(lambda x: analyze_text(x, vader))
164
  news_df["date"] = pd.to_datetime(news_df["date"])
165
 
 
166
  avg_sentiment = news_df["sentiment"].mean()
167
  pos_pct = (news_df["sentiment"] > 0.1).mean() * 100
168
  neg_pct = (news_df["sentiment"] < -0.1).mean() * 100
@@ -179,62 +179,48 @@ def main():
179
  img = generate_wordcloud(all_text)
180
  st.image(f"data:image/png;base64,{img}", use_column_width=True)
181
 
182
- # แนวโน้ม + พยากรณ์ + ราคาหุ้น
183
- st.subheader("📈 แนวโน้มอารมณ์ของข่าว & ราคาหุ้น")
184
- df_sorted = news_df.sort_values("date").copy()
185
- df_sorted["timestamp"] = (df_sorted["date"] - df_sorted["date"].min()).dt.days
186
-
187
- # Train sentiment model
188
- model = LinearRegression()
189
- model.fit(df_sorted[["timestamp"]], df_sorted["sentiment"])
190
-
191
- # Forecast next 7 days
192
- future_days = 7
193
- future_timestamps = np.arange(df_sorted["timestamp"].max() + 1, df_sorted["timestamp"].max() + future_days + 1)
194
- future_dates = [df_sorted["date"].max() + timedelta(days=i) for i in range(1, future_days + 1)]
195
- future_preds = model.predict(future_timestamps.reshape(-1, 1))
196
-
197
  # ดึงราคาหุ้น
198
- stock_df = fetch_stock_price(symbol)
199
 
200
- # Plot
 
201
  fig = go.Figure()
202
- # Actual sentiment
203
- fig.add_trace(go.Scatter(
204
- x=df_sorted["date"], y=df_sorted["sentiment"],
205
- mode="lines+markers", name="Actual Sentiment",
206
- line=dict(color="blue")
207
- ))
208
- # Predicted sentiment
209
  fig.add_trace(go.Scatter(
210
- x=future_dates, y=future_preds,
211
- mode="lines+markers", name="Predicted Sentiment (7-day Forecast)",
212
- line=dict(color="orange", dash="dash")
213
  ))
 
214
  # Stock price
215
- if not stock_df.empty:
216
  fig.add_trace(go.Scatter(
217
- x=stock_df["date"], y=stock_df["price"],
218
  mode="lines+markers", name=f"{symbol} Stock Price",
219
- line=dict(color="green"), yaxis="y2"
 
220
  ))
 
 
 
 
 
 
 
221
 
222
  fig.update_layout(
223
- title=f"แนวโน้มและพยากรณ์อารมณ์ข่าว & ราคาหุ้น '{company} ({symbol})'",
224
- xaxis_title="วันที่",
225
- yaxis=dict(title="Sentiment", side="left", range=[-1, 1]),
226
- yaxis2=dict(title="Stock Price", overlaying="y", side="right", showgrid=False),
227
  hovermode="x unified",
228
  template="plotly_white"
229
  )
230
-
231
  st.plotly_chart(fig, use_container_width=True)
232
 
233
  # แสดงข่าว
234
  st.subheader("📰 รายการข่าว")
235
  st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_container_width=True)
236
 
237
-
238
  if __name__ == "__main__":
239
- nltk.download("stopwords", quiet=True)
240
  main()
 
3
  import pandas as pd
4
  from datetime import datetime, timedelta
5
  from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer
 
 
6
  from wordcloud import WordCloud
7
  import base64
8
  from io import BytesIO
9
  import numpy as np
 
10
  import plotly.graph_objects as go
11
  import yfinance as yf
12
 
13
  # --------------------------
14
  # CONFIG
15
  # --------------------------
16
+ st.set_page_config(page_title="📰 SentimentSync News+Stock", layout="wide")
17
+ NEWS_API_KEY = "88bc396d4eab4be494a4b86ec842db47"
18
 
19
  # --------------------------
20
  # UTILITIES
21
  # --------------------------
22
+ @st.cache_resource
23
+ def load_sentiment_model():
24
+ st.info("Loading sentiment analyzer...")
25
+ vader = SentimentIntensityAnalyzer()
26
+ return vader
27
+
28
  def analyze_text(text, vader):
29
  if not text.strip():
30
  return 0
31
+ return vader.polarity_scores(text)["compound"]
 
 
 
 
 
 
 
 
 
 
 
32
 
 
 
 
33
  def resolve_company_symbol(keyword: str):
34
+ """
35
+ คืน (company_name, symbol) จากชื่อบริษัทหรือ ticker
36
+ """
37
+ import yfinance as yf
38
+ import requests
39
+
40
  keyword = keyword.strip()
41
  ticker = None
42
  name = None
 
64
 
65
  return name, ticker
66
 
 
 
 
 
67
  @st.cache_data(ttl=3600)
68
+ def fetch_financial_news(company, symbol):
69
+ """ดึงข่าวย้อนหลัง 7 วันจาก NewsAPI.org"""
70
  to_date = datetime.now().strftime('%Y-%m-%d')
71
  from_date = (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d')
72
 
73
+ query_keyword = f"({company} OR {symbol})"
74
 
75
  all_articles = []
76
  page = 1
77
  while True:
78
  url = (
79
  f"https://newsapi.org/v2/everything?"
80
+ f"q={query_keyword}+finance+stock&"
81
  f"from={from_date}&to={to_date}&"
82
  f"language=en&sortBy=publishedAt&"
83
+ f"pageSize=100&page={page}&apiKey={NEWS_API_KEY}"
84
  )
85
  r = requests.get(url)
86
  data = r.json()
 
105
  break
106
  page += 1
107
 
108
+ return pd.DataFrame(all_articles)
109
 
110
+ def generate_wordcloud(text):
111
+ stopwords = ["the","and","of","to","in","for","on","with","at","a","an"]
112
+ wordcloud = WordCloud(width=800, height=400, background_color="white", stopwords=stopwords).generate(text)
113
+ buf = BytesIO()
114
+ wordcloud.to_image().save(buf, format="PNG")
115
+ return base64.b64encode(buf.getvalue()).decode()
116
 
117
+ def get_stock_prices(symbol: str, start_date: datetime, end_date: datetime):
118
+ """ดึงราคาหุ้น Close price ของ symbol"""
 
 
 
119
  try:
120
+ stock_df = yf.download(symbol, start=start_date.strftime('%Y-%m-%d'),
121
+ end=end_date.strftime('%Y-%m-%d'), progress=False)
122
+ if stock_df.empty or 'Close' not in stock_df.columns:
123
+ return pd.DataFrame()
124
+ stock_df = stock_df.reset_index()[['Date', 'Close']]
125
+ stock_df.rename(columns={'Date': 'date', 'Close': 'price'}, inplace=True)
126
+ stock_df['date'] = pd.to_datetime(stock_df['date'].dt.date)
127
+ return stock_df
128
  except Exception as e:
129
+ print(f"Error fetching stock data: {e}")
130
  return pd.DataFrame()
131
 
 
132
  # --------------------------
133
  # MAIN APP
134
  # --------------------------
135
  def main():
136
+ st.title("📰 SentimentSync News + Stock Prices")
137
+ st.markdown("วิเคราะห์แนวโน้มอารมณ์ข่าวและราคาหุ้นย้อนหลัง 7 วัน")
138
 
 
139
  with st.sidebar:
140
+ keyword = st.text_input("ค้นหาบริษัทหรือ Symbol:", "")
141
  analyze_btn = st.button("วิเคราะห์เลย")
142
 
143
  if not analyze_btn:
144
+ st.info("กรอกคำค้นแล้วกด 'วิเคราะห์เลย' เพื่อเริ่ม")
145
  return
146
 
147
+ vader = load_sentiment_model()
148
+
149
+ # แปลงชื่อ → (company, symbol)
150
+ company, symbol = resolve_company_symbol(keyword)
151
+ st.write(f"Resolved: {company} ({symbol})")
152
 
153
  # ดึงข่าว
154
+ st.info(f"กำลังดึงข่าวย้อนหลัง 7 วันสำหรับ '{company} / {symbol}' ...")
155
+ news_df = fetch_financial_news(company, symbol)
156
  if news_df.empty:
157
  st.warning("ไม่พบบทความข่าวในช่วง 7 วันที่ผ่านมา")
158
  return
 
162
  news_df["sentiment"] = news_df["text"].apply(lambda x: analyze_text(x, vader))
163
  news_df["date"] = pd.to_datetime(news_df["date"])
164
 
165
+ # สรุป sentiment
166
  avg_sentiment = news_df["sentiment"].mean()
167
  pos_pct = (news_df["sentiment"] > 0.1).mean() * 100
168
  neg_pct = (news_df["sentiment"] < -0.1).mean() * 100
 
179
  img = generate_wordcloud(all_text)
180
  st.image(f"data:image/png;base64,{img}", use_column_width=True)
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  # ดึงราคาหุ้น
183
+ stock_prices = get_stock_prices(symbol, news_df['date'].min(), news_df['date'].max())
184
 
185
+ # กราฟ sentiment + stock
186
+ st.subheader("📈 แนวโน้มอารมณ์ข่าว + ราคาหุ้น")
187
  fig = go.Figure()
188
+
189
+ # Sentiment
 
 
 
 
 
190
  fig.add_trace(go.Scatter(
191
+ x=news_df["date"], y=news_df["sentiment"],
192
+ mode="lines+markers", name="Sentiment",
193
+ line=dict(color="orange")
194
  ))
195
+
196
  # Stock price
197
+ if not stock_prices.empty:
198
  fig.add_trace(go.Scatter(
199
+ x=stock_prices["date"], y=stock_prices["price"],
200
  mode="lines+markers", name=f"{symbol} Stock Price",
201
+ line=dict(color="blue"),
202
+ yaxis="y2"
203
  ))
204
+ fig.update_layout(
205
+ yaxis2=dict(
206
+ title="Stock Price",
207
+ overlaying="y",
208
+ side="right"
209
+ )
210
+ )
211
 
212
  fig.update_layout(
213
+ title=f"Sentiment & Stock Price for {company} ({symbol})",
214
+ xaxis_title="Date",
215
+ yaxis_title="Sentiment Score",
 
216
  hovermode="x unified",
217
  template="plotly_white"
218
  )
 
219
  st.plotly_chart(fig, use_container_width=True)
220
 
221
  # แสดงข่าว
222
  st.subheader("📰 รายการข่าว")
223
  st.dataframe(news_df[["date", "source", "text", "sentiment", "url"]], use_container_width=True)
224
 
 
225
  if __name__ == "__main__":
 
226
  main()